UNPKG

json-schema-describes-subset

Version:

Tools for static JSON schema analysis, including functions to determine if one schema describes a subset of another or if a schema describes the empty set or to convert a schema to its disjunctive normal form (DNF).

100 lines 3.53 kB
import { isLogicLiteral, AllOfSchema, AnyOfSchema, negateAtomicSchema, isAtomicSchema, NotSchema, } from '../atomic-schema.js'; export function negate(schema) { if (isAtomicSchema(schema)) { /* this shoulf be called only once */ return negateAtomicSchema(schema); } if (schema instanceof AllOfSchema) { return new AnyOfSchema(schema.allOf.map(negate)); } if (schema instanceof AnyOfSchema) { return new AllOfSchema(schema.anyOf.map(negate)); } // => schema instanceof NotSchema return moveNotsToLiterals(schema.not); } /** * Makes all the `not`s move down, so that `NOT`s are exclusively in the * literals. `NOT`s are then resolved by applying {@link negateAtomicSchema}. * */ export function moveNotsToLiterals(schema) { if (schema instanceof AllOfSchema) { return new AllOfSchema(schema.allOf.map(moveNotsToLiterals)); } if (schema instanceof AnyOfSchema) { return new AnyOfSchema(schema.anyOf.map(moveNotsToLiterals)); } if (schema instanceof NotSchema) { return negate(schema.not); } // schema is AtomicSchema return schema; } /** * Moves `AND`s down and `OR`s up to create the RawDNF. * */ export function logicalCombinationOfLiteralsToRawDNFPart(schema) { if (schema instanceof AnyOfSchema) { return new AnyOfSchema(schema.anyOf .map(logicalCombinationOfLiteralsToRawDNFPart) .map((subschema) => { if (subschema instanceof AnyOfSchema) { /* anyOf as child of anyOf => flat */ return [...subschema.anyOf]; } if (isLogicLiteral(subschema)) { /* logicLiteral as child of anyOf => insert allOf */ return [new AllOfSchema([subschema])]; } /* subschema is already a ConjunctionOfLiterals */ return [subschema]; }) .flat()); } if (schema instanceof AllOfSchema) { const children = schema.allOf.map(logicalCombinationOfLiteralsToRawDNFPart); const dnfs = []; const logicLiterals = []; for (const child of children) { if (child instanceof AllOfSchema) { logicLiterals.push(...child.allOf); } else if (child instanceof AnyOfSchema) { dnfs.push(child); } else { logicLiterals.push(child); } } if (dnfs.length === 0) { return new AllOfSchema(logicLiterals); } const plainArrayDNF = dnfs.reduce((acc, { anyOf }) => { const result = []; for (const { allOf } of anyOf) { for (const accItem of acc) { result.push([...allOf, ...accItem]); } } return result; }, [logicLiterals]); return new AnyOfSchema(plainArrayDNF.map((plainArrayConjunctionOfLiterals) => new AllOfSchema(plainArrayConjunctionOfLiterals))); } // schema is LogicLiteral return schema; } export function dnfPartToRawDNF(dnfPart) { if (isLogicLiteral(dnfPart)) { return new AnyOfSchema([new AllOfSchema([dnfPart])]); } if (dnfPart instanceof AllOfSchema) { return new AnyOfSchema([dnfPart]); } return dnfPart; } export function toRawDNF(schema) { return dnfPartToRawDNF(logicalCombinationOfLiteralsToRawDNFPart(moveNotsToLiterals(schema))); } //# sourceMappingURL=to-raw-dnf.js.map