@constructive-io/graphql-codegen 2.18.0 → 2.20.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 (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,343 @@
1
+ /**
2
+ * Dynamic GraphQL AST builders for custom operations
3
+ *
4
+ * Generates GraphQL query/mutation documents from CleanOperation data
5
+ * using gql-ast library for proper AST construction.
6
+ */
7
+ import * as t from 'gql-ast';
8
+ import { print } from 'graphql';
9
+ import { getBaseTypeKind, shouldSkipField } from './type-resolver';
10
+ // ============================================================================
11
+ // Type Node Builders (GraphQL Type AST)
12
+ // ============================================================================
13
+ /**
14
+ * Build a GraphQL type node from CleanTypeRef
15
+ * Handles NON_NULL, LIST, and named types
16
+ */
17
+ function buildTypeNode(typeRef) {
18
+ switch (typeRef.kind) {
19
+ case 'NON_NULL':
20
+ if (typeRef.ofType) {
21
+ const innerType = buildTypeNode(typeRef.ofType);
22
+ // Can't wrap NON_NULL in NON_NULL
23
+ if (innerType.kind === 'NonNullType') {
24
+ return innerType;
25
+ }
26
+ return t.nonNullType({ type: innerType });
27
+ }
28
+ return t.namedType({ type: 'String' });
29
+ case 'LIST':
30
+ if (typeRef.ofType) {
31
+ return t.listType({ type: buildTypeNode(typeRef.ofType) });
32
+ }
33
+ return t.listType({ type: t.namedType({ type: 'String' }) });
34
+ case 'SCALAR':
35
+ case 'ENUM':
36
+ case 'OBJECT':
37
+ case 'INPUT_OBJECT':
38
+ return t.namedType({ type: typeRef.name ?? 'String' });
39
+ default:
40
+ return t.namedType({ type: typeRef.name ?? 'String' });
41
+ }
42
+ }
43
+ // ============================================================================
44
+ // Variable Definition Builders
45
+ // ============================================================================
46
+ /**
47
+ * Build variable definitions from operation arguments
48
+ */
49
+ export function buildVariableDefinitions(args) {
50
+ return args.map((arg) => t.variableDefinition({
51
+ variable: t.variable({ name: arg.name }),
52
+ type: buildTypeNode(arg.type),
53
+ }));
54
+ }
55
+ /**
56
+ * Build argument nodes that reference variables
57
+ */
58
+ function buildArgumentNodes(args) {
59
+ return args.map((arg) => t.argument({
60
+ name: arg.name,
61
+ value: t.variable({ name: arg.name }),
62
+ }));
63
+ }
64
+ // ============================================================================
65
+ // Field Selection Builders
66
+ // ============================================================================
67
+ /**
68
+ * Check if a type should have selections (is an object type)
69
+ */
70
+ function typeNeedsSelections(typeRef) {
71
+ const baseKind = getBaseTypeKind(typeRef);
72
+ return baseKind === 'OBJECT';
73
+ }
74
+ /**
75
+ * Get the resolved fields for a type reference
76
+ * Uses type registry for deep resolution
77
+ */
78
+ function getResolvedFields(typeRef, typeRegistry) {
79
+ // First check if fields are directly on the typeRef
80
+ if (typeRef.fields) {
81
+ return typeRef.fields;
82
+ }
83
+ // For wrapper types, unwrap and check
84
+ if (typeRef.ofType) {
85
+ return getResolvedFields(typeRef.ofType, typeRegistry);
86
+ }
87
+ // Look up in type registry
88
+ if (typeRegistry && typeRef.name) {
89
+ const resolved = typeRegistry.get(typeRef.name);
90
+ if (resolved?.fields) {
91
+ return resolved.fields;
92
+ }
93
+ }
94
+ return undefined;
95
+ }
96
+ /**
97
+ * Build field selections for an object type
98
+ * Recursively handles nested objects up to maxDepth
99
+ */
100
+ export function buildFieldSelections(typeRef, config, currentDepth = 0) {
101
+ const { maxDepth, skipQueryField, typeRegistry } = config;
102
+ // Stop recursion at max depth
103
+ if (currentDepth >= maxDepth) {
104
+ return [];
105
+ }
106
+ const fields = getResolvedFields(typeRef, typeRegistry);
107
+ if (!fields || fields.length === 0) {
108
+ return [];
109
+ }
110
+ const selections = [];
111
+ for (const field of fields) {
112
+ // Skip internal fields
113
+ if (shouldSkipField(field.name, skipQueryField)) {
114
+ continue;
115
+ }
116
+ const fieldKind = getBaseTypeKind(field.type);
117
+ // For scalar and enum types, just add the field
118
+ if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') {
119
+ selections.push(t.field({ name: field.name }));
120
+ continue;
121
+ }
122
+ // For object types, recurse if within depth limit
123
+ if (fieldKind === 'OBJECT' && currentDepth < maxDepth - 1) {
124
+ const nestedSelections = buildFieldSelections(field.type, config, currentDepth + 1);
125
+ if (nestedSelections.length > 0) {
126
+ selections.push(t.field({
127
+ name: field.name,
128
+ selectionSet: t.selectionSet({ selections: nestedSelections }),
129
+ }));
130
+ }
131
+ }
132
+ }
133
+ return selections;
134
+ }
135
+ /**
136
+ * Build selections for a return type, handling connections and payloads
137
+ */
138
+ function buildReturnTypeSelections(returnType, config) {
139
+ const fields = getResolvedFields(returnType, config.typeRegistry);
140
+ if (!fields || fields.length === 0) {
141
+ return [];
142
+ }
143
+ // Check if this is a connection type
144
+ const hasNodes = fields.some((f) => f.name === 'nodes');
145
+ const hasTotalCount = fields.some((f) => f.name === 'totalCount');
146
+ if (hasNodes && hasTotalCount) {
147
+ return buildConnectionSelections(fields, config);
148
+ }
149
+ // Check if this is a mutation payload (has clientMutationId)
150
+ const hasClientMutationId = fields.some((f) => f.name === 'clientMutationId');
151
+ if (hasClientMutationId) {
152
+ return buildPayloadSelections(fields, config);
153
+ }
154
+ // Regular object - build normal selections
155
+ return buildFieldSelections(returnType, config);
156
+ }
157
+ /**
158
+ * Build selections for a connection type
159
+ */
160
+ function buildConnectionSelections(fields, config) {
161
+ const selections = [];
162
+ // Add totalCount
163
+ const totalCountField = fields.find((f) => f.name === 'totalCount');
164
+ if (totalCountField) {
165
+ selections.push(t.field({ name: 'totalCount' }));
166
+ }
167
+ // Add nodes with nested selections
168
+ const nodesField = fields.find((f) => f.name === 'nodes');
169
+ if (nodesField) {
170
+ const nodeSelections = buildFieldSelections(nodesField.type, config);
171
+ if (nodeSelections.length > 0) {
172
+ selections.push(t.field({
173
+ name: 'nodes',
174
+ selectionSet: t.selectionSet({ selections: nodeSelections }),
175
+ }));
176
+ }
177
+ }
178
+ // Add pageInfo
179
+ const pageInfoField = fields.find((f) => f.name === 'pageInfo');
180
+ if (pageInfoField) {
181
+ selections.push(t.field({
182
+ name: 'pageInfo',
183
+ selectionSet: t.selectionSet({
184
+ selections: [
185
+ t.field({ name: 'hasNextPage' }),
186
+ t.field({ name: 'hasPreviousPage' }),
187
+ t.field({ name: 'startCursor' }),
188
+ t.field({ name: 'endCursor' }),
189
+ ],
190
+ }),
191
+ }));
192
+ }
193
+ return selections;
194
+ }
195
+ /**
196
+ * Build selections for a mutation payload type
197
+ */
198
+ function buildPayloadSelections(fields, config) {
199
+ const selections = [];
200
+ for (const field of fields) {
201
+ // Skip query field
202
+ if (shouldSkipField(field.name, config.skipQueryField)) {
203
+ continue;
204
+ }
205
+ const fieldKind = getBaseTypeKind(field.type);
206
+ // Add scalar fields directly
207
+ if (fieldKind === 'SCALAR' || fieldKind === 'ENUM') {
208
+ selections.push(t.field({ name: field.name }));
209
+ continue;
210
+ }
211
+ // For object fields (like the returned entity), add with selections
212
+ if (fieldKind === 'OBJECT') {
213
+ const nestedSelections = buildFieldSelections(field.type, config);
214
+ if (nestedSelections.length > 0) {
215
+ selections.push(t.field({
216
+ name: field.name,
217
+ selectionSet: t.selectionSet({ selections: nestedSelections }),
218
+ }));
219
+ }
220
+ }
221
+ }
222
+ return selections;
223
+ }
224
+ /**
225
+ * Build a custom query AST from a CleanOperation
226
+ */
227
+ export function buildCustomQueryAST(config) {
228
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, } = config;
229
+ const operationName = `${ucFirst(operation.name)}Query`;
230
+ // Build variable definitions
231
+ const variableDefinitions = buildVariableDefinitions(operation.args);
232
+ // Build arguments that reference the variables
233
+ const args = buildArgumentNodes(operation.args);
234
+ // Build return type selections
235
+ const fieldSelectionConfig = {
236
+ maxDepth,
237
+ skipQueryField,
238
+ typeRegistry,
239
+ };
240
+ const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType);
241
+ let selections = [];
242
+ if (returnTypeNeedsSelections) {
243
+ selections = buildReturnTypeSelections(operation.returnType, fieldSelectionConfig);
244
+ }
245
+ // Build the query field
246
+ const queryField = selections.length > 0
247
+ ? t.field({
248
+ name: operation.name,
249
+ args: args.length > 0 ? args : undefined,
250
+ selectionSet: t.selectionSet({ selections }),
251
+ })
252
+ : t.field({
253
+ name: operation.name,
254
+ args: args.length > 0 ? args : undefined,
255
+ });
256
+ return t.document({
257
+ definitions: [
258
+ t.operationDefinition({
259
+ operation: 'query',
260
+ name: operationName,
261
+ variableDefinitions: variableDefinitions.length > 0 ? variableDefinitions : undefined,
262
+ selectionSet: t.selectionSet({
263
+ selections: [queryField],
264
+ }),
265
+ }),
266
+ ],
267
+ });
268
+ }
269
+ /**
270
+ * Build a custom mutation AST from a CleanOperation
271
+ */
272
+ export function buildCustomMutationAST(config) {
273
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, } = config;
274
+ const operationName = `${ucFirst(operation.name)}Mutation`;
275
+ // Build variable definitions
276
+ const variableDefinitions = buildVariableDefinitions(operation.args);
277
+ // Build arguments that reference the variables
278
+ const args = buildArgumentNodes(operation.args);
279
+ // Build return type selections
280
+ const fieldSelectionConfig = {
281
+ maxDepth,
282
+ skipQueryField,
283
+ typeRegistry,
284
+ };
285
+ const returnTypeNeedsSelections = typeNeedsSelections(operation.returnType);
286
+ let selections = [];
287
+ if (returnTypeNeedsSelections) {
288
+ selections = buildReturnTypeSelections(operation.returnType, fieldSelectionConfig);
289
+ }
290
+ // Build the mutation field
291
+ const mutationField = selections.length > 0
292
+ ? t.field({
293
+ name: operation.name,
294
+ args: args.length > 0 ? args : undefined,
295
+ selectionSet: t.selectionSet({ selections }),
296
+ })
297
+ : t.field({
298
+ name: operation.name,
299
+ args: args.length > 0 ? args : undefined,
300
+ });
301
+ return t.document({
302
+ definitions: [
303
+ t.operationDefinition({
304
+ operation: 'mutation',
305
+ name: operationName,
306
+ variableDefinitions: variableDefinitions.length > 0 ? variableDefinitions : undefined,
307
+ selectionSet: t.selectionSet({
308
+ selections: [mutationField],
309
+ }),
310
+ }),
311
+ ],
312
+ });
313
+ }
314
+ // ============================================================================
315
+ // Print Utilities
316
+ // ============================================================================
317
+ /**
318
+ * Print a document AST to GraphQL string
319
+ */
320
+ export function printGraphQL(ast) {
321
+ return print(ast);
322
+ }
323
+ /**
324
+ * Build and print a custom query in one call
325
+ */
326
+ export function buildCustomQueryString(config) {
327
+ return printGraphQL(buildCustomQueryAST(config));
328
+ }
329
+ /**
330
+ * Build and print a custom mutation in one call
331
+ */
332
+ export function buildCustomMutationString(config) {
333
+ return printGraphQL(buildCustomMutationAST(config));
334
+ }
335
+ // ============================================================================
336
+ // Helper Utilities
337
+ // ============================================================================
338
+ /**
339
+ * Uppercase first character
340
+ */
341
+ function ucFirst(str) {
342
+ return str.charAt(0).toUpperCase() + str.slice(1);
343
+ }
@@ -0,0 +1,122 @@
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, SourceFile, type InterfaceDeclarationStructure, type FunctionDeclarationStructure, type VariableStatementStructure, type ImportDeclarationStructure, type TypeAliasDeclarationStructure } from 'ts-morph';
8
+ /**
9
+ * Create a new ts-morph project for code generation
10
+ */
11
+ export declare function createProject(): Project;
12
+ /**
13
+ * Create a source file in the project
14
+ */
15
+ export declare function createSourceFile(project: Project, fileName: string): SourceFile;
16
+ /**
17
+ * Get formatted output from source file
18
+ */
19
+ export declare function getFormattedOutput(sourceFile: SourceFile): string;
20
+ /**
21
+ * Get output with minimal formatting (preserves intentional blank lines)
22
+ * Post-processes to fix indentation and section comment spacing
23
+ *
24
+ * ts-morph generates type alias bodies with extra indentation:
25
+ * - Properties get 6 spaces (we want 2)
26
+ * - Closing brace gets 4 spaces (we want 0)
27
+ *
28
+ * For interfaces it uses 4 spaces which we convert to 2.
29
+ */
30
+ export declare function getMinimalFormattedOutput(sourceFile: SourceFile): string;
31
+ /**
32
+ * Create a file header comment
33
+ */
34
+ export declare function createFileHeader(description: string): string;
35
+ /**
36
+ * Create JSDoc comment for a declaration
37
+ */
38
+ export declare function createJsDoc(lines: string[]): string;
39
+ export interface ImportSpec {
40
+ moduleSpecifier: string;
41
+ namedImports?: string[];
42
+ typeOnlyNamedImports?: string[];
43
+ defaultImport?: string;
44
+ }
45
+ /**
46
+ * Create import declaration structure
47
+ */
48
+ export declare function createImport(spec: ImportSpec): ImportDeclarationStructure;
49
+ export interface InterfaceProperty {
50
+ name: string;
51
+ type: string;
52
+ optional?: boolean;
53
+ docs?: string[];
54
+ }
55
+ /**
56
+ * Create interface declaration structure
57
+ */
58
+ export declare function createInterface(name: string, properties: InterfaceProperty[], options?: {
59
+ docs?: string[];
60
+ isExported?: boolean;
61
+ extends?: string[];
62
+ }): InterfaceDeclarationStructure;
63
+ /**
64
+ * Create filter interface with standard PostGraphile operators
65
+ */
66
+ export declare function createFilterInterface(name: string, fieldFilters: Array<{
67
+ fieldName: string;
68
+ filterType: string;
69
+ }>): InterfaceDeclarationStructure;
70
+ /**
71
+ * Create type alias declaration structure
72
+ */
73
+ export declare function createTypeAlias(name: string, type: string, options?: {
74
+ docs?: string[];
75
+ isExported?: boolean;
76
+ }): TypeAliasDeclarationStructure;
77
+ /**
78
+ * Create union type from string literals
79
+ */
80
+ export declare function createUnionType(values: string[]): string;
81
+ /**
82
+ * Create const variable statement structure
83
+ */
84
+ export declare function createConst(name: string, initializer: string, options?: {
85
+ docs?: string[];
86
+ isExported?: boolean;
87
+ type?: string;
88
+ }): VariableStatementStructure;
89
+ /**
90
+ * Create a template literal string (for GraphQL documents)
91
+ */
92
+ export declare function createTemplateLiteral(content: string): string;
93
+ export interface FunctionParameter {
94
+ name: string;
95
+ type: string;
96
+ optional?: boolean;
97
+ initializer?: string;
98
+ }
99
+ /**
100
+ * Create function declaration structure
101
+ */
102
+ export declare function createFunction(name: string, parameters: FunctionParameter[], returnType: string, body: string, options?: {
103
+ docs?: string[];
104
+ isExported?: boolean;
105
+ isAsync?: boolean;
106
+ }): FunctionDeclarationStructure;
107
+ /**
108
+ * Create re-export statement
109
+ */
110
+ export declare function createReExport(names: string[], moduleSpecifier: string, isTypeOnly?: boolean): string;
111
+ /**
112
+ * Create barrel export statement
113
+ */
114
+ export declare function createBarrelExport(moduleSpecifier: string): string;
115
+ /**
116
+ * Create a section divider comment for generated code
117
+ */
118
+ export declare function createSectionComment(title: string): string;
119
+ /**
120
+ * Add a section comment to source file with proper spacing
121
+ */
122
+ export declare function addSectionComment(sourceFile: SourceFile, title: string): void;