jsonld-streaming-parser
Advanced tools
Comparing version 3.1.0 to 3.2.0
@@ -57,3 +57,3 @@ "use strict"; | ||
for (const indexValue of indexValues) { | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth + 1, indexProperty, indexValue, false); | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth + 1, indexProperty, indexValue, false, false, false); | ||
} | ||
@@ -60,0 +60,0 @@ } |
@@ -53,3 +53,3 @@ "use strict"; | ||
// Push the type to the stack using the rdf:type predicate | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth + 1, util.rdfType, type, false); | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth + 1, util.rdfType, type, false, false, false); | ||
} | ||
@@ -56,0 +56,0 @@ // Flush any pending flush buffers |
@@ -5,2 +5,3 @@ "use strict"; | ||
const Util_1 = require("../Util"); | ||
const jsonld_context_parser_1 = require("jsonld-context-parser"); | ||
/** | ||
@@ -121,2 +122,6 @@ * Handles values that are part of an array. | ||
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)); | ||
} | ||
} | ||
@@ -123,0 +128,0 @@ } |
@@ -20,5 +20,7 @@ import * as RDF from "@rdfjs/types"; | ||
* @param {boolean} reverse If the property is reversed. | ||
* @param {boolean} isEmbedded If the property exists in an embedded node as direct child. | ||
* @param {boolean} isAnnotation If the property exists in an annotation object. | ||
* @return {Promise<void>} A promise resolving when handling is done. | ||
*/ | ||
static handlePredicateObject(parsingContext: ParsingContext, util: Util, keys: any[], depth: number, predicate: RDF.Term, object: RDF.Term, reverse: boolean): Promise<void>; | ||
static handlePredicateObject(parsingContext: ParsingContext, util: Util, keys: any[], depth: number, predicate: RDF.Term, object: RDF.Term, reverse: boolean, isEmbedded: boolean, isAnnotation: boolean): Promise<void>; | ||
isPropertyHandler(): boolean; | ||
@@ -25,0 +27,0 @@ isStackProcessor(): boolean; |
@@ -21,5 +21,7 @@ "use strict"; | ||
* @param {boolean} reverse If the property is reversed. | ||
* @param {boolean} isEmbedded If the property exists in an embedded node as direct child. | ||
* @param {boolean} isAnnotation If the property exists in an annotation object. | ||
* @return {Promise<void>} A promise resolving when handling is done. | ||
*/ | ||
static async handlePredicateObject(parsingContext, util, keys, depth, predicate, object, reverse) { | ||
static async handlePredicateObject(parsingContext, util, keys, depth, predicate, object, reverse, isEmbedded, isAnnotation) { | ||
const depthProperties = await util.getPropertiesDepth(keys, depth); | ||
@@ -29,3 +31,3 @@ const depthOffsetGraph = await util.getDepthOffsetGraph(depth, keys); | ||
const subjects = parsingContext.idStack[depthProperties]; | ||
if (subjects) { | ||
if (subjects && !isAnnotation) { | ||
// Emit directly if the @id was already defined | ||
@@ -40,9 +42,3 @@ for (const subject of subjects) { | ||
// Emit our quad if graph @id is known | ||
if (reverse) { | ||
util.validateReverseSubject(object); | ||
parsingContext.emitQuad(depth, util.dataFactory.quad(object, predicate, subject, graph)); | ||
} | ||
else { | ||
parsingContext.emitQuad(depth, util.dataFactory.quad(subject, predicate, object, graph)); | ||
} | ||
util.emitQuadChecked(depth, subject, predicate, object, graph, reverse, isEmbedded); | ||
} | ||
@@ -54,7 +50,7 @@ } | ||
util.validateReverseSubject(object); | ||
parsingContext.getUnidentifiedGraphBufferSafe(depthPropertiesGraph - 1).push({ subject: object, predicate, object: subject }); | ||
parsingContext.getUnidentifiedGraphBufferSafe(depthPropertiesGraph - 1).push({ subject: object, predicate, object: subject, isEmbedded }); | ||
} | ||
else { | ||
parsingContext.getUnidentifiedGraphBufferSafe(depthPropertiesGraph - 1) | ||
.push({ subject, predicate, object }); | ||
.push({ subject, predicate, object, isEmbedded }); | ||
} | ||
@@ -66,9 +62,3 @@ } | ||
const graph = await util.getGraphContainerValue(keys, depthProperties); | ||
if (reverse) { | ||
util.validateReverseSubject(object); | ||
parsingContext.emitQuad(depth, util.dataFactory.quad(object, predicate, subject, graph)); | ||
} | ||
else { | ||
parsingContext.emitQuad(depth, util.dataFactory.quad(subject, predicate, object, graph)); | ||
} | ||
util.emitQuadChecked(depth, subject, predicate, object, graph, reverse, isEmbedded); | ||
} | ||
@@ -82,3 +72,35 @@ } | ||
} | ||
parsingContext.getUnidentifiedValueBufferSafe(depthProperties).push({ predicate, object, reverse }); | ||
// Either push to the annotations or the actual value buffer | ||
if (isAnnotation) { | ||
// Only add to buffer if rdfstar is enabled | ||
if (parsingContext.rdfstar) { | ||
// Error if an @id was defined | ||
if (parsingContext.idStack[depth]) { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found an illegal @id inside an annotation: ${parsingContext.idStack[depth][0].value}`, jsonld_context_parser_1.ERROR_CODES.INVALID_ANNOTATION)); | ||
} | ||
// Error if we're in an embedded node | ||
for (let i = 0; i < depth; i++) { | ||
if (await util.unaliasKeyword(keys[i], keys, i) === '@id') { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found an illegal annotation inside an embedded node`, jsonld_context_parser_1.ERROR_CODES.INVALID_ANNOTATION)); | ||
} | ||
} | ||
// Store new annotation in the buffer | ||
const annotationsBuffer = parsingContext.getAnnotationsBufferSafe(depthProperties); | ||
const newAnnotation = { predicate, object, reverse, nestedAnnotations: [], depth: depthProperties }; | ||
annotationsBuffer.push(newAnnotation); | ||
// Check in the buffer if any annotations were defined at a deeper depth, | ||
// if so, they are considered nested annotations. | ||
for (let i = annotationsBuffer.length - 2; i >= 0; i--) { | ||
// We iterate in reverse order, to enable easy item removal from the back. | ||
const existingAnnotation = annotationsBuffer[i]; | ||
if (existingAnnotation.depth > depthProperties) { | ||
newAnnotation.nestedAnnotations.push(existingAnnotation); | ||
annotationsBuffer.splice(i, 1); | ||
} | ||
} | ||
} | ||
} | ||
else { | ||
parsingContext.getUnidentifiedValueBufferSafe(depthProperties).push({ predicate, object, reverse, isEmbedded }); | ||
} | ||
} | ||
@@ -117,3 +139,19 @@ } | ||
for (let object of objects) { | ||
const reverse = Util_1.Util.isPropertyReverse(context, keyOriginal, await util.unaliasKeywordParent(keys, depth)); | ||
// Based on parent key, check if reverse, embedded, and annotation. | ||
let parentKey = await util.unaliasKeywordParent(keys, depth); | ||
const reverse = Util_1.Util.isPropertyReverse(context, keyOriginal, parentKey); | ||
let parentDepthOffset = 0; | ||
while (parentKey === '@reverse' || typeof parentKey === 'number') { | ||
// Check parent of parent when checking while we're in an array or in @reverse | ||
if (typeof parentKey === 'number') { | ||
parentDepthOffset++; | ||
} | ||
else { | ||
depth--; | ||
} | ||
parentKey = await util.unaliasKeywordParent(keys, depth - parentDepthOffset); | ||
} | ||
const isEmbedded = Util_1.Util.isPropertyInEmbeddedNode(parentKey); | ||
util.validateReverseInEmbeddedNode(key, reverse, isEmbedded); | ||
const isAnnotation = Util_1.Util.isPropertyInAnnotationObject(parentKey); | ||
if (value) { | ||
@@ -138,3 +176,3 @@ // Special case if our term was defined as an @list, but does not occur in an array, | ||
} | ||
await EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth, predicate, object, reverse); | ||
await EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth, predicate, object, reverse, isEmbedded, isAnnotation); | ||
} | ||
@@ -141,0 +179,0 @@ } |
@@ -18,3 +18,13 @@ "use strict"; | ||
if (typeof value !== 'string') { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found illegal @id '${value}'`, jsonld_context_parser_1.ERROR_CODES.INVALID_ID_VALUE)); | ||
// JSON-LD-star allows @id object values | ||
if (parsingContext.rdfstar && typeof value === 'object') { | ||
const valueKeys = Object.keys(value); | ||
if (valueKeys.length === 1 && valueKeys[0] === '@id') { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Invalid embedded node without property with @id ${value['@id']}`, jsonld_context_parser_1.ERROR_CODES.INVALID_EMBEDDED_NODE)); | ||
} | ||
} | ||
else { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found illegal @id '${value}'`, jsonld_context_parser_1.ERROR_CODES.INVALID_ID_VALUE)); | ||
} | ||
return; | ||
} | ||
@@ -36,2 +46,10 @@ // Determine the canonical place for this id. | ||
} | ||
// Error if an annotation was defined | ||
if (parsingContext.rdfstar && parsingContext.annotationsBuffer[depth]) { | ||
for (const annotation of parsingContext.annotationsBuffer[depth]) { | ||
if (annotation.depth === depth) { | ||
parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Found an illegal @id inside an annotation: ${value}`, jsonld_context_parser_1.ERROR_CODES.INVALID_ANNOTATION)); | ||
} | ||
} | ||
} | ||
// Save our @id on the stack | ||
@@ -38,0 +56,0 @@ parsingContext.idStack[depthProperties] = util.nullableTermToArray(await util.resourceToTerm(await parsingContext.getContext(keys), value)); |
@@ -25,3 +25,7 @@ "use strict"; | ||
const predicate = util.rdfType; | ||
const reverse = Util_1.Util.isPropertyReverse(context, keyOriginal, await util.unaliasKeywordParent(keys, depth)); | ||
const parentKey = await util.unaliasKeywordParent(keys, depth); | ||
const reverse = Util_1.Util.isPropertyReverse(context, keyOriginal, parentKey); | ||
const isEmbedded = Util_1.Util.isPropertyInEmbeddedNode(parentKey); | ||
util.validateReverseInEmbeddedNode(key, reverse, isEmbedded); | ||
const isAnnotation = Util_1.Util.isPropertyInAnnotationObject(parentKey); | ||
// Handle multiple values if the value is an array | ||
@@ -35,3 +39,3 @@ const elements = Array.isArray(value) ? value : [value]; | ||
if (type) { | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth, predicate, type, reverse); | ||
await EntryHandlerPredicate_1.EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth, predicate, type, reverse, isEmbedded, isAnnotation); | ||
} | ||
@@ -38,0 +42,0 @@ } |
@@ -212,2 +212,12 @@ /// <reference types="node" /> | ||
skipContextValidation?: boolean; | ||
/** | ||
* If embedded nodes and annotated objects should be parsed according to the JSON-LD star specification. | ||
* Defaults to true | ||
*/ | ||
rdfstar?: boolean; | ||
/** | ||
* If embedded nodes may use reverse properties | ||
* Defaults to false. | ||
*/ | ||
rdfstarReverseInEmbedded?: boolean; | ||
} |
@@ -23,2 +23,3 @@ "use strict"; | ||
const http_link_header_1 = require("http-link-header"); | ||
const EntryHandlerKeywordAnnotation_1 = require("./entryhandler/keyword/EntryHandlerKeywordAnnotation"); | ||
/** | ||
@@ -193,3 +194,3 @@ * A stream transformer that parses JSON-LD (text) streams to an {@link RDF.Stream}. | ||
// Skip further processing if this node is part of a literal | ||
if (this.util.isLiteral(depth)) { | ||
if (await this.util.isLiteral(keys, depth)) { | ||
handleKey = false; | ||
@@ -240,2 +241,3 @@ } | ||
this.parsingContext.literalStack.splice(depth, this.parsingContext.literalStack.length - depth); | ||
this.parsingContext.annotationsBuffer.splice(depth, 1); | ||
// TODO: just like the literal stack, splice all other stack until the end as well? | ||
@@ -254,3 +256,4 @@ } | ||
let subjects = this.parsingContext.idStack[depth]; | ||
if (!subjects) { | ||
const subjectsWasDefined = !!subjects; | ||
if (!subjectsWasDefined) { | ||
subjects = this.parsingContext.idStack[depth] = [this.util.dataFactory.blankNode()]; | ||
@@ -271,8 +274,3 @@ } | ||
for (const bufferedValue of valueBuffer) { | ||
if (bufferedValue.reverse) { | ||
this.parsingContext.emitQuad(depth, this.util.dataFactory.quad(bufferedValue.object, bufferedValue.predicate, subject, graph)); | ||
} | ||
else { | ||
this.parsingContext.emitQuad(depth, this.util.dataFactory.quad(subject, bufferedValue.predicate, bufferedValue.object, graph)); | ||
} | ||
this.util.emitQuadChecked(depth, subject, bufferedValue.predicate, bufferedValue.object, graph, bufferedValue.reverse, bufferedValue.isEmbedded); | ||
} | ||
@@ -290,2 +288,3 @@ } | ||
subject: bufferedValue.object, | ||
isEmbedded: bufferedValue.isEmbedded, | ||
}); | ||
@@ -298,2 +297,3 @@ } | ||
subject, | ||
isEmbedded: bufferedValue.isEmbedded, | ||
}); | ||
@@ -324,2 +324,16 @@ } | ||
} | ||
// Push unhandled annotations up the stack as nested annotations | ||
const annotationsBuffer = this.parsingContext.annotationsBuffer[depth]; | ||
if (annotationsBuffer) { | ||
// Throw an error if we reach the top, and still have annotations | ||
if (annotationsBuffer.length > 0 && depth === 1) { | ||
this.parsingContext.emitError(new jsonld_context_parser_1.ErrorCoded(`Annotations can not be made on top-level nodes`, jsonld_context_parser_1.ERROR_CODES.INVALID_ANNOTATION)); | ||
} | ||
// Pass the annotations buffer up one level in the stack | ||
const annotationsBufferParent = this.parsingContext.getAnnotationsBufferSafe(depth - 1); | ||
for (const annotation of annotationsBuffer) { | ||
annotationsBufferParent.push(annotation); | ||
} | ||
delete this.parsingContext.annotationsBuffer[depth]; | ||
} | ||
} | ||
@@ -464,2 +478,3 @@ /** | ||
new EntryHandlerKeywordValue_1.EntryHandlerKeywordValue(), | ||
new EntryHandlerKeywordAnnotation_1.EntryHandlerKeywordAnnotation(), | ||
new EntryHandlerContainer_1.EntryHandlerContainer(), | ||
@@ -466,0 +481,0 @@ new EntryHandlerKeywordUnknownFallback_1.EntryHandlerKeywordUnknownFallback(), |
@@ -5,2 +5,9 @@ import { ContextParser, IExpandOptions, IJsonLdContextNormalizedRaw, JsonLdContext, JsonLdContextNormalized } from "jsonld-context-parser"; | ||
import { IJsonLdParserOptions, JsonLdParser } from "./JsonLdParser"; | ||
export type AnnotationsBufferEntry = { | ||
predicate: RDF.Term; | ||
object: RDF.Term; | ||
reverse: boolean; | ||
nestedAnnotations: AnnotationsBufferEntry[]; | ||
depth: number; | ||
}; | ||
/** | ||
@@ -26,2 +33,4 @@ * Data holder for parsing information. | ||
readonly streamingProfileAllowOutOfOrderPlainType?: boolean; | ||
readonly rdfstar: boolean; | ||
readonly rdfstarReverseInEmbedded?: boolean; | ||
readonly processingStack: boolean[]; | ||
@@ -52,2 +61,3 @@ readonly processingType: boolean[]; | ||
reverse: boolean; | ||
isEmbedded: boolean; | ||
}[][]; | ||
@@ -58,3 +68,5 @@ readonly unidentifiedGraphsBuffer: { | ||
object: RDF.Term; | ||
isEmbedded: boolean; | ||
}[][]; | ||
readonly annotationsBuffer: AnnotationsBufferEntry[][]; | ||
pendingContainerFlushBuffers: { | ||
@@ -145,2 +157,3 @@ depth: number; | ||
reverse: boolean; | ||
isEmbedded: boolean; | ||
}[]; | ||
@@ -157,4 +170,11 @@ /** | ||
object: RDF.Term; | ||
isEmbedded: boolean; | ||
}[]; | ||
/** | ||
* Safely get or create the depth value of {@link ParsingContext.annotationsBuffer}. | ||
* @param {number} depth A depth. | ||
* @return {} An element of {@link ParsingContext.annotationsBuffer}. | ||
*/ | ||
getAnnotationsBufferSafe(depth: number): AnnotationsBufferEntry[]; | ||
/** | ||
* @return IExpandOptions The expand options for the active processing mode. | ||
@@ -161,0 +181,0 @@ */ |
@@ -26,2 +26,4 @@ "use strict"; | ||
this.streamingProfileAllowOutOfOrderPlainType = options.streamingProfileAllowOutOfOrderPlainType; | ||
this.rdfstar = options.rdfstar !== false; | ||
this.rdfstarReverseInEmbedded = options.rdfstarReverseInEmbedded; | ||
this.topLevelProperties = false; | ||
@@ -44,2 +46,3 @@ this.activeProcessingMode = parseFloat(this.processingMode); | ||
this.unidentifiedGraphsBuffer = []; | ||
this.annotationsBuffer = []; | ||
this.pendingContainerFlushBuffers = []; | ||
@@ -272,2 +275,15 @@ this.parser = options.parser; | ||
/** | ||
* Safely get or create the depth value of {@link ParsingContext.annotationsBuffer}. | ||
* @param {number} depth A depth. | ||
* @return {} An element of {@link ParsingContext.annotationsBuffer}. | ||
*/ | ||
getAnnotationsBufferSafe(depth) { | ||
let buffer = this.annotationsBuffer[depth]; | ||
if (!buffer) { | ||
buffer = []; | ||
this.annotationsBuffer[depth] = buffer; | ||
} | ||
return buffer; | ||
} | ||
/** | ||
* @return IExpandOptions The expand options for the active processing mode. | ||
@@ -309,2 +325,12 @@ */ | ||
} | ||
if (this.annotationsBuffer[depth + depthOffset - 1]) { | ||
if (!this.annotationsBuffer[depth - 1]) { | ||
this.annotationsBuffer[depth - 1] = []; | ||
} | ||
this.annotationsBuffer[depth - 1] = [ | ||
...this.annotationsBuffer[depth - 1], | ||
...this.annotationsBuffer[depth + depthOffset - 1], | ||
]; | ||
delete this.annotationsBuffer[depth + depthOffset - 1]; | ||
} | ||
// TODO: also do the same for other stacks | ||
@@ -311,0 +337,0 @@ } |
import { JsonLdContextNormalized } from "jsonld-context-parser"; | ||
import * as RDF from "@rdfjs/types"; | ||
import { ParsingContext } from "./ParsingContext"; | ||
import { AnnotationsBufferEntry, ParsingContext } from "./ParsingContext"; | ||
/** | ||
@@ -94,2 +94,14 @@ * Utility functions and methods. | ||
/** | ||
* Check if the given key exists inside an embedded node as direct child. | ||
* @param {string} parentKey The parent key. | ||
* @return {boolean} If the property is embedded. | ||
*/ | ||
static isPropertyInEmbeddedNode(parentKey: string): boolean; | ||
/** | ||
* Check if the given key exists inside an annotation object as direct child. | ||
* @param {string} parentKey The parent key. | ||
* @return {boolean} If the property is an annotation. | ||
*/ | ||
static isPropertyInAnnotationObject(parentKey: string): boolean; | ||
/** | ||
* Check if the given IRI is valid. | ||
@@ -235,6 +247,7 @@ * @param {string} iri A potential IRI. | ||
* then the deeper levels are definitely a literal as well. | ||
* @param {any[]} keys The keys. | ||
* @param {number} depth The depth. | ||
* @return {boolean} If we are processing a literal. | ||
*/ | ||
isLiteral(depth: number): boolean; | ||
isLiteral(keys: any[], depth: number): Promise<boolean>; | ||
/** | ||
@@ -290,2 +303,21 @@ * Check how many parents should be skipped for checking the @graph for the given node. | ||
getContainerKey(key: any, keys: string[], depth: number): Promise<any>; | ||
/** | ||
* Check if no reverse properties are present in embedded nodes. | ||
* @param key The current key. | ||
* @param reverse If a reverse property is active. | ||
* @param isEmbedded If we're in an embedded node. | ||
*/ | ||
validateReverseInEmbeddedNode(key: string, reverse: boolean, isEmbedded: boolean): void; | ||
/** | ||
* Emit a quad, with checks. | ||
* @param depth The current depth. | ||
* @param subject S | ||
* @param predicate P | ||
* @param object O | ||
* @param graph G | ||
* @param reverse If a reverse property is active. | ||
* @param isEmbedded If we're in an embedded node. | ||
*/ | ||
emitQuadChecked(depth: number, subject: RDF.Term, predicate: RDF.Term, object: RDF.Term, graph: RDF.Term, reverse: boolean, isEmbedded: boolean): void; | ||
protected emitAnnotation(depth: number, quad: RDF.BaseQuad, annotation: AnnotationsBufferEntry): void; | ||
} |
114
lib/Util.js
@@ -116,2 +116,18 @@ "use strict"; | ||
/** | ||
* Check if the given key exists inside an embedded node as direct child. | ||
* @param {string} parentKey The parent key. | ||
* @return {boolean} If the property is embedded. | ||
*/ | ||
static isPropertyInEmbeddedNode(parentKey) { | ||
return parentKey === '@id'; | ||
} | ||
/** | ||
* Check if the given key exists inside an annotation object as direct child. | ||
* @param {string} parentKey The parent key. | ||
* @return {boolean} If the property is an annotation. | ||
*/ | ||
static isPropertyInAnnotationObject(parentKey) { | ||
return parentKey === '@annotation'; | ||
} | ||
/** | ||
* Check if the given IRI is valid. | ||
@@ -232,2 +248,5 @@ * @param {string} iri A potential IRI. | ||
break; | ||
case '@annotation': | ||
// This keyword is allowed, but is processed like normal nodes | ||
break; | ||
default: | ||
@@ -363,3 +382,16 @@ throw new jsonld_context_parser_1.ErrorCoded(`Unknown value entry '${key}' in @value: ${JSON.stringify(value)}`, jsonld_context_parser_1.ERROR_CODES.INVALID_VALUE_OBJECT); | ||
else { | ||
return this.nullableTermToArray(this.resourceToTerm(context, value["@id"])); | ||
const valueId = value["@id"]; | ||
let valueTerm; | ||
if (typeof valueId === 'object') { | ||
if (this.parsingContext.rdfstar) { | ||
valueTerm = this.parsingContext.idStack[depth + 1][0]; | ||
} | ||
else { | ||
throw new jsonld_context_parser_1.ErrorCoded(`Found illegal @id '${value}'`, jsonld_context_parser_1.ERROR_CODES.INVALID_ID_VALUE); | ||
} | ||
} | ||
else { | ||
valueTerm = this.resourceToTerm(context, valueId); | ||
} | ||
return this.nullableTermToArray(valueTerm); | ||
} | ||
@@ -666,7 +698,12 @@ } | ||
* then the deeper levels are definitely a literal as well. | ||
* @param {any[]} keys The keys. | ||
* @param {number} depth The depth. | ||
* @return {boolean} If we are processing a literal. | ||
*/ | ||
isLiteral(depth) { | ||
async isLiteral(keys, depth) { | ||
for (let i = depth; i >= 0; i--) { | ||
if (await this.unaliasKeyword(keys[i], keys, i) === '@annotation') { | ||
// Literals may have annotations, which require processing of inner nodes. | ||
return false; | ||
} | ||
if (this.parsingContext.literalStack[i] || this.parsingContext.jsonLiteralStack[i]) { | ||
@@ -796,2 +833,75 @@ return true; | ||
} | ||
/** | ||
* Check if no reverse properties are present in embedded nodes. | ||
* @param key The current key. | ||
* @param reverse If a reverse property is active. | ||
* @param isEmbedded If we're in an embedded node. | ||
*/ | ||
validateReverseInEmbeddedNode(key, reverse, isEmbedded) { | ||
if (isEmbedded && reverse && !this.parsingContext.rdfstarReverseInEmbedded) { | ||
throw new jsonld_context_parser_1.ErrorCoded(`Illegal reverse property in embedded node in ${key}`, jsonld_context_parser_1.ERROR_CODES.INVALID_EMBEDDED_NODE); | ||
} | ||
} | ||
/** | ||
* Emit a quad, with checks. | ||
* @param depth The current depth. | ||
* @param subject S | ||
* @param predicate P | ||
* @param object O | ||
* @param graph G | ||
* @param reverse If a reverse property is active. | ||
* @param isEmbedded If we're in an embedded node. | ||
*/ | ||
emitQuadChecked(depth, subject, predicate, object, graph, reverse, isEmbedded) { | ||
// Create a quad | ||
let quad; | ||
if (reverse) { | ||
this.validateReverseSubject(object); | ||
quad = this.dataFactory.quad(object, predicate, subject, graph); | ||
} | ||
else { | ||
quad = this.dataFactory.quad(subject, predicate, object, graph); | ||
} | ||
// Emit the quad, unless it was created in an embedded node | ||
if (isEmbedded) { | ||
// Embedded nodes don't inherit the active graph | ||
if (quad.graph.termType !== 'DefaultGraph') { | ||
quad = this.dataFactory.quad(quad.subject, quad.predicate, quad.object); | ||
} | ||
// Multiple embedded nodes are not allowed | ||
if (this.parsingContext.idStack[depth - 1]) { | ||
throw new jsonld_context_parser_1.ErrorCoded(`Illegal multiple properties in an embedded node`, jsonld_context_parser_1.ERROR_CODES.INVALID_EMBEDDED_NODE); | ||
} | ||
this.parsingContext.idStack[depth - 1] = [quad]; | ||
} | ||
else { | ||
this.parsingContext.emitQuad(depth, quad); | ||
} | ||
// Flush annotations | ||
const annotationsBuffer = this.parsingContext.annotationsBuffer[depth]; | ||
if (annotationsBuffer) { | ||
for (const annotation of annotationsBuffer) { | ||
this.emitAnnotation(depth, quad, annotation); | ||
} | ||
delete this.parsingContext.annotationsBuffer[depth]; | ||
} | ||
} | ||
// This is a separate function to enable recursion | ||
emitAnnotation(depth, quad, annotation) { | ||
// Construct annotation quad | ||
let annotationQuad; | ||
if (annotation.reverse) { | ||
this.validateReverseSubject(annotation.object); | ||
annotationQuad = this.dataFactory.quad(annotation.object, annotation.predicate, quad); | ||
} | ||
else { | ||
annotationQuad = this.dataFactory.quad(quad, annotation.predicate, annotation.object); | ||
} | ||
// Emit annotated quad | ||
this.parsingContext.emitQuad(depth, annotationQuad); | ||
// Also emit nested annotations | ||
for (const nestedAnnotation of annotation.nestedAnnotations) { | ||
this.emitAnnotation(depth, annotationQuad, nestedAnnotation); | ||
} | ||
} | ||
} | ||
@@ -798,0 +908,0 @@ exports.Util = Util; |
{ | ||
"name": "jsonld-streaming-parser", | ||
"version": "3.1.0", | ||
"version": "3.2.0", | ||
"description": "A fast and lightweight streaming JSON-LD parser", | ||
@@ -41,3 +41,3 @@ "keywords": [ | ||
"http-link-header": "^1.0.2", | ||
"jsonld-context-parser": "^2.1.3", | ||
"jsonld-context-parser": "^2.3.0", | ||
"rdf-data-factory": "^1.1.0", | ||
@@ -61,3 +61,3 @@ "readable-stream": "^4.0.0" | ||
"pre-commit": "^1.2.2", | ||
"rdf-test-suite": "^1.13.4", | ||
"rdf-test-suite": "^1.21.0", | ||
"streamify-string": "^1.0.1", | ||
@@ -105,4 +105,4 @@ "ts-jest": "^28.0.0", | ||
"version": "manual-git-changelog onversion", | ||
"spec": "npm run spec-tordf && npm run spec-stream-tordf", | ||
"spec-earl": "npm run spec-earl-tordf && npm run spec-earl-stream-tordf", | ||
"spec": "npm run spec-tordf && npm run spec-stream-tordf && npm run spec-star-tordf", | ||
"spec-earl": "npm run spec-earl-tordf && npm run spec-earl-stream-tordf && npm run spec-earl-star-tordf", | ||
"spec-tordf": "rdf-test-suite spec/parser.js https://w3c.github.io/json-ld-api/tests/toRdf-manifest.jsonld -c .rdf-test-suite-cache/ -e", | ||
@@ -112,2 +112,4 @@ "spec-earl-tordf": "rdf-test-suite spec/parser.js https://w3c.github.io/json-ld-api/tests/toRdf-manifest.jsonld -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-tordf.ttl", | ||
"spec-earl-stream-tordf": "rdf-test-suite spec/parser.js -i '{ \"streamingProfile\": true }' https://w3c.github.io/json-ld-streaming/tests/stream-toRdf-manifest.jsonld -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-stream-tordf.ttl", | ||
"spec-star-tordf": "rdf-test-suite spec/parser.js https://json-ld.github.io/json-ld-star/tests/toRdf-manifest.jsonld -c .rdf-test-suite-cache/", | ||
"spec-earl-star-tordf": "rdf-test-suite spec/parser.js https://json-ld.github.io/json-ld-star/tests/toRdf-manifest.jsonld -c .rdf-test-suite-cache/ -o earl -p spec/earl-meta.json > spec/earl-star-tordf.ttl", | ||
"spec-clean": "rm -r .rdf-test-suite-cache/" | ||
@@ -114,0 +116,0 @@ }, |
@@ -165,2 +165,4 @@ # JSON-LD Streaming Parser | ||
* `skipContextValidation`: If JSON-LD context validation should be skipped. This is useful when parsing large contexts that are known to be valid. _(Default: `false`)_ | ||
* `rdfstar`: If embedded nodes and annotated objects should be parsed according to the [JSON-LD star specification](https://json-ld.github.io/json-ld-star/). _(Default: `true`)_ | ||
* `rdfstarReverseInEmbedded`: If embedded nodes in JSON-LD star can have reverse properties. _(Default: `false`)_ | ||
@@ -183,2 +185,3 @@ ```javascript | ||
normalizeLanguageTags: true, | ||
rdfstar: true, | ||
}); | ||
@@ -244,4 +247,5 @@ ``` | ||
This parser adheres to both the [JSON-LD 1.1](https://www.w3.org/TR/json-ld/) specification | ||
and the [JSON-LD 1.1 Streaming specification](https://w3c.github.io/json-ld-streaming/). | ||
This parser adheres to the [JSON-LD 1.1](https://www.w3.org/TR/json-ld/) specification, | ||
the [JSON-LD 1.1 Streaming](https://w3c.github.io/json-ld-streaming/) specification, | ||
and the [JSON-LD star](https://json-ld.github.io/json-ld-star/) specification. | ||
@@ -267,2 +271,4 @@ By default, this parser assumes that JSON-LD document | ||
* JSON-LD 1.1 - Streaming Transform JSON-LD to RDF | ||
* [JSON-LD star](https://json-ld.github.io/json-ld-star/) - Transform JSON-LD star to RDF | ||
* [JSON-LD star](https://json-ld.github.io/json-ld-star/) - Error handling | ||
@@ -269,0 +275,0 @@ ## Performance |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
450294
78
4059
299
Updatedjsonld-context-parser@^2.3.0