@@ -66,6 +66,21 @@ api.process = ({
66
66
return activeCtx ;
67
67
}
68
68
69
+ // track the previous context
70
+ const previousContext = activeCtx ;
71
+
72
+ // if context is property scoped and there's a previous context, amend it,
73
+ // not the current one
74
+ if ( isPropertyTermScopedContext && activeCtx . previousContext ) {
75
+ activeCtx . previousContext = api . process ( {
76
+ activeCtx : activeCtx . previousContext ,
77
+ localCtx : ctxs ,
78
+ options,
79
+ isPropertyTermScopedContext
80
+ } ) ;
81
+ return activeCtx ;
82
+ }
83
+
69
84
// process each context in order, update active context
70
85
// on each iteration to ensure proper caching
71
86
let rval = activeCtx ;
@@ -75,15 +90,6 @@ api.process = ({
75
90
// update active context to one computed from last iteration
76
91
activeCtx = rval ;
77
92
78
- // get context from cache if available
79
- if ( api . cache ) {
80
- const cached = api . cache . get ( activeCtx , ctx ) ;
81
- if ( cached ) {
82
- rval = activeCtx = cached ;
83
- continue ;
84
- }
85
- }
86
-
87
93
// reset to initial context
88
94
if ( ctx === null ) {
89
95
// We can't nullify if there are protected terms and we're
@@ -102,7 +108,7 @@ api.process = ({
102
108
console . warn ( 'WARNING: invalid context nullification' ) ;
103
109
const oldActiveCtx = activeCtx ;
104
110
// copy all protected term definitions to fresh initial context
105
- rval = activeCtx = api . getInitialContext ( options ) ;
111
+ rval = activeCtx = api . getInitialContext ( options ) . clone ( ) ;
106
112
for ( const [ term , _protected ] of
107
113
Object . entries ( oldActiveCtx . protected ) ) {
108
114
if ( _protected ) {
@@ -124,10 +130,23 @@ api.process = ({
124
130
'jsonld.SyntaxError' ,
125
131
{ code : 'invalid protected mode' , context : localCtx , protectedMode} ) ;
126
132
}
127
- rval = activeCtx = api . getInitialContext ( options ) ;
133
+ rval = activeCtx = api . getInitialContext ( options ) . clone ( ) ;
134
+ // if context is type-scoped, ensure previous context has been set
135
+ if ( isTypeScopedContext ) {
136
+ rval . previousContext = previousContext . clone ( ) ;
137
+ }
128
138
continue ;
129
139
}
130
140
141
+ // get context from cache if available
142
+ if ( api . cache ) {
143
+ const cached = api . cache . get ( activeCtx , ctx ) ;
144
+ if ( cached ) {
145
+ rval = activeCtx = cached ;
146
+ continue ;
147
+ }
148
+ }
149
+
131
150
// dereference @context key if present
132
151
if ( _isObject ( ctx ) && '@context' in ctx ) {
133
152
ctx = ctx [ '@context' ] ;
@@ -140,6 +159,9 @@ api.process = ({
140
159
'jsonld.SyntaxError' , { code : 'invalid local context' , context : ctx } ) ;
141
160
}
142
161
162
+ // TODO: there is likely a `preivousContext` cloning optimization that
163
+ // could be applied here (no need to copy it under certain conditions)
164
+
143
165
// clone context before updating it
144
166
rval = rval . clone ( ) ;
145
167
@@ -242,12 +264,22 @@ api.process = ({
242
264
isPropertyTermScopedContext , isTypeScopedContext ) ;
243
265
}
244
266
267
+ // if context is type-scoped, ensure previous context has been set
268
+ if ( isTypeScopedContext && ! rval . previousContext ) {
269
+ rval . previousContext = previousContext . clone ( ) ;
270
+ }
271
+
245
272
// cache result
246
273
if ( api . cache ) {
247
274
api . cache . set ( activeCtx , ctx , rval ) ;
248
275
}
249
276
}
250
277
278
+ // if context is type-scoped, ensure previous context has been set
279
+ if ( isTypeScopedContext && ! rval . previousContext ) {
280
+ rval . previousContext = previousContext . clone ( ) ;
281
+ }
282
+
251
283
return rval ;
252
284
} ;
253
285
@@ -301,10 +333,11 @@ api.createTermDefinition = (
301
333
{ code : 'invalid term definition' , context : localCtx } ) ;
302
334
}
303
335
336
+ // keep reference to previous mapping for potential `@protected` check
337
+ const previousMapping = activeCtx . mappings . get ( term ) ;
338
+
304
339
// remove old mapping
305
- let previousMapping = null ;
306
340
if ( activeCtx . mappings . has ( term ) ) {
307
- previousMapping = activeCtx . mappings . get ( term ) ;
308
341
activeCtx . mappings . delete ( term ) ;
309
342
}
310
343
@@ -339,11 +372,6 @@ api.createTermDefinition = (
339
372
// create new mapping
340
373
const mapping = { } ;
341
374
activeCtx . mappings . set ( term , mapping ) ;
342
- if ( isTypeScopedContext ) {
343
- activeCtx . hasTypeScopedTerms = true ;
344
- mapping . isTypeScopedTerm = true ;
345
- mapping . previousMapping = previousMapping ;
346
- }
347
375
mapping . reverse = false ;
348
376
349
377
// make sure term definition only has expected keywords
@@ -961,6 +989,9 @@ api.getInitialContext = options => {
961
989
child . inverse = null ;
962
990
child . getInverse = this . getInverse ;
963
991
child . protected = util . clone ( this . protected ) ;
992
+ if ( this . previousContext ) {
993
+ child . previousContext = this . previousContext . clone ( ) ;
994
+ }
964
995
child . revertTypeScopedTerms = this . revertTypeScopedTerms ;
965
996
if ( '@language' in this ) {
966
997
child [ '@language' ] = this [ '@language' ] ;
@@ -976,31 +1007,10 @@ api.getInitialContext = options => {
976
1007
* mappings.
977
1008
*/
978
1009
function _revertTypeScopedTerms ( ) {
979
- // optimization: no type-scoped terms to remove, reuse active context
980
- if ( ! this . hasTypeScopedTerms ) {
1010
+ if ( ! this . previousContext ) {
981
1011
return this ;
982
1012
}
983
- // create clone without type scoped terms
984
- const child = this . clone ( ) ;
985
- const entries = child . mappings . entries ( ) ;
986
- for ( const [ term , mapping ] of entries ) {
987
- if ( mapping . isTypeScopedTerm ) {
988
- if ( mapping . previousMapping ) {
989
- child . mappings . set ( term , mapping . previousMapping ) ;
990
- if ( mapping . previousMapping . protected ) {
991
- child . protected [ term ] = true ;
992
- } else {
993
- delete child . protected [ term ] ;
994
- }
995
- } else {
996
- child . mappings . delete ( term ) ;
997
- if ( child . protected [ term ] ) {
998
- delete child . protected [ term ] ;
999
- }
1000
- }
1001
- }
1002
- }
1003
- return child ;
1013
+ return this . previousContext . clone ( ) ;
1004
1014
}
1005
1015
} ;
1006
1016
0 commit comments