@gqlkit-ts/cli 0.1.0 → 0.2.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 (234) hide show
  1. package/dist/auto-type-generator/auto-type-generator.d.ts +19 -3
  2. package/dist/auto-type-generator/auto-type-generator.d.ts.map +1 -1
  3. package/dist/auto-type-generator/auto-type-generator.js +236 -49
  4. package/dist/auto-type-generator/auto-type-generator.js.map +1 -1
  5. package/dist/auto-type-generator/index.d.ts +1 -1
  6. package/dist/auto-type-generator/index.d.ts.map +1 -1
  7. package/dist/auto-type-generator/index.js.map +1 -1
  8. package/dist/auto-type-generator/inline-enum-collector.d.ts +31 -0
  9. package/dist/auto-type-generator/inline-enum-collector.d.ts.map +1 -0
  10. package/dist/auto-type-generator/inline-enum-collector.js +157 -0
  11. package/dist/auto-type-generator/inline-enum-collector.js.map +1 -0
  12. package/dist/auto-type-generator/naming-convention.d.ts +4 -0
  13. package/dist/auto-type-generator/naming-convention.d.ts.map +1 -1
  14. package/dist/auto-type-generator/naming-convention.js +8 -0
  15. package/dist/auto-type-generator/naming-convention.js.map +1 -1
  16. package/dist/gen-orchestrator/orchestrator.d.ts.map +1 -1
  17. package/dist/gen-orchestrator/orchestrator.js +106 -8
  18. package/dist/gen-orchestrator/orchestrator.js.map +1 -1
  19. package/dist/resolver-extractor/extract-resolvers.d.ts +10 -1
  20. package/dist/resolver-extractor/extract-resolvers.d.ts.map +1 -1
  21. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts +11 -1
  22. package/dist/resolver-extractor/extractor/define-api-extractor.d.ts.map +1 -1
  23. package/dist/resolver-extractor/extractor/define-api-extractor.js +88 -264
  24. package/dist/resolver-extractor/extractor/define-api-extractor.js.map +1 -1
  25. package/dist/schema-generator/emitter/code-emitter.d.ts +10 -2
  26. package/dist/schema-generator/emitter/code-emitter.d.ts.map +1 -1
  27. package/dist/schema-generator/emitter/code-emitter.js +19 -4
  28. package/dist/schema-generator/emitter/code-emitter.js.map +1 -1
  29. package/dist/schema-generator/generate-schema.d.ts.map +1 -1
  30. package/dist/schema-generator/generate-schema.js +18 -1
  31. package/dist/schema-generator/generate-schema.js.map +1 -1
  32. package/dist/schema-generator/integrator/result-integrator.d.ts +20 -0
  33. package/dist/schema-generator/integrator/result-integrator.d.ts.map +1 -1
  34. package/dist/schema-generator/integrator/result-integrator.js +42 -0
  35. package/dist/schema-generator/integrator/result-integrator.js.map +1 -1
  36. package/dist/shared/constants.d.ts +0 -16
  37. package/dist/shared/constants.d.ts.map +1 -1
  38. package/dist/shared/constants.js +0 -19
  39. package/dist/shared/constants.js.map +1 -1
  40. package/dist/shared/directive-detector.d.ts.map +1 -1
  41. package/dist/shared/directive-detector.js +8 -15
  42. package/dist/shared/directive-detector.js.map +1 -1
  43. package/dist/shared/file-scanner.d.ts.map +1 -1
  44. package/dist/shared/file-scanner.js +5 -3
  45. package/dist/shared/file-scanner.js.map +1 -1
  46. package/dist/shared/index.d.ts +1 -1
  47. package/dist/shared/index.d.ts.map +1 -1
  48. package/dist/shared/index.js +1 -3
  49. package/dist/shared/index.js.map +1 -1
  50. package/dist/shared/interface-detector.d.ts +3 -2
  51. package/dist/shared/interface-detector.d.ts.map +1 -1
  52. package/dist/shared/interface-detector.js +54 -11
  53. package/dist/shared/interface-detector.js.map +1 -1
  54. package/dist/shared/path-utils.d.ts +2 -0
  55. package/dist/shared/path-utils.d.ts.map +1 -0
  56. package/dist/shared/path-utils.js +4 -0
  57. package/dist/shared/path-utils.js.map +1 -0
  58. package/dist/shared/type-converter.d.ts.map +1 -1
  59. package/dist/shared/type-converter.js +11 -0
  60. package/dist/shared/type-converter.js.map +1 -1
  61. package/dist/shared/typescript-utils.d.ts +34 -7
  62. package/dist/shared/typescript-utils.d.ts.map +1 -1
  63. package/dist/shared/typescript-utils.js +72 -24
  64. package/dist/shared/typescript-utils.js.map +1 -1
  65. package/dist/type-extractor/collector/scalar-collector.d.ts.map +1 -1
  66. package/dist/type-extractor/collector/scalar-collector.js +4 -14
  67. package/dist/type-extractor/collector/scalar-collector.js.map +1 -1
  68. package/dist/type-extractor/converter/graphql-converter.d.ts.map +1 -1
  69. package/dist/type-extractor/converter/graphql-converter.js +42 -3
  70. package/dist/type-extractor/converter/graphql-converter.js.map +1 -1
  71. package/dist/type-extractor/extractor/field-type-resolver.d.ts +28 -0
  72. package/dist/type-extractor/extractor/field-type-resolver.d.ts.map +1 -0
  73. package/dist/type-extractor/extractor/field-type-resolver.js +394 -0
  74. package/dist/type-extractor/extractor/field-type-resolver.js.map +1 -0
  75. package/dist/type-extractor/extractor/type-extractor.d.ts +12 -3
  76. package/dist/type-extractor/extractor/type-extractor.d.ts.map +1 -1
  77. package/dist/type-extractor/extractor/type-extractor.js +176 -210
  78. package/dist/type-extractor/extractor/type-extractor.js.map +1 -1
  79. package/dist/type-extractor/extractor/type-name-collector.d.ts +24 -0
  80. package/dist/type-extractor/extractor/type-name-collector.d.ts.map +1 -0
  81. package/dist/type-extractor/extractor/type-name-collector.js +102 -0
  82. package/dist/type-extractor/extractor/type-name-collector.js.map +1 -0
  83. package/dist/type-extractor/mapper/scalar-base-type-mapper.d.ts +89 -0
  84. package/dist/type-extractor/mapper/scalar-base-type-mapper.d.ts.map +1 -0
  85. package/dist/type-extractor/mapper/scalar-base-type-mapper.js +158 -0
  86. package/dist/type-extractor/mapper/scalar-base-type-mapper.js.map +1 -0
  87. package/dist/type-extractor/types/diagnostics.d.ts +1 -1
  88. package/dist/type-extractor/types/diagnostics.d.ts.map +1 -1
  89. package/dist/type-extractor/types/graphql.d.ts +2 -0
  90. package/dist/type-extractor/types/graphql.d.ts.map +1 -1
  91. package/dist/type-extractor/types/index.d.ts +2 -1
  92. package/dist/type-extractor/types/index.d.ts.map +1 -1
  93. package/dist/type-extractor/types/index.js +1 -1
  94. package/dist/type-extractor/types/index.js.map +1 -1
  95. package/dist/type-extractor/types/ts-type-reference-factory.d.ts +39 -0
  96. package/dist/type-extractor/types/ts-type-reference-factory.d.ts.map +1 -0
  97. package/dist/type-extractor/types/ts-type-reference-factory.js +69 -0
  98. package/dist/type-extractor/types/ts-type-reference-factory.js.map +1 -0
  99. package/dist/type-extractor/types/typescript.d.ts +21 -1
  100. package/dist/type-extractor/types/typescript.d.ts.map +1 -1
  101. package/dist/type-extractor/validator/type-validator.js +1 -1
  102. package/dist/type-extractor/validator/type-validator.js.map +1 -1
  103. package/docs/index.md +1 -0
  104. package/docs/integration/drizzle.md +191 -0
  105. package/docs/schema/enums.md +208 -0
  106. package/docs/schema/fields.md +2 -0
  107. package/docs/schema/inputs.md +2 -0
  108. package/docs/schema/objects.md +2 -0
  109. package/docs/schema/queries-mutations.md +2 -0
  110. package/package.json +10 -3
  111. package/src/auto-type-generator/auto-type-generator.ts +925 -0
  112. package/src/auto-type-generator/index.ts +21 -0
  113. package/src/auto-type-generator/inline-enum-collector.ts +290 -0
  114. package/src/auto-type-generator/name-collision-validator.ts +119 -0
  115. package/src/auto-type-generator/naming-convention.ts +126 -0
  116. package/src/cli.ts +11 -0
  117. package/src/commands/gen.ts +141 -0
  118. package/src/commands/main.ts +5 -0
  119. package/src/config/define-config.ts +28 -0
  120. package/src/config/index.ts +7 -0
  121. package/src/config/types.ts +144 -0
  122. package/src/config-loader/index.ts +14 -0
  123. package/src/config-loader/loader.ts +143 -0
  124. package/src/config-loader/validator.ts +672 -0
  125. package/src/gen-orchestrator/hook-executor/hook-executor.ts +117 -0
  126. package/src/gen-orchestrator/orchestrator.ts +784 -0
  127. package/src/gen-orchestrator/reporter/diagnostic-reporter.ts +44 -0
  128. package/src/gen-orchestrator/reporter/progress-reporter.ts +61 -0
  129. package/src/gen-orchestrator/writer/file-writer.ts +38 -0
  130. package/src/index.ts +2 -0
  131. package/src/resolver-extractor/extract-resolvers.ts +63 -0
  132. package/src/resolver-extractor/extractor/define-api-extractor.ts +806 -0
  133. package/src/resolver-extractor/index.ts +19 -0
  134. package/src/resolver-extractor/validator/abstract-resolver-validator.ts +251 -0
  135. package/src/resolver-extractor/validator/only-validator.ts +158 -0
  136. package/src/schema-generator/builder/ast-builder.ts +706 -0
  137. package/src/schema-generator/emitter/code-emitter.ts +351 -0
  138. package/src/schema-generator/emitter/sdl-emitter.ts +13 -0
  139. package/src/schema-generator/generate-schema.ts +170 -0
  140. package/src/schema-generator/index.ts +19 -0
  141. package/src/schema-generator/integrator/result-integrator.ts +690 -0
  142. package/src/schema-generator/pruner/schema-pruner.ts +112 -0
  143. package/src/schema-generator/resolver-collector/resolver-collector.ts +123 -0
  144. package/src/shared/constants.ts +122 -0
  145. package/src/shared/default-value-detector.ts +172 -0
  146. package/src/shared/diagnostics.ts +35 -0
  147. package/src/shared/directive-definition-extractor.ts +564 -0
  148. package/src/shared/directive-detector.ts +556 -0
  149. package/src/shared/file-scanner.ts +170 -0
  150. package/src/shared/index.ts +32 -0
  151. package/src/shared/inline-object-extractor.ts +102 -0
  152. package/src/shared/inline-object-utils.ts +23 -0
  153. package/src/shared/interface-detector.ts +176 -0
  154. package/src/shared/interface-validator.ts +211 -0
  155. package/src/shared/metadata-detector.ts +443 -0
  156. package/src/shared/path-utils.ts +3 -0
  157. package/src/shared/program-factory.ts +51 -0
  158. package/src/shared/source-location.ts +27 -0
  159. package/src/shared/tsconfig-loader.ts +126 -0
  160. package/src/shared/tsdoc-parser.ts +155 -0
  161. package/src/shared/type-converter.ts +99 -0
  162. package/src/shared/typescript-utils.ts +246 -0
  163. package/src/type-extractor/collector/result-collector.ts +57 -0
  164. package/src/type-extractor/collector/scalar-collector.ts +254 -0
  165. package/src/type-extractor/converter/field-eligibility.ts +112 -0
  166. package/src/type-extractor/converter/graphql-converter.ts +459 -0
  167. package/src/type-extractor/extract-types.ts +1 -0
  168. package/src/type-extractor/extractor/field-type-resolver.ts +569 -0
  169. package/src/type-extractor/extractor/type-extractor.ts +1567 -0
  170. package/src/type-extractor/extractor/type-name-collector.ts +130 -0
  171. package/src/type-extractor/index.ts +20 -0
  172. package/src/type-extractor/mapper/scalar-base-type-mapper.ts +265 -0
  173. package/src/type-extractor/types/diagnostics.ts +99 -0
  174. package/src/type-extractor/types/graphql.ts +55 -0
  175. package/src/type-extractor/types/index.ts +37 -0
  176. package/src/type-extractor/types/ts-type-reference-factory.ts +137 -0
  177. package/src/type-extractor/types/typescript.ts +133 -0
  178. package/src/type-extractor/validator/type-validator.ts +77 -0
  179. package/dist/auto-type-generator/auto-type-generator.test.d.ts +0 -2
  180. package/dist/auto-type-generator/auto-type-generator.test.d.ts.map +0 -1
  181. package/dist/auto-type-generator/auto-type-generator.test.js +0 -613
  182. package/dist/auto-type-generator/auto-type-generator.test.js.map +0 -1
  183. package/dist/auto-type-generator/name-collision-validator.test.d.ts +0 -2
  184. package/dist/auto-type-generator/name-collision-validator.test.d.ts.map +0 -1
  185. package/dist/auto-type-generator/name-collision-validator.test.js +0 -358
  186. package/dist/auto-type-generator/name-collision-validator.test.js.map +0 -1
  187. package/dist/auto-type-generator/naming-convention.test.d.ts +0 -2
  188. package/dist/auto-type-generator/naming-convention.test.d.ts.map +0 -1
  189. package/dist/auto-type-generator/naming-convention.test.js +0 -132
  190. package/dist/auto-type-generator/naming-convention.test.js.map +0 -1
  191. package/dist/commands/gen.test.d.ts +0 -2
  192. package/dist/commands/gen.test.d.ts.map +0 -1
  193. package/dist/commands/gen.test.js +0 -226
  194. package/dist/commands/gen.test.js.map +0 -1
  195. package/dist/config-loader/loader.test.d.ts +0 -2
  196. package/dist/config-loader/loader.test.d.ts.map +0 -1
  197. package/dist/config-loader/loader.test.js +0 -123
  198. package/dist/config-loader/loader.test.js.map +0 -1
  199. package/dist/config-loader/validator.test.d.ts +0 -2
  200. package/dist/config-loader/validator.test.d.ts.map +0 -1
  201. package/dist/config-loader/validator.test.js +0 -846
  202. package/dist/config-loader/validator.test.js.map +0 -1
  203. package/dist/gen-orchestrator/golden.test.d.ts +0 -2
  204. package/dist/gen-orchestrator/golden.test.d.ts.map +0 -1
  205. package/dist/gen-orchestrator/golden.test.js +0 -102
  206. package/dist/gen-orchestrator/golden.test.js.map +0 -1
  207. package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts +0 -2
  208. package/dist/gen-orchestrator/hook-executor/hook-executor.test.d.ts.map +0 -1
  209. package/dist/gen-orchestrator/hook-executor/hook-executor.test.js +0 -167
  210. package/dist/gen-orchestrator/hook-executor/hook-executor.test.js.map +0 -1
  211. package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts +0 -2
  212. package/dist/gen-orchestrator/reporter/progress-reporter.test.d.ts.map +0 -1
  213. package/dist/gen-orchestrator/reporter/progress-reporter.test.js +0 -74
  214. package/dist/gen-orchestrator/reporter/progress-reporter.test.js.map +0 -1
  215. package/dist/resolver-extractor/validator/only-validator.test.d.ts +0 -8
  216. package/dist/resolver-extractor/validator/only-validator.test.d.ts.map +0 -1
  217. package/dist/resolver-extractor/validator/only-validator.test.js +0 -352
  218. package/dist/resolver-extractor/validator/only-validator.test.js.map +0 -1
  219. package/dist/schema-generator/builder/ast-builder.test.d.ts +0 -2
  220. package/dist/schema-generator/builder/ast-builder.test.d.ts.map +0 -1
  221. package/dist/schema-generator/builder/ast-builder.test.js +0 -469
  222. package/dist/schema-generator/builder/ast-builder.test.js.map +0 -1
  223. package/dist/shared/file-scanner.test.d.ts +0 -2
  224. package/dist/shared/file-scanner.test.d.ts.map +0 -1
  225. package/dist/shared/file-scanner.test.js +0 -138
  226. package/dist/shared/file-scanner.test.js.map +0 -1
  227. package/dist/shared/interface-validator.test.d.ts +0 -2
  228. package/dist/shared/interface-validator.test.d.ts.map +0 -1
  229. package/dist/shared/interface-validator.test.js +0 -145
  230. package/dist/shared/interface-validator.test.js.map +0 -1
  231. package/dist/type-extractor/types/typescript.test.d.ts +0 -2
  232. package/dist/type-extractor/types/typescript.test.d.ts.map +0 -1
  233. package/dist/type-extractor/types/typescript.test.js +0 -287
  234. package/dist/type-extractor/types/typescript.test.js.map +0 -1
@@ -0,0 +1,569 @@
1
+ import ts from "typescript";
2
+ import { isInternalTypeSymbol } from "../../shared/constants.js";
3
+ import { extractInlineObjectProperties as extractInlineObjectPropertiesShared } from "../../shared/inline-object-extractor.js";
4
+ import { isInlineObjectType } from "../../shared/inline-object-utils.js";
5
+ import { detectScalarMetadata } from "../../shared/metadata-detector.js";
6
+ import {
7
+ type DeprecationInfo,
8
+ extractTsDocFromSymbol,
9
+ } from "../../shared/tsdoc-parser.js";
10
+ import {
11
+ findEnumParentSymbol,
12
+ findNonNullTypeNode,
13
+ getNonNullableTypes,
14
+ getTypeNameFromNode,
15
+ isBooleanUnion,
16
+ isNullableUnion,
17
+ resolveOriginalSymbol,
18
+ } from "../../shared/typescript-utils.js";
19
+ import type {
20
+ ScalarBaseTypeMappingTable,
21
+ ScalarMappingContext,
22
+ } from "../mapper/scalar-base-type-mapper.js";
23
+ import { lookupScalarMapping } from "../mapper/scalar-base-type-mapper.js";
24
+ import {
25
+ createArrayType,
26
+ createInlineEnumType,
27
+ createInlineObjectType,
28
+ createLiteralType,
29
+ createPrimitiveType,
30
+ createReferenceType,
31
+ createScalarType,
32
+ createUnionType,
33
+ } from "../types/ts-type-reference-factory.js";
34
+ import type {
35
+ InlineEnumMemberInfo,
36
+ TSTypeReference,
37
+ } from "../types/typescript.js";
38
+ import type { GlobalTypeMapping } from "./type-extractor.js";
39
+
40
+ export interface FieldTypeResolverContext {
41
+ readonly checker: ts.TypeChecker;
42
+ readonly knownTypeNames: ReadonlySet<string>;
43
+ readonly knownTypeSymbols: ReadonlyMap<string, ts.Symbol>;
44
+ readonly underlyingSymbolToTypeName: ReadonlyMap<ts.Symbol, string>;
45
+ readonly globalTypeMappings: ReadonlyArray<GlobalTypeMapping>;
46
+ readonly sourceFiles: ReadonlySet<string>;
47
+ /** Scalar base type mapping table for automatic base type -> scalar mapping */
48
+ readonly scalarMappingTable: ScalarBaseTypeMappingTable | null;
49
+ /** Current resolution context for scalar mapping (input or output) */
50
+ readonly scalarMappingContext: ScalarMappingContext;
51
+ }
52
+
53
+ /**
54
+ * Internal context including cycle detection state.
55
+ */
56
+ interface InternalFieldTypeContext extends FieldTypeResolverContext {
57
+ readonly visitedTypes: WeakSet<ts.Type>;
58
+ }
59
+
60
+ /**
61
+ * Resolves a TypeScript type to a TSTypeReference for use in field context.
62
+ *
63
+ * This function is specifically for field type resolution (not type declarations).
64
+ * Key differences from type declaration context:
65
+ * - Uses knownTypeNames to determine if a type exists in the schema
66
+ * - Intersection types are always treated as inline objects
67
+ * - Utility types (both builtin and user-defined) are treated as inline objects
68
+ * unless they are explicitly declared in the schema
69
+ */
70
+ export function resolveFieldType(
71
+ type: ts.Type,
72
+ typeNode: ts.TypeNode | undefined,
73
+ ctx: FieldTypeResolverContext,
74
+ ): TSTypeReference {
75
+ const internalCtx: InternalFieldTypeContext = {
76
+ ...ctx,
77
+ visitedTypes: new WeakSet(),
78
+ };
79
+ return resolveFieldTypeInternal(type, typeNode, internalCtx);
80
+ }
81
+
82
+ function resolveFieldTypeInternal(
83
+ type: ts.Type,
84
+ typeNode: ts.TypeNode | undefined,
85
+ ctx: InternalFieldTypeContext,
86
+ ): TSTypeReference {
87
+ const { checker, knownTypeNames, globalTypeMappings } = ctx;
88
+
89
+ // Scalar detection
90
+ const metadataResult = detectScalarMetadata(type, checker);
91
+ if (
92
+ metadataResult.scalarName &&
93
+ !metadataResult.isPrimitive &&
94
+ !metadataResult.isList
95
+ ) {
96
+ return createScalarType({
97
+ name: metadataResult.scalarName,
98
+ scalarInfo: {
99
+ scalarName: metadataResult.scalarName,
100
+ typeName: metadataResult.scalarName,
101
+ baseType: undefined,
102
+ isCustom: true,
103
+ only: metadataResult.only,
104
+ },
105
+ nullable: metadataResult.nullable,
106
+ });
107
+ }
108
+
109
+ // Boolean union handling
110
+ if (isBooleanUnion(type)) {
111
+ const nullable = isNullableUnion(type);
112
+ return createPrimitiveType({ name: "boolean", nullable });
113
+ }
114
+
115
+ // Union type handling
116
+ if (type.isUnion()) {
117
+ const nullable = isNullableUnion(type);
118
+
119
+ // Preserve type alias name for enum types (string literal unions)
120
+ const aliasSymbol = type.aliasSymbol;
121
+ if (aliasSymbol) {
122
+ const name = aliasSymbol.getName();
123
+ if (isKnownSchemaType(name, aliasSymbol, ctx)) {
124
+ return createReferenceType({ name, nullable });
125
+ }
126
+ }
127
+
128
+ // Fallback: Extract name from typeNode when aliasSymbol is not available (e.g., re-exported types)
129
+ if (typeNode && ts.isTypeReferenceNode(typeNode)) {
130
+ const typeName = getTypeNameFromNode(typeNode);
131
+ const nodeSymbol = checker.getSymbolAtLocation(typeNode.typeName);
132
+ if (
133
+ typeName &&
134
+ isKnownSchemaType(typeName, nodeSymbol ?? undefined, ctx)
135
+ ) {
136
+ return createReferenceType({ name: typeName, nullable });
137
+ }
138
+ }
139
+
140
+ const nonNullTypes = getNonNullableTypes(type);
141
+
142
+ // Check if all non-null types belong to the same enum
143
+ const enumParentSymbol = findEnumParentSymbol(nonNullTypes);
144
+ if (enumParentSymbol) {
145
+ const enumName = enumParentSymbol.getName();
146
+ // If enum is in knownTypeNames, treat as reference type
147
+ if (isKnownSchemaType(enumName, enumParentSymbol, ctx)) {
148
+ return createReferenceType({ name: enumName, nullable });
149
+ }
150
+ // External enum: extract members and treat as inline enum
151
+ const externalEnumResult = tryExtractExternalEnumAsInlineEnum(
152
+ enumParentSymbol,
153
+ checker,
154
+ );
155
+ if (externalEnumResult) {
156
+ return createInlineEnumType({
157
+ members: externalEnumResult.members,
158
+ nullable,
159
+ externalEnumSymbol: enumParentSymbol,
160
+ externalEnumDescription: externalEnumResult.description,
161
+ externalEnumDeprecated: externalEnumResult.deprecated,
162
+ });
163
+ }
164
+ }
165
+
166
+ // Check if all non-null types are string literals (inline enum)
167
+ const inlineEnumResult = tryExtractAsInlineEnum(nonNullTypes);
168
+ if (inlineEnumResult) {
169
+ return createInlineEnumType({
170
+ members: inlineEnumResult,
171
+ nullable,
172
+ externalEnumSymbol: null,
173
+ externalEnumDescription: null,
174
+ externalEnumDeprecated: null,
175
+ });
176
+ }
177
+
178
+ if (nonNullTypes.length === 1) {
179
+ const nonNullTypeNode =
180
+ typeNode && ts.isUnionTypeNode(typeNode)
181
+ ? findNonNullTypeNode(typeNode)
182
+ : undefined;
183
+
184
+ const innerResult = resolveFieldTypeInternal(
185
+ nonNullTypes[0]!,
186
+ nonNullTypeNode,
187
+ ctx,
188
+ );
189
+ return { ...innerResult, nullable };
190
+ }
191
+
192
+ const memberResults = nonNullTypes.map((t) =>
193
+ resolveFieldTypeInternal(t, undefined, ctx),
194
+ );
195
+
196
+ return createUnionType({ members: memberResults, nullable });
197
+ }
198
+
199
+ // Array type handling
200
+ if (checker.isArrayType(type)) {
201
+ const typeArgs = (type as ts.TypeReference).typeArguments;
202
+ const elementType = typeArgs?.[0];
203
+
204
+ let elementTypeNode: ts.TypeNode | undefined;
205
+ if (typeNode && ts.isArrayTypeNode(typeNode)) {
206
+ elementTypeNode = typeNode.elementType;
207
+ }
208
+
209
+ const elementResult = elementType
210
+ ? resolveFieldTypeInternal(elementType, elementTypeNode, ctx)
211
+ : createPrimitiveType({ name: "unknown", nullable: false });
212
+
213
+ return createArrayType(elementResult);
214
+ }
215
+
216
+ // Primitive types
217
+ const typeString = checker.typeToString(type);
218
+
219
+ if (type.flags & ts.TypeFlags.String) {
220
+ return createPrimitiveType({ name: "string", nullable: false });
221
+ }
222
+ if (type.flags & ts.TypeFlags.Number) {
223
+ return createPrimitiveType({ name: "number", nullable: false });
224
+ }
225
+ if (
226
+ type.flags & ts.TypeFlags.Boolean ||
227
+ type.flags & ts.TypeFlags.BooleanLiteral
228
+ ) {
229
+ return createPrimitiveType({ name: "boolean", nullable: false });
230
+ }
231
+ if (type.flags & ts.TypeFlags.StringLiteral) {
232
+ return createLiteralType(typeString.replace(/"/g, ""));
233
+ }
234
+ if (type.flags & ts.TypeFlags.NumberLiteral) {
235
+ return createLiteralType(typeString);
236
+ }
237
+
238
+ // Intersection types in field context are ALWAYS treated as inline objects
239
+ // GraphQL doesn't have intersection types, so we must expand them
240
+ if (type.isIntersection()) {
241
+ // If the intersection has an alias that's in knownTypeNames, use it
242
+ if (type.aliasSymbol) {
243
+ const aliasName = type.aliasSymbol.getName();
244
+ if (isKnownSchemaType(aliasName, type.aliasSymbol, ctx)) {
245
+ return createReferenceType({ name: aliasName, nullable: false });
246
+ }
247
+ }
248
+
249
+ // Otherwise, treat as inline object
250
+ return tryExtractAsInlineObject(type, ctx);
251
+ }
252
+
253
+ // Inline object type handling
254
+ if (isInlineObjectType(type)) {
255
+ // Check if typeNode references a known type
256
+ if (typeNode && ts.isTypeReferenceNode(typeNode)) {
257
+ const typeName = getTypeNameFromNode(typeNode);
258
+ const nodeSymbol = checker.getSymbolAtLocation(typeNode.typeName);
259
+ if (
260
+ typeName &&
261
+ isKnownSchemaType(typeName, nodeSymbol ?? undefined, ctx)
262
+ ) {
263
+ return createReferenceType({ name: typeName, nullable: false });
264
+ }
265
+ }
266
+
267
+ return tryExtractAsInlineObject(type, ctx);
268
+ }
269
+
270
+ // Mapped types (utility types like Omit, Pick, user-defined utilities)
271
+ if (type.flags & ts.TypeFlags.Object) {
272
+ const objectType = type as ts.ObjectType;
273
+ if (objectType.objectFlags & ts.ObjectFlags.Mapped) {
274
+ // Check if typeNode references a known type (schema-defined type)
275
+ if (typeNode && ts.isTypeReferenceNode(typeNode)) {
276
+ const typeName = getTypeNameFromNode(typeNode);
277
+ const nodeSymbol = checker.getSymbolAtLocation(typeNode.typeName);
278
+ if (
279
+ typeName &&
280
+ isKnownSchemaType(typeName, nodeSymbol ?? undefined, ctx)
281
+ ) {
282
+ return createReferenceType({ name: typeName, nullable: false });
283
+ }
284
+ }
285
+ // Not a known type - treat as inline object
286
+ return tryExtractAsInlineObject(type, ctx);
287
+ }
288
+ }
289
+
290
+ // Extract type name from typeNode first (takes precedence over type.symbol).
291
+ // This handles cases like:
292
+ // - `typeof def` where the type's symbol is internal (__type, __object)
293
+ // - `Simplify<T>` where the typeNode is the declared alias name but type.symbol is the expanded type
294
+ if (typeNode && ts.isTypeReferenceNode(typeNode)) {
295
+ const typeName = getTypeNameFromNode(typeNode);
296
+ const nodeSymbol = checker.getSymbolAtLocation(typeNode.typeName);
297
+ if (typeName && isKnownSchemaType(typeName, nodeSymbol ?? undefined, ctx)) {
298
+ return createReferenceType({ name: typeName, nullable: false });
299
+ }
300
+ }
301
+
302
+ // Named type reference (symbol-based lookup)
303
+ if (type.symbol) {
304
+ const symbolName = type.symbol.getName();
305
+
306
+ if (!isInternalTypeSymbol(symbolName)) {
307
+ // Check for global type mappings (custom scalars)
308
+ const globalMapping = globalTypeMappings.find(
309
+ (m) => m.typeName === symbolName,
310
+ );
311
+ if (globalMapping) {
312
+ return createScalarType({
313
+ name: globalMapping.scalarName,
314
+ scalarInfo: {
315
+ scalarName: globalMapping.scalarName,
316
+ typeName: globalMapping.typeName,
317
+ baseType: undefined,
318
+ isCustom: true,
319
+ only: globalMapping.only,
320
+ },
321
+ nullable: false,
322
+ });
323
+ }
324
+
325
+ // Check if it's a known type by symbol comparison
326
+ if (isKnownSchemaType(symbolName, type.symbol, ctx)) {
327
+ return createReferenceType({ name: symbolName, nullable: false });
328
+ }
329
+
330
+ // Check if the symbol is the underlying type of a schema type alias
331
+ // For `type User = ExternalUser;`, this allows `ExternalUser` to be recognized as `User`
332
+ const resolvedSymbol = resolveOriginalSymbol(type.symbol, checker);
333
+ const schemaTypeName = ctx.underlyingSymbolToTypeName.get(resolvedSymbol);
334
+ if (schemaTypeName) {
335
+ return createReferenceType({ name: schemaTypeName, nullable: false });
336
+ }
337
+
338
+ // If the name exists in schema but symbol doesn't match,
339
+ // it's a different type with the same name
340
+ if (knownTypeNames.has(symbolName)) {
341
+ // Check if the type is declared within schema files (local shadowing)
342
+ if (isTypeFromSchemaFiles(type.symbol, ctx.sourceFiles)) {
343
+ // Local shadowing - use name matching for backwards compatibility
344
+ return createReferenceType({ name: symbolName, nullable: false });
345
+ }
346
+ // Type from outside schema files - expand as inline object
347
+ return tryExtractAsInlineObject(type, ctx);
348
+ }
349
+
350
+ // Check for scalar base type mapping
351
+ // This allows automatic mapping of base types (e.g., Date) to scalar types (e.g., DateTime)
352
+ if (ctx.scalarMappingTable) {
353
+ const scalarMappingResult = lookupScalarMapping({
354
+ baseTypeSymbol: resolvedSymbol,
355
+ context: ctx.scalarMappingContext,
356
+ table: ctx.scalarMappingTable,
357
+ });
358
+
359
+ if (scalarMappingResult.mapping) {
360
+ return createScalarType({
361
+ name: scalarMappingResult.mapping.scalarName,
362
+ scalarInfo: {
363
+ scalarName: scalarMappingResult.mapping.scalarName,
364
+ typeName: scalarMappingResult.mapping.sourceTypeName,
365
+ baseType: undefined,
366
+ isCustom: true,
367
+ only: scalarMappingResult.mapping.only,
368
+ },
369
+ nullable: false,
370
+ });
371
+ }
372
+ // Note: Conflicts are handled at the pipeline level, not here
373
+ }
374
+
375
+ // Check for external TypeScript enum (not in knownTypeNames)
376
+ // When a field uses an enum type directly (not as a union), handle it here
377
+ // Check both symbol flags and declarations since the flags may vary
378
+ const isEnumSymbol =
379
+ (resolvedSymbol.flags & ts.SymbolFlags.Enum) !== 0 ||
380
+ resolvedSymbol.getDeclarations()?.some(ts.isEnumDeclaration) === true;
381
+ if (isEnumSymbol) {
382
+ const externalEnumResult = tryExtractExternalEnumAsInlineEnum(
383
+ resolvedSymbol,
384
+ checker,
385
+ );
386
+ if (externalEnumResult) {
387
+ return createInlineEnumType({
388
+ members: externalEnumResult.members,
389
+ nullable: false,
390
+ externalEnumSymbol: resolvedSymbol,
391
+ externalEnumDescription: externalEnumResult.description,
392
+ externalEnumDeprecated: externalEnumResult.deprecated,
393
+ });
394
+ }
395
+ }
396
+
397
+ // Unknown type - still return reference but it will likely cause validation error later
398
+ return createReferenceType({ name: symbolName, nullable: false });
399
+ }
400
+ }
401
+
402
+ return createReferenceType({ name: typeString, nullable: false });
403
+ }
404
+
405
+ function tryExtractAsInlineObject(
406
+ type: ts.Type,
407
+ ctx: InternalFieldTypeContext,
408
+ ): TSTypeReference {
409
+ const { visitedTypes } = ctx;
410
+ if (visitedTypes.has(type)) {
411
+ // Cycle detected, return a placeholder reference
412
+ const typeName = type.symbol?.getName() ?? "Unknown";
413
+ return createReferenceType({ name: typeName, nullable: false });
414
+ }
415
+
416
+ visitedTypes.add(type);
417
+
418
+ const inlineProperties = extractInlineObjectPropertiesShared(
419
+ type,
420
+ ctx.checker,
421
+ (propType) => resolveFieldTypeInternal(propType, undefined, ctx),
422
+ );
423
+
424
+ return createInlineObjectType(inlineProperties);
425
+ }
426
+
427
+ /**
428
+ * Checks if all types are string literals and extracts them as inline enum members.
429
+ * Returns null if any type is not a string literal.
430
+ */
431
+ function tryExtractAsInlineEnum(
432
+ types: ReadonlyArray<ts.Type>,
433
+ ): ReadonlyArray<InlineEnumMemberInfo> | null {
434
+ if (types.length === 0) {
435
+ return null;
436
+ }
437
+
438
+ const members: InlineEnumMemberInfo[] = [];
439
+
440
+ for (const type of types) {
441
+ if (!(type.flags & ts.TypeFlags.StringLiteral)) {
442
+ return null;
443
+ }
444
+
445
+ const literalType = type as ts.StringLiteralType;
446
+ const value = literalType.value;
447
+
448
+ members.push({
449
+ value,
450
+ description: null,
451
+ deprecated: null,
452
+ });
453
+ }
454
+
455
+ return members;
456
+ }
457
+
458
+ /**
459
+ * Result of extracting an external TypeScript enum.
460
+ * Includes both member info and type-level TSDoc.
461
+ */
462
+ interface ExternalEnumExtractionResult {
463
+ readonly members: ReadonlyArray<InlineEnumMemberInfo>;
464
+ /** TSDoc description from the enum type itself */
465
+ readonly description: string | null;
466
+ /** @deprecated tag from the enum type itself */
467
+ readonly deprecated: DeprecationInfo | null;
468
+ }
469
+
470
+ /**
471
+ * Extracts enum members from an external TypeScript enum symbol.
472
+ * Returns the member info including TSDoc description and deprecated status,
473
+ * as well as the enum type's own TSDoc information.
474
+ * Returns null if the enum declaration cannot be found or has no valid members.
475
+ */
476
+ function tryExtractExternalEnumAsInlineEnum(
477
+ enumSymbol: ts.Symbol,
478
+ checker: ts.TypeChecker,
479
+ ): ExternalEnumExtractionResult | null {
480
+ const declarations = enumSymbol.getDeclarations();
481
+ if (!declarations || declarations.length === 0) {
482
+ return null;
483
+ }
484
+
485
+ const enumDeclaration = declarations.find(ts.isEnumDeclaration);
486
+ if (!enumDeclaration) {
487
+ return null;
488
+ }
489
+
490
+ const members: InlineEnumMemberInfo[] = [];
491
+
492
+ for (const member of enumDeclaration.members) {
493
+ const initializer = member.initializer;
494
+ if (!initializer || !ts.isStringLiteral(initializer)) {
495
+ continue;
496
+ }
497
+
498
+ const value = initializer.text;
499
+ const memberSymbol = checker.getSymbolAtLocation(member.name);
500
+ const tsdocInfo = memberSymbol
501
+ ? extractTsDocFromSymbol(memberSymbol, checker)
502
+ : { description: null, deprecated: null };
503
+
504
+ members.push({
505
+ value,
506
+ description: tsdocInfo.description,
507
+ deprecated: tsdocInfo.deprecated,
508
+ });
509
+ }
510
+
511
+ if (members.length === 0) {
512
+ return null;
513
+ }
514
+
515
+ // Extract TSDoc from the enum type itself
516
+ const enumTsDoc = extractTsDocFromSymbol(enumSymbol, checker);
517
+
518
+ return {
519
+ members,
520
+ description: enumTsDoc.description,
521
+ deprecated: enumTsDoc.deprecated,
522
+ };
523
+ }
524
+
525
+ /**
526
+ * Checks if a type's symbol matches the known schema type symbol.
527
+ * Returns true if both name matches AND symbol matches (or if symbol comparison is not possible).
528
+ */
529
+ function isKnownSchemaType(
530
+ name: string,
531
+ typeSymbol: ts.Symbol | undefined,
532
+ ctx: FieldTypeResolverContext,
533
+ ): boolean {
534
+ const { knownTypeNames, knownTypeSymbols, checker } = ctx;
535
+
536
+ if (!knownTypeNames.has(name)) {
537
+ return false;
538
+ }
539
+
540
+ const schemaSymbol = knownTypeSymbols.get(name);
541
+ if (!schemaSymbol || !typeSymbol) {
542
+ return false;
543
+ }
544
+
545
+ const resolvedTypeSymbol = resolveOriginalSymbol(typeSymbol, checker);
546
+ return resolvedTypeSymbol === schemaSymbol;
547
+ }
548
+
549
+ /**
550
+ * Checks if a type's symbol is declared within the schema source files.
551
+ * Returns true if the type is a local definition (shadowing), false if from external files.
552
+ */
553
+ function isTypeFromSchemaFiles(
554
+ symbol: ts.Symbol,
555
+ sourceFiles: ReadonlySet<string>,
556
+ ): boolean {
557
+ const declarations = symbol.getDeclarations();
558
+ if (!declarations || declarations.length === 0) {
559
+ return false;
560
+ }
561
+
562
+ const declaration = declarations[0];
563
+ if (!declaration) {
564
+ return false;
565
+ }
566
+
567
+ const sourceFile = declaration.getSourceFile();
568
+ return sourceFiles.has(sourceFile.fileName);
569
+ }