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