Skip to content

Commit 4f1f54c

Browse files
committed
* Indexing on an arbitrary property, not just @index.
1 parent 35edf3b commit 4f1f54c

File tree

5 files changed

+95
-33
lines changed

5 files changed

+95
-33
lines changed

lib/compact.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,31 @@ api.compact = async ({
520520
}
521521
key = expandedItem['@language'];
522522
} else if(container.includes('@index')) {
523-
key = expandedItem['@index'];
523+
const indexKey = _getContextValue(activeCtx, itemActiveProperty, '@index') || '@index';
524+
const containerKey = api.compactIri({activeCtx, iri: indexKey, vocab: true});
525+
if(indexKey === '@index') {
526+
key = expandedItem['@index'];
527+
delete compactedItem[containerKey];
528+
} else {
529+
let others;
530+
[key, ...others] = _asArray(compactedItem[indexKey] || []);
531+
if(!_isString(key)) {
532+
// Will use @none if it isn't a string.
533+
key = null;
534+
} else {
535+
switch(others.length) {
536+
case 0:
537+
delete compactedItem[indexKey];
538+
break;
539+
case 1:
540+
compactedItem[indexKey] = others[0];
541+
break;
542+
default:
543+
compactedItem[indexKey] = others;
544+
break;
545+
}
546+
}
547+
}
524548
} else if(container.includes('@id')) {
525549
const idKey = api.compactIri({activeCtx, iri: '@id', vocab: true});
526550
key = compactedItem[idKey];

lib/context.js

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ api.createTermDefinition = (
374374

375375
// JSON-LD 1.1 support
376376
if(api.processingMode(activeCtx, 1.1)) {
377-
validKeys.push('@context', '@nest', '@prefix', '@protected');
377+
validKeys.push('@context', '@index', '@nest', '@prefix', '@protected');
378378
}
379379

380380
for(const kw in value) {
@@ -608,6 +608,21 @@ api.createTermDefinition = (
608608
mapping['@container'] = container;
609609
}
610610

611+
// property indexing
612+
if('@index' in value) {
613+
if (!('@container' in value) || !mapping['@container'].includes('@index')) {
614+
throw new JsonLdError(
615+
'Invalid JSON-LD syntax; @index without @index in @container: ${value["@index"]} on term ${term}.', 'jsonld.SyntaxError',
616+
{code: 'invalid term definition', context: localCtx});
617+
}
618+
if (!_isString(value['@index']) || value['@index'].indexOf('@') === 0) {
619+
throw new JsonLdError(
620+
'Invalid JSON-LD syntax; "@index must expand to an IRI: ${value["@index"]} on term ${term}.', 'jsonld.SyntaxError',
621+
{code: 'invalid term definition', context: localCtx});
622+
}
623+
mapping['@index'] = value['@index']
624+
}
625+
611626
// scoped contexts
612627
if('@context' in value) {
613628
mapping['@context'] = value['@context'];

lib/expand.js

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -610,14 +610,19 @@ async function _expandObject({
610610
} else if(container.includes('@index') && _isObject(value)) {
611611
// handle index container (skip if value is not an object)
612612
const asGraph = container.includes('@graph');
613+
const indexKey = _getContextValue(termCtx, key, '@index') || '@index';
614+
const propertyIndex = indexKey !== '@index' &&
615+
_expandIri(activeCtx, indexKey, {vocab: true}, options);
616+
613617
expandedValue = await _expandIndexMap({
614618
activeCtx: termCtx,
615619
options,
616620
activeProperty: key,
617621
value,
618622
expansionMap,
619623
asGraph,
620-
indexKey: '@index'
624+
indexKey: indexKey,
625+
propertyIndex
621626
});
622627
} else if(container.includes('@id') && _isObject(value)) {
623628
// handle id container (skip if value is not an object)
@@ -890,7 +895,7 @@ function _expandLanguageMap(activeCtx, languageMap, options) {
890895

891896
async function _expandIndexMap(
892897
{activeCtx, options, activeProperty, value, expansionMap, asGraph,
893-
indexKey}) {
898+
indexKey, propertyIndex}) {
894899
const rval = [];
895900
const keys = Object.keys(value).sort();
896901
const isTypeIndex = indexKey === '@type';
@@ -913,15 +918,6 @@ async function _expandIndexMap(
913918
val = [val];
914919
}
915920

916-
// expand for @type, but also for @none
917-
const expandedKey = _expandIri(activeCtx, key, {vocab: true}, options);
918-
if(indexKey === '@id') {
919-
// expand document relative
920-
key = _expandIri(activeCtx, key, {base: true}, options);
921-
} else if(isTypeIndex) {
922-
key = expandedKey;
923-
}
924-
925921
val = await api.expand({
926922
activeCtx,
927923
activeProperty,
@@ -931,6 +927,26 @@ async function _expandIndexMap(
931927
insideIndex: true,
932928
expansionMap
933929
});
930+
931+
// expand for @type, but also for @none
932+
let expandedKey;
933+
if(propertyIndex) {
934+
if(key === '@none') {
935+
expandedKey = '@none'
936+
} else {
937+
expandedKey =_expandValue({activeCtx, activeProperty: indexKey, value: key, options});
938+
}
939+
} else {
940+
expandedKey = _expandIri(activeCtx, key, {vocab: true}, options);
941+
}
942+
943+
if(indexKey === '@id') {
944+
// expand document relative
945+
key = _expandIri(activeCtx, key, {base: true}, options);
946+
} else if(isTypeIndex) {
947+
key = expandedKey;
948+
}
949+
934950
for(let item of val) {
935951
// If this is also a @graph container, turn items into graphs
936952
if(asGraph && !_isGraph(item)) {
@@ -944,6 +960,20 @@ async function _expandIndexMap(
944960
} else {
945961
item['@type'] = [key];
946962
}
963+
} else if(_isValue(item) && !['@language', '@type', '@index'].includes(indexKey)) {
964+
throw new JsonLdError(
965+
'Invalid JSON-LD syntax; Attempt to add illegal key to value object: ${indexKey}.',
966+
'jsonld.SyntaxError',
967+
{code: 'invalid value object', value: item});
968+
} else if(propertyIndex) {
969+
// index is a property to be expanded, and values interpreted for that property
970+
if(expandedKey !== '@none') {
971+
// expand key as a value
972+
_addValue(item, propertyIndex, expandedKey, {
973+
propertyIsArray: true,
974+
prependValue: true
975+
});
976+
}
947977
} else if(expandedKey !== '@none' && !(indexKey in item)) {
948978
item[indexKey] = key;
949979
}

lib/util.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ api.hasValue = (subject, property, value) => {
234234
* an array (lists) (default: false).
235235
* [allowDuplicate] true to allow duplicates, false not to (uses a
236236
* simple shallow comparison of subject ID or value) (default: true).
237+
* [prependValue] false to prepend value to any existing values. (default: false)
237238
*/
238239
api.addValue = (subject, property, value, options) => {
239240
options = options || {};
@@ -246,6 +247,9 @@ api.addValue = (subject, property, value, options) => {
246247
if(!('allowDuplicate' in options)) {
247248
options.allowDuplicate = true;
248249
}
250+
if(!('prependValue' in options)) {
251+
options.prependValue = false;
252+
}
249253

250254
if(options.valueIsArray) {
251255
subject[property] = value;
@@ -254,6 +258,10 @@ api.addValue = (subject, property, value, options) => {
254258
!subject.hasOwnProperty(property)) {
255259
subject[property] = [];
256260
}
261+
if(options.prependValue) {
262+
value = value.concat(subject[property]);
263+
subject[property] = [];
264+
}
257265
for(let i = 0; i < value.length; ++i) {
258266
api.addValue(subject, property, value[i], options);
259267
}
@@ -270,7 +278,11 @@ api.addValue = (subject, property, value, options) => {
270278

271279
// add new value
272280
if(!hasValue) {
273-
subject[property].push(value);
281+
if(options.prependValue) {
282+
subject[property].unshift(value)
283+
} else {
284+
subject[property].push(value);
285+
}
274286
}
275287
} else {
276288
// add new value as set or single value

tests/test-common.js

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -45,13 +45,6 @@ const TEST_TYPES = {
4545
/compact-manifest.jsonld#ttn01$/,
4646
/compact-manifest.jsonld#ttn02$/,
4747
/compact-manifest.jsonld#ttn03$/,
48-
// property-valued indexes
49-
/compact-manifest.jsonld#tpi01$/,
50-
/compact-manifest.jsonld#tpi02$/,
51-
/compact-manifest.jsonld#tpi03$/,
52-
/compact-manifest.jsonld#tpi04$/,
53-
/compact-manifest.jsonld#tpi05$/,
54-
/compact-manifest.jsonld#tpi06$/,
5548
// IRI confusion
5649
/compact-manifest.jsonld#te002$/,
5750
// @propogate
@@ -157,18 +150,6 @@ const TEST_TYPES = {
157150
/expand-manifest.jsonld#thc05$/,
158151
// @type: @none
159152
/expand-manifest.jsonld#ttn02$/,
160-
// property index maps
161-
/expand-manifest.jsonld#tpi01$/,
162-
/expand-manifest.jsonld#tpi02$/,
163-
/expand-manifest.jsonld#tpi03$/,
164-
/expand-manifest.jsonld#tpi04$/,
165-
/expand-manifest.jsonld#tpi05$/,
166-
/expand-manifest.jsonld#tpi06$/,
167-
/expand-manifest.jsonld#tpi07$/,
168-
/expand-manifest.jsonld#tpi08$/,
169-
/expand-manifest.jsonld#tpi09$/,
170-
/expand-manifest.jsonld#tpi10$/,
171-
/expand-manifest.jsonld#tpi11$/,
172153
// misc
173154
/expand-manifest.jsonld#te043$/,
174155
/expand-manifest.jsonld#te044$/,

0 commit comments

Comments
 (0)