@gqlkit-ts/cli 0.5.1 → 0.7.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 (212) 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 +379 -56
  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 +23 -2
  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/resolver-field-iterator.d.ts +1 -1
  48. package/dist/auto-type-generator/resolver-field-iterator.d.ts.map +1 -1
  49. package/dist/auto-type-generator/resolver-field-iterator.js +3 -0
  50. package/dist/auto-type-generator/resolver-field-iterator.js.map +1 -1
  51. package/dist/auto-type-generator/typename-extractor.d.ts +2 -0
  52. package/dist/auto-type-generator/typename-extractor.d.ts.map +1 -1
  53. package/dist/auto-type-generator/typename-extractor.js +11 -3
  54. package/dist/auto-type-generator/typename-extractor.js.map +1 -1
  55. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts +2 -0
  56. package/dist/auto-type-generator/typename-resolve-type-generator.d.ts.map +1 -1
  57. package/dist/auto-type-generator/typename-resolve-type-generator.js +12 -84
  58. package/dist/auto-type-generator/typename-resolve-type-generator.js.map +1 -1
  59. package/dist/auto-type-generator/typename-types.d.ts +4 -0
  60. package/dist/auto-type-generator/typename-types.d.ts.map +1 -1
  61. package/dist/auto-type-generator/typename-types.js +6 -0
  62. package/dist/auto-type-generator/typename-types.js.map +1 -1
  63. package/dist/auto-type-generator/typename-validator.d.ts.map +1 -1
  64. package/dist/auto-type-generator/typename-validator.js +4 -3
  65. package/dist/auto-type-generator/typename-validator.js.map +1 -1
  66. package/dist/commands/docs.d.ts +1 -0
  67. package/dist/commands/docs.d.ts.map +1 -1
  68. package/dist/commands/gen.d.ts +1 -0
  69. package/dist/commands/gen.d.ts.map +1 -1
  70. package/dist/commands/gen.js +2 -1
  71. package/dist/commands/gen.js.map +1 -1
  72. package/dist/commands/main.d.ts +1 -0
  73. package/dist/commands/main.d.ts.map +1 -1
  74. package/dist/config/types.d.ts +7 -0
  75. package/dist/config/types.d.ts.map +1 -1
  76. package/dist/config-loader/index.d.ts +1 -1
  77. package/dist/config-loader/index.d.ts.map +1 -1
  78. package/dist/config-loader/index.js.map +1 -1
  79. package/dist/config-loader/loader.d.ts +6 -0
  80. package/dist/config-loader/loader.d.ts.map +1 -1
  81. package/dist/config-loader/loader.js +1 -0
  82. package/dist/config-loader/loader.js.map +1 -1
  83. package/dist/config-loader/validator.d.ts.map +1 -1
  84. package/dist/config-loader/validator.js +84 -1
  85. package/dist/config-loader/validator.js.map +1 -1
  86. package/dist/gen-orchestrator/orchestrator.d.ts +2 -1
  87. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  88. package/dist/gen-orchestrator/orchestrator.js +43 -3
  89. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  90. package/dist/resolver-extractor/extract-resolvers.d.ts +4 -0
  91. package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
  92. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +2 -1
  93. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  94. package/dist/resolver-extractor/extractor/define-api-extractor.js +35 -6
  95. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  96. package/dist/resolver-extractor/index.d.ts +1 -1
  97. package/dist/resolver-extractor/index.d.ts.map +1 -1
  98. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts +2 -0
  99. package/dist/resolver-extractor/validator/abstract-resolver-validator.d.ts.map +1 -1
  100. package/dist/resolver-extractor/validator/abstract-resolver-validator.js +16 -3
  101. package/dist/resolver-extractor/validator/abstract-resolver-validator.js.map +1 -1
  102. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  103. package/dist/schema-generator/emitter/code-emitter.js +24 -4
  104. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  105. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts +18 -0
  106. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.d.ts.map +1 -0
  107. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js +89 -0
  108. package/dist/schema-generator/emitter/discriminator-resolve-type-emitter.js.map +1 -0
  109. package/dist/schema-generator/generate-schema.d.ts +2 -0
  110. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  111. package/dist/schema-generator/generate-schema.js +69 -10
  112. package/dist/schema-generator/generate-schema.js.map +1 -1
  113. package/dist/schema-generator/integrator/result-integrator.d.ts +5 -0
  114. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  115. package/dist/schema-generator/integrator/result-integrator.js +44 -3
  116. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  117. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts +2 -0
  118. package/dist/schema-generator/resolver-collector/resolver-collector.d.ts.map +1 -1
  119. package/dist/schema-generator/resolver-collector/resolver-collector.js +4 -0
  120. package/dist/schema-generator/resolver-collector/resolver-collector.js.map +1 -1
  121. package/dist/shared/constants.d.ts.map +1 -1
  122. package/dist/shared/constants.js +14 -1
  123. package/dist/shared/constants.js.map +1 -1
  124. package/dist/shared/enum-prefix-detector.d.ts.map +1 -1
  125. package/dist/shared/enum-prefix-detector.js +78 -8
  126. package/dist/shared/enum-prefix-detector.js.map +1 -1
  127. package/dist/shared/inline-object-utils.js +1 -1
  128. package/dist/shared/inline-object-utils.js.map +1 -1
  129. package/dist/shared/type-converter.d.ts.map +1 -1
  130. package/dist/shared/type-converter.js +55 -0
  131. package/dist/shared/type-converter.js.map +1 -1
  132. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  133. package/dist/type-extractor/converter/graphql-converter.js +11 -1
  134. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  135. package/dist/type-extractor/extractor/field-type-resolver.d.ts +18 -0
  136. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -1
  137. package/dist/type-extractor/extractor/field-type-resolver.js +198 -15
  138. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -1
  139. package/dist/type-extractor/extractor/type-extractor.d.ts +1 -0
  140. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  141. package/dist/type-extractor/extractor/type-extractor.js +100 -9
  142. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  143. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  144. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  145. package/dist/type-extractor/types/index.d.ts +1 -1
  146. package/dist/type-extractor/types/index.d.ts.map +1 -1
  147. package/dist/type-extractor/types/index.js +1 -1
  148. package/dist/type-extractor/types/index.js.map +1 -1
  149. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +7 -1
  150. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -1
  151. package/dist/type-extractor/types/ts-type-reference-factory.js +18 -3
  152. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -1
  153. package/dist/type-extractor/types/typescript.d.ts +3 -1
  154. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  155. package/dist/type-extractor/validator/type-validator.d.ts.map +1 -1
  156. package/dist/type-extractor/validator/type-validator.js +6 -1
  157. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  158. package/docs/configuration.md +19 -0
  159. package/docs/getting-started.md +2 -1
  160. package/docs/index.md +2 -0
  161. package/docs/integration/ai-sdk.md +189 -0
  162. package/docs/schema/conventions.md +7 -0
  163. package/docs/schema/fields.md +15 -0
  164. package/docs/schema/queries-mutations.md +21 -2
  165. package/docs/schema/subscriptions.md +173 -0
  166. package/docs/schema/unions.md +117 -0
  167. package/package.json +4 -4
  168. package/src/auto-type-generator/auto-type-generator.ts +588 -62
  169. package/src/auto-type-generator/discriminator-field-validator.ts +368 -0
  170. package/src/auto-type-generator/discriminator-naming.ts +24 -0
  171. package/src/auto-type-generator/discriminator-resolve-type-generator.ts +136 -0
  172. package/src/auto-type-generator/index.ts +17 -0
  173. package/src/auto-type-generator/inline-enum-collector.ts +19 -4
  174. package/src/auto-type-generator/inline-object-converter.ts +100 -0
  175. package/src/auto-type-generator/inline-object-traverser.ts +33 -7
  176. package/src/auto-type-generator/inline-union-collector.ts +26 -4
  177. package/src/auto-type-generator/inline-union-types.ts +2 -0
  178. package/src/auto-type-generator/inline-union-validator.ts +3 -3
  179. package/src/auto-type-generator/intersection-flattener.ts +554 -0
  180. package/src/auto-type-generator/naming-convention.ts +207 -3
  181. package/src/auto-type-generator/resolver-field-iterator.ts +5 -1
  182. package/src/auto-type-generator/typename-extractor.ts +17 -3
  183. package/src/auto-type-generator/typename-resolve-type-generator.ts +19 -108
  184. package/src/auto-type-generator/typename-types.ts +7 -0
  185. package/src/auto-type-generator/typename-validator.ts +4 -3
  186. package/src/commands/gen.ts +9 -2
  187. package/src/config/types.ts +10 -0
  188. package/src/config-loader/index.ts +1 -0
  189. package/src/config-loader/loader.ts +11 -0
  190. package/src/config-loader/validator.ts +100 -1
  191. package/src/gen-orchestrator/orchestrator.ts +50 -3
  192. package/src/resolver-extractor/extract-resolvers.ts +5 -0
  193. package/src/resolver-extractor/extractor/define-api-extractor.ts +47 -7
  194. package/src/resolver-extractor/index.ts +1 -0
  195. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +20 -6
  196. package/src/schema-generator/emitter/code-emitter.ts +43 -5
  197. package/src/schema-generator/emitter/discriminator-resolve-type-emitter.ts +125 -0
  198. package/src/schema-generator/generate-schema.ts +100 -13
  199. package/src/schema-generator/integrator/result-integrator.ts +55 -2
  200. package/src/schema-generator/resolver-collector/resolver-collector.ts +7 -0
  201. package/src/shared/constants.ts +15 -1
  202. package/src/shared/enum-prefix-detector.ts +96 -8
  203. package/src/shared/inline-object-utils.ts +1 -1
  204. package/src/shared/type-converter.ts +63 -0
  205. package/src/type-extractor/converter/graphql-converter.ts +17 -1
  206. package/src/type-extractor/extractor/field-type-resolver.ts +241 -16
  207. package/src/type-extractor/extractor/type-extractor.ts +119 -5
  208. package/src/type-extractor/types/diagnostics.ts +10 -1
  209. package/src/type-extractor/types/index.ts +2 -1
  210. package/src/type-extractor/types/ts-type-reference-factory.ts +24 -3
  211. package/src/type-extractor/types/typescript.ts +6 -2
  212. package/src/type-extractor/validator/type-validator.ts +6 -1
@@ -6,6 +6,7 @@ import {
6
6
  DEFAULT_SOURCE_DIR,
7
7
  DEFAULT_TYPEDEFS_PATH,
8
8
  type ResolvedConfig,
9
+ type ResolvedDiscriminatorFieldsMap,
9
10
  type ResolvedHooksConfig,
10
11
  type ResolvedOutputConfig,
11
12
  type ResolvedScalarMapping,
@@ -584,6 +585,96 @@ function validateHooksConfig(
584
585
  return { resolved: undefined, diagnostics };
585
586
  }
586
587
 
588
+ function validateDiscriminatorFieldsConfig(
589
+ value: unknown,
590
+ configPath: string,
591
+ ): {
592
+ resolved: ResolvedDiscriminatorFieldsMap | undefined;
593
+ diagnostics: Diagnostic[];
594
+ } {
595
+ const diagnostics: Diagnostic[] = [];
596
+
597
+ if (value === undefined) {
598
+ return { resolved: new Map(), diagnostics: [] };
599
+ }
600
+
601
+ if (!isRecord(value)) {
602
+ diagnostics.push({
603
+ code: "CONFIG_INVALID_DISCRIMINATOR_FIELDS",
604
+ message: "discriminatorFields must be an object",
605
+ severity: "error",
606
+ location: { file: configPath, line: 1, column: 1 },
607
+ });
608
+ return { resolved: undefined, diagnostics };
609
+ }
610
+
611
+ const result = new Map<string, ReadonlyArray<string>>();
612
+
613
+ for (const [key, entry] of Object.entries(value)) {
614
+ if (typeof entry === "string") {
615
+ if (entry === "") {
616
+ diagnostics.push({
617
+ code: "CONFIG_EMPTY_DISCRIMINATOR_FIELDS",
618
+ message: `discriminatorFields["${key}"] cannot be an empty string`,
619
+ severity: "error",
620
+ location: { file: configPath, line: 1, column: 1 },
621
+ });
622
+ continue;
623
+ }
624
+ result.set(key, [entry]);
625
+ } else if (Array.isArray(entry)) {
626
+ if (entry.length === 0) {
627
+ diagnostics.push({
628
+ code: "CONFIG_EMPTY_DISCRIMINATOR_FIELDS",
629
+ message: `discriminatorFields["${key}"] cannot be an empty array`,
630
+ severity: "error",
631
+ location: { file: configPath, line: 1, column: 1 },
632
+ });
633
+ continue;
634
+ }
635
+ let hasError = false;
636
+ for (const item of entry) {
637
+ if (typeof item !== "string") {
638
+ diagnostics.push({
639
+ code: "CONFIG_INVALID_DISCRIMINATOR_ENTRY",
640
+ message: `discriminatorFields["${key}"] array must contain only strings`,
641
+ severity: "error",
642
+ location: { file: configPath, line: 1, column: 1 },
643
+ });
644
+ hasError = true;
645
+ break;
646
+ }
647
+ if (item === "") {
648
+ diagnostics.push({
649
+ code: "CONFIG_EMPTY_DISCRIMINATOR_FIELDS",
650
+ message: `discriminatorFields["${key}"] array contains an empty string`,
651
+ severity: "error",
652
+ location: { file: configPath, line: 1, column: 1 },
653
+ });
654
+ hasError = true;
655
+ break;
656
+ }
657
+ }
658
+ if (!hasError) {
659
+ result.set(key, entry as string[]);
660
+ }
661
+ } else {
662
+ diagnostics.push({
663
+ code: "CONFIG_INVALID_DISCRIMINATOR_ENTRY",
664
+ message: `discriminatorFields["${key}"] must be a string or array of strings`,
665
+ severity: "error",
666
+ location: { file: configPath, line: 1, column: 1 },
667
+ });
668
+ }
669
+ }
670
+
671
+ if (diagnostics.length > 0) {
672
+ return { resolved: undefined, diagnostics };
673
+ }
674
+
675
+ return { resolved: result, diagnostics: [] };
676
+ }
677
+
587
678
  export function validateConfig(
588
679
  options: ValidateConfigOptions,
589
680
  ): ValidateConfigResult {
@@ -621,6 +712,12 @@ export function validateConfig(
621
712
  const hooksResult = validateHooksConfig(config["hooks"], configPath);
622
713
  diagnostics.push(...hooksResult.diagnostics);
623
714
 
715
+ const discriminatorFieldsResult = validateDiscriminatorFieldsConfig(
716
+ config["discriminatorFields"],
717
+ configPath,
718
+ );
719
+ diagnostics.push(...discriminatorFieldsResult.diagnostics);
720
+
624
721
  if (config["scalars"] !== undefined && !Array.isArray(config["scalars"])) {
625
722
  diagnostics.push({
626
723
  code: "CONFIG_INVALID_TYPE",
@@ -685,7 +782,8 @@ export function validateConfig(
685
782
  !sourceDirResult.resolved ||
686
783
  !sourceIgnoreGlobsResult.resolved ||
687
784
  !outputResult.resolved ||
688
- !hooksResult.resolved
785
+ !hooksResult.resolved ||
786
+ !discriminatorFieldsResult.resolved
689
787
  ) {
690
788
  return { valid: false, resolvedConfig: undefined, diagnostics };
691
789
  }
@@ -699,6 +797,7 @@ export function validateConfig(
699
797
  scalars: resolvedScalars,
700
798
  tsconfigPath: tsconfigPathResult.resolved,
701
799
  hooks: hooksResult.resolved,
800
+ discriminatorFields: discriminatorFieldsResult.resolved,
702
801
  },
703
802
  diagnostics: [],
704
803
  };
@@ -1,6 +1,7 @@
1
1
  import { dirname, relative, resolve } from "node:path";
2
2
  import type ts from "typescript";
3
3
  import type {
4
+ ResolvedDiscriminatorFieldsMap,
4
5
  ResolvedOutputConfig,
5
6
  ResolvedScalarMapping,
6
7
  } from "../config-loader/index.js";
@@ -34,6 +35,7 @@ import {
34
35
  collectScalars,
35
36
  type ScalarMetadataInfo,
36
37
  } from "../type-extractor/collector/scalar-collector.js";
38
+ import { isEligibleField } from "../type-extractor/converter/field-eligibility.js";
37
39
  import { convertToGraphQL } from "../type-extractor/converter/graphql-converter.js";
38
40
  import {
39
41
  extractTypesFromProgram,
@@ -60,6 +62,7 @@ export interface GenerationConfig {
60
62
  readonly configDir: string | null;
61
63
  readonly customScalars: ReadonlyArray<ResolvedScalarMapping> | null;
62
64
  readonly tsconfigPath: string | null;
65
+ readonly discriminatorFields: ResolvedDiscriminatorFieldsMap;
63
66
  }
64
67
 
65
68
  export interface GeneratedFile {
@@ -81,11 +84,13 @@ interface TypesResult {
81
84
  detectedScalars: ReadonlyArray<ScalarMetadataInfo>;
82
85
  collectedScalars: ReadonlyArray<CollectedScalarType>;
83
86
  scalarMappingTable: ScalarBaseTypeMappingTable | null;
87
+ discoveredTypeNames: ReadonlySet<string>;
84
88
  }
85
89
 
86
90
  interface ResolversResult {
87
91
  queryFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
88
92
  mutationFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
93
+ subscriptionFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
89
94
  typeExtensions: ReadonlyArray<TypeExtension>;
90
95
  abstractTypeResolvers: ReadonlyArray<AbstractResolverInfo>;
91
96
  diagnostics: Diagnostics;
@@ -249,6 +254,7 @@ function extractTypesCore(params: ExtractTypesCoreParams): TypesResult {
249
254
  detectedScalars: extractionResult.detectedScalars,
250
255
  collectedScalars,
251
256
  scalarMappingTable,
257
+ discoveredTypeNames: extractionResult.discoveredTypeNames,
252
258
  };
253
259
  }
254
260
 
@@ -279,20 +285,42 @@ function convertDefineApiToFields(
279
285
  ): {
280
286
  queryFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
281
287
  mutationFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
288
+ subscriptionFields: { fields: ReadonlyArray<GraphQLFieldDefinition> };
282
289
  typeExtensions: ReadonlyArray<TypeExtension>;
290
+ diagnostics: ReadonlyArray<Diagnostic>;
283
291
  } {
284
292
  const queryFields: GraphQLFieldDefinition[] = [];
285
293
  const mutationFields: GraphQLFieldDefinition[] = [];
294
+ const subscriptionFields: GraphQLFieldDefinition[] = [];
286
295
  const typeExtensionMap = new Map<string, GraphQLFieldDefinition[]>();
296
+ const diagnostics: Diagnostic[] = [];
287
297
 
288
298
  for (const resolver of resolvers) {
299
+ const eligibility = isEligibleField({
300
+ fieldName: resolver.fieldName,
301
+ kind: "object",
302
+ });
303
+ if (!eligibility.eligible) {
304
+ diagnostics.push({
305
+ code: "SKIPPED_FIELD",
306
+ message: eligibility.skipReason.message,
307
+ severity: "warning",
308
+ location: {
309
+ file: resolver.sourceLocation.file,
310
+ line: resolver.sourceLocation.line,
311
+ column: resolver.sourceLocation.column,
312
+ },
313
+ });
314
+ continue;
315
+ }
316
+
289
317
  const returnType = resolver.returnType;
290
318
  const fieldDef: GraphQLFieldDefinition = {
291
319
  name: resolver.fieldName,
292
320
  type: convertTsTypeToGraphQLType(returnType),
293
321
  args: resolver.args ? convertArgsToInputValues(resolver.args) : null,
294
322
  sourceLocation: resolver.sourceLocation,
295
- resolverExportName: resolver.fieldName,
323
+ resolverExportName: resolver.resolverExportName,
296
324
  description: resolver.description,
297
325
  deprecated: resolver.deprecated,
298
326
  directives: resolver.directives,
@@ -316,6 +344,8 @@ function convertDefineApiToFields(
316
344
  queryFields.push(fieldDef);
317
345
  } else if (resolver.resolverType === "mutation") {
318
346
  mutationFields.push(fieldDef);
347
+ } else if (resolver.resolverType === "subscription") {
348
+ subscriptionFields.push(fieldDef);
319
349
  } else if (resolver.resolverType === "field" && resolver.parentTypeName) {
320
350
  const existing = typeExtensionMap.get(resolver.parentTypeName) ?? [];
321
351
  existing.push(fieldDef);
@@ -331,7 +361,9 @@ function convertDefineApiToFields(
331
361
  return {
332
362
  queryFields: { fields: queryFields },
333
363
  mutationFields: { fields: mutationFields },
364
+ subscriptionFields: { fields: subscriptionFields },
334
365
  typeExtensions,
366
+ diagnostics,
335
367
  };
336
368
  }
337
369
 
@@ -411,9 +443,11 @@ function extractResolversCore(
411
443
  allDiagnostics.push(...defineApiExtractionResult.diagnostics);
412
444
 
413
445
  const result = convertDefineApiToFields(defineApiExtractionResult.resolvers);
446
+ allDiagnostics.push(...result.diagnostics);
414
447
  return {
415
448
  queryFields: result.queryFields,
416
449
  mutationFields: result.mutationFields,
450
+ subscriptionFields: result.subscriptionFields,
417
451
  typeExtensions: result.typeExtensions,
418
452
  abstractTypeResolvers: defineApiExtractionResult.abstractTypeResolvers,
419
453
  diagnostics: collectDiagnostics(allDiagnostics),
@@ -602,6 +636,18 @@ function extractTypesStep(ctx: PipelineContext): PipelineContext {
602
636
  return { ...ctx, typesResult };
603
637
  }
604
638
 
639
+ function augmentKnownTypeNamesStep(ctx: PipelineContext): PipelineContext {
640
+ if (ctx.aborted || !ctx.typesResult || !ctx.knownTypeNames) return ctx;
641
+
642
+ if (ctx.typesResult.discoveredTypeNames.size === 0) return ctx;
643
+
644
+ const augmented = new Set(ctx.knownTypeNames);
645
+ for (const name of ctx.typesResult.discoveredTypeNames) {
646
+ augmented.add(name);
647
+ }
648
+ return { ...ctx, knownTypeNames: augmented };
649
+ }
650
+
605
651
  function extractResolversStep(ctx: PipelineContext): PipelineContext {
606
652
  if (
607
653
  ctx.aborted ||
@@ -693,8 +739,7 @@ function generateSchemaStep(ctx: PipelineContext): {
693
739
 
694
740
  const { customScalarNames } = ctx.scalarConfig;
695
741
  const allCustomScalarNames = [
696
- ...customScalarNames,
697
- ...ctx.typesResult.detectedScalarNames,
742
+ ...new Set([...customScalarNames, ...ctx.typesResult.detectedScalarNames]),
698
743
  ];
699
744
 
700
745
  const schemaResult = generateSchema({
@@ -712,6 +757,7 @@ function generateSchemaStep(ctx: PipelineContext): {
712
757
  sourceRoot: ctx.config.cwd,
713
758
  knownTypeNames: ctx.knownTypeNames,
714
759
  importExtension: ctx.config.output.importExtension,
760
+ discriminatorFields: ctx.config.discriminatorFields,
715
761
  });
716
762
 
717
763
  const newDiagnostics = [...ctx.diagnostics, ...schemaResult.diagnostics];
@@ -766,6 +812,7 @@ export async function executeGeneration(
766
812
  ctx = collectTypeNamesStep(ctx);
767
813
  ctx = prepareScalarConfigStep(ctx);
768
814
  ctx = extractTypesStep(ctx);
815
+ ctx = augmentKnownTypeNamesStep(ctx);
769
816
  ctx = extractResolversStep(ctx);
770
817
  ctx = extractDirectivesStep(ctx);
771
818
  ctx = validateExtractionStep(ctx);
@@ -68,6 +68,10 @@ export interface MutationFieldDefinitions {
68
68
  readonly fields: ReadonlyArray<GraphQLFieldDefinition>;
69
69
  }
70
70
 
71
+ export interface SubscriptionFieldDefinitions {
72
+ readonly fields: ReadonlyArray<GraphQLFieldDefinition>;
73
+ }
74
+
71
75
  export interface TypeExtension {
72
76
  readonly targetTypeName: string;
73
77
  readonly fields: ReadonlyArray<GraphQLFieldDefinition>;
@@ -76,6 +80,7 @@ export interface TypeExtension {
76
80
  export interface ExtractResolversResult {
77
81
  readonly queryFields: QueryFieldDefinitions;
78
82
  readonly mutationFields: MutationFieldDefinitions;
83
+ readonly subscriptionFields: SubscriptionFieldDefinitions;
79
84
  readonly typeExtensions: ReadonlyArray<TypeExtension>;
80
85
  readonly abstractTypeResolvers: ReadonlyArray<AbstractResolverInfo>;
81
86
  readonly diagnostics: Diagnostics;
@@ -35,7 +35,11 @@ import type {
35
35
  TSTypeReference,
36
36
  } from "../../type-extractor/types/index.js";
37
37
 
38
- export type DefineApiResolverType = "query" | "mutation" | "field";
38
+ export type DefineApiResolverType =
39
+ | "query"
40
+ | "mutation"
41
+ | "field"
42
+ | "subscription";
39
43
 
40
44
  export type AbstractResolverKind = "resolveType" | "isTypeOf";
41
45
 
@@ -56,6 +60,7 @@ export interface ArgumentDefinition {
56
60
 
57
61
  export interface DefineApiResolverInfo {
58
62
  readonly fieldName: string;
63
+ readonly resolverExportName: string;
59
64
  readonly resolverType: DefineApiResolverType;
60
65
  readonly parentTypeName: string | null;
61
66
  readonly argsType: TSTypeReference | null;
@@ -222,7 +227,12 @@ function detectResolverFromMetadataType(
222
227
  const kindType = checker.getTypeOfSymbol(kindProp);
223
228
  if (kindType.isStringLiteral()) {
224
229
  const kind = kindType.value;
225
- if (kind === "query" || kind === "mutation" || kind === "field") {
230
+ if (
231
+ kind === "query" ||
232
+ kind === "mutation" ||
233
+ kind === "field" ||
234
+ kind === "subscription"
235
+ ) {
226
236
  return kind;
227
237
  }
228
238
  }
@@ -230,6 +240,20 @@ function detectResolverFromMetadataType(
230
240
  return null;
231
241
  }
232
242
 
243
+ function resolveFieldNameFromExportName(exportName: string): string | null {
244
+ const delimiterIndex = exportName.lastIndexOf("$");
245
+ if (delimiterIndex === -1) {
246
+ return exportName;
247
+ }
248
+
249
+ const fieldName = exportName.slice(delimiterIndex + 1);
250
+ if (fieldName.length === 0) {
251
+ return null;
252
+ }
253
+
254
+ return fieldName;
255
+ }
256
+
233
257
  function isInlineTypeLiteralDeclaration(declaration: ts.Declaration): boolean {
234
258
  if (!ts.isPropertySignature(declaration)) {
235
259
  return false;
@@ -596,6 +620,8 @@ export function extractDefineApiResolvers(
596
620
  sourceFiles,
597
621
  scalarMappingTable,
598
622
  scalarMappingContext: "input",
623
+ discoveredTypes: null,
624
+ diagnostics: [],
599
625
  };
600
626
  const outputContext: FieldTypeResolverContext = {
601
627
  checker,
@@ -606,6 +632,8 @@ export function extractDefineApiResolvers(
606
632
  sourceFiles,
607
633
  scalarMappingTable,
608
634
  scalarMappingContext: "output",
635
+ discoveredTypes: null,
636
+ diagnostics: [],
609
637
  };
610
638
 
611
639
  for (const filePath of files) {
@@ -633,7 +661,7 @@ export function extractDefineApiResolvers(
633
661
  continue;
634
662
  }
635
663
 
636
- const fieldName = declaration.name.getText(sourceFile);
664
+ const exportName = declaration.name.getText(sourceFile);
637
665
  const initializer = declaration.initializer;
638
666
 
639
667
  if (!initializer) {
@@ -647,11 +675,11 @@ export function extractDefineApiResolvers(
647
675
  ) {
648
676
  const hasDefineCall = initializer
649
677
  .getText(sourceFile)
650
- .match(/define(Query|Mutation|Field)/);
678
+ .match(/define(Query|Mutation|Field|Subscription)/);
651
679
  if (hasDefineCall) {
652
680
  diagnostics.push({
653
681
  code: "INVALID_DEFINE_CALL",
654
- message: `Complex expressions with define* functions are not supported. Use a simple 'export const ${fieldName} = defineXxx(...)' pattern.`,
682
+ message: `Complex expressions with define* functions are not supported. Use a simple 'export const ${exportName} = defineXxx(...)' pattern.`,
655
683
  severity: "error",
656
684
  location: getSourceLocationFromNode(declaration.name),
657
685
  });
@@ -671,7 +699,7 @@ export function extractDefineApiResolvers(
671
699
  abstractTypeResolvers.push({
672
700
  kind: abstractResolverInfo.kind,
673
701
  targetTypeName: abstractResolverInfo.targetTypeName,
674
- exportName: fieldName,
702
+ exportName,
675
703
  sourceFile: filePath,
676
704
  sourceLocation,
677
705
  });
@@ -688,6 +716,17 @@ export function extractDefineApiResolvers(
688
716
  continue;
689
717
  }
690
718
 
719
+ const fieldName = resolveFieldNameFromExportName(exportName);
720
+ if (fieldName === null) {
721
+ diagnostics.push({
722
+ code: "INVALID_DEFINE_CALL",
723
+ message: `Resolver export '${exportName}' must have a non-empty field name after '$'.`,
724
+ severity: "error",
725
+ location: getSourceLocationFromNode(declaration.name),
726
+ });
727
+ continue;
728
+ }
729
+
691
730
  const funcName = ts.isIdentifier(initializer.expression)
692
731
  ? initializer.expression.text
693
732
  : undefined;
@@ -702,7 +741,7 @@ export function extractDefineApiResolvers(
702
741
  if (!typeInfo) {
703
742
  diagnostics.push({
704
743
  code: "INVALID_DEFINE_CALL",
705
- message: `Failed to extract type arguments from ${funcName ?? "define*"} call for '${fieldName}'`,
744
+ message: `Failed to extract type arguments from ${funcName ?? "define*"} call for '${exportName}'`,
706
745
  severity: "error",
707
746
  location: getSourceLocationFromNode(declaration.name),
708
747
  });
@@ -720,6 +759,7 @@ export function extractDefineApiResolvers(
720
759
 
721
760
  resolvers.push({
722
761
  fieldName,
762
+ resolverExportName: exportName,
723
763
  resolverType,
724
764
  parentTypeName: typeInfo.parentTypeName,
725
765
  argsType: typeInfo.argsType,
@@ -5,6 +5,7 @@ export type {
5
5
  GraphQLInputValue,
6
6
  MutationFieldDefinitions,
7
7
  QueryFieldDefinitions,
8
+ SubscriptionFieldDefinitions,
8
9
  TypeExtension,
9
10
  } from "./extract-resolvers.js";
10
11
  export type {
@@ -17,6 +17,8 @@ export interface ValidateAbstractResolversOptions {
17
17
  readonly abstractResolvers: ReadonlyArray<AbstractResolverInfo>;
18
18
  readonly baseTypes: ReadonlyArray<BaseType>;
19
19
  readonly typenameAutoResolveTypeNames?: ReadonlySet<string>;
20
+ /** Mapping from TypeScript type alias names to auto-generated GraphQL union names */
21
+ readonly tsAliasToGraphQLNameMap: ReadonlyMap<string, string>;
20
22
  }
21
23
 
22
24
  export interface ValidateAbstractResolversResult {
@@ -207,7 +209,22 @@ export function validateAbstractResolvers(
207
209
  typeMap.set(baseType.name, baseType);
208
210
  }
209
211
 
210
- for (const resolver of options.abstractResolvers) {
212
+ // Remap resolver target type names using TS alias → GraphQL name mapping
213
+ // e.g., defineResolveType<ItemPart> where ItemPart is a TS alias
214
+ // maps to the auto-generated union name "ContainerItems"
215
+ // Only remap resolveType resolvers — isTypeOf targets object types, not unions
216
+ const resolvers = options.abstractResolvers.map((resolver) => {
217
+ if (resolver.kind !== "resolveType") return resolver;
218
+ const mappedName = options.tsAliasToGraphQLNameMap.get(
219
+ resolver.targetTypeName,
220
+ );
221
+ if (mappedName !== undefined) {
222
+ return { ...resolver, targetTypeName: mappedName };
223
+ }
224
+ return resolver;
225
+ });
226
+
227
+ for (const resolver of resolvers) {
211
228
  const targetType = typeMap.get(resolver.targetTypeName);
212
229
 
213
230
  if (!targetType) {
@@ -241,14 +258,11 @@ export function validateAbstractResolvers(
241
258
  }
242
259
  }
243
260
 
244
- const duplicateDiagnostics = detectDuplicateResolvers(
245
- options.abstractResolvers,
246
- typeMap,
247
- );
261
+ const duplicateDiagnostics = detectDuplicateResolvers(resolvers, typeMap);
248
262
  diagnostics.push(...duplicateDiagnostics);
249
263
 
250
264
  const missingResolverWarnings = detectMissingAbstractTypeResolvers({
251
- resolvers: options.abstractResolvers,
265
+ resolvers,
252
266
  typeMap,
253
267
  typenameAutoResolveTypeNames:
254
268
  options.typenameAutoResolveTypeNames ?? new Set(),
@@ -1,4 +1,5 @@
1
1
  import path from "node:path";
2
+ import type { DiscriminatorResolveTypeInfo } from "../../auto-type-generator/discriminator-resolve-type-generator.js";
2
3
  import type { AutoGeneratedResolveType } from "../../auto-type-generator/resolve-type-generator.js";
3
4
  import { TYPENAME_FIELD_NAMES } from "../../auto-type-generator/typename-types.js";
4
5
  import type { ImportExtension } from "../../config/types.js";
@@ -15,9 +16,11 @@ import type {
15
16
  } from "../integrator/result-integrator.js";
16
17
  import type {
17
18
  AbstractTypeResolverInfo,
19
+ FieldResolver,
18
20
  ResolverInfo,
19
21
  TypeResolvers,
20
22
  } from "../resolver-collector/resolver-collector.js";
23
+ import { buildDiscriminatorResolveTypeEntry } from "./discriminator-resolve-type-emitter.js";
21
24
 
22
25
  const GENERATED_FILE_HEADER =
23
26
  "// This file is auto-generated by gqlkit. DO NOT EDIT.";
@@ -315,21 +318,33 @@ function buildStringEnumResolvers(
315
318
  return stringEnumMappings.map(buildStringEnumResolver);
316
319
  }
317
320
 
321
+ function buildFieldResolverValue(
322
+ localName: string,
323
+ field: FieldResolver,
324
+ ): string {
325
+ if (field.isDirectExport) {
326
+ return localName;
327
+ }
328
+ return `${localName}.${field.fieldName}`;
329
+ }
330
+
318
331
  function buildTypeResolverEntry(
319
332
  type: TypeResolvers,
320
333
  abstractResolverForType: AbstractTypeResolverInfo | null,
321
334
  ): string {
322
335
  const entries: string[] = [];
336
+ const isSubscription = type.typeName === "Subscription";
323
337
 
324
338
  for (const field of type.fields) {
325
339
  const localName = makeResolverLocalName(type.typeName, field.fieldName);
340
+ const resolverValue = buildFieldResolverValue(localName, field);
326
341
 
327
- if (field.isDirectExport) {
328
- entries.push(` ${field.fieldName}: ${localName},`);
329
- } else {
342
+ if (isSubscription) {
330
343
  entries.push(
331
- ` ${field.fieldName}: ${localName}.${field.fieldName},`,
344
+ ` ${field.fieldName}: { subscribe: ${resolverValue}, resolve: (event: unknown) => event },`,
332
345
  );
346
+ } else {
347
+ entries.push(` ${field.fieldName}: ${resolverValue},`);
333
348
  }
334
349
  }
335
350
 
@@ -361,11 +376,22 @@ function getResolveTypeExpression(
361
376
  return expressions.join(" ?? ");
362
377
  }
363
378
 
379
+ function buildResolveTypeObjType(
380
+ fieldPattern: AutoGeneratedResolveType["fieldPattern"],
381
+ ): string {
382
+ const fields = TYPENAME_FIELD_NAMES.filter((name) =>
383
+ fieldPattern.usedFieldNames.has(name),
384
+ ).map((name) => `${name}: string`);
385
+
386
+ return `{ ${fields.join("; ")} }`;
387
+ }
388
+
364
389
  function buildAutoResolveTypeEntry(
365
390
  autoResolveType: AutoGeneratedResolveType,
366
391
  ): string {
367
392
  const expression = getResolveTypeExpression(autoResolveType.fieldPattern);
368
- return ` ${autoResolveType.unionTypeName}: {\n __resolveType: (obj) => ${expression},\n },`;
393
+ const objType = buildResolveTypeObjType(autoResolveType.fieldPattern);
394
+ return ` ${autoResolveType.unionTypeName}: {\n __resolveType: (obj: ${objType}) => ${expression},\n },`;
369
395
  }
370
396
 
371
397
  function buildTypeEntries(
@@ -393,10 +419,16 @@ function buildTypeEntries(
393
419
  resolverInfo.autoGeneratedResolveTypes.map((r) => [r.unionTypeName, r]),
394
420
  );
395
421
 
422
+ const discriminatorResolveTypeByUnion = new Map<
423
+ string,
424
+ DiscriminatorResolveTypeInfo
425
+ >(resolverInfo.discriminatorResolveTypes.map((r) => [r.unionTypeName, r]));
426
+
396
427
  const allTypeNames = new Set<string>([
397
428
  ...typesWithFields.keys(),
398
429
  ...abstractResolversByType.keys(),
399
430
  ...autoResolveTypeByUnion.keys(),
431
+ ...discriminatorResolveTypeByUnion.keys(),
400
432
  ]);
401
433
  const sortedTypeNames = [...allTypeNames].sort();
402
434
 
@@ -404,6 +436,8 @@ function buildTypeEntries(
404
436
  const typeWithFields = typesWithFields.get(typeName);
405
437
  const abstractResolver = abstractResolversByType.get(typeName) ?? null;
406
438
  const autoResolveType = autoResolveTypeByUnion.get(typeName);
439
+ const discriminatorResolveType =
440
+ discriminatorResolveTypeByUnion.get(typeName);
407
441
 
408
442
  if (typeWithFields !== undefined) {
409
443
  typeEntries.push(
@@ -411,6 +445,10 @@ function buildTypeEntries(
411
445
  );
412
446
  } else if (abstractResolver !== null) {
413
447
  typeEntries.push(buildAbstractOnlyTypeEntry(abstractResolver));
448
+ } else if (discriminatorResolveType !== undefined) {
449
+ typeEntries.push(
450
+ buildDiscriminatorResolveTypeEntry(discriminatorResolveType),
451
+ );
414
452
  } else if (autoResolveType !== undefined) {
415
453
  typeEntries.push(buildAutoResolveTypeEntry(autoResolveType));
416
454
  }