Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 28 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,16 @@ const output1 = isString("foo");
const output2 = isString(42);
```

You can also serialize a compiled validation function and restore it later without needing to recompile the schema.

```javascript
import { restoreValidator } from "@hyperjump/json-schema/draft-2020-12";

const serializedValidator = isString.serialize();
const restoredIsString = restoreValidator(serializedValidator);
const output3 = restoredIsString("foo");
```

**File-based and web-based schemas**

Schemas that are available on the web can be loaded automatically without
Expand Down Expand Up @@ -240,21 +250,24 @@ Schema, such as `@hyperjump/json-schema/draft-2020-12`.
Load a schema manually rather than fetching it from the filesystem or over
the network. Any schema already registered with the same identifier will be
replaced with no warning.
* **validate**: (schemaURI: string, instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => Promise\<OutputUnit>
* **validate**: (schemaURI: string, instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => Promise\<Output>

Validate an instance against a schema. This function is curried to allow
compiling the schema once and applying it to multiple instances.
* **validate**: (schemaURI: string) => Promise\<(instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => OutputUnit>
* **validate**: (schemaURI: string) => Promise\<Validator>

Compiling a schema to a validation function.
* **restoreValidator**: (serialized: string) => Validator

Restore a validation function from a serialized string without needing to recompile.
* **FLAG**: "FLAG"

An identifier for the `FLAG` output format as defined by the 2019-09 and
2020-12 specifications.
* **InvalidSchemaError**: Error & { output: OutputUnit }
* **InvalidSchemaError**: Error & { output: Output & { valid: false } }

This error is thrown if the schema being compiled is found to be invalid.
The `output` field contains an `OutputUnit` with information about the
The `output` field contains an `Output` object with information about the
error. You can use the `setMetaSchemaOutputFormat` configuration to set the
output format that is returned in `output`.
* **setMetaSchemaOutputFormat**: (outputFormat: OutputFormat) => void
Expand All @@ -278,11 +291,18 @@ The following types are used in the above definitions

Only the `FLAG` output format is part of the Stable API. Additional [output
formats](#output-formats) are included as part of the Experimental API.
* **OutputUnit**: { valid: boolean }
* **Validator**: (instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => Output
* **serialize**: () => string

A compiled validation function that can be executed to validate an instance, or serialized to a string so it can be restored at a later time without needing to recompile.
* **Output**: { valid: boolean }

Output is an experimental feature of the JSON Schema specification. There
may be additional fields present in the OutputUnit, but only the `valid`
may be additional fields present in the Output, but only the `valid`
property should be considered part of the Stable API.
* **OutputUnit**:

A type used in detailed or hierarchical output formats. Contains information about an individual validation error or annotation.
* **ValidationOptions**:

* outputFormat?: OutputFormat
Expand Down Expand Up @@ -760,7 +780,8 @@ These are available from the `@hyperjump/json-schema/experimental` export.

Return a compiled schema. This is useful if you're creating tooling for
something other than validation.
* **interpret**: (schema: CompiledSchema, instance: JsonNode, outputFormat: OutputFormat = BASIC) => OutputUnit
* **interpret**: (schema: CompiledSchema, instance: JsonNode, outputFormat: ValidationOptions | OutputFormat = BASIC) => Output
* **interpret**: (schema: CompiledSchema) => Validator

A curried function for validating an instance against a compiled schema.
This can be useful for creating custom output formats.
Expand Down
10 changes: 10 additions & 0 deletions lib/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ export const validate: (
(url: string) => Promise<Validator>
);

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;
Expand Down
2 changes: 1 addition & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ addKeyword(unknown);
addKeyword(vocabulary);
addKeyword(writeOnly);

export { addSchema, unregisterSchema, validate, FLAG } from "./core.js";
export { addSchema, unregisterSchema, validate, restoreValidator, FLAG } from "./core.js";
export { registerSchema, hasSchema, getAllRegisteredSchemaUris } from "./schema.js";
export {
getMetaSchemaOutputFormat,
Expand Down
32 changes: 32 additions & 0 deletions lib/restore-validator.spec.ts
Original file line number Diff line number Diff line change
@@ -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);
});
});
Loading