Skip to content

Commit e1e4a4e

Browse files
gkelloggdavidlehn
authored andcommitted
Replace removePreserve.
Replaced removePreserve with cleanupPreserve and cleanupNulls.
1 parent a121a8e commit e1e4a4e

File tree

3 files changed

+110
-90
lines changed

3 files changed

+110
-90
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
- `embed` to "@once" and warn on "@first" or "@last".
2929
- `pruneBlankNodeIdentifiers` based on processingMode.
3030
- `omitGraph` based on processingMode.
31+
- replaced removePreserve with cleanupPreserve and cleanupNulls
3132

3233
### Added
3334
- Support for `"@import"`.

lib/compact.js

Lines changed: 0 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1067,95 +1067,6 @@ api.compactValue = ({activeCtx, activeProperty, value, options}) => {
10671067
};
10681068
};
10691069

1070-
/**
1071-
* Removes the @preserve keywords as the last step of the compaction
1072-
* algorithm when it is running on framed output.
1073-
*
1074-
* @param ctx the active context used to compact the input.
1075-
* @param input the framed, compacted output.
1076-
* @param options the compaction options used.
1077-
*
1078-
* @return the resulting output.
1079-
*/
1080-
api.removePreserve = (ctx, input, options) => {
1081-
// recurse through arrays
1082-
if(_isArray(input)) {
1083-
const output = [];
1084-
for(let i = 0; i < input.length; ++i) {
1085-
const result = api.removePreserve(ctx, input[i], options);
1086-
// drop nulls from arrays
1087-
if(result !== null) {
1088-
output.push(result);
1089-
}
1090-
}
1091-
input = output;
1092-
} else if(_isObject(input)) {
1093-
// remove @preserve
1094-
if('@preserve' in input) {
1095-
if(input['@preserve'] === '@null') {
1096-
return null;
1097-
}
1098-
return input['@preserve'];
1099-
}
1100-
1101-
// skip @values
1102-
if(_isValue(input)) {
1103-
return input;
1104-
}
1105-
1106-
// recurse through @lists
1107-
if(_isList(input)) {
1108-
input['@list'] = api.removePreserve(ctx, input['@list'], options);
1109-
return input;
1110-
}
1111-
1112-
// handle in-memory linked nodes
1113-
const idAlias = api.compactIri({
1114-
activeCtx: ctx,
1115-
iri: '@id',
1116-
relativeTo: {vocab: true}
1117-
});
1118-
if(input.hasOwnProperty(idAlias)) {
1119-
const id = input[idAlias];
1120-
if(options.link.hasOwnProperty(id)) {
1121-
const idx = options.link[id].indexOf(input);
1122-
if(idx !== -1) {
1123-
// already visited
1124-
return options.link[id][idx];
1125-
}
1126-
// prevent circular visitation
1127-
options.link[id].push(input);
1128-
} else {
1129-
// prevent circular visitation
1130-
options.link[id] = [input];
1131-
}
1132-
}
1133-
1134-
// recurse through properties
1135-
const graphAlias = api.compactIri({
1136-
activeCtx: ctx,
1137-
iri: '@graph',
1138-
relativeTo: {vocab: true}
1139-
});
1140-
for(const prop in input) {
1141-
// potentially remove the id, if it is an unreference bnode
1142-
if(prop === idAlias && options.bnodesToClear.includes(input[prop])) {
1143-
delete input[idAlias];
1144-
continue;
1145-
}
1146-
1147-
let result = api.removePreserve(ctx, input[prop], options);
1148-
const container = _getContextValue(ctx, prop, '@container') || [];
1149-
if(options.compactArrays && _isArray(result) && result.length === 1 &&
1150-
container.length === 0 && prop !== graphAlias) {
1151-
result = result[0];
1152-
}
1153-
input[prop] = result;
1154-
}
1155-
}
1156-
return input;
1157-
};
1158-
11591070
/**
11601071
* Picks the preferred compaction term from the given inverse context entry.
11611072
*

lib/frame.js

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ api.frameMergedOrDefault = (input, frame, options) => {
5959
Object.keys(state.bnodeMap).filter(id => state.bnodeMap[id].length === 1);
6060
}
6161

62-
return framed;
62+
// remove @preserve from results
63+
options.link = {};
64+
return _cleanupPreserve(framed, options);
6365
};
6466

6567
/**
@@ -316,6 +318,50 @@ api.frame = (state, subjects, frame, parent, property = null) => {
316318
}
317319
};
318320

321+
/**
322+
* Replace `@null` with `null`, removing it from arrays.
323+
*
324+
* @param input the framed, compacted output.
325+
* @param options the framing options used.
326+
*
327+
* @return the resulting output.
328+
*/
329+
api.cleanupNull = (input, options) => {
330+
// recurse through arrays
331+
if(types.isArray(input)) {
332+
const noNulls = input.map(v => api.cleanupNull(v, options));
333+
return noNulls.filter(v => v); // removes nulls from array
334+
}
335+
336+
if(input === '@null') {
337+
return null;
338+
}
339+
340+
if(types.isObject(input)) {
341+
// handle in-memory linked nodes
342+
if(input.hasOwnProperty('@id')) {
343+
const id = input['@id'];
344+
if(options.link.hasOwnProperty(id)) {
345+
const idx = options.link[id].indexOf(input);
346+
if(idx !== -1) {
347+
// already visited
348+
return options.link[id][idx];
349+
}
350+
// prevent circular visitation
351+
options.link[id].push(input);
352+
} else {
353+
// prevent circular visitation
354+
options.link[id] = [input];
355+
}
356+
}
357+
358+
for(const key in input) {
359+
input[key] = api.cleanupNull(input[key], options);
360+
}
361+
}
362+
return input;
363+
};
364+
319365
/**
320366
* Creates an implicit frame when recursing through subject matches. If
321367
* a frame doesn't have an explicit frame for a particular property, then
@@ -614,6 +660,68 @@ function _removeEmbed(state, id) {
614660
removeDependents(id);
615661
}
616662

663+
/**
664+
* Removes the @preserve keywords from expanded result of framing.
665+
*
666+
* @param input the framed, framed output.
667+
* @param options the framing options used.
668+
*
669+
* @return the resulting output.
670+
*/
671+
function _cleanupPreserve(input, options) {
672+
// recurse through arrays
673+
if(types.isArray(input)) {
674+
return input.map(value => _cleanupPreserve(value, options));
675+
}
676+
677+
if(types.isObject(input)) {
678+
// remove @preserve
679+
if('@preserve' in input) {
680+
return input['@preserve'][0];
681+
}
682+
683+
// skip @values
684+
if(graphTypes.isValue(input)) {
685+
return input;
686+
}
687+
688+
// recurse through @lists
689+
if(graphTypes.isList(input)) {
690+
input['@list'] = _cleanupPreserve(input['@list'], options);
691+
return input;
692+
}
693+
694+
// handle in-memory linked nodes
695+
if(input.hasOwnProperty('@id')) {
696+
const id = input['@id'];
697+
if(options.link.hasOwnProperty(id)) {
698+
const idx = options.link[id].indexOf(input);
699+
if(idx !== -1) {
700+
// already visited
701+
return options.link[id][idx];
702+
}
703+
// prevent circular visitation
704+
options.link[id].push(input);
705+
} else {
706+
// prevent circular visitation
707+
options.link[id] = [input];
708+
}
709+
}
710+
711+
// recurse through properties
712+
for(const prop in input) {
713+
// potentially remove the id, if it is an unreference bnode
714+
if(prop === '@id' && options.bnodesToClear.includes(input[prop])) {
715+
delete input['@id'];
716+
continue;
717+
}
718+
719+
input[prop] = _cleanupPreserve(input[prop], options);
720+
}
721+
}
722+
return input;
723+
};
724+
617725
/**
618726
* Adds framing output to the given parent.
619727
*

0 commit comments

Comments
 (0)