UNPKG

lincd-jsonld

Version:

Utilities to parse and write JSON-LD for the LINCD library

343 lines 15.8 kB
"use strict"; var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.JSONParser = void 0; /* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ const NodeURIMappings_1 = require("lincd/collections/NodeURIMappings"); const CoreMap_1 = require("lincd/collections/CoreMap"); const models_1 = require("lincd/models"); const NodeSet_1 = require("lincd/collections/NodeSet"); const CoreSet_1 = require("lincd/collections/CoreSet"); const JSONLD_js_1 = require("./JSONLD.js"); const QuadSet_1 = require("lincd/collections/QuadSet"); const ShapeSet_1 = require("lincd/collections/ShapeSet"); const package_js_1 = require("../package.js"); const ShapeClass_1 = require("lincd/utils/ShapeClass"); const QuadArray_1 = require("lincd/collections/QuadArray"); const LinkedStorage_1 = require("lincd/utils/LinkedStorage"); let shapeErrorMessage = 'The class that generates it is likely not loaded into local memory. Import the class. On the backend, check your dependencies in package.json'; let JSONParser = class JSONParser { static parse(json, targetGraph, setQuadsLoaded = false, nodemap = new NodeURIMappings_1.NodeURIMappings()) { try { var object = JSON.parse(json); } catch (error) { console.warn('Error parsing json: '); console.trace(error.message); } return this.parseObject(object, targetGraph, setQuadsLoaded, nodemap); } static parseObject(object, targetGraph, setQuadsLoaded = false, nodemap = new NodeURIMappings_1.NodeURIMappings(), overwriteData = false) { if (!nodemap) { nodemap = new NodeURIMappings_1.NodeURIMappings(); } var dataPromise; if ((object instanceof Object && object !== null) || object instanceof Array) { //update URI's before anything else if ('__map' in object) { var mappings = JSON.parse(object['__map']); this.applyURIMappings(mappings); // delete object['__map']; } //process data, which are quads if ('__data' in object) { dataPromise = JSONLD_js_1.JSONLD.parse(object['__data'], true, nodemap, targetGraph, overwriteData); // delete object['__data']; } } //set the target graph whilst parsing this.targetGraph = targetGraph; var contentPromise = this.parseObjectInternal(object, nodemap); //reset the target graph for next run delete this.targetGraph; //make sure both the actual content-object is done AND its data return Promise.all([dataPromise, contentPromise]).then(([dataResult, contentParseResult]) => { //and return both, so the user can easily access the intended content but also the new quads //combine all quads into one collection let allQuads, content; if (contentParseResult === null || contentParseResult === void 0 ? void 0 : contentParseResult.quads) { content = contentParseResult.content; allQuads = dataResult ? contentParseResult.quads.addFrom(dataResult.quads) : contentParseResult.quads; } else { content = contentParseResult; allQuads = dataResult === null || dataResult === void 0 ? void 0 : dataResult.quads; } //if indicated to do so, update the cache of which property paths are now loaded based on these new quads if (setQuadsLoaded && allQuads) { LinkedStorage_1.LinkedStorage.setQuadsLoaded(allQuads); } return { content, quads: allQuads }; }); } static parseObjectInternal(object, nodemap) { if (typeof object === 'string' || typeof object === 'number' || typeof object === 'boolean') { return Promise.resolve(object); } else if ((object instanceof Object && object !== null) || object instanceof Array) { if ('__type' in object) { var type = object['__type']; if (type == 'ns') { return this.createNodeSet(object, nodemap); } if (type == 'ss') { return this.createShapeSet(object, nodemap); } if (type == 'cs') { return this.createCoreSet(object, nodemap); } if (type == 'cm') { return this.createCoreMap(object, nodemap); } if (type == 'qd') { return this.createQuadSetData(object, nodemap); } } else if ('__t' in object) { return Promise.resolve(this.createQuad(object, nodemap, this.targetGraph)); } else if ('__s' in object) { return Promise.resolve(this.createShape(object, nodemap)); } else if ('__sc' in object) { return Promise.resolve(this.createShapeClass(object, nodemap)); } else if ('__b' in object) { return Promise.resolve(this.createBlankNode(object, nodemap)); } else if ('__u' in object) { return Promise.resolve(this.createNamedNode(object, nodemap)); } else if ('__l' in object) { return Promise.resolve(this.createLiteral(object)); } else if ('__g' in object) { return this.createGraph(object, nodemap); } else if ('__qs' in object) { return this.createQuadSet(object, nodemap); } else if ('__qa' in object) { return this.createQuadArray(object, nodemap); } else if ('__n' in object) { // return this.parseNativeObject(object['__n'],nodemap); return this.parseObjectInternal(object['__n'], nodemap); } else { return this.parseNativeObject(object, nodemap); } } else if (!object) { return Promise.resolve(null); } else { throw Error('Unable to parse this object: ' + object.toString()); } } static parseNativeObject(object, nodemap) { //this was a native javascript object whose values may still need to be converted var valuePromises = []; //we create a new object for the result and leave the initial one intact let resultObject = Array.isArray(object) ? [] : {}; let quads = new QuadSet_1.QuadSet(); var setValue = (key, keyParseResult) => { if (keyParseResult === null || keyParseResult === void 0 ? void 0 : keyParseResult.quads) { resultObject[key] = keyParseResult.content; quads.addFrom(keyParseResult.quads); } else { resultObject[key] = keyParseResult; } }; for (let key in object) { valuePromises.push(this.parseObjectInternal(object[key], nodemap).then(setValue.bind(null, key))); } return Promise.all(valuePromises) .then(() => { return quads.size > 0 ? { content: resultObject, quads } : resultObject; }) .catch((e) => { console.warn('Error in parsing object keys'); throw e; }); } static createQuad(object, nodemap, targetGraph) { var [subjectUri, predicateUri, objectString, graphString] = object['__t']; var subject = this.createNamedNodeFromString(subjectUri, nodemap); var predicate = this.createNamedNodeFromString(predicateUri, nodemap); var objectNode = this.createNodeFromString(objectString, nodemap); let graphNode, graph; if (graphString) { graphNode = this.createNodeFromString(graphString, nodemap); graph = models_1.Graph.getOrCreate(graphNode.value); } else { graph = targetGraph; } let q = models_1.Quad.getOrCreate(subject, predicate, objectNode, graph); return { content: q, quads: [q] }; } static createNodeFromString(str, nodemap) { if (str.substr(0, 1) == '"') { return models_1.Literal.fromString(str); } return this.createNamedNodeFromString(str, nodemap); } static createNamedNodeFromString(str, nodemap) { //TODO: move this check into general "nodemap" method if (str.substr(0, 1) == '_') { return nodemap.getOrCreateBlankNode(str); } return nodemap.getOrCreateNamedNode(str); } static createShape(object, nodemap) { // throw new Error('Outdated. Support for SHAPES still needs to be added'); var node = this.createNamedNodeFromString(object['u'], nodemap); var nodeShape = this.createNamedNodeFromString(object['__s'], nodemap); var ShapeClass = (0, ShapeClass_1.getShapeClass)(nodeShape); if (!ShapeClass) { this.throwShapeError(nodeShape); } return new ShapeClass(node); } static throwShapeError(nodeShape) { //TODO add link to documentation throw Error(`You need to import this shape: ${nodeShape.uri}. Could not convert JSON back to this shape, probably because the shape is not loaded. Make sure to IMPORT AND USE the shape in the code that receives this shape.`); } static createShapeClass(object, nodemap) { var nodeShape = this.createNamedNodeFromString(object['__sc'], nodemap); var ShapeClass = (0, ShapeClass_1.getShapeClass)(nodeShape); if (!ShapeClass) { this.throwShapeError(nodeShape); } return ShapeClass; } static createNamedNode(object, nodemap) { return nodemap.getOrCreateNamedNode(object['__u']); } static createBlankNode(object, nodemap) { return nodemap.getOrCreateBlankNode(object['__b']); } static createLiteral(object) { return models_1.Literal.fromString(object['__l']); } static createShapeSet(object, nodemap) { // throw new Error('Converting ShapeSets to JSON is not yet supported'); return this.createCoreSet(object, nodemap, new ShapeSet_1.ShapeSet()); } static createNodeSet(object, nodemap) { return this.createCoreSet(object, nodemap, new NodeSet_1.NodeSet()); } static applyURIMappings(uriMappings) { if (uriMappings && Array.isArray(uriMappings)) { uriMappings.forEach(([oldUri, newUri]) => { var resource = models_1.NamedNode.getNamedNode(oldUri); //we check if a node with the old uri exists, because its uri may already have been updated through other channels (like sockets) if (resource) { throw Error('Updating uris through JSON needs to be reimplemented'); // NamedNode.updateUri(resource, newUri); } }); return true; } return false; } static createCoreSet(object, nodemap, resultSet = new CoreSet_1.CoreSet()) { var entryPromises = []; let quads = new QuadSet_1.QuadSet(); object.entries.forEach((entry) => { entryPromises.push(this.parseObjectInternal(entry, nodemap).then((entryParseResult) => { //if the entry was an internal object that also returned quads if (entryParseResult && entryParseResult.quads) { quads.addFrom(entryParseResult.quads); resultSet.add(entryParseResult.content); } else { resultSet.add(entryParseResult); } })); }); return Promise.all(entryPromises).then(() => { return quads.size > 0 ? { content: resultSet, quads } : resultSet; }); } static createCoreMap(object, nodemap) { var res = new CoreMap_1.CoreMap(); let quads = new QuadSet_1.QuadSet(); var entryPromises = []; object.entries.forEach((entry) => { entryPromises.push(this.parseObjectInternal(entry, nodemap).then((entryParseResult) => { //if the entry was an internal object that also returned quads if (entryParseResult && entryParseResult.quads) { //then we store those quads and return an object with content & quads at the end of this method let [key, value] = entryParseResult.content; quads.addFrom(entryParseResult.quads); res.set(key, value); return; } else { let [key, value] = entryParseResult; res.set(key, value); } })); }); return Promise.all(entryPromises).then(() => quads.size > 0 ? { content: res, quads } : res); } static createGraph(object, nodemap) { if (object.content) { return JSONLD_js_1.JSONLD.parse(object.content, true, nodemap, this.targetGraph).then((parseResult) => { var graph = models_1.Graph.getOrCreate(object.__g); if (object.content) { return JSONLD_js_1.JSONLD.parse(object.content).then((parseResult) => { return { content: graph, quads: parseResult.quads }; }); } //TODO: test this use case, do we ever send graphs over? If so, does it need its content directly inside that graph? // or do we keep it in the (potentially temporary) given target graph, for memory management reasons? (this is what we do now) // graph.setContents(parseResult.quads); return graph; }); } else { return Promise.resolve(models_1.Graph.getOrCreate(object.__g)); } } static createQuadSet(object, nodemap) { return JSONLD_js_1.JSONLD.parse(object['__qs'], true, nodemap, this.targetGraph).then((parseResult) => { return { content: parseResult.quads, quads: parseResult.quads }; }); } static createQuadArray(object, nodemap) { return JSONLD_js_1.JSONLD.parse(object['__qa'], true, nodemap, this.targetGraph).then((parseResult) => { //@ts-ignore let content = new QuadArray_1.QuadArray(...parseResult.quads); return { content, quads: parseResult.quads }; }); } static createQuadSetData(object, nodemap) { return Promise.resolve(object.entries); } }; exports.JSONParser = JSONParser; exports.JSONParser = JSONParser = __decorate([ package_js_1.linkedUtil ], JSONParser); //# sourceMappingURL=JSONParser.js.map