Skip to content

Commit

Permalink
Improve @direction support.
Browse files Browse the repository at this point in the history
- Emit `toRdf` warning if `@direction` is used and `rdfDirection` is not
  set.
- Add safe mode support for `@direction`. Using `@direction` without
  `rdfDirection` set will cause a safe mode failure.
- Add tests.
  • Loading branch information
davidlehn committed Sep 7, 2023
1 parent d12ccd9 commit 8f9f888
Show file tree
Hide file tree
Showing 7 changed files with 419 additions and 16 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# jsonld ChangeLog

## 8.3.0 - 2023-09-xx

### Added
- Emit `toRdf` warning if `@direction` is used and `rdfDirection` is not set.

### Fixed
- Add safe mode support for `@direction`. Using `@direction` without
`rdfDirection` set will cause a safe mode failure.

## 8.2.1 - 2023-08-31

### Fixed
Expand Down
4 changes: 3 additions & 1 deletion lib/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ const _notSafeEventCodes = new Set([
'relative graph reference',
'relative object reference',
'relative predicate reference',
'relative subject reference'
'relative subject reference',
// toRDF / fromRDF
'rdfDirection not set'
]);

// safe handler that rejects unsafe warning conditions
Expand Down
22 changes: 18 additions & 4 deletions lib/fromRdf.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2017-2023 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

Expand Down Expand Up @@ -52,14 +52,28 @@ api.fromRDF = async (
dataset,
options
) => {
const defaultGraph = {};
const graphMap = {'@default': defaultGraph};
const referencedOnce = {};
const {
useRdfType = false,
useNativeTypes = false,
rdfDirection = null
} = options;
// FIXME: use Maps?
const defaultGraph = {};
const graphMap = {'@default': defaultGraph};
const referencedOnce = {};
if(rdfDirection) {
if(rdfDirection === 'compound-literal') {
throw new JsonLdError(
'Unsupported rdfDirection value.',
'jsonld.InvalidRdfDirection',
{value: rdfDirection});
} else if(rdfDirection !== 'i18n-datatype') {
throw new JsonLdError(
'Unknown rdfDirection value.',
'jsonld.InvalidRdfDirection',
{value: rdfDirection});
}
}

for(const quad of dataset) {
// TODO: change 'name' to 'graph'
Expand Down
17 changes: 12 additions & 5 deletions lib/jsonld.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ const _resolvedContextCache = new LRU({max: RESOLVED_CONTEXT_CACHE_MAX_SIZE});
* [graph] true to always output a top-level graph (default: false).
* [expandContext] a context to expand with.
* [skipExpansion] true to assume the input is expanded and skip
* expansion, false not to, defaults to false.
* expansion, false not to, defaults to false. Some well-formed
* and safe-mode checks may be omitted.
* [documentLoader(url, options)] the document loader.
* [framing] true if compaction is occuring during a framing operation.
* [safe] true to use safe mode. (default: false)
Expand Down Expand Up @@ -538,13 +539,16 @@ jsonld.link = async function(input, ctx, options) {
* [base] the base IRI to use (default: `null`).
* [expandContext] a context to expand with.
* [skipExpansion] true to assume the input is expanded and skip
* expansion, false not to, defaults to false.
* expansion, false not to, defaults to false. Some well-formed
* and safe-mode checks may be omitted.
* [inputFormat] the format if input is not JSON-LD:
* 'application/n-quads' for N-Quads.
* [format] the format if output is a string:
* 'application/n-quads' for N-Quads.
* [documentLoader(url, options)] the document loader.
* [useNative] true to use a native canonize algorithm
* [rdfDirection] null or 'i18n-datatype' to support RDF
* transformation of @direction (default: null).
* [safe] true to use safe mode. (default: true).
* [contextResolver] internal use only.
*
Expand Down Expand Up @@ -601,8 +605,8 @@ jsonld.normalize = jsonld.canonize = async function(input, options) {
* (default: false).
* [useNativeTypes] true to convert XSD types into native types
* (boolean, integer, double), false not to (default: false).
* [rdfDirection] 'i18n-datatype' to support RDF transformation of
* @direction (default: null).
* [rdfDirection] null or 'i18n-datatype' to support RDF
* transformation of @direction (default: null).
* [safe] true to use safe mode. (default: false)
*
* @return a Promise that resolves to the JSON-LD document.
Expand Down Expand Up @@ -647,13 +651,16 @@ jsonld.fromRDF = async function(dataset, options) {
* [base] the base IRI to use.
* [expandContext] a context to expand with.
* [skipExpansion] true to assume the input is expanded and skip
* expansion, false not to, defaults to false.
* expansion, false not to, defaults to false. Some well-formed
* and safe-mode checks may be omitted.
* [format] the format to use to output a string:
* 'application/n-quads' for N-Quads.
* [produceGeneralizedRdf] true to output generalized RDF, false
* to produce only standard RDF (default: false).
* [documentLoader(url, options)] the document loader.
* [safe] true to use safe mode. (default: false)
* [rdfDirection] null or 'i18n-datatype' to support RDF
* transformation of @direction (default: null).
* [contextResolver] internal use only.
*
* @return a Promise that resolves to the RDF dataset.
Expand Down
56 changes: 50 additions & 6 deletions lib/toRdf.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
/*
* Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2017-2023 Digital Bazaar, Inc. All rights reserved.
*/
'use strict';

const {createNodeMap} = require('./nodeMap');
const {isKeyword} = require('./context');
const graphTypes = require('./graphTypes');
const jsonCanonicalize = require('canonicalize');
const JsonLdError = require('./JsonLdError');
const types = require('./types');
const util = require('./util');

Expand Down Expand Up @@ -312,18 +313,61 @@ function _objectToRDF(
} else if(types.isNumber(value)) {
object.value = value.toFixed(0);
object.datatype.value = datatype || XSD_INTEGER;
} else if(rdfDirection === 'i18n-datatype' &&
'@direction' in item) {
const datatype = 'https://www.w3.org/ns/i18n#' +
(item['@language'] || '') +
`_${item['@direction']}`;
} else if('@direction' in item && rdfDirection === 'i18n-datatype') {
const language = (item['@language'] || '').toLowerCase();
const direction = item['@direction'];
const datatype = `https://www.w3.org/ns/i18n#${language}_${direction}`;
object.datatype.value = datatype;
object.value = value;
} else if('@direction' in item && rdfDirection === 'compound-literal') {
throw new JsonLdError(
'Unsupported rdfDirection value.',
'jsonld.InvalidRdfDirection',
{value: rdfDirection});
} else if('@direction' in item && rdfDirection) {
throw new JsonLdError(
'Unknown rdfDirection value.',
'jsonld.InvalidRdfDirection',
{value: rdfDirection});
} else if('@language' in item) {
if('@direction' in item && rdfDirection === null) {
if(options.eventHandler) {
// FIXME: only emit once?
_handleEvent({
event: {
type: ['JsonLdEvent'],
code: 'rdfDirection not set',
level: 'warning',
message: 'rdfDirection not set for @direction.',
details: {
object: object.value
}
},
options
});
}
}
object.value = value;
object.datatype.value = datatype || RDF_LANGSTRING;
object.language = item['@language'];
} else {
if('@direction' in item && rdfDirection === null) {
if(options.eventHandler) {
// FIXME: only emit once?
_handleEvent({
event: {
type: ['JsonLdEvent'],
code: 'rdfDirection not set',
level: 'warning',
message: 'rdfDirection not set for @direction.',
details: {
object: object.value
}
},
options
});
}
}
object.value = value;
object.datatype.value = datatype || XSD_STRING;
}
Expand Down
Loading

0 comments on commit 8f9f888

Please sign in to comment.