UNPKG

@squiz/json-schema-library

Version:

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

202 lines (179 loc) 7.75 kB
import step from "../step"; import validate from "../validate"; import resolveOneOf from "../resolveOneOf.strict"; import resolveRef from "../resolveRef.strict"; import resolveAllOf from "../resolveAllOf"; import resolveAnyOf from "../resolveAnyOf"; import getTemplate, { TemplateOptions } from "../getTemplate"; import getChildSchemaSelection from "../getChildSchemaSelection"; import getSchema from "../getSchema"; import { each, EachCallback } from "../each"; import isValid from "../isValid"; import { eachSchema, EachSchemaCallback } from "../eachSchema"; import createSchemaOf from "../createSchemaOf"; import compileSchema from "../compileSchema"; import { CreateError } from "../utils/createCustomError"; import addRemoteSchema from "../addRemoteSchema"; import { JSONSchema, JSONPointer, JSONValidator, JSONTypeValidator, JSONError } from "../types"; export type DraftConfig = { /** error creators by id */ errors: Record<string, CreateError>; /** map for valid keywords of a type */ typeKeywords: Record<string, string[]>; /** keyword validators */ validateKeyword: Record<string, JSONValidator>; /** type validators */ validateType: Record<string, JSONTypeValidator>; /** format validators */ validateFormat: Record<string, JSONValidator>; addRemoteSchema: typeof addRemoteSchema; compileSchema: typeof compileSchema; createSchemaOf: typeof createSchemaOf; each: typeof each; eachSchema: typeof eachSchema; getChildSchemaSelection: typeof getChildSchemaSelection; getSchema: typeof getSchema; getTemplate: typeof getTemplate; isValid: typeof isValid; resolveAllOf: typeof resolveAllOf; resolveAnyOf: typeof resolveAnyOf; resolveOneOf: typeof resolveOneOf; resolveRef: typeof resolveRef; step: typeof step; validate: typeof validate; }; export class Draft { readonly config: DraftConfig; /** entry point of schema */ private __rootSchema: JSONSchema; /** cache for remote schemas */ remotes: Record<string, JSONSchema> = {}; /** error creators by id */ readonly errors: Record<string, CreateError> = {}; /** map for valid keywords of a type */ readonly typeKeywords: Record<string, string[]> = {}; /** keyword validators */ readonly validateKeyword: Record<string, JSONValidator> = {}; /** type validators */ readonly validateType: Record<string, JSONTypeValidator> = {}; /** format validators */ readonly validateFormat: Record<string, JSONValidator> = {}; constructor(config: DraftConfig, schema?: JSONSchema) { this.config = config; this.typeKeywords = JSON.parse(JSON.stringify(config.typeKeywords)); this.validateKeyword = Object.assign({}, config.validateKeyword); this.validateType = Object.assign({}, config.validateType); this.validateFormat = Object.assign({}, config.validateFormat); this.errors = Object.assign({}, config.errors); this.setSchema(schema); } get rootSchema() { return this.__rootSchema; } set rootSchema(rootSchema: JSONSchema) { if (rootSchema == null) { return; } this.__rootSchema = this.config.compileSchema(this, rootSchema); } /** * register a json-schema to be referenced from another json-schema * @param url - base-url of json-schema (aka id) * @param schema - json-schema root */ addRemoteSchema(url: string, schema: JSONSchema): void { this.config.addRemoteSchema(this, url, schema); } compileSchema(schema: JSONSchema): JSONSchema { return this.config.compileSchema(this, schema, this.rootSchema ?? schema); } createSchemaOf(data: unknown) { return this.config.createSchemaOf(data); } /** * Iterates over data, retrieving its schema * * @param data - the data to iterate * @param callback - will be called with (schema, data, pointer) on each item * @param [schema] - the schema matching the data. Defaults to rootSchema * @param [pointer] - pointer to current data. Default to rootPointer */ each(data: any, callback: EachCallback, schema?: JSONSchema, pointer?: JSONPointer) { return this.config.each(this, data, callback, schema, pointer); } eachSchema(callback: EachSchemaCallback, schema = this.rootSchema) { return this.config.eachSchema(schema, callback); } getChildSchemaSelection(property: string | number, schema?: JSONSchema) { return this.config.getChildSchemaSelection(this, property, schema); } /** * Returns the json-schema of a data-json-pointer. * Notes * - Uses core.step to walk through data and schema * * @param pointer - json pointer in data to get the json schema for * @param [data] - the data object, which includes the json pointers value. This is optional, as * long as no oneOf, anyOf, etc statement is part of the pointers schema * @param [schema] - the json schema to iterate. Defaults to core.rootSchema * @return json schema object of the json-pointer or an error */ getSchema(pointer: JSONPointer = "#", data?: any, schema?: JSONSchema): JSONSchema | JSONError { return this.config.getSchema(this, pointer, data, schema); } /** * Create data object matching the given schema * * @param [data] - optional template data * @param [schema] - json schema, defaults to rootSchema * @return created template data */ getTemplate(data?: unknown, schema?: JSONSchema, opts?: TemplateOptions) { return this.config.getTemplate(this, data, schema, opts); } isValid(data: any, schema?: JSONSchema, pointer?: JSONPointer): boolean { return this.config.isValid(this, data, schema, pointer); } resolveAnyOf(data: any, schema: JSONSchema, pointer?: JSONPointer): JSONSchema { return this.config.resolveAnyOf(this, data, schema, pointer); } resolveAllOf(data: any, schema: JSONSchema, pointer?: JSONPointer): JSONSchema { return this.config.resolveAllOf(this, data, schema, pointer); } resolveRef(schema: JSONSchema): JSONSchema { return this.config.resolveRef(schema, this.rootSchema); } resolveOneOf(data: any, schema: JSONSchema, pointer?: JSONPointer): JSONSchema { return this.config.resolveOneOf(this, data, schema, pointer); } setSchema(schema: JSONSchema) { this.rootSchema = schema; } /** * Returns the json-schema of the given object property or array item. * e.g. it steps by one key into the data * * This helper determines the location of the property within the schema (additional properties, oneOf, ...) and * returns the correct schema. * * @param key - property-name or array-index * @param schema - json schema of current data * @param data - parent of key * @param [pointer] - pointer to schema and data (parent of key) * @return Schema or Error if failed resolving key */ step(key: string | number, schema: JSONSchema, data: any, pointer?: JSONPointer): JSONSchema { return this.config.step(this, key, schema, data, pointer); } /** * Validate data by a json schema * * @param value - value to validate * @param [schema] - json schema, defaults to rootSchema * @param [pointer] - json pointer pointing to value (used for error-messages only) * @return list of errors or empty */ validate(data: unknown, schema?: JSONSchema, pointer?: JSONPointer): JSONError[] { return this.config.validate(this, data, schema, pointer); } }