Skip to content

Commit b32c87c

Browse files
committed
Add locations to nodes and simplify data model
1 parent 7c930f4 commit b32c87c

File tree

4 files changed

+91
-208
lines changed

4 files changed

+91
-208
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"vitest": "*"
2626
},
2727
"dependencies": {
28+
"@hyperjump/json-pointer": "^1.1.0",
2829
"@hyperjump/uri": "^1.3.1",
2930
"json-stringify-deterministic": "^1.0.12"
3031
}

src/index.js

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,36 @@
11
import jsonStringify from "json-stringify-deterministic";
2-
import { parseIriReference, toAbsoluteIri } from "@hyperjump/uri";
2+
import * as JsonPointer from "@hyperjump/json-pointer";
3+
import { parseIriReference, resolveIri, toAbsoluteIri } from "@hyperjump/uri";
34
import {
45
assertNodeType,
56
toJsonNode,
6-
isNodeType,
77
jsonObjectHas,
88
jsonObjectKeys,
99
jsonPointerGet,
1010
jsonPointerStep,
11-
jsonValue,
12-
toSchemaNode
11+
jsonValue
1312
} from "./jsonast-util.js";
1413

1514
/**
1615
* @import {
1716
* Json,
1817
* JsonNode,
1918
* JsonObjectNode,
20-
* JsonStringNode,
21-
* SchemaNode
19+
* JsonStringNode
2220
* } from "./jsonast.d.ts"
2321
*/
2422

2523

2624
/** @type (schema: Json, instance: Json) => boolean */
2725
export const validate = (schema, instance) => {
2826
registerSchema(schema, "");
29-
const schemaNode = /** @type NonNullable<SchemaNode> */ (schemaRegistry.get(""));
27+
const schemaNode = /** @type NonNullable<JsonNode> */ (schemaRegistry.get(""));
3028
const isValid = validateSchema(schemaNode, toJsonNode(instance));
3129
schemaRegistry.delete("");
3230
return isValid;
3331
};
3432

35-
/** @type (schemaNode: SchemaNode, instanceNode: JsonNode) => boolean */
33+
/** @type (schemaNode: JsonNode, instanceNode: JsonNode) => boolean */
3634
const validateSchema = (schemaNode, instanceNode) => {
3735
if (schemaNode.type === "json") {
3836
switch (schemaNode.jsonType) {
@@ -53,35 +51,38 @@ const validateSchema = (schemaNode, instanceNode) => {
5351
throw Error("Invalid Schema");
5452
};
5553

56-
/** @type Map<string, SchemaNode> */
54+
/** @type Map<string, JsonNode> */
5755
const schemaRegistry = new Map();
5856

5957
/** @type (schema: Json, uri: string) => void */
6058
export const registerSchema = (schema, uri) => {
61-
schemaRegistry.set(uri, toSchemaNode(schema, uri));
59+
schemaRegistry.set(uri, toJsonNode(schema, uri));
6260
};
6361

6462
/**
6563
* @typedef {(
66-
* keywordNode: SchemaNode,
64+
* keywordNode: JsonNode,
6765
* instanceNode: JsonNode,
68-
* schemaNode: JsonObjectNode<SchemaNode>
66+
* schemaNode: JsonObjectNode
6967
* ) => boolean} KeywordHandler
7068
*/
7169

7270
/** @type Map<string, KeywordHandler> */
7371
const keywordHandlers = new Map();
7472

7573
keywordHandlers.set("$ref", (refNode, instanceNode) => {
76-
assertNodeType(refNode, "reference");
77-
const pointer = decodeURI(parseIriReference(refNode.value).fragment ?? "");
78-
const uri = refNode.value.startsWith("#") ? "" : toAbsoluteIri(refNode.value);
74+
assertNodeType(refNode, "string");
75+
76+
const uri = refNode.location.startsWith("#")
77+
? refNode.value.startsWith("#") ? "" : toAbsoluteIri(refNode.value)
78+
: toAbsoluteIri(resolveIri(refNode.value, toAbsoluteIri(refNode.location)));
7979

8080
const schemaNode = schemaRegistry.get(uri);
8181
if (!schemaNode) {
8282
throw Error(`Invalid reference: ${uri}`);
8383
}
8484

85+
const pointer = decodeURI(parseIriReference(refNode.value).fragment ?? "");
8586
const referencedSchemaNode = jsonPointerGet(pointer, schemaNode, uri);
8687

8788
return validateSchema(referencedSchemaNode, instanceNode);
@@ -96,7 +97,7 @@ keywordHandlers.set("additionalProperties", (additionalPropertiesNode, instanceN
9697

9798
if (jsonObjectHas("properties", schemaNode)) {
9899
const propertiesNode = jsonPointerStep("properties", schemaNode);
99-
if (isNodeType(propertiesNode, "object")) {
100+
if (propertiesNode.jsonType === "object") {
100101
for (const propertyName of jsonObjectKeys(propertiesNode)) {
101102
propertyPatterns.push(`^${regexEscape(propertyName)}$`);
102103
}
@@ -105,7 +106,7 @@ keywordHandlers.set("additionalProperties", (additionalPropertiesNode, instanceN
105106

106107
if (jsonObjectHas("patternProperties", schemaNode)) {
107108
const patternPropertiesNode = jsonPointerStep("patternProperties", schemaNode);
108-
if (isNodeType(patternPropertiesNode, "object")) {
109+
if (patternPropertiesNode.jsonType === "object") {
109110
propertyPatterns.push(...jsonObjectKeys(patternPropertiesNode));
110111
}
111112
}
@@ -171,15 +172,15 @@ keywordHandlers.set("contains", (containsNode, instanceNode, schemaNode) => {
171172
let minContains = 1;
172173
if (jsonObjectHas("minContains", schemaNode)) {
173174
const minContainsNode = jsonPointerStep("minContains", schemaNode);
174-
if (isNodeType(minContainsNode, "number")) {
175+
if (minContainsNode.jsonType === "number") {
175176
minContains = minContainsNode.value;
176177
}
177178
}
178179

179180
let maxContains = Number.MAX_SAFE_INTEGER;
180181
if (jsonObjectHas("maxContains", schemaNode)) {
181182
const maxContainsNode = jsonPointerStep("maxContains", schemaNode);
182-
if (isNodeType(maxContainsNode, "number")) {
183+
if (maxContainsNode.jsonType === "number") {
183184
maxContains = maxContainsNode.value;
184185
}
185186
}
@@ -242,7 +243,7 @@ keywordHandlers.set("items", (itemsNode, instanceNode, schemaNode) => {
242243
let numberOfPrefixItems = 0;
243244
if (jsonObjectHas("prefixItems", schemaNode)) {
244245
const prefixItemsNode = jsonPointerStep("prefixItems", schemaNode);
245-
if (isNodeType(prefixItemsNode, "array")) {
246+
if (prefixItemsNode.jsonType === "array") {
246247
numberOfPrefixItems = prefixItemsNode.children.length;
247248
}
248249
}
@@ -321,7 +322,8 @@ keywordHandlers.set("propertyNames", (propertyNamesNode, instanceNode) => {
321322
const keyNode = {
322323
type: "json",
323324
jsonType: "string",
324-
value: propertyNode.children[0].value
325+
value: propertyNode.children[0].value,
326+
location: JsonPointer.append(propertyNode.children[0].value, instanceNode.location)
325327
};
326328
if (!validateSchema(propertyNamesNode, keyNode)) {
327329
return false;

0 commit comments

Comments
 (0)