@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.
Files changed (194) hide show
  1. package/dist/auto-type-generator/auto-type-generator.d.ts +7 -0
  2. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  3. package/dist/auto-type-generator/auto-type-generator.js +375 -55
  4. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  5. package/dist/auto-type-generator/discriminator-field-validator.d.ts +26 -0
  6. package/dist/auto-type-generator/discriminator-field-validator.d.ts.map +1 -0
  7. package/dist/auto-type-generator/discriminator-field-validator.js +242 -0
  8. package/dist/auto-type-generator/discriminator-field-validator.js.map +1 -0
  9. package/dist/auto-type-generator/discriminator-naming.d.ts +11 -0
  10. package/dist/auto-type-generator/discriminator-naming.d.ts.map +1 -0
  11. package/dist/auto-type-generator/discriminator-naming.js +15 -0
  12. package/dist/auto-type-generator/discriminator-naming.js.map +1 -0
  13. package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts +44 -0
  14. package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts.map +1 -0
  15. package/dist/auto-type-generator/discriminator-resolve-type-generator.js +77 -0
  16. package/dist/auto-type-generator/discriminator-resolve-type-generator.js.map +1 -0
  17. package/dist/auto-type-generator/index.d.ts +3 -0
  18. package/dist/auto-type-generator/index.d.ts.map +1 -1
  19. package/dist/auto-type-generator/index.js +3 -0
  20. package/dist/auto-type-generator/index.js.map +1 -1
  21. package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
  22. package/dist/auto-type-generator/inline-enum-collector.js +14 -7
  23. package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
  24. package/dist/auto-type-generator/inline-object-converter.d.ts +12 -0
  25. package/dist/auto-type-generator/inline-object-converter.d.ts.map +1 -0
  26. package/dist/auto-type-generator/inline-object-converter.js +72 -0
  27. package/dist/auto-type-generator/inline-object-converter.js.map +1 -0
  28. package/dist/auto-type-generator/inline-object-traverser.d.ts +2 -1
  29. package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -1
  30. package/dist/auto-type-generator/inline-object-traverser.js +22 -4
  31. package/dist/auto-type-generator/inline-object-traverser.js.map +1 -1
  32. package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -1
  33. package/dist/auto-type-generator/inline-union-collector.js +20 -6
  34. package/dist/auto-type-generator/inline-union-collector.js.map +1 -1
  35. package/dist/auto-type-generator/inline-union-types.d.ts +2 -0
  36. package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -1
  37. package/dist/auto-type-generator/inline-union-validator.js +3 -3
  38. package/dist/auto-type-generator/inline-union-validator.js.map +1 -1
  39. package/dist/auto-type-generator/intersection-flattener.d.ts +44 -0
  40. package/dist/auto-type-generator/intersection-flattener.d.ts.map +1 -0
  41. package/dist/auto-type-generator/intersection-flattener.js +398 -0
  42. package/dist/auto-type-generator/intersection-flattener.js.map +1 -0
  43. package/dist/auto-type-generator/naming-convention.d.ts +21 -0
  44. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
  45. package/dist/auto-type-generator/naming-convention.js +145 -1
  46. package/dist/auto-type-generator/naming-convention.js.map +1 -1
  47. package/dist/auto-type-generator/typename-extractor.d.ts +2 -0
  48. package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -1
  49. package/dist/auto-type-generator/typename-extractor.js +11 -3
  50. package/dist/auto-type-generator/typename-extractor.js.map +1 -1
  51. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +2 -0
  52. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -1
  53. package/dist/auto-type-generator/typename-resolve-type-generator.js +12 -84
  54. package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -1
  55. package/dist/auto-type-generator/typename-types.d.ts +4 -0
  56. package/dist/auto-type-generator/typename-types.d.ts.map +1 -1
  57. package/dist/auto-type-generator/typename-types.js +6 -0
  58. package/dist/auto-type-generator/typename-types.js.map +1 -1
  59. package/dist/auto-type-generator/typename-validator.d.ts.map +1 -1
  60. package/dist/auto-type-generator/typename-validator.js +4 -3
  61. package/dist/auto-type-generator/typename-validator.js.map +1 -1
  62. package/dist/commands/gen.d.ts.map +1 -1
  63. package/dist/commands/gen.js +2 -1
  64. package/dist/commands/gen.js.map +1 -1
  65. package/dist/config/types.d.ts +7 -0
  66. package/dist/config/types.d.ts.map +1 -1
  67. package/dist/config-loader/index.d.ts +1 -1
  68. package/dist/config-loader/index.d.ts.map +1 -1
  69. package/dist/config-loader/index.js.map +1 -1
  70. package/dist/config-loader/loader.d.ts +6 -0
  71. package/dist/config-loader/loader.d.ts.map +1 -1
  72. package/dist/config-loader/loader.js +1 -0
  73. package/dist/config-loader/loader.js.map +1 -1
  74. package/dist/config-loader/validator.d.ts.map +1 -1
  75. package/dist/config-loader/validator.js +84 -1
  76. package/dist/config-loader/validator.js.map +1 -1
  77. package/dist/gen-orchestrator/orchestrator.d.ts +2 -1
  78. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  79. package/dist/gen-orchestrator/orchestrator.js +15 -2
  80. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  81. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  82. package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -0
  83. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  84. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +2 -0
  85. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
  86. package/dist/resolver-extractor/validator/abstract-resolver-validator.js +16 -3
  87. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
  88. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  89. package/dist/schema-generator/emitter/code-emitter.js +13 -1
  90. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  91. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts +18 -0
  92. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts.map +1 -0
  93. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js +89 -0
  94. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js.map +1 -0
  95. package/dist/schema-generator/generate-schema.d.ts +2 -0
  96. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  97. package/dist/schema-generator/generate-schema.js +69 -10
  98. package/dist/schema-generator/generate-schema.js.map +1 -1
  99. package/dist/schema-generator/integrator/result-integrator.d.ts +4 -0
  100. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  101. package/dist/schema-generator/integrator/result-integrator.js +18 -2
  102. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  103. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
  104. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
  105. package/dist/schema-generator/resolver-collector/resolver-collector.js +4 -0
  106. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
  107. package/dist/shared/constants.d.ts.map +1 -1
  108. package/dist/shared/constants.js +14 -1
  109. package/dist/shared/constants.js.map +1 -1
  110. package/dist/shared/enum-prefix-detector.d.ts.map +1 -1
  111. package/dist/shared/enum-prefix-detector.js +78 -8
  112. package/dist/shared/enum-prefix-detector.js.map +1 -1
  113. package/dist/shared/inline-object-utils.js +1 -1
  114. package/dist/shared/inline-object-utils.js.map +1 -1
  115. package/dist/shared/type-converter.d.ts.map +1 -1
  116. package/dist/shared/type-converter.js +55 -0
  117. package/dist/shared/type-converter.js.map +1 -1
  118. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  119. package/dist/type-extractor/converter/graphql-converter.js +11 -1
  120. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  121. package/dist/type-extractor/extractor/field-type-resolver.d.ts +18 -0
  122. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  123. package/dist/type-extractor/extractor/field-type-resolver.js +218 -16
  124. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  125. package/dist/type-extractor/extractor/type-extractor.d.ts +1 -0
  126. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  127. package/dist/type-extractor/extractor/type-extractor.js +127 -14
  128. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  129. package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -1
  130. package/dist/type-extractor/extractor/type-name-collector.js +19 -4
  131. package/dist/type-extractor/extractor/type-name-collector.js.map +1 -1
  132. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  133. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  134. package/dist/type-extractor/types/index.d.ts +1 -1
  135. package/dist/type-extractor/types/index.d.ts.map +1 -1
  136. package/dist/type-extractor/types/index.js +1 -1
  137. package/dist/type-extractor/types/index.js.map +1 -1
  138. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +7 -1
  139. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
  140. package/dist/type-extractor/types/ts-type-reference-factory.js +18 -3
  141. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
  142. package/dist/type-extractor/types/typescript.d.ts +3 -1
  143. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  144. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  145. package/dist/type-extractor/validator/type-validator.js +6 -1
  146. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  147. package/docs/configuration.md +19 -0
  148. package/docs/index.md +1 -0
  149. package/docs/integration/ai-sdk.md +189 -0
  150. package/docs/schema/unions.md +117 -0
  151. package/package.json +2 -2
  152. package/src/auto-type-generator/auto-type-generator.ts +576 -58
  153. package/src/auto-type-generator/discriminator-field-validator.ts +368 -0
  154. package/src/auto-type-generator/discriminator-naming.ts +24 -0
  155. package/src/auto-type-generator/discriminator-resolve-type-generator.ts +136 -0
  156. package/src/auto-type-generator/index.ts +17 -0
  157. package/src/auto-type-generator/inline-enum-collector.ts +19 -4
  158. package/src/auto-type-generator/inline-object-converter.ts +100 -0
  159. package/src/auto-type-generator/inline-object-traverser.ts +33 -7
  160. package/src/auto-type-generator/inline-union-collector.ts +26 -4
  161. package/src/auto-type-generator/inline-union-types.ts +2 -0
  162. package/src/auto-type-generator/inline-union-validator.ts +3 -3
  163. package/src/auto-type-generator/intersection-flattener.ts +554 -0
  164. package/src/auto-type-generator/naming-convention.ts +205 -1
  165. package/src/auto-type-generator/typename-extractor.ts +17 -3
  166. package/src/auto-type-generator/typename-resolve-type-generator.ts +19 -108
  167. package/src/auto-type-generator/typename-types.ts +7 -0
  168. package/src/auto-type-generator/typename-validator.ts +4 -3
  169. package/src/commands/gen.ts +9 -2
  170. package/src/config/types.ts +10 -0
  171. package/src/config-loader/index.ts +1 -0
  172. package/src/config-loader/loader.ts +11 -0
  173. package/src/config-loader/validator.ts +100 -1
  174. package/src/gen-orchestrator/orchestrator.ts +19 -2
  175. package/src/resolver-extractor/extractor/define-api-extractor.ts +4 -0
  176. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +20 -6
  177. package/src/schema-generator/emitter/code-emitter.ts +26 -1
  178. package/src/schema-generator/emitter/discriminator-resolve-type-emitter.ts +125 -0
  179. package/src/schema-generator/generate-schema.ts +100 -13
  180. package/src/schema-generator/integrator/result-integrator.ts +25 -1
  181. package/src/schema-generator/resolver-collector/resolver-collector.ts +7 -0
  182. package/src/shared/constants.ts +15 -1
  183. package/src/shared/enum-prefix-detector.ts +96 -8
  184. package/src/shared/inline-object-utils.ts +1 -1
  185. package/src/shared/type-converter.ts +63 -0
  186. package/src/type-extractor/converter/graphql-converter.ts +17 -1
  187. package/src/type-extractor/extractor/field-type-resolver.ts +266 -16
  188. package/src/type-extractor/extractor/type-extractor.ts +148 -11
  189. package/src/type-extractor/extractor/type-name-collector.ts +19 -4
  190. package/src/type-extractor/types/diagnostics.ts +10 -1
  191. package/src/type-extractor/types/index.ts +2 -1
  192. package/src/type-extractor/types/ts-type-reference-factory.ts +24 -3
  193. package/src/type-extractor/types/typescript.ts +6 -2
  194. 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
+ }