Skip to content

Commit 6307b89

Browse files
committed
Allow override of a protected term that uses the same definition.
- The only caveat to the "same definition" is that if the new definition does not include `@protected`, this flag is carried forward to maintain the protection status.
1 parent 271c52a commit 6307b89

File tree

1 file changed

+69
-24
lines changed

1 file changed

+69
-24
lines changed

lib/context.js

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -301,33 +301,10 @@ api.createTermDefinition = (
301301
{code: 'invalid term definition', context: localCtx});
302302
}
303303

304-
// FIXME if(1.1) ... ?
305-
if(activeCtx.protected.hasOwnProperty(term) &&
306-
!isPropertyTermScopedContext) {
307-
const protectedMode = (options && options.protectedMode) || 'error';
308-
if(protectedMode === 'error') {
309-
throw new JsonLdError(
310-
'Invalid JSON-LD syntax; tried to redefine a protected term.',
311-
'jsonld.SyntaxError',
312-
{code: 'protected term redefinition', context: localCtx, term});
313-
} else if(protectedMode === 'warn') {
314-
// FIXME: remove logging and use a handler
315-
console.warn('WARNING: protected term redefinition', {term});
316-
return;
317-
}
318-
throw new JsonLdError(
319-
'Invalid protectedMode.',
320-
'jsonld.SyntaxError',
321-
{code: 'invalid protected mode', context: localCtx, term,
322-
protectedMode});
323-
}
324-
325304
// remove old mapping
326305
let previousMapping = null;
327306
if(activeCtx.mappings.has(term)) {
328-
if(isTypeScopedContext) {
329-
previousMapping = activeCtx.mappings.get(term);
330-
}
307+
previousMapping = activeCtx.mappings.get(term);
331308
activeCtx.mappings.delete(term);
332309
}
333310

@@ -652,6 +629,33 @@ api.createTermDefinition = (
652629
'Invalid JSON-LD syntax; @context and @preserve cannot be aliased.',
653630
'jsonld.SyntaxError', {code: 'invalid keyword alias', context: localCtx});
654631
}
632+
633+
// FIXME if(1.1) ... ?
634+
if(previousMapping && previousMapping.protected &&
635+
!isPropertyTermScopedContext) {
636+
// force new term to continue to be protected and see if the mappings would
637+
// be equal
638+
activeCtx.protected[term] = true;
639+
mapping.protected = true;
640+
if(!_areTermDefinitionsEqual(previousMapping, mapping)) {
641+
const protectedMode = (options && options.protectedMode) || 'error';
642+
if(protectedMode === 'error') {
643+
throw new JsonLdError(
644+
'Invalid JSON-LD syntax; tried to redefine a protected term.',
645+
'jsonld.SyntaxError',
646+
{code: 'protected term redefinition', context: localCtx, term});
647+
} else if(protectedMode === 'warn') {
648+
// FIXME: remove logging and use a handler
649+
console.warn('WARNING: protected term redefinition', {term});
650+
return;
651+
}
652+
throw new JsonLdError(
653+
'Invalid protectedMode.',
654+
'jsonld.SyntaxError',
655+
{code: 'invalid protected mode', context: localCtx, term,
656+
protectedMode});
657+
}
658+
}
655659
};
656660

657661
/**
@@ -1303,3 +1307,44 @@ function _findContextUrls(input, urls, replace, base) {
13031307
}
13041308
}
13051309
}
1310+
1311+
function _areTermDefinitionsEqual(d1, d2) {
1312+
const k1 = Object.keys(d1);
1313+
const k2 = Object.keys(d2);
1314+
if(k1.length !== k2.length) {
1315+
return false;
1316+
}
1317+
1318+
for(const k of k1) {
1319+
const v1 = d1[k];
1320+
const v2 = d2[k];
1321+
if(k === '@context') {
1322+
if(JSON.stringify(v1) !== JSON.stringify(v2)) {
1323+
return false;
1324+
}
1325+
continue;
1326+
}
1327+
const isArray = Array.isArray(v1);
1328+
if(isArray !== Array.isArray(v2)) {
1329+
return false;
1330+
}
1331+
// `@container`
1332+
if(isArray) {
1333+
if(v1.length !== v2.length) {
1334+
return false;
1335+
}
1336+
v1.sort();
1337+
v2.sort();
1338+
for(let i = 0; i < v1.length; ++i) {
1339+
if(v1[i] !== v2[i]) {
1340+
return false;
1341+
}
1342+
}
1343+
}
1344+
// strings
1345+
if(v1 !== v2) {
1346+
return false;
1347+
}
1348+
}
1349+
return true;
1350+
}

0 commit comments

Comments
 (0)