diff --git a/CHANGELOG.md b/CHANGELOG.md index ea7a1ef5..c468a520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Better checking of absolute IRIs. - Terms that begin with a ':' are not considered absolute or compact IRIs. - Don't use terms with `"@prefix": false` or expanded term definitions to construct compact IRIs. +- "@type" may be used as a term definition only if "@container": "@set". ### Removed - **BREAKING**: Remove callback API support. This includes removing support diff --git a/lib/compact.js b/lib/compact.js index 66369c18..501bd938 100644 --- a/lib/compact.js +++ b/lib/compact.js @@ -24,7 +24,8 @@ const { expandIri: _expandIri, getContextValue: _getContextValue, isKeyword: _isKeyword, - process: _processContext + process: _processContext, + processingMode: _processingMode } = require('./context'); const { @@ -220,7 +221,15 @@ api.compact = async ({ // use keyword alias and add value const alias = api.compactIri( {activeCtx, iri: expandedProperty, relativeTo: {vocab: true}}); - const isArray = _isArray(compactedValue) && expandedValue.length === 0; + const container = _getContextValue( + activeCtx, alias, '@container') || []; + + // treat as array for @type if @container includes @set + const typeAsSet = isType && + container.includes('@set') && + _processingMode(activeCtx, 1.1); + const isArray = + typeAsSet || (_isArray(compactedValue) && expandedValue.length === 0); _addValue(rval, alias, compactedValue, {propertyIsArray: isArray}); continue; } diff --git a/lib/context.js b/lib/context.js index bb33d82f..1d69a916 100644 --- a/lib/context.js +++ b/lib/context.js @@ -315,14 +315,30 @@ api.createTermDefinition = ( // now defining term defined.set(term, false); - if(api.isKeyword(term)) { + // get context term value + let value; + if(localCtx.hasOwnProperty(term)) { + value = localCtx[term]; + } + + if(term === '@type' && + _isObject(value) && + value['@container'] === '@set' && + api.processingMode(activeCtx, 1.1)) { + + const validKeys = ['@container', '@id', '@protected']; + if(Object.keys(value).some(k => !validKeys.includes(k))) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; keywords cannot be overridden.', + 'jsonld.SyntaxError', + {code: 'keyword redefinition', context: localCtx, term}); + } + } else if(api.isKeyword(term)) { throw new JsonLdError( 'Invalid JSON-LD syntax; keywords cannot be overridden.', 'jsonld.SyntaxError', {code: 'keyword redefinition', context: localCtx, term}); - } - - if(term === '') { + } else if(term === '') { throw new JsonLdError( 'Invalid JSON-LD syntax; a term cannot be an empty string.', 'jsonld.SyntaxError', @@ -337,12 +353,6 @@ api.createTermDefinition = ( activeCtx.mappings.delete(term); } - // get context term value - let value; - if(localCtx.hasOwnProperty(term)) { - value = localCtx[term]; - } - // clear context entry if(value === null || (_isObject(value) && value['@id'] === null)) { activeCtx.mappings.set(term, null); @@ -468,6 +478,9 @@ api.createTermDefinition = ( // term is an absolute IRI mapping['@id'] = term; } + } else if(term == '@type') { + // Special case, were we've previously determined that container is @set + mapping['@id'] = term; } else { // non-IRIs *must* define @ids if @vocab is not available if(!('@vocab' in activeCtx)) { diff --git a/tests/test-common.js b/tests/test-common.js index 2129378c..eeea0989 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -32,9 +32,6 @@ const TEST_TYPES = { specVersion: ['json-ld-1.0'], // FIXME idRegex: [ - // type set - /compact-manifest.jsonld#t0104$/, - /compact-manifest.jsonld#t0105$/, // @type: @none /compact-manifest.jsonld#ttn01$/, /compact-manifest.jsonld#ttn02$/,