@gqlkit-ts/cli 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/auto-type-generator/auto-type-generator.d.ts +7 -0
  2. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  3. package/dist/auto-type-generator/auto-type-generator.js +375 -55
  4. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  5. package/dist/auto-type-generator/discriminator-field-validator.d.ts +26 -0
  6. package/dist/auto-type-generator/discriminator-field-validator.d.ts.map +1 -0
  7. package/dist/auto-type-generator/discriminator-field-validator.js +242 -0
  8. package/dist/auto-type-generator/discriminator-field-validator.js.map +1 -0
  9. package/dist/auto-type-generator/discriminator-naming.d.ts +11 -0
  10. package/dist/auto-type-generator/discriminator-naming.d.ts.map +1 -0
  11. package/dist/auto-type-generator/discriminator-naming.js +15 -0
  12. package/dist/auto-type-generator/discriminator-naming.js.map +1 -0
  13. package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts +44 -0
  14. package/dist/auto-type-generator/discriminator-resolve-type-generator.d.ts.map +1 -0
  15. package/dist/auto-type-generator/discriminator-resolve-type-generator.js +77 -0
  16. package/dist/auto-type-generator/discriminator-resolve-type-generator.js.map +1 -0
  17. package/dist/auto-type-generator/index.d.ts +3 -0
  18. package/dist/auto-type-generator/index.d.ts.map +1 -1
  19. package/dist/auto-type-generator/index.js +3 -0
  20. package/dist/auto-type-generator/index.js.map +1 -1
  21. package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -1
  22. package/dist/auto-type-generator/inline-enum-collector.js +14 -7
  23. package/dist/auto-type-generator/inline-enum-collector.js.map +1 -1
  24. package/dist/auto-type-generator/inline-object-converter.d.ts +12 -0
  25. package/dist/auto-type-generator/inline-object-converter.d.ts.map +1 -0
  26. package/dist/auto-type-generator/inline-object-converter.js +72 -0
  27. package/dist/auto-type-generator/inline-object-converter.js.map +1 -0
  28. package/dist/auto-type-generator/inline-object-traverser.d.ts +2 -1
  29. package/dist/auto-type-generator/inline-object-traverser.d.ts.map +1 -1
  30. package/dist/auto-type-generator/inline-object-traverser.js +22 -4
  31. package/dist/auto-type-generator/inline-object-traverser.js.map +1 -1
  32. package/dist/auto-type-generator/inline-union-collector.d.ts.map +1 -1
  33. package/dist/auto-type-generator/inline-union-collector.js +20 -6
  34. package/dist/auto-type-generator/inline-union-collector.js.map +1 -1
  35. package/dist/auto-type-generator/inline-union-types.d.ts +2 -0
  36. package/dist/auto-type-generator/inline-union-types.d.ts.map +1 -1
  37. package/dist/auto-type-generator/inline-union-validator.js +3 -3
  38. package/dist/auto-type-generator/inline-union-validator.js.map +1 -1
  39. package/dist/auto-type-generator/intersection-flattener.d.ts +44 -0
  40. package/dist/auto-type-generator/intersection-flattener.d.ts.map +1 -0
  41. package/dist/auto-type-generator/intersection-flattener.js +398 -0
  42. package/dist/auto-type-generator/intersection-flattener.js.map +1 -0
  43. package/dist/auto-type-generator/naming-convention.d.ts +21 -0
  44. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
  45. package/dist/auto-type-generator/naming-convention.js +145 -1
  46. package/dist/auto-type-generator/naming-convention.js.map +1 -1
  47. package/dist/auto-type-generator/typename-extractor.d.ts +2 -0
  48. package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -1
  49. package/dist/auto-type-generator/typename-extractor.js +11 -3
  50. package/dist/auto-type-generator/typename-extractor.js.map +1 -1
  51. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +2 -0
  52. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -1
  53. package/dist/auto-type-generator/typename-resolve-type-generator.js +12 -84
  54. package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -1
  55. package/dist/auto-type-generator/typename-types.d.ts +4 -0
  56. package/dist/auto-type-generator/typename-types.d.ts.map +1 -1
  57. package/dist/auto-type-generator/typename-types.js +6 -0
  58. package/dist/auto-type-generator/typename-types.js.map +1 -1
  59. package/dist/auto-type-generator/typename-validator.d.ts.map +1 -1
  60. package/dist/auto-type-generator/typename-validator.js +4 -3
  61. package/dist/auto-type-generator/typename-validator.js.map +1 -1
  62. package/dist/commands/gen.d.ts.map +1 -1
  63. package/dist/commands/gen.js +2 -1
  64. package/dist/commands/gen.js.map +1 -1
  65. package/dist/config/types.d.ts +7 -0
  66. package/dist/config/types.d.ts.map +1 -1
  67. package/dist/config-loader/index.d.ts +1 -1
  68. package/dist/config-loader/index.d.ts.map +1 -1
  69. package/dist/config-loader/index.js.map +1 -1
  70. package/dist/config-loader/loader.d.ts +6 -0
  71. package/dist/config-loader/loader.d.ts.map +1 -1
  72. package/dist/config-loader/loader.js +1 -0
  73. package/dist/config-loader/loader.js.map +1 -1
  74. package/dist/config-loader/validator.d.ts.map +1 -1
  75. package/dist/config-loader/validator.js +84 -1
  76. package/dist/config-loader/validator.js.map +1 -1
  77. package/dist/gen-orchestrator/orchestrator.d.ts +2 -1
  78. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  79. package/dist/gen-orchestrator/orchestrator.js +15 -2
  80. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  81. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  82. package/dist/resolver-extractor/extractor/define-api-extractor.js +4 -0
  83. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  84. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +2 -0
  85. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
  86. package/dist/resolver-extractor/validator/abstract-resolver-validator.js +16 -3
  87. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
  88. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  89. package/dist/schema-generator/emitter/code-emitter.js +13 -1
  90. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  91. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts +18 -0
  92. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts.map +1 -0
  93. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js +89 -0
  94. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js.map +1 -0
  95. package/dist/schema-generator/generate-schema.d.ts +2 -0
  96. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  97. package/dist/schema-generator/generate-schema.js +69 -10
  98. package/dist/schema-generator/generate-schema.js.map +1 -1
  99. package/dist/schema-generator/integrator/result-integrator.d.ts +4 -0
  100. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  101. package/dist/schema-generator/integrator/result-integrator.js +18 -2
  102. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  103. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
  104. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
  105. package/dist/schema-generator/resolver-collector/resolver-collector.js +4 -0
  106. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
  107. package/dist/shared/constants.d.ts.map +1 -1
  108. package/dist/shared/constants.js +14 -1
  109. package/dist/shared/constants.js.map +1 -1
  110. package/dist/shared/enum-prefix-detector.d.ts.map +1 -1
  111. package/dist/shared/enum-prefix-detector.js +78 -8
  112. package/dist/shared/enum-prefix-detector.js.map +1 -1
  113. package/dist/shared/inline-object-utils.js +1 -1
  114. package/dist/shared/inline-object-utils.js.map +1 -1
  115. package/dist/shared/type-converter.d.ts.map +1 -1
  116. package/dist/shared/type-converter.js +55 -0
  117. package/dist/shared/type-converter.js.map +1 -1
  118. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  119. package/dist/type-extractor/converter/graphql-converter.js +11 -1
  120. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  121. package/dist/type-extractor/extractor/field-type-resolver.d.ts +18 -0
  122. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  123. package/dist/type-extractor/extractor/field-type-resolver.js +218 -16
  124. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  125. package/dist/type-extractor/extractor/type-extractor.d.ts +1 -0
  126. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  127. package/dist/type-extractor/extractor/type-extractor.js +127 -14
  128. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  129. package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -1
  130. package/dist/type-extractor/extractor/type-name-collector.js +19 -4
  131. package/dist/type-extractor/extractor/type-name-collector.js.map +1 -1
  132. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  133. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  134. package/dist/type-extractor/types/index.d.ts +1 -1
  135. package/dist/type-extractor/types/index.d.ts.map +1 -1
  136. package/dist/type-extractor/types/index.js +1 -1
  137. package/dist/type-extractor/types/index.js.map +1 -1
  138. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +7 -1
  139. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
  140. package/dist/type-extractor/types/ts-type-reference-factory.js +18 -3
  141. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
  142. package/dist/type-extractor/types/typescript.d.ts +3 -1
  143. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  144. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  145. package/dist/type-extractor/validator/type-validator.js +6 -1
  146. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  147. package/docs/configuration.md +19 -0
  148. package/docs/index.md +1 -0
  149. package/docs/integration/ai-sdk.md +189 -0
  150. package/docs/schema/unions.md +117 -0
  151. package/package.json +2 -2
  152. package/src/auto-type-generator/auto-type-generator.ts +576 -58
  153. package/src/auto-type-generator/discriminator-field-validator.ts +368 -0
  154. package/src/auto-type-generator/discriminator-naming.ts +24 -0
  155. package/src/auto-type-generator/discriminator-resolve-type-generator.ts +136 -0
  156. package/src/auto-type-generator/index.ts +17 -0
  157. package/src/auto-type-generator/inline-enum-collector.ts +19 -4
  158. package/src/auto-type-generator/inline-object-converter.ts +100 -0
  159. package/src/auto-type-generator/inline-object-traverser.ts +33 -7
  160. package/src/auto-type-generator/inline-union-collector.ts +26 -4
  161. package/src/auto-type-generator/inline-union-types.ts +2 -0
  162. package/src/auto-type-generator/inline-union-validator.ts +3 -3
  163. package/src/auto-type-generator/intersection-flattener.ts +554 -0
  164. package/src/auto-type-generator/naming-convention.ts +205 -1
  165. package/src/auto-type-generator/typename-extractor.ts +17 -3
  166. package/src/auto-type-generator/typename-resolve-type-generator.ts +19 -108
  167. package/src/auto-type-generator/typename-types.ts +7 -0
  168. package/src/auto-type-generator/typename-validator.ts +4 -3
  169. package/src/commands/gen.ts +9 -2
  170. package/src/config/types.ts +10 -0
  171. package/src/config-loader/index.ts +1 -0
  172. package/src/config-loader/loader.ts +11 -0
  173. package/src/config-loader/validator.ts +100 -1
  174. package/src/gen-orchestrator/orchestrator.ts +19 -2
  175. package/src/resolver-extractor/extractor/define-api-extractor.ts +4 -0
  176. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +20 -6
  177. package/src/schema-generator/emitter/code-emitter.ts +26 -1
  178. package/src/schema-generator/emitter/discriminator-resolve-type-emitter.ts +125 -0
  179. package/src/schema-generator/generate-schema.ts +100 -13
  180. package/src/schema-generator/integrator/result-integrator.ts +25 -1
  181. package/src/schema-generator/resolver-collector/resolver-collector.ts +7 -0
  182. package/src/shared/constants.ts +15 -1
  183. package/src/shared/enum-prefix-detector.ts +96 -8
  184. package/src/shared/inline-object-utils.ts +1 -1
  185. package/src/shared/type-converter.ts +63 -0
  186. package/src/type-extractor/converter/graphql-converter.ts +17 -1
  187. package/src/type-extractor/extractor/field-type-resolver.ts +266 -16
  188. package/src/type-extractor/extractor/type-extractor.ts +148 -11
  189. package/src/type-extractor/extractor/type-name-collector.ts +19 -4
  190. package/src/type-extractor/types/diagnostics.ts +10 -1
  191. package/src/type-extractor/types/index.ts +2 -1
  192. package/src/type-extractor/types/ts-type-reference-factory.ts +24 -3
  193. package/src/type-extractor/types/typescript.ts +6 -2
  194. package/src/type-extractor/validator/type-validator.ts +6 -1
@@ -1,6 +1,9 @@
1
1
  import { resolve } from "node:path";
2
2
  import ts from "typescript";
3
- import { isInternalTypeSymbol } from "../../shared/constants.js";
3
+ import {
4
+ isBuiltInScalar,
5
+ isInternalTypeSymbol,
6
+ } from "../../shared/constants.js";
4
7
  import { detectDefaultValueMetadata } from "../../shared/default-value-detector.js";
5
8
  import {
6
9
  type DirectiveArgumentValue,
@@ -50,10 +53,11 @@ import type {
50
53
  import {
51
54
  createArrayType,
52
55
  createInlineObjectType,
53
- createLiteralType,
56
+ createNumericLiteralType,
54
57
  createPrimitiveType,
55
58
  createReferenceType,
56
59
  createScalarType,
60
+ createStringLiteralType,
57
61
  createUnionType,
58
62
  type Diagnostic,
59
63
  type EnumMemberInfo,
@@ -65,7 +69,11 @@ import {
65
69
  type TypeKind,
66
70
  type TypeMetadata,
67
71
  } from "../types/index.js";
68
- import { resolveFieldType } from "./field-type-resolver.js";
72
+ import {
73
+ type DiscoveredTypeEntry,
74
+ type FieldTypeResolverDiagnostic,
75
+ resolveFieldType,
76
+ } from "./field-type-resolver.js";
69
77
 
70
78
  /**
71
79
  * Global type mapping configuration.
@@ -98,6 +106,7 @@ export interface ExtractionResult {
98
106
  readonly diagnostics: ReadonlyArray<Diagnostic>;
99
107
  readonly detectedScalarNames: ReadonlyArray<string>;
100
108
  readonly detectedScalars: ReadonlyArray<ScalarMetadataInfo>;
109
+ readonly discoveredTypeNames: ReadonlySet<string>;
101
110
  }
102
111
 
103
112
  function isDefaultExport(node: ts.Node, sourceFile: ts.SourceFile): boolean {
@@ -163,6 +172,7 @@ function tryExtractAsInlineObject(
163
172
  properties: inlineProperties,
164
173
  description: null,
165
174
  deprecated: null,
175
+ hintName: null,
166
176
  }),
167
177
  };
168
178
  }
@@ -260,6 +270,7 @@ function convertTsTypeToReference(
260
270
  tsType: createUnionType({
261
271
  members: memberResults.map((r) => r.tsType),
262
272
  nullable,
273
+ aliasName: type.aliasSymbol?.getName() ?? null,
263
274
  }),
264
275
  };
265
276
  }
@@ -307,12 +318,12 @@ function convertTsTypeToReference(
307
318
  }
308
319
  if (type.flags & ts.TypeFlags.StringLiteral) {
309
320
  return {
310
- tsType: createLiteralType(typeString.replace(/"/g, "")),
321
+ tsType: createStringLiteralType(typeString.replace(/"/g, "")),
311
322
  };
312
323
  }
313
324
  if (type.flags & ts.TypeFlags.NumberLiteral) {
314
325
  return {
315
- tsType: createLiteralType(typeString),
326
+ tsType: createNumericLiteralType(typeString),
316
327
  };
317
328
  }
318
329
 
@@ -436,6 +447,7 @@ interface ExtractFieldsParams {
436
447
  readonly scalarMappingTable: ScalarBaseTypeMappingTable | null;
437
448
  readonly scalarMappingContext: ScalarMappingContext;
438
449
  readonly ignoreFields: ReadonlySet<string> | null;
450
+ readonly discoveredTypes: Map<string, DiscoveredTypeEntry> | null;
439
451
  }
440
452
 
441
453
  function extractFieldsFromType(
@@ -452,6 +464,7 @@ function extractFieldsFromType(
452
464
  scalarMappingTable,
453
465
  scalarMappingContext,
454
466
  ignoreFields,
467
+ discoveredTypes,
455
468
  } = params;
456
469
  const fields: FieldDefinition[] = [];
457
470
  const diagnostics: Diagnostic[] = [];
@@ -528,6 +541,7 @@ function extractFieldsFromType(
528
541
  propTypeNode = declaration.type;
529
542
  }
530
543
 
544
+ const fieldDiagnostics: FieldTypeResolverDiagnostic[] = [];
531
545
  const resolvedType = resolveFieldType(actualPropType, propTypeNode, {
532
546
  checker,
533
547
  knownTypeNames,
@@ -537,7 +551,22 @@ function extractFieldsFromType(
537
551
  sourceFiles,
538
552
  scalarMappingTable,
539
553
  scalarMappingContext,
554
+ discoveredTypes,
555
+ diagnostics: fieldDiagnostics,
540
556
  });
557
+ for (const d of fieldDiagnostics) {
558
+ diagnostics.push({
559
+ code: d.code,
560
+ message: `Field '${propName}': ${d.message}`,
561
+ severity: d.severity,
562
+ location: getSourceLocationFromNode(declaration),
563
+ });
564
+ }
565
+
566
+ // Skip fields with never type — they have no GraphQL representation
567
+ if (resolvedType.kind === "never") {
568
+ continue;
569
+ }
541
570
 
542
571
  // Preserve nullability from original WithDirectives type
543
572
  const tsType =
@@ -847,6 +876,7 @@ interface ProcessReexportedSymbolParams {
847
876
  readonly scannedSourceFiles: ReadonlySet<string>;
848
877
  readonly scalarMappingTable: ScalarBaseTypeMappingTable | null;
849
878
  readonly scalarMappingContext: ScalarMappingContext;
879
+ readonly discoveredTypes: Map<string, DiscoveredTypeEntry> | null;
850
880
  }
851
881
 
852
882
  interface ProcessReexportedSymbolResult {
@@ -874,6 +904,7 @@ function processReexportedSymbol(
874
904
  scannedSourceFiles,
875
905
  scalarMappingTable,
876
906
  scalarMappingContext,
907
+ discoveredTypes,
877
908
  } = params;
878
909
 
879
910
  const diagnostics: Diagnostic[] = [];
@@ -999,6 +1030,7 @@ function processReexportedSymbol(
999
1030
  scalarMappingTable,
1000
1031
  scalarMappingContext,
1001
1032
  ignoreFields,
1033
+ discoveredTypes,
1002
1034
  });
1003
1035
  diagnostics.push(...fieldResult.diagnostics);
1004
1036
 
@@ -1036,16 +1068,13 @@ function processExportDeclaration(
1036
1068
  underlyingSymbolToTypeName: ReadonlyMap<ts.Symbol, string>,
1037
1069
  scannedSourceFiles: ReadonlySet<string>,
1038
1070
  scalarMappingTable: ScalarBaseTypeMappingTable | null,
1071
+ discoveredTypes: Map<string, DiscoveredTypeEntry> | null,
1039
1072
  ): ProcessExportDeclarationResult {
1040
1073
  const types: ExtractedTypeInfo[] = [];
1041
1074
  const diagnostics: Diagnostic[] = [];
1042
1075
  const detectedScalarNames: string[] = [];
1043
1076
  const detectedScalars: ScalarMetadataInfo[] = [];
1044
1077
 
1045
- if (!node.isTypeOnly) {
1046
- return { types, diagnostics, detectedScalarNames, detectedScalars };
1047
- }
1048
-
1049
1078
  const exportClause = node.exportClause;
1050
1079
 
1051
1080
  const symbolsToProcess: Array<{
@@ -1054,8 +1083,35 @@ function processExportDeclaration(
1054
1083
  type: ts.Type;
1055
1084
  }> = [];
1056
1085
 
1057
- if (exportClause && ts.isNamedExports(exportClause)) {
1086
+ if (node.isTypeOnly && exportClause && ts.isNamedExports(exportClause)) {
1087
+ // Declaration-level type-only: `export type { Foo, Bar } from "..."`
1088
+ for (const specifier of exportClause.elements) {
1089
+ const exportedName = specifier.name.text;
1090
+ const localTargetSymbol =
1091
+ checker.getExportSpecifierLocalTargetSymbol(specifier);
1092
+ if (!localTargetSymbol) continue;
1093
+
1094
+ const originalSymbol =
1095
+ localTargetSymbol.flags & ts.SymbolFlags.Alias
1096
+ ? checker.getAliasedSymbol(localTargetSymbol)
1097
+ : localTargetSymbol;
1098
+ if (!originalSymbol) continue;
1099
+
1100
+ const type = checker.getDeclaredTypeOfSymbol(originalSymbol);
1101
+ symbolsToProcess.push({
1102
+ exportedName,
1103
+ resolvedSymbol: originalSymbol,
1104
+ type,
1105
+ });
1106
+ }
1107
+ } else if (
1108
+ !node.isTypeOnly &&
1109
+ exportClause &&
1110
+ ts.isNamedExports(exportClause)
1111
+ ) {
1112
+ // Specifier-level type-only: `export { type Foo, type Bar } from "..."`
1058
1113
  for (const specifier of exportClause.elements) {
1114
+ if (!specifier.isTypeOnly) continue;
1059
1115
  const exportedName = specifier.name.text;
1060
1116
  const localTargetSymbol =
1061
1117
  checker.getExportSpecifierLocalTargetSymbol(specifier);
@@ -1074,7 +1130,7 @@ function processExportDeclaration(
1074
1130
  type,
1075
1131
  });
1076
1132
  }
1077
- } else if (!exportClause && node.moduleSpecifier) {
1133
+ } else if (node.isTypeOnly && !exportClause && node.moduleSpecifier) {
1078
1134
  const moduleSymbol = checker.getSymbolAtLocation(node.moduleSpecifier);
1079
1135
  if (!moduleSymbol) {
1080
1136
  const location = getSourceLocationFromNode(node)!;
@@ -1132,6 +1188,7 @@ function processExportDeclaration(
1132
1188
  scannedSourceFiles,
1133
1189
  scalarMappingTable,
1134
1190
  scalarMappingContext: exportedName.endsWith("Input") ? "input" : "output",
1191
+ discoveredTypes,
1135
1192
  });
1136
1193
 
1137
1194
  if (result.skip) continue;
@@ -1317,6 +1374,7 @@ export function extractTypesFromProgram(
1317
1374
  const diagnostics: Diagnostic[] = [];
1318
1375
  const detectedScalarNames = new Set<string>();
1319
1376
  const detectedScalars: ScalarMetadataInfo[] = [];
1377
+ const discoveredTypes = new Map<string, DiscoveredTypeEntry>();
1320
1378
  const {
1321
1379
  globalTypeMappings,
1322
1380
  knownTypeNames,
@@ -1562,6 +1620,7 @@ export function extractTypesFromProgram(
1562
1620
  ? "input"
1563
1621
  : "output",
1564
1622
  ignoreFields,
1623
+ discoveredTypes,
1565
1624
  });
1566
1625
  const fields = fieldResult.fields;
1567
1626
  diagnostics.push(...fieldResult.diagnostics);
@@ -1624,6 +1683,7 @@ export function extractTypesFromProgram(
1624
1683
  underlyingSymbolToTypeName,
1625
1684
  scannedSourceFilesSet,
1626
1685
  scalarMappingTable,
1686
+ discoveredTypes,
1627
1687
  );
1628
1688
  types.push(...result.types);
1629
1689
  diagnostics.push(...result.diagnostics);
@@ -1635,10 +1695,87 @@ export function extractTypesFromProgram(
1635
1695
  });
1636
1696
  }
1637
1697
 
1698
+ // Process transitively discovered types
1699
+ const processedDiscovered = new Set<string>();
1700
+ while (discoveredTypes.size > processedDiscovered.size) {
1701
+ for (const [name, entry] of discoveredTypes) {
1702
+ if (processedDiscovered.has(name)) continue;
1703
+ processedDiscovered.add(name);
1704
+ if (knownTypeNames.has(name)) continue;
1705
+
1706
+ const { fields } = extractFieldsFromType({
1707
+ type: entry.tsType,
1708
+ checker,
1709
+ globalTypeMappings,
1710
+ knownTypeNames,
1711
+ knownTypeSymbols,
1712
+ underlyingSymbolToTypeName,
1713
+ sourceFiles: scannedSourceFilesSet,
1714
+ scalarMappingTable,
1715
+ scalarMappingContext: "output",
1716
+ ignoreFields: null,
1717
+ discoveredTypes,
1718
+ });
1719
+ if (fields.length === 0) continue;
1720
+
1721
+ types.push({
1722
+ metadata: {
1723
+ name,
1724
+ kind: "object",
1725
+ sourceFile: entry.sourceFile,
1726
+ sourceLocation: entry.sourceLocation,
1727
+ exportKind: "named",
1728
+ description: null,
1729
+ deprecated: null,
1730
+ directives: null,
1731
+ },
1732
+ fields,
1733
+ enumMembers: null,
1734
+ unionMembers: null,
1735
+ implementedInterfaces: null,
1736
+ inlineObjectMembers: null,
1737
+ });
1738
+ }
1739
+ }
1740
+
1741
+ // Collect scalar names from field types (e.g., unknown → Unknown scalar)
1742
+ for (const typeInfo of types) {
1743
+ for (const field of typeInfo.fields) {
1744
+ collectScalarNamesFromType(field.tsType, detectedScalarNames);
1745
+ }
1746
+ }
1747
+
1638
1748
  return {
1639
1749
  types,
1640
1750
  diagnostics,
1641
1751
  detectedScalarNames: [...detectedScalarNames],
1642
1752
  detectedScalars,
1753
+ discoveredTypeNames: new Set(discoveredTypes.keys()),
1643
1754
  };
1644
1755
  }
1756
+
1757
+ function collectScalarNamesFromType(
1758
+ tsType: TSTypeReference,
1759
+ scalarNames: Set<string>,
1760
+ ): void {
1761
+ if (
1762
+ tsType.kind === "scalar" &&
1763
+ tsType.scalarInfo?.isCustom &&
1764
+ !isBuiltInScalar(tsType.scalarInfo.scalarName)
1765
+ ) {
1766
+ scalarNames.add(tsType.scalarInfo.scalarName);
1767
+ }
1768
+ if (tsType.elementType) {
1769
+ collectScalarNamesFromType(tsType.elementType, scalarNames);
1770
+ }
1771
+ if (tsType.members) {
1772
+ for (const member of tsType.members) {
1773
+ collectScalarNamesFromType(member, scalarNames);
1774
+ }
1775
+ }
1776
+ if (tsType.inlineObjectProperties) {
1777
+ for (const prop of tsType.inlineObjectProperties) {
1778
+ collectScalarNamesFromType(prop.tsType, scalarNames);
1779
+ }
1780
+ }
1781
+ }
@@ -142,9 +142,9 @@ export function collectDeclaredTypeNames(
142
142
  }
143
143
 
144
144
  // Re-exports: `export type { ... } from "..."` or `export type * from "..."`
145
- if (ts.isExportDeclaration(node) && node.isTypeOnly) {
146
- if (node.exportClause) {
147
- // Named re-exports: `export type { Foo, Bar } from "..."`
145
+ if (ts.isExportDeclaration(node)) {
146
+ if (node.isTypeOnly && node.exportClause) {
147
+ // Declaration-level type-only named re-exports: `export type { Foo, Bar } from "..."`
148
148
  if (ts.isNamedExports(node.exportClause)) {
149
149
  for (const element of node.exportClause.elements) {
150
150
  // Use the exported name (element.name), not the property name
@@ -154,7 +154,22 @@ export function collectDeclaredTypeNames(
154
154
  registerTypeName(name, location, symbol);
155
155
  }
156
156
  }
157
- } else if (node.moduleSpecifier) {
157
+ } else if (!node.isTypeOnly && node.exportClause) {
158
+ // Specifier-level type-only re-exports: `export { type Foo, type Bar } from "..."`
159
+ if (ts.isNamedExports(node.exportClause)) {
160
+ for (const element of node.exportClause.elements) {
161
+ if (!element.isTypeOnly) continue;
162
+ const name = element.name.getText(sourceFile);
163
+ const location = getSourceLocationFromNode(element)!;
164
+ const symbol = checker.getSymbolAtLocation(element.name);
165
+ registerTypeName(name, location, symbol);
166
+ }
167
+ }
168
+ } else if (
169
+ node.isTypeOnly &&
170
+ !node.exportClause &&
171
+ node.moduleSpecifier
172
+ ) {
158
173
  // Wildcard re-exports: `export type * from "..."`
159
174
  const moduleSymbol = checker.getSymbolAtLocation(
160
175
  node.moduleSpecifier,
@@ -95,9 +95,18 @@ export type DiagnosticCode =
95
95
  | "NULLABLE_TYPENAME_PROPERTY"
96
96
  | "TYPENAME_FIELD_STRUCTURE_MISMATCH"
97
97
  | "DUPLICATE_TYPENAME_VALUE"
98
+ | "UNNAMEABLE_UNION_MEMBER"
98
99
  | "IGNORE_FIELD_NOT_FOUND"
99
100
  | "IGNORE_ALL_FIELDS"
100
- | "DUPLICATE_TYPE_EXPORT";
101
+ | "DUPLICATE_TYPE_EXPORT"
102
+ | "CONFIG_INVALID_DISCRIMINATOR_FIELDS"
103
+ | "CONFIG_INVALID_DISCRIMINATOR_ENTRY"
104
+ | "CONFIG_EMPTY_DISCRIMINATOR_FIELDS"
105
+ | "DISCRIMINATOR_FIELD_NOT_FOUND"
106
+ | "DISCRIMINATOR_FIELD_NOT_STRING_LITERAL"
107
+ | "DISCRIMINATOR_DUPLICATE_VALUE_TUPLE"
108
+ | "DISCRIMINATOR_UNKNOWN_UNION"
109
+ | "CYCLE_DETECTED";
101
110
 
102
111
  export interface Diagnostic {
103
112
  readonly code: DiagnosticCode;
@@ -15,10 +15,11 @@ export type {
15
15
  export {
16
16
  createArrayType,
17
17
  createInlineObjectType,
18
- createLiteralType,
18
+ createNumericLiteralType,
19
19
  createPrimitiveType,
20
20
  createReferenceType,
21
21
  createScalarType,
22
+ createStringLiteralType,
22
23
  createUnionType,
23
24
  } from "./ts-type-reference-factory.js";
24
25
  export type {
@@ -25,6 +25,7 @@ function createTSTypeReference(
25
25
  inlineObjectProperties: null,
26
26
  inlineObjectDescription: null,
27
27
  inlineObjectDeprecated: null,
28
+ inlineObjectHintName: null,
28
29
  inlineEnumMembers: null,
29
30
  externalEnumSymbol: null,
30
31
  externalEnumDescription: null,
@@ -68,6 +69,8 @@ export function createArrayType(elementType: TSTypeReference): TSTypeReference {
68
69
  interface CreateUnionTypeParams {
69
70
  readonly members: ReadonlyArray<TSTypeReference>;
70
71
  readonly nullable: boolean;
72
+ /** The TypeScript type alias name for this union (e.g., "ItemPart" for `type ItemPart = A | B`) */
73
+ readonly aliasName: string | null;
71
74
  }
72
75
 
73
76
  export function createUnionType(
@@ -75,7 +78,11 @@ export function createUnionType(
75
78
  ): TSTypeReference {
76
79
  return createTSTypeReference({
77
80
  kind: "union",
78
- overrides: { members: params.members, nullable: params.nullable },
81
+ overrides: {
82
+ members: params.members,
83
+ nullable: params.nullable,
84
+ name: params.aliasName,
85
+ },
79
86
  });
80
87
  }
81
88
 
@@ -85,6 +92,8 @@ interface CreateInlineObjectTypeParams {
85
92
  readonly description: string | null;
86
93
  /** @deprecated tag from the type alias (null for true inline objects) */
87
94
  readonly deprecated: DeprecationInfo | null;
95
+ /** Original type name hint for inline objects extracted from external types */
96
+ readonly hintName: string | null;
88
97
  }
89
98
 
90
99
  export function createInlineObjectType(
@@ -96,6 +105,7 @@ export function createInlineObjectType(
96
105
  inlineObjectProperties: params.properties,
97
106
  inlineObjectDescription: params.description,
98
107
  inlineObjectDeprecated: params.deprecated,
108
+ inlineObjectHintName: params.hintName,
99
109
  },
100
110
  });
101
111
  }
@@ -119,8 +129,19 @@ export function createScalarType(
119
129
  });
120
130
  }
121
131
 
122
- export function createLiteralType(name: string): TSTypeReference {
123
- return createTSTypeReference({ kind: "literal", overrides: { name } });
132
+ export function createNeverType(): TSTypeReference {
133
+ return createTSTypeReference({ kind: "never", overrides: {} });
134
+ }
135
+
136
+ export function createStringLiteralType(name: string): TSTypeReference {
137
+ return createTSTypeReference({ kind: "stringLiteral", overrides: { name } });
138
+ }
139
+
140
+ export function createNumericLiteralType(name: string): TSTypeReference {
141
+ return createTSTypeReference({
142
+ kind: "numericLiteral",
143
+ overrides: { name },
144
+ });
124
145
  }
125
146
 
126
147
  interface CreateInlineEnumTypeParams {
@@ -45,10 +45,12 @@ export type TSTypeReferenceKind =
45
45
  | "reference"
46
46
  | "array"
47
47
  | "union"
48
- | "literal"
48
+ | "stringLiteral"
49
+ | "numericLiteral"
49
50
  | "scalar"
50
51
  | "inlineObject"
51
- | "inlineEnum";
52
+ | "inlineEnum"
53
+ | "never";
52
54
 
53
55
  /**
54
56
  * Information about an inline enum member (string literal union value).
@@ -76,6 +78,8 @@ export interface TSTypeReference {
76
78
  readonly inlineObjectDeprecated: DeprecationInfo | null;
77
79
  /** Inline enum members when kind is "inlineEnum" */
78
80
  readonly inlineEnumMembers: ReadonlyArray<InlineEnumMemberInfo> | null;
81
+ /** Original type name hint for inline objects extracted from external types */
82
+ readonly inlineObjectHintName: string | null;
79
83
  /** External TypeScript enum symbol for deduplication (Requirement 5.2) */
80
84
  readonly externalEnumSymbol: ts.Symbol | null;
81
85
  /** TSDoc description from the external enum type itself (Requirement 6.1) */
@@ -10,7 +10,12 @@ export interface ValidateTypesOptions {
10
10
  readonly types: ReadonlyArray<GraphQLTypeInfo>;
11
11
  readonly customScalarNames: ReadonlyArray<string> | null;
12
12
  }
13
- const PLACEHOLDER_TYPES = new Set(["__INLINE_OBJECT__", "__INLINE_ENUM__"]);
13
+ const PLACEHOLDER_TYPES = new Set([
14
+ "__INLINE_OBJECT__",
15
+ "__INLINE_ENUM__",
16
+ "__INLINE_UNION__",
17
+ "__NEVER__",
18
+ ]);
14
19
 
15
20
  export function validateTypes(options: ValidateTypesOptions): ValidationResult {
16
21
  const { types, customScalarNames } = options;