Hyperjump - JSON Schema
A collection of modules for working with JSON Schemas.
- Validate JSON-compatible values against a JSON Schemas
format keyword
* Schemas can reference other schemas using a different dialect
* Work directly with schemas on the filesystem or HTTP
- OpenAPI
- Create custom keywords, formats, vocabularies, and dialects
- Bundle multiple schemas into one document
- API for building non-validation JSON Schema tooling
- API for working with annotations
Install
Includes support for node.js/bun.js (ES Modules, TypeScript) and browsers (works
with CSP
unsafe-eval).
Node.js
npm install @hyperjump/json-schema
TypeScript
This package uses the package.json "exports" field. TypeScript understands
"exports",
but you need to change a couple settings in your tsconfig.json for it to work.
"module": "Node16", // or "NodeNext"
"moduleResolution": "Node16", // or "NodeNext"
Versioning
The API for this library is divided into two categories: Stable and Experimental. The Stable API follows semantic versioning, but the Experimental API may have backward-incompatible changes between minor versions.
All experimental features are segregated into exports that include the word "experimental" so you never accidentally depend on something that could change or be removed in future releases.
Validation
Usage
This library supports many versions of JSON Schema. Use the pattern
@hyperjump/json-schema/* to import the version you need.
import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
You can import support for additional versions as needed.
import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
import "@hyperjump/json-schema/draft-07";
Note: The default export (@hyperjump/json-schema) is reserved for v1 of
JSON Schema that will hopefully be released in near future.
Validate schema from JavaScript
registerSchema({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "string"
}, "http://example.com/schemas/string");
const output = await validate("http://example.com/schemas/string", "foo");
if (output.valid) {
console.log("Instance is valid :-)");
} else {
console.log("Instance is invalid :-(");
}
Compile schema
If you need to validate multiple instances against the same schema, you can compile the schema into a reusable validation function.
const isString = await validate("http://example.com/schemas/string");
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.
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 needing to load them manually.
const output = await validate("http://example.com/schemas/string", "foo");
When running on the server, you can also load schemas directly from the
filesystem. When fetching from the file system, there are limitations for
security reasons. You can only reference a schema identified by a file URI
scheme (file:///path/to/my/schemas) from another schema identified by a file
URI scheme. Also, a schema is not allowed to self-identify ($id) with a
file: URI scheme.
const output = await validate(file://${__dirname}/string.schema.json, "foo");
If the schema URI is relative, the base URI in the browser is the browser location and the base URI on the server is the current working directory. This is the preferred way to work with file-based schemas on the server.
const output = await validate(./string.schema.json, "foo");
You can add/modify/remove support for any URI scheme using the plugin
system provided by
@hyperjump/browser.
Format
Format validation support needs to be explicitly loaded by importing
@hyperjump/json-schema/formats. Once loaded, it depends on the dialect whether
validation is enabled by default or not. You should explicitly enable/disable it
with the setShouldValidateFormat function.
The hostname, idn-hostname, and idn-email validators are fairly large. If
you don't need support for those formats and bundle size is a concern, you can
use @hyperjump/json-schema/formats-lite instead to leave out support for those
formats.
import { registerSchema, setShouldValidateFormat, validate } from "@hyperjump/json-schema/draft-2020-12";
import "@hyperjump/json-schema/formats";
const schemaUri = "https://example.com/number";
registerSchema({
"type": "string",
"format": "date"
}, schemaUri);
setShouldValidateFormat(true);
const output = await validate(schemaUri, "Feb 29, 2031"); // { valid: false }
OpenAPI
The OpenAPI 3.0 and 3.1 and 3.2 meta-schemas are pre-loaded and the OpenAPI JSON
Schema dialects for each of those versions is supported. A document with a
Content-Type of application/openapi+json (web) or a file extension of
openapi.json (filesystem) is understood as an OpenAPI document.
Use the pattern @hyperjump/json-schema/* to import the version you need. The
available versions are openapi-3-0 for 3.0, openapi-3-1 for 3.1, and
openapi-3-2 for 3.2.
import { validate } from "@hyperjump/json-schema/openapi-3-2";
// Validate an OpenAPI 3.2 document
const output = await validate("https://spec.openapis.org/oas/3.2/schema-base", openapi);
// Validate an instance against a schema in an OpenAPI 3.2 document
const output = await validate("./example.openapi.json#/components/schemas/foo", 42);
YAML support isn't built in, but you can add it by writing a
MediaTypePlugin. You can
use the one at lib/openapi.js as an example and replace the JSON parts with
YAML.
Media types
This library uses media types to determine how to parse a retrieved document. It
will never assume the retrieved document is a schema. By default it's configured
to accept documents with a application/schema+json Content-Type header (web)
or a .schema.json file extension (filesystem).
You can add/modify/remove support for any media-type using the plugin
system provided by
@hyperjump/browser. The following example shows how to add support for JSON
Schemas written in YAML.
import YAML from "yaml";
import contentTypeParser from "content-type";
import { addMediaTypePlugin } from "@hyperjump/browser";
import { buildSchemaDocument } from "@hyperjump/json-schema/experimental";
addMediaTypePlugin("application/schema+yaml", {
parse: async (response) => {
const contentType = contentTypeParser.parse(response.headers.get("content-type") ?? "");
const contextDialectId = contentType.parameters.schema ?? contentType.parameters.profile;
const foo = YAML.parse(await response.text());
return buildSchemaDocument(foo, response.url, contextDialectId);
},
fileMatcher: (path) => path.endsWith(".schema.yml")
});
API
These are available from any of the exports that refer to a version of JSON
Schema, such as @hyperjump/json-schema/draft-2020-12.
- registerSchema: (schema: object, retrievalUri?: string, defaultDialectId?: string) => void
- unregisterSchema: (uri: string) => void
- getAllRegisteredSchemaUris: () => string[]
- hasSchema: (uri: string) => boolean
- _(deprecated)_ addSchema: (schema: object, retrievalUri?: string, defaultDialectId?: string) => void
- validate: (schemaURI: string, instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => Promise\
- validate: (schemaURI: string) => Promise\
- restoreValidator: (serialized: string) => Validator
- FLAG: "FLAG"
FLAG output format as defined by the 2019-09 and
2020-12 specifications.
- InvalidSchemaError: Error & { output: Output & { valid: false } }
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
- getMetaSchemaOutputFormat: () => OutputFormat
- setShouldMetaValidate: (isEnabled: boolean) => void
- getShouldMetaValidate: (isEnabled: boolean) => void
Type Definitions
The following types are used in the above definitions
- OutputFormat: FLAG
FLAG output format is part of the Stable API. Additional output
formats are included as part of the Experimental API.
- Validator: (instance: any, outputFormat: ValidationOptions | OutputFormat = FLAG) => Output
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 }
valid
property should be considered part of the Stable API.
- OutputUnit:
- ValidationOptions:
Bundling
Usage
You can bundle schemas with external references into a single deliverable using the official JSON Schema bundling process introduced in the 2020-12 specification. Given a schema with external references, any external schemas will be embedded in the schema resulting in a Compound Schema Document with all the schemas necessary to evaluate the given schema in a single JSON document.
The bundling process allows schemas to be embedded without needing to modify any references which means you get the same output details whether you validate the bundle or the original unbundled schemas.
import { registerSchema } from "@hyperjump/json-schema/draft-2020-12";
import { bundle } from "@hyperjump/json-schema/bundle";
registerSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"foo": { "$ref": "/string" }
}
}, "https://example.com/main");
registerSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string"
}, "https://example.com/string");
const bundledSchema = await bundle("https://example.com/main"); // {
// "$schema": "https://json-schema.org/draft/2020-12/schema",
//
// "type": "object",
// "properties": {
// "foo": { "$ref": "/string" }
// },
//
// "$defs": {
// "string": {
// "$id": "https://example.com/string",
// "type": "string"
// }
// }
// }
API
These are available from the @hyperjump/json-schema/bundle export.
- bundle: (uri: string, options: Options) => Promise\
Options: * alwaysIncludeDialect: boolean (default: false) -- Include dialect even when it isn't strictly needed * definitionNamingStrategy: "uri" | "uuid" (default: "uri") -- By default the name used in definitions for embedded schemas will match the identifier of the embedded schema. Alternatively, you can use a UUID instead of the schema's URI. * externalSchemas: string[] (default: []) -- A list of schemas URIs that are available externally and should not be included in the bundle.
Experimental
Output Formats
Change the validation output format
The FLAG output format isn't very informative. You can change the output
format used for validation to get more information about failures. The official
output format is still evolving, so these may change or be replaced in the
future. This implementation currently supports the BASIC and DETAILED output
formats.
import { BASIC } from "@hyperjump/json-schema/experimental";
const output = await validate("https://example.com/schema1", 42, BASIC);
Change the schema validation output format
The output format used for validating schemas can be changed as well.
import { validate, setMetaSchemaOutputFormat } from "@hyperjump/json-schema/draft-2020-12";
import { BASIC } from "@hyperjump/json-schema/experimental";
setMetaSchemaOutputFormat(BASIC);
try {
const output = await validate("https://example.com/invalid-schema");
} catch (error) {
console.log(error.output);
}
Custom Keywords, Vocabularies, and Dialects
In order to create and use a custom keyword, you need to define your keyword's behavior, create a vocabulary that includes that keyword, and then create a dialect that includes your vocabulary.
Schemas are represented using the
@hyperjump/browser package. You'll
use that API to traverse schemas. @hyperjump/browser uses async generators to
iterate over arrays and objects. If you like using higher order functions like
map/filter/reduce, see
@hyperjump/pact for utilities for
working with generators and async generators.
import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
import { addKeyword, defineVocabulary, Validation } from "@hyperjump/json-schema/experimental";
import * as Browser from "@hyperjump/browser";
// Define a keyword that's an array of schemas that are applied sequentially
// using implication: A -> B -> C -> D
addKeyword({
id: "https://example.com/keyword/implication",
compile: async (schema, ast) => {
const subSchemas = [];
for await (const subSchema of Browser.iter(schema)) {
subSchemas.push(Validation.compile(subSchema, ast));
}
return subSchemas;
// Alternative using @hyperjump/pact
// return pipe(
// Browser.iter(schema),
// asyncMap((subSchema) => Validation.compile(subSchema, ast)),
// asyncCollectArray
// );
},
interpret: (implies, instance, context) => {
return implies.reduce((valid, schema) => {
return !valid || Validation.interpret(schema, instance, context);
}, true);
}
});
// Create a vocabulary with this keyword and call it "implies"
defineVocabulary("https://example.com/vocab/logic", {
"implies": "https://example.com/keyword/implication"
});
// Create a vocabulary schema for this vocabulary
registerSchema({
"$id": "https://example.com/meta/logic",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$dynamicAnchor": "meta",
"properties": {
"implies": {
"type": "array",
"items": { "$dynamicRef": "meta" },
"minItems": 2
}
}
});
// Create a dialect schema adding this vocabulary to the standard JSON Schema
// vocabularies
registerSchema({
"$id": "https://example.com/dialect/logic",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
"https://json-schema.org/draft/2020-12/vocab/core": true,
"https://json-schema.org/draft/2020-12/vocab/applicator": true,
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
"https://json-schema.org/draft/2020-12/vocab/validation": true,
"https://json-schema.org/draft/2020-12/vocab/meta-data": true,
"https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
"https://json-schema.org/draft/2020-12/vocab/content": true
"https://example.com/vocab/logic": true
},
"$dynamicAnchor": "meta",
"allOf": [
{ "$ref": "https://json-schema.org/draft/2020-12/schema" },
{ "$ref": "/meta/logic" }
]
});
// Use your dialect to validate a JSON instance
registerSchema({
"$schema": "https://example.com/dialect/logic",
"type": "number",
"implies": [
{ "minimum": 10 },
{ "multipleOf": 2 }
]
}, "https://example.com/schema1");
const output = await validate("https://example.com/schema1", 42);
Custom Formats
Custom formats work similarly to keywords. You define a format handler and then associate that format handler with the format keyword that applies to the dialects you're targeting.
import { registerSchema, validate, setShouldValidateFormat } from "@hyperjump/json-schema/draft-2020-12";
import { addFormat, setFormatHandler } from "@hyperjump/json-schema/experimental";
const isoDateFormatUri = "https://example.com/format/iso-8601-date";
// Add the iso-date format handler
addFormat({
id: isoDateFormatUri,
handler: (date) => new Date(date).toISOString() === date
});
// Add the "iso-date" format to the 2020-12 version of format
setFormatHandler("https://json-schema.org/keyword/draft-2020-12/format", "iso-date", isoDateFormatUri);
setFormatHandler("https://json-schema.org/keyword/draft-2020-12/format-assertion", "iso-date", isoDateFormatUri);
// Optional: Add the "iso-date" format to other dialects
setFormatHandler("https://json-schema.org/keyword/draft-2019-09/format", "iso-date", isoDateFormatUri);
setFormatHandler("https://json-schema.org/keyword/draft-2019-09/format-assertion", "iso-date", isoDateFormatUri);
setFormatHandler("https://json-schema.org/keyword/draft-07/format", "iso-date", isoDateFormatUri);
setFormatHandler("https://json-schema.org/keyword/draft-06/format", "iso-date", isoDateFormatUri);
setFormatHandler("https://json-schema.org/keyword/draft-04/format", "iso-date", isoDateFormatUri);
const schemaUri = "https://example.com/main";
registerSchema({
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "string",
"format": "iso-date"
}, schemaUri);
setShouldValidateFormat(true);
const output = await validate(schemaUri, "Feb 28, 2031"); // { valid: false }
Custom Meta Schema
You can use a custom meta-schema to restrict users to a subset of JSON Schema functionality. This example requires that no unknown keywords are used in the schema.
registerSchema({
"$id": "https://example.com/meta-schema1",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$vocabulary": {
"https://json-schema.org/draft/2020-12/vocab/core": true,
"https://json-schema.org/draft/2020-12/vocab/applicator": true,
"https://json-schema.org/draft/2020-12/vocab/unevaluated": true,
"https://json-schema.org/draft/2020-12/vocab/validation": true,
"https://json-schema.org/draft/2020-12/vocab/meta-data": true,
"https://json-schema.org/draft/2020-12/vocab/format-annotation": true,
"https://json-schema.org/draft/2020-12/vocab/content": true
},
"$dynamicAnchor": "meta",
"$ref": "https://json-schema.org/draft/2020-12/schema",
"unevaluatedProperties": false
});
registerSchema({
$schema: "https://example.com/meta-schema1",
type: "number",
foo: 42
}, "https://example.com/schema1");
const output = await validate("https://example.com/schema1", 42); // Expect InvalidSchemaError
EvaluationPlugins
EvaluationPlugins allow you to hook into the validation process for various purposes. There are hooks for before an after schema evaluation and before and after keyword evaluation. (See the API section for the full interface) The following is a simple example to record all the schema locations that were evaluated. This could be used as part of a solution for determining test coverage for a schema.
import { registerSchema, validate } from "@hyperjump/json-schema/draft-2020-12";
import { BASIC } from "@hyperjump/json-schema/experimental.js";
class EvaluatedKeywordsPlugin {
id = "https://example.com/plugins/evaluated-keywords";
constructor() {
this.schemaLocations = new Set();
}
beforeKeyword([, schemaUri]) {
this.schemaLocations.add(schemaUri);
}
}
registerSchema({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
properties: {
foo: { type: "number" },
bar: { type: "boolean" }
},
required: ["foo"]
}, "https://schemas.hyperjump.io/main");
const evaluatedKeywordPlugin = new EvaluatedKeywordsPlugin();
await validate("https://schemas.hyperjump.io/main", { foo: 42 }, {
outputFormat: BASIC,
plugins: [evaluatedKeywordPlugin]
});
console.log(evaluatedKeywordPlugin.schemaLocations);
// Set(4) {
// 'https://schemas.hyperjump.io/main#/type',
// 'https://schemas.hyperjump.io/main#/properties',
// 'https://schemas.hyperjump.io/main#/properties/foo/type',
// 'https://schemas.hyperjump.io/main#/required'
// }
// NOTE: #/properties/bar is not in the list because the instance doesn't include that property.
API
These are available from the @hyperjump/json-schema/experimental export.
- addKeyword: (keywordHandler: Keyword) => void
* Keyword: object * id: string
A URI that uniquely identifies the keyword. It should use a domain you
own to avoid conflict with keywords defined by others.
* compile: (schema: Browser, ast: AST, parentSchema: Browser) => Promise\
This function takes the keyword value, does whatever preprocessing it
can on it without an instance, and returns the result. The returned
value will be passed to the interpret function. The ast parameter
is needed for compiling sub-schemas. The parentSchema parameter is
primarily useful for looking up the value of an adjacent keyword that
might effect this one.
* interpret: (compiledKeywordValue: any, instance: JsonNode, context: ValidationContext) => boolean
This function takes the value returned by the compile function and
the instance value that is being validated and returns whether the
value is valid or not. The other parameters are only needed for
validating sub-schemas.
* simpleApplicator?: boolean
Some applicator keywords just apply schemas and don't do any validation of its own. In these cases, it isn't helpful to include them in BASIC output. This flag is used to trim those nodes from the output. * annotation?: (compiledKeywordValue: any) => any | undefined
If the keyword is an annotation, it will need to implement this function to return the annotation. * plugin?: EvaluationPlugin
If the keyword needs to track state during the evaluation process, you can include an EvaluationPlugin that will get added only when this keyword is present in the schema.
* ValidationContext: object * ast: AST * plugins: EvaluationPlugins[]
- addFormat: (formatHandler: Format) => void
* Format: object * id: string
A URI that uniquely identifies the format. It should use a domain you own to avoid conflict with keywords defined by others. * handler: (value: any) => boolean
A function that takes the value and returns a boolean determining if it passes validation for the format.
- setFormatHandler: (keywordUri: string, formatName: string, formatUri: string) => void
- removeFormatHandler: (keywordUri, formatName) => void
- defineVocabulary: (id: string, keywords: { [keyword: string]: string }) => void
addKeyword.
- getKeywordId: (keywordName: string, dialectId: string) => string
- getKeyword: (keywordId: string) => Keyword
- getKeywordByName: (keywordName: string, dialectId: string) => Keyword
- getKeywordName: (dialectId: string, keywordId: string) => string
contains depends on minContains and maxContains).
- loadDialect: (dialectId: string, dialect: { [vocabularyId: string] }, allowUnknownKeywords: boolean = false) => void
$vocabulary keyword in the meta-schema. The only time you would need to
load a dialect manually is if you're creating a distinct version of JSON
Schema rather than creating a dialect of an existing version of JSON Schema.
- unloadDialect: (dialectId: string) => void
unregisterSchema.
- Validation: Keyword
- getSchema: (uri: string, browser?: Browser) => Promise\
- buildSchemaDocument: (schema: SchemaObject | boolean, retrievalUri?: string, contextDialectId?: string) => SchemaDocument
- canonicalUri: (schema: Browser) => string
- toSchema: (schema: Browser, options: ToSchemaOptions) => object
* ToSchemaOptions: object
* contextDialectId: string (default: "") -- If the dialect of the schema
matches this value, the $schema keyword will be omitted.
* includeDialect: "auto" | "always" | "never" (default: "auto") -- If
"auto", $schema will only be included if it differs from
contextDialectId.
* contextUri: string (default: "") -- $ids will be relative to this
URI.
* includeEmbedded: boolean (default: true) -- If false, embedded schemas
will be unbundled from the schema.
- compile: (schema: Browser) => Promise\
- interpret: (schema: CompiledSchema, instance: JsonNode, outputFormat: ValidationOptions | OutputFormat = BASIC) => Output
- interpret: (schema: CompiledSchema) => Validator
- serialize: (compiledSchema: CompiledSchema) => string
- deserialize: (serialized: string) => CompiledSchema
- OutputFormat: FLAG | BASIC
FLAG output format in the Stable API, the Experimental
API includes support for the BASIC format as specified in the 2019-09
specification (with some minor customizations). This implementation doesn't
include annotations or human readable error messages. The output can be
processed to create human readable error messages as needed.
- EvaluationPlugin: object
Instance API (experimental)
These functions are available from the
@hyperjump/json-schema/instance/experimental export.
This library uses JsonNode objects to represent instances. You'll work with these objects if you create a custom keyword.
This API uses generators to iterate over arrays and objects. If you like using
higher order functions like map/filter/reduce, see
@hyperjump/pact for utilities for
working with generators and async generators.
- fromJs: (value: any, uri?: string) => JsonNode
- fromJson: (json: string, uri?: string) => JsonNode
fromJs, each node includes
offset and length properties that give the node's location in the
source text. Property nodes also include a colonOffset property that gives
the location of the : separating the property name and value. Throws a SyntaxError if the text isn't valid JSON.
- cons: (baseUri: string, pointer: string, value: any, type: string, children: JsonNode[], parent?: JsonNode, offset?: number, length?: number, colonOffset?: number) => JsonNode
fromJs
instead.
- get: (url: string, instance: JsonNode) => JsonNode
- uri: (instance: JsonNode) => string
- value: (instance: JsonNode) => any
- has: (key: string, instance: JsonNode) => boolean
- typeOf: (instance: JsonNode) => string
property type that indicates a property name/value pair
in an object.
- step: (key: string, instance: JsonNode) => JsonType
[] operator.
- iter: (instance: JsonNode) => Generator\
- entries: (instance: JsonNode) => Generator\<[JsonNode, JsonNode]>
Object.entries, but yields JsonNodes for keys and values.
- values: (instance: JsonNode) => Generator\
Object.values, but yields JsonNodes for values.
- keys: (instance: JsonNode) => Generator\
Object.keys, but yields JsonNodes for keys.
- length: (instance: JsonNode) => number
Array.prototype.length.
Annotations (experimental)
JSON Schema is for annotating JSON instances as well as validating them. This module provides utilities for working with JSON documents annotated with JSON Schema.Usage
An annotated JSON document is represented as a (JsonNode)[#instance-api-experimental] AST. You can use this AST to traverse the data structure and get annotations for the values it represents.import { registerSchema } from "@hyperjump/json-schema/draft/2020-12";
import { annotate } from "@hyperjump/json-schema/annotations/experimental";
import * as AnnotatedInstance from "@hyperjump/json-schema/annotated-instance/experimental";
const schemaId = "https://example.com/foo";
const dialectId = "https://json-schema.org/draft/2020-12/schema";
registerSchema({
"$schema": dialectId,
"title": "Person",
"unknown": "foo",
"type": "object",
"properties": {
"name": {
"$ref": "#/$defs/name",
"deprecated": true
},
"givenName": {
"$ref": "#/$defs/name",
"title": "Given Name"
},
"familyName": {
"$ref": "#/$defs/name",
"title": "Family Name"
}
},
"$defs": {
"name": {
"type": "string",
"title": "Name"
}
}
}, schemaId);
const instance = await annotate(schemaId, {
name: "Jason Desrosiers",
givenName: "Jason",
familyName: "Desrosiers"
});
// Get the title of the instance
const titles = AnnotatedInstance.annotation(instance, "title", dialectId); // => ["Person"]
// Unknown keywords are collected as annotations
const unknowns = AnnotatedInstance.annotation(instance, "unknown", dialectId); // => ["foo"]
// The type keyword doesn't produce annotations
const types = AnnotatedInstance.annotation(instance, "type", dialectId); // => []
// Get the title of each of the properties in the object
for (const [propertyNameNode, propertyInstance] of AnnotatedInstance.entries(instance)) {
const propertyName = AnnotatedInstance.value(propertyName);
console.log(propertyName, AnnotatedInstance.annotation(propertyInstance, "title", dialectId));
}
// List all locations in the instance that are deprecated
for (const deprecated of AnnotatedInstance.annotatedWith(instance, "deprecated", dialectId)) {
if (AnnotatedInstance.annotation(deprecated, "deprecated", dialectId)[0]) {
logger.warn(The value at '${deprecated.pointer}' has been deprecated.); // => (Example) "WARN: The value at '/name' has been deprecated."
}
}
API
These are available from the@hyperjump/json-schema/annotations/experimental
export.
- annotate: (schemaUri: string, instance: any, outputFormat: OutputFormat = BASIC) => Promise\
- interpret: (compiledSchema: CompiledSchema, instance: JsonNode, outputFormat: OutputFormat = BASIC) => JsonNode
- ValidationError: Error & { output: OutputUnit }
output field contains an OutputUnit with information about the
error.
AnnotatedInstance API (experimental)
These are available from the@hyperjump/json-schema/annotated-instance/experimental export. The
following functions are available in addition to the functions available in the
Instance API.
- annotation: (instance: JsonNode, keyword: string, dialect?: string): any[];
- annotatedWith: (instance: JsonNode, keyword: string, dialect?: string): Generator
;
- setAnnotation: (instance: JsonNode, keywordId: string, value: any) => JsonNode
Contributing
Tests
Run the tests
npm test
Run the tests with a continuous test runner
npm test -- --watch