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).

109 lines 4.04 kB
import isString from 'lodash/isString.js'; import { AtomicSchemaObject, AllOfSchema, NotSchema, } from '../atomic-schema/index.js'; import { TypeAtomicSchema } from './type.js'; import { negateIntegerMaximum, negateIntegerMinimum, } from '../utils/negate-integer-min-max/index.js'; import { getUniqueNegatedConstSchemasFromNegatedAtomicSchemasByConstructor } from './negated-const-helpers.js'; export class PatternAtomicSchema extends AtomicSchemaObject { pattern; constructor(pattern) { super(); this.pattern = pattern; } negate() { return new AllOfSchema([ new NotSchema(this), /* actually redundant, but makes checking for contradictions easier */ new TypeAtomicSchema('string'), ]); } toJSONSchema() { return { pattern: this.pattern }; } } export class MinLengthAtomicSchema extends AtomicSchemaObject { minLength; constructor(minLength) { super(); this.minLength = minLength; } negate() { return new AllOfSchema([ new MaxLengthAtomicSchema(negateIntegerMinimum(this.minLength)), new TypeAtomicSchema('string'), ]); } toJSONSchema() { return { minLength: this.minLength }; } } export class MaxLengthAtomicSchema extends AtomicSchemaObject { maxLength; constructor(maxLength) { super(); this.maxLength = maxLength; } negate() { return new AllOfSchema([ new MinLengthAtomicSchema(negateIntegerMaximum(this.maxLength)), new TypeAtomicSchema('string'), ]); } toJSONSchema() { return { maxLength: this.maxLength }; } } export const stringExtraction = { extract: ({ schema }) => { const schemas = []; if (typeof schema.pattern === 'string') { schemas.push(new PatternAtomicSchema(schema.pattern)); } if (typeof schema.minLength === 'number') { schemas.push(new MinLengthAtomicSchema(schema.minLength)); } if (typeof schema.maxLength === 'number') { schemas.push(new MaxLengthAtomicSchema(schema.maxLength)); } if (schemas.length === 0) { return true; } return new AllOfSchema(schemas); }, }; export const stringSimplification = { appliesToJSONSchemaType: 'string', mergeableKeywords: ['minLength', 'maxLength'], simplify({ schemaDescribesEmptySet, atomicSchemasByConstructor, negatedAtomicSchemasByConstructor, validateConst, }) { const minLength = Math.ceil(Math.max(0, ...atomicSchemasByConstructor .get(MinLengthAtomicSchema) .map(({ minLength }) => minLength))); const maxLength = Math.floor(Math.min(...atomicSchemasByConstructor .get(MaxLengthAtomicSchema) .map(({ maxLength }) => maxLength))); if (minLength > maxLength) { return false; } if (maxLength <= 0) { return validateConst(''); } const patternAtomicSchemas = atomicSchemasByConstructor.get(PatternAtomicSchema); const negatedPatternAtomicSchemas = negatedAtomicSchemasByConstructor.get(PatternAtomicSchema); for (const { pattern } of patternAtomicSchemas) { if (negatedPatternAtomicSchemas.some((notSchema) => pattern === notSchema.pattern)) { return false; } } return { ...(minLength > 0 ? { minLength } : {}), ...(maxLength < Infinity ? { maxLength } : {}), allOf: [ ...patternAtomicSchemas.map(({ pattern }) => ({ pattern })), ...negatedPatternAtomicSchemas.map(({ pattern }) => ({ not: { pattern }, })), ...getUniqueNegatedConstSchemasFromNegatedAtomicSchemasByConstructor(schemaDescribesEmptySet, negatedAtomicSchemasByConstructor, isString), ], }; }, }; //# sourceMappingURL=string.js.map