@hyperjump/json-schema
Advanced tools
Comparing version 1.1.2 to 1.2.0
@@ -10,3 +10,3 @@ import contentTypeParser from "content-type"; | ||
export const parse = (response) => { | ||
export const parseResponse = (response) => { | ||
const contentType = contentTypeParser.parse(response.headers.get("content-type")); | ||
@@ -13,0 +13,0 @@ if (!(contentType.type in mediaTypePlugins)) { |
@@ -7,4 +7,4 @@ import curry from "just-curry-it"; | ||
import fetch from "./fetch.js"; | ||
import * as Keywords from "./keywords.js"; | ||
import * as MediaTypes from "./media-types.js"; | ||
import { hasDialect, loadDialect, getKeywordName } from "./keywords.js"; | ||
import { parseResponse } from "./media-types.js"; | ||
import * as Reference from "./reference.js"; | ||
@@ -26,3 +26,3 @@ | ||
if (!Keywords.hasDialect(dialectId)) { | ||
if (!hasDialect(dialectId)) { | ||
throw Error(`Encountered unknown dialect '${dialectId}'`); | ||
@@ -32,4 +32,4 @@ } | ||
// Identifiers | ||
const idToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/id") | ||
|| Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id"); | ||
const idToken = getKeywordName(dialectId, "https://json-schema.org/keyword/id") | ||
|| getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id"); | ||
if (retrievalUri === undefined && !(idToken in schema)) { | ||
@@ -47,3 +47,3 @@ throw Error(`Unable to determine an identifier for the schema. Use the '${idToken}' keyword or pass a retrievalUri when loading the schema.`); | ||
// Vocabulary | ||
const vocabularyToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/vocabulary"); | ||
const vocabularyToken = getKeywordName(dialectId, "https://json-schema.org/keyword/vocabulary"); | ||
if (jsonTypeOf(schema[vocabularyToken], "object")) { | ||
@@ -53,3 +53,3 @@ const allowUnknownKeywords = schema[vocabularyToken]["https://json-schema.org/draft/2019-09/vocab/core"] | ||
Keywords.loadDialect(id, schema[vocabularyToken], allowUnknownKeywords); | ||
loadDialect(id, schema[vocabularyToken], allowUnknownKeywords); | ||
delete schema[vocabularyToken]; | ||
@@ -61,3 +61,3 @@ } | ||
// Recursive anchor | ||
const recursiveAnchorToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-2019-09/recursiveAnchor"); | ||
const recursiveAnchorToken = getKeywordName(dialectId, "https://json-schema.org/keyword/draft-2019-09/recursiveAnchor"); | ||
if (schema[recursiveAnchorToken] === true) { | ||
@@ -85,3 +85,3 @@ dynamicAnchors[""] = `${id}#`; | ||
// Legacy id | ||
const legacyIdToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id"); | ||
const legacyIdToken = getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/id"); | ||
if (typeof subject[legacyIdToken] === "string") { | ||
@@ -102,3 +102,3 @@ if (subject[legacyIdToken][0] === "#") { | ||
const embeddedDialectId = typeof subject.$schema === "string" ? toAbsoluteUri(subject.$schema) : dialectId; | ||
const idToken = Keywords.getKeywordName(embeddedDialectId, "https://json-schema.org/keyword/id"); | ||
const idToken = getKeywordName(embeddedDialectId, "https://json-schema.org/keyword/id"); | ||
if (typeof subject[idToken] === "string") { | ||
@@ -111,3 +111,3 @@ subject[idToken] = resolveUri(subject[idToken], id); | ||
// Legacy dynamic anchor | ||
const legacyDynamicAnchorToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-2020-12/dynamicAnchor"); | ||
const legacyDynamicAnchorToken = getKeywordName(dialectId, "https://json-schema.org/keyword/draft-2020-12/dynamicAnchor"); | ||
if (typeof subject[legacyDynamicAnchorToken] === "string") { | ||
@@ -119,3 +119,3 @@ dynamicAnchors[subject[legacyDynamicAnchorToken]] = `${id}#${encodeURI(pointer)}`; | ||
const dynamicAnchorToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/dynamicAnchor"); | ||
const dynamicAnchorToken = getKeywordName(dialectId, "https://json-schema.org/keyword/dynamicAnchor"); | ||
if (typeof subject[dynamicAnchorToken] === "string") { | ||
@@ -126,3 +126,3 @@ dynamicAnchors[subject[dynamicAnchorToken]] = `${id}#${encodeURI(pointer)}`; | ||
const anchorToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/anchor"); | ||
const anchorToken = getKeywordName(dialectId, "https://json-schema.org/keyword/anchor"); | ||
if (typeof subject[anchorToken] === "string") { | ||
@@ -134,3 +134,3 @@ anchors[subject[anchorToken]] = pointer; | ||
// Legacy $ref | ||
const jrefToken = Keywords.getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/ref"); | ||
const jrefToken = getKeywordName(dialectId, "https://json-schema.org/keyword/draft-04/ref"); | ||
if (typeof subject[jrefToken] === "string") { | ||
@@ -183,7 +183,7 @@ return Reference.cons(subject[jrefToken], subject); | ||
const [schema, contextDialectId] = await MediaTypes.parse(response); | ||
const [schema, contextDialectId] = await parseResponse(response); | ||
// Try to determine the dialect from the meta-schema if it isn't already known | ||
const dialectId = toAbsoluteUri(schema.$schema || contextDialectId || defaultDialectId); | ||
if (!Keywords.hasDialect(dialectId) && !hasStoredSchema(dialectId)) { | ||
if (!hasDialect(dialectId) && !hasStoredSchema(dialectId)) { | ||
await get(dialectId); | ||
@@ -257,7 +257,8 @@ } | ||
const idToken = Keywords.getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/id"); | ||
const anchorToken = Keywords.getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/anchor"); | ||
const dynamicAnchorToken = Keywords.getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/dynamicAnchor"); | ||
const legacyDynamicAnchorToken = Keywords.getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-2020-12/dynamicAnchor"); | ||
const recursiveAnchorToken = Keywords.getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/recursiveAnchor"); | ||
const idToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/id") | ||
|| getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-04/id"); | ||
const anchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/anchor"); | ||
const dynamicAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/dynamicAnchor"); | ||
const legacyDynamicAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/draft-2020-12/dynamicAnchor"); | ||
const recursiveAnchorToken = getKeywordName(schemaDoc.dialectId, "https://json-schema.org/keyword/recursiveAnchor"); | ||
@@ -264,0 +265,0 @@ const anchors = {}; |
{ | ||
"name": "@hyperjump/json-schema", | ||
"version": "1.1.2", | ||
"version": "1.2.0", | ||
"description": "A JSON Schema validator with support for custom keywords, vocabularies, and dialects", | ||
@@ -18,3 +18,4 @@ "type": "module", | ||
"./schema/experimental": "./lib/schema.js", | ||
"./instance/experimental": "./lib/instance.js" | ||
"./instance/experimental": "./lib/instance.js", | ||
"./bundle": "./bundle/index.js" | ||
}, | ||
@@ -27,3 +28,3 @@ "browser": { | ||
"lint": "eslint lib stable draft-* openapi-*", | ||
"test": "mocha 'lib/**/*.spec.ts' 'stable/**/*.spec.ts' 'draft-*/**/*.spec.ts' 'openapi-*/**/*.spec.ts'" | ||
"test": "mocha 'lib/**/*.spec.ts' 'stable/**/*.spec.ts' 'draft-*/**/*.spec.ts' 'openapi-*/**/*.spec.ts' 'bundle/**/*.spec.ts'" | ||
}, | ||
@@ -72,4 +73,5 @@ "repository": "github:hyperjump-io/json-schema", | ||
"fastest-stable-stringify": "^2.0.2", | ||
"node-fetch": "^3.3.0" | ||
"node-fetch": "^3.3.0", | ||
"uuid": "^9.0.0" | ||
} | ||
} |
166
README.md
@@ -14,2 +14,5 @@ # Hyperjump - JSON Schema | ||
* Create custom keywords, vocabularies, and dialects | ||
* Bundle multiple schemas into one document | ||
* Uses the process defined in the 2020-12 specification but works with any | ||
dialect. | ||
* Provides utilities for building non-validation JSON Schema tooling | ||
@@ -45,3 +48,8 @@ | ||
## Usage | ||
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 | ||
@@ -135,3 +143,3 @@ `@hyperjump/json-schema/*` to import the version you need. | ||
**Open API** | ||
**OpenAPI** | ||
@@ -161,3 +169,3 @@ The OpenAPI 3.0 and 3.1 meta-schemas are pre-loaded and the OpenAPI JSON Schema | ||
## API | ||
### API | ||
These are available from any of the exports that refer to a version of JSON | ||
@@ -185,8 +193,8 @@ Schema, such as `@hyperjump/json-schema/draft-2020-12`. | ||
The `output` field contains an `OutputUnit` with information about the | ||
error. You can use the `setMetaOutputFormat` configuration to set the output | ||
format that is returned in `output`. | ||
* **setMetaOutputFormat**: (outputFormat: OutputFormat) => void | ||
error. You can use the `setMetaSchemaOutputFormat` configuration to set the | ||
output format that is returned in `output`. | ||
* **setMetaSchemaOutputFormat**: (outputFormat: OutputFormat) => void | ||
Set the output format used for validating schemas. | ||
* **getMetaOutputFormat**: () => OutputFormat | ||
* **getMetaSchemaOutputFormat**: () => OutputFormat | ||
@@ -229,24 +237,88 @@ Get the output format used for validating schemas. | ||
## Experimental | ||
The JSON Schema specification includes several features that are experimental in | ||
nature including the Vocabulary System, Output Formats, and Annotations. This | ||
implementation aims to support only the latest version of experimental features | ||
as they evolve. There will not be a major version bump if there needs to be | ||
backward incompatible changes to the Experimental API. | ||
## Bundling | ||
### Usage | ||
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. | ||
You can bundle schemas with external references into 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 one 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. | ||
```javascript | ||
import { BASIC } from "@hyperjump/json-schema/experimental"; | ||
import { addSchema } from "@hyperjump/json-schema/draft-2020-12"; | ||
import { bundle } from "@hyperjump/json-schema/bundle"; | ||
addSchema({ | ||
"$id": "https://example.com/main" | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"type": "object", | ||
"properties": { | ||
"foo": { "$ref": "/string" } | ||
} | ||
}); | ||
addSchema({ | ||
"$id": "https://example.com/string", | ||
"$schema": "https://json-schema.org/draft/2020-12/schema", | ||
"type": "string" | ||
}); | ||
const bundledSchema = await bundle("https://example.com/main"); // { | ||
// "$id": "https://example.com/main", | ||
// "$schema": "https://json-schema.org/draft/2020-12/schema", | ||
// | ||
// "type": "object", | ||
// "properties": { | ||
// "foo": { "$ref": "/string" } | ||
// }, | ||
// | ||
// "$defs": { | ||
// "https://example.com/main": { | ||
// "$id": "https://example.com/main", | ||
// "type": "string" | ||
// } | ||
// } | ||
// } | ||
``` | ||
### API | ||
These are available from the `@hyperjump/json-schema/bundle` export. | ||
* **bundle**: (uri: string, options: Options) => Promise<SchemaObject> | ||
Create a bundled schema starting with the given schema. External schemas | ||
will be fetched from the filesystem, the network, or internally as needed. | ||
Options: | ||
* alwaysIncludeDialect: boolean (default: false) -- Include dialect even | ||
when it isn't strictly needed | ||
* bundleMode: "flat" | "full" (default: "flat") -- When bundling schemas | ||
that already contain bundled schemas, "flat" mode with remove nested | ||
embedded schemas and put them all in the top level `$defs`. When using | ||
"full" mode, it will keep the already embedded schemas around, which will | ||
result in some embedded schema duplication. | ||
* definitionNamingStrategy: "uri" | "uuid" (default: "uri") -- By default | ||
the name used in definitions for embedded schemas will match the | ||
identifier of the embedded schema. This naming is unlikely to collide | ||
with actual definitions, but if you want to be sure, you can use the | ||
"uuid" strategy instead to be sure you get a unique name. | ||
* externalSchemas: string[] (default: []) -- A list of schemas URIs that | ||
are available externally and should not be included in the bundle. | ||
## Output Formats (Experimental) | ||
### Usage | ||
**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. | ||
format used for validation to get more information about failures. | ||
```javascript | ||
import { BASIC } from "@hyperjump/json-schema/experimental"; | ||
const output = await validate("https://example.com/schema1", 42, BASIC); | ||
@@ -260,3 +332,6 @@ ``` | ||
```javascript | ||
setMetaOutputFormat(BASIC); | ||
import { validate, setMetaSchemaOutputFormat } from "@hyperjump/json-schema/draft-2020-12"; | ||
import { BASIC } from "@hyperjump/json-schema/experimental"; | ||
setMetaSchemaOutputFormat(BASIC); | ||
try { | ||
@@ -269,4 +344,16 @@ const output = await validate("https://example.com/invalid-schema"); | ||
**Keywords, Vocabularies, and Dialects** | ||
### API | ||
**Type Definitions** | ||
* **OutputFormat**: **FLAG** | **BASIC** | **DETAILED** | **VERBOSE** | ||
In addition to the `FLAG` output format in the Stable API, the Experimental | ||
API includes support for the `BASIC`, `DETAILED`, and `VERBOSE` formats 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. | ||
## Meta-Schemas, Keywords, Vocabularies, and Dialects (Experimental) | ||
### Usage | ||
In order to create and use a custom keyword, you need to define your keyword's | ||
@@ -395,10 +482,2 @@ behavior, create a vocabulary that includes that keyword, and then create a | ||
* **compile**: (schema: SchemaDocument) => Promise<CompiledSchema> | ||
Return a compiled schema. This is useful if you're creating tooling for | ||
something other than validation. | ||
* **interpret**: (schema: CompiledSchema, instance: Instance, outputFormat: OutputFormat = BASIC) => OutputUnit | ||
A curried function for validating an instance against a compiled schema. | ||
This can be useful for creating custom output formats. | ||
* **addKeyword**: (keywordHandler: Keyword) => void | ||
@@ -431,14 +510,2 @@ | ||
**Type Definitions** | ||
The following types are used in the above definitions | ||
* **OutputFormat**: **FLAG** | **BASIC** | **DETAILED** | **VERBOSE** | ||
In addition to the `FLAG` output format in the Stable API, the Experimental | ||
API includes support for the `BASIC`, `DETAILED`, and `VERBOSE` formats 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. | ||
* **Keyword**: object | ||
@@ -472,3 +539,3 @@ * id: string | ||
### Schema | ||
### Schema API | ||
These functions are available from the | ||
@@ -532,3 +599,3 @@ `@hyperjump/json-schema/schema/experimental` export. | ||
### Instance | ||
### Instance API | ||
These functions are available from the | ||
@@ -584,2 +651,15 @@ `@hyperjump/json-schema/instance/experimental` export. | ||
## Low-level Utilities (Experimental) | ||
### API | ||
These are available from the `@hyperjump/json-schema/experimental` export. | ||
* **compile**: (schema: SchemaDocument) => Promise<CompiledSchema> | ||
Return a compiled schema. This is useful if you're creating tooling for | ||
something other than validation. | ||
* **interpret**: (schema: CompiledSchema, instance: Instance, outputFormat: OutputFormat = BASIC) => OutputUnit | ||
A curried function for validating an instance against a compiled schema. | ||
This can be useful for creating custom output formats. | ||
## Contributing | ||
@@ -586,0 +666,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
286293
162
7762
667
8
+ Addeduuid@^9.0.0
+ Addeduuid@9.0.1(transitive)