@gqlkit-ts/cli 0.2.0 → 0.3.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 (190) hide show
  1. package/dist/auto-type-generator/auto-type-generator.d.ts +10 -4
  2. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  3. package/dist/auto-type-generator/auto-type-generator.js +640 -133
  4. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  5. package/dist/auto-type-generator/index.d.ts +8 -1
  6. package/dist/auto-type-generator/index.d.ts.map +1 -1
  7. package/dist/auto-type-generator/index.js +3 -0
  8. package/dist/auto-type-generator/index.js.map +1 -1
  9. package/dist/auto-type-generator/inline-enum-collector.d.ts +13 -5
  10. package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
  11. package/dist/auto-type-generator/inline-enum-collector.js +107 -71
  12. package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
  13. package/dist/auto-type-generator/inline-object-traverser.d.ts +20 -0
  14. package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -0
  15. package/dist/auto-type-generator/inline-object-traverser.js +22 -0
  16. package/dist/auto-type-generator/inline-object-traverser.js.map +1 -0
  17. package/dist/auto-type-generator/inline-union-collector.d.ts +29 -0
  18. package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -0
  19. package/dist/auto-type-generator/inline-union-collector.js +216 -0
  20. package/dist/auto-type-generator/inline-union-collector.js.map +1 -0
  21. package/dist/auto-type-generator/inline-union-types.d.ts +29 -0
  22. package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -0
  23. package/dist/auto-type-generator/inline-union-types.js +2 -0
  24. package/dist/auto-type-generator/inline-union-types.js.map +1 -0
  25. package/dist/auto-type-generator/inline-union-validator.d.ts +76 -0
  26. package/dist/auto-type-generator/inline-union-validator.d.ts.map +1 -0
  27. package/dist/auto-type-generator/inline-union-validator.js +329 -0
  28. package/dist/auto-type-generator/inline-union-validator.js.map +1 -0
  29. package/dist/auto-type-generator/naming-convention.d.ts +18 -1
  30. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
  31. package/dist/auto-type-generator/naming-convention.js +16 -0
  32. package/dist/auto-type-generator/naming-convention.js.map +1 -1
  33. package/dist/auto-type-generator/resolve-type-generator.d.ts +20 -0
  34. package/dist/auto-type-generator/resolve-type-generator.d.ts.map +1 -0
  35. package/dist/auto-type-generator/resolve-type-generator.js +2 -0
  36. package/dist/auto-type-generator/resolve-type-generator.js.map +1 -0
  37. package/dist/auto-type-generator/resolver-field-iterator.d.ts +13 -0
  38. package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -0
  39. package/dist/auto-type-generator/resolver-field-iterator.js +22 -0
  40. package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -0
  41. package/dist/auto-type-generator/typename-extractor.d.ts +26 -0
  42. package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -0
  43. package/dist/auto-type-generator/typename-extractor.js +142 -0
  44. package/dist/auto-type-generator/typename-extractor.js.map +1 -0
  45. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +35 -0
  46. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -0
  47. package/dist/auto-type-generator/typename-resolve-type-generator.js +177 -0
  48. package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -0
  49. package/dist/auto-type-generator/typename-types.d.ts +43 -0
  50. package/dist/auto-type-generator/typename-types.d.ts.map +1 -0
  51. package/dist/auto-type-generator/typename-types.js +37 -0
  52. package/dist/auto-type-generator/typename-types.js.map +1 -0
  53. package/dist/auto-type-generator/typename-validator.d.ts +37 -0
  54. package/dist/auto-type-generator/typename-validator.d.ts.map +1 -0
  55. package/dist/auto-type-generator/typename-validator.js +206 -0
  56. package/dist/auto-type-generator/typename-validator.js.map +1 -0
  57. package/dist/cli.js +2 -0
  58. package/dist/cli.js.map +1 -1
  59. package/dist/commands/docs.d.ts +51 -0
  60. package/dist/commands/docs.d.ts.map +1 -0
  61. package/dist/commands/docs.js +154 -0
  62. package/dist/commands/docs.js.map +1 -0
  63. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  64. package/dist/gen-orchestrator/orchestrator.js +13 -6
  65. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  66. package/dist/resolver-extractor/extract-resolvers.d.ts +19 -1
  67. package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
  68. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +5 -0
  69. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  70. package/dist/resolver-extractor/extractor/define-api-extractor.js +14 -61
  71. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  72. package/dist/resolver-extractor/index.d.ts +0 -1
  73. package/dist/resolver-extractor/index.d.ts.map +1 -1
  74. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +1 -0
  75. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
  76. package/dist/resolver-extractor/validator/abstract-resolver-validator.js +9 -5
  77. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
  78. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  79. package/dist/schema-generator/emitter/code-emitter.js +20 -0
  80. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  81. package/dist/schema-generator/generate-schema.d.ts +1 -0
  82. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  83. package/dist/schema-generator/generate-schema.js +72 -3
  84. package/dist/schema-generator/generate-schema.js.map +1 -1
  85. package/dist/schema-generator/integrator/result-integrator.d.ts +14 -2
  86. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  87. package/dist/schema-generator/integrator/result-integrator.js +54 -1
  88. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  89. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
  90. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
  91. package/dist/schema-generator/resolver-collector/resolver-collector.js +22 -0
  92. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
  93. package/dist/shared/enum-prefix-detector.d.ts +63 -0
  94. package/dist/shared/enum-prefix-detector.d.ts.map +1 -0
  95. package/dist/shared/enum-prefix-detector.js +80 -0
  96. package/dist/shared/enum-prefix-detector.js.map +1 -0
  97. package/dist/shared/ignore-fields-detector.d.ts +26 -0
  98. package/dist/shared/ignore-fields-detector.d.ts.map +1 -0
  99. package/dist/shared/ignore-fields-detector.js +83 -0
  100. package/dist/shared/ignore-fields-detector.js.map +1 -0
  101. package/dist/shared/ignore-fields-validator.d.ts +29 -0
  102. package/dist/shared/ignore-fields-validator.d.ts.map +1 -0
  103. package/dist/shared/ignore-fields-validator.js +43 -0
  104. package/dist/shared/ignore-fields-validator.js.map +1 -0
  105. package/dist/shared/index.d.ts +2 -0
  106. package/dist/shared/index.d.ts.map +1 -1
  107. package/dist/shared/index.js.map +1 -1
  108. package/dist/shared/source-location.d.ts +5 -0
  109. package/dist/shared/source-location.d.ts.map +1 -1
  110. package/dist/shared/source-location.js +7 -0
  111. package/dist/shared/source-location.js.map +1 -1
  112. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  113. package/dist/type-extractor/converter/graphql-converter.js +21 -7
  114. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  115. package/dist/type-extractor/extractor/field-type-resolver.js +42 -3
  116. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  117. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  118. package/dist/type-extractor/extractor/type-extractor.js +88 -23
  119. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  120. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  121. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  122. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +10 -2
  123. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
  124. package/dist/type-extractor/types/ts-type-reference-factory.js +8 -2
  125. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
  126. package/dist/type-extractor/types/typescript.d.ts +4 -0
  127. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  128. package/docs/coding-agents.md +64 -0
  129. package/docs/configuration.md +6 -20
  130. package/docs/getting-started.md +15 -12
  131. package/docs/index.md +36 -22
  132. package/docs/integration/apollo.md +8 -40
  133. package/docs/integration/drizzle.md +6 -10
  134. package/docs/integration/prisma.md +196 -0
  135. package/docs/integration/yoga.md +8 -40
  136. package/docs/schema/abstract-resolvers.md +117 -0
  137. package/docs/schema/directives.md +5 -0
  138. package/docs/schema/documentation.md +5 -0
  139. package/docs/schema/enums.md +99 -0
  140. package/docs/schema/fields.md +64 -0
  141. package/docs/schema/index.md +21 -0
  142. package/docs/schema/inputs.md +115 -15
  143. package/docs/schema/interfaces.md +31 -1
  144. package/docs/schema/objects.md +40 -0
  145. package/docs/schema/queries-mutations.md +136 -22
  146. package/docs/schema/scalars.md +5 -0
  147. package/docs/schema/unions.md +208 -1
  148. package/docs/what-is-gqlkit.md +13 -8
  149. package/package.json +6 -4
  150. package/src/auto-type-generator/auto-type-generator.ts +946 -201
  151. package/src/auto-type-generator/index.ts +42 -0
  152. package/src/auto-type-generator/inline-enum-collector.ts +187 -139
  153. package/src/auto-type-generator/inline-object-traverser.ts +49 -0
  154. package/src/auto-type-generator/inline-union-collector.ts +402 -0
  155. package/src/auto-type-generator/inline-union-types.ts +33 -0
  156. package/src/auto-type-generator/inline-union-validator.ts +482 -0
  157. package/src/auto-type-generator/naming-convention.ts +38 -1
  158. package/src/auto-type-generator/resolve-type-generator.ts +21 -0
  159. package/src/auto-type-generator/resolver-field-iterator.ts +39 -0
  160. package/src/auto-type-generator/typename-extractor.ts +230 -0
  161. package/src/auto-type-generator/typename-resolve-type-generator.ts +281 -0
  162. package/src/auto-type-generator/typename-types.ts +66 -0
  163. package/src/auto-type-generator/typename-validator.ts +326 -0
  164. package/src/cli.ts +2 -0
  165. package/src/commands/docs.ts +211 -0
  166. package/src/gen-orchestrator/orchestrator.ts +20 -6
  167. package/src/resolver-extractor/extract-resolvers.ts +19 -0
  168. package/src/resolver-extractor/extractor/define-api-extractor.ts +23 -89
  169. package/src/resolver-extractor/index.ts +0 -6
  170. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +16 -8
  171. package/src/schema-generator/emitter/code-emitter.ts +34 -0
  172. package/src/schema-generator/generate-schema.ts +99 -2
  173. package/src/schema-generator/integrator/result-integrator.ts +70 -1
  174. package/src/schema-generator/resolver-collector/resolver-collector.ts +34 -0
  175. package/src/shared/enum-prefix-detector.ts +99 -0
  176. package/src/shared/ignore-fields-detector.ts +109 -0
  177. package/src/shared/ignore-fields-validator.ts +66 -0
  178. package/src/shared/index.ts +2 -0
  179. package/src/shared/source-location.ts +11 -0
  180. package/src/type-extractor/converter/graphql-converter.ts +31 -7
  181. package/src/type-extractor/extractor/field-type-resolver.ts +48 -3
  182. package/src/type-extractor/extractor/type-extractor.ts +103 -26
  183. package/src/type-extractor/types/diagnostics.ts +12 -2
  184. package/src/type-extractor/types/ts-type-reference-factory.ts +18 -5
  185. package/src/type-extractor/types/typescript.ts +4 -0
  186. package/dist/resolver-extractor/validator/only-validator.d.ts +0 -61
  187. package/dist/resolver-extractor/validator/only-validator.d.ts.map +0 -1
  188. package/dist/resolver-extractor/validator/only-validator.js +0 -76
  189. package/dist/resolver-extractor/validator/only-validator.js.map +0 -1
  190. package/src/resolver-extractor/validator/only-validator.ts +0 -158
@@ -1,10 +1,45 @@
1
+ import { detectEnumPrefix, stripEnumPrefix, } from "../shared/enum-prefix-detector.js";
2
+ import { getSourceLocationOrDefault } from "../shared/source-location.js";
1
3
  import { convertTsTypeToGraphQLType } from "../shared/type-converter.js";
2
4
  import { isEligibleAsInputObjectField, isEligibleAsObjectField, } from "../type-extractor/converter/field-eligibility.js";
3
5
  import { createReferenceType, } from "../type-extractor/types/index.js";
4
- import { collectInlineEnumsFromResolvers, collectInlineEnumsFromTypes, } from "./inline-enum-collector.js";
5
- import { buildFieldContext, generateAutoTypeName, } from "./naming-convention.js";
6
- function isInputTypeName(name) {
7
- return name.endsWith("Input");
6
+ import { collectInlineEnumsFromPayloads, collectInlineEnumsFromResolvers, collectInlineEnumsFromTypes, } from "./inline-enum-collector.js";
7
+ import { collectInlineUnionsFromPayloads, collectInlineUnionsFromResolvers, collectInlineUnionsFromTypes, } from "./inline-union-collector.js";
8
+ import { validateOneOfMembers, validateUnionMembers, validateUnionMemberTypenames, } from "./inline-union-validator.js";
9
+ import { buildFieldContext, generateAutoTypeName, isInputTypeName, } from "./naming-convention.js";
10
+ import { forEachResolverField } from "./resolver-field-iterator.js";
11
+ import { createFieldNameSet, findTypenameProperty, } from "./typename-types.js";
12
+ function extractNestedInlineObjectsRecursively(params) {
13
+ const { properties, currentPath, sourceLocation, buildContext, preserveDocumentation, results, } = params;
14
+ for (const prop of properties) {
15
+ if (prop.tsType.kind === "inlineObject" &&
16
+ prop.tsType.inlineObjectProperties) {
17
+ const nestedPath = [...currentPath, prop.name];
18
+ const nestedContext = buildContext(nestedPath);
19
+ // Use property's source location if available for more accurate diagnostics
20
+ const nestedSourceLocation = prop.sourceLocation ?? sourceLocation;
21
+ results.push({
22
+ properties: prop.tsType.inlineObjectProperties,
23
+ context: nestedContext,
24
+ sourceLocation: nestedSourceLocation,
25
+ nullable: prop.tsType.nullable,
26
+ description: preserveDocumentation
27
+ ? prop.tsType.inlineObjectDescription
28
+ : null,
29
+ deprecated: preserveDocumentation
30
+ ? prop.tsType.inlineObjectDeprecated
31
+ : null,
32
+ });
33
+ extractNestedInlineObjectsRecursively({
34
+ properties: prop.tsType.inlineObjectProperties,
35
+ currentPath: nestedPath,
36
+ sourceLocation: nestedSourceLocation,
37
+ buildContext,
38
+ preserveDocumentation,
39
+ results,
40
+ });
41
+ }
42
+ }
8
43
  }
9
44
  function getContextKey(context) {
10
45
  switch (context.kind) {
@@ -14,6 +49,8 @@ function getContextKey(context) {
14
49
  return `inputField:${context.parentTypeName}:${context.fieldPath.join(".")}`;
15
50
  case "resolverArg":
16
51
  return `resolverArg:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.argName}:${context.fieldPath.join(".")}`;
52
+ case "resolverPayload":
53
+ return `resolverPayload:${context.resolverType}:${context.parentTypeName ?? ""}:${context.fieldName}:${context.fieldPath.join(".")}`;
17
54
  }
18
55
  }
19
56
  function mapContextKindToGeneratedFromContext(kind) {
@@ -24,6 +61,8 @@ function mapContextKindToGeneratedFromContext(kind) {
24
61
  return "inputField";
25
62
  case "resolverArg":
26
63
  return "resolverArg";
64
+ case "resolverPayload":
65
+ return "resolverPayload";
27
66
  }
28
67
  }
29
68
  function buildGeneratedFromInfo(context) {
@@ -61,78 +100,31 @@ function collectInlineObjectsFromField(field, parentTypeName, parentPath, isInpu
61
100
  parentTypeName,
62
101
  fieldPath,
63
102
  };
103
+ const sourceLocation = getSourceLocationOrDefault(field.sourceLocation, sourceFile);
64
104
  results.push({
65
105
  properties: tsType.inlineObjectProperties,
66
106
  context,
67
- sourceLocation: field.sourceLocation ?? {
68
- file: sourceFile,
69
- line: 1,
70
- column: 1,
71
- },
107
+ sourceLocation,
72
108
  nullable: tsType.nullable,
109
+ description: tsType.inlineObjectDescription,
110
+ deprecated: tsType.inlineObjectDeprecated,
73
111
  });
74
- for (const prop of tsType.inlineObjectProperties) {
75
- if (prop.tsType.kind === "inlineObject" &&
76
- prop.tsType.inlineObjectProperties) {
77
- const nestedPath = [...fieldPath, prop.name];
78
- const nestedContext = isInput
79
- ? {
80
- kind: "inputField",
81
- parentTypeName,
82
- fieldPath: nestedPath,
83
- }
84
- : {
85
- kind: "objectField",
86
- parentTypeName,
87
- fieldPath: nestedPath,
88
- };
89
- extractNestedInlineObjects(prop.tsType.inlineObjectProperties, nestedContext, nestedPath, parentTypeName, isInput, sourceFile, prop.sourceLocation, results);
90
- }
91
- }
92
- }
93
- function extractNestedInlineObjects(properties, context, currentPath, parentTypeName, isInput, sourceFile, parentSourceLocation, results) {
94
- results.push({
95
- properties,
96
- context,
97
- sourceLocation: parentSourceLocation ?? {
98
- file: sourceFile,
99
- line: 1,
100
- column: 1,
101
- },
102
- nullable: false,
112
+ extractNestedInlineObjectsRecursively({
113
+ properties: tsType.inlineObjectProperties,
114
+ currentPath: fieldPath,
115
+ sourceLocation,
116
+ buildContext: (nestedPath) => isInput
117
+ ? { kind: "inputField", parentTypeName, fieldPath: nestedPath }
118
+ : { kind: "objectField", parentTypeName, fieldPath: nestedPath },
119
+ preserveDocumentation: true,
120
+ results,
103
121
  });
104
- for (const prop of properties) {
105
- if (prop.tsType.kind === "inlineObject" &&
106
- prop.tsType.inlineObjectProperties) {
107
- const nestedPath = [...currentPath, prop.name];
108
- const nestedContext = isInput
109
- ? {
110
- kind: "inputField",
111
- parentTypeName,
112
- fieldPath: nestedPath,
113
- }
114
- : {
115
- kind: "objectField",
116
- parentTypeName,
117
- fieldPath: nestedPath,
118
- };
119
- extractNestedInlineObjects(prop.tsType.inlineObjectProperties, nestedContext, nestedPath, parentTypeName, isInput, sourceFile, prop.sourceLocation, results);
120
- }
121
- }
122
122
  }
123
123
  function collectInlineObjectsFromResolvers(resolversResult) {
124
124
  const results = [];
125
- for (const field of resolversResult.queryFields.fields) {
126
- collectInlineObjectsFromResolverArgs(field, "query", null, results);
127
- }
128
- for (const field of resolversResult.mutationFields.fields) {
129
- collectInlineObjectsFromResolverArgs(field, "mutation", null, results);
130
- }
131
- for (const ext of resolversResult.typeExtensions) {
132
- for (const field of ext.fields) {
133
- collectInlineObjectsFromResolverArgs(field, "field", ext.targetTypeName, results);
134
- }
135
- }
125
+ forEachResolverField(resolversResult, ({ field, resolverType, parentTypeName }) => {
126
+ collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeName, results);
127
+ });
136
128
  return results;
137
129
  }
138
130
  function collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeName, results) {
@@ -154,35 +146,68 @@ function collectInlineObjectsFromResolverArgs(field, resolverType, parentTypeNam
154
146
  context,
155
147
  sourceLocation: field.sourceLocation,
156
148
  nullable: arg.type.nullable,
149
+ description: null,
150
+ deprecated: null,
157
151
  });
158
- extractNestedInlineObjectsFromArg(arg.inlineObjectProperties, resolverType, field.name, arg.name, parentTypeName, [], field.sourceLocation, results);
159
- }
160
- }
161
- function extractNestedInlineObjectsFromArg(properties, resolverType, fieldName, argName, parentTypeName, currentPath, sourceLocation, results) {
162
- for (const prop of properties) {
163
- if (prop.tsType.kind === "inlineObject" &&
164
- prop.tsType.inlineObjectProperties) {
165
- const nestedPath = [...currentPath, prop.name];
166
- const nestedContext = {
152
+ extractNestedInlineObjectsRecursively({
153
+ properties: arg.inlineObjectProperties,
154
+ currentPath: [],
155
+ sourceLocation: field.sourceLocation,
156
+ buildContext: (nestedPath) => ({
167
157
  kind: "resolverArg",
168
158
  resolverType,
169
- fieldName,
170
- argName,
159
+ fieldName: field.name,
160
+ argName: arg.name,
171
161
  parentTypeName,
172
162
  fieldPath: nestedPath,
173
- };
174
- results.push({
175
- properties: prop.tsType.inlineObjectProperties,
176
- context: nestedContext,
177
- sourceLocation,
178
- nullable: prop.tsType.nullable,
179
- });
180
- extractNestedInlineObjectsFromArg(prop.tsType.inlineObjectProperties, resolverType, fieldName, argName, parentTypeName, nestedPath, sourceLocation, results);
181
- }
163
+ }),
164
+ preserveDocumentation: false,
165
+ results,
166
+ });
182
167
  }
183
168
  }
169
+ function collectInlinePayloadsFromResolvers(resolversResult) {
170
+ const results = [];
171
+ forEachResolverField(resolversResult, ({ field, resolverType, parentTypeName }) => {
172
+ collectInlinePayloadFromReturnType(field, resolverType, parentTypeName, results);
173
+ });
174
+ return results;
175
+ }
176
+ function collectInlinePayloadFromReturnType(field, resolverType, parentTypeName, results) {
177
+ if (!field.returnTypeInlineObjectProperties)
178
+ return;
179
+ const context = {
180
+ kind: "resolverPayload",
181
+ resolverType,
182
+ fieldName: field.name,
183
+ parentTypeName,
184
+ fieldPath: [],
185
+ };
186
+ results.push({
187
+ properties: field.returnTypeInlineObjectProperties,
188
+ context,
189
+ sourceLocation: field.sourceLocation,
190
+ nullable: field.type.nullable,
191
+ description: field.returnTypeInlineObjectDescription,
192
+ deprecated: field.returnTypeInlineObjectDeprecated,
193
+ });
194
+ extractNestedInlineObjectsRecursively({
195
+ properties: field.returnTypeInlineObjectProperties,
196
+ currentPath: [],
197
+ sourceLocation: field.sourceLocation,
198
+ buildContext: (nestedPath) => ({
199
+ kind: "resolverPayload",
200
+ resolverType,
201
+ fieldName: field.name,
202
+ parentTypeName,
203
+ fieldPath: nestedPath,
204
+ }),
205
+ preserveDocumentation: true,
206
+ results,
207
+ });
208
+ }
184
209
  function generateAutoType(params) {
185
- const { inlineObj, generatedTypeNames, enumTypeNames } = params;
210
+ const { inlineObj, generatedTypeNames, enumTypeNames, unionTypeNames } = params;
186
211
  const name = generateAutoTypeName(inlineObj.context);
187
212
  const isInput = inlineObj.context.kind === "inputField" ||
188
213
  inlineObj.context.kind === "resolverArg";
@@ -205,6 +230,7 @@ function generateAutoType(params) {
205
230
  prop,
206
231
  generatedTypeNames,
207
232
  enumTypeNames,
233
+ unionTypeNames,
208
234
  parentContext: inlineObj.context,
209
235
  });
210
236
  fields.push({
@@ -222,50 +248,51 @@ function generateAutoType(params) {
222
248
  kind: isInput ? "InputObject" : "Object",
223
249
  fields,
224
250
  enumValues: null,
251
+ unionMembers: null,
225
252
  needsStringEnumMapping: false,
226
253
  sourceLocation: inlineObj.sourceLocation,
227
254
  generatedFrom: buildGeneratedFromInfo(inlineObj.context),
228
- description: null,
255
+ description: inlineObj.description,
256
+ resolveTypeFieldPattern: null,
229
257
  },
230
258
  diagnostics,
231
259
  };
232
260
  }
261
+ function tryResolveNestedType(prop, parentContext, typeNamesMap) {
262
+ const nestedPath = [...parentContext.fieldPath, prop.name];
263
+ const nestedContext = {
264
+ ...parentContext,
265
+ fieldPath: nestedPath,
266
+ };
267
+ const contextKey = getContextKey(nestedContext);
268
+ const resolvedTypeName = typeNamesMap.get(contextKey);
269
+ if (resolvedTypeName) {
270
+ return {
271
+ typeName: resolvedTypeName,
272
+ nullable: prop.tsType.nullable || prop.optional,
273
+ list: false,
274
+ listItemNullable: null,
275
+ };
276
+ }
277
+ return null;
278
+ }
233
279
  function resolveFieldType(params) {
234
- const { prop, generatedTypeNames, enumTypeNames, parentContext } = params;
280
+ const { prop, generatedTypeNames, enumTypeNames, unionTypeNames, parentContext, } = params;
235
281
  if (prop.tsType.kind === "inlineObject" &&
236
282
  prop.tsType.inlineObjectProperties) {
237
- const nestedPath = [...parentContext.fieldPath, prop.name];
238
- const nestedContext = {
239
- ...parentContext,
240
- fieldPath: nestedPath,
241
- };
242
- const contextKey = getContextKey(nestedContext);
243
- const resolvedTypeName = generatedTypeNames.get(contextKey);
244
- if (resolvedTypeName) {
245
- return {
246
- typeName: resolvedTypeName,
247
- nullable: prop.tsType.nullable || prop.optional,
248
- list: false,
249
- listItemNullable: null,
250
- };
251
- }
283
+ const result = tryResolveNestedType(prop, parentContext, generatedTypeNames);
284
+ if (result)
285
+ return result;
252
286
  }
253
287
  if (prop.tsType.kind === "inlineEnum" && prop.tsType.inlineEnumMembers) {
254
- const nestedPath = [...parentContext.fieldPath, prop.name];
255
- const nestedContext = {
256
- ...parentContext,
257
- fieldPath: nestedPath,
258
- };
259
- const contextKey = getContextKey(nestedContext);
260
- const resolvedTypeName = enumTypeNames.get(contextKey);
261
- if (resolvedTypeName) {
262
- return {
263
- typeName: resolvedTypeName,
264
- nullable: prop.tsType.nullable || prop.optional,
265
- list: false,
266
- listItemNullable: null,
267
- };
268
- }
288
+ const result = tryResolveNestedType(prop, parentContext, enumTypeNames);
289
+ if (result)
290
+ return result;
291
+ }
292
+ if (prop.tsType.kind === "union" && prop.tsType.members) {
293
+ const result = tryResolveNestedType(prop, parentContext, unionTypeNames);
294
+ if (result)
295
+ return result;
269
296
  }
270
297
  return convertTsTypeToGraphQLType(prop.tsType, prop.optional);
271
298
  }
@@ -279,7 +306,7 @@ function updateExtractedTypes(extractedTypes, params) {
279
306
  });
280
307
  }
281
308
  function updateField(field, params, parentTypeName, isInput) {
282
- const { generatedTypeNames, enumTypeNames } = params;
309
+ const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
283
310
  const context = buildFieldContext(parentTypeName, [field.name], isInput);
284
311
  const contextKey = getContextKey(context);
285
312
  // Handle inline objects
@@ -327,6 +354,19 @@ function updateField(field, params, parentTypeName, isInput) {
327
354
  };
328
355
  }
329
356
  }
357
+ // Handle inline union types
358
+ if (field.tsType.kind === "union" && field.tsType.members) {
359
+ const resolvedTypeName = unionTypeNames.get(contextKey);
360
+ if (resolvedTypeName) {
361
+ return {
362
+ ...field,
363
+ tsType: createReferenceType({
364
+ name: resolvedTypeName,
365
+ nullable: field.tsType.nullable,
366
+ }),
367
+ };
368
+ }
369
+ }
330
370
  return field;
331
371
  }
332
372
  function updateResolversResult(resolversResult, params) {
@@ -345,9 +385,51 @@ function updateResolversResult(resolversResult, params) {
345
385
  };
346
386
  }
347
387
  function updateResolverField(field, params, resolverType, parentTypeName) {
348
- if (!field.args)
349
- return field;
350
- const { generatedTypeNames, enumTypeNames } = params;
388
+ const { generatedTypeNames, enumTypeNames, unionTypeNames } = params;
389
+ let updatedType = field.type;
390
+ // Create payload context once for all inline return type checks
391
+ const hasInlinePayload = field.returnTypeInlineObjectProperties ||
392
+ field.returnTypeInlineEnumMembers ||
393
+ field.returnTypeInlineUnionMembers;
394
+ if (hasInlinePayload) {
395
+ const payloadContext = {
396
+ kind: "resolverPayload",
397
+ resolverType,
398
+ fieldName: field.name,
399
+ parentTypeName,
400
+ fieldPath: [],
401
+ };
402
+ const payloadContextKey = getContextKey(payloadContext);
403
+ // These are mutually exclusive - a return type can only be one of:
404
+ // inline object, inline enum, or inline union
405
+ if (field.returnTypeInlineObjectProperties) {
406
+ // Handle inline payload objects in return type
407
+ const resolvedTypeName = generatedTypeNames.get(payloadContextKey);
408
+ if (resolvedTypeName) {
409
+ updatedType = { ...field.type, typeName: resolvedTypeName };
410
+ }
411
+ }
412
+ else if (field.returnTypeInlineEnumMembers) {
413
+ // Handle inline enum in return type
414
+ const resolvedTypeName = enumTypeNames.get(payloadContextKey);
415
+ if (resolvedTypeName) {
416
+ updatedType = { ...field.type, typeName: resolvedTypeName };
417
+ }
418
+ }
419
+ else if (field.returnTypeInlineUnionMembers) {
420
+ // Handle inline union in return type
421
+ const resolvedTypeName = unionTypeNames.get(payloadContextKey);
422
+ if (resolvedTypeName) {
423
+ updatedType = { ...field.type, typeName: resolvedTypeName };
424
+ }
425
+ }
426
+ }
427
+ if (!field.args) {
428
+ return {
429
+ ...field,
430
+ type: updatedType,
431
+ };
432
+ }
351
433
  const updatedArgs = field.args.map((arg) => {
352
434
  const context = {
353
435
  kind: "resolverArg",
@@ -384,10 +466,24 @@ function updateResolverField(field, params, resolverType, parentTypeName) {
384
466
  };
385
467
  }
386
468
  }
469
+ // Handle inline unions (OneOf input objects)
470
+ if (arg.inlineUnionMembers) {
471
+ const resolvedTypeName = unionTypeNames.get(contextKey);
472
+ if (resolvedTypeName) {
473
+ return {
474
+ ...arg,
475
+ type: {
476
+ ...arg.type,
477
+ typeName: resolvedTypeName,
478
+ },
479
+ };
480
+ }
481
+ }
387
482
  return arg;
388
483
  });
389
484
  return {
390
485
  ...field,
486
+ type: updatedType,
391
487
  args: updatedArgs,
392
488
  };
393
489
  }
@@ -412,27 +508,40 @@ function convertInlineEnumMembers(params) {
412
508
  let needsStringEnumMapping = false;
413
509
  const enumValues = [];
414
510
  const diagnostics = [];
415
- const convertedNameToOriginals = new Map();
511
+ const convertedMembers = [];
416
512
  for (const member of members) {
417
513
  const convertedName = toScreamingSnakeCase(member.value);
418
- if (convertedName !== member.value) {
514
+ convertedMembers.push({ convertedName, member });
515
+ }
516
+ const prefixDetectionResult = detectEnumPrefix({
517
+ enumName,
518
+ memberValues: convertedMembers.map((m) => m.convertedName),
519
+ });
520
+ const finalNameToOriginals = new Map();
521
+ for (const { convertedName, member } of convertedMembers) {
522
+ let finalName = convertedName;
523
+ if (prefixDetectionResult.shouldStrip && prefixDetectionResult.prefix) {
524
+ finalName = stripEnumPrefix(convertedName, prefixDetectionResult.prefix);
525
+ needsStringEnumMapping = true;
526
+ }
527
+ else if (convertedName !== member.value) {
419
528
  needsStringEnumMapping = true;
420
529
  }
421
- const originals = convertedNameToOriginals.get(convertedName) ?? [];
530
+ const originals = finalNameToOriginals.get(finalName) ?? [];
422
531
  originals.push(member.value);
423
- convertedNameToOriginals.set(convertedName, originals);
532
+ finalNameToOriginals.set(finalName, originals);
424
533
  enumValues.push({
425
- name: convertedName,
534
+ name: finalName,
426
535
  originalValue: member.value,
427
536
  description: member.description,
428
537
  deprecated: member.deprecated,
429
538
  });
430
539
  }
431
- for (const [convertedName, originals] of convertedNameToOriginals) {
540
+ for (const [finalName, originals] of finalNameToOriginals) {
432
541
  if (originals.length > 1) {
433
542
  diagnostics.push({
434
543
  code: "DUPLICATE_ENUM_VALUE_AFTER_CONVERSION",
435
- message: `Enum '${enumName}' has duplicate value '${convertedName}' after conversion (from '${originals.join("' and '")}')`,
544
+ message: `Enum '${enumName}' has duplicate value '${finalName}' after conversion (from '${originals.join("' and '")}')`,
436
545
  severity: "error",
437
546
  location: sourceLocation,
438
547
  });
@@ -452,10 +561,12 @@ function generateAutoEnumType(inlineEnum, typeName) {
452
561
  kind: "Enum",
453
562
  fields: null,
454
563
  enumValues,
564
+ unionMembers: null,
455
565
  needsStringEnumMapping,
456
566
  sourceLocation: inlineEnum.sourceLocation,
457
567
  generatedFrom: buildGeneratedFromInfo(inlineEnum.context),
458
568
  description: inlineEnum.externalEnumDescription,
569
+ resolveTypeFieldPattern: null,
459
570
  },
460
571
  diagnostics,
461
572
  };
@@ -491,21 +602,404 @@ function buildEnumTypeNamesMap(inlineEnums) {
491
602
  uniqueInlineEnums,
492
603
  };
493
604
  }
605
+ function buildUnionTypeNamesMap(inlineUnions) {
606
+ const unionTypeNames = new Map();
607
+ for (const inlineUnion of inlineUnions) {
608
+ const contextKey = getContextKey(inlineUnion.context);
609
+ const typeName = generateAutoTypeName(inlineUnion.context);
610
+ unionTypeNames.set(contextKey, typeName);
611
+ }
612
+ return unionTypeNames;
613
+ }
614
+ function processOneOfInputObjects(params) {
615
+ const { inlineUnions, knownTypeNames, typeMap, unionTypeNames } = params;
616
+ const types = [];
617
+ const diagnostics = [];
618
+ for (const inlineUnion of inlineUnions) {
619
+ const contextKey = getContextKey(inlineUnion.context);
620
+ const typeName = generateAutoTypeName(inlineUnion.context);
621
+ const validationResult = validateOneOfMembers({
622
+ members: inlineUnion.members,
623
+ typeName,
624
+ sourceLocation: inlineUnion.sourceLocation,
625
+ typeMap,
626
+ });
627
+ diagnostics.push(...validationResult.diagnostics);
628
+ if (!validationResult.valid) {
629
+ continue;
630
+ }
631
+ const fields = generateOneOfFields({
632
+ members: inlineUnion.members,
633
+ knownTypeNames,
634
+ });
635
+ types.push({
636
+ name: typeName,
637
+ kind: "OneOfInputObject",
638
+ fields,
639
+ enumValues: null,
640
+ unionMembers: null,
641
+ needsStringEnumMapping: false,
642
+ sourceLocation: inlineUnion.sourceLocation,
643
+ generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
644
+ description: null,
645
+ resolveTypeFieldPattern: null,
646
+ });
647
+ unionTypeNames.set(contextKey, typeName);
648
+ }
649
+ return { types, diagnostics };
650
+ }
651
+ function processUnionTypes(params) {
652
+ const { inlineUnions, knownTypeNames, generatedTypeNames, enumTypeNames, unionTypeNames, typeMap, } = params;
653
+ const types = [];
654
+ const diagnostics = [];
655
+ const generatedTypenameTypes = new Map();
656
+ for (const inlineUnion of inlineUnions) {
657
+ const contextKey = getContextKey(inlineUnion.context);
658
+ const typeName = generateAutoTypeName(inlineUnion.context);
659
+ const validationResult = validateUnionMembers({
660
+ members: inlineUnion.members,
661
+ typeName,
662
+ sourceLocation: inlineUnion.sourceLocation,
663
+ typeMap,
664
+ });
665
+ diagnostics.push(...validationResult.diagnostics);
666
+ if (!validationResult.valid) {
667
+ continue;
668
+ }
669
+ let resolveTypeFieldPattern = null;
670
+ if (inlineUnion.context.kind === "resolverPayload") {
671
+ const typenameValidationResult = validateUnionMemberTypenames({
672
+ members: inlineUnion.members,
673
+ unionTypeName: typeName,
674
+ sourceLocation: inlineUnion.sourceLocation,
675
+ typeMap,
676
+ });
677
+ diagnostics.push(...typenameValidationResult.diagnostics);
678
+ if (!typenameValidationResult.valid) {
679
+ continue;
680
+ }
681
+ if (typenameValidationResult.allMembersHaveTypename) {
682
+ resolveTypeFieldPattern = determineFieldPattern(typenameValidationResult.memberTypenames);
683
+ }
684
+ }
685
+ const memberNames = resolveMemberNames({
686
+ members: inlineUnion.members,
687
+ knownTypeNames,
688
+ generatedTypeNames,
689
+ enumTypeNames,
690
+ parentContext: inlineUnion.context,
691
+ unionTypeNames,
692
+ types,
693
+ diagnostics,
694
+ generatedTypenameTypes,
695
+ sourceLocation: inlineUnion.sourceLocation,
696
+ });
697
+ types.push({
698
+ name: typeName,
699
+ kind: "Union",
700
+ fields: null,
701
+ enumValues: null,
702
+ unionMembers: memberNames,
703
+ needsStringEnumMapping: false,
704
+ sourceLocation: inlineUnion.sourceLocation,
705
+ generatedFrom: buildGeneratedFromInfo(inlineUnion.context),
706
+ description: null,
707
+ resolveTypeFieldPattern,
708
+ });
709
+ unionTypeNames.set(contextKey, typeName);
710
+ }
711
+ return { types, diagnostics };
712
+ }
713
+ /**
714
+ * Determine the field pattern for resolveType based on the typename fields used by members.
715
+ */
716
+ function determineFieldPattern(memberTypenames) {
717
+ const fieldNames = new Set();
718
+ for (const info of memberTypenames.values()) {
719
+ fieldNames.add(info.fieldName);
720
+ }
721
+ if (fieldNames.size === 0) {
722
+ return { usedFieldNames: createFieldNameSet(["__typename"]) };
723
+ }
724
+ return { usedFieldNames: fieldNames };
725
+ }
726
+ function processInlineUnions(params) {
727
+ const { inlineUnions, knownTypeNames, generatedTypeNames, enumTypeNames, unionTypeNames, extractedTypes, } = params;
728
+ const typeMap = new Map();
729
+ for (const typeInfo of extractedTypes) {
730
+ typeMap.set(typeInfo.metadata.name, typeInfo);
731
+ }
732
+ const inputUnions = inlineUnions.filter((u) => u.isInputContext);
733
+ const outputUnions = inlineUnions.filter((u) => !u.isInputContext);
734
+ const oneOfResult = processOneOfInputObjects({
735
+ inlineUnions: inputUnions,
736
+ knownTypeNames,
737
+ typeMap,
738
+ unionTypeNames,
739
+ });
740
+ const unionResult = processUnionTypes({
741
+ inlineUnions: outputUnions,
742
+ knownTypeNames,
743
+ generatedTypeNames,
744
+ enumTypeNames,
745
+ unionTypeNames,
746
+ typeMap,
747
+ });
748
+ return {
749
+ types: [...oneOfResult.types, ...unionResult.types],
750
+ diagnostics: [...oneOfResult.diagnostics, ...unionResult.diagnostics],
751
+ };
752
+ }
753
+ function generateOneOfFields(params) {
754
+ const { members, knownTypeNames } = params;
755
+ const fields = [];
756
+ for (const member of members) {
757
+ const memberType = member.memberType;
758
+ if (memberType.kind === "inlineObject" &&
759
+ memberType.inlineObjectProperties) {
760
+ for (const prop of memberType.inlineObjectProperties) {
761
+ const fieldType = convertTsTypeToGraphQLType(prop.tsType, prop.optional);
762
+ fields.push({
763
+ name: prop.name,
764
+ type: {
765
+ ...fieldType,
766
+ nullable: true,
767
+ },
768
+ description: prop.description,
769
+ deprecated: prop.deprecated,
770
+ directives: prop.directives,
771
+ defaultValue: prop.defaultValue,
772
+ });
773
+ }
774
+ }
775
+ else if (memberType.kind === "reference" && memberType.name) {
776
+ if (knownTypeNames.has(memberType.name)) {
777
+ const camelCaseName = memberType.name.charAt(0).toLowerCase() + memberType.name.slice(1);
778
+ fields.push({
779
+ name: camelCaseName,
780
+ type: {
781
+ typeName: memberType.name,
782
+ nullable: true,
783
+ list: false,
784
+ listItemNullable: null,
785
+ },
786
+ description: null,
787
+ deprecated: null,
788
+ directives: null,
789
+ defaultValue: null,
790
+ });
791
+ }
792
+ }
793
+ }
794
+ return fields;
795
+ }
796
+ /**
797
+ * Extract __typename or $typeName property value from inline object properties.
798
+ * Returns null if neither is found or neither is a valid string literal.
799
+ * __typename takes priority over $typeName if both are present.
800
+ */
801
+ function extractTypenameFromInlineObject(properties) {
802
+ const found = findTypenameProperty(properties, (p) => p.name);
803
+ if (!found) {
804
+ return null;
805
+ }
806
+ const { property, fieldName } = found;
807
+ const { tsType } = property;
808
+ if (tsType.kind === "literal" && tsType.name !== null) {
809
+ return { typeName: tsType.name, fieldName };
810
+ }
811
+ return null;
812
+ }
813
+ function resolveMemberNames(params) {
814
+ const { members, generatedTypeNames, parentContext, types, generatedTypenameTypes, diagnostics, sourceLocation, } = params;
815
+ const memberNames = [];
816
+ for (let i = 0; i < members.length; i++) {
817
+ const member = members[i];
818
+ const memberType = member.memberType;
819
+ if (memberType.kind === "reference" && memberType.name) {
820
+ memberNames.push(memberType.name);
821
+ }
822
+ else if (memberType.kind === "inlineObject" &&
823
+ memberType.inlineObjectProperties) {
824
+ // Only extract __typename or $typeName for resolverPayload context
825
+ // For other contexts (resolverArg, objectField, inputField), these fields
826
+ // should be treated as regular fields, not as type discriminators
827
+ const extractedInfo = parentContext.kind === "resolverPayload"
828
+ ? extractTypenameFromInlineObject(memberType.inlineObjectProperties)
829
+ : null;
830
+ let memberTypeName;
831
+ let contextKey;
832
+ if (extractedInfo !== null) {
833
+ memberTypeName = extractedInfo.typeName;
834
+ const nestedContext = {
835
+ ...parentContext,
836
+ fieldPath: [...parentContext.fieldPath, extractedInfo.typeName],
837
+ };
838
+ contextKey = getContextKey(nestedContext);
839
+ }
840
+ else {
841
+ const nestedContext = {
842
+ ...parentContext,
843
+ fieldPath: [...parentContext.fieldPath, `member${i}`],
844
+ };
845
+ memberTypeName = generateAutoTypeName(nestedContext);
846
+ contextKey = getContextKey(nestedContext);
847
+ }
848
+ // Only filter out __typename or $typeName for resolverPayload context
849
+ // For other contexts, these are regular fields that should be preserved
850
+ const typenameFieldToFilter = extractedInfo?.fieldName ?? null;
851
+ const fields = memberType.inlineObjectProperties
852
+ .filter((prop) => parentContext.kind !== "resolverPayload" ||
853
+ prop.name !== typenameFieldToFilter)
854
+ .map((prop) => {
855
+ const fieldType = convertTsTypeToGraphQLType(prop.tsType, prop.optional);
856
+ return {
857
+ name: prop.name,
858
+ type: fieldType,
859
+ description: prop.description,
860
+ deprecated: prop.deprecated,
861
+ directives: prop.directives,
862
+ defaultValue: prop.defaultValue,
863
+ };
864
+ });
865
+ // Check if this typename was already seen with a different field structure
866
+ if (extractedInfo !== null) {
867
+ const existingFields = generatedTypenameTypes.get(extractedInfo.typeName);
868
+ if (existingFields !== undefined) {
869
+ // Compare field structures
870
+ if (!areFieldStructuresEqual(existingFields, fields)) {
871
+ diagnostics.push({
872
+ code: "TYPENAME_FIELD_STRUCTURE_MISMATCH",
873
+ 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.`,
874
+ severity: "error",
875
+ location: sourceLocation,
876
+ });
877
+ }
878
+ // Skip generating duplicate type and avoid adding duplicate union member
879
+ if (!memberNames.includes(memberTypeName)) {
880
+ memberNames.push(memberTypeName);
881
+ }
882
+ continue;
883
+ }
884
+ }
885
+ const nestedContext = {
886
+ ...parentContext,
887
+ fieldPath: [
888
+ ...parentContext.fieldPath,
889
+ extractedInfo?.typeName ?? `member${i}`,
890
+ ],
891
+ };
892
+ types.push({
893
+ name: memberTypeName,
894
+ kind: "Object",
895
+ fields,
896
+ enumValues: null,
897
+ unionMembers: null,
898
+ needsStringEnumMapping: false,
899
+ sourceLocation: {
900
+ file: "",
901
+ line: 1,
902
+ column: 1,
903
+ },
904
+ generatedFrom: buildGeneratedFromInfo(nestedContext),
905
+ description: memberType.inlineObjectDescription,
906
+ resolveTypeFieldPattern: null,
907
+ });
908
+ generatedTypeNames.set(contextKey, memberTypeName);
909
+ if (extractedInfo !== null) {
910
+ generatedTypenameTypes.set(extractedInfo.typeName, fields);
911
+ }
912
+ memberNames.push(memberTypeName);
913
+ }
914
+ }
915
+ return memberNames;
916
+ }
917
+ /**
918
+ * Compare two field structures for equality.
919
+ * Returns true if both have the same fields with the same types.
920
+ */
921
+ function areFieldStructuresEqual(fields1, fields2) {
922
+ if (fields1.length !== fields2.length) {
923
+ return false;
924
+ }
925
+ const sorted1 = [...fields1].sort((a, b) => a.name.localeCompare(b.name));
926
+ const sorted2 = [...fields2].sort((a, b) => a.name.localeCompare(b.name));
927
+ for (let i = 0; i < sorted1.length; i++) {
928
+ const f1 = sorted1[i];
929
+ const f2 = sorted2[i];
930
+ if (f1.name !== f2.name) {
931
+ return false;
932
+ }
933
+ if (!areGraphQLTypesEqual(f1.type, f2.type)) {
934
+ return false;
935
+ }
936
+ }
937
+ return true;
938
+ }
939
+ /**
940
+ * Compare two GraphQL type references for equality.
941
+ */
942
+ function areGraphQLTypesEqual(type1, type2) {
943
+ if (type1.typeName !== type2.typeName) {
944
+ return false;
945
+ }
946
+ if (type1.nullable !== type2.nullable) {
947
+ return false;
948
+ }
949
+ if (type1.list !== type2.list) {
950
+ return false;
951
+ }
952
+ if (type1.listItemNullable !== type2.listItemNullable) {
953
+ return false;
954
+ }
955
+ return true;
956
+ }
494
957
  export function generateAutoTypes(input) {
495
958
  const inlineObjectsFromTypes = [];
496
959
  for (const typeInfo of input.extractedTypes) {
497
960
  inlineObjectsFromTypes.push(...collectInlineObjectsFromType(typeInfo));
498
961
  }
499
962
  const inlineObjectsFromResolvers = collectInlineObjectsFromResolvers(input.resolversResult);
963
+ const inlinePayloadsFromResolvers = collectInlinePayloadsFromResolvers(input.resolversResult);
500
964
  const allInlineObjects = [
501
965
  ...inlineObjectsFromTypes,
502
966
  ...inlineObjectsFromResolvers,
967
+ ...inlinePayloadsFromResolvers,
503
968
  ];
504
969
  const generatedTypeNames = buildGeneratedTypeNamesMap(allInlineObjects);
505
970
  const inlineEnumsFromTypes = collectInlineEnumsFromTypes(input.extractedTypes);
506
- const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers(input.resolversResult);
507
- const allInlineEnums = [...inlineEnumsFromTypes, ...inlineEnumsFromResolvers];
971
+ const inlineEnumsFromResolvers = collectInlineEnumsFromResolvers({
972
+ resolversResult: input.resolversResult,
973
+ });
974
+ const inlineEnumsFromPayloads = collectInlineEnumsFromPayloads({
975
+ resolversResult: input.resolversResult,
976
+ });
977
+ const allInlineEnums = [
978
+ ...inlineEnumsFromTypes,
979
+ ...inlineEnumsFromResolvers,
980
+ ...inlineEnumsFromPayloads,
981
+ ];
508
982
  const { enumTypeNames, uniqueInlineEnums } = buildEnumTypeNamesMap(allInlineEnums);
983
+ // Collect inline unions from types, resolvers, and payloads
984
+ const inlineUnionsFromTypes = collectInlineUnionsFromTypes({
985
+ extractedTypes: input.extractedTypes,
986
+ knownTypeNames: input.knownTypeNames,
987
+ });
988
+ const inlineUnionsFromResolvers = collectInlineUnionsFromResolvers({
989
+ resolversResult: input.resolversResult,
990
+ knownTypeNames: input.knownTypeNames,
991
+ });
992
+ const inlineUnionsFromPayloads = collectInlineUnionsFromPayloads({
993
+ resolversResult: input.resolversResult,
994
+ knownTypeNames: input.knownTypeNames,
995
+ });
996
+ const allInlineUnions = [
997
+ ...inlineUnionsFromTypes,
998
+ ...inlineUnionsFromResolvers,
999
+ ...inlineUnionsFromPayloads,
1000
+ ];
1001
+ // Build union type names map before generating auto types
1002
+ const unionTypeNames = buildUnionTypeNamesMap(allInlineUnions);
509
1003
  const autoGeneratedTypes = [];
510
1004
  const diagnostics = [];
511
1005
  for (const inlineObj of allInlineObjects) {
@@ -513,6 +1007,7 @@ export function generateAutoTypes(input) {
513
1007
  inlineObj,
514
1008
  generatedTypeNames,
515
1009
  enumTypeNames,
1010
+ unionTypeNames,
516
1011
  });
517
1012
  autoGeneratedTypes.push(result.type);
518
1013
  diagnostics.push(...result.diagnostics);
@@ -524,9 +1019,21 @@ export function generateAutoTypes(input) {
524
1019
  autoGeneratedTypes.push(result.type);
525
1020
  diagnostics.push(...result.diagnostics);
526
1021
  }
1022
+ // Process inline unions
1023
+ const { types: unionTypes, diagnostics: unionDiagnostics } = processInlineUnions({
1024
+ inlineUnions: allInlineUnions,
1025
+ knownTypeNames: input.knownTypeNames,
1026
+ generatedTypeNames,
1027
+ enumTypeNames,
1028
+ unionTypeNames,
1029
+ extractedTypes: input.extractedTypes,
1030
+ });
1031
+ autoGeneratedTypes.push(...unionTypes);
1032
+ diagnostics.push(...unionDiagnostics);
527
1033
  const updateParams = {
528
1034
  generatedTypeNames,
529
1035
  enumTypeNames,
1036
+ unionTypeNames,
530
1037
  };
531
1038
  const updatedExtractedTypes = updateExtractedTypes(input.extractedTypes, updateParams);
532
1039
  const updatedResolversResult = updateResolversResult(input.resolversResult, updateParams);