Skip to content

Commit 3754a2c

Browse files
committed
Improve @direction support.
- 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.
1 parent 78d1ab6 commit 3754a2c

File tree

7 files changed

+419
-16
lines changed

7 files changed

+419
-16
lines changed

Diff for: CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
# jsonld ChangeLog
22

3+
## 8.3.0 - 2023-09-xx
4+
5+
### Added
6+
- Emit `toRdf` warning if `@direction` is used and `rdfDirection` is not set.
7+
8+
### Fixed
9+
- Add safe mode support for `@direction`. Using `@direction` without
10+
`rdfDirection` set will cause a safe mode failure.
11+
312
## 8.2.1 - 2023-08-31
413

514
### Fixed

Diff for: lib/events.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,9 @@ const _notSafeEventCodes = new Set([
123123
'relative graph reference',
124124
'relative object reference',
125125
'relative predicate reference',
126-
'relative subject reference'
126+
'relative subject reference',
127+
// toRDF / fromRDF
128+
'rdfDirection not set'
127129
]);
128130

129131
// safe handler that rejects unsafe warning conditions

Diff for: lib/fromRdf.js

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.
2+
* Copyright (c) 2017-2023 Digital Bazaar, Inc. All rights reserved.
33
*/
44
'use strict';
55

@@ -52,14 +52,28 @@ api.fromRDF = async (
5252
dataset,
5353
options
5454
) => {
55-
const defaultGraph = {};
56-
const graphMap = {'@default': defaultGraph};
57-
const referencedOnce = {};
5855
const {
5956
useRdfType = false,
6057
useNativeTypes = false,
6158
rdfDirection = null
6259
} = options;
60+
// FIXME: use Maps?
61+
const defaultGraph = {};
62+
const graphMap = {'@default': defaultGraph};
63+
const referencedOnce = {};
64+
if(rdfDirection) {
65+
if(rdfDirection === 'compound-literal') {
66+
throw new JsonLdError(
67+
'Unsupported rdfDirection value.',
68+
'jsonld.InvalidRdfDirection',
69+
{value: rdfDirection});
70+
} else if(rdfDirection !== 'i18n-datatype') {
71+
throw new JsonLdError(
72+
'Unknown rdfDirection value.',
73+
'jsonld.InvalidRdfDirection',
74+
{value: rdfDirection});
75+
}
76+
}
6377

6478
for(const quad of dataset) {
6579
// TODO: change 'name' to 'graph'

Diff for: lib/jsonld.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ const _resolvedContextCache = new LRU({max: RESOLVED_CONTEXT_CACHE_MAX_SIZE});
118118
* [graph] true to always output a top-level graph (default: false).
119119
* [expandContext] a context to expand with.
120120
* [skipExpansion] true to assume the input is expanded and skip
121-
* expansion, false not to, defaults to false.
121+
* expansion, false not to, defaults to false. Some well-formed
122+
* and safe-mode checks may be omitted.
122123
* [documentLoader(url, options)] the document loader.
123124
* [framing] true if compaction is occuring during a framing operation.
124125
* [safe] true to use safe mode. (default: false)
@@ -538,13 +539,16 @@ jsonld.link = async function(input, ctx, options) {
538539
* [base] the base IRI to use (default: `null`).
539540
* [expandContext] a context to expand with.
540541
* [skipExpansion] true to assume the input is expanded and skip
541-
* expansion, false not to, defaults to false.
542+
* expansion, false not to, defaults to false. Some well-formed
543+
* and safe-mode checks may be omitted.
542544
* [inputFormat] the format if input is not JSON-LD:
543545
* 'application/n-quads' for N-Quads.
544546
* [format] the format if output is a string:
545547
* 'application/n-quads' for N-Quads.
546548
* [documentLoader(url, options)] the document loader.
547549
* [useNative] true to use a native canonize algorithm
550+
* [rdfDirection] null or 'i18n-datatype' to support RDF
551+
* transformation of @direction (default: null).
548552
* [safe] true to use safe mode. (default: true).
549553
* [contextResolver] internal use only.
550554
*
@@ -601,8 +605,8 @@ jsonld.normalize = jsonld.canonize = async function(input, options) {
601605
* (default: false).
602606
* [useNativeTypes] true to convert XSD types into native types
603607
* (boolean, integer, double), false not to (default: false).
604-
* [rdfDirection] 'i18n-datatype' to support RDF transformation of
605-
* @direction (default: null).
608+
* [rdfDirection] null or 'i18n-datatype' to support RDF
609+
* transformation of @direction (default: null).
606610
* [safe] true to use safe mode. (default: false)
607611
*
608612
* @return a Promise that resolves to the JSON-LD document.
@@ -647,13 +651,16 @@ jsonld.fromRDF = async function(dataset, options) {
647651
* [base] the base IRI to use.
648652
* [expandContext] a context to expand with.
649653
* [skipExpansion] true to assume the input is expanded and skip
650-
* expansion, false not to, defaults to false.
654+
* expansion, false not to, defaults to false. Some well-formed
655+
* and safe-mode checks may be omitted.
651656
* [format] the format to use to output a string:
652657
* 'application/n-quads' for N-Quads.
653658
* [produceGeneralizedRdf] true to output generalized RDF, false
654659
* to produce only standard RDF (default: false).
655660
* [documentLoader(url, options)] the document loader.
656661
* [safe] true to use safe mode. (default: false)
662+
* [rdfDirection] null or 'i18n-datatype' to support RDF
663+
* transformation of @direction (default: null).
657664
* [contextResolver] internal use only.
658665
*
659666
* @return a Promise that resolves to the RDF dataset.

Diff for: lib/toRdf.js

+50-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
/*
2-
* Copyright (c) 2017 Digital Bazaar, Inc. All rights reserved.
2+
* Copyright (c) 2017-2023 Digital Bazaar, Inc. All rights reserved.
33
*/
44
'use strict';
55

66
const {createNodeMap} = require('./nodeMap');
77
const {isKeyword} = require('./context');
88
const graphTypes = require('./graphTypes');
99
const jsonCanonicalize = require('canonicalize');
10+
const JsonLdError = require('./JsonLdError');
1011
const types = require('./types');
1112
const util = require('./util');
1213

@@ -312,18 +313,61 @@ function _objectToRDF(
312313
} else if(types.isNumber(value)) {
313314
object.value = value.toFixed(0);
314315
object.datatype.value = datatype || XSD_INTEGER;
315-
} else if(rdfDirection === 'i18n-datatype' &&
316-
'@direction' in item) {
317-
const datatype = 'https://www.w3.org/ns/i18n#' +
318-
(item['@language'] || '') +
319-
`_${item['@direction']}`;
316+
} else if('@direction' in item && rdfDirection === 'i18n-datatype') {
317+
const language = (item['@language'] || '').toLowerCase();
318+
const direction = item['@direction'];
319+
const datatype = `https://www.w3.org/ns/i18n#${language}_${direction}`;
320320
object.datatype.value = datatype;
321321
object.value = value;
322+
} else if('@direction' in item && rdfDirection === 'compound-literal') {
323+
throw new JsonLdError(
324+
'Unsupported rdfDirection value.',
325+
'jsonld.InvalidRdfDirection',
326+
{value: rdfDirection});
327+
} else if('@direction' in item && rdfDirection) {
328+
throw new JsonLdError(
329+
'Unknown rdfDirection value.',
330+
'jsonld.InvalidRdfDirection',
331+
{value: rdfDirection});
322332
} else if('@language' in item) {
333+
if('@direction' in item && rdfDirection === null) {
334+
if(options.eventHandler) {
335+
// FIXME: only emit once?
336+
_handleEvent({
337+
event: {
338+
type: ['JsonLdEvent'],
339+
code: 'rdfDirection not set',
340+
level: 'warning',
341+
message: 'rdfDirection not set for @direction.',
342+
details: {
343+
object: object.value
344+
}
345+
},
346+
options
347+
});
348+
}
349+
}
323350
object.value = value;
324351
object.datatype.value = datatype || RDF_LANGSTRING;
325352
object.language = item['@language'];
326353
} else {
354+
if('@direction' in item && rdfDirection === null) {
355+
if(options.eventHandler) {
356+
// FIXME: only emit once?
357+
_handleEvent({
358+
event: {
359+
type: ['JsonLdEvent'],
360+
code: 'rdfDirection not set',
361+
level: 'warning',
362+
message: 'rdfDirection not set for @direction.',
363+
details: {
364+
object: object.value
365+
}
366+
},
367+
options
368+
});
369+
}
370+
}
327371
object.value = value;
328372
object.datatype.value = datatype || XSD_STRING;
329373
}

0 commit comments

Comments
 (0)