jsonld-streaming-parser
Version:
A fast and lightweight streaming JSON-LD parser
176 lines • 9.99 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.EntryHandlerPredicate = void 0;
const jsonld_context_parser_1 = require("jsonld-context-parser");
const Util_1 = require("../Util");
/**
* Interprets keys as predicates.
* The most common case in JSON-LD processing.
*/
class EntryHandlerPredicate {
/**
* Handle the given predicate-object by either emitting it,
* or by placing it in the appropriate stack for later emission when no @graph and/or @id has been defined.
* @param {ParsingContext} parsingContext A parsing context.
* @param {Util} util A utility instance.
* @param {any[]} keys A stack of keys.
* @param {number} depth The current depth.
* @param {Term} predicate The predicate.
* @param {Term} object The object.
* @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, isEmbedded, isAnnotation) {
const depthProperties = await util.getPropertiesDepth(keys, depth);
const depthOffsetGraph = await util.getDepthOffsetGraph(depth, keys);
const depthPropertiesGraph = depth - depthOffsetGraph;
const subjects = parsingContext.idStack[depthProperties];
if (subjects && !isAnnotation) {
// Emit directly if the @id was already defined
for (const subject of subjects) {
// Check if we're in a @graph context
const atGraph = depthOffsetGraph >= 0;
if (atGraph) {
const graphs = parsingContext.idStack[depthPropertiesGraph - 1];
if (graphs) {
for (const graph of graphs) {
// Emit our quad if graph @id is known
util.emitQuadChecked(depth, subject, predicate, object, graph, reverse, isEmbedded);
}
}
else {
// Buffer our triple if graph @id is not known yet.
if (reverse) {
util.validateReverseSubject(object);
parsingContext.getUnidentifiedGraphBufferSafe(depthPropertiesGraph - 1).push({ subject: object, predicate, object: subject, isEmbedded });
}
else {
parsingContext.getUnidentifiedGraphBufferSafe(depthPropertiesGraph - 1)
.push({ subject, predicate, object, isEmbedded });
}
}
}
else {
// Emit if no @graph was applicable
const graph = await util.getGraphContainerValue(keys, depthProperties);
util.emitQuadChecked(depth, subject, predicate, object, graph, reverse, isEmbedded);
}
}
}
else {
// Buffer until our @id becomes known, or we go up the stack
if (reverse) {
util.validateReverseSubject(object);
}
// 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 });
}
}
}
isPropertyHandler() {
return true;
}
isStackProcessor() {
return true;
}
async validate(parsingContext, util, keys, depth, inProperty) {
const key = keys[depth];
if (key) {
const context = await parsingContext.getContext(keys);
if (!parsingContext.jsonLiteralStack[depth] && await util.predicateToTerm(context, keys[depth])) {
// If this valid predicate is of type @json, mark it so in the stack so that no deeper handling of nodes occurs.
if (Util_1.Util.getContextValueType(context, key) === '@json') {
parsingContext.jsonLiteralStack[depth + 1] = true;
}
return true;
}
}
return false;
}
async test(parsingContext, util, key, keys, depth) {
return keys[depth];
}
async handle(parsingContext, util, key, keys, value, depth, testResult) {
const keyOriginal = keys[depth];
const context = await parsingContext.getContext(keys);
const predicate = await util.predicateToTerm(context, key);
if (predicate) {
const objects = await util.valueToTerm(context, key, value, depth, keys);
if (objects.length) {
for (let object of objects) {
// 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) {
// Special case if our term was defined as an @list, but does not occur in an array,
// In that case we just emit it as an RDF list with a single element.
const listValueContainer = '@list' in Util_1.Util.getContextValueContainer(context, key);
if (listValueContainer || value['@list']) {
if (((listValueContainer && !Array.isArray(value) && !value['@list'])
|| (value['@list'] && !Array.isArray(value['@list'])))
&& object !== util.rdfNil) {
const listPointer = util.dataFactory.blankNode();
parsingContext.emitQuad(depth, util.dataFactory.quad(listPointer, util.rdfRest, util.rdfNil, util.getDefaultGraph()));
parsingContext.emitQuad(depth, util.dataFactory.quad(listPointer, util.rdfFirst, object, util.getDefaultGraph()));
object = listPointer;
}
// Lists are not allowed in @reverse'd properties
if (reverse && !parsingContext.allowSubjectList) {
throw new jsonld_context_parser_1.ErrorCoded(`Found illegal list value in subject position at ${key}`, jsonld_context_parser_1.ERROR_CODES.INVALID_REVERSE_PROPERTY_VALUE);
}
}
}
await EntryHandlerPredicate.handlePredicateObject(parsingContext, util, keys, depth, predicate, object, reverse, isEmbedded, isAnnotation);
}
}
}
}
}
exports.EntryHandlerPredicate = EntryHandlerPredicate;
//# sourceMappingURL=EntryHandlerPredicate.js.map
;