Skip to content

Commit da06c80

Browse files
authored
Merge pull request #46 from arpitkuriyal/fileRefactor
refactor keywordHandlers and errorHandlers
2 parents b7a425a + 9d6d07a commit da06c80

Some content is hidden

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

72 files changed

+2025
-1327
lines changed

eslint.config.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import importPlugin from "eslint-plugin-import";
55
export default tseslint.config(
66
...tseslint.configs.recommendedTypeChecked,
77
...tseslint.configs.stylisticTypeChecked,
8-
importPlugin.flatConfigs.recommended, // eslint-disable-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
9-
importPlugin.flatConfigs.typescript, // eslint-disable-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
8+
importPlugin.flatConfigs.recommended,
9+
importPlugin.flatConfigs.typescript,
1010
stylistic.configs.customize({
1111
arrowParens: true,
1212
braceStyle: "1tbs",
@@ -36,6 +36,7 @@ export default tseslint.config(
3636
}],
3737
"@typescript-eslint/no-empty-function": "off",
3838
"@typescript-eslint/consistent-type-definitions": ["error", "type"],
39+
"@typescript-eslint/consistent-indexed-object-style": "off",
3940
"no-console": "error",
4041

4142
// Imports

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: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as Instance from "@hyperjump/json-schema/instance/experimental";
2+
3+
/**
4+
* @import { ErrorHandler, ErrorObject } from "../index.d.ts"
5+
*/
6+
7+
/** @type ErrorHandler */
8+
// eslint-disable-next-line @typescript-eslint/require-await
9+
const additionalProperties = async (normalizedErrors, instance, localization) => {
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+
errors.push({
17+
message: localization.getAdditionalPropertiesErrorMessage(notAllowedValue),
18+
instanceLocation: Instance.uri(instance),
19+
schemaLocation: schemaLocation
20+
});
21+
}
22+
}
23+
}
24+
return errors;
25+
};
26+
27+
export default additionalProperties;

src/error-handlers/anyOf.js

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

src/error-handlers/const.js

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

src/error-handlers/contains.js

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

src/error-handlers/enum.js

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

0 commit comments

Comments
 (0)