diff --git a/lib/expand.js b/lib/expand.js index c8e985b3..d40368a3 100644 --- a/lib/expand.js +++ b/lib/expand.js @@ -213,12 +213,16 @@ api.expand = async ({ // set the type-scoped context to the context on input, for use later typeScopedContext = activeCtx; + // Remember the first key found expanding to @type + let typeKey = null; + // look for scoped contexts on `@type` for(const key of keys) { const expandedProperty = _expandIri(activeCtx, key, {vocab: true}, options); if(expandedProperty === '@type') { // set scoped contexts from @type // avoid sorting if possible + typeKey = typeKey || key; const value = element[key]; const types = Array.isArray(value) ? @@ -248,6 +252,7 @@ api.expand = async ({ options, insideList, typeScopedContext, + typeKey, expansionMap}); // get property count on expanded output @@ -283,7 +288,10 @@ api.expand = async ({ const types = _getValues(rval, '@type'); // drop null @values unless custom mapped - if(values.length === 0) { + if(_processingMode(activeCtx, 1.1) && types.includes('@json') && + types.length === 1) { + // Any value of @value is okay if @type: @json + } else if(values.length === 0) { const mapped = await expansionMap({ unmappedValue: rval, activeCtx, @@ -304,9 +312,6 @@ api.expand = async ({ 'Invalid JSON-LD syntax; only strings may be language-tagged.', 'jsonld.SyntaxError', {code: 'invalid language-tagged value', element: rval}); - } else if(_processingMode(activeCtx, 1.1) && types.includes('@json') && - types.length === 1) { - // Any value of @value is okay if @type: @json } else if(!types.every(t => (_isAbsoluteIri(t) && !(_isString(t) && t.indexOf('_:') === 0) || _isEmptyObject(t)))) { @@ -402,11 +407,19 @@ async function _expandObject({ options = {}, insideList, typeScopedContext, + typeKey, expansionMap }) { const keys = Object.keys(element).sort(); const nests = []; let unexpandedValue; + + // Figure out if this is the type for a JSON literal + const isJsonType = element[typeKey] && + _expandIri(activeCtx, + (_isArray(element[typeKey]) ? element[typeKey][0] : element[typeKey]), + {vocab: true}, options) == '@json'; + for(const key of keys) { let value = element[key]; let expandedValue; @@ -517,8 +530,13 @@ async function _expandObject({ // capture value for later // "colliding keywords" check prevents this from being set twice unexpandedValue = value; - _addValue( - expandedParent, '@value', value, {propertyIsArray: options.isFrame}); + if(isJsonType && _processingMode(activeCtx, 1.1)) { + // no coercion to array, and retain all values + expandedParent['@value'] = value; + } else { + _addValue( + expandedParent, '@value', value, {propertyIsArray: options.isFrame}); + } continue; } @@ -803,6 +821,7 @@ async function _expandObject({ expandedParent, options, insideList, + typeKey, expansionMap}); } } diff --git a/tests/test-common.js b/tests/test-common.js index 81149cc1..d0a63ecc 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -42,8 +42,6 @@ const TEST_TYPES = { /compact-manifest.jsonld#tin03$/, /compact-manifest.jsonld#tin04$/, /compact-manifest.jsonld#tin05$/, - // @json null - /compact-manifest.jsonld#tjs11$/, // direction /compact-manifest.jsonld#tdi01$/, /compact-manifest.jsonld#tdi02$/, @@ -113,8 +111,6 @@ const TEST_TYPES = { /expand-manifest.jsonld#te044$/, /expand-manifest.jsonld#te048$/, /expand-manifest.jsonld#te049$/, - /expand-manifest.jsonld#tjs22$/, - /expand-manifest.jsonld#tjs23$/, // protected null IRI mapping /expand-manifest.jsonld#tpr28$/, // remote @@ -440,9 +436,6 @@ const TEST_TYPES = { /toRdf-manifest.jsonld#tdi10$/, /toRdf-manifest.jsonld#tdi11$/, /toRdf-manifest.jsonld#tdi12$/, - // JSON literal - /toRdf-manifest.jsonld#tjs22$/, - /toRdf-manifest.jsonld#tjs23$/, ] }, fn: 'toRDF',