diff --git a/packages/quicktype-core/src/rewrites/ResolveIntersections.ts b/packages/quicktype-core/src/rewrites/ResolveIntersections.ts index 05b424f43..4db68fae7 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 { @@ -337,6 +348,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.fail.date-time.json b/test/inputs/schema/transformed-string-intersection.1.fail.date-time.json new file mode 100644 index 000000000..2e1669a4d --- /dev/null +++ b/test/inputs/schema/transformed-string-intersection.1.fail.date-time.json @@ -0,0 +1,5 @@ +{ + "committer": { + "date": "not a real timestamp" + } +} 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 000000000..e958405c2 --- /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 000000000..89adcc72a --- /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"] +}