UNPKG

json-schema-library

Version:

Customizable and hackable json-validator and json-schema utilities for traversal, data generation and validation

70 lines (60 loc) 2.36 kB
import { Keyword, JsonSchemaValidatorParams, ValidationPath } from "../../Keyword"; import { resolveRef } from "../../keywords/$ref"; import { SchemaNode } from "../../types"; import { joinId } from "../../utils/joinId"; import { validateNode } from "../../validateNode"; export const $refKeyword: Keyword = { id: "$ref", keyword: "$ref", parse: parseRef, addValidate: ({ schema }) => schema.$ref != null, validate: validateRef }; function parseRef(node: SchemaNode) { // get and store current $id of node - this may be the same as parent $id let currentId = node.parent?.$id; if (node.schema?.$ref == null) { currentId = joinId(node.parent?.$id, node.schema?.$id); } node.$id = currentId; node.lastIdPointer = node.parent?.lastIdPointer ?? "#"; // add ref resolution method to node node.resolveRef = resolveRef; // store this node for retrieval by $id if (node.context.refs[currentId] == null) { node.context.refs[currentId] = node; } const idChanged = currentId !== node.parent?.$id; if (idChanged) { node.lastIdPointer = node.evaluationPath; } // store this node for retrieval by $id + json-pointer from $id if (node.lastIdPointer !== "#" && node.evaluationPath.startsWith(node.lastIdPointer)) { const localPointer = `#${node.evaluationPath.replace(node.lastIdPointer, "")}`; node.context.refs[joinId(currentId, localPointer)] = node; } else { node.context.refs[joinId(currentId, node.evaluationPath)] = node; } node.context.refs[joinId(node.context.rootNode.$id, node.evaluationPath)] = node; // precompile reference if (node.schema.$ref) { node.$ref = joinId(currentId, node.schema.$ref); } } function validateRef({ node, data, pointer = "#", path }: JsonSchemaValidatorParams) { const nextNode = resolveAllRefs(node, pointer, path); if (nextNode == null) { return undefined; } return validateNode(nextNode, data, pointer, path); } function resolveAllRefs(node: SchemaNode, pointer: string, path: ValidationPath) { const nextNode = node.resolveRef({ pointer, path }); if (nextNode == null) { return undefined; } if (nextNode !== node && nextNode) { return resolveAllRefs(nextNode, pointer, path); } return node; }