From 5ec69079d7c2238b36faafc1f81671a834e5c6f0 Mon Sep 17 00:00:00 2001 From: Diya Date: Tue, 27 Jan 2026 03:22:36 +0530 Subject: [PATCH 1/3] Refactor type error handler to combine type error messages --- src/error-handlers/type.js | 51 +++++++++++++++++++++++++++++--------- 1 file changed, 39 insertions(+), 12 deletions(-) diff --git a/src/error-handlers/type.js b/src/error-handlers/type.js index 39a9dc6..411184f 100644 --- a/src/error-handlers/type.js +++ b/src/error-handlers/type.js @@ -6,26 +6,53 @@ import * as Instance from "@hyperjump/json-schema/instance/experimental"; * @import { ErrorHandler, ErrorObject } from "../index.d.ts" */ +const ALL_TYPES = new Set(["null", "boolean", "number", "string", "array", "object", "integer"]); + /** @type ErrorHandler */ const typeErrorHandler = async (normalizedErrors, instance, localization) => { /** @type ErrorObject[] */ const errors = []; - for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/type"]) { - if (normalizedErrors["https://json-schema.org/keyword/type"][schemaLocation]) { - continue; + if (normalizedErrors["https://json-schema.org/keyword/type"]) { + /** @type {Set} */ + let allowedTypes = ALL_TYPES; + const failedTypeLocations = []; + + for (const schemaLocation in normalizedErrors["https://json-schema.org/keyword/type"]) { + const isValid = normalizedErrors["https://json-schema.org/keyword/type"][schemaLocation]; + if (!isValid) { + failedTypeLocations.push(schemaLocation); + + const keyword = await getSchema(schemaLocation); + /** @type {string|string[]} */ + const value = Schema.value(keyword); + const types = Array.isArray(value) ? value : [value]; + /** @type {Set} */ + const keywordTypes = new Set(types); + if (keywordTypes.has("number")) { + keywordTypes.add("integer"); + } + allowedTypes = allowedTypes.intersection(keywordTypes); + } } - const keyword = await getSchema(schemaLocation); - const expectedTypes = /** @type string[] */ (Schema.typeOf(keyword) === "array" - ? Schema.value(keyword) - : [Schema.value(keyword)]); + if (allowedTypes.has("number")) { + allowedTypes.delete("integer"); + } - errors.push({ - message: localization.getTypeErrorMessage(expectedTypes), - instanceLocation: Instance.uri(instance), - schemaLocations: [schemaLocation] - }); + if (allowedTypes.size === 0) { + errors.push({ + message: localization.getUnknownErrorMessage("type"), + instanceLocation: Instance.uri(instance), + schemaLocations: failedTypeLocations + }); + } else if (failedTypeLocations.length > 0) { + errors.push({ + message: localization.getTypeErrorMessage([...allowedTypes]), + instanceLocation: Instance.uri(instance), + schemaLocations: failedTypeLocations + }); + } } return errors; From 987b6f3cef6484569d5a1fa303a65901759902f1 Mon Sep 17 00:00:00 2001 From: Diya Date: Tue, 27 Jan 2026 04:42:07 +0530 Subject: [PATCH 2/3] Add test for type error handler --- src/test-suite/tests/type.json | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/test-suite/tests/type.json b/src/test-suite/tests/type.json index 94cf934..5209e43 100644 --- a/src/test-suite/tests/type.json +++ b/src/test-suite/tests/type.json @@ -36,6 +36,27 @@ "schemaLocations": ["#/type"] } ] + }, + { + "description": "collapsed type errors", + "schema": { + "allOf": [ + {"type": ["string","boolean","number"]}, + {"type": ["string","number"]}, + {"type": "string"} + ] + }, + "instance": null, + "errors": [ + { + "messageId": "type-message", + "messageParams": { + "expectedTypes": "string" + }, + "instanceLocation": "#", + "schemaLocations": ["#/allOf/0/type", "#/allOf/1/type", "#/allOf/2/type"] + } + ] } ] } From bb2139b6fd6c820c8a0b1b69617fcdef4d1f36ff Mon Sep 17 00:00:00 2001 From: Diya Srivastava Date: Wed, 28 Jan 2026 07:20:56 +0000 Subject: [PATCH 3/3] change getUnknownErrorMessage to getBooleanSchemaErrorMessage and add test --- src/error-handlers/type.js | 2 +- src/test-suite/tests/type.json | 25 +++++++++++++++++++++---- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/error-handlers/type.js b/src/error-handlers/type.js index 411184f..99bcb9b 100644 --- a/src/error-handlers/type.js +++ b/src/error-handlers/type.js @@ -42,7 +42,7 @@ const typeErrorHandler = async (normalizedErrors, instance, localization) => { if (allowedTypes.size === 0) { errors.push({ - message: localization.getUnknownErrorMessage("type"), + message: localization.getBooleanSchemaErrorMessage(), instanceLocation: Instance.uri(instance), schemaLocations: failedTypeLocations }); diff --git a/src/test-suite/tests/type.json b/src/test-suite/tests/type.json index 5209e43..fcaf923 100644 --- a/src/test-suite/tests/type.json +++ b/src/test-suite/tests/type.json @@ -41,9 +41,9 @@ "description": "collapsed type errors", "schema": { "allOf": [ - {"type": ["string","boolean","number"]}, - {"type": ["string","number"]}, - {"type": "string"} + { "type": ["string", "boolean", "number"] }, + { "type": ["string", "number"] }, + { "type": "string" } ] }, "instance": null, @@ -51,12 +51,29 @@ { "messageId": "type-message", "messageParams": { - "expectedTypes": "string" + "expectedTypes": { "or": ["string"] } }, "instanceLocation": "#", "schemaLocations": ["#/allOf/0/type", "#/allOf/1/type", "#/allOf/2/type"] } ] + }, + { + "description": "no types allowed", + "schema": { + "allOf": [ + { "type": "string" }, + { "type": "number" } + ] + }, + "instance": null, + "errors": [ + { + "messageId": "boolean-schema-message", + "instanceLocation": "#", + "schemaLocations": ["#/allOf/0/type", "#/allOf/1/type"] + } + ] } ] }