Skip to content

Commit 0870386

Browse files
committed
added combine handlers for min-maxProperites and min-maxItems
1 parent 33eb965 commit 0870386

File tree

10 files changed

+241
-152
lines changed

10 files changed

+241
-152
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 { ArrayConstraints } from "../localization.js"
7+
* @import { ErrorHandler } from "../index.d.ts"
8+
*/
9+
10+
/** @type ErrorHandler */
11+
const arrayRangeHandler = async (normalizedErrors, instance, localization) => {
12+
/** @type ArrayConstraints */
13+
const constraints = {};
14+
15+
/** @type string[] */
16+
const failedSchemaLocations = [];
17+
18+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/minItems"]) {
19+
if (!normalizedErrors["https://json-schema.org/keyword/minItems"][schemaLocation]) {
20+
failedSchemaLocations.push(schemaLocation);
21+
}
22+
23+
const keyword = await getSchema(schemaLocation);
24+
/** @type number */
25+
const minItems = Schema.value(keyword);
26+
constraints.minItems = Math.max(constraints.minItems ?? Number.MIN_VALUE, minItems);
27+
}
28+
29+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/maxItems"]) {
30+
if (!normalizedErrors["https://json-schema.org/keyword/maxItems"][schemaLocation]) {
31+
failedSchemaLocations.push(schemaLocation);
32+
}
33+
34+
const keyword = await getSchema(schemaLocation);
35+
/** @type number */
36+
const maxItems = Schema.value(keyword);
37+
constraints.maxItems = Math.min(constraints.maxItems ?? Number.MAX_VALUE, maxItems);
38+
}
39+
40+
if (failedSchemaLocations.length > 0) {
41+
return [
42+
{
43+
message: localization.getArrayErrorMessage(constraints),
44+
instanceLocation: Instance.uri(instance),
45+
schemaLocation: failedSchemaLocations.length > 1 ? failedSchemaLocations : failedSchemaLocations[0]
46+
}
47+
];
48+
}
49+
50+
return [];
51+
};
52+
53+
export default arrayRangeHandler;

src/error-handlers/maxItems.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/error-handlers/maxProperties.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/error-handlers/minItems.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/error-handlers/minProperties.js

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
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 { PropertiesConstraints } from "../localization.js"
7+
* @import { ErrorHandler } from "../index.d.ts"
8+
*/
9+
10+
/** @type ErrorHandler */
11+
const propertiesRangeHandler = async (normalizedErrors, instance, localization) => {
12+
/** @type PropertiesConstraints */
13+
const constraints = {};
14+
15+
/** @type string[] */
16+
const failedSchemaLocations = [];
17+
18+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/minProperties"]) {
19+
if (!normalizedErrors["https://json-schema.org/keyword/minProperties"][schemaLocation]) {
20+
failedSchemaLocations.push(schemaLocation);
21+
}
22+
23+
const keyword = await getSchema(schemaLocation);
24+
/** @type number */
25+
const minProperties = Schema.value(keyword);
26+
constraints.minProperties = Math.max(constraints.minProperties ?? Number.MIN_VALUE, minProperties);
27+
}
28+
29+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/maxProperties"]) {
30+
if (!normalizedErrors["https://json-schema.org/keyword/maxProperties"][schemaLocation]) {
31+
failedSchemaLocations.push(schemaLocation);
32+
}
33+
34+
const keyword = await getSchema(schemaLocation);
35+
/** @type number */
36+
const maxProperties = Schema.value(keyword);
37+
constraints.maxProperties = Math.min(constraints.maxProperties ?? Number.MAX_VALUE, maxProperties);
38+
}
39+
40+
if (failedSchemaLocations.length > 0) {
41+
return [
42+
{
43+
message: localization.getPropertiesErrorMessage(constraints),
44+
instanceLocation: Instance.uri(instance),
45+
schemaLocation: failedSchemaLocations.length > 1 ? failedSchemaLocations : failedSchemaLocations[0]
46+
}
47+
];
48+
}
49+
50+
return [];
51+
};
52+
53+
export default propertiesRangeHandler;

src/index.js

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,12 @@ import uniqueItems from "./normalization-handlers/uniqueItems.js";
4646
// Error Handlers
4747
import anyOfErrorHandler from "./error-handlers/anyOf.js";
4848
import additionalPropertiesErrorHandler from "./error-handlers/additionalProperties.js";
49+
import arrayRangeErrorHandler from "./error-handlers/array-range-handler.js";
4950
import constErrorHandler from "./error-handlers/const.js";
5051
import containsErrorHandler from "./error-handlers/contains.js";
5152
import dependentRequiredErrorHandler from "./error-handlers/dependentRequired.js";
5253
import enumErrorHandler from "./error-handlers/enum.js";
5354
import formatErrorHandler from "./error-handlers/format.js";
54-
import maxItemsErrorHandler from "./error-handlers/maxItems.js";
55-
import minItemsErrorHandler from "./error-handlers/minItems.js";
56-
import maxPropertiesErrorHandler from "./error-handlers/maxProperties.js";
57-
import minPropertiesErrorHandler from "./error-handlers/minProperties.js";
5855
import multipleOfErrorHandler from "./error-handlers/multipleOf.js";
5956
import notErrorHandler from "./error-handlers/not.js";
6057
import numberRangeHandler from "./error-handlers/number-range-handler.js";
@@ -63,6 +60,7 @@ import typeErrorHandler from "./error-handlers/type.js";
6360
import uniqueItemsErrorHandler from "./error-handlers/uniqueItems.js";
6461
import stringErrorHandler from "./error-handlers/string-handler.js";
6562
import patternErrorHandler from "./error-handlers/pattern.js";
63+
import propertiesRangeHandler from "./error-handlers/properties-range-handler.js";
6664

6765
/**
6866
* @import { betterJsonSchemaErrors } from "./index.d.ts"
@@ -122,10 +120,7 @@ addErrorHandler(containsErrorHandler);
122120
addErrorHandler(dependentRequiredErrorHandler);
123121
addErrorHandler(enumErrorHandler);
124122
addErrorHandler(formatErrorHandler);
125-
addErrorHandler(maxItemsErrorHandler);
126-
addErrorHandler(minItemsErrorHandler);
127-
addErrorHandler(maxPropertiesErrorHandler);
128-
addErrorHandler(minPropertiesErrorHandler);
123+
addErrorHandler(arrayRangeErrorHandler);
129124
addErrorHandler(multipleOfErrorHandler);
130125
addErrorHandler(notErrorHandler);
131126
addErrorHandler(numberRangeHandler);
@@ -134,6 +129,7 @@ addErrorHandler(typeErrorHandler);
134129
addErrorHandler(uniqueItemsErrorHandler);
135130
addErrorHandler(stringErrorHandler);
136131
addErrorHandler(patternErrorHandler);
132+
addErrorHandler(propertiesRangeHandler);
137133

138134
export { setNormalizationHandler } from "./normalized-output.js";
139135
export { addErrorHandler } from "./error-handling.js";

src/keyword-error-message.test.js

Lines changed: 75 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,7 +396,7 @@ describe("Error messages", async () => {
396396
expect(result.errors).to.eql([{
397397
schemaLocation: "https://example.com/main#/maxProperties",
398398
instanceLocation: "#",
399-
message: localization.getMaxPropertiesErrorMessage(2)
399+
message: localization.getPropertiesErrorMessage({ maxProperties: 2 })
400400
}]);
401401
});
402402

@@ -424,7 +424,43 @@ describe("Error messages", async () => {
424424
expect(result.errors).to.eql([{
425425
schemaLocation: "https://example.com/main#/minProperties",
426426
instanceLocation: "#",
427-
message: localization.getMinPropertiesErrorMessage(2)
427+
message: localization.getPropertiesErrorMessage({ minProperties: 2 })
428+
}]);
429+
});
430+
431+
test("max-min Properties", async () => {
432+
registerSchema({
433+
$schema: "https://json-schema.org/draft/2020-12/schema",
434+
maxProperties: 3,
435+
minProperties: 2
436+
437+
}, schemaUri);
438+
439+
const instance = { foo: 1 };
440+
441+
/** @type OutputFormat */
442+
const output = {
443+
valid: false,
444+
errors: [
445+
{
446+
absoluteKeywordLocation: "https://example.com/main#/maxProperties",
447+
instanceLocation: "#"
448+
},
449+
{
450+
absoluteKeywordLocation: "https://example.com/main#/minProperties",
451+
instanceLocation: "#"
452+
}
453+
]
454+
};
455+
456+
const result = await betterJsonSchemaErrors(output, schemaUri, instance);
457+
expect(result.errors).to.eql([{
458+
schemaLocation: [
459+
"https://example.com/main#/minProperties",
460+
"https://example.com/main#/maxProperties"
461+
],
462+
instanceLocation: "#",
463+
message: localization.getPropertiesErrorMessage({ maxProperties: 3, minProperties: 2 })
428464
}]);
429465
});
430466

@@ -507,7 +543,7 @@ describe("Error messages", async () => {
507543
expect(result.errors).to.eql([{
508544
schemaLocation: "https://example.com/main#/maxItems",
509545
instanceLocation: "#",
510-
message: localization.getMaxItemsErrorMessage(3)
546+
message: localization.getArrayErrorMessage({ maxItems: 3 })
511547
}]);
512548
});
513549

@@ -534,7 +570,42 @@ describe("Error messages", async () => {
534570
expect(result.errors).to.eql([{
535571
schemaLocation: "https://example.com/main#/minItems",
536572
instanceLocation: "#",
537-
message: localization.getMinItemsErrorMessage(3)
573+
message: localization.getArrayErrorMessage({ minItems: 3 })
574+
}]);
575+
});
576+
577+
test("minItems and maxItems", async () => {
578+
registerSchema({
579+
$schema: "https://json-schema.org/draft/2020-12/schema",
580+
minItems: 3,
581+
maxItems: 4
582+
}, schemaUri);
583+
584+
const instance = [1, 3];
585+
586+
/** @type OutputFormat */
587+
const output = {
588+
valid: false,
589+
errors: [
590+
{
591+
absoluteKeywordLocation: "https://example.com/main#/minItems",
592+
instanceLocation: "#"
593+
},
594+
{
595+
absoluteKeywordLocation: "https://example.com/main#/maxItems",
596+
instanceLocation: "#"
597+
}
598+
]
599+
};
600+
601+
const result = await betterJsonSchemaErrors(output, schemaUri, instance);
602+
expect(result.errors).to.eql([{
603+
schemaLocation: [
604+
"https://example.com/main#/minItems",
605+
"https://example.com/main#/maxItems"
606+
],
607+
instanceLocation: "#",
608+
message: localization.getArrayErrorMessage({ minItems: 3, maxItems: 4 })
538609
}]);
539610
});
540611

0 commit comments

Comments
 (0)