From fe75f889c510cec992dea1129cf5d8cfa8423207 Mon Sep 17 00:00:00 2001 From: Diya Date: Fri, 15 May 2026 01:23:26 +0530 Subject: [PATCH] cleanup validator deserialization API --- lib/core.js | 10 ++++++++++ lib/experimental.d.ts | 9 ++++++++- lib/index.d.ts | 7 ++++++- lib/restore-validator.spec.ts | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 lib/restore-validator.spec.ts diff --git a/lib/core.js b/lib/core.js index 51785a6a..c49c86d6 100644 --- a/lib/core.js +++ b/lib/core.js @@ -13,6 +13,7 @@ import { getKeywordName } from "./keywords.js"; import Validation from "./keywords/validation.js"; import { BasicOutputPlugin } from "./evaluation-plugins/basic-output.js"; import { DetailedOutputPlugin } from "./evaluation-plugins/detailed-output.js"; +import { serialize, deserialize } from "./compiled-schema-serialization.js"; export const FLAG = "FLAG", BASIC = "BASIC", DETAILED = "DETAILED"; @@ -22,10 +23,19 @@ export const validate = async (url, value = undefined, options = undefined) => { const schema = await getSchema(url); const compiled = await compile(schema); const interpretAst = (value, options) => interpret(compiled, Instance.fromJs(value), options); + interpretAst.serialize = () => serialize(compiled); return value === undefined ? interpretAst : interpretAst(value, options); }; +export const restoreValidator = (json) => { + const compiled = deserialize(json); + const interpretAst = (value, options) => interpret(compiled, Instance.fromJs(value), options); + interpretAst.serialize = () => serialize(compiled); + + return interpretAst; +}; + export const compile = async (schema) => { const ast = { metaData: {}, plugins: new Set() }; const schemaUri = await Validation.compile(schema, ast); diff --git a/lib/experimental.d.ts b/lib/experimental.d.ts index 969ef138..8ecd99f9 100644 --- a/lib/experimental.d.ts +++ b/lib/experimental.d.ts @@ -17,9 +17,12 @@ export type CompiledSchema = { ast: AST; }; +export const serialize: (compiledSchema: CompiledSchema) => string; +export const deserialize: (serialized: string) => CompiledSchema; + type AST = { metaData: Record; - plugins: EvaluationPlugin[]; + plugins: Set; } & Record[] | boolean>; type Node = [keywordId: string, schemaUri: string, keywordValue: A]; @@ -88,6 +91,7 @@ export type ValidationContext = { // Evaluation Plugins export type EvaluationPlugin = { + id?: string; beforeSchema?(url: string, instance: JsonNode, context: Context): void; beforeKeyword?(keywordNode: Node, instance: JsonNode, context: Context, schemaContext: Context, keyword: Keyword): void; afterKeyword?(keywordNode: Node, instance: JsonNode, context: Context, valid: boolean, schemaContext: Context, keyword: Keyword): void; @@ -95,6 +99,7 @@ export type EvaluationPlugin { + id: string; errors: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: ErrorsContext): void; @@ -104,6 +109,7 @@ export class BasicOutputPlugin implements EvaluationPlugin { } export class DetailedOutputPlugin implements EvaluationPlugin { + id: string; errors: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: ErrorsContext): void; @@ -117,6 +123,7 @@ export type ErrorsContext = ValidationContext & { }; export class AnnotationsPlugin implements EvaluationPlugin { + id: string; annotations: OutputUnit[]; beforeSchema(url: string, instance: JsonNode, context: AnnotationsContext): void; diff --git a/lib/index.d.ts b/lib/index.d.ts index 0a9410d0..9e5761f5 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -28,7 +28,12 @@ export const validate: ( (url: string) => Promise ); -export type Validator = (value: Json, options?: OutputFormat | ValidationOptions) => Output; +export const restoreValidator: (json: string) => Validator; + +export type Validator = { + (value: Json, options?: OutputFormat | ValidationOptions): Output; + serialize(): string; +}; export type Output = { valid: true; diff --git a/lib/restore-validator.spec.ts b/lib/restore-validator.spec.ts new file mode 100644 index 00000000..c7e6531f --- /dev/null +++ b/lib/restore-validator.spec.ts @@ -0,0 +1,32 @@ +import { describe, expect, test } from "vitest"; +import { registerSchema, validate, restoreValidator } from "../v1/index.js"; + + +describe("Validator Serialization for high-level API", () => { + const schemaUri = "schema:high-level-serialization"; + const dialectUri = "https://json-schema.org/v1"; + + test("serializes and restores a validator successfully", async () => { + registerSchema({ + type: "object", + properties: { + foo: { type: "string", pattern: "^[a-z]+$" }, + bar: { type: "number", minimum: 10 } + }, + required: ["foo"] + }, schemaUri, dialectUri); + + const originalValidator = await validate(schemaUri); + + expect(originalValidator({ foo: "abc", bar: 42 }).valid).toBe(true); + expect(originalValidator({ foo: "123" }).valid).toBe(false); + + const json = originalValidator.serialize(); + expect(typeof json).toBe("string"); + + const restoredValidator = restoreValidator(json); + + expect(restoredValidator({ foo: "abc", bar: 42 }).valid).toBe(true); + expect(restoredValidator({ foo: "123" }).valid).toBe(false); + }); +});