Skip to content

Commit be34889

Browse files
committed
Fix @protected context processing bugs.
- Allow redefinition via property term scoped contexts. - Rename property term scoped context flag and use in `options`. - Pass property term scoped context flag in compaction algorithm. - Fix context caching/processing for arrays of contexts.
1 parent 5adf787 commit be34889

File tree

3 files changed

+37
-26
lines changed

3 files changed

+37
-26
lines changed

lib/compact.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,12 @@ api.compact = ({
102102
// use any scoped context on activeProperty
103103
const ctx = _getContextValue(activeCtx, activeProperty, '@context');
104104
if(!_isUndefined(ctx)) {
105-
activeCtx = _processContext({activeCtx, localCtx: ctx, options});
105+
// Note: spec's `from term` var is named `isPropertyTermScopedContext`
106+
activeCtx = _processContext({
107+
activeCtx,
108+
localCtx: ctx,
109+
options: {...options, isPropertyTermScopedContext: true}
110+
});
106111
}
107112

108113
// recursively compact object

lib/context.js

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,7 @@ api.cache = new ActiveContextCache();
4545
*
4646
* @return the new active context.
4747
*/
48-
api.process = ({activeCtx, localCtx, options,
49-
propertyTermDefinition = false}) => {
48+
api.process = ({activeCtx, localCtx, options}) => {
5049
// normalize local context to an array of @context objects
5150
if(_isObject(localCtx) && '@context' in localCtx &&
5251
_isArray(localCtx['@context'])) {
@@ -65,11 +64,23 @@ api.process = ({activeCtx, localCtx, options,
6564
for(let i = 0; i < ctxs.length; ++i) {
6665
let ctx = ctxs[i];
6766

67+
// update active context to one computed from last iteration
68+
activeCtx = rval;
69+
70+
// get context from cache if available
71+
if(api.cache) {
72+
const cached = api.cache.get(activeCtx, ctx);
73+
if(cached) {
74+
rval = activeCtx = cached;
75+
continue;
76+
}
77+
}
78+
6879
// reset to initial context
6980
if(ctx === null) {
7081
// We can't nullify if there are protected terms and we're
71-
// not in a term definition
72-
if(!propertyTermDefinition &&
82+
// not processing a property term scoped context
83+
if(!options.isPropertyTermScopedContext &&
7384
Object.keys(activeCtx.protected).length !== 0) {
7485
const protectedMode = (options && options.protectedMode) || 'error';
7586
if(protectedMode === 'error') {
@@ -82,6 +93,7 @@ api.process = ({activeCtx, localCtx, options,
8293
// FIXME: remove logging and use a handler
8394
console.warn('WARNING: invalid context nullification');
8495
const oldActiveCtx = activeCtx;
96+
// copy all protected term definitions to fresh initial context
8597
rval = activeCtx = api.getInitialContext(options);
8698
for(const [term, _protected] of
8799
Object.entries(oldActiveCtx.protected)) {
@@ -91,6 +103,12 @@ api.process = ({activeCtx, localCtx, options,
91103
}
92104
}
93105
activeCtx.protected = util.clone(oldActiveCtx.protected);
106+
107+
// cache result
108+
if(api.cache) {
109+
api.cache.set(oldActiveCtx, ctx, rval);
110+
}
111+
94112
continue;
95113
}
96114
throw new JsonLdError(
@@ -114,17 +132,7 @@ api.process = ({activeCtx, localCtx, options,
114132
'jsonld.SyntaxError', {code: 'invalid local context', context: ctx});
115133
}
116134

117-
// get context from cache if available
118-
if(api.cache) {
119-
const cached = api.cache.get(activeCtx, ctx);
120-
if(cached) {
121-
rval = activeCtx = cached;
122-
continue;
123-
}
124-
}
125-
126-
// update active context and clone new one before updating
127-
activeCtx = rval;
135+
// clone context before updating it
128136
rval = rval.clone();
129137

130138
// define context mappings for keys in local context
@@ -277,7 +285,7 @@ api.createTermDefinition = (activeCtx, localCtx, term, defined, options) => {
277285
}
278286

279287
// FIXME if(1.1) ... ?
280-
if(term in activeCtx.protected) {
288+
if(term in activeCtx.protected && !options.isPropertyTermScopedContext) {
281289
const protectedMode = (options && options.protectedMode) || 'error';
282290
if(protectedMode === 'error') {
283291
throw new JsonLdError(
@@ -442,14 +450,9 @@ api.createTermDefinition = (activeCtx, localCtx, term, defined, options) => {
442450
}
443451

444452
// Handle term protection
445-
if('@protected' in value) {
446-
if(value['@protected']) {
447-
activeCtx.protected[term] = true;
448-
}
449-
} else if('@protected' in defined) {
450-
if(defined['@protected']) {
451-
activeCtx.protected[term] = true;
452-
}
453+
if(value['@protected'] === true ||
454+
(defined['@protected'] === true && value['@protected'] !== false)) {
455+
activeCtx.protected[term] = true;
453456
}
454457

455458
// IRI mapping now defined

lib/expand.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,11 @@ function _expandObject({
558558
let termCtx = activeCtx;
559559
const ctx = _getContextValue(activeCtx, key, '@context');
560560
if(!_isUndefined(ctx)) {
561+
// Note: spec's `from term` var is named `isPropertyTermScopedContext`
561562
termCtx = _processContext({
562-
activeCtx, localCtx: ctx, options, propertyTermDefinition: true
563+
activeCtx,
564+
localCtx: ctx,
565+
options: {...options, isPropertyTermScopedContext: true}
563566
});
564567
}
565568

0 commit comments

Comments
 (0)