UNPKG

@hyperjump/json-schema

Version:

A JSON Schema validator with support for custom keywords, vocabularies, and dialects

127 lines (102 loc) 5.55 kB
import type { Browser, Document } from "@hyperjump/browser"; import type { Validator, OutputUnit, OutputFormat, SchemaObject } from "./index.js"; import type { JsonNode } from "./instance.js"; // Compile/interpret export const compile: (schema: Browser<SchemaDocument>) => Promise<CompiledSchema>; export const interpret: ( (compiledSchema: CompiledSchema, value: JsonNode, outputFormat?: OutputFormat) => OutputUnit ) & ( (compiledSchema: CompiledSchema) => Validator ); export type CompiledSchema = { schemaUri: string; ast: AST; }; type AST = { metaData: Record<string, MetaData>; plugins: Set<EvaluationPlugin>; } & Record<string, Node<unknown>[] | boolean>; type Node<A> = [keywordId: string, schemaUri: string, keywordValue: A]; type MetaData = { id: string; dynamicAnchors: Anchors; anchors: Anchors; }; type Anchors = Record<string, string>; // Output Formats export const BASIC: "BASIC"; export const DETAILED: "DETAILED"; // Schema export const getSchema: (uri: string, browser?: Browser) => Promise<Browser<SchemaDocument>>; export const buildSchemaDocument: (schema: SchemaObject | boolean, retrievalUri?: string, contextDialectId?: string) => SchemaDocument; export const canonicalUri: (browser: Browser<SchemaDocument>) => string; export const toSchema: (browser: Browser<SchemaDocument>, options?: ToSchemaOptions) => SchemaObject; export type ToSchemaOptions = { contextDialectId?: string; includeDialect?: "auto" | "always" | "never"; selfIdentify?: boolean; contextUri?: string; includeEmbedded?: boolean; }; export type SchemaDocument = Document & { dialectId: string; anchors: Record<string, string>; dynamicAnchors: Record<string, string>; }; // Vocabulary System export const addKeyword: <A>(keywordHandler: Keyword<A>) => void; export const getKeywordName: (dialectId: string, keywordId: string) => string; export const getKeyword: <A>(id: string) => Keyword<A>; export const getKeywordByName: <A>(keywordName: string, dialectId: string) => Keyword<A>; export const getKeywordId: (keywordName: string, dialectId: string) => string; export const defineVocabulary: (id: string, keywords: Record<string, string>) => void; export const loadDialect: (dialectId: string, dialect: Record<string, boolean>, allowUnknownKeywords?: boolean) => void; export const unloadDialect: (dialectId: string) => void; export const hasDialect: (dialectId: string) => boolean; export type Keyword<A, Context extends ValidationContext = ValidationContext> = { id: string; compile: (schema: Browser<SchemaDocument>, ast: AST, parentSchema: Browser<SchemaDocument>) => Promise<A>; interpret: (compiledKeywordValue: A, instance: JsonNode, context: Context) => boolean; simpleApplicator?: boolean; annotation?: <B>(compiledKeywordValue: A, instance: JsonNode) => B | undefined; plugin?: EvaluationPlugin<Context>; }; export type ValidationContext = { ast: AST; plugins: EvaluationPlugin[]; }; // Evaluation Plugins export type EvaluationPlugin<Context extends ValidationContext = ValidationContext> = { beforeSchema?(url: string, instance: JsonNode, context: Context): void; beforeKeyword?(keywordNode: Node<unknown>, instance: JsonNode, context: Context, schemaContext: Context, keyword: Keyword): void; afterKeyword?(keywordNode: Node<unknown>, instance: JsonNode, context: Context, valid: boolean, schemaContext: Context, keyword: Keyword): void; afterSchema?(url: string, instance: JsonNode, context: Context, valid: boolean): void; }; export class BasicOutputPlugin implements EvaluationPlugin<ErrorsContext> { errors: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: ErrorsContext): void; beforeKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: ErrorsContext, schemaContext: ErrorsContext, keyword: Keyword<unknown>): void; afterKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: ErrorsContext, valid: boolean, schemaContext: ErrorsContext, keyword: Keyword<unknown>): void; afterSchema(url: string, instance: JsonNode, context: ErrorsContext, valid: boolean): void; } export class DetailedOutputPlugin implements EvaluationPlugin<ErrorsContext> { errors: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: ErrorsContext): void; beforeKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: ErrorsContext, schemaContext: ErrorsContext, keyword: Keyword<unknown>): void; afterKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: ErrorsContext, valid: boolean, schemaContext: ErrorsContext, keyword: Keyword<unknown>): void; afterSchema(url: string, instance: JsonNode, context: ErrorsContext, valid: boolean): void; } export type ErrorsContext = ValidationContext & { errors: OutputUnit[]; }; export class AnnotationsPlugin implements EvaluationPlugin<AnnotationsContext> { annotations: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: AnnotationsContext): void; beforeKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: AnnotationsContext, schemaContext: AnnotationsContext, keyword: Keyword<unknown>): void; afterKeyword(keywordNode: Node<unknown>, instance: JsonNode, context: AnnotationsContext, valid: boolean, schemaContext: AnnotationsContext, keyword: Keyword<unknown>): void; afterSchema(url: string, instance: JsonNode, context: AnnotationsContext, valid: boolean): void; } export type AnnotationsContext = ValidationContext & { annotations: OutputUnit[]; }; export const Validation: Keyword<string>;