UNPKG

json-schema-library

Version:

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

112 lines (111 loc) 4.83 kB
import { isSchemaNode } from "./types"; import { mergeSchema } from "./utils/mergeSchema"; import { joinDynamicId } from "./SchemaNode"; function sortCb(a, b) { var _a, _b; return ((_a = b.order) !== null && _a !== void 0 ? _a : 0) - ((_b = a.order) !== null && _b !== void 0 ? _b : 0); } export function removeDuplicates(fun, funIndex, list) { var _a, _b; if (fun == null || list.indexOf(fun) !== funIndex) { return false; } const funName = (_b = (_a = fun.toJSON) === null || _a === void 0 ? void 0 : _a.call(fun)) !== null && _b !== void 0 ? _b : fun.name; return list.find((fun, index) => { var _a, _b; return ((_b = (_a = fun.toJSON) === null || _a === void 0 ? void 0 : _a.call(fun)) !== null && _b !== void 0 ? _b : fun.name) === funName && index === funIndex; }); } function mergeObjects(a, b) { if (a == null || b == null) { return b || a; } const object = {}; [...Object.keys(a), ...Object.keys(b)] .filter((p, i, l) => l.indexOf(p) === i) .forEach((key) => { const result = mergeNode(a[key], b[key]); if (isSchemaNode(result)) { object[key] = result; } }); return object; } // function mergeArray<T = unknown[]>(a?: T[], b?: T[]) { // return a || b ? [...(a ?? []), ...(b ?? [])] : undefined; // } function mergePatternProperties(a, b) { if (a == null || b == null) { return a || b; } const result = [...a]; const pointerList = a.map((p) => p.node.evaluationPath); b.forEach((p) => { if (!pointerList.includes(p.node.evaluationPath)) { result.push(p); } }); return result; } export function mergeNode(a, b, ...omit) { var _a, _b; if (a == null || b == null) { return a || b; } // do not merge items and prefixItems (+ additionalItems) const arraySelection = {}; if ((a.items && b.prefixItems) || (a.prefixItems && b.items)) { if (b.prefixItems) { arraySelection.prefixItems = b.prefixItems; } else { arraySelection.items = b.items; } } else { // prefixItems?: SchemaNode[]; arraySelection.prefixItems = (_a = b.prefixItems) !== null && _a !== void 0 ? _a : a.prefixItems; arraySelection.items = mergeNode(a.items, b.items); } // we have no node-type if (atype !== b.type) {return a; } // note: {x: b.x ?? a.x} is already done by {...a, ...b} const mergedNode = { ...a, ...b, ...arraySelection, dynamicId: joinDynamicId(a.dynamicId, b.dynamicId), oneOfIndex: (_b = a.oneOfIndex) !== null && _b !== void 0 ? _b : b.oneOfIndex, schema: mergeSchema(a.schema, b.schema, ...omit), parent: a.parent, resolvers: a.resolvers.concat(b.resolvers).filter(removeDuplicates).sort(sortCb), reducers: a.reducers.concat(b.reducers).filter(removeDuplicates).sort(sortCb), validators: a.validators.concat(b.validators).filter(removeDuplicates).sort(sortCb), additionalProperties: mergeNode(a.additionalProperties, b.additionalProperties), contains: mergeNode(a.contains, b.contains), if: mergeNode(a.if, b.if), then: mergeNode(a.then, b.then), else: mergeNode(a.else, b.else), not: mergeNode(a.not, b.not), propertyNames: mergeNode(a.propertyNames, b.propertyNames), unevaluatedProperties: mergeNode(a.unevaluatedProperties, b.unevaluatedProperties), unevaluatedItems: mergeNode(a.unevaluatedItems, b.unevaluatedItems), $defs: mergeObjects(a.$defs, b.$defs), patternProperties: mergePatternProperties(a.patternProperties, b.patternProperties), properties: mergeObjects(a.properties, b.properties) }; // this removes any function that has no keyword associated on schema function filterKeywordsBySchema(fun) { var _a, _b, _c; const funName = (_b = (_a = fun.toJSON) === null || _a === void 0 ? void 0 : _a.call(fun)) !== null && _b !== void 0 ? _b : fun.name; if (((_c = mergedNode.schema) === null || _c === void 0 ? void 0 : _c[funName]) === undefined) { // @ts-expect-error forced key mergedNode[funName] = undefined; return false; } return true; } // @ts-expect-error forced key omit === null || omit === void 0 ? void 0 : omit.forEach((key) => (mergedNode[key] = undefined)); // @todo better run addX features to determine removal as it is more performant and direct? mergedNode.resolvers = mergedNode.resolvers.filter(filterKeywordsBySchema); mergedNode.reducers = mergedNode.reducers.filter(filterKeywordsBySchema); mergedNode.validators = mergedNode.validators.filter(filterKeywordsBySchema); return mergedNode; }