@gqlkit-ts/cli 0.2.0 → 0.4.0

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 (235) hide show
  1. package/README.md +143 -0
  2. package/dist/auto-type-generator/auto-type-generator.d.ts +10 -4
  3. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  4. package/dist/auto-type-generator/auto-type-generator.js +656 -146
  5. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  6. package/dist/auto-type-generator/index.d.ts +8 -1
  7. package/dist/auto-type-generator/index.d.ts.map +1 -1
  8. package/dist/auto-type-generator/index.js +3 -0
  9. package/dist/auto-type-generator/index.js.map +1 -1
  10. package/dist/auto-type-generator/inline-enum-collector.d.ts +13 -5
  11. package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
  12. package/dist/auto-type-generator/inline-enum-collector.js +107 -71
  13. package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
  14. package/dist/auto-type-generator/inline-object-traverser.d.ts +20 -0
  15. package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -0
  16. package/dist/auto-type-generator/inline-object-traverser.js +22 -0
  17. package/dist/auto-type-generator/inline-object-traverser.js.map +1 -0
  18. package/dist/auto-type-generator/inline-union-collector.d.ts +29 -0
  19. package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -0
  20. package/dist/auto-type-generator/inline-union-collector.js +216 -0
  21. package/dist/auto-type-generator/inline-union-collector.js.map +1 -0
  22. package/dist/auto-type-generator/inline-union-types.d.ts +29 -0
  23. package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -0
  24. package/dist/auto-type-generator/inline-union-types.js +2 -0
  25. package/dist/auto-type-generator/inline-union-types.js.map +1 -0
  26. package/dist/auto-type-generator/inline-union-validator.d.ts +76 -0
  27. package/dist/auto-type-generator/inline-union-validator.d.ts.map +1 -0
  28. package/dist/auto-type-generator/inline-union-validator.js +329 -0
  29. package/dist/auto-type-generator/inline-union-validator.js.map +1 -0
  30. package/dist/auto-type-generator/naming-convention.d.ts +18 -1
  31. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
  32. package/dist/auto-type-generator/naming-convention.js +16 -0
  33. package/dist/auto-type-generator/naming-convention.js.map +1 -1
  34. package/dist/auto-type-generator/resolve-type-generator.d.ts +20 -0
  35. package/dist/auto-type-generator/resolve-type-generator.d.ts.map +1 -0
  36. package/dist/auto-type-generator/resolve-type-generator.js +2 -0
  37. package/dist/auto-type-generator/resolve-type-generator.js.map +1 -0
  38. package/dist/auto-type-generator/resolver-field-iterator.d.ts +13 -0
  39. package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -0
  40. package/dist/auto-type-generator/resolver-field-iterator.js +22 -0
  41. package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -0
  42. package/dist/auto-type-generator/typename-extractor.d.ts +26 -0
  43. package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -0
  44. package/dist/auto-type-generator/typename-extractor.js +142 -0
  45. package/dist/auto-type-generator/typename-extractor.js.map +1 -0
  46. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +35 -0
  47. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -0
  48. package/dist/auto-type-generator/typename-resolve-type-generator.js +177 -0
  49. package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -0
  50. package/dist/auto-type-generator/typename-types.d.ts +43 -0
  51. package/dist/auto-type-generator/typename-types.d.ts.map +1 -0
  52. package/dist/auto-type-generator/typename-types.js +37 -0
  53. package/dist/auto-type-generator/typename-types.js.map +1 -0
  54. package/dist/auto-type-generator/typename-validator.d.ts +37 -0
  55. package/dist/auto-type-generator/typename-validator.d.ts.map +1 -0
  56. package/dist/auto-type-generator/typename-validator.js +206 -0
  57. package/dist/auto-type-generator/typename-validator.js.map +1 -0
  58. package/dist/cli.js +2 -0
  59. package/dist/cli.js.map +1 -1
  60. package/dist/commands/docs.d.ts +51 -0
  61. package/dist/commands/docs.d.ts.map +1 -0
  62. package/dist/commands/docs.js +154 -0
  63. package/dist/commands/docs.js.map +1 -0
  64. package/dist/config/types.d.ts +13 -0
  65. package/dist/config/types.d.ts.map +1 -1
  66. package/dist/config-loader/loader.d.ts +3 -0
  67. package/dist/config-loader/loader.d.ts.map +1 -1
  68. package/dist/config-loader/loader.js +1 -0
  69. package/dist/config-loader/loader.js.map +1 -1
  70. package/dist/config-loader/validator.d.ts.map +1 -1
  71. package/dist/config-loader/validator.js +23 -0
  72. package/dist/config-loader/validator.js.map +1 -1
  73. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  74. package/dist/gen-orchestrator/orchestrator.js +32 -12
  75. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  76. package/dist/resolver-extractor/extract-resolvers.d.ts +19 -1
  77. package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
  78. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +5 -0
  79. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  80. package/dist/resolver-extractor/extractor/define-api-extractor.js +18 -65
  81. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  82. package/dist/resolver-extractor/index.d.ts +0 -1
  83. package/dist/resolver-extractor/index.d.ts.map +1 -1
  84. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +1 -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 +9 -5
  87. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
  88. package/dist/schema-generator/builder/ast-builder.d.ts +2 -2
  89. package/dist/schema-generator/builder/ast-builder.d.ts.map +1 -1
  90. package/dist/schema-generator/builder/ast-builder.js +12 -34
  91. package/dist/schema-generator/builder/ast-builder.js.map +1 -1
  92. package/dist/schema-generator/emitter/code-emitter.d.ts +3 -1
  93. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  94. package/dist/schema-generator/emitter/code-emitter.js +42 -12
  95. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  96. package/dist/schema-generator/emitter/sdl-emitter.d.ts +0 -4
  97. package/dist/schema-generator/emitter/sdl-emitter.d.ts.map +1 -1
  98. package/dist/schema-generator/emitter/sdl-emitter.js +0 -4
  99. package/dist/schema-generator/emitter/sdl-emitter.js.map +1 -1
  100. package/dist/schema-generator/generate-schema.d.ts +3 -0
  101. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  102. package/dist/schema-generator/generate-schema.js +83 -5
  103. package/dist/schema-generator/generate-schema.js.map +1 -1
  104. package/dist/schema-generator/integrator/result-integrator.d.ts +19 -9
  105. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  106. package/dist/schema-generator/integrator/result-integrator.js +60 -44
  107. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  108. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
  109. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
  110. package/dist/schema-generator/resolver-collector/resolver-collector.js +22 -0
  111. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
  112. package/dist/shared/branded-type-detector.d.ts +43 -0
  113. package/dist/shared/branded-type-detector.d.ts.map +1 -0
  114. package/dist/shared/branded-type-detector.js +146 -0
  115. package/dist/shared/branded-type-detector.js.map +1 -0
  116. package/dist/shared/enum-prefix-detector.d.ts +63 -0
  117. package/dist/shared/enum-prefix-detector.d.ts.map +1 -0
  118. package/dist/shared/enum-prefix-detector.js +80 -0
  119. package/dist/shared/enum-prefix-detector.js.map +1 -0
  120. package/dist/shared/ignore-fields-detector.d.ts +26 -0
  121. package/dist/shared/ignore-fields-detector.d.ts.map +1 -0
  122. package/dist/shared/ignore-fields-detector.js +83 -0
  123. package/dist/shared/ignore-fields-detector.js.map +1 -0
  124. package/dist/shared/ignore-fields-validator.d.ts +29 -0
  125. package/dist/shared/ignore-fields-validator.d.ts.map +1 -0
  126. package/dist/shared/ignore-fields-validator.js +43 -0
  127. package/dist/shared/ignore-fields-validator.js.map +1 -0
  128. package/dist/shared/index.d.ts +2 -0
  129. package/dist/shared/index.d.ts.map +1 -1
  130. package/dist/shared/index.js.map +1 -1
  131. package/dist/shared/source-location.d.ts +5 -0
  132. package/dist/shared/source-location.d.ts.map +1 -1
  133. package/dist/shared/source-location.js +7 -0
  134. package/dist/shared/source-location.js.map +1 -1
  135. package/dist/shared/string-utils.d.ts +2 -0
  136. package/dist/shared/string-utils.d.ts.map +1 -0
  137. package/dist/shared/string-utils.js +8 -0
  138. package/dist/shared/string-utils.js.map +1 -0
  139. package/dist/type-extractor/converter/field-eligibility.d.ts +8 -6
  140. package/dist/type-extractor/converter/field-eligibility.d.ts.map +1 -1
  141. package/dist/type-extractor/converter/field-eligibility.js +7 -28
  142. package/dist/type-extractor/converter/field-eligibility.js.map +1 -1
  143. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  144. package/dist/type-extractor/converter/graphql-converter.js +27 -18
  145. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  146. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  147. package/dist/type-extractor/extractor/field-type-resolver.js +81 -7
  148. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  149. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  150. package/dist/type-extractor/extractor/type-extractor.js +88 -23
  151. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  152. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  153. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  154. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +10 -2
  155. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
  156. package/dist/type-extractor/types/ts-type-reference-factory.js +8 -2
  157. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
  158. package/dist/type-extractor/types/typescript.d.ts +4 -0
  159. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  160. package/dist/type-extractor/validator/type-validator.d.ts +1 -1
  161. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  162. package/dist/type-extractor/validator/type-validator.js +2 -10
  163. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  164. package/docs/coding-agents.md +64 -0
  165. package/docs/configuration.md +15 -20
  166. package/docs/getting-started.md +15 -12
  167. package/docs/index.md +36 -22
  168. package/docs/integration/apollo.md +8 -40
  169. package/docs/integration/drizzle.md +6 -10
  170. package/docs/integration/prisma.md +196 -0
  171. package/docs/integration/yoga.md +8 -40
  172. package/docs/schema/abstract-resolvers.md +117 -0
  173. package/docs/schema/directives.md +5 -0
  174. package/docs/schema/documentation.md +5 -0
  175. package/docs/schema/enums.md +99 -0
  176. package/docs/schema/fields.md +64 -0
  177. package/docs/schema/index.md +21 -0
  178. package/docs/schema/inputs.md +115 -15
  179. package/docs/schema/interfaces.md +31 -1
  180. package/docs/schema/objects.md +40 -0
  181. package/docs/schema/queries-mutations.md +136 -22
  182. package/docs/schema/scalars.md +5 -0
  183. package/docs/schema/unions.md +208 -1
  184. package/docs/what-is-gqlkit.md +13 -8
  185. package/package.json +6 -4
  186. package/src/auto-type-generator/auto-type-generator.ts +969 -227
  187. package/src/auto-type-generator/index.ts +42 -0
  188. package/src/auto-type-generator/inline-enum-collector.ts +187 -139
  189. package/src/auto-type-generator/inline-object-traverser.ts +49 -0
  190. package/src/auto-type-generator/inline-union-collector.ts +402 -0
  191. package/src/auto-type-generator/inline-union-types.ts +33 -0
  192. package/src/auto-type-generator/inline-union-validator.ts +482 -0
  193. package/src/auto-type-generator/naming-convention.ts +38 -1
  194. package/src/auto-type-generator/resolve-type-generator.ts +21 -0
  195. package/src/auto-type-generator/resolver-field-iterator.ts +39 -0
  196. package/src/auto-type-generator/typename-extractor.ts +230 -0
  197. package/src/auto-type-generator/typename-resolve-type-generator.ts +281 -0
  198. package/src/auto-type-generator/typename-types.ts +66 -0
  199. package/src/auto-type-generator/typename-validator.ts +326 -0
  200. package/src/cli.ts +2 -0
  201. package/src/commands/docs.ts +211 -0
  202. package/src/config/types.ts +15 -0
  203. package/src/config-loader/loader.ts +4 -0
  204. package/src/config-loader/validator.ts +33 -0
  205. package/src/gen-orchestrator/orchestrator.ts +50 -17
  206. package/src/resolver-extractor/extract-resolvers.ts +19 -0
  207. package/src/resolver-extractor/extractor/define-api-extractor.ts +28 -94
  208. package/src/resolver-extractor/index.ts +0 -6
  209. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +16 -8
  210. package/src/schema-generator/builder/ast-builder.ts +52 -81
  211. package/src/schema-generator/emitter/code-emitter.ts +82 -11
  212. package/src/schema-generator/emitter/sdl-emitter.ts +0 -4
  213. package/src/schema-generator/generate-schema.ts +109 -14
  214. package/src/schema-generator/integrator/result-integrator.ts +91 -63
  215. package/src/schema-generator/resolver-collector/resolver-collector.ts +34 -0
  216. package/src/shared/branded-type-detector.ts +182 -0
  217. package/src/shared/enum-prefix-detector.ts +99 -0
  218. package/src/shared/ignore-fields-detector.ts +109 -0
  219. package/src/shared/ignore-fields-validator.ts +66 -0
  220. package/src/shared/index.ts +2 -0
  221. package/src/shared/source-location.ts +11 -0
  222. package/src/shared/string-utils.ts +7 -0
  223. package/src/type-extractor/converter/field-eligibility.ts +13 -29
  224. package/src/type-extractor/converter/graphql-converter.ts +37 -23
  225. package/src/type-extractor/extractor/field-type-resolver.ts +97 -7
  226. package/src/type-extractor/extractor/type-extractor.ts +103 -26
  227. package/src/type-extractor/types/diagnostics.ts +13 -2
  228. package/src/type-extractor/types/ts-type-reference-factory.ts +18 -5
  229. package/src/type-extractor/types/typescript.ts +4 -0
  230. package/src/type-extractor/validator/type-validator.ts +2 -15
  231. package/dist/resolver-extractor/validator/only-validator.d.ts +0 -61
  232. package/dist/resolver-extractor/validator/only-validator.d.ts.map +0 -1
  233. package/dist/resolver-extractor/validator/only-validator.js +0 -76
  234. package/dist/resolver-extractor/validator/only-validator.js.map +0 -1
  235. package/src/resolver-extractor/validator/only-validator.ts +0 -158
@@ -7,12 +7,15 @@ import type {
7
7
  DirectiveArgumentValue,
8
8
  DirectiveInfo,
9
9
  } from "../shared/directive-detector.js";
10
+ import {
11
+ detectEnumPrefix,
12
+ stripEnumPrefix,
13
+ } from "../shared/enum-prefix-detector.js";
14
+ import { getSourceLocationOrDefault } from "../shared/source-location.js";
15
+ import { toScreamingSnakeCase } from "../shared/string-utils.js";
10
16
  import type { DeprecationInfo } from "../shared/tsdoc-parser.js";
11
17
  import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
12
- import {
13
- isEligibleAsInputObjectField,
14
- isEligibleAsObjectField,
15
- } from "../type-extractor/converter/field-eligibility.js";
18
+ import { isEligibleField } from "../type-extractor/converter/field-eligibility.js";
16
19
  import {
17
20
  createReferenceType,
18
21
  type Diagnostic,
@@ -24,15 +27,38 @@ import {
24
27
  type SourceLocation,
25
28
  } from "../type-extractor/types/index.js";
26
29
  import {
30
+ collectInlineEnumsFromPayloads,
27
31
  collectInlineEnumsFromResolvers,
28
32
  collectInlineEnumsFromTypes,
29
33
  type InlineEnumWithContext,
30
34
  } from "./inline-enum-collector.js";
35
+ import {
36
+ collectInlineUnionsFromPayloads,
37
+ collectInlineUnionsFromResolvers,
38
+ collectInlineUnionsFromTypes,
39
+ type InlineUnionWithContext,
40
+ } from "./inline-union-collector.js";
41
+ import type { InlineUnionMemberInfo } from "./inline-union-types.js";
42
+ import {
43
+ type ValidatedTypenameInfo,
44
+ validateOneOfMembers,
45
+ validateUnionMembers,
46
+ validateUnionMemberTypenames,
47
+ } from "./inline-union-validator.js";
31
48
  import {
32
49
  type AutoTypeNameContext,
33
50
  buildFieldContext,
34
51
  generateAutoTypeName,
52
+ isInputTypeName,
35
53
  } from "./naming-convention.js";
54
+ import type { ResolveTypeFieldPattern } from "./resolve-type-generator.js";
55
+ import { forEachResolverField } from "./resolver-field-iterator.js";
56
+ import {
57
+ createFieldNameSet,
58
+ findTypenameProperty,
59
+ type TypenameFieldInfo,
60
+ type TypenameFieldName,
61
+ } from "./typename-types.js";
36
62
 
37
63
  /**
38
64
  * Information about where an auto-generated type was generated from.
@@ -40,7 +66,11 @@ import {
40
66
  export interface GeneratedFromInfo {
41
67
  readonly parentTypeName: string | null;
42
68
  readonly fieldPath: ReadonlyArray<string>;
43
- readonly context: "typeField" | "inputField" | "resolverArg";
69
+ readonly context:
70
+ | "typeField"
71
+ | "inputField"
72
+ | "resolverArg"
73
+ | "resolverPayload";
44
74
  }
45
75
 
46
76
  /**
@@ -72,21 +102,31 @@ export interface AutoGeneratedEnumValue {
72
102
  */
73
103
  export interface AutoGeneratedType {
74
104
  readonly name: string;
75
- readonly kind: "Object" | "InputObject" | "Enum";
76
- /** Fields for Object/InputObject kinds (null for Enum) */
105
+ readonly kind:
106
+ | "Object"
107
+ | "InputObject"
108
+ | "Enum"
109
+ | "Union"
110
+ | "OneOfInputObject";
111
+ /** Fields for Object/InputObject/OneOfInputObject kinds (null for Enum/Union) */
77
112
  readonly fields: ReadonlyArray<AutoGeneratedField> | null;
78
- /** Enum values for Enum kind (null for Object/InputObject) */
113
+ /** Enum values for Enum kind (null for Object/InputObject/Union/OneOfInputObject) */
79
114
  readonly enumValues: ReadonlyArray<AutoGeneratedEnumValue> | null;
115
+ /** Union members for Union kind (null for Object/InputObject/Enum/OneOfInputObject) */
116
+ readonly unionMembers: ReadonlyArray<string> | null;
80
117
  /** True if enum needs value mapping (at least one value converted) */
81
118
  readonly needsStringEnumMapping: boolean;
82
119
  readonly sourceLocation: SourceLocation;
83
120
  readonly generatedFrom: GeneratedFromInfo;
84
121
  readonly description: string | null;
122
+ /** For Union types from resolverPayload context: the field pattern for resolveType */
123
+ readonly resolveTypeFieldPattern: ResolveTypeFieldPattern | null;
85
124
  }
86
125
 
87
126
  export interface AutoTypeGeneratorInput {
88
127
  readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
89
128
  readonly resolversResult: ExtractResolversResult;
129
+ readonly knownTypeNames: ReadonlySet<string>;
90
130
  }
91
131
 
92
132
  export interface AutoTypeGeneratorResult {
@@ -101,10 +141,70 @@ interface InlineObjectWithContext {
101
141
  readonly context: AutoTypeNameContext;
102
142
  readonly sourceLocation: SourceLocation;
103
143
  readonly nullable: boolean;
144
+ /** TSDoc description from the inline object type alias (Requirement 7.2) */
145
+ readonly description: string | null;
146
+ /** @deprecated tag from the inline object type alias (Requirement 7.3) */
147
+ readonly deprecated: DeprecationInfo | null;
104
148
  }
105
149
 
106
- function isInputTypeName(name: string): boolean {
107
- return name.endsWith("Input");
150
+ type ContextBuilderFn = (
151
+ nestedPath: ReadonlyArray<string>,
152
+ ) => AutoTypeNameContext;
153
+
154
+ interface ExtractNestedInlineObjectsParams {
155
+ readonly properties: ReadonlyArray<InlineObjectPropertyDef>;
156
+ readonly currentPath: ReadonlyArray<string>;
157
+ readonly sourceLocation: SourceLocation;
158
+ readonly buildContext: ContextBuilderFn;
159
+ readonly preserveDocumentation: boolean;
160
+ readonly results: InlineObjectWithContext[];
161
+ }
162
+
163
+ function extractNestedInlineObjectsRecursively(
164
+ params: ExtractNestedInlineObjectsParams,
165
+ ): void {
166
+ const {
167
+ properties,
168
+ currentPath,
169
+ sourceLocation,
170
+ buildContext,
171
+ preserveDocumentation,
172
+ results,
173
+ } = params;
174
+
175
+ for (const prop of properties) {
176
+ if (
177
+ prop.tsType.kind === "inlineObject" &&
178
+ prop.tsType.inlineObjectProperties
179
+ ) {
180
+ const nestedPath = [...currentPath, prop.name];
181
+ const nestedContext = buildContext(nestedPath);
182
+ // Use property's source location if available for more accurate diagnostics
183
+ const nestedSourceLocation = prop.sourceLocation ?? sourceLocation;
184
+
185
+ results.push({
186
+ properties: prop.tsType.inlineObjectProperties,
187
+ context: nestedContext,
188
+ sourceLocation: nestedSourceLocation,
189
+ nullable: prop.tsType.nullable,
190
+ description: preserveDocumentation
191
+ ? prop.tsType.inlineObjectDescription
192
+ : null,
193
+ deprecated: preserveDocumentation
194
+ ? prop.tsType.inlineObjectDeprecated
195
+ : null,
196
+ });
197
+
198
+ extractNestedInlineObjectsRecursively({
199
+ properties: prop.tsType.inlineObjectProperties,
200
+ currentPath: nestedPath,
201
+ sourceLocation: nestedSourceLocation,
202
+ buildContext,
203
+ preserveDocumentation,
204
+ results,
205
+ });
206
+ }
207
+ }
108
208
  }
109
209
 
110
210
  function getContextKey(context: AutoTypeNameContext): string {
@@ -115,6 +215,8 @@ function getContextKey(context: AutoTypeNameContext): string {
115
215
  return `inputField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
116
216
  case "resolverArg":
117
217
  return `resolverArg:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.argName}:${context.fieldPath.join(".")}`;
218
+ case "resolverPayload":
219
+ return `resolverPayload:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.fieldPath.join(".")}`;
118
220
  }
119
221
  }
120
222
 
@@ -128,6 +230,8 @@ function mapContextKindToGeneratedFromContext(
128
230
  return "inputField";
129
231
  case "resolverArg":
130
232
  return "resolverArg";
233
+ case "resolverPayload":
234
+ return "resolverPayload";
131
235
  }
132
236
  }
133
237
 
@@ -153,27 +257,33 @@ function collectInlineObjectsFromType(
153
257
  const isInput = isInputTypeName(typeInfo.metadata.name);
154
258
 
155
259
  for (const field of typeInfo.fields) {
156
- collectInlineObjectsFromField(
260
+ collectInlineObjectsFromField({
157
261
  field,
158
- typeInfo.metadata.name,
159
- [],
262
+ parentTypeName: typeInfo.metadata.name,
263
+ parentPath: [],
160
264
  isInput,
161
- typeInfo.metadata.sourceFile,
265
+ sourceFile: typeInfo.metadata.sourceFile,
162
266
  results,
163
- );
267
+ });
164
268
  }
165
269
 
166
270
  return results;
167
271
  }
168
272
 
273
+ interface CollectInlineObjectsFromFieldParams {
274
+ readonly field: FieldDefinition;
275
+ readonly parentTypeName: string;
276
+ readonly parentPath: ReadonlyArray<string>;
277
+ readonly isInput: boolean;
278
+ readonly sourceFile: string;
279
+ readonly results: InlineObjectWithContext[];
280
+ }
281
+
169
282
  function collectInlineObjectsFromField(
170
- field: FieldDefinition,
171
- parentTypeName: string,
172
- parentPath: ReadonlyArray<string>,
173
- isInput: boolean,
174
- sourceFile: string,
175
- results: InlineObjectWithContext[],
283
+ params: CollectInlineObjectsFromFieldParams,
176
284
  ): void {
285
+ const { field, parentTypeName, parentPath, isInput, sourceFile, results } =
286
+ params;
177
287
  const tsType = field.tsType;
178
288
 
179
289
  if (tsType.kind !== "inlineObject" || !tsType.inlineObjectProperties) {
@@ -194,100 +304,31 @@ function collectInlineObjectsFromField(
194
304
  fieldPath,
195
305
  };
196
306
 
307
+ const sourceLocation = getSourceLocationOrDefault(
308
+ field.sourceLocation,
309
+ sourceFile,
310
+ );
311
+
197
312
  results.push({
198
313
  properties: tsType.inlineObjectProperties,
199
314
  context,
200
- sourceLocation: field.sourceLocation ?? {
201
- file: sourceFile,
202
- line: 1,
203
- column: 1,
204
- },
315
+ sourceLocation,
205
316
  nullable: tsType.nullable,
317
+ description: tsType.inlineObjectDescription,
318
+ deprecated: tsType.inlineObjectDeprecated,
206
319
  });
207
320
 
208
- for (const prop of tsType.inlineObjectProperties) {
209
- if (
210
- prop.tsType.kind === "inlineObject" &&
211
- prop.tsType.inlineObjectProperties
212
- ) {
213
- const nestedPath = [...fieldPath, prop.name];
214
- const nestedContext: AutoTypeNameContext = isInput
215
- ? {
216
- kind: "inputField",
217
- parentTypeName,
218
- fieldPath: nestedPath,
219
- }
220
- : {
221
- kind: "objectField",
222
- parentTypeName,
223
- fieldPath: nestedPath,
224
- };
225
-
226
- extractNestedInlineObjects(
227
- prop.tsType.inlineObjectProperties,
228
- nestedContext,
229
- nestedPath,
230
- parentTypeName,
231
- isInput,
232
- sourceFile,
233
- prop.sourceLocation,
234
- results,
235
- );
236
- }
237
- }
238
- }
239
-
240
- function extractNestedInlineObjects(
241
- properties: ReadonlyArray<InlineObjectPropertyDef>,
242
- context: AutoTypeNameContext,
243
- currentPath: ReadonlyArray<string>,
244
- parentTypeName: string,
245
- isInput: boolean,
246
- sourceFile: string,
247
- parentSourceLocation: SourceLocation | null,
248
- results: InlineObjectWithContext[],
249
- ): void {
250
- results.push({
251
- properties,
252
- context,
253
- sourceLocation: parentSourceLocation ?? {
254
- file: sourceFile,
255
- line: 1,
256
- column: 1,
257
- },
258
- nullable: false,
321
+ extractNestedInlineObjectsRecursively({
322
+ properties: tsType.inlineObjectProperties,
323
+ currentPath: fieldPath,
324
+ sourceLocation,
325
+ buildContext: (nestedPath) =>
326
+ isInput
327
+ ? { kind: "inputField", parentTypeName, fieldPath: nestedPath }
328
+ : { kind: "objectField", parentTypeName, fieldPath: nestedPath },
329
+ preserveDocumentation: true,
330
+ results,
259
331
  });
260
-
261
- for (const prop of properties) {
262
- if (
263
- prop.tsType.kind === "inlineObject" &&
264
- prop.tsType.inlineObjectProperties
265
- ) {
266
- const nestedPath = [...currentPath, prop.name];
267
- const nestedContext: AutoTypeNameContext = isInput
268
- ? {
269
- kind: "inputField",
270
- parentTypeName,
271
- fieldPath: nestedPath,
272
- }
273
- : {
274
- kind: "objectField",
275
- parentTypeName,
276
- fieldPath: nestedPath,
277
- };
278
-
279
- extractNestedInlineObjects(
280
- prop.tsType.inlineObjectProperties,
281
- nestedContext,
282
- nestedPath,
283
- parentTypeName,
284
- isInput,
285
- sourceFile,
286
- prop.sourceLocation,
287
- results,
288
- );
289
- }
290
- }
291
332
  }
292
333
 
293
334
  function collectInlineObjectsFromResolvers(
@@ -295,24 +336,17 @@ function collectInlineObjectsFromResolvers(
295
336
  ): InlineObjectWithContext[] {
296
337
  const results: InlineObjectWithContext[] = [];
297
338
 
298
- for (const field of resolversResult.queryFields.fields) {
299
- collectInlineObjectsFromResolverArgs(field, "query", null, results);
300
- }
301
-
302
- for (const field of resolversResult.mutationFields.fields) {
303
- collectInlineObjectsFromResolverArgs(field, "mutation", null, results);
304
- }
305
-
306
- for (const ext of resolversResult.typeExtensions) {
307
- for (const field of ext.fields) {
339
+ forEachResolverField(
340
+ resolversResult,
341
+ ({ field, resolverType, parentTypeName }) => {
308
342
  collectInlineObjectsFromResolverArgs(
309
343
  field,
310
- "field",
311
- ext.targetTypeName,
344
+ resolverType,
345
+ parentTypeName,
312
346
  results,
313
347
  );
314
- }
315
- }
348
+ },
349
+ );
316
350
 
317
351
  return results;
318
352
  }
@@ -342,65 +376,87 @@ function collectInlineObjectsFromResolverArgs(
342
376
  context,
343
377
  sourceLocation: field.sourceLocation,
344
378
  nullable: arg.type.nullable,
379
+ description: null,
380
+ deprecated: null,
345
381
  });
346
382
 
347
- extractNestedInlineObjectsFromArg(
348
- arg.inlineObjectProperties,
349
- resolverType,
350
- field.name,
351
- arg.name,
352
- parentTypeName,
353
- [],
354
- field.sourceLocation,
355
- results,
356
- );
357
- }
358
- }
359
-
360
- function extractNestedInlineObjectsFromArg(
361
- properties: ReadonlyArray<InlineObjectPropertyDef>,
362
- resolverType: "query" | "mutation" | "field",
363
- fieldName: string,
364
- argName: string,
365
- parentTypeName: string | null,
366
- currentPath: ReadonlyArray<string>,
367
- sourceLocation: SourceLocation,
368
- results: InlineObjectWithContext[],
369
- ): void {
370
- for (const prop of properties) {
371
- if (
372
- prop.tsType.kind === "inlineObject" &&
373
- prop.tsType.inlineObjectProperties
374
- ) {
375
- const nestedPath = [...currentPath, prop.name];
376
- const nestedContext: AutoTypeNameContext = {
383
+ extractNestedInlineObjectsRecursively({
384
+ properties: arg.inlineObjectProperties,
385
+ currentPath: [],
386
+ sourceLocation: field.sourceLocation,
387
+ buildContext: (nestedPath) => ({
377
388
  kind: "resolverArg",
378
389
  resolverType,
379
- fieldName,
380
- argName,
390
+ fieldName: field.name,
391
+ argName: arg.name,
381
392
  parentTypeName,
382
393
  fieldPath: nestedPath,
383
- };
394
+ }),
395
+ preserveDocumentation: false,
396
+ results,
397
+ });
398
+ }
399
+ }
384
400
 
385
- results.push({
386
- properties: prop.tsType.inlineObjectProperties,
387
- context: nestedContext,
388
- sourceLocation,
389
- nullable: prop.tsType.nullable,
390
- });
401
+ function collectInlinePayloadsFromResolvers(
402
+ resolversResult: ExtractResolversResult,
403
+ ): InlineObjectWithContext[] {
404
+ const results: InlineObjectWithContext[] = [];
391
405
 
392
- extractNestedInlineObjectsFromArg(
393
- prop.tsType.inlineObjectProperties,
406
+ forEachResolverField(
407
+ resolversResult,
408
+ ({ field, resolverType, parentTypeName }) => {
409
+ collectInlinePayloadFromReturnType(
410
+ field,
394
411
  resolverType,
395
- fieldName,
396
- argName,
397
412
  parentTypeName,
398
- nestedPath,
399
- sourceLocation,
400
413
  results,
401
414
  );
402
- }
403
- }
415
+ },
416
+ );
417
+
418
+ return results;
419
+ }
420
+
421
+ function collectInlinePayloadFromReturnType(
422
+ field: GraphQLFieldDefinition,
423
+ resolverType: "query" | "mutation" | "field",
424
+ parentTypeName: string | null,
425
+ results: InlineObjectWithContext[],
426
+ ): void {
427
+ if (!field.returnTypeInlineObjectProperties) return;
428
+
429
+ const context: AutoTypeNameContext = {
430
+ kind: "resolverPayload",
431
+ resolverType,
432
+ fieldName: field.name,
433
+ parentTypeName,
434
+ fieldPath: [],
435
+ };
436
+
437
+ results.push({
438
+ properties: field.returnTypeInlineObjectProperties,
439
+ context,
440
+ sourceLocation: field.sourceLocation,
441
+ nullable: field.type.nullable,
442
+ description: field.returnTypeInlineObjectDescription,
443
+ deprecated: field.returnTypeInlineObjectDeprecated,
444
+ });
445
+
446
+ extractNestedInlineObjectsRecursively({
447
+ properties: field.returnTypeInlineObjectProperties,
448
+ currentPath: [],
449
+ sourceLocation: field.sourceLocation,
450
+ buildContext: (nestedPath) => ({
451
+ kind: "resolverPayload",
452
+ resolverType,
453
+ fieldName: field.name,
454
+ parentTypeName,
455
+ fieldPath: nestedPath,
456
+ }),
457
+ preserveDocumentation: true,
458
+ results,
459
+ });
404
460
  }
405
461
 
406
462
  interface GenerateAutoTypeResult {
@@ -412,12 +468,14 @@ interface GenerateAutoTypeParams {
412
468
  readonly inlineObj: InlineObjectWithContext;
413
469
  readonly generatedTypeNames: Map<string, string>;
414
470
  readonly enumTypeNames: Map<string, string>;
471
+ readonly unionTypeNames: Map<string, string>;
415
472
  }
416
473
 
417
474
  function generateAutoType(
418
475
  params: GenerateAutoTypeParams,
419
476
  ): GenerateAutoTypeResult {
420
- const { inlineObj, generatedTypeNames, enumTypeNames } = params;
477
+ const { inlineObj, generatedTypeNames, enumTypeNames, unionTypeNames } =
478
+ params;
421
479
  const name = generateAutoTypeName(inlineObj.context);
422
480
  const isInput =
423
481
  inlineObj.context.kind === "inputField" ||
@@ -427,9 +485,10 @@ function generateAutoType(
427
485
  const diagnostics: Diagnostic[] = [];
428
486
 
429
487
  for (const prop of inlineObj.properties) {
430
- const eligibility = isInput
431
- ? isEligibleAsInputObjectField(prop.name)
432
- : isEligibleAsObjectField(prop.name);
488
+ const eligibility = isEligibleField({
489
+ fieldName: prop.name,
490
+ kind: isInput ? "input" : "object",
491
+ });
433
492
 
434
493
  if (!eligibility.eligible) {
435
494
  diagnostics.push({
@@ -445,6 +504,7 @@ function generateAutoType(
445
504
  prop,
446
505
  generatedTypeNames,
447
506
  enumTypeNames,
507
+ unionTypeNames,
448
508
  parentContext: inlineObj.context,
449
509
  });
450
510
  fields.push({
@@ -463,10 +523,12 @@ function generateAutoType(
463
523
  kind: isInput ? "InputObject" : "Object",
464
524
  fields,
465
525
  enumValues: null,
526
+ unionMembers: null,
466
527
  needsStringEnumMapping: false,
467
528
  sourceLocation: inlineObj.sourceLocation,
468
529
  generatedFrom: buildGeneratedFromInfo(inlineObj.context),
469
- description: null,
530
+ description: inlineObj.description,
531
+ resolveTypeFieldPattern: null,
470
532
  },
471
533
  diagnostics,
472
534
  };
@@ -476,49 +538,63 @@ interface ResolveFieldTypeParams {
476
538
  readonly prop: InlineObjectPropertyDef;
477
539
  readonly generatedTypeNames: Map<string, string>;
478
540
  readonly enumTypeNames: Map<string, string>;
541
+ readonly unionTypeNames: Map<string, string>;
479
542
  readonly parentContext: AutoTypeNameContext;
480
543
  }
481
544
 
545
+ function tryResolveNestedType(
546
+ prop: InlineObjectPropertyDef,
547
+ parentContext: AutoTypeNameContext,
548
+ typeNamesMap: ReadonlyMap<string, string>,
549
+ ): GraphQLFieldType | null {
550
+ const nestedPath = [...parentContext.fieldPath, prop.name];
551
+ const nestedContext: AutoTypeNameContext = {
552
+ ...parentContext,
553
+ fieldPath: nestedPath,
554
+ };
555
+ const contextKey = getContextKey(nestedContext);
556
+ const resolvedTypeName = typeNamesMap.get(contextKey);
557
+
558
+ if (resolvedTypeName) {
559
+ return {
560
+ typeName: resolvedTypeName,
561
+ nullable: prop.tsType.nullable || prop.optional,
562
+ list: false,
563
+ listItemNullable: null,
564
+ };
565
+ }
566
+ return null;
567
+ }
568
+
482
569
  function resolveFieldType(params: ResolveFieldTypeParams): GraphQLFieldType {
483
- const { prop, generatedTypeNames, enumTypeNames, parentContext } = params;
570
+ const {
571
+ prop,
572
+ generatedTypeNames,
573
+ enumTypeNames,
574
+ unionTypeNames,
575
+ parentContext,
576
+ } = params;
484
577
 
485
578
  if (
486
579
  prop.tsType.kind === "inlineObject" &&
487
580
  prop.tsType.inlineObjectProperties
488
581
  ) {
489
- const nestedPath = [...parentContext.fieldPath, prop.name];
490
- const nestedContext: AutoTypeNameContext = {
491
- ...parentContext,
492
- fieldPath: nestedPath,
493
- };
494
- const contextKey = getContextKey(nestedContext);
495
- const resolvedTypeName = generatedTypeNames.get(contextKey);
496
- if (resolvedTypeName) {
497
- return {
498
- typeName: resolvedTypeName,
499
- nullable: prop.tsType.nullable || prop.optional,
500
- list: false,
501
- listItemNullable: null,
502
- };
503
- }
582
+ const result = tryResolveNestedType(
583
+ prop,
584
+ parentContext,
585
+ generatedTypeNames,
586
+ );
587
+ if (result) return result;
504
588
  }
505
589
 
506
590
  if (prop.tsType.kind === "inlineEnum" && prop.tsType.inlineEnumMembers) {
507
- const nestedPath = [...parentContext.fieldPath, prop.name];
508
- const nestedContext: AutoTypeNameContext = {
509
- ...parentContext,
510
- fieldPath: nestedPath,
511
- };
512
- const contextKey = getContextKey(nestedContext);
513
- const resolvedTypeName = enumTypeNames.get(contextKey);
514
- if (resolvedTypeName) {
515
- return {
516
- typeName: resolvedTypeName,
517
- nullable: prop.tsType.nullable || prop.optional,
518
- list: false,
519
- listItemNullable: null,
520
- };
521
- }
591
+ const result = tryResolveNestedType(prop, parentContext, enumTypeNames);
592
+ if (result) return result;
593
+ }
594
+
595
+ if (prop.tsType.kind === "union" && prop.tsType.members) {
596
+ const result = tryResolveNestedType(prop, parentContext, unionTypeNames);
597
+ if (result) return result;
522
598
  }
523
599
 
524
600
  return convertTsTypeToGraphQLType(prop.tsType, prop.optional);
@@ -527,6 +603,7 @@ function resolveFieldType(params: ResolveFieldTypeParams): GraphQLFieldType {
527
603
  interface UpdateTypeNamesParams {
528
604
  readonly generatedTypeNames: Map<string, string>;
529
605
  readonly enumTypeNames: Map<string, string>;
606
+ readonly unionTypeNames: Map<string, string>;
530
607
  }
531
608
 
532
609
  function updateExtractedTypes(
@@ -550,7 +627,7 @@ function updateField(
550
627
  parentTypeName: string,
551
628
  isInput: boolean,
552
629
  ): FieldDefinition {
553
- const { generatedTypeNames, enumTypeNames } = params;
630
+ const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
554
631
  const context = buildFieldContext(parentTypeName, [field.name], isInput);
555
632
  const contextKey = getContextKey(context);
556
633
 
@@ -606,6 +683,20 @@ function updateField(
606
683
  }
607
684
  }
608
685
 
686
+ // Handle inline union types
687
+ if (field.tsType.kind === "union" && field.tsType.members) {
688
+ const resolvedTypeName = unionTypeNames.get(contextKey);
689
+ if (resolvedTypeName) {
690
+ return {
691
+ ...field,
692
+ tsType: createReferenceType({
693
+ name: resolvedTypeName,
694
+ nullable: field.tsType.nullable,
695
+ }),
696
+ };
697
+ }
698
+ }
699
+
609
700
  return field;
610
701
  }
611
702
 
@@ -640,9 +731,55 @@ function updateResolverField(
640
731
  resolverType: "query" | "mutation" | "field",
641
732
  parentTypeName: string | null,
642
733
  ): GraphQLFieldDefinition {
643
- if (!field.args) return field;
734
+ const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
644
735
 
645
- const { generatedTypeNames, enumTypeNames } = params;
736
+ let updatedType = field.type;
737
+
738
+ // Create payload context once for all inline return type checks
739
+ const hasInlinePayload =
740
+ field.returnTypeInlineObjectProperties ||
741
+ field.returnTypeInlineEnumMembers ||
742
+ field.returnTypeInlineUnionMembers;
743
+
744
+ if (hasInlinePayload) {
745
+ const payloadContext: AutoTypeNameContext = {
746
+ kind: "resolverPayload",
747
+ resolverType,
748
+ fieldName: field.name,
749
+ parentTypeName,
750
+ fieldPath: [],
751
+ };
752
+ const payloadContextKey = getContextKey(payloadContext);
753
+
754
+ // These are mutually exclusive - a return type can only be one of:
755
+ // inline object, inline enum, or inline union
756
+ if (field.returnTypeInlineObjectProperties) {
757
+ // Handle inline payload objects in return type
758
+ const resolvedTypeName = generatedTypeNames.get(payloadContextKey);
759
+ if (resolvedTypeName) {
760
+ updatedType = { ...field.type, typeName: resolvedTypeName };
761
+ }
762
+ } else if (field.returnTypeInlineEnumMembers) {
763
+ // Handle inline enum in return type
764
+ const resolvedTypeName = enumTypeNames.get(payloadContextKey);
765
+ if (resolvedTypeName) {
766
+ updatedType = { ...field.type, typeName: resolvedTypeName };
767
+ }
768
+ } else if (field.returnTypeInlineUnionMembers) {
769
+ // Handle inline union in return type
770
+ const resolvedTypeName = unionTypeNames.get(payloadContextKey);
771
+ if (resolvedTypeName) {
772
+ updatedType = { ...field.type, typeName: resolvedTypeName };
773
+ }
774
+ }
775
+ }
776
+
777
+ if (!field.args) {
778
+ return {
779
+ ...field,
780
+ type: updatedType,
781
+ };
782
+ }
646
783
 
647
784
  const updatedArgs = field.args.map((arg) => {
648
785
  const context: AutoTypeNameContext = {
@@ -683,11 +820,26 @@ function updateResolverField(
683
820
  }
684
821
  }
685
822
 
823
+ // Handle inline unions (OneOf input objects)
824
+ if (arg.inlineUnionMembers) {
825
+ const resolvedTypeName = unionTypeNames.get(contextKey);
826
+ if (resolvedTypeName) {
827
+ return {
828
+ ...arg,
829
+ type: {
830
+ ...arg.type,
831
+ typeName: resolvedTypeName,
832
+ },
833
+ };
834
+ }
835
+ }
836
+
686
837
  return arg;
687
838
  });
688
839
 
689
840
  return {
690
841
  ...field,
842
+ type: updatedType,
691
843
  args: updatedArgs,
692
844
  };
693
845
  }
@@ -706,14 +858,6 @@ function buildGeneratedTypeNamesMap(
706
858
  return map;
707
859
  }
708
860
 
709
- function toScreamingSnakeCase(value: string): string {
710
- return value
711
- .replace(/[-\s]+/g, "_")
712
- .replace(/([a-z])([A-Z])/g, "$1_$2")
713
- .replace(/([A-Z]+)([A-Z][a-z])/g, "$1_$2")
714
- .toUpperCase();
715
- }
716
-
717
861
  interface ConvertInlineEnumMembersParams {
718
862
  readonly members: ReadonlyArray<InlineEnumMemberInfo>;
719
863
  readonly enumName: string;
@@ -726,6 +870,11 @@ interface ConvertEnumMembersWithDiagnosticsResult {
726
870
  readonly diagnostics: ReadonlyArray<Diagnostic>;
727
871
  }
728
872
 
873
+ interface ConvertedMemberInfo {
874
+ readonly convertedName: string;
875
+ readonly member: InlineEnumMemberInfo;
876
+ }
877
+
729
878
  function convertInlineEnumMembers(
730
879
  params: ConvertInlineEnumMembersParams,
731
880
  ): ConvertEnumMembersWithDiagnosticsResult {
@@ -734,32 +883,46 @@ function convertInlineEnumMembers(
734
883
  const enumValues: AutoGeneratedEnumValue[] = [];
735
884
  const diagnostics: Diagnostic[] = [];
736
885
 
737
- const convertedNameToOriginals = new Map<string, string[]>();
886
+ const convertedMembers: ConvertedMemberInfo[] = [];
738
887
 
739
888
  for (const member of members) {
740
889
  const convertedName = toScreamingSnakeCase(member.value);
890
+ convertedMembers.push({ convertedName, member });
891
+ }
892
+
893
+ const prefixDetectionResult = detectEnumPrefix({
894
+ enumName,
895
+ memberValues: convertedMembers.map((m) => m.convertedName),
896
+ });
897
+
898
+ const finalNameToOriginals = new Map<string, string[]>();
741
899
 
742
- if (convertedName !== member.value) {
900
+ for (const { convertedName, member } of convertedMembers) {
901
+ let finalName = convertedName;
902
+ if (prefixDetectionResult.shouldStrip && prefixDetectionResult.prefix) {
903
+ finalName = stripEnumPrefix(convertedName, prefixDetectionResult.prefix);
904
+ needsStringEnumMapping = true;
905
+ } else if (convertedName !== member.value) {
743
906
  needsStringEnumMapping = true;
744
907
  }
745
908
 
746
- const originals = convertedNameToOriginals.get(convertedName) ?? [];
909
+ const originals = finalNameToOriginals.get(finalName) ?? [];
747
910
  originals.push(member.value);
748
- convertedNameToOriginals.set(convertedName, originals);
911
+ finalNameToOriginals.set(finalName, originals);
749
912
 
750
913
  enumValues.push({
751
- name: convertedName,
914
+ name: finalName,
752
915
  originalValue: member.value,
753
916
  description: member.description,
754
917
  deprecated: member.deprecated,
755
918
  });
756
919
  }
757
920
 
758
- for (const [convertedName, originals] of convertedNameToOriginals) {
921
+ for (const [finalName, originals] of finalNameToOriginals) {
759
922
  if (originals.length > 1) {
760
923
  diagnostics.push({
761
924
  code: "DUPLICATE_ENUM_VALUE_AFTER_CONVERSION",
762
- message: `Enum '${enumName}' has duplicate value '${convertedName}' after conversion (from '${originals.join("' and '")}')`,
925
+ message: `Enum '${enumName}' has duplicate value '${finalName}' after conversion (from '${originals.join("' and '")}')`,
763
926
  severity: "error",
764
927
  location: sourceLocation,
765
928
  });
@@ -791,10 +954,12 @@ function generateAutoEnumType(
791
954
  kind: "Enum",
792
955
  fields: null,
793
956
  enumValues,
957
+ unionMembers: null,
794
958
  needsStringEnumMapping,
795
959
  sourceLocation: inlineEnum.sourceLocation,
796
960
  generatedFrom: buildGeneratedFromInfo(inlineEnum.context),
797
961
  description: inlineEnum.externalEnumDescription,
962
+ resolveTypeFieldPattern: null,
798
963
  },
799
964
  diagnostics,
800
965
  };
@@ -850,6 +1015,534 @@ function buildEnumTypeNamesMap(
850
1015
  };
851
1016
  }
852
1017
 
1018
+ function buildUnionTypeNamesMap(
1019
+ inlineUnions: InlineUnionWithContext[],
1020
+ ): Map<string, string> {
1021
+ const unionTypeNames = new Map<string, string>();
1022
+
1023
+ for (const inlineUnion of inlineUnions) {
1024
+ const contextKey = getContextKey(inlineUnion.context);
1025
+ const typeName = generateAutoTypeName(inlineUnion.context);
1026
+ unionTypeNames.set(contextKey, typeName);
1027
+ }
1028
+
1029
+ return unionTypeNames;
1030
+ }
1031
+
1032
+ interface ProcessInlineUnionsParams {
1033
+ readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
1034
+ readonly knownTypeNames: ReadonlySet<string>;
1035
+ readonly generatedTypeNames: Map<string, string>;
1036
+ readonly enumTypeNames: Map<string, string>;
1037
+ readonly unionTypeNames: Map<string, string>;
1038
+ readonly extractedTypes: ReadonlyArray<ExtractedTypeInfo>;
1039
+ }
1040
+
1041
+ interface ProcessInlineUnionsResult {
1042
+ readonly types: AutoGeneratedType[];
1043
+ readonly diagnostics: Diagnostic[];
1044
+ }
1045
+
1046
+ interface ProcessOneOfInputObjectsParams {
1047
+ readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
1048
+ readonly knownTypeNames: ReadonlySet<string>;
1049
+ readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
1050
+ readonly unionTypeNames: Map<string, string>;
1051
+ }
1052
+
1053
+ function processOneOfInputObjects(
1054
+ params: ProcessOneOfInputObjectsParams,
1055
+ ): ProcessInlineUnionsResult {
1056
+ const { inlineUnions, knownTypeNames, typeMap, unionTypeNames } = params;
1057
+ const types: AutoGeneratedType[] = [];
1058
+ const diagnostics: Diagnostic[] = [];
1059
+
1060
+ for (const inlineUnion of inlineUnions) {
1061
+ const contextKey = getContextKey(inlineUnion.context);
1062
+ const typeName = generateAutoTypeName(inlineUnion.context);
1063
+
1064
+ const validationResult = validateOneOfMembers({
1065
+ members: inlineUnion.members,
1066
+ typeName,
1067
+ sourceLocation: inlineUnion.sourceLocation,
1068
+ typeMap,
1069
+ });
1070
+
1071
+ diagnostics.push(...validationResult.diagnostics);
1072
+
1073
+ if (!validationResult.valid) {
1074
+ continue;
1075
+ }
1076
+
1077
+ const fields = generateOneOfFields({
1078
+ members: inlineUnion.members,
1079
+ knownTypeNames,
1080
+ });
1081
+
1082
+ types.push({
1083
+ name: typeName,
1084
+ kind: "OneOfInputObject",
1085
+ fields,
1086
+ enumValues: null,
1087
+ unionMembers: null,
1088
+ needsStringEnumMapping: false,
1089
+ sourceLocation: inlineUnion.sourceLocation,
1090
+ generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
1091
+ description: null,
1092
+ resolveTypeFieldPattern: null,
1093
+ });
1094
+
1095
+ unionTypeNames.set(contextKey, typeName);
1096
+ }
1097
+
1098
+ return { types, diagnostics };
1099
+ }
1100
+
1101
+ interface ProcessUnionTypesParams {
1102
+ readonly inlineUnions: ReadonlyArray<InlineUnionWithContext>;
1103
+ readonly knownTypeNames: ReadonlySet<string>;
1104
+ readonly generatedTypeNames: Map<string, string>;
1105
+ readonly enumTypeNames: Map<string, string>;
1106
+ readonly unionTypeNames: Map<string, string>;
1107
+ readonly typeMap: ReadonlyMap<string, ExtractedTypeInfo>;
1108
+ }
1109
+
1110
+ function processUnionTypes(
1111
+ params: ProcessUnionTypesParams,
1112
+ ): ProcessInlineUnionsResult {
1113
+ const {
1114
+ inlineUnions,
1115
+ knownTypeNames,
1116
+ generatedTypeNames,
1117
+ enumTypeNames,
1118
+ unionTypeNames,
1119
+ typeMap,
1120
+ } = params;
1121
+ const types: AutoGeneratedType[] = [];
1122
+ const diagnostics: Diagnostic[] = [];
1123
+ const generatedTypenameTypes = new Map<
1124
+ string,
1125
+ ReadonlyArray<AutoGeneratedField>
1126
+ >();
1127
+
1128
+ for (const inlineUnion of inlineUnions) {
1129
+ const contextKey = getContextKey(inlineUnion.context);
1130
+ const typeName = generateAutoTypeName(inlineUnion.context);
1131
+
1132
+ const validationResult = validateUnionMembers({
1133
+ members: inlineUnion.members,
1134
+ typeName,
1135
+ sourceLocation: inlineUnion.sourceLocation,
1136
+ typeMap,
1137
+ });
1138
+
1139
+ diagnostics.push(...validationResult.diagnostics);
1140
+
1141
+ if (!validationResult.valid) {
1142
+ continue;
1143
+ }
1144
+
1145
+ let resolveTypeFieldPattern: AutoGeneratedType["resolveTypeFieldPattern"] =
1146
+ null;
1147
+
1148
+ if (inlineUnion.context.kind === "resolverPayload") {
1149
+ const typenameValidationResult = validateUnionMemberTypenames({
1150
+ members: inlineUnion.members,
1151
+ unionTypeName: typeName,
1152
+ sourceLocation: inlineUnion.sourceLocation,
1153
+ typeMap,
1154
+ });
1155
+
1156
+ diagnostics.push(...typenameValidationResult.diagnostics);
1157
+
1158
+ if (!typenameValidationResult.valid) {
1159
+ continue;
1160
+ }
1161
+
1162
+ if (typenameValidationResult.allMembersHaveTypename) {
1163
+ resolveTypeFieldPattern = determineFieldPattern(
1164
+ typenameValidationResult.memberTypenames,
1165
+ );
1166
+ }
1167
+ }
1168
+
1169
+ const memberNames = resolveMemberNames({
1170
+ members: inlineUnion.members,
1171
+ knownTypeNames,
1172
+ generatedTypeNames,
1173
+ enumTypeNames,
1174
+ parentContext: inlineUnion.context,
1175
+ unionTypeNames,
1176
+ types,
1177
+ diagnostics,
1178
+ generatedTypenameTypes,
1179
+ sourceLocation: inlineUnion.sourceLocation,
1180
+ });
1181
+
1182
+ types.push({
1183
+ name: typeName,
1184
+ kind: "Union",
1185
+ fields: null,
1186
+ enumValues: null,
1187
+ unionMembers: memberNames,
1188
+ needsStringEnumMapping: false,
1189
+ sourceLocation: inlineUnion.sourceLocation,
1190
+ generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
1191
+ description: null,
1192
+ resolveTypeFieldPattern,
1193
+ });
1194
+
1195
+ unionTypeNames.set(contextKey, typeName);
1196
+ }
1197
+
1198
+ return { types, diagnostics };
1199
+ }
1200
+
1201
+ /**
1202
+ * Determine the field pattern for resolveType based on the typename fields used by members.
1203
+ */
1204
+ function determineFieldPattern(
1205
+ memberTypenames: ReadonlyMap<number, ValidatedTypenameInfo>,
1206
+ ): ResolveTypeFieldPattern {
1207
+ const fieldNames = new Set<TypenameFieldName>();
1208
+ for (const info of memberTypenames.values()) {
1209
+ fieldNames.add(info.fieldName);
1210
+ }
1211
+
1212
+ if (fieldNames.size === 0) {
1213
+ return { usedFieldNames: createFieldNameSet(["__typename"]) };
1214
+ }
1215
+
1216
+ return { usedFieldNames: fieldNames };
1217
+ }
1218
+
1219
+ function processInlineUnions(
1220
+ params: ProcessInlineUnionsParams,
1221
+ ): ProcessInlineUnionsResult {
1222
+ const {
1223
+ inlineUnions,
1224
+ knownTypeNames,
1225
+ generatedTypeNames,
1226
+ enumTypeNames,
1227
+ unionTypeNames,
1228
+ extractedTypes,
1229
+ } = params;
1230
+
1231
+ const typeMap = new Map<string, ExtractedTypeInfo>();
1232
+ for (const typeInfo of extractedTypes) {
1233
+ typeMap.set(typeInfo.metadata.name, typeInfo);
1234
+ }
1235
+
1236
+ const inputUnions = inlineUnions.filter((u) => u.isInputContext);
1237
+ const outputUnions = inlineUnions.filter((u) => !u.isInputContext);
1238
+
1239
+ const oneOfResult = processOneOfInputObjects({
1240
+ inlineUnions: inputUnions,
1241
+ knownTypeNames,
1242
+ typeMap,
1243
+ unionTypeNames,
1244
+ });
1245
+
1246
+ const unionResult = processUnionTypes({
1247
+ inlineUnions: outputUnions,
1248
+ knownTypeNames,
1249
+ generatedTypeNames,
1250
+ enumTypeNames,
1251
+ unionTypeNames,
1252
+ typeMap,
1253
+ });
1254
+
1255
+ return {
1256
+ types: [...oneOfResult.types, ...unionResult.types],
1257
+ diagnostics: [...oneOfResult.diagnostics, ...unionResult.diagnostics],
1258
+ };
1259
+ }
1260
+
1261
+ interface GenerateOneOfFieldsParams {
1262
+ readonly members: ReadonlyArray<InlineUnionMemberInfo>;
1263
+ readonly knownTypeNames: ReadonlySet<string>;
1264
+ }
1265
+
1266
+ function generateOneOfFields(
1267
+ params: GenerateOneOfFieldsParams,
1268
+ ): AutoGeneratedField[] {
1269
+ const { members, knownTypeNames } = params;
1270
+
1271
+ const fields: AutoGeneratedField[] = [];
1272
+
1273
+ for (const member of members) {
1274
+ const memberType = member.memberType;
1275
+
1276
+ if (
1277
+ memberType.kind === "inlineObject" &&
1278
+ memberType.inlineObjectProperties
1279
+ ) {
1280
+ for (const prop of memberType.inlineObjectProperties) {
1281
+ const fieldType = convertTsTypeToGraphQLType(
1282
+ prop.tsType,
1283
+ prop.optional,
1284
+ );
1285
+ fields.push({
1286
+ name: prop.name,
1287
+ type: {
1288
+ ...fieldType,
1289
+ nullable: true,
1290
+ },
1291
+ description: prop.description,
1292
+ deprecated: prop.deprecated,
1293
+ directives: prop.directives,
1294
+ defaultValue: prop.defaultValue,
1295
+ });
1296
+ }
1297
+ } else if (memberType.kind === "reference" && memberType.name) {
1298
+ if (knownTypeNames.has(memberType.name)) {
1299
+ const camelCaseName =
1300
+ memberType.name.charAt(0).toLowerCase() + memberType.name.slice(1);
1301
+ fields.push({
1302
+ name: camelCaseName,
1303
+ type: {
1304
+ typeName: memberType.name,
1305
+ nullable: true,
1306
+ list: false,
1307
+ listItemNullable: null,
1308
+ },
1309
+ description: null,
1310
+ deprecated: null,
1311
+ directives: null,
1312
+ defaultValue: null,
1313
+ });
1314
+ }
1315
+ }
1316
+ }
1317
+
1318
+ return fields;
1319
+ }
1320
+
1321
+ interface ResolveMemberNamesParams {
1322
+ readonly members: ReadonlyArray<InlineUnionMemberInfo>;
1323
+ readonly knownTypeNames: ReadonlySet<string>;
1324
+ readonly generatedTypeNames: Map<string, string>;
1325
+ readonly enumTypeNames: Map<string, string>;
1326
+ readonly parentContext: AutoTypeNameContext;
1327
+ readonly unionTypeNames: Map<string, string>;
1328
+ readonly types: AutoGeneratedType[];
1329
+ readonly diagnostics: Diagnostic[];
1330
+ readonly generatedTypenameTypes: Map<
1331
+ string,
1332
+ ReadonlyArray<AutoGeneratedField>
1333
+ >;
1334
+ readonly sourceLocation: SourceLocation;
1335
+ }
1336
+
1337
+ /**
1338
+ * Extract __typename or $typeName property value from inline object properties.
1339
+ * Returns null if neither is found or neither is a valid string literal.
1340
+ * __typename takes priority over $typeName if both are present.
1341
+ */
1342
+ function extractTypenameFromInlineObject(
1343
+ properties: ReadonlyArray<InlineObjectPropertyDef>,
1344
+ ): TypenameFieldInfo | null {
1345
+ const found = findTypenameProperty(properties, (p) => p.name);
1346
+ if (!found) {
1347
+ return null;
1348
+ }
1349
+
1350
+ const { property, fieldName } = found;
1351
+ const { tsType } = property;
1352
+
1353
+ if (tsType.kind === "literal" && tsType.name !== null) {
1354
+ return { typeName: tsType.name, fieldName };
1355
+ }
1356
+
1357
+ return null;
1358
+ }
1359
+
1360
+ function resolveMemberNames(params: ResolveMemberNamesParams): string[] {
1361
+ const {
1362
+ members,
1363
+ generatedTypeNames,
1364
+ parentContext,
1365
+ types,
1366
+ generatedTypenameTypes,
1367
+ diagnostics,
1368
+ sourceLocation,
1369
+ } = params;
1370
+
1371
+ const memberNames: string[] = [];
1372
+
1373
+ for (let i = 0; i < members.length; i++) {
1374
+ const member = members[i]!;
1375
+ const memberType = member.memberType;
1376
+
1377
+ if (memberType.kind === "reference" && memberType.name) {
1378
+ memberNames.push(memberType.name);
1379
+ } else if (
1380
+ memberType.kind === "inlineObject" &&
1381
+ memberType.inlineObjectProperties
1382
+ ) {
1383
+ // Only extract __typename or $typeName for resolverPayload context
1384
+ // For other contexts (resolverArg, objectField, inputField), these fields
1385
+ // should be treated as regular fields, not as type discriminators
1386
+ const extractedInfo =
1387
+ parentContext.kind === "resolverPayload"
1388
+ ? extractTypenameFromInlineObject(memberType.inlineObjectProperties)
1389
+ : null;
1390
+
1391
+ let memberTypeName: string;
1392
+ let contextKey: string;
1393
+
1394
+ if (extractedInfo !== null) {
1395
+ memberTypeName = extractedInfo.typeName;
1396
+ const nestedContext: AutoTypeNameContext = {
1397
+ ...parentContext,
1398
+ fieldPath: [...parentContext.fieldPath, extractedInfo.typeName],
1399
+ };
1400
+ contextKey = getContextKey(nestedContext);
1401
+ } else {
1402
+ const nestedContext: AutoTypeNameContext = {
1403
+ ...parentContext,
1404
+ fieldPath: [...parentContext.fieldPath, `member${i}`],
1405
+ };
1406
+ memberTypeName = generateAutoTypeName(nestedContext);
1407
+ contextKey = getContextKey(nestedContext);
1408
+ }
1409
+
1410
+ // Only filter out __typename or $typeName for resolverPayload context
1411
+ // For other contexts, these are regular fields that should be preserved
1412
+ const typenameFieldToFilter = extractedInfo?.fieldName ?? null;
1413
+ const fields: AutoGeneratedField[] = memberType.inlineObjectProperties
1414
+ .filter(
1415
+ (prop) =>
1416
+ parentContext.kind !== "resolverPayload" ||
1417
+ prop.name !== typenameFieldToFilter,
1418
+ )
1419
+ .map((prop) => {
1420
+ const fieldType = convertTsTypeToGraphQLType(
1421
+ prop.tsType,
1422
+ prop.optional,
1423
+ );
1424
+ return {
1425
+ name: prop.name,
1426
+ type: fieldType,
1427
+ description: prop.description,
1428
+ deprecated: prop.deprecated,
1429
+ directives: prop.directives,
1430
+ defaultValue: prop.defaultValue,
1431
+ };
1432
+ });
1433
+
1434
+ // Check if this typename was already seen with a different field structure
1435
+ if (extractedInfo !== null) {
1436
+ const existingFields = generatedTypenameTypes.get(
1437
+ extractedInfo.typeName,
1438
+ );
1439
+ if (existingFields !== undefined) {
1440
+ // Compare field structures
1441
+ if (!areFieldStructuresEqual(existingFields, fields)) {
1442
+ diagnostics.push({
1443
+ code: "TYPENAME_FIELD_STRUCTURE_MISMATCH",
1444
+ message: `Type with ${extractedInfo.fieldName} '${extractedInfo.typeName}' has inconsistent field structures across different union members. All types with the same ${extractedInfo.fieldName} must have identical field definitions.`,
1445
+ severity: "error",
1446
+ location: sourceLocation,
1447
+ });
1448
+ }
1449
+ // Skip generating duplicate type and avoid adding duplicate union member
1450
+ if (!memberNames.includes(memberTypeName)) {
1451
+ memberNames.push(memberTypeName);
1452
+ }
1453
+ continue;
1454
+ }
1455
+ }
1456
+
1457
+ const nestedContext: AutoTypeNameContext = {
1458
+ ...parentContext,
1459
+ fieldPath: [
1460
+ ...parentContext.fieldPath,
1461
+ extractedInfo?.typeName ?? `member${i}`,
1462
+ ],
1463
+ };
1464
+
1465
+ types.push({
1466
+ name: memberTypeName,
1467
+ kind: "Object",
1468
+ fields,
1469
+ enumValues: null,
1470
+ unionMembers: null,
1471
+ needsStringEnumMapping: false,
1472
+ sourceLocation: {
1473
+ file: "",
1474
+ line: 1,
1475
+ column: 1,
1476
+ },
1477
+ generatedFrom: buildGeneratedFromInfo(nestedContext),
1478
+ description: memberType.inlineObjectDescription,
1479
+ resolveTypeFieldPattern: null,
1480
+ });
1481
+
1482
+ generatedTypeNames.set(contextKey, memberTypeName);
1483
+ if (extractedInfo !== null) {
1484
+ generatedTypenameTypes.set(extractedInfo.typeName, fields);
1485
+ }
1486
+ memberNames.push(memberTypeName);
1487
+ }
1488
+ }
1489
+
1490
+ return memberNames;
1491
+ }
1492
+
1493
+ /**
1494
+ * Compare two field structures for equality.
1495
+ * Returns true if both have the same fields with the same types.
1496
+ */
1497
+ function areFieldStructuresEqual(
1498
+ fields1: ReadonlyArray<AutoGeneratedField>,
1499
+ fields2: ReadonlyArray<AutoGeneratedField>,
1500
+ ): boolean {
1501
+ if (fields1.length !== fields2.length) {
1502
+ return false;
1503
+ }
1504
+
1505
+ const sorted1 = [...fields1].sort((a, b) => a.name.localeCompare(b.name));
1506
+ const sorted2 = [...fields2].sort((a, b) => a.name.localeCompare(b.name));
1507
+
1508
+ for (let i = 0; i < sorted1.length; i++) {
1509
+ const f1 = sorted1[i]!;
1510
+ const f2 = sorted2[i]!;
1511
+
1512
+ if (f1.name !== f2.name) {
1513
+ return false;
1514
+ }
1515
+
1516
+ if (!areGraphQLTypesEqual(f1.type, f2.type)) {
1517
+ return false;
1518
+ }
1519
+ }
1520
+
1521
+ return true;
1522
+ }
1523
+
1524
+ /**
1525
+ * Compare two GraphQL type references for equality.
1526
+ */
1527
+ function areGraphQLTypesEqual(
1528
+ type1: GraphQLFieldType,
1529
+ type2: GraphQLFieldType,
1530
+ ): boolean {
1531
+ if (type1.typeName !== type2.typeName) {
1532
+ return false;
1533
+ }
1534
+ if (type1.nullable !== type2.nullable) {
1535
+ return false;
1536
+ }
1537
+ if (type1.list !== type2.list) {
1538
+ return false;
1539
+ }
1540
+ if (type1.listItemNullable !== type2.listItemNullable) {
1541
+ return false;
1542
+ }
1543
+ return true;
1544
+ }
1545
+
853
1546
  export function generateAutoTypes(
854
1547
  input: AutoTypeGeneratorInput,
855
1548
  ): AutoTypeGeneratorResult {
@@ -862,9 +1555,14 @@ export function generateAutoTypes(
862
1555
  input.resolversResult,
863
1556
  );
864
1557
 
1558
+ const inlinePayloadsFromResolvers = collectInlinePayloadsFromResolvers(
1559
+ input.resolversResult,
1560
+ );
1561
+
865
1562
  const allInlineObjects = [
866
1563
  ...inlineObjectsFromTypes,
867
1564
  ...inlineObjectsFromResolvers,
1565
+ ...inlinePayloadsFromResolvers,
868
1566
  ];
869
1567
 
870
1568
  const generatedTypeNames = buildGeneratedTypeNamesMap(allInlineObjects);
@@ -872,14 +1570,43 @@ export function generateAutoTypes(
872
1570
  const inlineEnumsFromTypes = collectInlineEnumsFromTypes(
873
1571
  input.extractedTypes,
874
1572
  );
875
- const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers(
876
- input.resolversResult,
877
- );
878
- const allInlineEnums = [...inlineEnumsFromTypes, ...inlineEnumsFromResolvers];
1573
+ const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers({
1574
+ resolversResult: input.resolversResult,
1575
+ });
1576
+ const inlineEnumsFromPayloads = collectInlineEnumsFromPayloads({
1577
+ resolversResult: input.resolversResult,
1578
+ });
1579
+ const allInlineEnums = [
1580
+ ...inlineEnumsFromTypes,
1581
+ ...inlineEnumsFromResolvers,
1582
+ ...inlineEnumsFromPayloads,
1583
+ ];
879
1584
 
880
1585
  const { enumTypeNames, uniqueInlineEnums } =
881
1586
  buildEnumTypeNamesMap(allInlineEnums);
882
1587
 
1588
+ // Collect inline unions from types, resolvers, and payloads
1589
+ const inlineUnionsFromTypes = collectInlineUnionsFromTypes({
1590
+ extractedTypes: input.extractedTypes,
1591
+ knownTypeNames: input.knownTypeNames,
1592
+ });
1593
+ const inlineUnionsFromResolvers = collectInlineUnionsFromResolvers({
1594
+ resolversResult: input.resolversResult,
1595
+ knownTypeNames: input.knownTypeNames,
1596
+ });
1597
+ const inlineUnionsFromPayloads = collectInlineUnionsFromPayloads({
1598
+ resolversResult: input.resolversResult,
1599
+ knownTypeNames: input.knownTypeNames,
1600
+ });
1601
+ const allInlineUnions = [
1602
+ ...inlineUnionsFromTypes,
1603
+ ...inlineUnionsFromResolvers,
1604
+ ...inlineUnionsFromPayloads,
1605
+ ];
1606
+
1607
+ // Build union type names map before generating auto types
1608
+ const unionTypeNames = buildUnionTypeNamesMap(allInlineUnions);
1609
+
883
1610
  const autoGeneratedTypes: AutoGeneratedType[] = [];
884
1611
  const diagnostics: Diagnostic[] = [];
885
1612
 
@@ -888,6 +1615,7 @@ export function generateAutoTypes(
888
1615
  inlineObj,
889
1616
  generatedTypeNames,
890
1617
  enumTypeNames,
1618
+ unionTypeNames,
891
1619
  });
892
1620
  autoGeneratedTypes.push(result.type);
893
1621
  diagnostics.push(...result.diagnostics);
@@ -901,9 +1629,23 @@ export function generateAutoTypes(
901
1629
  diagnostics.push(...result.diagnostics);
902
1630
  }
903
1631
 
1632
+ // Process inline unions
1633
+ const { types: unionTypes, diagnostics: unionDiagnostics } =
1634
+ processInlineUnions({
1635
+ inlineUnions: allInlineUnions,
1636
+ knownTypeNames: input.knownTypeNames,
1637
+ generatedTypeNames,
1638
+ enumTypeNames,
1639
+ unionTypeNames,
1640
+ extractedTypes: input.extractedTypes,
1641
+ });
1642
+ autoGeneratedTypes.push(...unionTypes);
1643
+ diagnostics.push(...unionDiagnostics);
1644
+
904
1645
  const updateParams: UpdateTypeNamesParams = {
905
1646
  generatedTypeNames,
906
1647
  enumTypeNames,
1648
+ unionTypeNames,
907
1649
  };
908
1650
 
909
1651
  const updatedExtractedTypes = updateExtractedTypes(