Skip to content

Commit 8bf9ec3

Browse files
committed
completed the normalizingOutputFormat for betterJSONSchemaErrors
1 parent 7210501 commit 8bf9ec3

File tree

6 files changed

+172
-52
lines changed

6 files changed

+172
-52
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,6 @@
3838
},
3939
"dependencies": {
4040
"@hyperjump/browser": "^1.3.1",
41-
"@hyperjump/json-schema": "^1.14.1"
41+
"@hyperjump/json-schema": "^1.16.0"
4242
}
4343
}

src/index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ export const betterJsonSchemaErrors: (
22
instance: Json,
33
schema: SchemaObject,
44
errorOutput: OutputFormat
5-
) => BetterJsonSchemaErrors;
5+
) => Promise<BetterJsonSchemaErrors>;
66

77
export type BetterJsonSchemaErrors = {
88
errors: ErrorObject[];

src/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import { normalizeOutputFormat } from "./normalizeOutputFormat/normalizeOutput.j
55
*/
66

77
/** @type betterJsonSchemaErrors */
8-
export function betterJsonSchemaErrors(instance, schema, errorOutput) {
9-
const normalizedErrors = normalizeOutputFormat(errorOutput);
8+
export async function betterJsonSchemaErrors(instance, schema, errorOutput) {
9+
const normalizedErrors = await normalizeOutputFormat(errorOutput, schema);
1010

1111
const errors = [];
1212
for (const error of normalizedErrors) {
Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,61 @@
1+
import * as Browser from "@hyperjump/browser";
2+
import { registerSchema, unregisterSchema } from "@hyperjump/json-schema/draft-2020-12";
3+
import { getSchema } from "@hyperjump/json-schema/experimental";
4+
import { pointerSegments } from "@hyperjump/json-pointer";
5+
import { randomUUID } from "crypto";
6+
17
/**
2-
* @import {OutputFormat, OutputUnit, NormalizedError } from "../index.d.ts"
8+
* @import { OutputFormat, OutputUnit, NormalizedError, SchemaObject} from "../index.d.ts";
9+
* @import { SchemaDocument } from "@hyperjump/json-schema/experimental";
10+
* @import { Browser as BrowserType } from "@hyperjump/browser";
311
*/
412

5-
/** @type {(errorOutput: OutputFormat) => NormalizedError[]} */
6-
export function normalizeOutputFormat(errorOutput) {
7-
/** @type NormalizedError[] */
13+
/**
14+
* @param {OutputFormat} errorOutput
15+
* @param {SchemaObject} schema
16+
* @returns {Promise<NormalizedError[]>}
17+
*/
18+
export async function normalizeOutputFormat(errorOutput, schema) {
19+
/** @type {NormalizedError[]} */
820
const output = [];
21+
922
if (!errorOutput || errorOutput.valid !== false) {
1023
throw new Error("error Output must follow Draft 2019-09");
1124
}
1225

13-
/** @type {(errorOutput: OutputUnit) => void} */
14-
function collectErrors(error) {
26+
const keywords = new Set([
27+
"type", "minLength", "maxLength", "minimum", "maximum", "format", "pattern",
28+
"enum", "const", "required", "items", "properties", "allOf", "anyOf", "oneOf",
29+
"not", "contains", "uniqueItems", "additionalProperties", "minItems", "maxItems",
30+
"minProperties", "maxProperties", "dependentRequired", "dependencies"
31+
]);
32+
33+
/** @type {(errorOutput: OutputUnit) => Promise<void>} */
34+
async function collectErrors(error) {
1535
if (error.valid) return;
1636

1737
if (!("instanceLocation" in error) || !("absoluteKeywordLocation" in error || "keywordLocation" in error)) {
1838
throw new Error("error Output must follow Draft 2019-09");
1939
}
2040

21-
// TODO: Convert keywordLocation to absoluteKeywordLocation
22-
error.absoluteKeywordLocation ??= "https://example.com/main#/minLength";
41+
const absoluteKeywordLocation = error.absoluteKeywordLocation
42+
?? await toAbsoluteKeywordLocation(schema, /** @type string */ (error.keywordLocation));
43+
44+
const fragment = absoluteKeywordLocation.split("#")[1];
45+
const lastSegment = fragment.split("/").filter(Boolean).pop();
2346

24-
output.push({
25-
valid: false,
26-
absoluteKeywordLocation: error.absoluteKeywordLocation,
27-
instanceLocation: normalizeInstanceLocation(error.instanceLocation)
28-
});
47+
// make a check here to remove the schemaLocation.
48+
if (lastSegment && keywords.has(lastSegment)) {
49+
output.push({
50+
valid: false,
51+
absoluteKeywordLocation,
52+
instanceLocation: normalizeInstanceLocation(error.instanceLocation)
53+
});
54+
}
2955

3056
if (error.errors) {
3157
for (const nestedError of error.errors) {
32-
collectErrors(nestedError);
58+
await collectErrors(nestedError); // Recursive
3359
}
3460
}
3561
}
@@ -39,14 +65,35 @@ export function normalizeOutputFormat(errorOutput) {
3965
}
4066

4167
for (const err of errorOutput.errors) {
42-
collectErrors(err);
68+
await collectErrors(err);
4369
}
4470

4571
return output;
4672
}
4773

48-
/** @type (location: string) => string */
74+
/** @type {(location: string) => string} */
4975
function normalizeInstanceLocation(location) {
50-
if (location.startsWith("/") || location === "") return "#" + location;
51-
return location;
76+
return location.startsWith("/") || location === "" ? `#${location}` : location;
77+
}
78+
79+
/**
80+
* Convert keywordLocation to absoluteKeywordLocation
81+
* @param {SchemaObject} schema
82+
* @param {string} keywordLocation
83+
* @returns {Promise<string>}
84+
*/
85+
export async function toAbsoluteKeywordLocation(schema, keywordLocation) {
86+
const uri = `urn:uuid:${randomUUID()}`;
87+
try {
88+
registerSchema(schema, uri);
89+
90+
let browser = await getSchema(uri);
91+
for (const segment of pointerSegments(keywordLocation)) {
92+
browser = /** @type BrowserType<SchemaDocument> */ (await Browser.step(segment, browser));
93+
}
94+
95+
return `${browser.document.baseUri}#${browser.cursor}`;
96+
} finally {
97+
unregisterSchema(uri);
98+
}
5299
}

0 commit comments

Comments
 (0)