Skip to content

WIP: Framing #365

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Feb 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,21 @@
- Keywords may not be used as prefixes.
- Handle term definition on `@type` with empty map.
- Handling of `@` values for `@reverse`.
- Changes in object embedding.
- Better support for graph framing.
- Better frame validation.
- Wildcard matching on `@id` and other `requireAll` semantics.

### Changed
- Keep term definitions mapping to null so they may be protected.
- **NOTE**: `LINK_HEADER_REL` in `lib/constants.js` has been deprecated and
renamed to `LINK_HEADER_CONTEXT`. It remains for now but will be removed in a
future release.
- Changed framing defaults
- `embed` to "@once" and warn on "@first" or "@last".
- `pruneBlankNodeIdentifiers` based on processingMode.
- `omitGraph` based on processingMode.
- Replaced `removePreserve` with `cleanupPreserve` and `cleanupNulls`.

### Added
- Support for `"@import"`.
Expand All @@ -30,6 +39,9 @@
- Support for expansion and compaction of values container `"@direction"`.
- Support for RDF transformation of `@direction` when `rdfDirection` is
'i18n-datatype'.
- Top level `@graph` omitted if `omitGraph` is `true`.
- Check for invalid values of `@embed`.
- Support default values for `@type` when framing.

## 2.0.2 - 2020-01-17

Expand Down
89 changes: 0 additions & 89 deletions lib/compact.js
Original file line number Diff line number Diff line change
Expand Up @@ -1067,95 +1067,6 @@ api.compactValue = ({activeCtx, activeProperty, value, options}) => {
};
};

/**
* Removes the @preserve keywords as the last step of the compaction
* algorithm when it is running on framed output.
*
* @param ctx the active context used to compact the input.
* @param input the framed, compacted output.
* @param options the compaction options used.
*
* @return the resulting output.
*/
api.removePreserve = (ctx, input, options) => {
// recurse through arrays
if(_isArray(input)) {
const output = [];
for(let i = 0; i < input.length; ++i) {
const result = api.removePreserve(ctx, input[i], options);
// drop nulls from arrays
if(result !== null) {
output.push(result);
}
}
input = output;
} else if(_isObject(input)) {
// remove @preserve
if('@preserve' in input) {
if(input['@preserve'] === '@null') {
return null;
}
return input['@preserve'];
}

// skip @values
if(_isValue(input)) {
return input;
}

// recurse through @lists
if(_isList(input)) {
input['@list'] = api.removePreserve(ctx, input['@list'], options);
return input;
}

// handle in-memory linked nodes
const idAlias = api.compactIri({
activeCtx: ctx,
iri: '@id',
relativeTo: {vocab: true}
});
if(input.hasOwnProperty(idAlias)) {
const id = input[idAlias];
if(options.link.hasOwnProperty(id)) {
const idx = options.link[id].indexOf(input);
if(idx !== -1) {
// already visited
return options.link[id][idx];
}
// prevent circular visitation
options.link[id].push(input);
} else {
// prevent circular visitation
options.link[id] = [input];
}
}

// recurse through properties
const graphAlias = api.compactIri({
activeCtx: ctx,
iri: '@graph',
relativeTo: {vocab: true}
});
for(const prop in input) {
// potentially remove the id, if it is an unreference bnode
if(prop === idAlias && options.bnodesToClear.includes(input[prop])) {
delete input[idAlias];
continue;
}

let result = api.removePreserve(ctx, input[prop], options);
const container = _getContextValue(ctx, prop, '@container') || [];
if(options.compactArrays && _isArray(result) && result.length === 1 &&
container.length === 0 && prop !== graphAlias) {
result = result[0];
}
input[prop] = result;
}
}
return input;
};

/**
* Picks the preferred compaction term from the given inverse context entry.
*
Expand Down
4 changes: 2 additions & 2 deletions lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -1284,12 +1284,12 @@ api.getContextValue = (ctx, key, type) => {
}

// get default language
if(type === '@language' && ctx.hasOwnProperty(type)) {
if(type === '@language' && type in ctx) {
return ctx[type];
}

// get default direction
if(type === '@direction' && ctx.hasOwnProperty(type)) {
if(type === '@direction' && type in ctx) {
return ctx[type];
}

Expand Down
15 changes: 12 additions & 3 deletions lib/expand.js
Original file line number Diff line number Diff line change
Expand Up @@ -466,8 +466,7 @@ async function _expandObject({
}
if(expandedProperty in expandedParent &&
expandedProperty !== '@included' &&
expandedProperty !== '@type')
{
expandedProperty !== '@type') {
throw new JsonLdError(
'Invalid JSON-LD syntax; colliding keywords detected.',
'jsonld.SyntaxError',
Expand Down Expand Up @@ -515,7 +514,17 @@ async function _expandObject({
}

if(expandedProperty === '@type') {
_validateTypeValue(value);
// if framing, can be a default object, but need to expand
// key to determine that
if(_isObject(value)) {
value = Object.fromEntries(Object.entries(value).map(([k, v]) => [
_expandIri(typeScopedContext, k, {vocab: true}),
_asArray(v).map(vv =>
_expandIri(typeScopedContext, vv, {base: true, vocab: true})
)
]));
}
_validateTypeValue(value, options.isFrame);
_addValue(
expandedParent, '@type',
_asArray(value).map(v =>
Expand Down
Loading