@constructive-io/graphql-codegen 3.2.1 → 3.3.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 (215) hide show
  1. package/cli/index.js +36 -43
  2. package/cli/shared.d.ts +15 -19
  3. package/cli/shared.js +104 -25
  4. package/client/error.js +31 -9
  5. package/client/execute.js +2 -2
  6. package/client/index.d.ts +3 -3
  7. package/client/index.js +6 -6
  8. package/core/ast.d.ts +1 -1
  9. package/core/ast.js +1 -1
  10. package/core/codegen/babel-ast.d.ts +1 -1
  11. package/core/codegen/babel-ast.js +2 -2
  12. package/core/codegen/barrel.d.ts +0 -6
  13. package/core/codegen/barrel.js +22 -19
  14. package/core/codegen/client.d.ts +2 -12
  15. package/core/codegen/client.js +7 -21
  16. package/core/codegen/custom-mutations.d.ts +0 -14
  17. package/core/codegen/custom-mutations.js +139 -88
  18. package/core/codegen/custom-queries.d.ts +0 -14
  19. package/core/codegen/custom-queries.js +483 -193
  20. package/core/codegen/hooks-ast.d.ts +75 -0
  21. package/core/codegen/hooks-ast.js +522 -0
  22. package/core/codegen/index.d.ts +16 -18
  23. package/core/codegen/index.js +42 -88
  24. package/core/codegen/invalidation.d.ts +1 -7
  25. package/core/codegen/invalidation.js +50 -16
  26. package/core/codegen/mutation-keys.d.ts +1 -10
  27. package/core/codegen/mutation-keys.js +22 -8
  28. package/core/codegen/mutations.d.ts +0 -13
  29. package/core/codegen/mutations.js +301 -366
  30. package/core/codegen/orm/barrel.d.ts +0 -5
  31. package/core/codegen/orm/barrel.js +5 -0
  32. package/core/codegen/orm/client-generator.d.ts +0 -5
  33. package/core/codegen/orm/client-generator.js +7 -2
  34. package/core/codegen/orm/client.js +3 -1
  35. package/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  36. package/core/codegen/orm/custom-ops-generator.js +104 -51
  37. package/core/codegen/orm/index.d.ts +4 -4
  38. package/core/codegen/orm/index.js +28 -15
  39. package/core/codegen/orm/input-types-generator.d.ts +1 -13
  40. package/core/codegen/orm/input-types-generator.js +85 -23
  41. package/core/codegen/orm/model-generator.d.ts +0 -5
  42. package/core/codegen/orm/model-generator.js +309 -131
  43. package/core/codegen/orm/select-types.d.ts +19 -14
  44. package/core/codegen/queries.d.ts +0 -8
  45. package/core/codegen/queries.js +360 -559
  46. package/core/codegen/query-keys.d.ts +1 -1
  47. package/core/codegen/query-keys.js +37 -23
  48. package/core/codegen/scalars.js +3 -1
  49. package/core/codegen/schema-types-generator.d.ts +1 -1
  50. package/core/codegen/schema-types-generator.js +17 -2
  51. package/core/codegen/select-helpers.d.ts +19 -0
  52. package/core/codegen/select-helpers.js +40 -0
  53. package/core/codegen/selection.d.ts +4 -0
  54. package/core/codegen/selection.js +65 -0
  55. package/core/codegen/shared/index.d.ts +2 -15
  56. package/core/codegen/shared/index.js +17 -4
  57. package/core/codegen/templates/hooks-client.ts +49 -0
  58. package/core/codegen/templates/hooks-selection.ts +58 -0
  59. package/core/codegen/templates/orm-client.ts +8 -6
  60. package/core/codegen/templates/query-builder.ts +250 -46
  61. package/core/codegen/templates/select-types.ts +31 -14
  62. package/core/codegen/type-resolver.d.ts +1 -5
  63. package/core/codegen/type-resolver.js +0 -22
  64. package/core/codegen/types.d.ts +0 -3
  65. package/core/codegen/types.js +71 -14
  66. package/core/codegen/utils.d.ts +1 -4
  67. package/core/codegen/utils.js +4 -1
  68. package/core/config/index.d.ts +1 -1
  69. package/core/config/resolver.js +1 -3
  70. package/core/generate.js +38 -50
  71. package/core/index.d.ts +3 -3
  72. package/core/index.js +3 -4
  73. package/core/introspect/index.d.ts +6 -6
  74. package/core/introspect/index.js +5 -8
  75. package/core/introspect/infer-tables.d.ts +0 -14
  76. package/core/introspect/infer-tables.js +15 -1
  77. package/core/introspect/source/database.js +1 -1
  78. package/core/introspect/source/endpoint.d.ts +0 -6
  79. package/core/introspect/source/endpoint.js +7 -1
  80. package/core/introspect/source/index.d.ts +4 -4
  81. package/core/introspect/source/index.js +5 -9
  82. package/core/introspect/source/pgpm-module.js +3 -3
  83. package/core/introspect/transform-schema.d.ts +2 -2
  84. package/core/introspect/transform-schema.js +2 -2
  85. package/core/output/index.d.ts +1 -1
  86. package/core/output/index.js +2 -2
  87. package/core/output/writer.d.ts +3 -0
  88. package/core/output/writer.js +20 -1
  89. package/core/pipeline/index.d.ts +2 -2
  90. package/core/query-builder.d.ts +2 -2
  91. package/core/query-builder.js +1 -1
  92. package/core/watch/index.d.ts +4 -4
  93. package/core/watch/index.js +9 -9
  94. package/core/watch/orchestrator.js +5 -3
  95. package/esm/cli/index.js +37 -44
  96. package/esm/cli/shared.d.ts +15 -19
  97. package/esm/cli/shared.js +94 -23
  98. package/esm/client/error.js +31 -9
  99. package/esm/client/execute.js +2 -2
  100. package/esm/client/index.d.ts +3 -3
  101. package/esm/client/index.js +3 -3
  102. package/esm/core/ast.d.ts +1 -1
  103. package/esm/core/ast.js +1 -1
  104. package/esm/core/codegen/babel-ast.d.ts +1 -1
  105. package/esm/core/codegen/babel-ast.js +2 -2
  106. package/esm/core/codegen/barrel.d.ts +0 -6
  107. package/esm/core/codegen/barrel.js +23 -20
  108. package/esm/core/codegen/client.d.ts +2 -12
  109. package/esm/core/codegen/client.js +7 -21
  110. package/esm/core/codegen/custom-mutations.d.ts +0 -14
  111. package/esm/core/codegen/custom-mutations.js +141 -90
  112. package/esm/core/codegen/custom-queries.d.ts +0 -14
  113. package/esm/core/codegen/custom-queries.js +486 -196
  114. package/esm/core/codegen/hooks-ast.d.ts +75 -0
  115. package/esm/core/codegen/hooks-ast.js +424 -0
  116. package/esm/core/codegen/index.d.ts +16 -18
  117. package/esm/core/codegen/index.js +26 -71
  118. package/esm/core/codegen/invalidation.d.ts +1 -7
  119. package/esm/core/codegen/invalidation.js +51 -17
  120. package/esm/core/codegen/mutation-keys.d.ts +1 -10
  121. package/esm/core/codegen/mutation-keys.js +23 -9
  122. package/esm/core/codegen/mutations.d.ts +0 -13
  123. package/esm/core/codegen/mutations.js +302 -367
  124. package/esm/core/codegen/orm/barrel.d.ts +0 -5
  125. package/esm/core/codegen/orm/barrel.js +6 -1
  126. package/esm/core/codegen/orm/client-generator.d.ts +0 -5
  127. package/esm/core/codegen/orm/client-generator.js +7 -2
  128. package/esm/core/codegen/orm/client.js +3 -1
  129. package/esm/core/codegen/orm/custom-ops-generator.d.ts +0 -6
  130. package/esm/core/codegen/orm/custom-ops-generator.js +103 -50
  131. package/esm/core/codegen/orm/index.d.ts +4 -4
  132. package/esm/core/codegen/orm/index.js +25 -12
  133. package/esm/core/codegen/orm/input-types-generator.d.ts +1 -13
  134. package/esm/core/codegen/orm/input-types-generator.js +85 -23
  135. package/esm/core/codegen/orm/model-generator.d.ts +0 -5
  136. package/esm/core/codegen/orm/model-generator.js +310 -132
  137. package/esm/core/codegen/orm/select-types.d.ts +19 -14
  138. package/esm/core/codegen/queries.d.ts +0 -8
  139. package/esm/core/codegen/queries.js +362 -561
  140. package/esm/core/codegen/query-keys.d.ts +1 -1
  141. package/esm/core/codegen/query-keys.js +38 -24
  142. package/esm/core/codegen/scalars.js +3 -1
  143. package/esm/core/codegen/schema-types-generator.d.ts +1 -1
  144. package/esm/core/codegen/schema-types-generator.js +17 -2
  145. package/esm/core/codegen/select-helpers.d.ts +19 -0
  146. package/esm/core/codegen/select-helpers.js +35 -0
  147. package/esm/core/codegen/selection.d.ts +4 -0
  148. package/esm/core/codegen/selection.js +29 -0
  149. package/esm/core/codegen/shared/index.d.ts +2 -15
  150. package/esm/core/codegen/shared/index.js +16 -3
  151. package/esm/core/codegen/type-resolver.d.ts +1 -5
  152. package/esm/core/codegen/type-resolver.js +1 -22
  153. package/esm/core/codegen/types.d.ts +0 -3
  154. package/esm/core/codegen/types.js +72 -15
  155. package/esm/core/codegen/utils.d.ts +1 -4
  156. package/esm/core/codegen/utils.js +4 -1
  157. package/esm/core/config/index.d.ts +1 -1
  158. package/esm/core/config/resolver.js +2 -4
  159. package/esm/core/generate.js +38 -50
  160. package/esm/core/index.d.ts +3 -3
  161. package/esm/core/index.js +2 -3
  162. package/esm/core/introspect/index.d.ts +6 -6
  163. package/esm/core/introspect/index.js +3 -6
  164. package/esm/core/introspect/infer-tables.d.ts +0 -14
  165. package/esm/core/introspect/infer-tables.js +16 -2
  166. package/esm/core/introspect/source/database.js +2 -2
  167. package/esm/core/introspect/source/endpoint.d.ts +0 -6
  168. package/esm/core/introspect/source/endpoint.js +7 -1
  169. package/esm/core/introspect/source/index.d.ts +4 -4
  170. package/esm/core/introspect/source/index.js +6 -10
  171. package/esm/core/introspect/source/pgpm-module.js +3 -3
  172. package/esm/core/introspect/transform-schema.d.ts +2 -2
  173. package/esm/core/introspect/transform-schema.js +2 -2
  174. package/esm/core/output/index.d.ts +1 -1
  175. package/esm/core/output/index.js +1 -1
  176. package/esm/core/output/writer.d.ts +3 -0
  177. package/esm/core/output/writer.js +20 -1
  178. package/esm/core/pipeline/index.d.ts +2 -2
  179. package/esm/core/pipeline/index.js +2 -2
  180. package/esm/core/query-builder.d.ts +2 -2
  181. package/esm/core/query-builder.js +2 -2
  182. package/esm/core/watch/index.d.ts +4 -4
  183. package/esm/core/watch/index.js +3 -3
  184. package/esm/core/watch/orchestrator.js +5 -3
  185. package/esm/generators/index.d.ts +3 -3
  186. package/esm/generators/index.js +3 -3
  187. package/esm/generators/mutations.d.ts +1 -1
  188. package/esm/generators/select.d.ts +1 -1
  189. package/esm/index.d.ts +3 -3
  190. package/esm/index.js +1 -4
  191. package/esm/types/config.d.ts +0 -10
  192. package/esm/types/config.js +0 -2
  193. package/esm/types/index.d.ts +6 -6
  194. package/esm/types/index.js +1 -1
  195. package/generators/index.d.ts +3 -3
  196. package/generators/index.js +8 -8
  197. package/generators/mutations.d.ts +1 -1
  198. package/generators/select.d.ts +1 -1
  199. package/index.d.ts +3 -3
  200. package/index.js +11 -6
  201. package/package.json +10 -10
  202. package/types/config.d.ts +0 -10
  203. package/types/config.js +0 -2
  204. package/types/index.d.ts +6 -6
  205. package/types/index.js +2 -2
  206. package/core/codegen/gql-ast.d.ts +0 -41
  207. package/core/codegen/gql-ast.js +0 -353
  208. package/core/codegen/schema-gql-ast.d.ts +0 -51
  209. package/core/codegen/schema-gql-ast.js +0 -385
  210. package/core/codegen/templates/client.browser.ts +0 -271
  211. package/core/codegen/templates/client.node.ts +0 -337
  212. package/esm/core/codegen/gql-ast.d.ts +0 -41
  213. package/esm/core/codegen/gql-ast.js +0 -312
  214. package/esm/core/codegen/schema-gql-ast.d.ts +0 -51
  215. package/esm/core/codegen/schema-gql-ast.js +0 -343
@@ -1,240 +1,531 @@
1
+ /**
2
+ * Custom query hook generators for non-table operations (Babel AST-based)
3
+ *
4
+ * Generates hooks for operations discovered via schema introspection
5
+ * that are NOT table CRUD operations (e.g., currentUser, nodeById, etc.)
6
+ *
7
+ * Delegates to ORM custom query operations:
8
+ * getClient().query.operationName(args, { select }).unwrap()
9
+ *
10
+ * Output structure:
11
+ * queries/
12
+ * useCurrentUserQuery.ts
13
+ * useNodeQuery.ts
14
+ * ...
15
+ */
1
16
  import * as t from '@babel/types';
2
- import { generateCode, addJSDocComment, typedParam, createTypedCallExpression } from './babel-ast';
3
- import { buildCustomQueryString } from './schema-gql-ast';
4
- import { typeRefToTsType, isTypeRequired, getOperationHookName, getOperationFileName, getOperationVariablesTypeName, getOperationResultTypeName, getDocumentConstName, getQueryKeyName, createTypeTracker, } from './type-resolver';
5
- import { ucFirst, getGeneratedFileHeader } from './utils';
6
- function generateVariablesProperties(args, tracker) {
7
- return args.map((arg) => ({
8
- name: arg.name,
9
- type: typeRefToTsType(arg.type, tracker),
10
- optional: !isTypeRequired(arg.type),
11
- docs: arg.description ? [arg.description] : undefined,
12
- }));
13
- }
17
+ import { asConst } from './babel-ast';
18
+ import { addJSDocComment, buildSelectionArgsCall, callExpr, constDecl, createFunctionParam, createImportDeclaration, createSAndTDataTypeParams, createSTypeParam, createTDataTypeParam, createTypeReExport, customSelectResultTypeLiteral, destructureParamsWithSelection, exportAsyncDeclareFunction, exportAsyncFunction, exportDeclareFunction, exportFunction, generateHookFileCode, getClientCustomCallUnwrap, objectProp, omitType, returnUseQuery, selectionConfigType, spreadObj, sRef, typeRef, useQueryOptionsImplType, voidStatement, } from './hooks-ast';
19
+ import { getSelectTypeName } from './select-helpers';
20
+ import { createTypeTracker, getOperationFileName, getOperationHookName, getQueryKeyName, getTypeBaseName, isTypeRequired, typeRefToTsType, } from './type-resolver';
21
+ import { ucFirst } from './utils';
14
22
  export function generateCustomQueryHook(options) {
15
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
23
+ const { operation, typeRegistry, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
16
24
  const hookName = getOperationHookName(operation.name, 'query');
17
25
  const fileName = getOperationFileName(operation.name, 'query');
18
- const variablesTypeName = getOperationVariablesTypeName(operation.name, 'query');
19
- const resultTypeName = getOperationResultTypeName(operation.name, 'query');
20
- const documentConstName = getDocumentConstName(operation.name, 'query');
21
26
  const queryKeyName = getQueryKeyName(operation.name);
27
+ const varTypeName = `${ucFirst(operation.name)}Variables`;
22
28
  const tracker = createTypeTracker({ tableTypeNames });
23
- const queryDocument = buildCustomQueryString({
24
- operation,
25
- typeRegistry,
26
- maxDepth,
27
- skipQueryField,
28
- });
29
- const statements = [];
30
- const variablesProps = operation.args.length > 0
31
- ? generateVariablesProperties(operation.args, tracker)
32
- : [];
29
+ const hasArgs = operation.args.length > 0;
30
+ const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type));
33
31
  const resultType = typeRefToTsType(operation.returnType, tracker);
34
- const schemaTypes = tracker.getImportableTypes();
35
- const tableTypes = tracker.getTableTypes();
32
+ for (const arg of operation.args) {
33
+ typeRefToTsType(arg.type, tracker);
34
+ }
35
+ const selectTypeName = getSelectTypeName(operation.returnType);
36
+ const payloadTypeName = getTypeBaseName(operation.returnType);
37
+ const hasSelect = !!selectTypeName && !!payloadTypeName;
38
+ const statements = [];
39
+ // Imports
36
40
  if (reactQueryEnabled) {
37
- const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
38
- statements.push(reactQueryImport);
39
- const reactQueryTypeImport = t.importDeclaration([
40
- t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
41
- t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
42
- ], t.stringLiteral('@tanstack/react-query'));
43
- reactQueryTypeImport.importKind = 'type';
44
- statements.push(reactQueryTypeImport);
41
+ statements.push(createImportDeclaration('@tanstack/react-query', ['useQuery']));
42
+ statements.push(createImportDeclaration('@tanstack/react-query', ['UseQueryOptions', 'UseQueryResult', 'QueryClient'], true));
45
43
  }
46
- const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
47
- statements.push(clientImport);
48
- const clientTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions'))], t.stringLiteral('../client'));
49
- clientTypeImport.importKind = 'type';
50
- statements.push(clientTypeImport);
51
- if (tableTypes.length > 0) {
52
- const typesImport = t.importDeclaration(tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), t.stringLiteral('../types'));
53
- typesImport.importKind = 'type';
54
- statements.push(typesImport);
44
+ statements.push(createImportDeclaration('../client', ['getClient']));
45
+ statements.push(createImportDeclaration('../selection', ['buildSelectionArgs']));
46
+ statements.push(createImportDeclaration('../selection', ['SelectionConfig'], true));
47
+ if (useCentralizedKeys) {
48
+ statements.push(createImportDeclaration('../query-keys', ['customQueryKeys']));
55
49
  }
56
- if (schemaTypes.length > 0) {
57
- const schemaTypesImport = t.importDeclaration(schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), t.stringLiteral('../schema-types'));
58
- schemaTypesImport.importKind = 'type';
59
- statements.push(schemaTypesImport);
50
+ if (hasArgs) {
51
+ statements.push(createImportDeclaration('../../orm/query', [varTypeName], true));
60
52
  }
61
- if (useCentralizedKeys) {
62
- const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier('customQueryKeys'), t.identifier('customQueryKeys'))], t.stringLiteral('../query-keys'));
63
- statements.push(queryKeyImport);
53
+ const inputTypeImports = [];
54
+ if (hasSelect) {
55
+ inputTypeImports.push(selectTypeName);
56
+ inputTypeImports.push(payloadTypeName);
57
+ }
58
+ else {
59
+ const baseName = getTypeBaseName(operation.returnType);
60
+ if (baseName && !tracker.referencedTypes.has('__skip__')) {
61
+ for (const refType of tracker.referencedTypes) {
62
+ if (!inputTypeImports.includes(refType)) {
63
+ inputTypeImports.push(refType);
64
+ }
65
+ }
66
+ }
67
+ }
68
+ if (inputTypeImports.length > 0) {
69
+ statements.push(createImportDeclaration('../../orm/input-types', inputTypeImports, true));
70
+ }
71
+ if (hasSelect) {
72
+ statements.push(createImportDeclaration('../../orm/select-types', ['InferSelectResult', 'StrictSelect'], true));
64
73
  }
65
- const queryDocConst = t.variableDeclaration('const', [
66
- t.variableDeclarator(t.identifier(documentConstName), t.templateLiteral([t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true)], [])),
67
- ]);
68
- const queryDocExport = t.exportNamedDeclaration(queryDocConst);
69
- addJSDocComment(queryDocExport, ['GraphQL query document']);
70
- statements.push(queryDocExport);
71
- if (operation.args.length > 0) {
72
- const variablesInterfaceProps = variablesProps.map((vp) => {
73
- const prop = t.tsPropertySignature(t.identifier(vp.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))));
74
- prop.optional = vp.optional;
75
- return prop;
76
- });
77
- const variablesInterface = t.tsInterfaceDeclaration(t.identifier(variablesTypeName), null, null, t.tsInterfaceBody(variablesInterfaceProps));
78
- statements.push(t.exportNamedDeclaration(variablesInterface));
74
+ // Re-exports
75
+ if (hasArgs) {
76
+ statements.push(createTypeReExport([varTypeName], '../../orm/query'));
77
+ }
78
+ if (hasSelect) {
79
+ statements.push(createTypeReExport([selectTypeName], '../../orm/input-types'));
79
80
  }
80
- const resultInterfaceBody = t.tsInterfaceBody([
81
- t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType)))),
82
- ]);
83
- const resultInterface = t.tsInterfaceDeclaration(t.identifier(resultTypeName), null, null, resultInterfaceBody);
84
- statements.push(t.exportNamedDeclaration(resultInterface));
81
+ // Query key
85
82
  if (useCentralizedKeys) {
86
- const queryKeyConst = t.variableDeclaration('const', [
83
+ const keyDecl = t.exportNamedDeclaration(t.variableDeclaration('const', [
87
84
  t.variableDeclarator(t.identifier(queryKeyName), t.memberExpression(t.identifier('customQueryKeys'), t.identifier(operation.name))),
85
+ ]));
86
+ addJSDocComment(keyDecl, [
87
+ 'Query key factory - re-exported from query-keys.ts',
88
88
  ]);
89
- const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
90
- addJSDocComment(queryKeyExport, ['Query key factory - re-exported from query-keys.ts']);
91
- statements.push(queryKeyExport);
89
+ statements.push(keyDecl);
92
90
  }
93
- else if (operation.args.length > 0) {
94
- const queryKeyArrow = t.arrowFunctionExpression([typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), true)], t.tsAsExpression(t.arrayExpression([t.stringLiteral(operation.name), t.identifier('variables')]), t.tsTypeReference(t.identifier('const'))));
95
- const queryKeyConst = t.variableDeclaration('const', [
96
- t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow),
97
- ]);
98
- const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
99
- addJSDocComment(queryKeyExport, ['Query key factory for caching']);
100
- statements.push(queryKeyExport);
91
+ else if (hasArgs) {
92
+ const keyFn = t.arrowFunctionExpression([createFunctionParam('variables', typeRef(varTypeName), true)], asConst(t.arrayExpression([
93
+ t.stringLiteral(operation.name),
94
+ t.identifier('variables'),
95
+ ])));
96
+ const keyDecl = t.exportNamedDeclaration(t.variableDeclaration('const', [
97
+ t.variableDeclarator(t.identifier(queryKeyName), keyFn),
98
+ ]));
99
+ addJSDocComment(keyDecl, ['Query key factory for caching']);
100
+ statements.push(keyDecl);
101
101
  }
102
102
  else {
103
- const queryKeyArrow = t.arrowFunctionExpression([], t.tsAsExpression(t.arrayExpression([t.stringLiteral(operation.name)]), t.tsTypeReference(t.identifier('const'))));
104
- const queryKeyConst = t.variableDeclaration('const', [
105
- t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow),
106
- ]);
107
- const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
108
- addJSDocComment(queryKeyExport, ['Query key factory for caching']);
109
- statements.push(queryKeyExport);
103
+ const keyFn = t.arrowFunctionExpression([], asConst(t.arrayExpression([t.stringLiteral(operation.name)])));
104
+ const keyDecl = t.exportNamedDeclaration(t.variableDeclaration('const', [
105
+ t.variableDeclarator(t.identifier(queryKeyName), keyFn),
106
+ ]));
107
+ addJSDocComment(keyDecl, ['Query key factory for caching']);
108
+ statements.push(keyDecl);
110
109
  }
110
+ // Helper to build query key call expression
111
+ const buildQueryKeyCall = (withVars) => {
112
+ if (useCentralizedKeys) {
113
+ return withVars
114
+ ? callExpr(t.identifier(queryKeyName), [t.identifier('variables')])
115
+ : callExpr(t.identifier(queryKeyName), []);
116
+ }
117
+ return withVars
118
+ ? callExpr(t.identifier(queryKeyName), [t.identifier('variables')])
119
+ : callExpr(t.identifier(queryKeyName), []);
120
+ };
121
+ // Helper to build the fields+StrictSelect intersection type
122
+ const fieldsSelectionType = (s) => t.tsParenthesizedType(t.tsIntersectionType([
123
+ t.tsTypeLiteral([
124
+ t.tsPropertySignature(t.identifier('fields'), t.tsTypeAnnotation(s)),
125
+ ]),
126
+ typeRef('StrictSelect', [s, typeRef(selectTypeName)]),
127
+ ]));
128
+ const selectedResultType = (sel) => customSelectResultTypeLiteral(operation.name, operation.returnType, payloadTypeName, sel);
129
+ // Hook
111
130
  if (reactQueryEnabled) {
112
- const hasArgs = operation.args.length > 0;
113
- const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type));
114
- const hookBodyStatements = [];
115
- const useQueryOptions = [];
116
- if (hasArgs) {
117
- useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
118
- useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables')], [
119
- t.tsTypeReference(t.identifier(resultTypeName)),
120
- t.tsTypeReference(t.identifier(variablesTypeName)),
121
- ]))));
122
- if (hasRequiredArgs) {
123
- useQueryOptions.push(t.objectProperty(t.identifier('enabled'), t.logicalExpression('&&', t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), t.binaryExpression('!==', t.optionalMemberExpression(t.identifier('options'), t.identifier('enabled'), false, true), t.booleanLiteral(false)))));
131
+ const description = operation.description || `Query hook for ${operation.name}`;
132
+ const argNames = operation.args.map((a) => a.name).join(', ');
133
+ const exampleCall = hasArgs
134
+ ? hasSelect
135
+ ? `${hookName}({ variables: { ${argNames} }, selection: { fields: { id: true } } })`
136
+ : `${hookName}({ variables: { ${argNames} } })`
137
+ : hasSelect
138
+ ? `${hookName}({ selection: { fields: { id: true } } })`
139
+ : `${hookName}()`;
140
+ if (hasSelect) {
141
+ // Overload 1: with selection.fields
142
+ const o1Props = [];
143
+ if (hasArgs) {
144
+ const varType = hasRequiredArgs
145
+ ? typeRef(varTypeName)
146
+ : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]);
147
+ o1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
124
148
  }
149
+ o1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType(sRef()))));
150
+ const o1ParamType = t.tsIntersectionType([
151
+ t.tsTypeLiteral(o1Props),
152
+ omitType(typeRef('UseQueryOptions', [
153
+ selectedResultType(sRef()),
154
+ typeRef('Error'),
155
+ typeRef('TData'),
156
+ ]), ['queryKey', 'queryFn']),
157
+ ]);
158
+ const o1 = exportDeclareFunction(hookName, createSAndTDataTypeParams(selectTypeName, selectedResultType(sRef())), [createFunctionParam('params', o1ParamType)], typeRef('UseQueryResult', [typeRef('TData')]));
159
+ addJSDocComment(o1, [
160
+ description,
161
+ '',
162
+ '@example',
163
+ '```tsx',
164
+ `const { data, isLoading } = ${exampleCall};`,
165
+ '',
166
+ `if (data?.${operation.name}) {`,
167
+ ` console.log(data.${operation.name});`,
168
+ '}',
169
+ '```',
170
+ ]);
171
+ statements.push(o1);
172
+ // Implementation
173
+ const implProps = [];
174
+ if (hasArgs) {
175
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
176
+ if (!hasRequiredArgs)
177
+ varProp.optional = true;
178
+ implProps.push(varProp);
179
+ }
180
+ const implSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))));
181
+ implProps.push(implSelProp);
182
+ const implParamType = t.tsIntersectionType([
183
+ t.tsTypeLiteral(implProps),
184
+ useQueryOptionsImplType(),
185
+ ]);
186
+ const implParam = createFunctionParam('params', implParamType, false);
187
+ const body = [];
188
+ if (hasArgs) {
189
+ body.push(constDecl('variables', hasRequiredArgs
190
+ ? t.memberExpression(t.identifier('params'), t.identifier('variables'))
191
+ : t.logicalExpression('??', t.memberExpression(t.identifier('params'), t.identifier('variables')), t.objectExpression([]))));
192
+ }
193
+ body.push(buildSelectionArgsCall(selectTypeName));
194
+ if (hasArgs) {
195
+ const destructPattern = t.objectPattern([
196
+ t.objectProperty(t.identifier('variables'), t.identifier('_variables'), false, false),
197
+ t.objectProperty(t.identifier('selection'), t.identifier('_selection'), false, false),
198
+ t.restElement(t.identifier('queryOptions')),
199
+ ]);
200
+ body.push(t.variableDeclaration('const', [
201
+ t.variableDeclarator(destructPattern, t.logicalExpression('??', t.identifier('params'), t.objectExpression([]))),
202
+ ]));
203
+ body.push(voidStatement('_variables'));
204
+ body.push(voidStatement('_selection'));
205
+ }
206
+ else {
207
+ body.push(destructureParamsWithSelection('queryOptions'));
208
+ body.push(voidStatement('_selection'));
209
+ }
210
+ const selectArgExpr = t.objectExpression([
211
+ objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
212
+ ]);
213
+ const queryFnArgs = hasArgs
214
+ ? [
215
+ hasRequiredArgs
216
+ ? t.tsNonNullExpression(t.identifier('variables'))
217
+ : t.identifier('variables'),
218
+ selectArgExpr,
219
+ ]
220
+ : [selectArgExpr];
221
+ const queryFnExpr = t.arrowFunctionExpression([], getClientCustomCallUnwrap('query', operation.name, queryFnArgs));
222
+ const extraProps = [];
223
+ const enabledExpr = hasRequiredArgs
224
+ ? t.logicalExpression('&&', t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), t.binaryExpression('!==', t.optionalMemberExpression(t.identifier('params'), t.identifier('enabled'), false, true), t.booleanLiteral(false)))
225
+ : undefined;
226
+ extraProps.push(spreadObj(t.identifier('queryOptions')));
227
+ body.push(returnUseQuery(buildQueryKeyCall(hasArgs), queryFnExpr, extraProps, enabledExpr));
228
+ statements.push(exportFunction(hookName, null, [implParam], body));
125
229
  }
126
230
  else {
127
- useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
128
- useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName)], [t.tsTypeReference(t.identifier(resultTypeName))]))));
231
+ // Without select: simple hook (scalar return type)
232
+ const resultTypeLiteral = t.tsTypeLiteral([
233
+ t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(typeRef(resultType))),
234
+ ]);
235
+ const optType = omitType(typeRef('UseQueryOptions', [
236
+ resultTypeLiteral,
237
+ typeRef('Error'),
238
+ typeRef('TData'),
239
+ ]), ['queryKey', 'queryFn']);
240
+ let paramType;
241
+ if (hasArgs) {
242
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
243
+ if (!hasRequiredArgs)
244
+ varProp.optional = true;
245
+ paramType = t.tsIntersectionType([t.tsTypeLiteral([varProp]), optType]);
246
+ }
247
+ else {
248
+ paramType = optType;
249
+ }
250
+ const implParam = createFunctionParam('params', paramType, !hasRequiredArgs);
251
+ const hookDecl = exportDeclareFunction(hookName, createTDataTypeParam(resultTypeLiteral), [implParam], typeRef('UseQueryResult', [typeRef('TData')]));
252
+ addJSDocComment(hookDecl, [
253
+ description,
254
+ '',
255
+ '@example',
256
+ '```tsx',
257
+ `const { data, isLoading } = ${exampleCall};`,
258
+ '',
259
+ `if (data?.${operation.name}) {`,
260
+ ` console.log(data.${operation.name});`,
261
+ '}',
262
+ '```',
263
+ ]);
264
+ const body = [];
265
+ if (hasArgs) {
266
+ body.push(constDecl('variables', hasRequiredArgs
267
+ ? t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true)
268
+ : t.logicalExpression('??', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true), t.objectExpression([]))));
269
+ const destructPattern = t.objectPattern([
270
+ t.objectProperty(t.identifier('variables'), t.identifier('_variables'), false, false),
271
+ t.restElement(t.identifier('queryOptions')),
272
+ ]);
273
+ body.push(t.variableDeclaration('const', [
274
+ t.variableDeclarator(destructPattern, t.logicalExpression('??', t.identifier('params'), t.objectExpression([]))),
275
+ ]));
276
+ body.push(voidStatement('_variables'));
277
+ }
278
+ else {
279
+ body.push(constDecl('queryOptions', t.logicalExpression('??', t.identifier('params'), t.objectExpression([]))));
280
+ }
281
+ const queryFnArgs = hasArgs
282
+ ? [
283
+ hasRequiredArgs
284
+ ? t.tsNonNullExpression(t.identifier('variables'))
285
+ : t.identifier('variables'),
286
+ ]
287
+ : [];
288
+ const queryFnExpr = t.arrowFunctionExpression([], getClientCustomCallUnwrap('query', operation.name, queryFnArgs));
289
+ const enabledExpr = hasRequiredArgs
290
+ ? t.logicalExpression('&&', t.unaryExpression('!', t.unaryExpression('!', t.identifier('variables'))), t.binaryExpression('!==', t.optionalMemberExpression(t.identifier('params'), t.identifier('enabled'), false, true), t.booleanLiteral(false)))
291
+ : undefined;
292
+ body.push(returnUseQuery(buildQueryKeyCall(hasArgs), queryFnExpr, [spreadObj(t.identifier('queryOptions'))], enabledExpr));
293
+ // We need the implementation version (not declare), with return type
294
+ statements.push(hookDecl);
295
+ statements.push(exportFunction(hookName, createTDataTypeParam(resultTypeLiteral), [implParam], body, typeRef('UseQueryResult', [typeRef('TData')])));
129
296
  }
130
- useQueryOptions.push(t.spreadElement(t.identifier('options')));
131
- hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [t.objectExpression(useQueryOptions)])));
132
- const hookParams = [];
297
+ }
298
+ // Fetch function (non-hook)
299
+ const fetchFnName = `fetch${ucFirst(operation.name)}Query`;
300
+ const fetchArgNames = operation.args.map((a) => a.name).join(', ');
301
+ const fetchExampleCall = hasArgs
302
+ ? hasSelect
303
+ ? `${fetchFnName}({ variables: { ${fetchArgNames} }, selection: { fields: { id: true } } })`
304
+ : `${fetchFnName}({ variables: { ${fetchArgNames} } })`
305
+ : hasSelect
306
+ ? `${fetchFnName}({ selection: { fields: { id: true } } })`
307
+ : `${fetchFnName}()`;
308
+ if (hasSelect) {
309
+ // Overload 1: with fields
310
+ const f1Props = [];
133
311
  if (hasArgs) {
134
- hookParams.push(typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
312
+ const varType = hasRequiredArgs
313
+ ? typeRef(varTypeName)
314
+ : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]);
315
+ f1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
135
316
  }
136
- const optionsTypeStr = `Omit<UseQueryOptions<${resultTypeName}, Error>, 'queryKey' | 'queryFn'>`;
137
- const optionsParam = t.identifier('options');
138
- optionsParam.optional = true;
139
- optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
140
- hookParams.push(optionsParam);
141
- const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
142
- const hookExport = t.exportNamedDeclaration(hookFunc);
143
- const description = operation.description || `Query hook for ${operation.name}`;
144
- const argNames = operation.args.map((a) => a.name).join(', ');
145
- const exampleCall = hasArgs ? `${hookName}({ ${argNames} })` : `${hookName}()`;
146
- addJSDocComment(hookExport, [
147
- description,
317
+ f1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType(sRef()))));
318
+ const f1Decl = exportAsyncDeclareFunction(fetchFnName, createSTypeParam(selectTypeName), [createFunctionParam('params', t.tsTypeLiteral(f1Props))], typeRef('Promise', [selectedResultType(sRef())]));
319
+ addJSDocComment(f1Decl, [
320
+ `Fetch ${operation.name} without React hooks`,
148
321
  '',
149
322
  '@example',
150
- '```tsx',
151
- `const { data, isLoading } = ${exampleCall};`,
152
- '',
153
- `if (data?.${operation.name}) {`,
154
- ` console.log(data.${operation.name});`,
155
- '}',
323
+ '```ts',
324
+ `const data = await ${fetchExampleCall};`,
156
325
  '```',
157
326
  ]);
158
- statements.push(hookExport);
159
- }
160
- const fetchFnName = `fetch${ucFirst(operation.name)}Query`;
161
- const hasArgs = operation.args.length > 0;
162
- const hasRequiredArgs = operation.args.some((arg) => isTypeRequired(arg.type));
163
- const fetchBodyStatements = [];
164
- if (hasArgs) {
165
- fetchBodyStatements.push(t.returnStatement(createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
166
- t.tsTypeReference(t.identifier(resultTypeName)),
167
- t.tsTypeReference(t.identifier(variablesTypeName)),
168
- ])));
327
+ statements.push(f1Decl);
328
+ // Implementation
329
+ const fImplProps = [];
330
+ if (hasArgs) {
331
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
332
+ if (!hasRequiredArgs)
333
+ varProp.optional = true;
334
+ fImplProps.push(varProp);
335
+ }
336
+ const fImplSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))));
337
+ fImplProps.push(fImplSelProp);
338
+ const fBody = [];
339
+ if (hasArgs) {
340
+ fBody.push(constDecl('variables', hasRequiredArgs
341
+ ? t.memberExpression(t.identifier('params'), t.identifier('variables'))
342
+ : t.logicalExpression('??', t.memberExpression(t.identifier('params'), t.identifier('variables')), t.objectExpression([]))));
343
+ }
344
+ fBody.push(buildSelectionArgsCall(selectTypeName));
345
+ const selectArgExpr = t.objectExpression([
346
+ objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
347
+ ]);
348
+ const fCallArgs = hasArgs
349
+ ? [
350
+ hasRequiredArgs
351
+ ? t.tsNonNullExpression(t.identifier('variables'))
352
+ : t.identifier('variables'),
353
+ selectArgExpr,
354
+ ]
355
+ : [selectArgExpr];
356
+ fBody.push(t.returnStatement(getClientCustomCallUnwrap('query', operation.name, fCallArgs)));
357
+ statements.push(exportAsyncFunction(fetchFnName, null, [
358
+ createFunctionParam('params', t.tsTypeLiteral(fImplProps), false),
359
+ ], fBody));
169
360
  }
170
361
  else {
171
- fetchBodyStatements.push(t.returnStatement(createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))])));
172
- }
173
- const fetchParams = [];
174
- if (hasArgs) {
175
- fetchParams.push(typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
362
+ const fBody = [];
363
+ if (hasArgs) {
364
+ const fProps = [];
365
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
366
+ if (!hasRequiredArgs)
367
+ varProp.optional = true;
368
+ fProps.push(varProp);
369
+ fBody.push(constDecl('variables', hasRequiredArgs
370
+ ? t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true)
371
+ : t.logicalExpression('??', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true), t.objectExpression([]))));
372
+ const fCallArgs = hasRequiredArgs
373
+ ? [t.tsNonNullExpression(t.identifier('variables'))]
374
+ : [t.identifier('variables')];
375
+ fBody.push(t.returnStatement(getClientCustomCallUnwrap('query', operation.name, fCallArgs)));
376
+ const fDecl = exportAsyncFunction(fetchFnName, null, [
377
+ createFunctionParam('params', t.tsTypeLiteral(fProps), !hasRequiredArgs),
378
+ ], fBody);
379
+ addJSDocComment(fDecl, [
380
+ `Fetch ${operation.name} without React hooks`,
381
+ '',
382
+ '@example',
383
+ '```ts',
384
+ `const data = await ${fetchExampleCall};`,
385
+ '```',
386
+ ]);
387
+ statements.push(fDecl);
388
+ }
389
+ else {
390
+ fBody.push(t.returnStatement(getClientCustomCallUnwrap('query', operation.name, [])));
391
+ const fDecl = exportAsyncFunction(fetchFnName, null, [], fBody);
392
+ addJSDocComment(fDecl, [
393
+ `Fetch ${operation.name} without React hooks`,
394
+ '',
395
+ '@example',
396
+ '```ts',
397
+ `const data = await ${fetchExampleCall};`,
398
+ '```',
399
+ ]);
400
+ statements.push(fDecl);
401
+ }
176
402
  }
177
- fetchParams.push(typedParam('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
178
- const fetchFunc = t.functionDeclaration(t.identifier(fetchFnName), fetchParams, t.blockStatement(fetchBodyStatements));
179
- fetchFunc.async = true;
180
- fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsTypeReference(t.identifier(resultTypeName))])));
181
- const fetchExport = t.exportNamedDeclaration(fetchFunc);
182
- const argNames = operation.args.map((a) => a.name).join(', ');
183
- const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${argNames} })` : `${fetchFnName}()`;
184
- addJSDocComment(fetchExport, [
185
- `Fetch ${operation.name} without React hooks`,
186
- '',
187
- '@example',
188
- '```ts',
189
- `const data = await ${fetchExampleCall};`,
190
- '```',
191
- ]);
192
- statements.push(fetchExport);
403
+ // Prefetch function
193
404
  if (reactQueryEnabled) {
194
405
  const prefetchFnName = `prefetch${ucFirst(operation.name)}Query`;
195
- const prefetchBodyStatements = [];
196
- const prefetchQueryOptions = [];
197
- if (hasArgs) {
198
- prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
199
- prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
200
- t.tsTypeReference(t.identifier(resultTypeName)),
201
- t.tsTypeReference(t.identifier(variablesTypeName)),
202
- ]))));
406
+ const prefetchArgNames = operation.args.map((a) => a.name).join(', ');
407
+ const prefetchExampleCall = hasArgs
408
+ ? hasSelect
409
+ ? `${prefetchFnName}(queryClient, { variables: { ${prefetchArgNames} }, selection: { fields: { id: true } } })`
410
+ : `${prefetchFnName}(queryClient, { variables: { ${prefetchArgNames} } })`
411
+ : hasSelect
412
+ ? `${prefetchFnName}(queryClient, { selection: { fields: { id: true } } })`
413
+ : `${prefetchFnName}(queryClient)`;
414
+ if (hasSelect) {
415
+ // Overload 1: with fields
416
+ const p1Props = [];
417
+ if (hasArgs) {
418
+ const varType = hasRequiredArgs
419
+ ? typeRef(varTypeName)
420
+ : t.tsUnionType([typeRef(varTypeName), t.tsUndefinedKeyword()]);
421
+ p1Props.push(t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(varType)));
422
+ }
423
+ p1Props.push(t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(fieldsSelectionType(sRef()))));
424
+ const p1Decl = exportAsyncDeclareFunction(prefetchFnName, createSTypeParam(selectTypeName), [
425
+ createFunctionParam('queryClient', typeRef('QueryClient')),
426
+ createFunctionParam('params', t.tsTypeLiteral(p1Props)),
427
+ ], typeRef('Promise', [t.tsVoidKeyword()]));
428
+ addJSDocComment(p1Decl, [
429
+ `Prefetch ${operation.name} for SSR or cache warming`,
430
+ '',
431
+ '@example',
432
+ '```ts',
433
+ `await ${prefetchExampleCall};`,
434
+ '```',
435
+ ]);
436
+ statements.push(p1Decl);
437
+ // Implementation
438
+ const pImplProps = [];
439
+ if (hasArgs) {
440
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
441
+ if (!hasRequiredArgs)
442
+ varProp.optional = true;
443
+ pImplProps.push(varProp);
444
+ }
445
+ const pImplSelProp = t.tsPropertySignature(t.identifier('selection'), t.tsTypeAnnotation(selectionConfigType(typeRef(selectTypeName))));
446
+ pImplProps.push(pImplSelProp);
447
+ const pBody = [];
448
+ if (hasArgs) {
449
+ pBody.push(constDecl('variables', hasRequiredArgs
450
+ ? t.memberExpression(t.identifier('params'), t.identifier('variables'))
451
+ : t.logicalExpression('??', t.memberExpression(t.identifier('params'), t.identifier('variables')), t.objectExpression([]))));
452
+ }
453
+ pBody.push(buildSelectionArgsCall(selectTypeName));
454
+ const selectArgExpr = t.objectExpression([
455
+ objectProp('select', t.memberExpression(t.identifier('args'), t.identifier('select'))),
456
+ ]);
457
+ const pCallArgs = hasArgs
458
+ ? [
459
+ hasRequiredArgs
460
+ ? t.tsNonNullExpression(t.identifier('variables'))
461
+ : t.identifier('variables'),
462
+ selectArgExpr,
463
+ ]
464
+ : [selectArgExpr];
465
+ const prefetchQueryCall = callExpr(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
466
+ t.objectExpression([
467
+ objectProp('queryKey', buildQueryKeyCall(hasArgs)),
468
+ objectProp('queryFn', t.arrowFunctionExpression([], getClientCustomCallUnwrap('query', operation.name, pCallArgs))),
469
+ ]),
470
+ ]);
471
+ pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall)));
472
+ statements.push(exportAsyncFunction(prefetchFnName, null, [
473
+ createFunctionParam('queryClient', typeRef('QueryClient')),
474
+ createFunctionParam('params', t.tsTypeLiteral(pImplProps), false),
475
+ ], pBody, typeRef('Promise', [t.tsVoidKeyword()])));
203
476
  }
204
477
  else {
205
- prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
206
- prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], createTypedCallExpression(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))]))));
207
- }
208
- prefetchBodyStatements.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [t.objectExpression(prefetchQueryOptions)]))));
209
- const prefetchParams = [
210
- typedParam('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
211
- ];
212
- if (hasArgs) {
213
- prefetchParams.push(typedParam('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
478
+ // Without select
479
+ const pBody = [];
480
+ const pParams = [
481
+ createFunctionParam('queryClient', typeRef('QueryClient')),
482
+ ];
483
+ if (hasArgs) {
484
+ const pProps = [];
485
+ const varProp = t.tsPropertySignature(t.identifier('variables'), t.tsTypeAnnotation(typeRef(varTypeName)));
486
+ if (!hasRequiredArgs)
487
+ varProp.optional = true;
488
+ pProps.push(varProp);
489
+ pParams.push(createFunctionParam('params', t.tsTypeLiteral(pProps), !hasRequiredArgs));
490
+ pBody.push(constDecl('variables', hasRequiredArgs
491
+ ? t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true)
492
+ : t.logicalExpression('??', t.optionalMemberExpression(t.identifier('params'), t.identifier('variables'), false, true), t.objectExpression([]))));
493
+ const pCallArgs = hasRequiredArgs
494
+ ? [t.tsNonNullExpression(t.identifier('variables'))]
495
+ : [t.identifier('variables')];
496
+ const prefetchQueryCall = callExpr(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
497
+ t.objectExpression([
498
+ objectProp('queryKey', buildQueryKeyCall(true)),
499
+ objectProp('queryFn', t.arrowFunctionExpression([], getClientCustomCallUnwrap('query', operation.name, pCallArgs))),
500
+ ]),
501
+ ]);
502
+ pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall)));
503
+ }
504
+ else {
505
+ const prefetchQueryCall = callExpr(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [
506
+ t.objectExpression([
507
+ objectProp('queryKey', buildQueryKeyCall(false)),
508
+ objectProp('queryFn', t.arrowFunctionExpression([], getClientCustomCallUnwrap('query', operation.name, []))),
509
+ ]),
510
+ ]);
511
+ pBody.push(t.expressionStatement(t.awaitExpression(prefetchQueryCall)));
512
+ }
513
+ const pDecl = exportAsyncFunction(prefetchFnName, null, pParams, pBody, typeRef('Promise', [t.tsVoidKeyword()]));
514
+ addJSDocComment(pDecl, [
515
+ `Prefetch ${operation.name} for SSR or cache warming`,
516
+ '',
517
+ '@example',
518
+ '```ts',
519
+ `await ${prefetchExampleCall};`,
520
+ '```',
521
+ ]);
522
+ statements.push(pDecl);
214
523
  }
215
- prefetchParams.push(typedParam('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
216
- const prefetchFunc = t.functionDeclaration(t.identifier(prefetchFnName), prefetchParams, t.blockStatement(prefetchBodyStatements));
217
- prefetchFunc.async = true;
218
- prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
219
- const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
220
- const prefetchExampleCall = hasArgs
221
- ? `${prefetchFnName}(queryClient, { ${argNames} })`
222
- : `${prefetchFnName}(queryClient)`;
223
- addJSDocComment(prefetchExport, [
224
- `Prefetch ${operation.name} for SSR or cache warming`,
225
- '',
226
- '@example',
227
- '```ts',
228
- `await ${prefetchExampleCall};`,
229
- '```',
230
- ]);
231
- statements.push(prefetchExport);
232
524
  }
233
- const code = generateCode(statements);
234
525
  const headerText = reactQueryEnabled
235
526
  ? `Custom query hook for ${operation.name}`
236
527
  : `Custom query functions for ${operation.name}`;
237
- const content = getGeneratedFileHeader(headerText) + '\n\n' + code;
528
+ const content = generateHookFileCode(headerText, statements);
238
529
  return {
239
530
  fileName,
240
531
  content,
@@ -242,13 +533,12 @@ export function generateCustomQueryHook(options) {
242
533
  };
243
534
  }
244
535
  export function generateAllCustomQueryHooks(options) {
245
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
536
+ const { operations, typeRegistry, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
246
537
  return operations
247
538
  .filter((op) => op.kind === 'query')
248
539
  .map((operation) => generateCustomQueryHook({
249
540
  operation,
250
541
  typeRegistry,
251
- maxDepth,
252
542
  skipQueryField,
253
543
  reactQueryEnabled,
254
544
  tableTypeNames,