Skip to content

Commit

Permalink
Revert instance as a class
Browse files Browse the repository at this point in the history
  • Loading branch information
jdesrosiers committed May 2, 2024
1 parent b0053e2 commit d8ca5d9
Show file tree
Hide file tree
Showing 75 changed files with 465 additions and 377 deletions.
9 changes: 7 additions & 2 deletions annotations/index.d.ts
@@ -1,17 +1,22 @@
import type { OutputFormat, OutputUnit } from "../lib/index.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>
) & (
(schemaUrl: string) => Promise<Annotator>
);

export type Annotator = (value: Json, outputFormat?: OutputFormat) => JsonNode;

export const interpret: (compiledSchema: CompiledSchema, value: JsonNode, outputFormat?: OutputFormat) => JsonNode;

export type Annotator = (value: unknown, outputFormat?: OutputFormat) => JsonNode;
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 class ValidationError extends Error {
public output: OutputUnit;
Expand Down
47 changes: 44 additions & 3 deletions annotations/index.js
@@ -1,12 +1,13 @@
import * as JsonPointer from "@hyperjump/json-pointer";
import { ValidationError } from "./validation-error.js";
import { getSchema, compile, interpret as validate, BASIC } from "../lib/experimental.js";
import { jsonNodeFromJs } from "../lib/json-node.js";
import { getSchema, compile, interpret as validate, BASIC, getKeywordId } from "../lib/experimental.js";
import * as Instance from "../lib/instance.js";


export const annotate = async (schemaUri, json = undefined, outputFormat = undefined) => {
const schema = await getSchema(schemaUri);
const compiled = await compile(schema);
const interpretAst = (json, outputFormat) => interpret(compiled, jsonNodeFromJs(json), outputFormat);
const interpretAst = (json, outputFormat) => interpret(compiled, Instance.fromJs(json), outputFormat);

return json === undefined ? interpretAst : interpretAst(json, outputFormat);
};
Expand All @@ -20,4 +21,44 @@ export const interpret = ({ ast, schemaUri }, instance, outputFormat = BASIC) =>
return instance;
};

export const setAnnotation = (node, keywordUri, schemaLocation, value) => {
if (!(keywordUri in node.annotations)) {
node.annotations[keywordUri] = {};
}
node.annotations[keywordUri][schemaLocation] = value;
};

export const annotation = (node, keyword, dialect = "https://json-schema.org/validation") => {
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 = "https://json-schema.org/validation") => {
const nodes = [];

for (const node of Instance.allNodes(instance)) {
if (annotation(node, keyword, dialectId).length > 0) {
nodes.push(node);
}
}

return nodes;
};

export { ValidationError } from "./validation-error.js";
12 changes: 7 additions & 5 deletions annotations/index.spec.ts
Expand Up @@ -3,17 +3,19 @@ import path from "node:path";
import { fileURLToPath } from "node:url";
import { describe, it, expect, beforeEach, beforeAll, afterAll } from "vitest";
import { toAbsoluteIri } from "@hyperjump/uri";
import { annotate } from "./index.js";
import { annotate, annotation } from "./index.js";
import { registerSchema, unregisterSchema } from "../lib/index.js";
import "../stable/index.js";
import "../draft-2020-12/index.js";
import "../draft-07/index.js";
import "../draft-06/index.js";
import "../draft-04/index.js";
import * as Instance from "../lib/instance.js";

import type { SchemaObject } from "../lib/index.js";
import type { Annotator } from "./index.js";
import type { JsonNode } from "../lib/json-node.js";
import type { JsonNode } from "../lib/instance.js";
import type { Json } from "@hyperjump/json-pointer";


type Suite = {
Expand All @@ -23,7 +25,7 @@ type Suite = {
};

type Subject = {
instance: unknown;
instance: Json;
assertions: Assertion[];
};

Expand Down Expand Up @@ -75,8 +77,8 @@ describe("Annotations", () => {
subject.assertions.forEach((assertion) => {
it(`${assertion.keyword} annotations at '${assertion.location}' should be ${JSON.stringify(assertion.expected)}`, () => {
const dialect: string | undefined = suite.schema.$schema ? toAbsoluteIri(suite.schema.$schema as string) : undefined;
const annotations = instance.get(assertion.location)
?.annotation(assertion.keyword, dialect) ?? [];
const subject = Instance.get(assertion.location, instance);
const annotations = subject ? annotation(subject, assertion.keyword, dialect) : [];

Check failure on line 81 in annotations/index.spec.ts

View workflow job for this annotation

GitHub Actions / build (20.x)

Unnecessary conditional, value is always truthy
expect(annotations).to.eql(assertion.expected);
});
});
Expand Down
4 changes: 2 additions & 2 deletions bundle/test-suite.spec.ts
Expand Up @@ -3,7 +3,7 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { isCompatible, md5, loadSchemas, unloadSchemas, toOutput, testSuite } from "./test-utils.js";
import { registerSchema, unregisterSchema } from "../lib/index.js";
import { compile, getKeywordName, getSchema, interpret } from "../lib/experimental.js";
import { jsonNodeFromJs } from "../lib/json-node.js";
import * as Instance from "../lib/instance.js";
import "../stable/index.js";
import "../draft-2020-12/index.js";
import "../draft-2019-09/index.js";
Expand Down Expand Up @@ -58,7 +58,7 @@ const testRunner = (version: number, dialect: string) => {
it(test.description, async () => {
const schema = await getSchema(mainSchemaUri);
const compiledSchema = await compile(schema);
const instance = jsonNodeFromJs(test.instance);
const instance = Instance.fromJs(test.instance);
interpret(compiledSchema, instance);
const output = toOutput(instance);

Expand Down
6 changes: 3 additions & 3 deletions bundle/test-utils.js
Expand Up @@ -3,7 +3,7 @@ import { readFileSync, readdirSync } from "node:fs";
import { basename, relative } from "node:path";
import { getKeywordName } from "../lib/keywords.js";
import { registerSchema, unregisterSchema } from "../lib/index.js";
import { allNodes } from "../lib/json-node.js";
import * as Instance from "../lib/instance.js";


export const testSuite = (path) => {
Expand Down Expand Up @@ -105,8 +105,8 @@ export const unloadSchemas = (testCase, retrievalUri) => {

export const toOutput = (root) => {
const output = {};
for (const node of allNodes(root)) {
output[node.uri()] = {
for (const node of Instance.allNodes(root)) {
output[Instance.uri(node)] = {
errors: node.errors,
annotations: node.annotations
};
Expand Down
7 changes: 4 additions & 3 deletions draft-04/additionalItems.js
@@ -1,5 +1,6 @@
import { pipe, drop, every } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../lib/instance.js";
import { getKeywordName, Validation } from "../lib/experimental.js";


Expand All @@ -14,12 +15,12 @@ const compile = async (schema, ast, parentSchema) => {
};

const interpret = ([numberOfItems, additionalItems], instance, ast, dynamicAnchors, quiet) => {
if (instance.typeOf() !== "array") {
if (Instance.typeOf(instance) !== "array") {
return true;
}

return pipe(
instance.iter(),
Instance.iter(instance),
drop(numberOfItems),
every((item) => Validation.interpret(additionalItems, item, ast, dynamicAnchors, quiet))
);
Expand All @@ -31,7 +32,7 @@ const collectEvaluatedItems = (keywordValue, instance, ast, dynamicAnchors) => {
}

const evaluatedIndexes = new Set();
for (let ndx = keywordValue[0]; ndx < instance.length(); ndx++) {
for (let ndx = keywordValue[0]; ndx < Instance.length(instance); ndx++) {
evaluatedIndexes.add(ndx);
}

Expand Down
5 changes: 3 additions & 2 deletions draft-04/dependencies.js
@@ -1,5 +1,6 @@
import { pipe, asyncMap, asyncCollectArray } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../lib/instance.js";
import { Validation } from "../lib/experimental.js";


Expand All @@ -15,9 +16,9 @@ const compile = (schema, ast) => pipe(
);

const interpret = (dependencies, instance, ast, dynamicAnchors, quiet) => {
const value = instance.value();
const value = Instance.value(instance);

return instance.typeOf() !== "object" || dependencies.every(([propertyName, dependency]) => {
return Instance.typeOf(instance) !== "object" || dependencies.every(([propertyName, dependency]) => {
if (!(propertyName in value)) {
return true;
}
Expand Down
11 changes: 6 additions & 5 deletions draft-04/items.js
@@ -1,5 +1,6 @@
import { pipe, asyncMap, asyncCollectArray, every, zip, take, range, collectSet } from "@hyperjump/pact";
import * as Browser from "@hyperjump/browser";
import * as Instance from "../lib/instance.js";
import { Validation } from "../lib/experimental.js";


Expand All @@ -18,24 +19,24 @@ const compile = (schema, ast) => {
};

const interpret = (items, instance, ast, dynamicAnchors, quiet) => {
if (instance.typeOf() !== "array") {
if (Instance.typeOf(instance) !== "array") {
return true;
}

if (typeof items === "string") {
return every((itemValue) => Validation.interpret(items, itemValue, ast, dynamicAnchors, quiet), instance.iter());
return every((itemValue) => Validation.interpret(items, itemValue, ast, dynamicAnchors, quiet), Instance.iter(instance));
} else {
return pipe(
zip(items, instance.iter()),
take(instance.length()),
zip(items, Instance.iter(instance)),
take(Instance.length(instance)),
every(([prefixItem, item]) => Validation.interpret(prefixItem, item, ast, dynamicAnchors, quiet))
);
}
};

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

Expand Down
3 changes: 2 additions & 1 deletion draft-04/json-schema-test-suite.spec.ts
Expand Up @@ -3,6 +3,7 @@ import { describe, it, beforeAll, expect, afterAll } from "vitest";
import { toAbsoluteIri } from "@hyperjump/uri";
import { registerSchema, unregisterSchema, validate } from "./index.js";

import type { Json } from "@hyperjump/json-pointer";
import type { JsonSchemaDraft04, SchemaObject, Validator } from "./index.js";


Expand All @@ -14,7 +15,7 @@ type Suite = {

type Test = {
description: string;
data: unknown;
data: Json;
valid: boolean;
};

Expand Down
5 changes: 3 additions & 2 deletions draft-04/maximum.js
@@ -1,4 +1,5 @@
import * as Browser from "@hyperjump/browser";
import * as Instance from "../lib/instance.js";
import { getKeywordName } from "../lib/experimental.js";


Expand All @@ -13,11 +14,11 @@ const compile = async (schema, _ast, parentSchema) => {
};

const interpret = ([maximum, isExclusive], instance) => {
if (instance.typeOf() !== "number") {
if (Instance.typeOf(instance) !== "number") {
return true;
}

const value = instance.value();
const value = Instance.value(instance);
return isExclusive ? value < maximum : value <= maximum;
};

Expand Down
5 changes: 3 additions & 2 deletions draft-04/minimum.js
@@ -1,4 +1,5 @@
import * as Browser from "@hyperjump/browser";
import * as Instance from "../lib/instance.js";
import { getKeywordName } from "../lib/experimental.js";


Expand All @@ -13,11 +14,11 @@ const compile = async (schema, _ast, parentSchema) => {
};

const interpret = ([minimum, isExclusive], instance) => {
if (instance.typeOf() !== "number") {
if (Instance.typeOf(instance) !== "number") {
return true;
}

const value = instance.value();
const value = Instance.value(instance);
return isExclusive ? value > minimum : value >= minimum;
};

Expand Down
3 changes: 2 additions & 1 deletion draft-06/contains.js
@@ -1,4 +1,5 @@
import { some } from "@hyperjump/pact";
import * as Instance from "../lib/instance.js";
import { Validation } from "../lib/experimental.js";


Expand All @@ -7,7 +8,7 @@ const id = "https://json-schema.org/keyword/draft-06/contains";
const compile = (schema, ast) => Validation.compile(schema, ast);

const interpret = (contains, instance, ast, dynamicAnchors, quiet) => {
return instance.typeOf() !== "array" || some((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet), instance.iter());
return Instance.typeOf(instance) !== "array" || some((item) => Validation.interpret(contains, item, ast, dynamicAnchors, quiet), Instance.iter(instance));
};

export default { id, compile, interpret };
3 changes: 2 additions & 1 deletion draft-06/json-schema-test-suite.spec.ts
Expand Up @@ -4,6 +4,7 @@ import { toAbsoluteIri } from "@hyperjump/uri";
import { registerSchema, unregisterSchema, validate } from "./index.js";

import type { JsonSchemaDraft06, SchemaObject, Validator } from "./index.js";
import type { Json } from "@hyperjump/json-pointer";


type Suite = {
Expand All @@ -14,7 +15,7 @@ type Suite = {

type Test = {
description: string;
data: unknown;
data: Json;
valid: boolean;
};

Expand Down
3 changes: 2 additions & 1 deletion draft-07/json-schema-test-suite.spec.ts
Expand Up @@ -3,6 +3,7 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { toAbsoluteIri } from "@hyperjump/uri";
import { registerSchema, unregisterSchema, validate } from "./index.js";

import type { Json } from "@hyperjump/json-pointer";
import type { JsonSchemaDraft07, SchemaObject, Validator } from "./index.js";


Expand All @@ -14,7 +15,7 @@ type Suite = {

type Test = {
description: string;
data: unknown;
data: Json;
valid: boolean;
};

Expand Down
3 changes: 2 additions & 1 deletion draft-2019-09/json-schema-test-suite.spec.ts
Expand Up @@ -3,6 +3,7 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { toAbsoluteIri } from "@hyperjump/uri";
import { registerSchema, unregisterSchema, validate } from "./index.js";

import type { Json } from "@hyperjump/json-pointer";
import type { JsonSchemaDraft201909, SchemaObject, Validator } from "./index.js";


Expand All @@ -14,7 +15,7 @@ type Suite = {

type Test = {
description: string;
data: unknown;
data: Json;
valid: boolean;
};

Expand Down
3 changes: 2 additions & 1 deletion draft-2020-12/json-schema-test-suite.spec.ts
Expand Up @@ -3,6 +3,7 @@ import { describe, it, expect, beforeAll, afterAll } from "vitest";
import { toAbsoluteIri } from "@hyperjump/uri";
import { registerSchema, unregisterSchema, validate } from "./index.js";

import type { Json } from "@hyperjump/json-pointer";
import type { JsonSchemaDraft202012, SchemaObject, Validator } from "./index.js";


Expand All @@ -14,7 +15,7 @@ type Suite = {

type Test = {
description: string;
data: unknown;
data: Json;
valid: boolean;
};

Expand Down

0 comments on commit d8ca5d9

Please sign in to comment.