Skip to content

Commit a9249b9

Browse files
cwebberdlongley
authored andcommitted
Support context sealing.
1 parent 1d431e2 commit a9249b9

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

lib/context.js

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ api.cache = new ActiveContextCache();
4545
*
4646
* @return the new active context.
4747
*/
48-
api.process = ({activeCtx, localCtx, options}) => {
48+
api.process = ({activeCtx, localCtx, options,
49+
propertyTermDefinition = false}) => {
4950
// normalize local context to an array of @context objects
5051
if(_isObject(localCtx) && '@context' in localCtx &&
5152
_isArray(localCtx['@context'])) {
@@ -66,6 +67,16 @@ api.process = ({activeCtx, localCtx, options}) => {
6667

6768
// reset to initial context
6869
if(ctx === null) {
70+
// We can't nullify if there are sealed terms and we're
71+
// not in a term definition
72+
if(!propertyTermDefinition &&
73+
Object.keys(activeCtx.sealed).length !== 0) {
74+
throw new JsonLdError(
75+
'Tried to nullify a context with sealed terms outside of ' +
76+
'a term definition.',
77+
'jsonld.SyntaxError',
78+
{code: 'invalid context nullification'});
79+
}
6980
rval = activeCtx = api.getInitialContext(options);
7081
continue;
7182
}
@@ -182,6 +193,11 @@ api.process = ({activeCtx, localCtx, options}) => {
182193
defined['@language'] = true;
183194
}
184195

196+
// handle @sealed; determine whether this sub-context is declaring
197+
// all its terms to be "sealed" (exceptions can be made on a
198+
// per-definition basis)
199+
defined['@sealed'] = ctx['@sealed'] || false;
200+
185201
// process all other keys
186202
for(const key in ctx) {
187203
api.createTermDefinition(rval, ctx, key, defined);
@@ -235,6 +251,15 @@ api.createTermDefinition = (activeCtx, localCtx, term, defined) => {
235251
{code: 'invalid term definition', context: localCtx});
236252
}
237253

254+
// Is this term currently sealed?
255+
// Then redefining it here is an error!
256+
if(activeCtx.sealed[term]) {
257+
throw new JsonLdError(
258+
'Invalid JSON-LD syntax; tried to redefine a sealed term.',
259+
'jsonld.SyntaxError',
260+
{code: 'sealed term redefinition', context: localCtx, term: term});
261+
}
262+
238263
// remove old mapping
239264
if(activeCtx.mappings[term]) {
240265
delete activeCtx.mappings[term];
@@ -274,7 +299,7 @@ api.createTermDefinition = (activeCtx, localCtx, term, defined) => {
274299

275300
// JSON-LD 1.1 support
276301
if(api.processingMode(activeCtx, 1.1)) {
277-
validKeys.push('@context', '@nest', '@prefix');
302+
validKeys.push('@context', '@nest', '@prefix', '@sealed');
278303
}
279304

280305
for(const kw in value) {
@@ -379,6 +404,17 @@ api.createTermDefinition = (activeCtx, localCtx, term, defined) => {
379404
}
380405
}
381406

407+
// Handle term sealing
408+
if('@sealed' in value) {
409+
if(value['@sealed']) {
410+
activeCtx.sealed[term] = true;
411+
}
412+
} else if ('@sealed' in defined) {
413+
if(defined['@sealed']) {
414+
activeCtx.sealed[term] = true;
415+
}
416+
}
417+
382418
// IRI mapping now defined
383419
defined[term] = true;
384420

@@ -650,7 +686,8 @@ api.getInitialContext = options => {
650686
mappings: {},
651687
inverse: null,
652688
getInverse: _createInverseContext,
653-
clone: _cloneActiveContext
689+
clone: _cloneActiveContext,
690+
sealed: {}
654691
};
655692
// TODO: consider using LRU cache instead
656693
if(INITIAL_CONTEXT_CACHE.size === INITIAL_CONTEXT_CACHE_MAX_SIZE) {
@@ -826,6 +863,7 @@ api.getInitialContext = options => {
826863
child.clone = this.clone;
827864
child.inverse = null;
828865
child.getInverse = this.getInverse;
866+
child.sealed = util.clone(this.sealed);
829867
if('@language' in this) {
830868
child['@language'] = this['@language'];
831869
}
@@ -937,6 +975,7 @@ api.isKeyword = v => {
937975
case '@preserve':
938976
case '@requireAll':
939977
case '@reverse':
978+
case '@sealed':
940979
case '@set':
941980
case '@type':
942981
case '@value':

lib/expand.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,8 @@ function _expandObject({
556556
let termCtx = activeCtx;
557557
const ctx = _getContextValue(activeCtx, key, '@context');
558558
if(ctx) {
559-
termCtx = _processContext({activeCtx, localCtx: ctx, options});
559+
termCtx = _processContext({activeCtx, localCtx: ctx, options,
560+
propertyTermDefinition: true});
560561
}
561562

562563
const container = _getContextValue(termCtx, key, '@container') || [];

0 commit comments

Comments
 (0)