Skip to content

Commit 41801ee

Browse files
committed
added string-handler
1 parent c11aab9 commit 41801ee

File tree

9 files changed

+157
-126
lines changed

9 files changed

+157
-126
lines changed

src/error-handlers/maxLength.js

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

src/error-handlers/minLength.js

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

src/error-handlers/pattern.js

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

src/error-handlers/string-handler.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+
5+
/**
6+
* @import { StringConstraints } from "../localization.js"
7+
* @import { ErrorHandler } from "../index.d.ts"
8+
*/
9+
10+
/** @type ErrorHandler */
11+
const stringHandler = async (normalizedErrors, instance, localization) => {
12+
/** @type StringConstraints */
13+
const constraints = {};
14+
15+
/** @type string[] */
16+
const failedSchemaLocations = [];
17+
18+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/minLength"]) {
19+
if (!normalizedErrors["https://json-schema.org/keyword/minLength"][schemaLocation]) {
20+
failedSchemaLocations.push(schemaLocation);
21+
}
22+
23+
const keyword = await getSchema(schemaLocation);
24+
/** @type number */
25+
const minLength = Schema.value(keyword);
26+
constraints.minLength = Math.max(constraints.minLength ?? Number.MIN_VALUE, minLength);
27+
}
28+
29+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/maxLength"]) {
30+
if (!normalizedErrors["https://json-schema.org/keyword/maxLength"][schemaLocation]) {
31+
failedSchemaLocations.push(schemaLocation);
32+
}
33+
34+
const keyword = await getSchema(schemaLocation);
35+
/** @type number */
36+
const maxLength = Schema.value(keyword);
37+
constraints.maxLength = Math.min(constraints.maxLength ?? Number.MAX_VALUE, maxLength);
38+
}
39+
40+
for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/pattern"]) {
41+
if (!normalizedErrors["https://json-schema.org/keyword/pattern"][schemaLocation]) {
42+
failedSchemaLocations.push(schemaLocation);
43+
}
44+
45+
const keyword = await getSchema(schemaLocation);
46+
/** @type string */
47+
const pattern = Schema.value(keyword);
48+
constraints.pattern = pattern;
49+
}
50+
51+
if (failedSchemaLocations.length > 0) {
52+
return [
53+
{
54+
message: localization.getStringErrorMessage(constraints),
55+
instanceLocation: Instance.uri(instance),
56+
schemaLocation: failedSchemaLocations.length > 1 ? failedSchemaLocations : failedSchemaLocations[0]
57+
}
58+
];
59+
}
60+
61+
return [];
62+
};
63+
64+
export default stringHandler;

src/index.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,13 @@ import maxItemsErrorHandler from "./error-handlers/maxItems.js";
5555
import minItemsErrorHandler from "./error-handlers/minItems.js";
5656
import maxPropertiesErrorHandler from "./error-handlers/maxProperties.js";
5757
import minPropertiesErrorHandler from "./error-handlers/minProperties.js";
58-
import minLengthErrorHandler from "./error-handlers/minLength.js";
5958
import multipleOfErrorHandler from "./error-handlers/multipleOf.js";
6059
import notErrorHandler from "./error-handlers/not.js";
6160
import numberRangeHandler from "./error-handlers/number-range-handler.js";
62-
import patternErrorHandler from "./error-handlers/pattern.js";
6361
import requiredErrorHandler from "./error-handlers/required.js";
6462
import typeErrorHandler from "./error-handlers/type.js";
6563
import uniqueItemsErrorHandler from "./error-handlers/uniqueItems.js";
66-
import maxLengthErrorHandler from "./error-handlers/maxLength.js";
64+
import stringHandler from "./error-handlers/string-handler.js";
6765

6866
/**
6967
* @import { betterJsonSchemaErrors } from "./index.d.ts"
@@ -127,15 +125,13 @@ addErrorHandler(maxItemsErrorHandler);
127125
addErrorHandler(minItemsErrorHandler);
128126
addErrorHandler(maxPropertiesErrorHandler);
129127
addErrorHandler(minPropertiesErrorHandler);
130-
addErrorHandler(minLengthErrorHandler);
131-
addErrorHandler(maxLengthErrorHandler);
132128
addErrorHandler(multipleOfErrorHandler);
133129
addErrorHandler(notErrorHandler);
134130
addErrorHandler(numberRangeHandler);
135-
addErrorHandler(patternErrorHandler);
136131
addErrorHandler(requiredErrorHandler);
137132
addErrorHandler(typeErrorHandler);
138133
addErrorHandler(uniqueItemsErrorHandler);
134+
addErrorHandler(stringHandler);
139135

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

src/keyword-error-message.test.js

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe("Error messages", async () => {
3939
expect(result.errors).to.eql([{
4040
schemaLocation: "https://example.com/main#/minLength",
4141
instanceLocation: "#",
42-
message: localization.getMinLengthErrorMessage(3)
42+
message: localization.getStringErrorMessage({ minLength: 3 })
4343
}]);
4444
});
4545

@@ -66,7 +66,7 @@ describe("Error messages", async () => {
6666
expect(result.errors).to.eql([{
6767
schemaLocation: "https://example.com/main#/maxLength",
6868
instanceLocation: "#",
69-
message: localization.getMaxLengthErrorMessage(3)
69+
message: localization.getStringErrorMessage({ maxLength: 3 })
7070
}]);
7171
});
7272

@@ -614,7 +614,7 @@ describe("Error messages", async () => {
614614
{
615615
schemaLocation: "https://example.com/main#/pattern",
616616
instanceLocation: "#",
617-
message: localization.getPatternErrorMessage("^[a-z]+$")
617+
message: localization.getStringErrorMessage({ pattern: "^[a-z]+$" })
618618
}
619619
]);
620620
});
@@ -822,7 +822,7 @@ describe("Error messages", async () => {
822822
{
823823
schemaLocation: `https://example.com/main#/anyOf/0/minLength`,
824824
instanceLocation: "#",
825-
message: localization.getMinLengthErrorMessage(5)
825+
message: localization.getStringErrorMessage({ minLength: 5 })
826826
}
827827
]);
828828
});
@@ -883,7 +883,7 @@ describe("Error messages", async () => {
883883
{
884884
schemaLocation: "https://example.com/main#/anyOf/1/properties/ID/pattern",
885885
instanceLocation: "#/ID",
886-
message: localization.getPatternErrorMessage("^[0-9\\-]+$")
886+
message: localization.getStringErrorMessage({ pattern: "^[0-9\\-]+$" })
887887
}
888888
]);
889889
});
@@ -1229,7 +1229,7 @@ describe("Error messages", async () => {
12291229
expect(result.errors).to.eql([
12301230
{
12311231
instanceLocation: "#/Foo",
1232-
message: localization.getPatternErrorMessage("^[a-z]*$"),
1232+
message: localization.getStringErrorMessage({ pattern: "^[a-z]*$" }),
12331233
schemaLocation: "https://example.com/main#/propertyNames/pattern"
12341234
}
12351235
]);
@@ -1256,7 +1256,7 @@ describe("Error messages", async () => {
12561256
expect(result.errors).to.eql([
12571257
{
12581258
instanceLocation: "#/Foo",
1259-
message: localization.getPatternErrorMessage("^[a-z]*$"),
1259+
message: localization.getStringErrorMessage({ pattern: "^[a-z]*$" }),
12601260
schemaLocation: "https://example.com/main#/propertyNames/pattern"
12611261
}
12621262
]);
@@ -1283,7 +1283,7 @@ describe("Error messages", async () => {
12831283
expect(result.errors).to.eql([
12841284
{
12851285
instanceLocation: "#*/Foo",
1286-
message: localization.getPatternErrorMessage("^[a-z]*$"),
1286+
message: localization.getStringErrorMessage({ pattern: "^[a-z]*$" }),
12871287
schemaLocation: "https://example.com/main#/propertyNames/pattern"
12881288
}
12891289
]);
@@ -1371,4 +1371,47 @@ describe("Error messages", async () => {
13711371
}
13721372
]);
13731373
});
1374+
1375+
test("minLength/maxLength and pattern test", async () => {
1376+
registerSchema({
1377+
$schema: "https://json-schema.org/draft/2020-12/schema",
1378+
allOf: [
1379+
{ minLength: 3 },
1380+
{ maxLength: 5 },
1381+
{ pattern: "^[a-z]+$" }
1382+
]
1383+
}, schemaUri);
1384+
1385+
const instance = "AAAAAAA";
1386+
1387+
/** @type OutputFormat */
1388+
const output = {
1389+
valid: false,
1390+
errors: [
1391+
{
1392+
absoluteKeywordLocation: "https://example.com/main#/allOf/0/minLength",
1393+
instanceLocation: "#"
1394+
},
1395+
{
1396+
absoluteKeywordLocation: "https://example.com/main#/allOf/1/maxLength",
1397+
instanceLocation: "#"
1398+
},
1399+
{
1400+
absoluteKeywordLocation: "https://example.com/main#/allOf/2/pattern",
1401+
instanceLocation: "#"
1402+
}
1403+
]
1404+
};
1405+
1406+
const result = await betterJsonSchemaErrors(output, schemaUri, instance);
1407+
expect(result.errors).to.eql([{
1408+
schemaLocation: [
1409+
"https://example.com/main#/allOf/0/minLength",
1410+
"https://example.com/main#/allOf/1/maxLength",
1411+
"https://example.com/main#/allOf/2/pattern"
1412+
],
1413+
instanceLocation: "#",
1414+
message: localization.getStringErrorMessage({ minLength: 3, maxLength: 5, pattern: "^[a-z]+$" })
1415+
}]);
1416+
});
13741417
});

src/localization.js

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,14 @@ import { FluentBundle, FluentResource } from "@fluent/bundle";
1414
* }} NumberConstraints
1515
*/
1616

17+
/**
18+
* @typedef {{
19+
* minLength?: number;
20+
* maxLength?: number;
21+
* pattern?: string;
22+
* }} StringConstraints
23+
*/
24+
1725
export class Localization {
1826
/**
1927
* @param {string} locale
@@ -65,16 +73,6 @@ export class Localization {
6573
});
6674
}
6775

68-
/** @type (limit: number) => string */
69-
getMinLengthErrorMessage(limit) {
70-
return this._formatMessage("min-length-error", { limit });
71-
}
72-
73-
/** @type (limit: number) => string */
74-
getMaxLengthErrorMessage(limit) {
75-
return this._formatMessage("max-length-error", { limit });
76-
}
77-
7876
/** @type (constraints: NumberConstraints) => string */
7977
getNumberErrorMessage(constraints) {
8078
/** @type string[] */
@@ -101,6 +99,28 @@ export class Localization {
10199
});
102100
}
103101

102+
/** @type (constraints: StringConstraints) => string */
103+
getStringErrorMessage(constraints) {
104+
/** @type string[] */
105+
const messages = [];
106+
107+
if (constraints.minLength) {
108+
messages.push(this._formatMessage("string-error-minLength", constraints));
109+
}
110+
111+
if (constraints.maxLength) {
112+
messages.push(this._formatMessage("string-error-maxLength", constraints));
113+
}
114+
115+
if (constraints.pattern) {
116+
messages.push(this._formatMessage("string-error-pattern", constraints));
117+
}
118+
119+
return this._formatMessage("string-error", {
120+
constraints: new Intl.ListFormat(this.locale, { type: "conjunction" }).format(messages)
121+
});
122+
}
123+
104124
/** @type (instanceLocation: string, missingProperties: string[]) => string */
105125
getRequiredErrorMessage(instanceLocation, missingProperties) {
106126
return this._formatMessage("required-error", {
@@ -149,11 +169,6 @@ export class Localization {
149169
return this._formatMessage("format-error", { format });
150170
}
151171

152-
/** @type (pattern: string) => string */
153-
getPatternErrorMessage(pattern) {
154-
return this._formatMessage("pattern-error", { pattern });
155-
}
156-
157172
/** @type () => string */
158173
getContainsErrorMessage() {
159174
return this._formatMessage("contains-error");

0 commit comments

Comments
 (0)