UNPKG

jsonld-streaming-parser

Version:
128 lines 6.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EntryHandlerArrayValue = void 0; const Util_1 = require("../Util"); const jsonld_context_parser_1 = require("jsonld-context-parser"); /** * Handles values that are part of an array. */ class EntryHandlerArrayValue { isPropertyHandler() { return false; } isStackProcessor() { return true; } async validate(parsingContext, util, keys, depth, inProperty) { return this.test(parsingContext, util, null, keys, depth); } async test(parsingContext, util, key, keys, depth) { return typeof keys[depth] === 'number'; } async handle(parsingContext, util, key, keys, value, depth) { let parentKey = await util.unaliasKeywordParent(keys, depth); // Check if we have an anonymous list if (parentKey === '@list') { // Our value is part of an array // Determine the list root key let listRootKey = null; let listRootDepth = 0; for (let i = depth - 2; i > 0; i--) { const keyOption = keys[i]; if (typeof keyOption === 'string' || typeof keyOption === 'number') { listRootDepth = i; listRootKey = keyOption; break; } } if (listRootKey !== null) { // Emit the given objects as list elements const values = await util.valueToTerm(await parsingContext.getContext(keys), listRootKey, value, depth, keys); for (const object of values) { await this.handleListElement(parsingContext, util, object, value, depth, keys.slice(0, listRootDepth), listRootDepth); } // If no values were found, emit a falsy list element to force an empty RDF list to be emitted. if (values.length === 0) { await this.handleListElement(parsingContext, util, null, value, depth, keys.slice(0, listRootDepth), listRootDepth); } } } else if (parentKey === '@set') { // Our value is part of a set, so we just add it to the parent-parent await parsingContext.newOnValueJob(keys.slice(0, -2), value, depth - 2, false); } else if (parentKey !== undefined && parentKey !== '@type') { // Buffer our value using the parent key as predicate // Determine the first parent key that is *not* an array key // This is needed in case we have an @list container with nested arrays, // where each of them should produce nested RDF lists. for (let i = depth - 1; i > 0; i--) { if (typeof keys[i] !== 'number') { parentKey = await util.unaliasKeyword(keys[i], keys, i); break; } } // Check if the predicate is marked as an @list in the context const parentContext = await parsingContext.getContext(keys.slice(0, -1)); if ('@list' in Util_1.Util.getContextValueContainer(parentContext, parentKey)) { // Our value is part of an array // Emit the given objects as list elements parsingContext.emittedStack[depth + 1] = true; // Ensure the creation of bnodes for empty nodes const values = await util.valueToTerm(await parsingContext.getContext(keys), parentKey, value, depth, keys); for (const object of values) { await this.handleListElement(parsingContext, util, object, value, depth, keys.slice(0, -1), depth - 1); } // If no values were found, emit a falsy list element to force an empty RDF list to be emitted. if (values.length === 0) { await this.handleListElement(parsingContext, util, null, value, depth, keys.slice(0, -1), depth - 1); } } else { // Copy the stack values up one level so that the next job can access them. parsingContext.shiftStack(depth, 1); // Execute the job one level higher await parsingContext.newOnValueJob(keys.slice(0, -1), value, depth - 1, false); // Remove any defined contexts at this level to avoid it to propagate to the next array element. parsingContext.contextTree.removeContext(keys.slice(0, -1)); } } } async handleListElement(parsingContext, util, value, valueOriginal, depth, listRootKeys, listRootDepth) { // Buffer our value as an RDF list using the listRootKey as predicate let listPointer = parsingContext.listPointerStack[depth]; if (valueOriginal !== null && (await util.unaliasKeywords(valueOriginal, listRootKeys, depth))['@value'] !== null) { if (!listPointer || !listPointer.value) { const linkTerm = util.dataFactory.blankNode(); listPointer = { value: linkTerm, listRootDepth, listId: linkTerm }; } else { // rdf:rest links are always emitted before the next element, // as the blank node identifier is only created at that point. // Because of this reason, the final rdf:nil is emitted when the stack depth is decreased. const newLinkTerm = util.dataFactory.blankNode(); parsingContext.emitQuad(depth, util.dataFactory.quad(listPointer.value, util.rdfRest, newLinkTerm, util.getDefaultGraph())); // Update the list pointer for the next element listPointer.value = newLinkTerm; } // Emit a list element for the current value // Omit rdf:first if the value is invalid if (value) { parsingContext.emitQuad(depth, util.dataFactory.quad(listPointer.value, util.rdfFirst, value, util.getDefaultGraph())); } } else { // A falsy list element if found. // Mark it as an rdf:nil list until another valid list element comes in if (!listPointer) { listPointer = { listRootDepth, listId: util.rdfNil }; } } parsingContext.listPointerStack[depth] = listPointer; // Error if an annotation was defined if (parsingContext.rdfstar && parsingContext.annotationsBuffer[depth]) { parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found an illegal annotation inside a list`, jsonld_context_parser_1.ERROR_CODES.INVALID_ANNOTATION)); } } } exports.EntryHandlerArrayValue = EntryHandlerArrayValue; //# sourceMappingURL=EntryHandlerArrayValue.js.map