From 24046f70cb6bc82ef7be9235bc340df85a450c40 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Fri, 1 Sep 2023 16:30:25 -0400 Subject: [PATCH] Improve `@direction` support. - Support `compound-literal` `rdfDirection` option. - 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. --- CHANGELOG.md | 10 ++ lib/events.js | 4 +- lib/fromRdf.js | 97 +++++++++- lib/jsonld.js | 17 +- lib/toRdf.js | 122 ++++++++++++- tests/misc.js | 472 +++++++++++++++++++++++++++++++++++++++++++++++++ tests/test.js | 9 +- 7 files changed, 704 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fa20ff2c..69b231d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # jsonld ChangeLog +## 8.3.0 - 2023-09-xx + +### Added +- Support `compound-literal` `rdfDirection` option. +- 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 diff --git a/lib/events.js b/lib/events.js index 3dbd6046..8650b9f6 100644 --- a/lib/events.js +++ b/lib/events.js @@ -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 diff --git a/lib/fromRdf.js b/lib/fromRdf.js index afddfdb9..518b4e8c 100644 --- a/lib/fromRdf.js +++ b/lib/fromRdf.js @@ -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'; @@ -18,7 +18,7 @@ const { // constants const { - // RDF, + RDF, RDF_LIST, RDF_FIRST, RDF_REST, @@ -52,14 +52,30 @@ 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 = {}; + let processCompoundLiterals = false; + if(rdfDirection) { + if(rdfDirection === 'compound-literal') { + processCompoundLiterals = true; + } else if(rdfDirection !== 'i18n-datatype') { + throw new JsonLdError( + 'Unknown rdfDirection value.', + 'jsonld.InvalidRdfDirection', + {value: rdfDirection}); + } + } + let compoundLiteralSubjects; + if(processCompoundLiterals) { + compoundLiteralSubjects = {}; + } for(const quad of dataset) { // TODO: change 'name' to 'graph' @@ -68,11 +84,18 @@ api.fromRDF = async ( if(!(name in graphMap)) { graphMap[name] = {}; } + if(processCompoundLiterals && !(name in compoundLiteralSubjects)) { + compoundLiteralSubjects[name] = {}; + } if(name !== '@default' && !(name in defaultGraph)) { defaultGraph[name] = {'@id': name}; } const nodeMap = graphMap[name]; + let compoundMap; + if(processCompoundLiterals) { + compoundMap = compoundLiteralSubjects[name]; + } // get subject, predicate, object const s = quad.subject.value; @@ -83,6 +106,9 @@ api.fromRDF = async ( nodeMap[s] = {'@id': s}; } const node = nodeMap[s]; + if(processCompoundLiterals && p === RDF + 'direction') { + compoundMap[s] = true; + } const objectIsNode = o.termType.endsWith('Node'); if(objectIsNode && !(o.value in nodeMap)) { @@ -194,6 +220,64 @@ api.fromRDF = async ( for(const name in graphMap) { const graphObject = graphMap[name]; + if(processCompoundLiterals) { + if(name in compoundLiteralSubjects) { + const cls = compoundLiteralSubjects[name]; + for(const cl of Object.keys(cls)) { + const clEntry = referencedOnce[cl]; + if(!clEntry) { + continue; + } + const node = clEntry.node; + const property = clEntry.property; + //const value = clEntry.value; + const clNode = graphObject[cl]; + if(!types.isObject(clNode)) { + continue; + } + delete graphObject[cl]; + for(const clReference of node[property]) { + if(clReference['@id'] === cl) { + delete clReference['@id']; + } + const value = clNode[RDF + 'value']; + // FIXME: error on !== 1 value + clReference['@value'] = value[0]['@value']; + const language = clNode[RDF + 'language']; + if(language) { + // FIXME: error on !== 1 language value + const v = language[0]['@value']; + if(!v.match(REGEX_BCP47)) { + throw new JsonLdError( + 'Invalid RDF syntax; rdf:language must be valid BCP47.', + 'jsonld.SyntaxError', + { + code: 'invalid language-tagged string', + value: v + }); + } + clReference['@language'] = v; + } + const direction = clNode[RDF + 'direction']; + if(direction) { + // FIXME: error on !== 1 direction value + const v = direction[0]['@value']; + if(!(v === 'ltr' || v === 'rtl')) { + throw new JsonLdError( + 'Invalid RDF syntax; rdf:direction must be "ltr" or "rtl".', + 'jsonld.SyntaxError', + { + code: 'invalid base direction', + value: v + }); + } + clReference['@direction'] = v; + } + } + } + } + } + // no @lists to be converted, continue if(!(RDF_NIL in graphObject)) { continue; @@ -282,7 +366,8 @@ api.fromRDF = async ( * * @param o the RDF triple object to convert. * @param useNativeTypes true to output native types, false not to. - * @param rdfDirection text direction mode [null, i18n-datatype] + * @param rdfDirection text direction mode [null, i18n-datatype, + * compound-literal] * @param options top level API options * * @return the JSON-LD object. diff --git a/lib/jsonld.js b/lib/jsonld.js index ce9b868c..e24a5acc 100644 --- a/lib/jsonld.js +++ b/lib/jsonld.js @@ -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) @@ -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] 'i18n-datatype' or 'compound-literal' to support RDF + * transformation of @direction (default: null). * [safe] true to use safe mode. (default: true). * [contextResolver] internal use only. * @@ -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] 'i18n-datatype' or 'compound-literal' 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. @@ -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] 'i18n-datatype' or 'compound-literal' to support RDF + * transformation of @direction (default: null). * [contextResolver] internal use only. * * @return a Promise that resolves to the RDF dataset. diff --git a/lib/toRdf.js b/lib/toRdf.js index d823a97e..7c960f76 100644 --- a/lib/toRdf.js +++ b/lib/toRdf.js @@ -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'; @@ -7,6 +7,7 @@ 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'); @@ -15,7 +16,7 @@ const { } = require('./events'); const { - // RDF, + RDF, // RDF_LIST, RDF_FIRST, RDF_REST, @@ -312,18 +313,125 @@ 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') { + const language = (item['@language'] || '').toLowerCase(); + const direction = item['@direction']; + // blank node + object.termType = 'BlankNode'; + object.value = issuer.getId(); + object.datatype = undefined; + // value + dataset.push({ + subject: { + termType: object.termType, + value: object.value + }, + predicate: { + termType: 'NamedNode', + value: RDF + 'value' + }, + object: { + termType: 'Literal', + value, + datatype: { + termType: 'NamedNode', + value: XSD_STRING + } + }, + graph: graphTerm + }); + // language if preset + if(language !== '') { + dataset.push({ + subject: { + termType: object.termType, + value: object.value + }, + predicate: { + termType: 'NamedNode', + value: RDF + 'language' + }, + object: { + termType: 'Literal', + value: language, + datatype: { + termType: 'NamedNode', + value: XSD_STRING + } + }, + graph: graphTerm + }); + } + // direction + dataset.push({ + subject: { + termType: object.termType, + value: object.value + }, + predicate: { + termType: 'NamedNode', + value: RDF + 'direction' + }, + object: { + termType: 'Literal', + value: direction, + datatype: { + termType: 'NamedNode', + value: XSD_STRING + } + }, + graph: graphTerm + }); + } 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; } diff --git a/tests/misc.js b/tests/misc.js index d43d5817..a0c1a559 100644 --- a/tests/misc.js +++ b/tests/misc.js @@ -3631,6 +3631,83 @@ _:b0 "[null]"^^ . }); }); + // inputs/outputs for @direction+rdfDirection fromRDF/toRDF tests + const _json_dir_nl_nd = +[ + { + "@id": "urn:id", + "ex:p": [ + { + "@value": "v" + } + ] + } +] +; + const _json_dir_nl_d = +[ + { + "@id": "urn:id", + "ex:p": [ + { + "@direction": "ltr", + "@value": "v" + } + ] + } +] +; + const _json_dir_l_nd = +[ + { + "@id": "urn:id", + "ex:p": [ + { + "@language": "en-us", + "@value": "v" + } + ] + } +] +; + const _json_dir_l_d = +[ + { + "@id": "urn:id", + "ex:p": [ + { + "@direction": "ltr", + "@language": "en-us", + "@value": "v" + } + ] + } +] +; + const _nq_dir_nl_nd = `\ + "v" . +`; + const _nq_dir_l_nd_ls = `\ + "v"@en-us . +`; + const _nq_dir_nl_d_i18n = `\ + "v"^^ . +`; + const _nq_dir_l_d_i18n = `\ + "v"^^ . +`; + const _nq_dir_nl_d_cl = `\ + _:b0 . +_:b0 "ltr" . +_:b0 "v" . +`; + const _nq_dir_l_d_cl = `\ + _:b0 . +_:b0 "ltr" . +_:b0 "en-us" . +_:b0 "v" . +`; + describe('fromRDF', () => { it('should emit for invalid N-Quads @language value', async () => { // N-Quads with invalid language tag (too long) @@ -3724,6 +3801,135 @@ _:b0 "[null]"^^ . testNotSafe: true }); }); + + // 'should handle [no] @lang, [no] @dir, rdfDirection=null' + // no tests due to no special N-Quads handling + + // other tests only check that rdfDirection type of input + // tests mixing rdfDirection formats not tested + + it('should handle no @lang, no @dir, rdfDirection=i18n', async () => { + const input = _nq_dir_nl_nd; + const expected = _json_dir_nl_nd; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, no @dir, rdfDirection=c-l', async () => { + const input = _nq_dir_nl_nd; + const expected = _json_dir_nl_nd; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, @dir, rdfDirection=i18n', async () => { + const input = _nq_dir_nl_d_i18n; + const expected = _json_dir_nl_d; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, @dir, rdfDirection=c-l', async () => { + const input = _nq_dir_nl_d_cl; + const expected = _json_dir_nl_d; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, no @dir, rdfDirection=i18n', async () => { + const input = _nq_dir_l_nd_ls; + const expected = _json_dir_l_nd; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, no @dir, rdfDirection=c-l', async () => { + const input = _nq_dir_l_nd_ls; + const expected = _json_dir_l_nd; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, @dir, rdfDirection=i18n', async () => { + const input = _nq_dir_l_d_i18n; + const expected = _json_dir_l_d; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, @dir, rdfDirection=c-l', async () => { + const input = _nq_dir_l_d_cl; + const expected = _json_dir_l_d; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle bad rdfDirection', async () => { + const input = _nq_dir_l_d_i18n; + + await _test({ + type: 'fromRDF', + input, + options: {skipExpansion: true, rdfDirection: 'bogus'}, + exception: 'jsonld.InvalidRdfDirection' + }); + }); }); describe('toRDF', () => { @@ -3933,6 +4139,272 @@ _:b0 "v" . testSafe: true }); }); + + it('should handle no @lang, no @dir, rdfDirection=null', async () => { + const input = _json_dir_nl_nd; + const nq = _nq_dir_nl_nd; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: null}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, no @dir, rdfDirection=i18n', async () => { + const input = _json_dir_nl_nd; + const nq = _nq_dir_nl_nd; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, no @dir, rdfDirection=c-l', async () => { + const input = _json_dir_nl_nd; + const nq = _nq_dir_nl_nd; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, @dir, rdfDirection=null', async () => { + const input = _json_dir_nl_d; + const nq = _nq_dir_nl_nd; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: null}, + expected: nq, + eventCodeLog: [ + 'rdfDirection not set' + ], + testNotSafe: true + }); + }); + + it('should handle no @lang, @dir, rdfDirection=i18n', async () => { + const input = _json_dir_nl_d; + const nq = _nq_dir_nl_d_i18n; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle no @lang, @dir, rdfDirection=c-l', async () => { + const input = _json_dir_nl_d; + const nq = _nq_dir_nl_d_cl; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, no @dir, rdfDirection=null', async () => { + const input = _json_dir_l_nd; + const nq = _nq_dir_l_nd_ls; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: null}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, no @dir, rdfDirection=i18n', async () => { + const input = _json_dir_l_nd; + const nq = _nq_dir_l_nd_ls; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, no @dir, rdfDirection=c-l', async () => { + const input = _json_dir_l_nd; + const nq = _nq_dir_l_nd_ls; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, @dir, rdfDirection=null', async () => { + const input = _json_dir_l_d; + const nq = _nq_dir_l_nd_ls; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: null}, + expected: nq, + eventCodeLog: [ + 'rdfDirection not set' + ], + testNotSafe: true + }); + }); + + it('should handle @lang, @dir, rdfDirection=i18n', async () => { + const input = _json_dir_l_d; + const nq = _nq_dir_l_d_i18n; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'i18n-datatype'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle @lang, @dir, rdfDirection=c-l', async () => { + const input = _json_dir_l_d; + const nq = _nq_dir_l_d_cl; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'compound-literal'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle bad rdfDirection', async () => { + const input = _json_dir_l_d; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: true, rdfDirection: 'bogus'}, + exception: 'jsonld.InvalidRdfDirection' + }); + }); + + /* eslint-disable-next-line */ + // https://www.w3.org/TR/json-ld/#example-76-expanded-term-definition-with-language-and-direction + // simplified complex context example + const _ctx_dir_input = +{ + "@context": { + "@version": 1.1, + "@language": "ar-EG", + "@direction": "rtl", + "ex": "urn:ex:", + "publisher": {"@id": "ex:publisher", "@direction": null}, + "title": {"@id": "ex:title"}, + "title_en": {"@id": "ex:title", "@language": "en", "@direction": "ltr"} + }, + "publisher": "NULL", + "title": "RTL", + "title_en": "LTR" +} +; + + it('should handle ctx @lang/@dir/rdfDirection=null', async () => { + const input = _ctx_dir_input; + const nq = `\ +_:b0 "NULL"@ar-eg . +_:b0 "LTR"@en . +_:b0 "RTL"@ar-eg . +`; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: false, rdfDirection: null}, + expected: nq, + eventCodeLog: [ + 'rdfDirection not set', + 'rdfDirection not set' + ], + testNotSafe: true + }); + }); + + it('should handle ctx @lang/@dir/rdfDirection=i18n', async () => { + const input = _ctx_dir_input; + const nq = `\ +_:b0 "NULL"@ar-eg . +_:b0 "LTR"^^ . +_:b0 "RTL"^^ . +`; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: false, rdfDirection: 'i18n-datatype'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); + + it('should handle ctx @lang/@dir/rdfDirection=c-l', async () => { + const input = _ctx_dir_input; + const nq = `\ +_:b0 "NULL"@ar-eg . +_:b0 _:b1 . +_:b0 _:b2 . +_:b1 "rtl" . +_:b1 "ar-eg" . +_:b1 "RTL" . +_:b2 "ltr" . +_:b2 "en" . +_:b2 "LTR" . +`; + + await _test({ + type: 'toRDF', + input, + options: {skipExpansion: false, rdfDirection: 'compound-literal'}, + expected: nq, + eventCodeLog: [], + testSafe: true + }); + }); }); describe('various', () => { diff --git a/tests/test.js b/tests/test.js index f06676af..c463bb64 100644 --- a/tests/test.js +++ b/tests/test.js @@ -264,11 +264,7 @@ const TEST_TYPES = { // NOTE: idRegex format: // /MMM-manifest#tNNN$/, // FIXME - idRegex: [ - // direction (compound-literal) - /fromRdf-manifest#tdi11$/, - /fromRdf-manifest#tdi12$/, - ] + idRegex: [] }, fn: 'fromRDF', params: [ @@ -335,9 +331,6 @@ const TEST_TYPES = { /toRdf-manifest#te075$/, /toRdf-manifest#te111$/, /toRdf-manifest#te112$/, - // direction (compound-literal) - /toRdf-manifest#tdi11$/, - /toRdf-manifest#tdi12$/, ] }, fn: 'toRDF',