@hyperjump/json-schema
Version:
A JSON Schema validator with support for custom keywords, vocabularies, and dialects
79 lines (65 loc) • 3.06 kB
JavaScript
import curry from "just-curry-it";
import { resolveIri, toAbsoluteIri } from "@hyperjump/uri";
import { subscribe } from "./pubsub.js";
import {
setMetaSchemaOutputFormat,
getShouldValidateSchema,
getMetaSchemaOutputFormat
} from "./configuration.js";
import * as Instance from "./instance.js";
import { InvalidSchemaError } from "./invalid-schema-error.js";
import { getSchema, registerSchema, unregisterSchema as schemaUnregister } from "./schema.js";
import { getKeywordName } from "./keywords.js";
import Validation from "./keywords/validation.js";
export const FLAG = "FLAG", BASIC = "BASIC", DETAILED = "DETAILED";
setMetaSchemaOutputFormat(FLAG);
export const validate = async (url, value = undefined, outputFormat = undefined) => {
const schema = await getSchema(url);
const compiled = await compile(schema);
const interpretAst = (value, outputFormat) => interpret(compiled, Instance.fromJs(value), outputFormat);
return value === undefined ? interpretAst : interpretAst(value, outputFormat);
};
export const compile = async (schema) => {
const ast = { metaData: {} };
const schemaUri = await Validation.compile(schema, ast);
return { ast, schemaUri };
};
export const interpret = curry(({ ast, schemaUri }, instance, outputFormat = FLAG) => {
const errors = [];
const context = { ast, dynamicAnchors: {}, errors, annotations: [], outputFormat };
const valid = Validation.interpret(schemaUri, instance, context);
return outputFormat === FLAG || valid ? { valid } : { valid, errors };
});
const metaValidators = {};
subscribe("validate.metaValidate", async (_message, schema) => {
if (getShouldValidateSchema() && !schema.document.validated) {
schema.document.validated = true;
// Compile
if (!(schema.document.dialectId in metaValidators)) {
const metaSchema = await getSchema(schema.document.dialectId, schema);
const compiledSchema = await compile(metaSchema);
metaValidators[schema.document.dialectId] = interpret(compiledSchema);
}
// Interpret
const schemaInstance = Instance.fromJs(schema.document.root, schema.document.baseUri);
const metaResults = metaValidators[schema.document.dialectId](schemaInstance, getMetaSchemaOutputFormat());
if (!metaResults.valid) {
throw new InvalidSchemaError(metaResults);
}
}
});
/**
* @deprecated since 1.7.0. Use registerSchema instead.
*/
export const addSchema = (schema, retrievalUri = undefined, contextDialectId = undefined) => {
const dialectId = typeof schema.$schema === "string" ? toAbsoluteIri(schema.$schema) : contextDialectId;
const idToken = getKeywordName(dialectId, "https://json-schema.org/keyword/id")
|| getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id");
const id = typeof schema[idToken] === "string" ? resolveIri(schema[idToken], retrievalUri) : retrievalUri;
unregisterSchema(id);
registerSchema(schema, retrievalUri, contextDialectId);
};
export const unregisterSchema = (uri) => {
schemaUnregister(uri);
delete metaValidators[uri];
};