@gqlkit-ts/cli 0.6.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-type-generator/auto-type-generator.d.ts +7 -0
- package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/auto-type-generator.js +375 -55
- package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
- package/dist/auto-type-generator/discriminator-field-validator.d.ts +26 -0
- package/dist/auto-type-generator/discriminator-field-validator.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-field-validator.js +242 -0
- package/dist/auto-type-generator/discriminator-field-validator.js.map +1 -0
- package/dist/auto-type-generator/discriminator-naming.d.ts +11 -0
- package/dist/auto-type-generator/discriminator-naming.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-naming.js +15 -0
- package/dist/auto-type-generator/discriminator-naming.js.map +1 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts +44 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts.map +1 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.js +77 -0
- package/dist/auto-type-generator/discriminator-resolve-type-generator.js.map +1 -0
- package/dist/auto-type-generator/index.d.ts +3 -0
- package/dist/auto-type-generator/index.d.ts.map +1 -1
- package/dist/auto-type-generator/index.js +3 -0
- package/dist/auto-type-generator/index.js.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-enum-collector.js +14 -7
- package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-object-converter.d.ts +12 -0
- package/dist/auto-type-generator/inline-object-converter.d.ts.map +1 -0
- package/dist/auto-type-generator/inline-object-converter.js +72 -0
- package/dist/auto-type-generator/inline-object-converter.js.map +1 -0
- package/dist/auto-type-generator/inline-object-traverser.d.ts +2 -1
- package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-object-traverser.js +22 -4
- package/dist/auto-type-generator/inline-object-traverser.js.map +1 -1
- package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-union-collector.js +20 -6
- package/dist/auto-type-generator/inline-union-collector.js.map +1 -1
- package/dist/auto-type-generator/inline-union-types.d.ts +2 -0
- package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -1
- package/dist/auto-type-generator/inline-union-validator.js +3 -3
- package/dist/auto-type-generator/inline-union-validator.js.map +1 -1
- package/dist/auto-type-generator/intersection-flattener.d.ts +44 -0
- package/dist/auto-type-generator/intersection-flattener.d.ts.map +1 -0
- package/dist/auto-type-generator/intersection-flattener.js +398 -0
- package/dist/auto-type-generator/intersection-flattener.js.map +1 -0
- package/dist/auto-type-generator/naming-convention.d.ts +21 -0
- package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
- package/dist/auto-type-generator/naming-convention.js +145 -1
- package/dist/auto-type-generator/naming-convention.js.map +1 -1
- package/dist/auto-type-generator/typename-extractor.d.ts +2 -0
- package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-extractor.js +11 -3
- package/dist/auto-type-generator/typename-extractor.js.map +1 -1
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +2 -0
- package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-resolve-type-generator.js +12 -84
- package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -1
- package/dist/auto-type-generator/typename-types.d.ts +4 -0
- package/dist/auto-type-generator/typename-types.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-types.js +6 -0
- package/dist/auto-type-generator/typename-types.js.map +1 -1
- package/dist/auto-type-generator/typename-validator.d.ts.map +1 -1
- package/dist/auto-type-generator/typename-validator.js +4 -3
- package/dist/auto-type-generator/typename-validator.js.map +1 -1
- package/dist/commands/gen.d.ts.map +1 -1
- package/dist/commands/gen.js +2 -1
- package/dist/commands/gen.js.map +1 -1
- package/dist/config/types.d.ts +7 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config-loader/index.d.ts +1 -1
- package/dist/config-loader/index.d.ts.map +1 -1
- package/dist/config-loader/index.js.map +1 -1
- package/dist/config-loader/loader.d.ts +6 -0
- package/dist/config-loader/loader.d.ts.map +1 -1
- package/dist/config-loader/loader.js +1 -0
- package/dist/config-loader/loader.js.map +1 -1
- package/dist/config-loader/validator.d.ts.map +1 -1
- package/dist/config-loader/validator.js +84 -1
- package/dist/config-loader/validator.js.map +1 -1
- package/dist/gen-orchestrator/orchestrator.d.ts +2 -1
- package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/gen-orchestrator/orchestrator.js +15 -2
- package/dist/gen-orchestrator/orchestrator.js.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
- package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -0
- package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +2 -0
- package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js +16 -3
- package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
- package/dist/schema-generator/emitter/code-emitter.js +13 -1
- package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts +18 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts.map +1 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js +89 -0
- package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js.map +1 -0
- package/dist/schema-generator/generate-schema.d.ts +2 -0
- package/dist/schema-generator/generate-schema.d.ts.map +1 -1
- package/dist/schema-generator/generate-schema.js +69 -10
- package/dist/schema-generator/generate-schema.js.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.d.ts +4 -0
- package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
- package/dist/schema-generator/integrator/result-integrator.js +18 -2
- package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
- package/dist/schema-generator/resolver-collector/resolver-collector.js +4 -0
- package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +14 -1
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/enum-prefix-detector.d.ts.map +1 -1
- package/dist/shared/enum-prefix-detector.js +78 -8
- package/dist/shared/enum-prefix-detector.js.map +1 -1
- package/dist/shared/inline-object-utils.js +1 -1
- package/dist/shared/inline-object-utils.js.map +1 -1
- package/dist/shared/type-converter.d.ts.map +1 -1
- package/dist/shared/type-converter.js +55 -0
- package/dist/shared/type-converter.js.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
- package/dist/type-extractor/converter/graphql-converter.js +11 -1
- package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.d.ts +18 -0
- package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
- package/dist/type-extractor/extractor/field-type-resolver.js +218 -16
- package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.d.ts +1 -0
- package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-extractor.js +127 -14
- package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
- package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -1
- package/dist/type-extractor/extractor/type-name-collector.js +19 -4
- package/dist/type-extractor/extractor/type-name-collector.js.map +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts +1 -1
- package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
- package/dist/type-extractor/types/index.d.ts +1 -1
- package/dist/type-extractor/types/index.d.ts.map +1 -1
- package/dist/type-extractor/types/index.js +1 -1
- package/dist/type-extractor/types/index.js.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts +7 -1
- package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
- package/dist/type-extractor/types/ts-type-reference-factory.js +18 -3
- package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
- package/dist/type-extractor/types/typescript.d.ts +3 -1
- package/dist/type-extractor/types/typescript.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
- package/dist/type-extractor/validator/type-validator.js +6 -1
- package/dist/type-extractor/validator/type-validator.js.map +1 -1
- package/docs/configuration.md +19 -0
- package/docs/index.md +1 -0
- package/docs/integration/ai-sdk.md +189 -0
- package/docs/schema/unions.md +117 -0
- package/package.json +2 -2
- package/src/auto-type-generator/auto-type-generator.ts +576 -58
- package/src/auto-type-generator/discriminator-field-validator.ts +368 -0
- package/src/auto-type-generator/discriminator-naming.ts +24 -0
- package/src/auto-type-generator/discriminator-resolve-type-generator.ts +136 -0
- package/src/auto-type-generator/index.ts +17 -0
- package/src/auto-type-generator/inline-enum-collector.ts +19 -4
- package/src/auto-type-generator/inline-object-converter.ts +100 -0
- package/src/auto-type-generator/inline-object-traverser.ts +33 -7
- package/src/auto-type-generator/inline-union-collector.ts +26 -4
- package/src/auto-type-generator/inline-union-types.ts +2 -0
- package/src/auto-type-generator/inline-union-validator.ts +3 -3
- package/src/auto-type-generator/intersection-flattener.ts +554 -0
- package/src/auto-type-generator/naming-convention.ts +205 -1
- package/src/auto-type-generator/typename-extractor.ts +17 -3
- package/src/auto-type-generator/typename-resolve-type-generator.ts +19 -108
- package/src/auto-type-generator/typename-types.ts +7 -0
- package/src/auto-type-generator/typename-validator.ts +4 -3
- package/src/commands/gen.ts +9 -2
- package/src/config/types.ts +10 -0
- package/src/config-loader/index.ts +1 -0
- package/src/config-loader/loader.ts +11 -0
- package/src/config-loader/validator.ts +100 -1
- package/src/gen-orchestrator/orchestrator.ts +19 -2
- package/src/resolver-extractor/extractor/define-api-extractor.ts +4 -0
- package/src/resolver-extractor/validator/abstract-resolver-validator.ts +20 -6
- package/src/schema-generator/emitter/code-emitter.ts +26 -1
- package/src/schema-generator/emitter/discriminator-resolve-type-emitter.ts +125 -0
- package/src/schema-generator/generate-schema.ts +100 -13
- package/src/schema-generator/integrator/result-integrator.ts +25 -1
- package/src/schema-generator/resolver-collector/resolver-collector.ts +7 -0
- package/src/shared/constants.ts +15 -1
- package/src/shared/enum-prefix-detector.ts +96 -8
- package/src/shared/inline-object-utils.ts +1 -1
- package/src/shared/type-converter.ts +63 -0
- package/src/type-extractor/converter/graphql-converter.ts +17 -1
- package/src/type-extractor/extractor/field-type-resolver.ts +266 -16
- package/src/type-extractor/extractor/type-extractor.ts +148 -11
- package/src/type-extractor/extractor/type-name-collector.ts +19 -4
- package/src/type-extractor/types/diagnostics.ts +10 -1
- package/src/type-extractor/types/index.ts +2 -1
- package/src/type-extractor/types/ts-type-reference-factory.ts +24 -3
- package/src/type-extractor/types/typescript.ts +6 -2
- package/src/type-extractor/validator/type-validator.ts +6 -1
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import type { ResolvedDiscriminatorFieldsMap } from "../config-loader/index.js";
|
|
2
|
+
import type {
|
|
3
|
+
ExtractedTypeInfo,
|
|
4
|
+
InlineObjectMember,
|
|
5
|
+
InlineObjectProperty,
|
|
6
|
+
InlineObjectPropertyDef,
|
|
7
|
+
TSTypeReference,
|
|
8
|
+
} from "../type-extractor/types/index.js";
|
|
9
|
+
import {
|
|
10
|
+
createInlineObjectType,
|
|
11
|
+
createPrimitiveType,
|
|
12
|
+
} from "../type-extractor/types/ts-type-reference-factory.js";
|
|
13
|
+
import { generateDiscriminatorMemberName } from "./discriminator-naming.js";
|
|
14
|
+
import type {
|
|
15
|
+
InlineUnionMemberInfo,
|
|
16
|
+
InlineUnionWithContext,
|
|
17
|
+
} from "./inline-union-types.js";
|
|
18
|
+
import { generateAutoTypeName } from "./naming-convention.js";
|
|
19
|
+
|
|
20
|
+
interface PropertyContribution {
|
|
21
|
+
readonly property: InlineObjectProperty;
|
|
22
|
+
readonly isNever: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Checks whether a type reference represents an absent/impossible value.
|
|
27
|
+
* This includes explicit `never` types and `undefined` references
|
|
28
|
+
* (from `field?: never` where TypeScript resolves to undefined).
|
|
29
|
+
*/
|
|
30
|
+
function isAbsentType(tsType: TSTypeReference): boolean {
|
|
31
|
+
if (tsType.kind === "never") {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
if (tsType.kind === "reference" && tsType.name === "undefined") {
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Extracts a string literal value from a discriminator field property.
|
|
42
|
+
* Returns null if the property is not a string literal.
|
|
43
|
+
*/
|
|
44
|
+
function getDiscriminatorValue(
|
|
45
|
+
member: InlineObjectMember,
|
|
46
|
+
fieldName: string,
|
|
47
|
+
): string | null {
|
|
48
|
+
for (const prop of member.properties) {
|
|
49
|
+
if (prop.propertyName === fieldName) {
|
|
50
|
+
if (
|
|
51
|
+
prop.propertyType.kind === "stringLiteral" &&
|
|
52
|
+
prop.propertyType.name !== null
|
|
53
|
+
) {
|
|
54
|
+
return prop.propertyType.name;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Checks whether two TSTypeReference values represent the same type
|
|
64
|
+
* (ignoring nullability).
|
|
65
|
+
*/
|
|
66
|
+
function isSameTypeIgnoringNullability(
|
|
67
|
+
a: TSTypeReference,
|
|
68
|
+
b: TSTypeReference,
|
|
69
|
+
): boolean {
|
|
70
|
+
if (a.kind !== b.kind) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
if (a.name !== b.name) {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
if (a.kind === "array" && b.kind === "array") {
|
|
77
|
+
if (a.elementType === null || b.elementType === null) {
|
|
78
|
+
return a.elementType === b.elementType;
|
|
79
|
+
}
|
|
80
|
+
return isSameTypeIgnoringNullability(a.elementType, b.elementType);
|
|
81
|
+
}
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Merges properties from a group of inline object members that share the same
|
|
87
|
+
* discriminator value. Handles partial presence, type widening, and never types.
|
|
88
|
+
*/
|
|
89
|
+
function mergeGroupProperties(
|
|
90
|
+
group: ReadonlyArray<InlineObjectMember>,
|
|
91
|
+
discriminatorFieldNames: ReadonlyArray<string>,
|
|
92
|
+
): ReadonlyArray<InlineObjectProperty> {
|
|
93
|
+
const discriminatorFieldSet = new Set(discriminatorFieldNames);
|
|
94
|
+
|
|
95
|
+
// Collect all property names across the group
|
|
96
|
+
const allPropertyNames = new Set<string>();
|
|
97
|
+
for (const member of group) {
|
|
98
|
+
for (const prop of member.properties) {
|
|
99
|
+
allPropertyNames.add(prop.propertyName);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const mergedProperties: InlineObjectProperty[] = [];
|
|
104
|
+
|
|
105
|
+
for (const propName of allPropertyNames) {
|
|
106
|
+
// Collect contributions from each member
|
|
107
|
+
const contributions: PropertyContribution[] = [];
|
|
108
|
+
for (const member of group) {
|
|
109
|
+
const prop = member.properties.find((p) => p.propertyName === propName);
|
|
110
|
+
if (prop !== undefined) {
|
|
111
|
+
contributions.push({
|
|
112
|
+
property: prop,
|
|
113
|
+
isNever: isAbsentType(prop.propertyType),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Skip properties that are never in ALL members
|
|
119
|
+
const nonNeverContributions = contributions.filter((c) => !c.isNever);
|
|
120
|
+
if (nonNeverContributions.length === 0) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const presentInAllMembers = nonNeverContributions.length === group.length;
|
|
125
|
+
const firstContribution = nonNeverContributions[0]!;
|
|
126
|
+
|
|
127
|
+
// Check if all non-never contributions have the same type
|
|
128
|
+
let allSameType = true;
|
|
129
|
+
for (let i = 1; i < nonNeverContributions.length; i++) {
|
|
130
|
+
if (
|
|
131
|
+
!isSameTypeIgnoringNullability(
|
|
132
|
+
firstContribution.property.propertyType,
|
|
133
|
+
nonNeverContributions[i]!.property.propertyType,
|
|
134
|
+
)
|
|
135
|
+
) {
|
|
136
|
+
allSameType = false;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Discriminator fields: keep original string literal value (all members in a group
|
|
142
|
+
// share the same discriminator value since that's the grouping key)
|
|
143
|
+
if (discriminatorFieldSet.has(propName)) {
|
|
144
|
+
mergedProperties.push({
|
|
145
|
+
propertyName: propName,
|
|
146
|
+
propertyType: firstContribution.property.propertyType,
|
|
147
|
+
description: firstContribution.property.description,
|
|
148
|
+
deprecated: firstContribution.property.deprecated,
|
|
149
|
+
});
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (allSameType) {
|
|
154
|
+
// Same type across all contributing members
|
|
155
|
+
const anyNullable = nonNeverContributions.some(
|
|
156
|
+
(c) => c.property.propertyType.nullable,
|
|
157
|
+
);
|
|
158
|
+
const needsNullable = !presentInAllMembers || anyNullable;
|
|
159
|
+
const baseType = firstContribution.property.propertyType;
|
|
160
|
+
mergedProperties.push({
|
|
161
|
+
propertyName: propName,
|
|
162
|
+
propertyType:
|
|
163
|
+
needsNullable && !baseType.nullable
|
|
164
|
+
? { ...baseType, nullable: true }
|
|
165
|
+
: baseType,
|
|
166
|
+
description: firstContribution.property.description,
|
|
167
|
+
deprecated: firstContribution.property.deprecated,
|
|
168
|
+
});
|
|
169
|
+
} else {
|
|
170
|
+
// Different types → widen to String
|
|
171
|
+
const needsNullable = !presentInAllMembers;
|
|
172
|
+
mergedProperties.push({
|
|
173
|
+
propertyName: propName,
|
|
174
|
+
propertyType: createPrimitiveType({
|
|
175
|
+
name: "string",
|
|
176
|
+
nullable: needsNullable,
|
|
177
|
+
}),
|
|
178
|
+
description: null,
|
|
179
|
+
deprecated: null,
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
return mergedProperties;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export interface FlattenIntersectionMembersParams {
|
|
188
|
+
readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
|
|
189
|
+
readonly discriminatorFields: ResolvedDiscriminatorFieldsMap;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Flattens inline object members of union types that have discriminator field config.
|
|
194
|
+
* Groups members by their discriminator value tuples and merges properties within each group.
|
|
195
|
+
*
|
|
196
|
+
* This resolves the issue where TypeScript distributes intersections over unions,
|
|
197
|
+
* creating many anonymous inline objects that would cause DISCRIMINATOR_DUPLICATE_VALUE_TUPLE
|
|
198
|
+
* errors.
|
|
199
|
+
*/
|
|
200
|
+
export function flattenIntersectionMembers(
|
|
201
|
+
params: FlattenIntersectionMembersParams,
|
|
202
|
+
): ReadonlyArray<ExtractedTypeInfo> {
|
|
203
|
+
const { extractedTypes, discriminatorFields } = params;
|
|
204
|
+
|
|
205
|
+
if (discriminatorFields.size === 0) {
|
|
206
|
+
return extractedTypes;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
return extractedTypes.map((typeInfo) => {
|
|
210
|
+
if (typeInfo.metadata.kind !== "union") {
|
|
211
|
+
return typeInfo;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const fieldNames = discriminatorFields.get(typeInfo.metadata.name);
|
|
215
|
+
if (fieldNames === undefined) {
|
|
216
|
+
return typeInfo;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const inlineObjectMembers = typeInfo.inlineObjectMembers;
|
|
220
|
+
if (inlineObjectMembers === null || inlineObjectMembers.length === 0) {
|
|
221
|
+
return typeInfo;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const primaryFieldName = fieldNames[0];
|
|
225
|
+
if (primaryFieldName === undefined) {
|
|
226
|
+
return typeInfo;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Group members by discriminator value tuple
|
|
230
|
+
const groups = new Map<string, InlineObjectMember[]>();
|
|
231
|
+
for (const member of inlineObjectMembers) {
|
|
232
|
+
const primaryValue = getDiscriminatorValue(member, primaryFieldName);
|
|
233
|
+
if (primaryValue === null) {
|
|
234
|
+
// Cannot group this member; leave as-is
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const secondaryValues = fieldNames
|
|
239
|
+
.slice(1)
|
|
240
|
+
.map((fn) => getDiscriminatorValue(member, fn));
|
|
241
|
+
const tupleKey = JSON.stringify([primaryValue, ...secondaryValues]);
|
|
242
|
+
|
|
243
|
+
let group = groups.get(tupleKey);
|
|
244
|
+
if (group === undefined) {
|
|
245
|
+
group = [];
|
|
246
|
+
groups.set(tupleKey, group);
|
|
247
|
+
}
|
|
248
|
+
group.push(member);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
// If no groups were formed, no flattening needed
|
|
252
|
+
if (groups.size === 0) {
|
|
253
|
+
return typeInfo;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Check if flattening is actually needed (i.e., any group has more than 1 member)
|
|
257
|
+
const needsFlattening = Array.from(groups.values()).some(
|
|
258
|
+
(g) => g.length > 1,
|
|
259
|
+
);
|
|
260
|
+
if (!needsFlattening) {
|
|
261
|
+
return typeInfo;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Flatten each group into a single member
|
|
265
|
+
const flattenedMembers: InlineObjectMember[] = [];
|
|
266
|
+
for (const group of groups.values()) {
|
|
267
|
+
const mergedProperties = mergeGroupProperties(group, [...fieldNames]);
|
|
268
|
+
flattenedMembers.push({ properties: mergedProperties });
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
return {
|
|
272
|
+
...typeInfo,
|
|
273
|
+
inlineObjectMembers: flattenedMembers,
|
|
274
|
+
};
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// --- Inline union member flattening ---
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Extracts a string literal discriminator value from an InlineObjectPropertyDef.
|
|
282
|
+
*/
|
|
283
|
+
function getDiscriminatorValueFromPropertyDef(
|
|
284
|
+
properties: ReadonlyArray<InlineObjectPropertyDef>,
|
|
285
|
+
fieldName: string,
|
|
286
|
+
): string | null {
|
|
287
|
+
for (const prop of properties) {
|
|
288
|
+
if (prop.name === fieldName) {
|
|
289
|
+
if (prop.tsType.kind === "stringLiteral" && prop.tsType.name !== null) {
|
|
290
|
+
return prop.tsType.name;
|
|
291
|
+
}
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
return null;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
interface PropertyDefContribution {
|
|
299
|
+
readonly property: InlineObjectPropertyDef;
|
|
300
|
+
readonly isNever: boolean;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Merges InlineObjectPropertyDef arrays from a group of inline object members.
|
|
305
|
+
*/
|
|
306
|
+
function mergeGroupPropertyDefs(
|
|
307
|
+
groups: ReadonlyArray<ReadonlyArray<InlineObjectPropertyDef>>,
|
|
308
|
+
discriminatorFieldNames: ReadonlyArray<string>,
|
|
309
|
+
): ReadonlyArray<InlineObjectPropertyDef> {
|
|
310
|
+
const discriminatorFieldSet = new Set(discriminatorFieldNames);
|
|
311
|
+
|
|
312
|
+
const allPropertyNames = new Set<string>();
|
|
313
|
+
for (const properties of groups) {
|
|
314
|
+
for (const prop of properties) {
|
|
315
|
+
allPropertyNames.add(prop.name);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const merged: InlineObjectPropertyDef[] = [];
|
|
320
|
+
|
|
321
|
+
for (const propName of allPropertyNames) {
|
|
322
|
+
const contributions: PropertyDefContribution[] = [];
|
|
323
|
+
for (const properties of groups) {
|
|
324
|
+
const prop = properties.find((p) => p.name === propName);
|
|
325
|
+
if (prop !== undefined) {
|
|
326
|
+
contributions.push({
|
|
327
|
+
property: prop,
|
|
328
|
+
isNever: isAbsentType(prop.tsType),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const nonNeverContributions = contributions.filter((c) => !c.isNever);
|
|
334
|
+
if (nonNeverContributions.length === 0) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
const presentInAllMembers = nonNeverContributions.length === groups.length;
|
|
339
|
+
const firstContribution = nonNeverContributions[0]!;
|
|
340
|
+
|
|
341
|
+
let allSameType = true;
|
|
342
|
+
for (let i = 1; i < nonNeverContributions.length; i++) {
|
|
343
|
+
if (
|
|
344
|
+
!isSameTypeIgnoringNullability(
|
|
345
|
+
firstContribution.property.tsType,
|
|
346
|
+
nonNeverContributions[i]!.property.tsType,
|
|
347
|
+
)
|
|
348
|
+
) {
|
|
349
|
+
allSameType = false;
|
|
350
|
+
break;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Discriminator fields: keep original value
|
|
355
|
+
if (discriminatorFieldSet.has(propName)) {
|
|
356
|
+
merged.push(firstContribution.property);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
if (allSameType) {
|
|
361
|
+
const anyNullable = nonNeverContributions.some(
|
|
362
|
+
(c) => c.property.tsType.nullable,
|
|
363
|
+
);
|
|
364
|
+
const anyOptional = nonNeverContributions.some(
|
|
365
|
+
(c) => c.property.optional,
|
|
366
|
+
);
|
|
367
|
+
const needsNullable = !presentInAllMembers || anyNullable || anyOptional;
|
|
368
|
+
const baseType = firstContribution.property.tsType;
|
|
369
|
+
merged.push({
|
|
370
|
+
...firstContribution.property,
|
|
371
|
+
optional: !presentInAllMembers || anyOptional,
|
|
372
|
+
tsType:
|
|
373
|
+
needsNullable && !baseType.nullable
|
|
374
|
+
? { ...baseType, nullable: true }
|
|
375
|
+
: baseType,
|
|
376
|
+
});
|
|
377
|
+
} else {
|
|
378
|
+
// Different types → widen to String
|
|
379
|
+
const needsNullable = !presentInAllMembers;
|
|
380
|
+
merged.push({
|
|
381
|
+
...firstContribution.property,
|
|
382
|
+
optional: !presentInAllMembers,
|
|
383
|
+
tsType: createPrimitiveType({
|
|
384
|
+
name: "string",
|
|
385
|
+
nullable: needsNullable,
|
|
386
|
+
}),
|
|
387
|
+
description: null,
|
|
388
|
+
deprecated: null,
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
return merged;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export interface InlineDiscriminatorResolveType {
|
|
397
|
+
readonly unionTypeName: string;
|
|
398
|
+
readonly fieldNames: ReadonlyArray<string>;
|
|
399
|
+
readonly valueMappings: ReadonlyArray<{
|
|
400
|
+
readonly memberGraphQLTypeName: string;
|
|
401
|
+
readonly values: ReadonlyArray<string | null>;
|
|
402
|
+
}>;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
export interface FlattenInlineUnionMembersParams {
|
|
406
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
407
|
+
readonly discriminatorFields: ResolvedDiscriminatorFieldsMap;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export interface FlattenInlineUnionMembersResult {
|
|
411
|
+
readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
|
|
412
|
+
readonly inlineDiscriminatorResolveTypes: ReadonlyArray<InlineDiscriminatorResolveType>;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/**
|
|
416
|
+
* Pre-processes inline unions that match discriminatorFields config.
|
|
417
|
+
* Groups inline object members by discriminator value and merges them,
|
|
418
|
+
* producing flattened members with inlineObjectHintName set for naming.
|
|
419
|
+
* Also returns discriminator resolveType info for generating __resolveType functions.
|
|
420
|
+
*
|
|
421
|
+
* This handles the case where TypeScript distributes intersections over unions
|
|
422
|
+
* within field types (e.g., `parts: UIMessagePart<...>[]`), creating many
|
|
423
|
+
* anonymous inline objects that would otherwise cause UNNAMEABLE_UNION_MEMBER errors.
|
|
424
|
+
*/
|
|
425
|
+
export function flattenInlineUnionMembers(
|
|
426
|
+
params: FlattenInlineUnionMembersParams,
|
|
427
|
+
): FlattenInlineUnionMembersResult {
|
|
428
|
+
const { inlineUnions, discriminatorFields } = params;
|
|
429
|
+
|
|
430
|
+
if (discriminatorFields.size === 0) {
|
|
431
|
+
return { inlineUnions, inlineDiscriminatorResolveTypes: [] };
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const inlineDiscriminatorResolveTypes: InlineDiscriminatorResolveType[] = [];
|
|
435
|
+
const resultUnions: InlineUnionWithContext[] = [];
|
|
436
|
+
|
|
437
|
+
for (const inlineUnion of inlineUnions) {
|
|
438
|
+
const unionTypeName = generateAutoTypeName(inlineUnion.context);
|
|
439
|
+
const fieldNames = discriminatorFields.get(unionTypeName);
|
|
440
|
+
if (fieldNames === undefined) {
|
|
441
|
+
resultUnions.push(inlineUnion);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const primaryFieldName = fieldNames[0];
|
|
446
|
+
if (primaryFieldName === undefined) {
|
|
447
|
+
resultUnions.push(inlineUnion);
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
// Only process inline object members
|
|
452
|
+
const inlineObjectMembers: Array<{
|
|
453
|
+
member: InlineUnionMemberInfo;
|
|
454
|
+
properties: ReadonlyArray<InlineObjectPropertyDef>;
|
|
455
|
+
}> = [];
|
|
456
|
+
const nonInlineMembers: InlineUnionMemberInfo[] = [];
|
|
457
|
+
|
|
458
|
+
for (const member of inlineUnion.members) {
|
|
459
|
+
if (
|
|
460
|
+
member.memberType.kind === "inlineObject" &&
|
|
461
|
+
member.memberType.inlineObjectProperties
|
|
462
|
+
) {
|
|
463
|
+
inlineObjectMembers.push({
|
|
464
|
+
member,
|
|
465
|
+
properties: member.memberType.inlineObjectProperties,
|
|
466
|
+
});
|
|
467
|
+
} else {
|
|
468
|
+
nonInlineMembers.push(member);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
if (inlineObjectMembers.length === 0) {
|
|
473
|
+
resultUnions.push(inlineUnion);
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// Group by discriminator value tuple
|
|
478
|
+
const groups = new Map<
|
|
479
|
+
string,
|
|
480
|
+
Array<ReadonlyArray<InlineObjectPropertyDef>>
|
|
481
|
+
>();
|
|
482
|
+
const groupValues = new Map<string, ReadonlyArray<string | null>>();
|
|
483
|
+
|
|
484
|
+
for (const { properties } of inlineObjectMembers) {
|
|
485
|
+
const primaryValue = getDiscriminatorValueFromPropertyDef(
|
|
486
|
+
properties,
|
|
487
|
+
primaryFieldName,
|
|
488
|
+
);
|
|
489
|
+
if (primaryValue === null) {
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
const secondaryValues = fieldNames
|
|
494
|
+
.slice(1)
|
|
495
|
+
.map((fn) => getDiscriminatorValueFromPropertyDef(properties, fn));
|
|
496
|
+
const tupleKey = JSON.stringify([primaryValue, ...secondaryValues]);
|
|
497
|
+
|
|
498
|
+
let group = groups.get(tupleKey);
|
|
499
|
+
if (group === undefined) {
|
|
500
|
+
group = [];
|
|
501
|
+
groups.set(tupleKey, group);
|
|
502
|
+
groupValues.set(tupleKey, [primaryValue, ...secondaryValues]);
|
|
503
|
+
}
|
|
504
|
+
group.push(properties);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
if (groups.size === 0) {
|
|
508
|
+
resultUnions.push(inlineUnion);
|
|
509
|
+
continue;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// Flatten each group into a single member with hint name
|
|
513
|
+
const flattenedMembers: InlineUnionMemberInfo[] = [];
|
|
514
|
+
const valueMappings: InlineDiscriminatorResolveType["valueMappings"][number][] =
|
|
515
|
+
[];
|
|
516
|
+
|
|
517
|
+
for (const [tupleKey, group] of groups) {
|
|
518
|
+
const values = groupValues.get(tupleKey)!;
|
|
519
|
+
const mergedProperties = mergeGroupPropertyDefs(group, [...fieldNames]);
|
|
520
|
+
const hintName = generateDiscriminatorMemberName({
|
|
521
|
+
unionTypeName,
|
|
522
|
+
values,
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
flattenedMembers.push({
|
|
526
|
+
memberType: createInlineObjectType({
|
|
527
|
+
properties: mergedProperties,
|
|
528
|
+
description: null,
|
|
529
|
+
deprecated: null,
|
|
530
|
+
hintName,
|
|
531
|
+
}),
|
|
532
|
+
needsAutoGeneration: true,
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
valueMappings.push({
|
|
536
|
+
memberGraphQLTypeName: hintName,
|
|
537
|
+
values,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
resultUnions.push({
|
|
542
|
+
...inlineUnion,
|
|
543
|
+
members: [...nonInlineMembers, ...flattenedMembers],
|
|
544
|
+
});
|
|
545
|
+
|
|
546
|
+
inlineDiscriminatorResolveTypes.push({
|
|
547
|
+
unionTypeName,
|
|
548
|
+
fieldNames: [...fieldNames],
|
|
549
|
+
valueMappings,
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
return { inlineUnions: resultUnions, inlineDiscriminatorResolveTypes };
|
|
554
|
+
}
|