From 34c75afbab227b41586e97ec293a396f4176991e Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 20 Jul 2026 17:57:54 -0400 Subject: [PATCH 1/2] fix(schema): don't collapse allOf-intersected string with date-time/etc to empty (#1770) Co-Authored-By: gpt-5.6-sol via pi --- .../src/rewrites/ResolveIntersections.ts | 26 +++++++++++++++ .../transformed-string-intersection.1.json | 5 +++ .../transformed-string-intersection.schema | 33 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 test/inputs/schema/transformed-string-intersection.1.json create mode 100644 test/inputs/schema/transformed-string-intersection.schema diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index 7f3ab80d84..19d701b7d9 100644 --- a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts +++ b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts @@ -32,6 +32,7 @@ import { UnionType, isNumberTypeKind, isPrimitiveTypeKind, + transformedStringTypeKinds, } from "../Type/index.js"; import type { TypeBuilder } from "../Type/TypeBuilder.js"; import type { StringTypeMapping } from "../Type/TypeBuilderUtils.js"; @@ -125,6 +126,11 @@ class IntersectionAccumulator iterableFind(this._primitiveTypes, isNumberTypeKind) !== undefined && iterableFind(kinds, isNumberTypeKind) !== undefined; + const narrowedStringTypes = this._primitiveTypes.has("string") + ? setIntersect(kinds, transformedStringTypeKinds) + : kinds.has("string") + ? setIntersect(this._primitiveTypes, transformedStringTypeKinds) + : new Set(); this._primitiveTypes = setIntersect(this._primitiveTypes, kinds); if ( haveNumber && @@ -134,6 +140,11 @@ class IntersectionAccumulator // of that is integer. this._primitiveTypes = this._primitiveTypes.add("integer"); } + + // A transformed string is a specialization of a plain string. + if (!this._primitiveTypes.has("string")) { + setUnionInto(this._primitiveTypes, narrowedStringTypes); + } } private updateArrayItemTypes(members: Iterable): void { @@ -339,6 +350,21 @@ class IntersectionAccumulator }); } + const maybeStringAttributes = this._primitiveAttributes.get("string"); + if (maybeStringAttributes !== undefined && !kinds.has("string")) { + for (const kind of transformedStringTypeKinds) { + if (kinds.has(kind)) { + mapUpdateInto(kinds, kind, (a) => + combineTypeAttributes( + "intersect", + defined(a), + maybeStringAttributes, + ), + ); + } + } + } + if ( this._arrayItemTypes !== undefined && this._arrayItemTypes !== false diff --git a/test/inputs/schema/transformed-string-intersection.1.json b/test/inputs/schema/transformed-string-intersection.1.json new file mode 100644 index 0000000000..e958405c28 --- /dev/null +++ b/test/inputs/schema/transformed-string-intersection.1.json @@ -0,0 +1,5 @@ +{ + "committer": { + "date": "2024-01-02T03:04:05Z" + } +} diff --git a/test/inputs/schema/transformed-string-intersection.schema b/test/inputs/schema/transformed-string-intersection.schema new file mode 100644 index 0000000000..89adcc72a2 --- /dev/null +++ b/test/inputs/schema/transformed-string-intersection.schema @@ -0,0 +1,33 @@ +{ + "definitions": { + "committer": { + "type": "object", + "properties": { + "date": { + "type": "string", + "format": "date-time" + } + }, + "required": ["date"] + } + }, + "type": "object", + "properties": { + "committer": { + "allOf": [ + { + "$ref": "#/definitions/committer" + }, + { + "type": "object", + "properties": { + "date": { + "type": "string" + } + } + } + ] + } + }, + "required": ["committer"] +} From 257d3a10fa763aec332ae9ee68547e6465643b92 Mon Sep 17 00:00:00 2001 From: Mark Probst Date: Mon, 20 Jul 2026 19:36:33 -0400 Subject: [PATCH 2/2] test: add missing fixture cases for transformed-string-intersection.schema (#3026) Co-Authored-By: Claude --- .../transformed-string-intersection.1.fail.date-time.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 test/inputs/schema/transformed-string-intersection.1.fail.date-time.json diff --git a/test/inputs/schema/transformed-string-intersection.1.fail.date-time.json b/test/inputs/schema/transformed-string-intersection.1.fail.date-time.json new file mode 100644 index 0000000000..2e1669a4dd --- /dev/null +++ b/test/inputs/schema/transformed-string-intersection.1.fail.date-time.json @@ -0,0 +1,5 @@ +{ + "committer": { + "date": "not a real timestamp" + } +}