@constructive-io/graphql-codegen 2.19.0 → 2.20.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 (301) hide show
  1. package/README.md +1818 -113
  2. package/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  3. package/__tests__/codegen/input-types-generator.test.js +635 -0
  4. package/cli/codegen/barrel.d.ts +27 -0
  5. package/cli/codegen/barrel.js +163 -0
  6. package/cli/codegen/client.d.ts +4 -0
  7. package/cli/codegen/client.js +170 -0
  8. package/cli/codegen/custom-mutations.d.ts +38 -0
  9. package/cli/codegen/custom-mutations.js +149 -0
  10. package/cli/codegen/custom-queries.d.ts +38 -0
  11. package/cli/codegen/custom-queries.js +358 -0
  12. package/cli/codegen/filters.d.ts +27 -0
  13. package/cli/codegen/filters.js +357 -0
  14. package/cli/codegen/gql-ast.d.ts +41 -0
  15. package/cli/codegen/gql-ast.js +329 -0
  16. package/cli/codegen/index.d.ts +71 -0
  17. package/cli/codegen/index.js +147 -0
  18. package/cli/codegen/mutations.d.ts +30 -0
  19. package/cli/codegen/mutations.js +410 -0
  20. package/cli/codegen/orm/barrel.d.ts +18 -0
  21. package/cli/codegen/orm/barrel.js +48 -0
  22. package/cli/codegen/orm/client-generator.d.ts +45 -0
  23. package/cli/codegen/orm/client-generator.js +646 -0
  24. package/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  25. package/cli/codegen/orm/custom-ops-generator.js +350 -0
  26. package/cli/codegen/orm/index.d.ts +38 -0
  27. package/cli/codegen/orm/index.js +88 -0
  28. package/cli/codegen/orm/input-types-generator.d.ts +21 -0
  29. package/cli/codegen/orm/input-types-generator.js +705 -0
  30. package/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  31. package/cli/codegen/orm/input-types-generator.test.js +75 -0
  32. package/cli/codegen/orm/model-generator.d.ts +32 -0
  33. package/cli/codegen/orm/model-generator.js +264 -0
  34. package/cli/codegen/orm/query-builder.d.ts +161 -0
  35. package/cli/codegen/orm/query-builder.js +366 -0
  36. package/cli/codegen/orm/select-types.d.ts +169 -0
  37. package/cli/codegen/orm/select-types.js +16 -0
  38. package/cli/codegen/orm/select-types.test.d.ts +11 -0
  39. package/cli/codegen/orm/select-types.test.js +22 -0
  40. package/cli/codegen/queries.d.ts +25 -0
  41. package/cli/codegen/queries.js +438 -0
  42. package/cli/codegen/scalars.d.ts +12 -0
  43. package/cli/codegen/scalars.js +71 -0
  44. package/cli/codegen/schema-gql-ast.d.ts +51 -0
  45. package/cli/codegen/schema-gql-ast.js +385 -0
  46. package/cli/codegen/ts-ast.d.ts +122 -0
  47. package/cli/codegen/ts-ast.js +280 -0
  48. package/cli/codegen/type-resolver.d.ts +96 -0
  49. package/cli/codegen/type-resolver.js +246 -0
  50. package/cli/codegen/types.d.ts +12 -0
  51. package/cli/codegen/types.js +69 -0
  52. package/cli/codegen/utils.d.ts +163 -0
  53. package/cli/codegen/utils.js +326 -0
  54. package/cli/commands/generate-orm.d.ts +37 -0
  55. package/cli/commands/generate-orm.js +195 -0
  56. package/cli/commands/generate.d.ts +39 -0
  57. package/cli/commands/generate.js +299 -0
  58. package/cli/commands/index.d.ts +7 -0
  59. package/cli/commands/index.js +12 -0
  60. package/cli/commands/init.d.ts +35 -0
  61. package/cli/commands/init.js +176 -0
  62. package/cli/index.d.ts +4 -0
  63. package/cli/index.js +291 -0
  64. package/cli/introspect/fetch-meta.d.ts +31 -0
  65. package/cli/introspect/fetch-meta.js +108 -0
  66. package/cli/introspect/fetch-schema.d.ts +21 -0
  67. package/cli/introspect/fetch-schema.js +86 -0
  68. package/cli/introspect/index.d.ts +8 -0
  69. package/cli/introspect/index.js +16 -0
  70. package/cli/introspect/meta-query.d.ts +111 -0
  71. package/cli/introspect/meta-query.js +191 -0
  72. package/cli/introspect/schema-query.d.ts +20 -0
  73. package/cli/introspect/schema-query.js +123 -0
  74. package/cli/introspect/transform-schema.d.ts +74 -0
  75. package/cli/introspect/transform-schema.js +269 -0
  76. package/cli/introspect/transform-schema.test.d.ts +1 -0
  77. package/cli/introspect/transform-schema.test.js +67 -0
  78. package/cli/introspect/transform.d.ts +21 -0
  79. package/cli/introspect/transform.js +216 -0
  80. package/cli/watch/cache.d.ts +45 -0
  81. package/cli/watch/cache.js +111 -0
  82. package/cli/watch/debounce.d.ts +19 -0
  83. package/cli/watch/debounce.js +89 -0
  84. package/cli/watch/hash.d.ts +17 -0
  85. package/cli/watch/hash.js +48 -0
  86. package/cli/watch/index.d.ts +10 -0
  87. package/cli/watch/index.js +22 -0
  88. package/cli/watch/orchestrator.d.ts +63 -0
  89. package/cli/watch/orchestrator.js +228 -0
  90. package/cli/watch/poller.d.ts +65 -0
  91. package/cli/watch/poller.js +203 -0
  92. package/cli/watch/types.d.ts +67 -0
  93. package/cli/watch/types.js +5 -0
  94. package/client/error.d.ts +95 -0
  95. package/client/error.js +255 -0
  96. package/client/execute.d.ts +57 -0
  97. package/client/execute.js +124 -0
  98. package/client/index.d.ts +6 -0
  99. package/client/index.js +18 -0
  100. package/client/typed-document.d.ts +31 -0
  101. package/client/typed-document.js +44 -0
  102. package/core/ast.d.ts +10 -0
  103. package/core/ast.js +593 -0
  104. package/core/custom-ast.d.ts +35 -0
  105. package/core/custom-ast.js +204 -0
  106. package/core/index.d.ts +8 -0
  107. package/core/index.js +33 -0
  108. package/core/meta-object/convert.d.ts +65 -0
  109. package/core/meta-object/convert.js +63 -0
  110. package/core/meta-object/format.json +93 -0
  111. package/core/meta-object/index.d.ts +2 -0
  112. package/core/meta-object/index.js +18 -0
  113. package/core/meta-object/validate.d.ts +9 -0
  114. package/core/meta-object/validate.js +34 -0
  115. package/core/query-builder.d.ts +46 -0
  116. package/core/query-builder.js +412 -0
  117. package/core/types.d.ts +139 -0
  118. package/core/types.js +28 -0
  119. package/esm/__tests__/codegen/input-types-generator.test.d.ts +1 -0
  120. package/esm/__tests__/codegen/input-types-generator.test.js +633 -0
  121. package/esm/cli/codegen/barrel.d.ts +27 -0
  122. package/esm/cli/codegen/barrel.js +156 -0
  123. package/esm/cli/codegen/client.d.ts +4 -0
  124. package/esm/cli/codegen/client.js +167 -0
  125. package/esm/cli/codegen/custom-mutations.d.ts +38 -0
  126. package/esm/cli/codegen/custom-mutations.js +145 -0
  127. package/esm/cli/codegen/custom-queries.d.ts +38 -0
  128. package/esm/cli/codegen/custom-queries.js +354 -0
  129. package/esm/cli/codegen/filters.d.ts +27 -0
  130. package/esm/cli/codegen/filters.js +351 -0
  131. package/esm/cli/codegen/gql-ast.d.ts +41 -0
  132. package/esm/cli/codegen/gql-ast.js +288 -0
  133. package/esm/cli/codegen/index.d.ts +71 -0
  134. package/esm/cli/codegen/index.js +124 -0
  135. package/esm/cli/codegen/mutations.d.ts +30 -0
  136. package/esm/cli/codegen/mutations.js +404 -0
  137. package/esm/cli/codegen/orm/barrel.d.ts +18 -0
  138. package/esm/cli/codegen/orm/barrel.js +44 -0
  139. package/esm/cli/codegen/orm/client-generator.d.ts +45 -0
  140. package/esm/cli/codegen/orm/client-generator.js +640 -0
  141. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +30 -0
  142. package/esm/cli/codegen/orm/custom-ops-generator.js +346 -0
  143. package/esm/cli/codegen/orm/index.d.ts +38 -0
  144. package/esm/cli/codegen/orm/index.js +75 -0
  145. package/esm/cli/codegen/orm/input-types-generator.d.ts +21 -0
  146. package/esm/cli/codegen/orm/input-types-generator.js +700 -0
  147. package/esm/cli/codegen/orm/input-types-generator.test.d.ts +1 -0
  148. package/esm/cli/codegen/orm/input-types-generator.test.js +73 -0
  149. package/esm/cli/codegen/orm/model-generator.d.ts +32 -0
  150. package/esm/cli/codegen/orm/model-generator.js +260 -0
  151. package/esm/cli/codegen/orm/query-builder.d.ts +161 -0
  152. package/esm/cli/codegen/orm/query-builder.js +353 -0
  153. package/esm/cli/codegen/orm/select-types.d.ts +169 -0
  154. package/esm/cli/codegen/orm/select-types.js +15 -0
  155. package/esm/cli/codegen/orm/select-types.test.d.ts +11 -0
  156. package/esm/cli/codegen/orm/select-types.test.js +21 -0
  157. package/esm/cli/codegen/queries.d.ts +25 -0
  158. package/esm/cli/codegen/queries.js +433 -0
  159. package/esm/cli/codegen/scalars.d.ts +12 -0
  160. package/esm/cli/codegen/scalars.js +66 -0
  161. package/esm/cli/codegen/schema-gql-ast.d.ts +51 -0
  162. package/esm/cli/codegen/schema-gql-ast.js +343 -0
  163. package/esm/cli/codegen/ts-ast.d.ts +122 -0
  164. package/esm/cli/codegen/ts-ast.js +260 -0
  165. package/esm/cli/codegen/type-resolver.d.ts +96 -0
  166. package/esm/cli/codegen/type-resolver.js +224 -0
  167. package/esm/cli/codegen/types.d.ts +12 -0
  168. package/esm/cli/codegen/types.js +65 -0
  169. package/esm/cli/codegen/utils.d.ts +163 -0
  170. package/esm/cli/codegen/utils.js +288 -0
  171. package/esm/cli/commands/generate-orm.d.ts +37 -0
  172. package/esm/cli/commands/generate-orm.js +192 -0
  173. package/esm/cli/commands/generate.d.ts +39 -0
  174. package/esm/cli/commands/generate.js +262 -0
  175. package/esm/cli/commands/index.d.ts +7 -0
  176. package/esm/cli/commands/index.js +5 -0
  177. package/esm/cli/commands/init.d.ts +35 -0
  178. package/esm/cli/commands/init.js +138 -0
  179. package/esm/cli/index.d.ts +4 -0
  180. package/esm/cli/index.js +256 -0
  181. package/esm/cli/introspect/fetch-meta.d.ts +31 -0
  182. package/esm/cli/introspect/fetch-meta.js +104 -0
  183. package/esm/cli/introspect/fetch-schema.d.ts +21 -0
  184. package/esm/cli/introspect/fetch-schema.js +83 -0
  185. package/esm/cli/introspect/index.d.ts +8 -0
  186. package/esm/cli/introspect/index.js +6 -0
  187. package/esm/cli/introspect/meta-query.d.ts +111 -0
  188. package/esm/cli/introspect/meta-query.js +188 -0
  189. package/esm/cli/introspect/schema-query.d.ts +20 -0
  190. package/esm/cli/introspect/schema-query.js +120 -0
  191. package/esm/cli/introspect/transform-schema.d.ts +74 -0
  192. package/esm/cli/introspect/transform-schema.js +259 -0
  193. package/esm/cli/introspect/transform-schema.test.d.ts +1 -0
  194. package/esm/cli/introspect/transform-schema.test.js +65 -0
  195. package/esm/cli/introspect/transform.d.ts +21 -0
  196. package/esm/cli/introspect/transform.js +210 -0
  197. package/esm/cli/watch/cache.d.ts +45 -0
  198. package/esm/cli/watch/cache.js +73 -0
  199. package/esm/cli/watch/debounce.d.ts +19 -0
  200. package/esm/cli/watch/debounce.js +85 -0
  201. package/esm/cli/watch/hash.d.ts +17 -0
  202. package/esm/cli/watch/hash.js +43 -0
  203. package/esm/cli/watch/index.d.ts +10 -0
  204. package/esm/cli/watch/index.js +8 -0
  205. package/esm/cli/watch/orchestrator.d.ts +63 -0
  206. package/esm/cli/watch/orchestrator.js +223 -0
  207. package/esm/cli/watch/poller.d.ts +65 -0
  208. package/esm/cli/watch/poller.js +198 -0
  209. package/esm/cli/watch/types.d.ts +67 -0
  210. package/esm/cli/watch/types.js +4 -0
  211. package/esm/client/error.d.ts +95 -0
  212. package/esm/client/error.js +249 -0
  213. package/esm/client/execute.d.ts +57 -0
  214. package/esm/client/execute.js +120 -0
  215. package/esm/client/index.d.ts +6 -0
  216. package/esm/client/index.js +6 -0
  217. package/esm/client/typed-document.d.ts +31 -0
  218. package/esm/client/typed-document.js +40 -0
  219. package/esm/core/ast.d.ts +10 -0
  220. package/esm/core/ast.js +549 -0
  221. package/esm/core/custom-ast.d.ts +35 -0
  222. package/esm/core/custom-ast.js +161 -0
  223. package/esm/core/index.d.ts +8 -0
  224. package/esm/core/index.js +12 -0
  225. package/esm/core/meta-object/convert.d.ts +65 -0
  226. package/esm/core/meta-object/convert.js +60 -0
  227. package/esm/core/meta-object/format.json +93 -0
  228. package/esm/core/meta-object/index.d.ts +2 -0
  229. package/esm/core/meta-object/index.js +2 -0
  230. package/esm/core/meta-object/validate.d.ts +9 -0
  231. package/esm/core/meta-object/validate.js +28 -0
  232. package/esm/core/query-builder.d.ts +46 -0
  233. package/esm/core/query-builder.js +375 -0
  234. package/esm/core/types.d.ts +139 -0
  235. package/esm/core/types.js +24 -0
  236. package/esm/generators/field-selector.d.ts +30 -0
  237. package/esm/generators/field-selector.js +355 -0
  238. package/esm/generators/index.d.ts +6 -0
  239. package/esm/generators/index.js +9 -0
  240. package/esm/generators/mutations.d.ts +31 -0
  241. package/esm/generators/mutations.js +197 -0
  242. package/esm/generators/select.d.ts +50 -0
  243. package/esm/generators/select.js +636 -0
  244. package/esm/index.d.ts +12 -0
  245. package/esm/index.js +17 -3
  246. package/esm/react/index.d.ts +5 -0
  247. package/esm/react/index.js +6 -0
  248. package/esm/types/config.d.ts +199 -0
  249. package/esm/types/config.js +106 -0
  250. package/esm/types/index.d.ts +9 -0
  251. package/esm/types/index.js +4 -0
  252. package/esm/types/introspection.d.ts +121 -0
  253. package/esm/types/introspection.js +54 -0
  254. package/esm/types/mutation.d.ts +45 -0
  255. package/esm/types/mutation.js +4 -0
  256. package/esm/types/query.d.ts +82 -0
  257. package/esm/types/query.js +4 -0
  258. package/esm/types/schema.d.ts +253 -0
  259. package/esm/types/schema.js +5 -0
  260. package/esm/types/selection.d.ts +43 -0
  261. package/esm/types/selection.js +4 -0
  262. package/esm/utils/index.d.ts +4 -0
  263. package/esm/utils/index.js +4 -0
  264. package/generators/field-selector.d.ts +30 -0
  265. package/generators/field-selector.js +361 -0
  266. package/generators/index.d.ts +6 -0
  267. package/generators/index.js +27 -0
  268. package/generators/mutations.d.ts +31 -0
  269. package/generators/mutations.js +235 -0
  270. package/generators/select.d.ts +50 -0
  271. package/generators/select.js +679 -0
  272. package/index.d.ts +12 -3
  273. package/index.js +19 -3
  274. package/package.json +59 -38
  275. package/react/index.d.ts +5 -0
  276. package/react/index.js +9 -0
  277. package/types/config.d.ts +199 -0
  278. package/types/config.js +111 -0
  279. package/types/index.d.ts +9 -0
  280. package/types/index.js +10 -0
  281. package/types/introspection.d.ts +121 -0
  282. package/types/introspection.js +62 -0
  283. package/types/mutation.d.ts +45 -0
  284. package/types/mutation.js +5 -0
  285. package/types/query.d.ts +82 -0
  286. package/types/query.js +5 -0
  287. package/types/schema.d.ts +253 -0
  288. package/types/schema.js +6 -0
  289. package/types/selection.d.ts +43 -0
  290. package/types/selection.js +5 -0
  291. package/utils/index.d.ts +4 -0
  292. package/utils/index.js +7 -0
  293. package/codegen.d.ts +0 -13
  294. package/codegen.js +0 -293
  295. package/esm/codegen.js +0 -253
  296. package/esm/gql.js +0 -939
  297. package/esm/options.js +0 -27
  298. package/gql.d.ts +0 -188
  299. package/gql.js +0 -992
  300. package/options.d.ts +0 -45
  301. package/options.js +0 -31
@@ -0,0 +1,260 @@
1
+ /**
2
+ * TypeScript AST builders using ts-morph
3
+ *
4
+ * Provides utilities for generating TypeScript code via AST manipulation
5
+ * instead of string concatenation.
6
+ */
7
+ import { Project, StructureKind, VariableDeclarationKind, ScriptTarget, ModuleKind, } from 'ts-morph';
8
+ // ============================================================================
9
+ // Project management
10
+ // ============================================================================
11
+ /**
12
+ * Create a new ts-morph project for code generation
13
+ */
14
+ export function createProject() {
15
+ return new Project({
16
+ useInMemoryFileSystem: true,
17
+ compilerOptions: {
18
+ declaration: true,
19
+ strict: true,
20
+ target: ScriptTarget.ESNext,
21
+ module: ModuleKind.ESNext,
22
+ },
23
+ });
24
+ }
25
+ /**
26
+ * Create a source file in the project
27
+ */
28
+ export function createSourceFile(project, fileName) {
29
+ return project.createSourceFile(fileName, '', { overwrite: true });
30
+ }
31
+ /**
32
+ * Get formatted output from source file
33
+ */
34
+ export function getFormattedOutput(sourceFile) {
35
+ sourceFile.formatText({
36
+ indentSize: 2,
37
+ convertTabsToSpaces: true,
38
+ });
39
+ return sourceFile.getFullText();
40
+ }
41
+ /**
42
+ * Get output with minimal formatting (preserves intentional blank lines)
43
+ * Post-processes to fix indentation and section comment spacing
44
+ *
45
+ * ts-morph generates type alias bodies with extra indentation:
46
+ * - Properties get 6 spaces (we want 2)
47
+ * - Closing brace gets 4 spaces (we want 0)
48
+ *
49
+ * For interfaces it uses 4 spaces which we convert to 2.
50
+ */
51
+ export function getMinimalFormattedOutput(sourceFile) {
52
+ let text = sourceFile.getFullText();
53
+ // Process each line to fix indentation
54
+ // ts-morph uses inconsistent indentation for type alias bodies
55
+ // We halve all indentation: 4->2, 6->3 (rounds to 2), 8->4, etc.
56
+ text = text.split('\n').map(line => {
57
+ // Match leading whitespace
58
+ const match = line.match(/^(\s*)/);
59
+ if (!match)
60
+ return line;
61
+ const spaces = match[1].length;
62
+ const content = line.slice(spaces);
63
+ // Skip empty lines
64
+ if (content === '')
65
+ return line;
66
+ // No indentation - keep as-is
67
+ if (spaces === 0)
68
+ return line;
69
+ // Halve the indentation (minimum 0)
70
+ const newSpaces = Math.floor(spaces / 2);
71
+ return ' '.repeat(newSpaces) + content;
72
+ }).join('\n');
73
+ // Ensure blank line after section comment blocks
74
+ text = text.replace(/(\/\/ =+\n\/\/ .+\n\/\/ =+)\n(export|\/\/)/g, '$1\n\n$2');
75
+ // Add blank line between consecutive export declarations (type aliases, interfaces)
76
+ // Pattern: "}\nexport" or ";\nexport" should become "}\n\nexport" or ";\n\nexport"
77
+ text = text.replace(/(\}|\;)\n(export )/g, '$1\n\n$2');
78
+ // Remove trailing extra blank lines at end of file
79
+ text = text.replace(/\n\n+$/, '\n');
80
+ return text;
81
+ }
82
+ // ============================================================================
83
+ // Comment helpers
84
+ // ============================================================================
85
+ /**
86
+ * Create a file header comment
87
+ */
88
+ export function createFileHeader(description) {
89
+ return [
90
+ '/**',
91
+ ` * ${description}`,
92
+ ' * @generated by @constructive-io/graphql-codegen',
93
+ ' * DO NOT EDIT - changes will be overwritten',
94
+ ' */',
95
+ ].join('\n');
96
+ }
97
+ /**
98
+ * Create JSDoc comment for a declaration
99
+ */
100
+ export function createJsDoc(lines) {
101
+ if (lines.length === 1) {
102
+ return `/** ${lines[0]} */`;
103
+ }
104
+ return ['/**', ...lines.map((l) => ` * ${l}`), ' */'].join('\n');
105
+ }
106
+ /**
107
+ * Create import declaration structure
108
+ */
109
+ export function createImport(spec) {
110
+ const namedImports = [];
111
+ if (spec.namedImports) {
112
+ namedImports.push(...spec.namedImports.map((name) => ({ name })));
113
+ }
114
+ if (spec.typeOnlyNamedImports) {
115
+ namedImports.push(...spec.typeOnlyNamedImports.map((name) => ({ name, isTypeOnly: true })));
116
+ }
117
+ return {
118
+ kind: StructureKind.ImportDeclaration,
119
+ moduleSpecifier: spec.moduleSpecifier,
120
+ defaultImport: spec.defaultImport,
121
+ namedImports: namedImports.length > 0 ? namedImports : undefined,
122
+ };
123
+ }
124
+ /**
125
+ * Create interface declaration structure
126
+ */
127
+ export function createInterface(name, properties, options) {
128
+ return {
129
+ kind: StructureKind.Interface,
130
+ name,
131
+ isExported: options?.isExported ?? true,
132
+ extends: options?.extends,
133
+ docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
134
+ properties: properties.map((prop) => ({
135
+ kind: StructureKind.PropertySignature,
136
+ name: prop.name,
137
+ type: prop.type,
138
+ hasQuestionToken: prop.optional,
139
+ docs: prop.docs ? [{ description: prop.docs.join('\n') }] : undefined,
140
+ })),
141
+ };
142
+ }
143
+ /**
144
+ * Create filter interface with standard PostGraphile operators
145
+ */
146
+ export function createFilterInterface(name, fieldFilters) {
147
+ const properties = [
148
+ ...fieldFilters.map((f) => ({
149
+ name: f.fieldName,
150
+ type: f.filterType,
151
+ optional: true,
152
+ })),
153
+ { name: 'and', type: `${name}[]`, optional: true, docs: ['Logical AND'] },
154
+ { name: 'or', type: `${name}[]`, optional: true, docs: ['Logical OR'] },
155
+ { name: 'not', type: name, optional: true, docs: ['Logical NOT'] },
156
+ ];
157
+ return createInterface(name, properties);
158
+ }
159
+ // ============================================================================
160
+ // Type alias builders
161
+ // ============================================================================
162
+ /**
163
+ * Create type alias declaration structure
164
+ */
165
+ export function createTypeAlias(name, type, options) {
166
+ return {
167
+ kind: StructureKind.TypeAlias,
168
+ name,
169
+ type,
170
+ isExported: options?.isExported ?? true,
171
+ docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
172
+ };
173
+ }
174
+ /**
175
+ * Create union type from string literals
176
+ */
177
+ export function createUnionType(values) {
178
+ return values.map((v) => `'${v}'`).join(' | ');
179
+ }
180
+ // ============================================================================
181
+ // Variable/constant builders
182
+ // ============================================================================
183
+ /**
184
+ * Create const variable statement structure
185
+ */
186
+ export function createConst(name, initializer, options) {
187
+ return {
188
+ kind: StructureKind.VariableStatement,
189
+ declarationKind: VariableDeclarationKind.Const,
190
+ isExported: options?.isExported ?? true,
191
+ docs: options?.docs ? [{ description: options.docs.join('\n') }] : undefined,
192
+ declarations: [
193
+ {
194
+ name,
195
+ type: options?.type,
196
+ initializer,
197
+ },
198
+ ],
199
+ };
200
+ }
201
+ /**
202
+ * Create a template literal string (for GraphQL documents)
203
+ */
204
+ export function createTemplateLiteral(content) {
205
+ return '`\n' + content + '\n`';
206
+ }
207
+ /**
208
+ * Create function declaration structure
209
+ */
210
+ export function createFunction(name, parameters, returnType, body, options) {
211
+ return {
212
+ kind: StructureKind.Function,
213
+ name,
214
+ isExported: options?.isExported ?? true,
215
+ isAsync: options?.isAsync,
216
+ parameters: parameters.map((p) => ({
217
+ name: p.name,
218
+ type: p.type,
219
+ hasQuestionToken: p.optional,
220
+ initializer: p.initializer,
221
+ })),
222
+ returnType,
223
+ statements: body,
224
+ };
225
+ }
226
+ // ============================================================================
227
+ // Export builders
228
+ // ============================================================================
229
+ /**
230
+ * Create re-export statement
231
+ */
232
+ export function createReExport(names, moduleSpecifier, isTypeOnly = false) {
233
+ const typePrefix = isTypeOnly ? 'type ' : '';
234
+ return `export ${typePrefix}{ ${names.join(', ')} } from '${moduleSpecifier}';`;
235
+ }
236
+ /**
237
+ * Create barrel export statement
238
+ */
239
+ export function createBarrelExport(moduleSpecifier) {
240
+ return `export * from '${moduleSpecifier}';`;
241
+ }
242
+ // ============================================================================
243
+ // Section comment helpers
244
+ // ============================================================================
245
+ /**
246
+ * Create a section divider comment for generated code
247
+ */
248
+ export function createSectionComment(title) {
249
+ return [
250
+ '// ============================================================================',
251
+ `// ${title}`,
252
+ '// ============================================================================',
253
+ ].join('\n');
254
+ }
255
+ /**
256
+ * Add a section comment to source file with proper spacing
257
+ */
258
+ export function addSectionComment(sourceFile, title) {
259
+ sourceFile.addStatements(`\n${createSectionComment(title)}\n\n`);
260
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Type Resolver - Convert GraphQL types to TypeScript
3
+ *
4
+ * Utilities for converting CleanTypeRef and other GraphQL types
5
+ * into TypeScript type strings and interface definitions.
6
+ */
7
+ import type { CleanTypeRef, CleanArgument, CleanObjectField } from '../../types/schema';
8
+ import type { InterfaceProperty } from './ts-ast';
9
+ /**
10
+ * Convert a GraphQL scalar type to TypeScript type
11
+ */
12
+ export declare function scalarToTsType(scalarName: string): string;
13
+ /**
14
+ * Convert a CleanTypeRef to a TypeScript type string
15
+ * Handles nested LIST and NON_NULL wrappers
16
+ */
17
+ export declare function typeRefToTsType(typeRef: CleanTypeRef): string;
18
+ /**
19
+ * Convert a CleanTypeRef to a nullable TypeScript type string
20
+ * (for optional fields that can be null)
21
+ */
22
+ export declare function typeRefToNullableTsType(typeRef: CleanTypeRef): string;
23
+ /**
24
+ * Check if a type reference is required (wrapped in NON_NULL)
25
+ */
26
+ export declare function isTypeRequired(typeRef: CleanTypeRef): boolean;
27
+ /**
28
+ * Check if a type reference is a list
29
+ */
30
+ export declare function isTypeList(typeRef: CleanTypeRef): boolean;
31
+ /**
32
+ * Get the base type name from a type reference (unwrapping wrappers)
33
+ */
34
+ export declare function getTypeBaseName(typeRef: CleanTypeRef): string | null;
35
+ /**
36
+ * Get the base type kind (unwrapping LIST and NON_NULL)
37
+ */
38
+ export declare function getBaseTypeKind(typeRef: CleanTypeRef): CleanTypeRef['kind'];
39
+ /**
40
+ * Convert CleanArgument to InterfaceProperty for ts-morph
41
+ */
42
+ export declare function argumentToInterfaceProperty(arg: CleanArgument): InterfaceProperty;
43
+ /**
44
+ * Convert CleanObjectField to InterfaceProperty for ts-morph
45
+ */
46
+ export declare function fieldToInterfaceProperty(field: CleanObjectField): InterfaceProperty;
47
+ /**
48
+ * Convert an array of CleanArguments to InterfaceProperty array
49
+ */
50
+ export declare function argumentsToInterfaceProperties(args: CleanArgument[]): InterfaceProperty[];
51
+ /**
52
+ * Convert an array of CleanObjectFields to InterfaceProperty array
53
+ */
54
+ export declare function fieldsToInterfaceProperties(fields: CleanObjectField[]): InterfaceProperty[];
55
+ /**
56
+ * Check if a field should be skipped in selections
57
+ */
58
+ export declare function shouldSkipField(fieldName: string, skipQueryField: boolean): boolean;
59
+ /**
60
+ * Filter fields to only include selectable scalar and object fields
61
+ */
62
+ export declare function getSelectableFields(fields: CleanObjectField[] | undefined, skipQueryField: boolean, maxDepth?: number, currentDepth?: number): CleanObjectField[];
63
+ /**
64
+ * Convert operation name to PascalCase for type names
65
+ */
66
+ export declare function operationNameToPascal(name: string): string;
67
+ /**
68
+ * Generate variables type name for an operation
69
+ * e.g., "login" -> "LoginMutationVariables"
70
+ */
71
+ export declare function getOperationVariablesTypeName(operationName: string, kind: 'query' | 'mutation'): string;
72
+ /**
73
+ * Generate result type name for an operation
74
+ * e.g., "login" -> "LoginMutationResult"
75
+ */
76
+ export declare function getOperationResultTypeName(operationName: string, kind: 'query' | 'mutation'): string;
77
+ /**
78
+ * Generate hook name for an operation
79
+ * e.g., "login" -> "useLoginMutation", "currentUser" -> "useCurrentUserQuery"
80
+ */
81
+ export declare function getOperationHookName(operationName: string, kind: 'query' | 'mutation'): string;
82
+ /**
83
+ * Generate file name for an operation hook
84
+ * e.g., "login" -> "useLoginMutation.ts"
85
+ */
86
+ export declare function getOperationFileName(operationName: string, kind: 'query' | 'mutation'): string;
87
+ /**
88
+ * Generate query key factory name
89
+ * e.g., "currentUser" -> "currentUserQueryKey"
90
+ */
91
+ export declare function getQueryKeyName(operationName: string): string;
92
+ /**
93
+ * Generate GraphQL document constant name
94
+ * e.g., "login" -> "loginMutationDocument"
95
+ */
96
+ export declare function getDocumentConstName(operationName: string, kind: 'query' | 'mutation'): string;
@@ -0,0 +1,224 @@
1
+ import { scalarToTsType as resolveScalarToTs } from './scalars';
2
+ // ============================================================================
3
+ // GraphQL to TypeScript Type Mapping
4
+ // ============================================================================
5
+ /**
6
+ * Convert a GraphQL scalar type to TypeScript type
7
+ */
8
+ export function scalarToTsType(scalarName) {
9
+ return resolveScalarToTs(scalarName, { unknownScalar: 'unknown' });
10
+ }
11
+ // ============================================================================
12
+ // CleanTypeRef to TypeScript
13
+ // ============================================================================
14
+ /**
15
+ * Convert a CleanTypeRef to a TypeScript type string
16
+ * Handles nested LIST and NON_NULL wrappers
17
+ */
18
+ export function typeRefToTsType(typeRef) {
19
+ switch (typeRef.kind) {
20
+ case 'NON_NULL':
21
+ // Non-null wrapper - unwrap and return the inner type
22
+ if (typeRef.ofType) {
23
+ return typeRefToTsType(typeRef.ofType);
24
+ }
25
+ return 'unknown';
26
+ case 'LIST':
27
+ // List wrapper - wrap inner type in array
28
+ if (typeRef.ofType) {
29
+ const innerType = typeRefToTsType(typeRef.ofType);
30
+ return `${innerType}[]`;
31
+ }
32
+ return 'unknown[]';
33
+ case 'SCALAR':
34
+ // Scalar type - map to TS type
35
+ return scalarToTsType(typeRef.name ?? 'unknown');
36
+ case 'ENUM':
37
+ // Enum type - use the GraphQL enum name
38
+ return typeRef.name ?? 'string';
39
+ case 'OBJECT':
40
+ case 'INPUT_OBJECT':
41
+ // Object types - use the GraphQL type name
42
+ return typeRef.name ?? 'unknown';
43
+ default:
44
+ return 'unknown';
45
+ }
46
+ }
47
+ /**
48
+ * Convert a CleanTypeRef to a nullable TypeScript type string
49
+ * (for optional fields that can be null)
50
+ */
51
+ export function typeRefToNullableTsType(typeRef) {
52
+ const baseType = typeRefToTsType(typeRef);
53
+ // If the outer type is NON_NULL, it's required
54
+ if (typeRef.kind === 'NON_NULL') {
55
+ return baseType;
56
+ }
57
+ // Otherwise, it can be null
58
+ return `${baseType} | null`;
59
+ }
60
+ /**
61
+ * Check if a type reference is required (wrapped in NON_NULL)
62
+ */
63
+ export function isTypeRequired(typeRef) {
64
+ return typeRef.kind === 'NON_NULL';
65
+ }
66
+ /**
67
+ * Check if a type reference is a list
68
+ */
69
+ export function isTypeList(typeRef) {
70
+ if (typeRef.kind === 'LIST')
71
+ return true;
72
+ if (typeRef.kind === 'NON_NULL' && typeRef.ofType) {
73
+ return typeRef.ofType.kind === 'LIST';
74
+ }
75
+ return false;
76
+ }
77
+ /**
78
+ * Get the base type name from a type reference (unwrapping wrappers)
79
+ */
80
+ export function getTypeBaseName(typeRef) {
81
+ if (typeRef.name)
82
+ return typeRef.name;
83
+ if (typeRef.ofType)
84
+ return getTypeBaseName(typeRef.ofType);
85
+ return null;
86
+ }
87
+ /**
88
+ * Get the base type kind (unwrapping LIST and NON_NULL)
89
+ */
90
+ export function getBaseTypeKind(typeRef) {
91
+ if (typeRef.kind === 'LIST' || typeRef.kind === 'NON_NULL') {
92
+ if (typeRef.ofType) {
93
+ return getBaseTypeKind(typeRef.ofType);
94
+ }
95
+ }
96
+ return typeRef.kind;
97
+ }
98
+ // ============================================================================
99
+ // Interface Property Generation
100
+ // ============================================================================
101
+ /**
102
+ * Convert CleanArgument to InterfaceProperty for ts-morph
103
+ */
104
+ export function argumentToInterfaceProperty(arg) {
105
+ return {
106
+ name: arg.name,
107
+ type: typeRefToTsType(arg.type),
108
+ optional: !isTypeRequired(arg.type),
109
+ docs: arg.description ? [arg.description] : undefined,
110
+ };
111
+ }
112
+ /**
113
+ * Convert CleanObjectField to InterfaceProperty for ts-morph
114
+ */
115
+ export function fieldToInterfaceProperty(field) {
116
+ return {
117
+ name: field.name,
118
+ type: typeRefToNullableTsType(field.type),
119
+ optional: false, // Fields are always present, just potentially null
120
+ docs: field.description ? [field.description] : undefined,
121
+ };
122
+ }
123
+ /**
124
+ * Convert an array of CleanArguments to InterfaceProperty array
125
+ */
126
+ export function argumentsToInterfaceProperties(args) {
127
+ return args.map(argumentToInterfaceProperty);
128
+ }
129
+ /**
130
+ * Convert an array of CleanObjectFields to InterfaceProperty array
131
+ */
132
+ export function fieldsToInterfaceProperties(fields) {
133
+ return fields.map(fieldToInterfaceProperty);
134
+ }
135
+ // ============================================================================
136
+ // Type Filtering
137
+ // ============================================================================
138
+ /**
139
+ * Check if a field should be skipped in selections
140
+ */
141
+ export function shouldSkipField(fieldName, skipQueryField) {
142
+ if (skipQueryField && fieldName === 'query')
143
+ return true;
144
+ if (fieldName === 'nodeId')
145
+ return true;
146
+ if (fieldName === '__typename')
147
+ return true;
148
+ return false;
149
+ }
150
+ /**
151
+ * Filter fields to only include selectable scalar and object fields
152
+ */
153
+ export function getSelectableFields(fields, skipQueryField, maxDepth = 2, currentDepth = 0) {
154
+ if (!fields || currentDepth >= maxDepth)
155
+ return [];
156
+ return fields.filter((field) => {
157
+ // Skip internal fields
158
+ if (shouldSkipField(field.name, skipQueryField))
159
+ return false;
160
+ // Get base type kind
161
+ const baseKind = getBaseTypeKind(field.type);
162
+ // Include scalars and enums
163
+ if (baseKind === 'SCALAR' || baseKind === 'ENUM')
164
+ return true;
165
+ // Include objects up to max depth
166
+ if (baseKind === 'OBJECT' && currentDepth < maxDepth - 1)
167
+ return true;
168
+ return false;
169
+ });
170
+ }
171
+ // ============================================================================
172
+ // Type Name Utilities
173
+ // ============================================================================
174
+ /**
175
+ * Convert operation name to PascalCase for type names
176
+ */
177
+ export function operationNameToPascal(name) {
178
+ return name.charAt(0).toUpperCase() + name.slice(1);
179
+ }
180
+ /**
181
+ * Generate variables type name for an operation
182
+ * e.g., "login" -> "LoginMutationVariables"
183
+ */
184
+ export function getOperationVariablesTypeName(operationName, kind) {
185
+ const pascal = operationNameToPascal(operationName);
186
+ return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Variables`;
187
+ }
188
+ /**
189
+ * Generate result type name for an operation
190
+ * e.g., "login" -> "LoginMutationResult"
191
+ */
192
+ export function getOperationResultTypeName(operationName, kind) {
193
+ const pascal = operationNameToPascal(operationName);
194
+ return `${pascal}${kind === 'query' ? 'Query' : 'Mutation'}Result`;
195
+ }
196
+ /**
197
+ * Generate hook name for an operation
198
+ * e.g., "login" -> "useLoginMutation", "currentUser" -> "useCurrentUserQuery"
199
+ */
200
+ export function getOperationHookName(operationName, kind) {
201
+ const pascal = operationNameToPascal(operationName);
202
+ return `use${pascal}${kind === 'query' ? 'Query' : 'Mutation'}`;
203
+ }
204
+ /**
205
+ * Generate file name for an operation hook
206
+ * e.g., "login" -> "useLoginMutation.ts"
207
+ */
208
+ export function getOperationFileName(operationName, kind) {
209
+ return `${getOperationHookName(operationName, kind)}.ts`;
210
+ }
211
+ /**
212
+ * Generate query key factory name
213
+ * e.g., "currentUser" -> "currentUserQueryKey"
214
+ */
215
+ export function getQueryKeyName(operationName) {
216
+ return `${operationName}QueryKey`;
217
+ }
218
+ /**
219
+ * Generate GraphQL document constant name
220
+ * e.g., "login" -> "loginMutationDocument"
221
+ */
222
+ export function getDocumentConstName(operationName, kind) {
223
+ return `${operationName}${kind === 'query' ? 'Query' : 'Mutation'}Document`;
224
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Types generator - generates types.ts with entity interfaces using AST
3
+ */
4
+ import type { CleanTable } from '../../types/schema';
5
+ /**
6
+ * Generate types.ts content with all entity interfaces and base filter types
7
+ */
8
+ export declare function generateTypesFile(tables: CleanTable[]): string;
9
+ /**
10
+ * Generate a minimal entity type (just id and display fields)
11
+ */
12
+ export declare function generateMinimalEntityType(table: CleanTable): string;
@@ -0,0 +1,65 @@
1
+ import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createInterface, } from './ts-ast';
2
+ import { getScalarFields, fieldTypeToTs } from './utils';
3
+ import { generateBaseFilterTypes } from './filters';
4
+ /**
5
+ * Generate types.ts content with all entity interfaces and base filter types
6
+ */
7
+ export function generateTypesFile(tables) {
8
+ const project = createProject();
9
+ const sourceFile = createSourceFile(project, 'types.ts');
10
+ // Add file header
11
+ sourceFile.insertText(0, createFileHeader('Entity types and filter types') + '\n\n');
12
+ // Add section comment
13
+ sourceFile.addStatements('// ============================================================================');
14
+ sourceFile.addStatements('// Entity types');
15
+ sourceFile.addStatements('// ============================================================================\n');
16
+ // Generate entity interfaces
17
+ for (const table of tables) {
18
+ const scalarFields = getScalarFields(table);
19
+ const properties = scalarFields.map((field) => ({
20
+ name: field.name,
21
+ type: `${fieldTypeToTs(field.type)} | null`,
22
+ }));
23
+ sourceFile.addInterface(createInterface(table.name, properties));
24
+ }
25
+ // Add section comment for filters
26
+ sourceFile.addStatements('\n// ============================================================================');
27
+ sourceFile.addStatements('// Filter types (shared)');
28
+ sourceFile.addStatements('// ============================================================================\n');
29
+ // Add base filter types (using string concat for complex types - acceptable for static definitions)
30
+ const filterTypesContent = generateBaseFilterTypes();
31
+ // Extract just the interfaces part (skip the header)
32
+ const filterInterfaces = filterTypesContent
33
+ .split('\n')
34
+ .slice(6) // Skip header lines
35
+ .join('\n');
36
+ sourceFile.addStatements(filterInterfaces);
37
+ return getFormattedOutput(sourceFile);
38
+ }
39
+ /**
40
+ * Generate a minimal entity type (just id and display fields)
41
+ */
42
+ export function generateMinimalEntityType(table) {
43
+ const project = createProject();
44
+ const sourceFile = createSourceFile(project, 'minimal.ts');
45
+ const scalarFields = getScalarFields(table);
46
+ // Find id and likely display fields
47
+ const displayFields = scalarFields.filter((f) => {
48
+ const name = f.name.toLowerCase();
49
+ return (name === 'id' ||
50
+ name === 'name' ||
51
+ name === 'title' ||
52
+ name === 'label' ||
53
+ name === 'email' ||
54
+ name.endsWith('name') ||
55
+ name.endsWith('title'));
56
+ });
57
+ // If no display fields found, take first 5 scalar fields
58
+ const fieldsToUse = displayFields.length > 0 ? displayFields : scalarFields.slice(0, 5);
59
+ const properties = fieldsToUse.map((field) => ({
60
+ name: field.name,
61
+ type: `${fieldTypeToTs(field.type)} | null`,
62
+ }));
63
+ sourceFile.addInterface(createInterface(`${table.name}Minimal`, properties));
64
+ return getFormattedOutput(sourceFile);
65
+ }