Skip to content
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# jsonld ChangeLog

### Added
- Support literal JSON.
- **NOTE**: The JSON serialization is based on the JSON Canonicalization
Scheme (JCS) drafts. Changes in the JCS algorithm could cause changes in
the `toRdf` output.

## 1.7.0 - 2019-08-30

### Added
Expand Down
1 change: 1 addition & 0 deletions lib/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ module.exports = {
RDF_TYPE: RDF + 'type',
RDF_PLAIN_LITERAL: RDF + 'PlainLiteral',
RDF_XML_LITERAL: RDF + 'XMLLiteral',
RDF_JSON_LITERAL: RDF + 'JSON',
RDF_OBJECT: RDF + 'object',
RDF_LANGSTRING: RDF + 'langString',

Expand Down
3 changes: 2 additions & 1 deletion lib/context.js
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ api.createTermDefinition = (
{code: 'invalid type mapping', context: localCtx});
}

if(type !== '@id' && type !== '@vocab') {
if(type !== '@id' && type !== '@vocab' && type !== '@json') {
// expand @type to full IRI
type = _expandIri(
activeCtx, type, {vocab: true, base: false}, localCtx, defined,
Expand Down Expand Up @@ -1114,6 +1114,7 @@ api.isKeyword = v => {
case '@graph':
case '@id':
case '@index':
case '@json':
case '@language':
case '@list':
case '@nest':
Expand Down
34 changes: 24 additions & 10 deletions lib/expand.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ const {
expandIri: _expandIri,
getContextValue: _getContextValue,
isKeyword: _isKeyword,
process: _processContext
process: _processContext,
processingMode: _processingMode
} = require('./context');

const {
Expand Down Expand Up @@ -289,6 +290,8 @@ api.expand = ({
'Invalid JSON-LD syntax; only strings may be language-tagged.',
'jsonld.SyntaxError',
{code: 'invalid language-tagged value', element: rval});
} else if(_processingMode(activeCtx, 1.1) && types.includes('@json') && types.length === 1) {
// Any value of @value is okay if @type: @json
} else if(!types.every(t =>
(_isAbsoluteIri(t) && !(_isString(t) && t.indexOf('_:') === 0) ||
_isEmptyObject(t)))) {
Expand Down Expand Up @@ -494,16 +497,7 @@ function _expandObject({
'jsonld.SyntaxError', {code: 'invalid @graph value', value});
}

// @value must not be an object or an array (unless framing)
if(expandedProperty === '@value') {
if((_isObject(value) || _isArray(value)) && !options.isFrame) {
throw new JsonLdError(
'Invalid JSON-LD syntax; "@value" value must not be an ' +
'object or an array.',
'jsonld.SyntaxError',
{code: 'invalid value object value', value});
}

_addValue(
expandedParent, '@value', value, {propertyIsArray: options.isFrame});
continue;
Expand Down Expand Up @@ -669,6 +663,12 @@ function _expandObject({
insideList: isList,
expansionMap
});
} else if(
_getContextValue(activeCtx, key, '@type') === '@json') {
expandedValue = {
'@type': '@json',
'@value': value
};
} else {
// recursively expand value with key as new active property
expandedValue = api.expand({
Expand Down Expand Up @@ -747,6 +747,20 @@ function _expandObject({
});
}

// @value must not be an object or an array (unless framing) or if @type is @json
if('@value' in element) {
const value = element['@value'];
if(element['@type'] === '@json' && _processingMode(activeCtx, 1.1)) {
// allow any value, to be verified when the object is fully expanded and the @type is @json.
} else if((_isObject(value) || _isArray(value)) && !options.isFrame) {
throw new JsonLdError(
'Invalid JSON-LD syntax; "@value" value must not be an ' +
'object or an array.',
'jsonld.SyntaxError',
{code: 'invalid value object value', value});
}
}

// expand each nested key
for(const key of nests) {
const nestedValues = _isArray(element[key]) ? element[key] : [element[key]];
Expand Down
13 changes: 13 additions & 0 deletions lib/fromRdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
'use strict';

const JsonLdError = require('./JsonLdError');
const graphTypes = require('./graphTypes');
const types = require('./types');
const util = require('./util');
Expand All @@ -17,6 +18,7 @@ const {
RDF_TYPE,
// RDF_PLAIN_LITERAL,
// RDF_XML_LITERAL,
RDF_JSON_LITERAL,
// RDF_OBJECT,
// RDF_LANGSTRING,

Expand Down Expand Up @@ -285,6 +287,17 @@ function _RDFToObject(o, useNativeTypes) {
if(!type) {
type = XSD_STRING;
}
if(type === RDF_JSON_LITERAL) {
type = '@json';
try {
rval['@value'] = JSON.parse(rval['@value']);
} catch(e) {
throw new JsonLdError(
'JSON literal could not be parsed.',
'jsonld.InvalidJsonLiteral',
{code: 'invalid JSON literal', value: rval['@value'], cause: e});
}
}
// use native types for certain xsd types
if(useNativeTypes) {
if(type === XSD_BOOLEAN) {
Expand Down
9 changes: 7 additions & 2 deletions lib/toRdf.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
const {createNodeMap} = require('./nodeMap');
const {isKeyword} = require('./context');
const graphTypes = require('./graphTypes');
const jsonCanonicalize = require('canonicalize');
const types = require('./types');
const util = require('./util');

Expand All @@ -18,6 +19,7 @@ const {
RDF_TYPE,
// RDF_PLAIN_LITERAL,
// RDF_XML_LITERAL,
RDF_JSON_LITERAL,
// RDF_OBJECT,
RDF_LANGSTRING,

Expand Down Expand Up @@ -224,8 +226,11 @@ function _objectToRDF(item, issuer, dataset, graphTerm) {
let value = item['@value'];
const datatype = item['@type'] || null;

// convert to XSD datatypes as appropriate
if(types.isBoolean(value)) {
// convert to XSD/JSON datatypes as appropriate
if(datatype === '@json') {
object.value = jsonCanonicalize(value);
object.datatype.value = RDF_JSON_LITERAL;
} else if(types.isBoolean(value)) {
object.value = value.toString();
object.datatype.value = datatype || XSD_BOOLEAN;
} else if(types.isDouble(value) || datatype === XSD_DOUBLE) {
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"lib/**/*.js"
],
"dependencies": {
"canonicalize": "^1.0.1",
"rdf-canonize": "^1.0.2",
"request": "^2.88.0",
"semver": "^5.6.0",
Expand Down
17 changes: 17 additions & 0 deletions tests/misc.js
Original file line number Diff line number Diff line change
Expand Up @@ -519,3 +519,20 @@ describe('js keywords', () => {
assert.deepStrictEqual(e, ex);
});
});

describe('literal JSON', () => {
it('handles error', done => {
const d =
'_:b0 <ex:p> "bogus"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#JSON> .'
;
const p = jsonld.fromRDF(d);
assert(p instanceof Promise);
p.then(() => {
assert.fail();
}).catch(e => {
assert(e);
assert.equal(e.name, 'jsonld.InvalidJsonLiteral');
done();
});
});
});
44 changes: 0 additions & 44 deletions tests/test-common.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,6 @@ const TEST_TYPES = {
/compact-manifest.jsonld#tpi04$/,
/compact-manifest.jsonld#tpi05$/,
/compact-manifest.jsonld#tpi06$/,
// JSON literals
/compact-manifest.jsonld#tjs01$/,
/compact-manifest.jsonld#tjs02$/,
/compact-manifest.jsonld#tjs03$/,
/compact-manifest.jsonld#tjs04$/,
/compact-manifest.jsonld#tjs05$/,
/compact-manifest.jsonld#tjs06$/,
/compact-manifest.jsonld#tjs07$/,
/compact-manifest.jsonld#tjs08$/,
/compact-manifest.jsonld#tjs09$/,
// IRI confusion
/compact-manifest.jsonld#te002$/,
// @propogate
Expand Down Expand Up @@ -171,18 +161,6 @@ const TEST_TYPES = {
/expand-manifest.jsonld#tpi09$/,
/expand-manifest.jsonld#tpi10$/,
/expand-manifest.jsonld#tpi11$/,
// JSON literals
/expand-manifest.jsonld#tjs01$/,
/expand-manifest.jsonld#tjs02$/,
/expand-manifest.jsonld#tjs03$/,
/expand-manifest.jsonld#tjs04$/,
/expand-manifest.jsonld#tjs05$/,
/expand-manifest.jsonld#tjs06$/,
/expand-manifest.jsonld#tjs07$/,
/expand-manifest.jsonld#tjs08$/,
/expand-manifest.jsonld#tjs09$/,
/expand-manifest.jsonld#tjs10$/,
/expand-manifest.jsonld#tjs11$/,
// misc
/expand-manifest.jsonld#te043$/,
/expand-manifest.jsonld#te044$/,
Expand Down Expand Up @@ -336,14 +314,6 @@ const TEST_TYPES = {
specVersion: ['json-ld-1.0'],
// FIXME
idRegex: [
// JSON literals
/fromRdf-manifest.jsonld#tjs01$/,
/fromRdf-manifest.jsonld#tjs02$/,
/fromRdf-manifest.jsonld#tjs03$/,
/fromRdf-manifest.jsonld#tjs04$/,
/fromRdf-manifest.jsonld#tjs05$/,
/fromRdf-manifest.jsonld#tjs06$/,
/fromRdf-manifest.jsonld#tjs07$/,
]
},
fn: 'fromRDF',
Expand Down Expand Up @@ -406,20 +376,6 @@ const TEST_TYPES = {
/html-manifest.jsonld#tr020$/,
/html-manifest.jsonld#tr021$/,
/html-manifest.jsonld#tr022$/,
// JSON literal
/toRdf-manifest.jsonld#tjs01$/,
/toRdf-manifest.jsonld#tjs02$/,
/toRdf-manifest.jsonld#tjs03$/,
/toRdf-manifest.jsonld#tjs04$/,
/toRdf-manifest.jsonld#tjs05$/,
/toRdf-manifest.jsonld#tjs06$/,
/toRdf-manifest.jsonld#tjs07$/,
/toRdf-manifest.jsonld#tjs08$/,
/toRdf-manifest.jsonld#tjs09$/,
/toRdf-manifest.jsonld#tjs10$/,
/toRdf-manifest.jsonld#tjs11$/,
/toRdf-manifest.jsonld#tjs12$/,
/toRdf-manifest.jsonld#tjs13$/,
// number fixes
/toRdf-manifest.jsonld#trt01$/,
// IRI resolution
Expand Down