New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@hyperjump/json-schema

Package Overview
Dependencies
Maintainers
1
Versions
99
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hyperjump/json-schema - npm Package Compare versions

Comparing version 1.8.0 to 1.9.0

lib/output.js

86

annotations/annotated-instance.d.ts

@@ -1,83 +0,5 @@

import type { JsonType } from "../lib/common.js";
import type { Json, JsonObject } from "@hyperjump/json-pointer";
export const setAnnotation: (keywordUri: string, schemaLocation: string, value: string) => void;
export const annotation: <A>(instance: JsonNode, keyword: string, dialectUri?: string) => A[];
export const annotatedWith: (instance: JsonNode, keyword: string, dialectUri?: string) => JsonNode[];
export const annotate: (instance: AnnotatedJsonDocument, keyword: string, value: string) => AnnotatedJsonDocument;
export const annotation: <A>(instance: AnnotatedJsonDocument, keyword: string, dialectId?: string) => A[];
export const annotatedWith: (instance: AnnotatedJsonDocument, keyword: string, dialectId?: string) => AnnotatedJsonDocument[];
export const nil: AnnotatedJsonDocument<undefined>;
export const cons: (instance: Json, id?: string) => AnnotatedJsonDocument;
export const get: (uri: string, context?: AnnotatedJsonDocument) => AnnotatedJsonDocument;
export const uri: (doc: AnnotatedJsonDocument) => string;
export const value: <A extends Json>(doc: AnnotatedJsonDocument<A>) => A;
export const has: (key: string, doc: AnnotatedJsonDocument<JsonObject>) => boolean;
export const typeOf: (
(doc: AnnotatedJsonDocument, type: "null") => doc is AnnotatedJsonDocument<null>
) & (
(doc: AnnotatedJsonDocument, type: "boolean") => doc is AnnotatedJsonDocument<boolean>
) & (
(doc: AnnotatedJsonDocument, type: "object") => doc is AnnotatedJsonDocument<JsonObject>
) & (
(doc: AnnotatedJsonDocument, type: "array") => doc is AnnotatedJsonDocument<Json[]>
) & (
(doc: AnnotatedJsonDocument, type: "number" | "integer") => doc is AnnotatedJsonDocument<number>
) & (
(doc: AnnotatedJsonDocument, type: "string") => doc is AnnotatedJsonDocument<string>
) & (
(doc: AnnotatedJsonDocument, type: JsonType) => boolean
) & (
(doc: AnnotatedJsonDocument) => (type: JsonType) => boolean
);
export const step: (key: string, doc: AnnotatedJsonDocument<JsonObject | Json[]>) => AnnotatedJsonDocument<typeof doc.value>;
export const entries: (doc: AnnotatedJsonDocument<JsonObject>) => [string, AnnotatedJsonDocument][];
export const keys: (doc: AnnotatedJsonDocument<JsonObject>) => string[];
export const map: (
<A>(fn: MapFn<A>, doc: AnnotatedJsonDocument<Json[]>) => A[]
) & (
<A>(fn: MapFn<A>) => (doc: AnnotatedJsonDocument<Json[]>) => A[]
);
export const forEach: (
(fn: ForEachFn, doc: AnnotatedJsonDocument<Json[]>) => void
) & (
(fn: ForEachFn) => (doc: AnnotatedJsonDocument<Json[]>) => void
);
export const filter: (
(fn: FilterFn, doc: AnnotatedJsonDocument<Json[]>) => AnnotatedJsonDocument[]
) & (
(fn: FilterFn) => (doc: AnnotatedJsonDocument<Json[]>) => AnnotatedJsonDocument[]
);
export const reduce: (
<A>(fn: ReduceFn<A>, acc: A, doc: AnnotatedJsonDocument<Json[]>) => A
) & (
<A>(fn: ReduceFn<A>) => (acc: A, doc: AnnotatedJsonDocument<Json[]>) => A
) & (
<A>(fn: ReduceFn<A>) => (acc: A) => (doc: AnnotatedJsonDocument<Json[]>) => A
);
export const every: (
(fn: FilterFn, doc: AnnotatedJsonDocument<Json[]>) => boolean
) & (
(fn: FilterFn) => (doc: AnnotatedJsonDocument<Json[]>) => boolean
);
export const some: (
(fn: FilterFn, doc: AnnotatedJsonDocument<Json[]>) => boolean
) & (
(fn: FilterFn) => (doc: AnnotatedJsonDocument<Json[]>) => boolean
);
export const length: (doc: AnnotatedJsonDocument<Json[] | string>) => number;
type MapFn<A> = (element: AnnotatedJsonDocument, index: number) => A;
type ForEachFn = (element: AnnotatedJsonDocument, index: number) => void;
type FilterFn = (element: AnnotatedJsonDocument, index: number) => boolean;
type ReduceFn<A> = (accumulator: A, currentValue: AnnotatedJsonDocument, index: number) => A;
export type AnnotatedJsonDocument<A extends Json | undefined = Json> = {
id: string;
pointer: string;
instance: Json;
value: A;
annotations: {
[pointer: string]: {
[keyword: string]: unknown[]
}
}
};
export * from "../lib/instance.js";

@@ -1,3 +0,3 @@

import { toAbsoluteIri } from "@hyperjump/uri";
import { nil as nilInstance, get } from "../lib/instance.js";
import * as JsonPointer from "@hyperjump/json-pointer";
import * as Instance from "../lib/instance.js";
import { getKeywordId } from "../lib/keywords.js";

@@ -8,44 +8,42 @@

export const nil = { ...nilInstance, annotations: {} }; // eslint-disable-line import/export
export const cons = (instance, id = undefined) => ({ // eslint-disable-line import/export
...nil,
id: id ? toAbsoluteIri(id) : "",
instance,
value: instance
});
export const annotation = (instance, keyword, dialectId = defaultDialectId) => {
const keywordId = getKeywordId(keyword, dialectId);
return instance.annotations[instance.pointer]?.[keywordId] || [];
export const setAnnotation = (node, keywordUri, schemaLocation, value) => {
if (!(keywordUri in node.annotations)) {
node.annotations[keywordUri] = {};
}
node.annotations[keywordUri][schemaLocation] = value;
};
export const annotate = (instance, keyword, value) => {
return Object.freeze({
...instance,
annotations: {
...instance.annotations,
[instance.pointer]: {
...instance.annotations[instance.pointer],
[keyword]: [
value,
...instance.annotations[instance.pointer]?.[keyword] || []
]
}
export const annotation = (node, keyword, dialect = defaultDialectId) => {
const keywordUri = getKeywordId(keyword, dialect);
let currentNode = node.root;
const errors = Object.keys(node.root.errors);
for (let segment of JsonPointer.pointerSegments(node.pointer)) {
segment = segment === "-" && currentNode.typeOf() === "array" ? currentNode.length() : segment;
currentNode = Instance.step(segment, currentNode);
errors.push(...Object.keys(currentNode.errors));
}
const annotations = [];
for (const schemaLocation in node.annotations[keywordUri]) {
if (!errors.some((error) => schemaLocation.startsWith(error))) {
annotations.unshift(node.annotations[keywordUri][schemaLocation]);
}
});
}
return annotations;
};
export const annotatedWith = (instance, keyword, dialectId = defaultDialectId) => {
const instances = [];
const nodes = [];
const keywordId = getKeywordId(keyword, dialectId);
for (const instancePointer in instance.annotations) {
if (keywordId in instance.annotations[instancePointer]) {
instances.push(get(`#${instancePointer}`, instance));
for (const node of Instance.allNodes(instance)) {
if (annotation(node, keyword, dialectId).length > 0) {
nodes.push(node);
}
}
return instances;
return nodes;
};
export * from "../lib/instance.js"; // eslint-disable-line import/export
export * from "../lib/instance.js";
import type { OutputFormat, OutputUnit } from "../lib/index.js";
import type { AnnotatedJsonDocument } from "./annotated-instance.js";
import type { CompiledSchema } from "../lib/experimental.js";
import type { JsonNode } from "../lib/json-node.js";
import type { Json } from "@hyperjump/json-pointer";
export const annotate: (
(schemaUrl: string, value: unknown, outputFormat?: OutputFormat) => Promise<Annotator>
(schemaUrl: string, value: Json, outputFormat?: OutputFormat) => Promise<JsonNode>
) & (

@@ -11,4 +13,6 @@ (schemaUrl: string) => Promise<Annotator>

export type Annotator = (value: unknown, outputFormat?: OutputFormat) => AnnotatedJsonDocument;
export type Annotator = (value: Json, outputFormat?: OutputFormat) => JsonNode;
export const interpret: (compiledSchema: CompiledSchema, value: JsonNode, outputFormat?: OutputFormat) => JsonNode;
export class ValidationError extends Error {

@@ -15,0 +19,0 @@ public output: OutputUnit;

@@ -1,12 +0,10 @@

import { subscribe, unsubscribe } from "../lib/pubsub.js";
import * as Instance from "./annotated-instance.js";
import { ValidationError } from "./validation-error.js";
import { getSchema, getKeyword, compile, interpret as validate, BASIC } from "../lib/experimental.js";
import { getSchema, compile, interpret as validate, BASIC } from "../lib/experimental.js";
import * as Instance from "../lib/instance.js";
export const annotate = async (schemaUri, json = undefined, outputFormat = undefined) => {
loadKeywordSupport();
const schema = await getSchema(schemaUri);
const compiled = await compile(schema);
const interpretAst = (json, outputFormat) => interpret(compiled, Instance.cons(json), outputFormat);
const interpretAst = (json, outputFormat) => interpret(compiled, Instance.fromJs(json), outputFormat);

@@ -16,109 +14,11 @@ return json === undefined ? interpretAst : interpretAst(json, outputFormat);

const interpret = ({ ast, schemaUri }, instance, outputFormat = BASIC) => {
const output = [instance];
const subscriptionToken = subscribe("result", outputHandler(output));
try {
const result = validate({ ast, schemaUri }, instance, outputFormat);
if (!result.valid) {
throw new ValidationError(result);
}
} finally {
unsubscribe("result", subscriptionToken);
export const interpret = ({ ast, schemaUri }, instance, outputFormat = BASIC) => {
const result = validate({ ast, schemaUri }, instance, outputFormat);
if (!result.valid) {
throw new ValidationError(result);
}
return output[0];
return instance;
};
const outputHandler = (output) => {
let isPassing = true;
const instanceStack = [];
return (message, resultNode) => {
if (message === "result.start") {
instanceStack.push(output[0]);
isPassing = true;
} else if (message === "result" && isPassing) {
output[0] = Instance.get(resultNode.instanceLocation, output[0]);
if (resultNode.valid) {
const keywordHandler = getKeyword(resultNode.keyword);
if (keywordHandler?.annotation) {
const annotation = keywordHandler.annotation(resultNode.ast);
output[0] = Instance.annotate(output[0], resultNode.keyword, annotation);
}
} else {
output[0] = instanceStack[instanceStack.length - 1];
isPassing = false;
}
} else if (message === "result.end") {
instanceStack.pop();
}
};
};
const identity = (a) => a;
const loadKeywordSupport = () => {
const title = getKeyword("https://json-schema.org/keyword/title");
if (title) {
title.annotation = identity;
}
const description = getKeyword("https://json-schema.org/keyword/description");
if (description) {
description.annotation = identity;
}
const _default = getKeyword("https://json-schema.org/keyword/default");
if (_default) {
_default.annotation = identity;
}
const deprecated = getKeyword("https://json-schema.org/keyword/deprecated");
if (deprecated) {
deprecated.annotation = identity;
}
const readOnly = getKeyword("https://json-schema.org/keyword/readOnly");
if (readOnly) {
readOnly.annotation = identity;
}
const writeOnly = getKeyword("https://json-schema.org/keyword/writeOnly");
if (writeOnly) {
writeOnly.annotation = identity;
}
const examples = getKeyword("https://json-schema.org/keyword/examples");
if (examples) {
examples.annotation = identity;
}
const format = getKeyword("https://json-schema.org/keyword/format");
if (format) {
format.annotation = identity;
}
const contentMediaType = getKeyword("https://json-schema.org/keyword/contentMediaType");
if (contentMediaType) {
contentMediaType.annotation = identity;
}
const contentEncoding = getKeyword("https://json-schema.org/keyword/contentEncoding");
if (contentEncoding) {
contentEncoding.annotation = identity;
}
const contentSchema = getKeyword("https://json-schema.org/keyword/contentSchema");
if (contentSchema) {
contentSchema.annotation = identity;
}
const unknown = getKeyword("https://json-schema.org/keyword/unknown");
if (unknown) {
unknown.annotation = identity;
}
};
export { ValidationError } from "./validation-error.js";

@@ -30,3 +30,3 @@ import { pipe, drop, every } from "@hyperjump/pact";

const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
if (!interpret(keywordValue, instance, ast, dynamicAnchors)) {
if (!interpret(keywordValue, instance, ast, dynamicAnchors, true)) {
return false;

@@ -33,0 +33,0 @@ }

@@ -38,3 +38,3 @@ import { pipe, asyncMap, asyncCollectArray, every, zip, take, range, collectSet } from "@hyperjump/pact";

const collectEvaluatedItems = (items, instance, ast, dynamicAnchors) => {
return interpret(items, instance, ast, dynamicAnchors) && (typeof items === "string"
return interpret(items, instance, ast, dynamicAnchors, true) && (typeof items === "string"
? collectSet(range(0, Instance.length(instance)))

@@ -41,0 +41,0 @@ : collectSet(range(0, items.length)));

import curry from "just-curry-it";
import { resolveIri, toAbsoluteIri } from "@hyperjump/uri";
import { subscribe, unsubscribe } from "./pubsub.js";
import { subscribe } from "./pubsub.js";
import {

@@ -14,5 +14,6 @@ setMetaSchemaOutputFormat,

import Validation from "./keywords/validation.js";
import { toOutputFormat } from "./output.js";
export const FLAG = "FLAG", BASIC = "BASIC", DETAILED = "DETAILED", VERBOSE = "VERBOSE";
export const FLAG = "FLAG", BASIC = "BASIC";
setMetaSchemaOutputFormat(FLAG);

@@ -23,3 +24,3 @@

const compiled = await compile(schema);
const interpretAst = (value, outputFormat) => interpret(compiled, Instance.cons(value), outputFormat);
const interpretAst = (value, outputFormat) => interpret(compiled, Instance.fromJs(value), outputFormat);

@@ -35,50 +36,7 @@ return value === undefined ? interpretAst : interpretAst(value, outputFormat);

export const interpret = curry(({ ast, schemaUri }, value, outputFormat = FLAG) => {
if (![FLAG, BASIC, DETAILED, VERBOSE].includes(outputFormat)) {
throw Error(`The '${outputFormat}' error format is not supported`);
}
const output = [];
const subscriptionToken = subscribe("result", outputHandler(outputFormat, output));
try {
Validation.interpret(schemaUri, value, ast, {});
} finally {
unsubscribe("result", subscriptionToken);
}
return output[0];
export const interpret = curry(({ ast, schemaUri }, instance, outputFormat = FLAG) => {
Validation.interpret(schemaUri, instance, ast, {});
return toOutputFormat(instance, outputFormat);
});
const outputHandler = (outputFormat, output) => {
const resultStack = [];
return (message, keywordResult) => {
if (message === "result") {
const { keyword, absoluteKeywordLocation, instanceLocation, valid } = keywordResult;
const result = { keyword, absoluteKeywordLocation, instanceLocation, valid, errors: [] };
resultStack.push(result);
} else if (message === "result.start") {
resultStack.push(message);
} else if (message === "result.end") {
const result = resultStack.pop();
while (resultStack[resultStack.length - 1] !== "result.start") {
const topResult = resultStack.pop();
const errors = [topResult];
if (outputFormat === BASIC) {
errors.push(...topResult.errors);
delete topResult.errors;
}
if (outputFormat === VERBOSE || (outputFormat !== FLAG && !topResult.valid)) {
result.errors.unshift(...errors);
}
}
resultStack[resultStack.length - 1] = result;
output[0] = result;
}
};
};
const metaValidators = {};

@@ -97,3 +55,3 @@ subscribe("validate.metaValidate", async (_message, schema) => {

// Interpret
const schemaInstance = Instance.cons(schema.document.root, schema.document.baseUri);
const schemaInstance = Instance.fromJs(schema.document.root, schema.document.baseUri);
const metaResults = metaValidators[schema.document.dialectId](schemaInstance, getMetaSchemaOutputFormat());

@@ -100,0 +58,0 @@ if (!metaResults.valid) {

import type { Browser, Document } from "@hyperjump/browser";
import type { Validator, OutputUnit, OutputFormat, SchemaObject } from "./index.js";
import type { JsonDocument } from "./instance.js";
import type { JsonNode } from "./instance.js";
// Compile/interpret
export const compile: (url: string) => Promise<CompiledSchema>;
export const compile: (schema: Browser<SchemaDocument>) => Promise<CompiledSchema>;
export const interpret: (

@@ -35,4 +35,2 @@ (compiledSchema: CompiledSchema, value: unknown, outputFormat?: OutputFormat) => OutputUnit

export const BASIC: "BASIC";
export const DETAILED: "DETAILED";
export const VERBOSE: "VERBOSE";

@@ -73,5 +71,5 @@ // Schema

compile: (schema: Browser<SchemaDocument>, ast: AST, parentSchema: Browser<SchemaDocument>) => Promise<A>;
interpret: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors) => boolean;
collectEvaluatedProperties?: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<string> | false;
collectEvaluatedItems?: (compiledKeywordValue: A, instance: JsonDocument, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<number> | false;
interpret: (compiledKeywordValue: A, instance: JsonNode, ast: AST, dynamicAnchors: Anchors, quiet: boolean, schemaLocation: string) => boolean;
collectEvaluatedProperties?: (compiledKeywordValue: A, instance: JsonNode, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<string> | false;
collectEvaluatedItems?: (compiledKeywordValue: A, instance: JsonNode, ast: AST, dynamicAnchors: Anchors, isTop?: boolean) => Set<number> | false;
collectExternalIds?: (visited: Set<string>, parentSchema: Browser<SchemaDocument>, schema: Browser<SchemaDocument>) => Promise<Set<string>>;

@@ -78,0 +76,0 @@ annotation?: <B>(compiledKeywordValue: A) => B;

@@ -1,2 +0,2 @@

export { compile, interpret, BASIC, DETAILED, VERBOSE } from "./core.js";
export { compile, interpret, BASIC } from "./core.js";
export {

@@ -3,0 +3,0 @@ addKeyword, getKeyword, getKeywordByName, getKeywordName, getKeywordId,

@@ -0,1 +1,4 @@

import type { Json } from "@hyperjump/json-pointer";
export type SchemaFragment = string | number | boolean | null | SchemaObject | SchemaFragment[];

@@ -15,3 +18,3 @@ export type SchemaObject = {

export const validate: (
(url: string, value: unknown, outputFormat?: OutputFormat) => Promise<OutputUnit>
(url: string, value: Json, outputFormat?: OutputFormat) => Promise<OutputUnit>
) & (

@@ -21,3 +24,3 @@ (url: string) => Promise<Validator>

export type Validator = (value: unknown, outputFormat?: OutputFormat) => OutputUnit;
export type Validator = (value: Json, outputFormat?: OutputFormat) => OutputUnit;

@@ -24,0 +27,0 @@ export type OutputUnit = {

@@ -1,29 +0,30 @@

import type { JsonType } from "./common.js";
import type { Json, JsonObject } from "@hyperjump/json-pointer";
import type { Json } from "@hyperjump/json-pointer";
export const nil: JsonDocument<undefined>;
export const cons: (instance: Json, id?: string) => JsonDocument;
export const get: (url: string, context?: JsonDocument) => JsonDocument;
export const uri: (doc: JsonDocument) => string;
export const value: <A extends Json>(doc: JsonDocument<A>) => A;
export const has: (key: string, doc: JsonDocument<JsonObject>) => boolean;
export const typeOf: (doc: JsonDocument) => JsonType;
export const step: (key: string, doc: JsonDocument<JsonObject | Json[]>) => JsonDocument<typeof doc.value>;
export const iter: (doc: JsonDocument<JsonObject>) => Generator<JsonDocument>;
export const keys: (doc: JsonDocument<JsonObject>) => Generator<string>;
export const values: (doc: JsonDocument<JsonObject>) => Generator<JsonDocument>;
export const entries: (doc: JsonDocument<JsonObject>) => Generator<[string, JsonDocument]>;
export const length: (doc: JsonDocument<Json[] | string>) => number;
export const fromJs: (value: Json, uri?: string) => JsonNode;
type MapFn<A> = (element: JsonDocument, index: number) => A;
type ForEachFn = (element: JsonDocument, index: number) => void;
type FilterFn = (element: JsonDocument, index: number) => boolean;
type ReduceFn<A> = (accumulator: A, currentValue: JsonDocument, index: number) => A;
export const get: (url: string, context: JsonNode) => JsonNode | undefined;
export const uri: (node: JsonNode) => string;
export const value: <A>(node: JsonNode) => A;
export const has: (key: string, node: JsonNode) => boolean;
export const typeOf: (node: JsonNode) => JsonType;
export const step: (key: string, node: JsonNode) => JsonNode;
export const iter: (node: JsonNode) => Generator<JsonNode>;
export const keys: (node: JsonNode) => Generator<JsonNode>;
export const values: (node: JsonNode) => Generator<JsonNode>;
export const entries: (node: JsonNode) => Generator<[JsonNode, JsonNode]>;
export const length: (node: JsonNode) => number;
export type JsonDocument<A extends Json | undefined = Json> = {
id: string;
export const allNodes: (node) => Generator<JsonNode>;
export type JsonNode = {
baseUri: string;
pointer: string;
instance: Json;
value: A;
type: JsonNodeType;
children: JsonNode[];
parent: JsonNode;
root: JsonNode;
valid: boolean;
};
type JsonNodeType = "object" | "array" | "string" | "number" | "boolean" | "null" | "property";

@@ -1,63 +0,158 @@

import { append as pointerAppend, get as pointerGet } from "@hyperjump/json-pointer";
import * as JsonPointer from "@hyperjump/json-pointer";
import { reduce } from "@hyperjump/pact";
import { toAbsoluteIri } from "@hyperjump/uri";
import { jsonTypeOf, uriFragment } from "./common.js";
import { Reference } from "@hyperjump/browser/jref";
import { toAbsoluteUri, uriFragment } from "./common.js";
export const nil = { id: undefined, pointer: "", instance: undefined, value: undefined };
export const cons = (instance, id = undefined) => ({
...nil,
id: id ? toAbsoluteIri(id) : "",
instance,
value: instance
});
export const fromJs = (value, uri = "", pointer = "", parent = undefined) => {
const jsType = typeof value;
export const get = (url, instance = nil) => {
if (!url.startsWith("#")) {
throw Error(`No JSON document found at '${url.split("#")[0]}'`);
switch (jsType) {
case "number":
case "string":
case "boolean":
return cons(uri, pointer, value, jsType, [], parent);
case "object":
if (value === null) {
return cons(uri, pointer, value, "null", [], parent);
} else if (Array.isArray(value)) {
const arrayNode = cons(uri, pointer, value, "array", [], parent);
arrayNode.children = value.map((item, index) => {
return fromJs(item, uri, JsonPointer.append(index, pointer), arrayNode);
});
return arrayNode;
} else if (Object.getPrototypeOf(value) === Object.prototype) {
const objectNode = cons(uri, pointer, value, "object", [], parent);
objectNode.children = Object.entries(value).map((entry) => {
const propertyPointer = JsonPointer.append(entry[0], pointer);
const propertyNode = cons(uri, propertyPointer, undefined, "property", [], objectNode);
propertyNode.children = entry.map((property) => fromJs(property, uri, propertyPointer, propertyNode));
return propertyNode;
});
return objectNode;
} else if (value instanceof Reference) {
return fromJs(value.toJSON(), uri, pointer, parent);
}
default:
const type = jsType === "object" ? Object.getPrototypeOf(value).constructor.name || "anonymous" : jsType;
throw Error(`Not a JSON compatible type: ${type}`);
}
};
const pointer = uriFragment(url);
return {
...instance,
const cons = (baseUri, pointer, value, type, children, parent) => {
const node = {
baseUri: baseUri ? toAbsoluteIri(baseUri) : "",
pointer: pointer,
value: pointerGet(pointer, instance.instance)
value: value,
type: type,
children: children,
parent: parent,
valid: true,
errors: {},
annotations: {}
};
node.root = parent?.root ?? node;
return node;
};
export const uri = (doc) => `${doc.id || ""}#${encodeURI(doc.pointer)}`;
export const value = (doc) => doc.value instanceof Reference ? doc.value.toJSON() : doc.value;
export const has = (key, doc) => key in value(doc);
export const typeOf = (doc) => jsonTypeOf(value(doc));
export const get = (uri, instance) => {
const schemaId = toAbsoluteUri(uri);
if (schemaId !== instance.baseUri && schemaId !== "") {
throw Error(`Reference '${uri}' is not local to '${instance.baseUri}'`);
}
export const step = (key, doc) => ({
...doc,
pointer: pointerAppend(key, doc.pointer),
value: value(doc)[key]
});
const pointer = uriFragment(uri);
return reduce((node, segment) => {
segment = segment === "-" && typeOf(node) === "array" ? length(node) : segment;
return step(segment, node);
}, instance.root, JsonPointer.pointerSegments(pointer));
};
export const iter = function* (doc) {
for (let index = 0; index < value(doc).length; index++) {
yield step(index, doc);
export const uri = (node) => `${node.baseUri}#${encodeURI(node.pointer)}`;
export const value = (node) => node.value;
export const typeOf = (node) => node.type;
export const has = (key, node) => key in node.value;
export const step = (key, node) => {
if (node.type !== "object" && node.type !== "array") {
return;
}
switch (node.type) {
case "object":
const property = node.children.find((propertyNode) => {
return value(propertyNode.children[0]) === key;
});
return property?.children[1];
case "array":
const index = parseInt(key, 10);
return node.children[index];
default:
return;
}
};
export const keys = function* (doc) {
for (const key in value(doc)) {
yield key;
export const iter = function* (node) {
if (node.type !== "array") {
return;
}
yield* node.children;
};
export const values = function* (doc) {
for (const key in value(doc)) {
yield step(key, doc);
export const keys = function* (node) {
if (node.type !== "object") {
return;
}
for (const property of node.children) {
yield property.children[0];
}
};
export const entries = function* (doc) {
for (const key in value(doc)) {
yield [key, step(key, doc)];
export const values = function* (node) {
if (node.type !== "object") {
return;
}
for (const property of node.children) {
yield property.children[1];
}
};
export const length = (doc) => value(doc).length;
export const entries = function* (node) {
if (node.type !== "object") {
return;
}
for (const property of node.children) {
yield property.children;
}
};
export const length = (node) => {
if (node.type !== "array") {
return;
}
return node.children.length;
};
export const allNodes = function* (node) {
yield node;
switch (typeOf(node)) {
case "object":
for (const child of values(node)) {
yield* allNodes(child);
}
break;
case "array":
for (const child of iter(node)) {
yield* allNodes(child);
}
break;
}
};

@@ -1,2 +0,2 @@

import { concat, join, empty, map, filter, every, pipe } from "@hyperjump/pact";
import { concat, join, empty, map, pipe } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";

@@ -39,7 +39,11 @@ import * as Instance from "../instance.js";

return pipe(
Instance.entries(instance),
filter(([propertyName]) => !isDefinedProperty.test(propertyName)),
every(([, property]) => Validation.interpret(additionalProperties, property, ast, dynamicAnchors, quiet))
);
let isValid = true;
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (!isDefinedProperty.test(propertyName) && !Validation.interpret(additionalProperties, property, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -53,3 +57,4 @@

const evaluatedPropertyNames = new Set();
for (const [propertyName, property] of Instance.entries(instance)) {
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (!isDefinedProperty.test(propertyName)) {

@@ -56,0 +61,0 @@ if (!Validation.interpret(additionalProperties, property, ast, dynamicAnchors, true)) {

@@ -15,3 +15,9 @@ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";

const interpret = (allOf, instance, ast, dynamicAnchors, quiet) => {
return allOf.every((schemaUrl) => Validation.interpret(schemaUrl, instance, ast, dynamicAnchors, quiet));
let isValid = true;
for (const schemaUri of allOf) {
if (!Validation.interpret(schemaUri, instance, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -18,0 +24,0 @@

@@ -1,4 +0,5 @@

import metaData from "./meta-data.js";
const id = "https://json-schema.org/keyword/comment";
const compile = () => undefined;
const interpret = () => true;
export default { id: "https://json-schema.org/keyword/comment", ...metaData };
export default { id, compile, interpret };

@@ -1,2 +0,2 @@

import jsonStringify from "fastest-stable-stringify";
import jsonStringify from "json-stringify-deterministic";
import * as Browser from "@hyperjump/browser";

@@ -3,0 +3,0 @@ import * as Instance from "../instance.js";

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/contentEncoding", ...metaData };
const id = "https://json-schema.org/keyword/contentEncoding";
const compile = (schema) => Browser.value(schema);
const interpret = (contentEncoding, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, contentEncoding);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/contentMediaType", ...metaData };
const id = "https://json-schema.org/keyword/contentMediaType";
const compile = (schema) => Browser.value(schema);
const interpret = (contentMediaType, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, contentMediaType);
return true;
};
export default { id, compile, interpret };

@@ -1,2 +0,3 @@

import * as Schema from "../schema.js";
import { canonicalUri } from "../schema.js";
import * as Instance from "../../annotations/annotated-instance.js";

@@ -6,5 +7,9 @@

const compile = (contentSchema) => Schema.canonicalUri(contentSchema);
const interpret = () => true;
const compile = (contentSchema) => canonicalUri(contentSchema);
const interpret = (contentSchema, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, contentSchema);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/default", ...metaData };
const id = "https://json-schema.org/keyword/default";
const compile = (schema) => Browser.value(schema);
const interpret = (value, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, value);
return true;
};
export default { id, compile, interpret };

@@ -15,7 +15,16 @@ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";

const interpret = (dependentRequired, instance) => {
return Instance.typeOf(instance) !== "object" || dependentRequired.every(([propertyName, required]) => {
return !Instance.has(propertyName, instance) || required.every((key) => Instance.has(key, instance));
});
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
for (const [propertyName, required] of dependentRequired) {
if (Instance.has(propertyName, instance) && !required.every((key) => Instance.has(key, instance))) {
isValid = false;
}
}
return isValid;
};
export default { id, compile, interpret };

@@ -16,5 +16,14 @@ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";

const interpret = (dependentSchemas, instance, ast, dynamicAnchors, quiet) => {
return Instance.typeOf(instance) !== "object" || dependentSchemas.every(([propertyName, dependentSchema]) => {
return !Instance.has(propertyName, instance) || Validation.interpret(dependentSchema, instance, ast, dynamicAnchors, quiet);
});
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
for (const [propertyName, dependentSchema] of dependentSchemas) {
if (Instance.has(propertyName, instance) && !Validation.interpret(dependentSchema, instance, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -21,0 +30,0 @@

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/deprecated", ...metaData };
const id = "https://json-schema.org/keyword/deprecated";
const compile = (schema) => Browser.value(schema);
const interpret = (deprecated, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, deprecated);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/description", ...metaData };
const id = "https://json-schema.org/keyword/description";
const compile = (schema) => Browser.value(schema);
const interpret = (description, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, description);
return true;
};
export default { id, compile, interpret };

@@ -1,2 +0,2 @@

import jsonStringify from "fastest-stable-stringify";
import jsonStringify from "json-stringify-deterministic";
import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";

@@ -16,4 +16,7 @@ import * as Browser from "@hyperjump/browser";

const interpret = (enum_, instance) => enum_.some((enumValue) => jsonStringify(Instance.value(instance)) === enumValue);
const interpret = (enum_, instance) => {
const instanceValue = jsonStringify(Instance.value(instance));
return enum_.some((enumValue) => instanceValue === enumValue);
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/examples", ...metaData };
const id = "https://json-schema.org/keyword/examples";
const compile = (schema) => Browser.value(schema);
const interpret = (examples, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, examples);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/format", ...metaData };
const id = "https://json-schema.org/keyword/format";
const compile = (schema) => Browser.value(schema);
const interpret = (format, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, format);
return true;
};
export default { id, compile, interpret };

@@ -1,2 +0,2 @@

import { pipe, drop, every } from "@hyperjump/pact";
import { drop } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";

@@ -22,7 +22,10 @@ import * as Instance from "../instance.js";

return pipe(
Instance.iter(instance),
drop(numberOfPrefixItems),
every((item) => Validation.interpret(items, item, ast, dynamicAnchors, quiet))
);
let isValid = true;
for (const item of drop(numberOfPrefixItems, Instance.iter(instance))) {
if (!Validation.interpret(items, item, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -29,0 +32,0 @@

@@ -1,4 +0,8 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
export default { id: "https://json-schema.org/keyword/maxContains", ...metaData };
const id = "https://json-schema.org/keyword/maxContains";
const compile = (schema) => Browser.value(schema);
const interpret = () => true;
export default { id, compile, interpret };

@@ -8,4 +8,6 @@ import * as Browser from "@hyperjump/browser";

const compile = (schema) => Browser.value(schema);
const interpret = (maxItems, instance) => Instance.typeOf(instance) !== "array" || Instance.length(instance) <= maxItems;
const interpret = (maxItems, instance) => {
return Instance.typeOf(instance) !== "array" || Instance.length(instance) <= maxItems;
};
export default { id, compile, interpret };

@@ -8,4 +8,6 @@ import * as Browser from "@hyperjump/browser";

const compile = (schema) => Browser.value(schema);
const interpret = (maxLength, instance) => Instance.typeOf(instance) !== "string" || [...Instance.value(instance)].length <= maxLength;
const interpret = (maxLength, instance) => {
return Instance.typeOf(instance) !== "string" || [...Instance.value(instance)].length <= maxLength;
};
export default { id, compile, interpret };

@@ -1,4 +0,8 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
export default { id: "https://json-schema.org/keyword/minContains", ...metaData };
const id = "https://json-schema.org/keyword/minContains";
const compile = (schema) => Browser.value(schema);
const interpret = () => true;
export default { id, compile, interpret };

@@ -8,4 +8,6 @@ import * as Browser from "@hyperjump/browser";

const compile = (schema) => Browser.value(schema);
const interpret = (minItems, instance) => Instance.typeOf(instance) !== "array" || Instance.length(instance) >= minItems;
const interpret = (minItems, instance) => {
return Instance.typeOf(instance) !== "array" || Instance.length(instance) >= minItems;
};
export default { id, compile, interpret };

@@ -8,4 +8,6 @@ import * as Browser from "@hyperjump/browser";

const compile = (schema) => Browser.value(schema);
const interpret = (minLength, instance) => Instance.typeOf(instance) !== "string" || [...Instance.value(instance)].length >= minLength;
const interpret = (minLength, instance) => {
return Instance.typeOf(instance) !== "string" || [...Instance.value(instance)].length >= minLength;
};
export default { id, compile, interpret };

@@ -20,6 +20,2 @@ import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";

}
if (validCount > 1) {
break;
}
}

@@ -26,0 +22,0 @@

@@ -8,4 +8,6 @@ import * as Browser from "@hyperjump/browser";

const compile = (schema) => new RegExp(Browser.value(schema), "u");
const interpret = (pattern, instance) => Instance.typeOf(instance) !== "string" || pattern.test(Instance.value(instance));
const interpret = (pattern, instance) => {
return Instance.typeOf(instance) !== "string" || pattern.test(Instance.value(instance));
};
export default { id, compile, interpret };

@@ -1,2 +0,2 @@

import { pipe, asyncMap, asyncCollectArray, filter, every } from "@hyperjump/pact";
import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";

@@ -19,9 +19,17 @@ import * as Instance from "../instance.js";

const interpret = (patternProperties, instance, ast, dynamicAnchors, quiet) => {
return Instance.typeOf(instance) !== "object" || patternProperties.every(([pattern, schemaUrl]) => {
return pipe(
Instance.entries(instance),
filter(([propertyName]) => pattern.test(propertyName)),
every(([, propertyValue]) => Validation.interpret(schemaUrl, propertyValue, ast, dynamicAnchors, quiet))
);
});
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
for (const [pattern, schemaUri] of patternProperties) {
for (const [propertyNameNode, propertyValue] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (pattern.test(propertyName) && !Validation.interpret(schemaUri, propertyValue, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
}
return isValid;
};

@@ -36,3 +44,4 @@

for (const [pattern, propertySchema] of patternProperties) {
for (const [propertyName, property] of Instance.entries(instance)) {
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (pattern.test(propertyName)) {

@@ -39,0 +48,0 @@ if (!Validation.interpret(propertySchema, property, ast, dynamicAnchors, true)) {

@@ -1,2 +0,2 @@

import { pipe, asyncMap, asyncCollectArray, every, zip, take } from "@hyperjump/pact";
import { pipe, asyncMap, asyncCollectArray, zip } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";

@@ -16,7 +16,22 @@ import * as Instance from "../instance.js";

const interpret = (prefixItems, instance, ast, dynamicAnchors, quiet) => {
return Instance.typeOf(instance) !== "array" || pipe(
zip(prefixItems, Instance.iter(instance)),
take(Instance.length(instance)),
every(([prefixItem, item]) => Validation.interpret(prefixItem, item, ast, dynamicAnchors, quiet))
);
if (Instance.typeOf(instance) !== "array") {
return true;
}
let isValid = true;
let index = 0;
const instanceLength = Instance.length(instance);
for (const [schemaUri, item] of zip(prefixItems, Instance.iter(instance))) {
if (index >= instanceLength) {
break;
}
if (!Validation.interpret(schemaUri, item, ast, dynamicAnchors, quiet)) {
isValid = false;
}
index++;
}
return isValid;
};

@@ -23,0 +38,0 @@

@@ -1,2 +0,2 @@

import { pipe, asyncMap, asyncCollectObject, filter, every } from "@hyperjump/pact";
import { pipe, asyncMap, asyncCollectObject } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";

@@ -16,7 +16,15 @@ import * as Instance from "../instance.js";

const interpret = (properties, instance, ast, dynamicAnchors, quiet) => {
return Instance.typeOf(instance) !== "object" || pipe(
Instance.entries(instance),
filter(([propertyName]) => propertyName in properties),
every(([propertyName, property]) => Validation.interpret(properties[propertyName], property, ast, dynamicAnchors, quiet))
);
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (propertyName in properties && !Validation.interpret(properties[propertyName], property, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -30,3 +38,4 @@

const evaluatedPropertyNames = new Set();
for (const [propertyName, property] of Instance.entries(instance)) {
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (propertyName in properties) {

@@ -33,0 +42,0 @@ if (!Validation.interpret(properties[propertyName], property, ast, dynamicAnchors, true)) {

@@ -24,8 +24,20 @@ import { pipe, asyncMap, asyncCollectObject } from "@hyperjump/pact";

const interpret = (propertyDependencies, instance, ast, dynamicAnchors, quiet) => {
return Instance.typeOf(instance) !== "object" || Object.entries(propertyDependencies).every(([propertyName, valueMappings]) => {
const propertyValue = Instance.value(instance)[propertyName];
return !Instance.has(propertyName, instance)
|| !(propertyValue in valueMappings)
|| Validation.interpret(valueMappings[propertyValue], instance, ast, dynamicAnchors, quiet);
});
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
const instanceValue = Instance.value(instance);
for (const [propertyName, valueMappings] of Object.entries(propertyDependencies)) {
const propertyValue = instanceValue[propertyName];
if (
Instance.has(propertyName, instance)
&& propertyValue in valueMappings
&& !Validation.interpret(valueMappings[propertyValue], instance, ast, dynamicAnchors, quiet)
) {
isValid = false;
}
}
return isValid;
};

@@ -32,0 +44,0 @@

@@ -1,4 +0,3 @@

import { every } from "@hyperjump/pact";
import { Validation } from "../experimental.js";
import * as Instance from "../instance.js";
import { Validation } from "../experimental.js";

@@ -11,7 +10,16 @@

const interpret = (propertyNames, instance, ast, dynamicAnchors) => {
return Instance.typeOf(instance) !== "object" || every((key) => {
return Validation.interpret(propertyNames, Instance.cons(key), ast, dynamicAnchors, true);
}, Instance.keys(instance));
if (Instance.typeOf(instance) !== "object") {
return true;
}
let isValid = true;
for (const key of Instance.keys(instance)) {
if (!Validation.interpret(propertyNames, key, ast, dynamicAnchors, true)) {
isValid = false;
}
}
return isValid;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/readOnly", ...metaData };
const id = "https://json-schema.org/keyword/readOnly";
const compile = (schema) => Browser.value(schema);
const interpret = (readOnly, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, readOnly);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/title", ...metaData };
const id = "https://json-schema.org/keyword/title";
const compile = (schema) => Browser.value(schema);
const interpret = (title, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, title);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,4 @@

import { pipe, filter, every, zip, range } from "@hyperjump/pact";
import { zip, range } from "@hyperjump/pact";
import * as Instance from "../instance.js";
import { canonicalUri } from "../schema.js";
import * as Instance from "../instance.js";
import { Validation } from "../experimental.js";

@@ -19,7 +19,14 @@

const itemIndexes = Validation.collectEvaluatedItems(schemaUrl, instance, ast, dynamicAnchors, true);
return itemIndexes === false || pipe(
zip(Instance.iter(instance), range(0)),
filter(([, index]) => !itemIndexes.has(index)),
every(([item]) => Validation.interpret(unevaluatedItems, item, ast, dynamicAnchors, quiet))
);
if (itemIndexes === false) {
return true;
}
let isValid = true;
for (const [item, index] of zip(Instance.iter(instance), range(0))) {
if (!itemIndexes.has(index) && !Validation.interpret(unevaluatedItems, item, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -26,0 +33,0 @@

@@ -1,4 +0,3 @@

import { pipe, filter, every } from "@hyperjump/pact";
import { Validation, canonicalUri } from "../experimental.js";
import * as Instance from "../instance.js";
import { Validation, canonicalUri } from "../experimental.js";

@@ -18,8 +17,15 @@

const evaluatedPropertyNames = Validation.collectEvaluatedProperties(schemaUrl, instance, ast, dynamicAnchors, true);
if (evaluatedPropertyNames === false) {
return true;
}
return !evaluatedPropertyNames || pipe(
Instance.entries(instance),
filter(([propertyName]) => !evaluatedPropertyNames.has(propertyName)),
every(([, property]) => Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors, quiet))
);
let isValid = true;
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (!evaluatedPropertyNames.has(propertyName) && !Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors, quiet)) {
isValid = false;
}
}
return isValid;
};

@@ -38,3 +44,4 @@

for (const [propertyName, property] of Instance.entries(instance)) {
for (const [propertyNameNode, property] of Instance.entries(instance)) {
const propertyName = Instance.value(propertyNameNode);
if (!evaluatedPropertyNames.has(propertyName)) {

@@ -41,0 +48,0 @@ if (!Validation.interpret(unevaluatedProperties, property, ast, dynamicAnchors, true)) {

@@ -1,2 +0,2 @@

import jsonStringify from "fastest-stable-stringify";
import jsonStringify from "json-stringify-deterministic";
import * as Browser from "@hyperjump/browser";

@@ -3,0 +3,0 @@ import * as Instance from "../instance.js";

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/unknown", ...metaData };
const id = "https://json-schema.org/keyword/unknown";
const compile = (schema) => Browser.value(schema);
const interpret = (value, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, value);
return true;
};
export default { id, compile, interpret };
import { value, entries } from "@hyperjump/browser";
import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
import { append as pointerAppend } from "@hyperjump/json-pointer";
import { publishAsync, publish } from "../pubsub.js";
import * as Instance from "../instance.js";
import { publishAsync } from "../pubsub.js";
import { toAbsoluteUri } from "../common.js";

@@ -50,27 +49,25 @@ import { canonicalUri, getKeyword, getKeywordByName } from "../experimental.js";

!quiet && publish("result.start");
const isValid = typeof ast[url] === "boolean" ? ast[url] : ast[url].every(([keywordId, schemaUrl, keywordValue]) => {
!quiet && publish("result.start");
const isValid = getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors, quiet);
let isSchemaValid = true;
if (typeof ast[url] === "boolean") {
isSchemaValid = ast[url];
} else {
for (const [keywordId, schemaUrl, keywordValue] of ast[url]) {
instance.valid = getKeyword(keywordId).interpret(keywordValue, instance, ast, dynamicAnchors, quiet, url);
if (!instance.valid) {
if (!quiet) {
instance.errors[schemaUrl] = keywordId;
}
isSchemaValid = false;
}
}
}
!quiet && publish("result", {
keyword: keywordId,
absoluteKeywordLocation: schemaUrl,
instanceLocation: Instance.uri(instance),
valid: isValid,
ast: keywordValue
});
!quiet && publish("result.end");
return isValid;
});
if (!isSchemaValid) {
if (!quiet) {
instance.errors[url] = id;
}
}
!quiet && publish("result", {
keyword: id,
absoluteKeywordLocation: url,
instanceLocation: Instance.uri(instance),
valid: isValid,
ast: url
});
!quiet && publish("result.end");
return isValid;
instance.valid = isSchemaValid;
return isSchemaValid;
};

@@ -77,0 +74,0 @@

@@ -1,4 +0,14 @@

import metaData from "./meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../../annotations/annotated-instance.js";
export default { id: "https://json-schema.org/keyword/writeOnly", ...metaData };
const id = "https://json-schema.org/keyword/writeOnly";
const compile = (schema) => Browser.value(schema);
const interpret = (writeOnly, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, writeOnly);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "../lib/keywords/meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../annotations/annotated-instance.js";
export default { id: "https://spec.openapis.org/oas/3.0/keyword/discriminator", ...metaData };
const id = "https://spec.openapis.org/oas/3.0/keyword/discriminator";
const compile = (schema) => Browser.value(schema);
const interpret = (discriminator, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, discriminator);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "../lib/keywords/meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../annotations/annotated-instance.js";
export default { id: "https://spec.openapis.org/oas/3.0/keyword/example", ...metaData };
const id = "https://spec.openapis.org/oas/3.0/keyword/example";
const compile = (schema) => Browser.value(schema);
const interpret = (example, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, example);
return true;
};
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "../lib/keywords/meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../annotations/annotated-instance.js";
export default { id: "https://spec.openapis.org/oas/3.0/keyword/externalDocs", ...metaData };
const id = "https://spec.openapis.org/oas/3.0/keyword/externalDocs";
const compile = (schema) => Browser.value(schema);
const interpret = (externalDocs, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, externalDocs);
return true;
};
export default { id, compile, interpret };

@@ -16,2 +16,4 @@ import { addKeyword, defineVocabulary, loadDialect } from "../lib/keywords.js";

export * from "../draft-04/index.js";
addKeyword(discriminator);

@@ -77,3 +79,1 @@ addKeyword(example);

registerSchema(schema, "https://spec.openapis.org/oas/3.0/schema/latest");
export * from "../draft-04/index.js";

@@ -1,4 +0,10 @@

import metaData from "../lib/keywords/meta-data.js";
import * as Browser from "@hyperjump/browser";
export default { id: "https://spec.openapis.org/oas/3.0/keyword/nullable", ...metaData };
const id = "https://spec.openapis.org/oas/3.0/keyword/nullable";
const compile = (schema) => Browser.value(schema);
const interpret = () => true;
export default { id, compile, interpret };

@@ -1,4 +0,14 @@

import metaData from "../lib/keywords/meta-data.js";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../annotations/annotated-instance.js";
export default { id: "https://spec.openapis.org/oas/3.0/keyword/xml", ...metaData };
const id = "https://spec.openapis.org/oas/3.0/keyword/xml";
const compile = (schema) => Browser.value(schema);
const interpret = (xml, instance, _ast, _dynamicAnchors, _quiet, schemaLocation) => {
Instance.setAnnotation(instance, id, schemaLocation, xml);
return true;
};
export default { id, compile, interpret };

@@ -21,2 +21,4 @@ import { addKeyword, defineVocabulary } from "../lib/keywords.js";

export * from "../draft-2020-12/index.js";
addKeyword(discriminator);

@@ -49,3 +51,1 @@ addKeyword(example);

registerSchema(schemaDraft04, "https://spec.openapis.org/oas/3.1/schema-draft-04");
export * from "../draft-2020-12/index.js";
{
"name": "@hyperjump/json-schema",
"version": "1.8.0",
"version": "1.9.0",
"description": "A JSON Schema validator with support for custom keywords, vocabularies, and dialects",

@@ -71,7 +71,7 @@ "type": "module",

"dependencies": {
"@hyperjump/json-pointer": "^1.0.0",
"@hyperjump/json-pointer": "^1.1.0",
"@hyperjump/pact": "^1.2.0",
"@hyperjump/uri": "^1.2.0",
"content-type": "^1.0.4",
"fastest-stable-stringify": "^2.0.2",
"json-stringify-deterministic": "^1.0.12",
"just-curry-it": "^5.3.0",

@@ -78,0 +78,0 @@ "uuid": "^9.0.0"

@@ -521,3 +521,3 @@ # Hyperjump - JSON Schema

might effect this one.
* interpret: (compiledKeywordValue: any, instance: InstanceDocument, ast: AST, dynamicAnchors: object, quiet: boolean) => boolean
* interpret: (compiledKeywordValue: any, instance: JsonNode, ast: AST, dynamicAnchors: object, quiet: boolean, schemaLocation: string) => boolean

@@ -528,7 +528,7 @@ This function takes the value returned by the `compile` function and

validating sub-schemas.
* collectEvaluatedProperties?: (compiledKeywordValue: any, instance: InstanceDocument, ast: AST, dynamicAnchors: object) => Set\<string> | false
* collectEvaluatedProperties?: (compiledKeywordValue: any, instance: JsonNode, ast: AST, dynamicAnchors: object) => Set\<string> | false
If the keyword is an applicator, it will need to implement this
function for `unevaluatedProperties` to work as expected.
* collectEvaluatedItems?: (compiledKeywordValue: A, instance: InstanceDocument, ast: AST, dynamicAnchors: object) => Set\<number> | false
* collectEvaluatedItems?: (compiledKeywordValue: A, instance: JsonNode, ast: AST, dynamicAnchors: object) => Set\<number> | false

@@ -540,7 +540,2 @@ If the keyword is an applicator, it will need to implement this

function to work properly with the [bundle](#bundling) feature.
* annotation?: (compiledKeywordValue: any) => any
If the keyword is an annotation, it will need to implement this
function to work with the [annotation](#annotations-experimental)
functions.
* **defineVocabulary**: (id: string, keywords: { [keyword: string]: string }) => void

@@ -613,3 +608,3 @@

something other than validation.
* **interpret**: (schema: CompiledSchema, instance: Instance, outputFormat: OutputFormat = BASIC) => OutputUnit
* **interpret**: (schema: CompiledSchema, instance: JsonNode, outputFormat: OutputFormat = BASIC) => OutputUnit

@@ -619,10 +614,9 @@ A curried function for validating an instance against a compiled schema.

* **OutputFormat**: **FLAG** | **BASIC** | **DETAILED** | **VERBOSE**
* **OutputFormat**: **FLAG** | **BASIC**
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.
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.

@@ -634,5 +628,4 @@ ## Instance API (experimental)

This library uses InstanceDocument objects to represent a value in an instance.
You'll work with these objects if you create a custom keyword. This module is a
set of functions for working with InstanceDocuments.
This library uses JsonNode objects to represent instances. You'll work with
these objects if you create a custom keyword.

@@ -644,36 +637,39 @@ This API uses generators to iterate over arrays and objects. If you like using

* **cons**: (instance: any, uri?: string) => InstanceDocument
* **fromJs**: (value: any, uri?: string) => JsonNode
Construct an InstanceDocument from a value.
* **get**: (url: string, contextDoc: InstanceDocument) => InstanceDocument
Construct a JsonNode from a JavaScript value.
* **get**: (url: string, instance: JsonNode) => JsonNode
Apply a same-resource reference to a InstanceDocument.
* **uri**: (doc: InstanceDocument) => string
Apply a same-resource reference to a JsonNode.
* **uri**: (instance: JsonNode) => string
Returns a URI for the value the InstanceDocument represents.
* **value**: (doc: InstanceDocument) => any
Returns a URI for the value the JsonNode represents.
* **value**: (instance: JsonNode) => any
Returns the value the InstanceDocument represents.
* **has**: (key: string, doc: InstanceDocument) => any
Returns the value the JsonNode represents.
* **has**: (key: string, instance: JsonNode) => boolean
Similar to `key in instance`.
* **typeOf**: (doc: InstanceDocument) => string
Returns whether or not "key" is a property name in a JsonNode that
represents an object.
* **typeOf**: (instance: JsonNode) => string
Determines if the JSON type of the given doc matches the given type.
* **step**: (key: string, doc: InstanceDocument) => InstanceDocument
The JSON type of the JsonNode. In addition to the standard JSON types,
there's also the `property` type that indicates a property name/value pair
in an object.
* **step**: (key: string, instance: JsonNode) => JsonType
Similar to `schema[key]`, but returns a InstanceDocument.
* **iter**: (doc: InstanceDocument) => Generator\<InstanceDocument>
Similar to indexing into a object or array using the `[]` operator.
* **iter**: (instance: JsonNode) => Generator\<JsonNode>
Iterate over the items in the array that the SchemaDocument represents.
* **entries**: (doc: InstanceDocument) => Generator\<[string, InstanceDocument]>
Iterate over the items in the array that the JsonNode represents.
* **entries**: (instance: JsonNode) => Generator\<[JsonNode, JsonNode]>
Similar to `Object.entries`, but yields InstanceDocuments for values.
* **values**: (doc: InstanceDocument) => Generator\<InstanceDocument>
Similar to `Object.entries`, but yields JsonNodes for keys and values.
* **values**: (instance: JsonNode) => Generator\<JsonNode>
Similar to `Object.values`, but yields InstanceDocuments for values.
* **keys**: (doc: InstanceDocument) => Generator\<string>
Similar to `Object.values`, but yields JsonNodes for values.
* **keys**: (instance: JsonNode) => Generator\<JsonNode>
Similar to `Object.keys`.
* **length**: (doc: InstanceDocument) => number
Similar to `Object.keys`, but yields JsonNodes for keys.
* **length**: (instance: JsonNode) => number

@@ -688,8 +684,9 @@ Similar to `Array.prototype.length`.

### Usage
An annotated JSON document is represented as an AnnotatedInstance object. This
object is a wrapper around your JSON document with functions that allow you to
traverse the data structure and get annotations for the values within.
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.
```javascript
import { annotate, annotatedWith, registerSchema } from "@hyperjump/json-schema/annotations/experimental";
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";

@@ -747,4 +744,5 @@

// Get the title of each of the properties in the object
for (const [propertyName, propertyInstance] of AnnotatedInstance.entries(instance)) {
console.log(propertyName, Instance.annotation(propertyInstance, "title", dialectId));
for (const [propertyNameNode, propertyInstance] of AnnotatedInstance.entries(instance)) {
const propertyName = AnnotatedInstance.value(propertyName);
console.log(propertyName, AnnotatedInstance.annotation(propertyInstance, "title", dialectId));
}

@@ -754,3 +752,3 @@

for (const deprecated of AnnotatedInstance.annotatedWith(instance, "deprecated", dialectId)) {
if (AnnotatedInstance.annotation(instance, "deprecated", dialectId)[0]) {
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."

@@ -765,3 +763,3 @@ }

* **annotate**: (schemaUri: string, instance: any, outputFormat: OutputFormat = FLAG) => Promise\<AnnotatedInstance>
* **annotate**: (schemaUri: string, instance: any, outputFormat: OutputFormat = BASIC) => Promise\<JsonNode>

@@ -773,2 +771,7 @@ Annotate an instance using the given schema. The function is curried to

schema.
* **interpret**: (compiledSchema: CompiledSchema, instance: JsonNode, outputFormat: OutputFormat = BASIC) => JsonNode
Annotate a JsonNode object rather than a plain JavaScript value. This might
be useful when building tools on top of the annotation functionality, but
you probably don't need it.
* **ValidationError**: Error & { output: OutputUnit }

@@ -784,11 +787,9 @@ The `output` field contains an `OutputUnit` with information about the

* **annotation**: (instance: AnnotatedInstance, keyword: string, dialectId?: string) => any[]
* **annotation**: (instance: JsonNode, keyword: string, dialect?: string): any[];
Get the annotations for a given keyword at the location represented by the
instance object.
* **annotatedWith**: (instance: AnnotatedInstance, keyword: string, dialectId?: string) => AnnotatedInstance[]
Get the annotations for a keyword for the value represented by the JsonNode.
* **annotatedWith**: (instance: JsonNode, keyword: string, dialect?: string): JsonNode[];
Get an array of instances for all the locations that are annotated with the
given keyword.
* **annotate**: (instance: AnnotatedInstance, keywordId: string, value: any) => AnnotatedInstance
Get all JsonNodes that are annotated with the given keyword.
* **setAnnotation**: (instance: JsonNode, keywordId: string, value: any) => JsonNode

@@ -795,0 +796,0 @@ Add an annotation to an instance. This is used internally, you probably

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc