Skip to content

Commit 50f0ca3

Browse files
committed
refactor keywordHandlers and errorHandlers
1 parent 0bba4dc commit 50f0ca3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1847
-1109
lines changed

package-lock.json

Lines changed: 1 addition & 0 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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"@fluent/bundle": "^0.19.1",
4141
"@hyperjump/browser": "^1.3.1",
4242
"@hyperjump/json-schema": "^1.16.0",
43+
"@hyperjump/pact": "^1.4.0",
4344
"leven": "^4.0.0"
4445
}
4546
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
2+
import { Localization } from "../localization.js";
3+
4+
/**
5+
* @import {ErrorObject } from "../index.d.ts"
6+
* @import {ErrorHandler} from "../utilis.js"
7+
*/
8+
/** @type ErrorHandler */
9+
const additionalProperties = async (normalizedErrors, instance, language) => {
10+
/** @type ErrorObject[] */
11+
const errors = [];
12+
if (normalizedErrors["https://json-schema.org/validation"]) {
13+
for (const schemaLocation in normalizedErrors["https://json-schema.org/validation"]) {
14+
if (!normalizedErrors["https://json-schema.org/validation"][schemaLocation] && schemaLocation.endsWith("/additionalProperties")) {
15+
const notAllowedValue = /** @type string */(Instance.uri(instance).split("/").pop());
16+
const localization = await Localization.forLocale(language);
17+
errors.push({
18+
message: localization.getAdditionalPropertiesErrorMessage(notAllowedValue),
19+
instanceLocation: Instance.uri(instance),
20+
schemaLocation: schemaLocation
21+
});
22+
}
23+
}
24+
}
25+
return errors;
26+
};
27+
28+
export default additionalProperties;

src/errorHandlers/anyOf.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import { getErrors } from "../utilis.js";
5+
import { Localization } from "../localization.js";
6+
7+
/**
8+
* @import {ErrorObject } from "../index.d.ts"
9+
* @import { NormalizedOutput } from "../normalizeOutputFormat/normalizeOutput.js"
10+
* @import {ErrorHandler} from "../utilis.js"
11+
*/
12+
13+
/** @type ErrorHandler */
14+
const anyOf = async (normalizedErrors, instance, language) => {
15+
/** @type ErrorObject[] */
16+
const errors = [];
17+
18+
if (normalizedErrors["https://json-schema.org/keyword/anyOf"]) {
19+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/anyOf"]) {
20+
/** @type NormalizedOutput[] */
21+
const alternatives = [];
22+
const allAlternatives = /** @type NormalizedOutput[] */ (normalizedErrors["https://json-schema.org/keyword/anyOf"][schemaLocation]);
23+
for (const alternative of allAlternatives) {
24+
if (Object.values(alternative[Instance.uri(instance)]["https://json-schema.org/keyword/type"]).every((valid) => valid)) {
25+
alternatives.push(alternative);
26+
}
27+
}
28+
// case 1 where no. alternative matched the type of the instance.
29+
if (alternatives.length === 0) {
30+
/** @type Set<string> */
31+
const expectedTypes = new Set();
32+
const localization = await Localization.forLocale(language);
33+
for (const alternative of allAlternatives) {
34+
for (const instanceLocation in alternative) {
35+
if (instanceLocation === Instance.uri(instance)) {
36+
for (const schemaLocation in alternative[instanceLocation]["https://json-schema.org/keyword/type"]) {
37+
const keyword = await getSchema(schemaLocation);
38+
const expectedType = /** @type string */ (Schema.value(keyword));
39+
expectedTypes.add(expectedType);
40+
}
41+
}
42+
}
43+
}
44+
errors.push({
45+
message: localization.getTypeErrorMessage([...expectedTypes], Instance.typeOf(instance)),
46+
instanceLocation: Instance.uri(instance),
47+
schemaLocation: schemaLocation
48+
});
49+
} else if (alternatives.length === 1) { // case 2 when only one type match
50+
return getErrors(alternatives[0], instance, language);
51+
} else if (instance.type === "object") {
52+
let targetAlternativeIndex = -1;
53+
for (const alternative of alternatives) {
54+
targetAlternativeIndex++;
55+
for (const instanceLocation in alternative) {
56+
if (instanceLocation !== "#") {
57+
return getErrors(alternatives[targetAlternativeIndex], instance, language);
58+
}
59+
}
60+
}
61+
}
62+
}
63+
}
64+
65+
return errors;
66+
};
67+
68+
export default anyOf;

src/errorHandlers/const.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import { Localization } from "../localization.js";
5+
6+
/**
7+
* @import {ErrorObject } from "../index.d.ts"
8+
* @import {ErrorHandler} from "../utilis.js"
9+
*/
10+
11+
/** @type ErrorHandler */
12+
const const_ = async (normalizedErrors, instance, language) => {
13+
/** @type ErrorObject[] */
14+
const errors = [];
15+
16+
if (normalizedErrors["https://json-schema.org/keyword/const"]) {
17+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/const"]) {
18+
if (!normalizedErrors["https://json-schema.org/keyword/const"][schemaLocation]) {
19+
const keyword = await getSchema(schemaLocation);
20+
const localization = await Localization.forLocale(language);
21+
errors.push({
22+
message: localization.getConstErrorMessage(Schema.value(keyword)),
23+
instanceLocation: Instance.uri(instance),
24+
schemaLocation: schemaLocation
25+
});
26+
}
27+
}
28+
}
29+
30+
return errors;
31+
};
32+
33+
export default const_;

src/errorHandlers/contains.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
2+
import { getErrors } from "../utilis.js";
3+
import { Localization } from "../localization.js";
4+
5+
/**
6+
* @import {ErrorObject } from "../index.d.ts"
7+
* @import { NormalizedOutput } from "../normalizeOutputFormat/normalizeOutput.js"
8+
* @import {ErrorHandler} from "../utilis.js"
9+
*/
10+
/** @type ErrorHandler */
11+
const contains = async (normalizedErrors, instance, language) => {
12+
/** @type ErrorObject[] */
13+
const errors = [];
14+
if (normalizedErrors["https://json-schema.org/keyword/contains"]) {
15+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/contains"]) {
16+
const localization = await Localization.forLocale(language);
17+
errors.push({
18+
message: localization.getContainsErrorMessage(),
19+
instanceLocation: Instance.uri(instance),
20+
schemaLocation: schemaLocation
21+
});
22+
const containsNodes = /** @type NormalizedOutput[] */(normalizedErrors["https://json-schema.org/keyword/contains"][schemaLocation]);
23+
for (const errorOutput of containsNodes) {
24+
const containsSubErrors = await getErrors(errorOutput, instance, language);
25+
errors.push(...containsSubErrors);
26+
}
27+
}
28+
}
29+
30+
return errors;
31+
};
32+
33+
export default contains;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import { Localization } from "../localization.js";
5+
6+
/**
7+
* @import {ErrorObject } from "../index.d.ts"
8+
* @import {ErrorHandler} from "../utilis.js"
9+
*/
10+
11+
/** @type ErrorHandler */
12+
const dependentRequired = async (normalizedErrors, instance, language) => {
13+
/** @type ErrorObject[] */
14+
const errors = [];
15+
16+
if (normalizedErrors["https://json-schema.org/keyword/dependentRequired"]) {
17+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/dependentRequired"]) {
18+
if (!normalizedErrors["https://json-schema.org/keyword/dependentRequired"][schemaLocation]) {
19+
const keyword = await getSchema(schemaLocation);
20+
const dependentRequired = /** @type {Record<string, string[]>} */(Schema.value(keyword));
21+
const localization = await Localization.forLocale(language);
22+
for (const propertyName in dependentRequired) {
23+
if (Instance.has(propertyName, instance)) {
24+
const required = dependentRequired[propertyName];
25+
const missing = required.filter((prop) => !Instance.has(prop, instance));
26+
27+
if (missing.length > 0) {
28+
errors.push({
29+
message: localization.getDependentRequiredErrorMessage(propertyName, [...missing]),
30+
instanceLocation: Instance.uri(instance),
31+
schemaLocation: schemaLocation
32+
});
33+
}
34+
}
35+
}
36+
}
37+
}
38+
}
39+
40+
return errors;
41+
};
42+
43+
export default dependentRequired;

src/errorHandlers/enum.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import leven from "leven";
5+
import { Localization } from "../localization.js";
6+
7+
/**
8+
* @import {ErrorObject } from "../index.d.ts"
9+
* @import {ErrorHandler} from "../utilis.js"
10+
*/
11+
12+
/** @type ErrorHandler */
13+
const enum_ = async (normalizedErrors, instance, language) => {
14+
/** @type ErrorObject[] */
15+
const errors = [];
16+
17+
if (normalizedErrors["https://json-schema.org/keyword/enum"]) {
18+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/enum"]) {
19+
if (!normalizedErrors["https://json-schema.org/keyword/enum"][schemaLocation]) {
20+
const keyword = await getSchema(schemaLocation);
21+
const localization = await Localization.forLocale(language);
22+
23+
/** @type {Array<string>} */
24+
const allowedValues = Schema.value(keyword);
25+
const currentValue = /** @type {string} */ (Instance.value(instance));
26+
27+
const bestMatch = allowedValues
28+
.map((value) => ({
29+
value,
30+
weight: leven(value, currentValue)
31+
}))
32+
.sort((a, b) => a.weight - b.weight)[0];
33+
let message;
34+
if (
35+
allowedValues.length === 1
36+
|| (bestMatch && bestMatch.weight < bestMatch.value.length)
37+
) {
38+
message = localization.getEnumErrorMessage({
39+
variant: "suggestion",
40+
instanceValue: currentValue,
41+
suggestion: bestMatch.value
42+
});
43+
} else {
44+
message = localization.getEnumErrorMessage({
45+
variant: "fallback",
46+
instanceValue: currentValue,
47+
allowedValues: allowedValues
48+
});
49+
}
50+
errors.push({
51+
message,
52+
instanceLocation: Instance.uri(instance),
53+
schemaLocation: schemaLocation
54+
});
55+
}
56+
}
57+
}
58+
59+
return errors;
60+
};
61+
62+
export default enum_;

src/errorHandlers/exclusiveMaximum.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import { Localization } from "../localization.js";
5+
6+
/**
7+
* @import {ErrorObject } from "../index.d.ts"
8+
* @import {ErrorHandler} from "../utilis.js"
9+
*/
10+
/** @type ErrorHandler */
11+
const exclusiveMaximum = async (normalizedErrors, instance, language) => {
12+
/** @type ErrorObject[] */
13+
const errors = [];
14+
15+
if (normalizedErrors["https://json-schema.org/keyword/exclusiveMaximum"]) {
16+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/exclusiveMaximum"]) {
17+
if (!normalizedErrors["https://json-schema.org/keyword/exclusiveMaximum"][schemaLocation]) {
18+
const keyword = await getSchema(schemaLocation);
19+
const localization = await Localization.forLocale(language);
20+
errors.push({
21+
message: localization.getExclusiveMaximumErrorMessage(Schema.value(keyword)),
22+
instanceLocation: Instance.uri(instance),
23+
schemaLocation: schemaLocation
24+
});
25+
}
26+
}
27+
}
28+
29+
return errors;
30+
};
31+
32+
export default exclusiveMaximum;

src/errorHandlers/exclusiveMinimum.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { getSchema } from "@hyperjump/json-schema/experimental";
2+
import * as Schema from "@hyperjump/browser";
3+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
4+
import { Localization } from "../localization.js";
5+
6+
/**
7+
* @import {ErrorObject } from "../index.d.ts"
8+
* @import {ErrorHandler} from "../utilis.js"
9+
*/
10+
11+
/** @type ErrorHandler */
12+
const exclusiveMinimum = async (normalizedErrors, instance, language) => {
13+
/** @type ErrorObject[] */
14+
const errors = [];
15+
16+
if (normalizedErrors["https://json-schema.org/keyword/exclusiveMinimum"]) {
17+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/exclusiveMinimum"]) {
18+
if (!normalizedErrors["https://json-schema.org/keyword/exclusiveMinimum"][schemaLocation]) {
19+
const keyword = await getSchema(schemaLocation);
20+
const localization = await Localization.forLocale(language);
21+
errors.push({
22+
message: localization.getExclusiveMinimumErrorMessage(Schema.value(keyword)),
23+
instanceLocation: Instance.uri(instance),
24+
schemaLocation: schemaLocation
25+
});
26+
}
27+
}
28+
}
29+
30+
return errors;
31+
};
32+
33+
export default exclusiveMinimum;

0 commit comments

Comments
 (0)