@constructive-io/graphql-codegen 2.23.3 → 2.24.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 (92) hide show
  1. package/README.md +147 -2
  2. package/cli/codegen/babel-ast.d.ts +53 -0
  3. package/cli/codegen/babel-ast.js +160 -0
  4. package/cli/codegen/barrel.d.ts +7 -2
  5. package/cli/codegen/barrel.js +193 -102
  6. package/cli/codegen/client.js +61 -0
  7. package/cli/codegen/custom-mutations.d.ts +2 -12
  8. package/cli/codegen/custom-mutations.js +116 -124
  9. package/cli/codegen/custom-queries.d.ts +2 -10
  10. package/cli/codegen/custom-queries.js +236 -335
  11. package/cli/codegen/gql-ast.js +22 -1
  12. package/cli/codegen/index.d.ts +3 -0
  13. package/cli/codegen/index.js +73 -3
  14. package/cli/codegen/invalidation.d.ts +20 -0
  15. package/cli/codegen/invalidation.js +327 -0
  16. package/cli/codegen/mutation-keys.d.ts +24 -0
  17. package/cli/codegen/mutation-keys.js +247 -0
  18. package/cli/codegen/mutations.d.ts +5 -19
  19. package/cli/codegen/mutations.js +385 -383
  20. package/cli/codegen/orm/barrel.d.ts +1 -1
  21. package/cli/codegen/orm/barrel.js +42 -10
  22. package/cli/codegen/orm/client-generator.d.ts +1 -19
  23. package/cli/codegen/orm/client-generator.js +108 -77
  24. package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  25. package/cli/codegen/orm/custom-ops-generator.js +192 -235
  26. package/cli/codegen/orm/input-types-generator.d.ts +13 -1
  27. package/cli/codegen/orm/input-types-generator.js +425 -147
  28. package/cli/codegen/orm/model-generator.d.ts +1 -19
  29. package/cli/codegen/orm/model-generator.js +229 -234
  30. package/cli/codegen/queries.d.ts +4 -12
  31. package/cli/codegen/queries.js +660 -390
  32. package/cli/codegen/query-keys.d.ts +15 -0
  33. package/cli/codegen/query-keys.js +477 -0
  34. package/cli/codegen/scalars.js +1 -0
  35. package/cli/codegen/schema-types-generator.d.ts +15 -10
  36. package/cli/codegen/schema-types-generator.js +87 -175
  37. package/cli/codegen/type-resolver.d.ts +1 -30
  38. package/cli/codegen/type-resolver.js +0 -53
  39. package/cli/codegen/types.d.ts +1 -1
  40. package/cli/codegen/types.js +76 -21
  41. package/cli/codegen/utils.d.ts +6 -0
  42. package/cli/codegen/utils.js +19 -0
  43. package/esm/cli/codegen/babel-ast.d.ts +53 -0
  44. package/esm/cli/codegen/babel-ast.js +111 -0
  45. package/esm/cli/codegen/barrel.d.ts +7 -2
  46. package/esm/cli/codegen/barrel.js +161 -103
  47. package/esm/cli/codegen/client.js +61 -0
  48. package/esm/cli/codegen/custom-mutations.d.ts +2 -12
  49. package/esm/cli/codegen/custom-mutations.js +83 -124
  50. package/esm/cli/codegen/custom-queries.d.ts +2 -10
  51. package/esm/cli/codegen/custom-queries.js +204 -336
  52. package/esm/cli/codegen/gql-ast.js +23 -2
  53. package/esm/cli/codegen/index.d.ts +3 -0
  54. package/esm/cli/codegen/index.js +69 -2
  55. package/esm/cli/codegen/invalidation.d.ts +20 -0
  56. package/esm/cli/codegen/invalidation.js +291 -0
  57. package/esm/cli/codegen/mutation-keys.d.ts +24 -0
  58. package/esm/cli/codegen/mutation-keys.js +211 -0
  59. package/esm/cli/codegen/mutations.d.ts +5 -19
  60. package/esm/cli/codegen/mutations.js +353 -384
  61. package/esm/cli/codegen/orm/barrel.d.ts +1 -1
  62. package/esm/cli/codegen/orm/barrel.js +10 -11
  63. package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
  64. package/esm/cli/codegen/orm/client-generator.js +76 -78
  65. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  66. package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
  67. package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
  68. package/esm/cli/codegen/orm/input-types-generator.js +393 -148
  69. package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
  70. package/esm/cli/codegen/orm/model-generator.js +197 -235
  71. package/esm/cli/codegen/queries.d.ts +4 -12
  72. package/esm/cli/codegen/queries.js +628 -391
  73. package/esm/cli/codegen/query-keys.d.ts +15 -0
  74. package/esm/cli/codegen/query-keys.js +441 -0
  75. package/esm/cli/codegen/scalars.js +1 -0
  76. package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
  77. package/esm/cli/codegen/schema-types-generator.js +54 -175
  78. package/esm/cli/codegen/type-resolver.d.ts +1 -30
  79. package/esm/cli/codegen/type-resolver.js +0 -49
  80. package/esm/cli/codegen/types.d.ts +1 -1
  81. package/esm/cli/codegen/types.js +44 -22
  82. package/esm/cli/codegen/utils.d.ts +6 -0
  83. package/esm/cli/codegen/utils.js +18 -0
  84. package/esm/types/config.d.ts +75 -0
  85. package/esm/types/config.js +18 -0
  86. package/package.json +6 -4
  87. package/types/config.d.ts +75 -0
  88. package/types/config.js +19 -1
  89. package/cli/codegen/ts-ast.d.ts +0 -124
  90. package/cli/codegen/ts-ast.js +0 -280
  91. package/esm/cli/codegen/ts-ast.d.ts +0 -124
  92. package/esm/cli/codegen/ts-ast.js +0 -260
@@ -1,385 +1,285 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.generateCustomQueryHook = generateCustomQueryHook;
4
37
  exports.generateAllCustomQueryHooks = generateAllCustomQueryHooks;
5
- const ts_ast_1 = require("./ts-ast");
38
+ const t = __importStar(require("@babel/types"));
39
+ const babel_ast_1 = require("./babel-ast");
6
40
  const schema_gql_ast_1 = require("./schema-gql-ast");
7
41
  const type_resolver_1 = require("./type-resolver");
8
42
  const utils_1 = require("./utils");
9
- /**
10
- * Generate a custom query hook file
11
- */
43
+ function generateVariablesProperties(args, tracker) {
44
+ return args.map((arg) => ({
45
+ name: arg.name,
46
+ type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
47
+ optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
48
+ docs: arg.description ? [arg.description] : undefined,
49
+ }));
50
+ }
12
51
  function generateCustomQueryHook(options) {
13
- const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
14
- const project = (0, ts_ast_1.createProject)();
52
+ const { operation, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
15
53
  const hookName = (0, type_resolver_1.getOperationHookName)(operation.name, 'query');
16
54
  const fileName = (0, type_resolver_1.getOperationFileName)(operation.name, 'query');
17
55
  const variablesTypeName = (0, type_resolver_1.getOperationVariablesTypeName)(operation.name, 'query');
18
56
  const resultTypeName = (0, type_resolver_1.getOperationResultTypeName)(operation.name, 'query');
19
57
  const documentConstName = (0, type_resolver_1.getDocumentConstName)(operation.name, 'query');
20
58
  const queryKeyName = (0, type_resolver_1.getQueryKeyName)(operation.name);
21
- // Create type tracker to collect referenced types (with table type awareness)
22
59
  const tracker = (0, type_resolver_1.createTypeTracker)({ tableTypeNames });
23
- // Generate GraphQL document
24
60
  const queryDocument = (0, schema_gql_ast_1.buildCustomQueryString)({
25
61
  operation,
26
62
  typeRegistry,
27
63
  maxDepth,
28
64
  skipQueryField,
29
65
  });
30
- const sourceFile = (0, ts_ast_1.createSourceFile)(project, fileName);
31
- // Add file header
32
- const headerText = reactQueryEnabled
33
- ? `Custom query hook for ${operation.name}`
34
- : `Custom query functions for ${operation.name}`;
35
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)(headerText) + '\n\n');
36
- // Generate variables interface if there are arguments (with tracking)
37
- let variablesProps = [];
38
- if (operation.args.length > 0) {
39
- variablesProps = generateVariablesProperties(operation.args, tracker);
40
- }
41
- // Generate result interface (with tracking)
66
+ const statements = [];
67
+ const variablesProps = operation.args.length > 0
68
+ ? generateVariablesProperties(operation.args, tracker)
69
+ : [];
42
70
  const resultType = (0, type_resolver_1.typeRefToTsType)(operation.returnType, tracker);
43
- const resultProps = [
44
- { name: operation.name, type: resultType },
45
- ];
46
- // Get importable types from tracker (separated by source)
47
- const schemaTypes = tracker.getImportableTypes(); // From schema-types.ts
48
- const tableTypes = tracker.getTableTypes(); // From types.ts
49
- // Add imports - conditionally include React Query imports
50
- const imports = [];
71
+ const schemaTypes = tracker.getImportableTypes();
72
+ const tableTypes = tracker.getTableTypes();
51
73
  if (reactQueryEnabled) {
52
- imports.push((0, ts_ast_1.createImport)({
53
- moduleSpecifier: '@tanstack/react-query',
54
- namedImports: ['useQuery'],
55
- typeOnlyNamedImports: ['UseQueryOptions', 'QueryClient'],
56
- }));
74
+ const reactQueryImport = t.importDeclaration([t.importSpecifier(t.identifier('useQuery'), t.identifier('useQuery'))], t.stringLiteral('@tanstack/react-query'));
75
+ statements.push(reactQueryImport);
76
+ const reactQueryTypeImport = t.importDeclaration([
77
+ t.importSpecifier(t.identifier('UseQueryOptions'), t.identifier('UseQueryOptions')),
78
+ t.importSpecifier(t.identifier('QueryClient'), t.identifier('QueryClient')),
79
+ ], t.stringLiteral('@tanstack/react-query'));
80
+ reactQueryTypeImport.importKind = 'type';
81
+ statements.push(reactQueryTypeImport);
57
82
  }
58
- imports.push((0, ts_ast_1.createImport)({
59
- moduleSpecifier: '../client',
60
- namedImports: ['execute'],
61
- typeOnlyNamedImports: ['ExecuteOptions'],
62
- }));
63
- // Add types.ts import for table entity types
83
+ const clientImport = t.importDeclaration([t.importSpecifier(t.identifier('execute'), t.identifier('execute'))], t.stringLiteral('../client'));
84
+ statements.push(clientImport);
85
+ const clientTypeImport = t.importDeclaration([t.importSpecifier(t.identifier('ExecuteOptions'), t.identifier('ExecuteOptions'))], t.stringLiteral('../client'));
86
+ clientTypeImport.importKind = 'type';
87
+ statements.push(clientTypeImport);
64
88
  if (tableTypes.length > 0) {
65
- imports.push((0, ts_ast_1.createImport)({
66
- moduleSpecifier: '../types',
67
- typeOnlyNamedImports: tableTypes,
68
- }));
89
+ const typesImport = t.importDeclaration(tableTypes.map((tt) => t.importSpecifier(t.identifier(tt), t.identifier(tt))), t.stringLiteral('../types'));
90
+ typesImport.importKind = 'type';
91
+ statements.push(typesImport);
69
92
  }
70
- // Add schema-types import for Input/Payload/Enum types
71
93
  if (schemaTypes.length > 0) {
72
- imports.push((0, ts_ast_1.createImport)({
73
- moduleSpecifier: '../schema-types',
74
- typeOnlyNamedImports: schemaTypes,
75
- }));
94
+ const schemaTypesImport = t.importDeclaration(schemaTypes.map((st) => t.importSpecifier(t.identifier(st), t.identifier(st))), t.stringLiteral('../schema-types'));
95
+ schemaTypesImport.importKind = 'type';
96
+ statements.push(schemaTypesImport);
76
97
  }
77
- sourceFile.addImportDeclarations(imports);
78
- // Add query document constant
79
- sourceFile.addVariableStatement((0, ts_ast_1.createConst)(documentConstName, '`\n' + queryDocument + '`', {
80
- docs: ['GraphQL query document'],
81
- }));
82
- // Add variables interface
83
- if (operation.args.length > 0) {
84
- sourceFile.addInterface((0, ts_ast_1.createInterface)(variablesTypeName, variablesProps));
98
+ if (useCentralizedKeys) {
99
+ const queryKeyImport = t.importDeclaration([t.importSpecifier(t.identifier('customQueryKeys'), t.identifier('customQueryKeys'))], t.stringLiteral('../query-keys'));
100
+ statements.push(queryKeyImport);
85
101
  }
86
- // Add result interface
87
- sourceFile.addInterface((0, ts_ast_1.createInterface)(resultTypeName, resultProps));
88
- // Query key factory
102
+ const queryDocConst = t.variableDeclaration('const', [
103
+ t.variableDeclarator(t.identifier(documentConstName), t.templateLiteral([t.templateElement({ raw: '\n' + queryDocument, cooked: '\n' + queryDocument }, true)], [])),
104
+ ]);
105
+ const queryDocExport = t.exportNamedDeclaration(queryDocConst);
106
+ (0, babel_ast_1.addJSDocComment)(queryDocExport, ['GraphQL query document']);
107
+ statements.push(queryDocExport);
89
108
  if (operation.args.length > 0) {
90
- sourceFile.addVariableStatement((0, ts_ast_1.createConst)(queryKeyName, `(variables?: ${variablesTypeName}) =>
91
- ['${operation.name}', variables] as const`, { docs: ['Query key factory for caching'] }));
109
+ const variablesInterfaceProps = variablesProps.map((vp) => {
110
+ const prop = t.tsPropertySignature(t.identifier(vp.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(vp.type))));
111
+ prop.optional = vp.optional;
112
+ return prop;
113
+ });
114
+ const variablesInterface = t.tsInterfaceDeclaration(t.identifier(variablesTypeName), null, null, t.tsInterfaceBody(variablesInterfaceProps));
115
+ statements.push(t.exportNamedDeclaration(variablesInterface));
116
+ }
117
+ const resultInterfaceBody = t.tsInterfaceBody([
118
+ t.tsPropertySignature(t.identifier(operation.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(resultType)))),
119
+ ]);
120
+ const resultInterface = t.tsInterfaceDeclaration(t.identifier(resultTypeName), null, null, resultInterfaceBody);
121
+ statements.push(t.exportNamedDeclaration(resultInterface));
122
+ if (useCentralizedKeys) {
123
+ const queryKeyConst = t.variableDeclaration('const', [
124
+ t.variableDeclarator(t.identifier(queryKeyName), t.memberExpression(t.identifier('customQueryKeys'), t.identifier(operation.name))),
125
+ ]);
126
+ const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
127
+ (0, babel_ast_1.addJSDocComment)(queryKeyExport, ['Query key factory - re-exported from query-keys.ts']);
128
+ statements.push(queryKeyExport);
129
+ }
130
+ else if (operation.args.length > 0) {
131
+ const queryKeyArrow = t.arrowFunctionExpression([(0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), true)], t.tsAsExpression(t.arrayExpression([t.stringLiteral(operation.name), t.identifier('variables')]), t.tsTypeReference(t.identifier('const'))));
132
+ const queryKeyConst = t.variableDeclaration('const', [
133
+ t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow),
134
+ ]);
135
+ const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
136
+ (0, babel_ast_1.addJSDocComment)(queryKeyExport, ['Query key factory for caching']);
137
+ statements.push(queryKeyExport);
92
138
  }
93
139
  else {
94
- sourceFile.addVariableStatement((0, ts_ast_1.createConst)(queryKeyName, `() => ['${operation.name}'] as const`, {
95
- docs: ['Query key factory for caching'],
96
- }));
140
+ const queryKeyArrow = t.arrowFunctionExpression([], t.tsAsExpression(t.arrayExpression([t.stringLiteral(operation.name)]), t.tsTypeReference(t.identifier('const'))));
141
+ const queryKeyConst = t.variableDeclaration('const', [
142
+ t.variableDeclarator(t.identifier(queryKeyName), queryKeyArrow),
143
+ ]);
144
+ const queryKeyExport = t.exportNamedDeclaration(queryKeyConst);
145
+ (0, babel_ast_1.addJSDocComment)(queryKeyExport, ['Query key factory for caching']);
146
+ statements.push(queryKeyExport);
97
147
  }
98
- // Generate hook function (only if React Query is enabled)
99
148
  if (reactQueryEnabled) {
100
- const hookParams = generateHookParameters(operation, variablesTypeName, resultTypeName);
101
- const hookBody = generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
102
- const hookDoc = generateHookDoc(operation, hookName);
103
- sourceFile.addFunction({
104
- name: hookName,
105
- isExported: true,
106
- parameters: hookParams,
107
- statements: hookBody,
108
- docs: [{ description: hookDoc }],
109
- });
149
+ const hasArgs = operation.args.length > 0;
150
+ const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
151
+ const hookBodyStatements = [];
152
+ const useQueryOptions = [];
153
+ if (hasArgs) {
154
+ useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
155
+ useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables')], [
156
+ t.tsTypeReference(t.identifier(resultTypeName)),
157
+ t.tsTypeReference(t.identifier(variablesTypeName)),
158
+ ]))));
159
+ if (hasRequiredArgs) {
160
+ 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)))));
161
+ }
162
+ }
163
+ else {
164
+ useQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
165
+ useQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName)], [t.tsTypeReference(t.identifier(resultTypeName))]))));
166
+ }
167
+ useQueryOptions.push(t.spreadElement(t.identifier('options')));
168
+ hookBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('useQuery'), [t.objectExpression(useQueryOptions)])));
169
+ const hookParams = [];
170
+ if (hasArgs) {
171
+ hookParams.push((0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
172
+ }
173
+ const optionsTypeStr = `Omit<UseQueryOptions<${resultTypeName}, Error>, 'queryKey' | 'queryFn'>`;
174
+ const optionsParam = t.identifier('options');
175
+ optionsParam.optional = true;
176
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(optionsTypeStr)));
177
+ hookParams.push(optionsParam);
178
+ const hookFunc = t.functionDeclaration(t.identifier(hookName), hookParams, t.blockStatement(hookBodyStatements));
179
+ const hookExport = t.exportNamedDeclaration(hookFunc);
180
+ const description = operation.description || `Query hook for ${operation.name}`;
181
+ const argNames = operation.args.map((a) => a.name).join(', ');
182
+ const exampleCall = hasArgs ? `${hookName}({ ${argNames} })` : `${hookName}()`;
183
+ (0, babel_ast_1.addJSDocComment)(hookExport, [
184
+ description,
185
+ '',
186
+ '@example',
187
+ '```tsx',
188
+ `const { data, isLoading } = ${exampleCall};`,
189
+ '',
190
+ `if (data?.${operation.name}) {`,
191
+ ` console.log(data.${operation.name});`,
192
+ '}',
193
+ '```',
194
+ ]);
195
+ statements.push(hookExport);
110
196
  }
111
- // Add standalone functions section
112
- sourceFile.addStatements('\n// ============================================================================');
113
- sourceFile.addStatements('// Standalone Functions (non-React)');
114
- sourceFile.addStatements('// ============================================================================\n');
115
- // Generate standalone fetch function
116
197
  const fetchFnName = `fetch${(0, utils_1.ucFirst)(operation.name)}Query`;
117
- const fetchParams = generateFetchParameters(operation, variablesTypeName);
118
- const fetchBody = generateFetchBody(operation, documentConstName, variablesTypeName, resultTypeName);
119
- const fetchDoc = generateFetchDoc(operation, fetchFnName);
120
- sourceFile.addFunction({
121
- name: fetchFnName,
122
- isExported: true,
123
- isAsync: true,
124
- parameters: fetchParams,
125
- returnType: `Promise<${resultTypeName}>`,
126
- statements: fetchBody,
127
- docs: [{ description: fetchDoc }],
128
- });
129
- // Generate prefetch function (only if React Query is enabled)
130
- if (reactQueryEnabled) {
131
- const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
132
- const prefetchParams = generatePrefetchParameters(operation, variablesTypeName);
133
- const prefetchBody = generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName);
134
- const prefetchDoc = generatePrefetchDoc(operation, prefetchFnName);
135
- sourceFile.addFunction({
136
- name: prefetchFnName,
137
- isExported: true,
138
- isAsync: true,
139
- parameters: prefetchParams,
140
- returnType: 'Promise<void>',
141
- statements: prefetchBody,
142
- docs: [{ description: prefetchDoc }],
143
- });
144
- }
145
- return {
146
- fileName,
147
- content: (0, ts_ast_1.getFormattedOutput)(sourceFile),
148
- operationName: operation.name,
149
- };
150
- }
151
- // ============================================================================
152
- // Helper functions
153
- // ============================================================================
154
- /**
155
- * Generate interface properties from CleanArguments
156
- */
157
- function generateVariablesProperties(args, tracker) {
158
- return args.map((arg) => ({
159
- name: arg.name,
160
- type: (0, type_resolver_1.typeRefToTsType)(arg.type, tracker),
161
- optional: !(0, type_resolver_1.isTypeRequired)(arg.type),
162
- docs: arg.description ? [arg.description] : undefined,
163
- }));
164
- }
165
- /**
166
- * Generate hook function parameters
167
- */
168
- function generateHookParameters(operation, variablesTypeName, resultTypeName) {
169
- const params = [];
170
- // Add variables parameter if there are required args
171
- const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
172
- if (operation.args.length > 0) {
173
- params.push({
174
- name: 'variables',
175
- type: variablesTypeName,
176
- hasQuestionToken: !hasRequiredArgs,
177
- });
178
- }
179
- // Add options parameter
180
- params.push({
181
- name: 'options',
182
- type: `Omit<UseQueryOptions<${resultTypeName}, Error>, 'queryKey' | 'queryFn'>`,
183
- hasQuestionToken: true,
184
- });
185
- return params;
186
- }
187
- /**
188
- * Generate hook function body
189
- */
190
- function generateHookBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName) {
191
198
  const hasArgs = operation.args.length > 0;
192
199
  const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
200
+ const fetchBodyStatements = [];
193
201
  if (hasArgs) {
194
- // With variables
195
- const enabledCondition = hasRequiredArgs
196
- ? `enabled: !!variables && (options?.enabled !== false),`
197
- : '';
198
- return `return useQuery({
199
- queryKey: ${queryKeyName}(variables),
200
- queryFn: () => execute<${resultTypeName}, ${variablesTypeName}>(
201
- ${documentConstName},
202
- variables
203
- ),
204
- ${enabledCondition}
205
- ...options,
206
- });`;
202
+ fetchBodyStatements.push(t.returnStatement((0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
203
+ t.tsTypeReference(t.identifier(resultTypeName)),
204
+ t.tsTypeReference(t.identifier(variablesTypeName)),
205
+ ])));
207
206
  }
208
207
  else {
209
- // No variables
210
- return `return useQuery({
211
- queryKey: ${queryKeyName}(),
212
- queryFn: () => execute<${resultTypeName}>(${documentConstName}),
213
- ...options,
214
- });`;
208
+ fetchBodyStatements.push(t.returnStatement((0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))])));
215
209
  }
216
- }
217
- /**
218
- * Generate hook JSDoc documentation
219
- */
220
- function generateHookDoc(operation, hookName) {
221
- const description = operation.description
222
- ? operation.description
223
- : `Query hook for ${operation.name}`;
224
- const hasArgs = operation.args.length > 0;
225
- let example;
210
+ const fetchParams = [];
226
211
  if (hasArgs) {
227
- const argNames = operation.args.map((a) => a.name).join(', ');
228
- example = `
229
- @example
230
- \`\`\`tsx
231
- const { data, isLoading } = ${hookName}({ ${argNames} });
232
-
233
- if (data?.${operation.name}) {
234
- console.log(data.${operation.name});
235
- }
236
- \`\`\``;
237
- }
238
- else {
239
- example = `
240
- @example
241
- \`\`\`tsx
242
- const { data, isLoading } = ${hookName}();
243
-
244
- if (data?.${operation.name}) {
245
- console.log(data.${operation.name});
246
- }
247
- \`\`\``;
212
+ fetchParams.push((0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
248
213
  }
249
- return description + '\n' + example;
250
- }
251
- // ============================================================================
252
- // Standalone function generators
253
- // ============================================================================
254
- /**
255
- * Generate fetch function parameters
256
- */
257
- function generateFetchParameters(operation, variablesTypeName) {
258
- const params = [];
259
- if (operation.args.length > 0) {
260
- const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
261
- params.push({
262
- name: 'variables',
263
- type: variablesTypeName,
264
- hasQuestionToken: !hasRequiredArgs,
265
- });
266
- }
267
- params.push({
268
- name: 'options',
269
- type: 'ExecuteOptions',
270
- hasQuestionToken: true,
271
- });
272
- return params;
273
- }
274
- /**
275
- * Generate fetch function body
276
- */
277
- function generateFetchBody(operation, documentConstName, variablesTypeName, resultTypeName) {
278
- if (operation.args.length > 0) {
279
- return `return execute<${resultTypeName}, ${variablesTypeName}>(
280
- ${documentConstName},
281
- variables,
282
- options
283
- );`;
284
- }
285
- else {
286
- return `return execute<${resultTypeName}>(${documentConstName}, undefined, options);`;
287
- }
288
- }
289
- /**
290
- * Generate fetch function documentation
291
- */
292
- function generateFetchDoc(operation, fnName) {
293
- const description = `Fetch ${operation.name} without React hooks`;
294
- if (operation.args.length > 0) {
295
- const argNames = operation.args.map((a) => a.name).join(', ');
296
- return `${description}
297
-
298
- @example
299
- \`\`\`ts
300
- const data = await ${fnName}({ ${argNames} });
301
- \`\`\``;
302
- }
303
- else {
304
- return `${description}
305
-
306
- @example
307
- \`\`\`ts
308
- const data = await ${fnName}();
309
- \`\`\``;
310
- }
311
- }
312
- /**
313
- * Generate prefetch function parameters
314
- */
315
- function generatePrefetchParameters(operation, variablesTypeName) {
316
- const params = [
317
- { name: 'queryClient', type: 'QueryClient' },
318
- ];
319
- if (operation.args.length > 0) {
320
- const hasRequiredArgs = operation.args.some((arg) => (0, type_resolver_1.isTypeRequired)(arg.type));
321
- params.push({
322
- name: 'variables',
323
- type: variablesTypeName,
324
- hasQuestionToken: !hasRequiredArgs,
325
- });
326
- }
327
- params.push({
328
- name: 'options',
329
- type: 'ExecuteOptions',
330
- hasQuestionToken: true,
331
- });
332
- return params;
333
- }
334
- /**
335
- * Generate prefetch function body
336
- */
337
- function generatePrefetchBody(operation, documentConstName, queryKeyName, variablesTypeName, resultTypeName) {
338
- if (operation.args.length > 0) {
339
- return `await queryClient.prefetchQuery({
340
- queryKey: ${queryKeyName}(variables),
341
- queryFn: () => execute<${resultTypeName}, ${variablesTypeName}>(
342
- ${documentConstName},
343
- variables,
344
- options
345
- ),
346
- });`;
347
- }
348
- else {
349
- return `await queryClient.prefetchQuery({
350
- queryKey: ${queryKeyName}(),
351
- queryFn: () => execute<${resultTypeName}>(${documentConstName}, undefined, options),
352
- });`;
353
- }
354
- }
355
- /**
356
- * Generate prefetch function documentation
357
- */
358
- function generatePrefetchDoc(operation, fnName) {
359
- const description = `Prefetch ${operation.name} for SSR or cache warming`;
360
- if (operation.args.length > 0) {
361
- const argNames = operation.args.map((a) => a.name).join(', ');
362
- return `${description}
363
-
364
- @example
365
- \`\`\`ts
366
- await ${fnName}(queryClient, { ${argNames} });
367
- \`\`\``;
368
- }
369
- else {
370
- return `${description}
371
-
372
- @example
373
- \`\`\`ts
374
- await ${fnName}(queryClient);
375
- \`\`\``;
214
+ fetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
215
+ const fetchFunc = t.functionDeclaration(t.identifier(fetchFnName), fetchParams, t.blockStatement(fetchBodyStatements));
216
+ fetchFunc.async = true;
217
+ fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsTypeReference(t.identifier(resultTypeName))])));
218
+ const fetchExport = t.exportNamedDeclaration(fetchFunc);
219
+ const argNames = operation.args.map((a) => a.name).join(', ');
220
+ const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${argNames} })` : `${fetchFnName}()`;
221
+ (0, babel_ast_1.addJSDocComment)(fetchExport, [
222
+ `Fetch ${operation.name} without React hooks`,
223
+ '',
224
+ '@example',
225
+ '```ts',
226
+ `const data = await ${fetchExampleCall};`,
227
+ '```',
228
+ ]);
229
+ statements.push(fetchExport);
230
+ if (reactQueryEnabled) {
231
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
232
+ const prefetchBodyStatements = [];
233
+ const prefetchQueryOptions = [];
234
+ if (hasArgs) {
235
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
236
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('variables'), t.identifier('options')], [
237
+ t.tsTypeReference(t.identifier(resultTypeName)),
238
+ t.tsTypeReference(t.identifier(variablesTypeName)),
239
+ ]))));
240
+ }
241
+ else {
242
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
243
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], (0, babel_ast_1.createTypedCallExpression)(t.identifier('execute'), [t.identifier(documentConstName), t.identifier('undefined'), t.identifier('options')], [t.tsTypeReference(t.identifier(resultTypeName))]))));
244
+ }
245
+ prefetchBodyStatements.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [t.objectExpression(prefetchQueryOptions)]))));
246
+ const prefetchParams = [
247
+ (0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
248
+ ];
249
+ if (hasArgs) {
250
+ prefetchParams.push((0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
251
+ }
252
+ prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
253
+ const prefetchFunc = t.functionDeclaration(t.identifier(prefetchFnName), prefetchParams, t.blockStatement(prefetchBodyStatements));
254
+ prefetchFunc.async = true;
255
+ prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
256
+ const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
257
+ const prefetchExampleCall = hasArgs
258
+ ? `${prefetchFnName}(queryClient, { ${argNames} })`
259
+ : `${prefetchFnName}(queryClient)`;
260
+ (0, babel_ast_1.addJSDocComment)(prefetchExport, [
261
+ `Prefetch ${operation.name} for SSR or cache warming`,
262
+ '',
263
+ '@example',
264
+ '```ts',
265
+ `await ${prefetchExampleCall};`,
266
+ '```',
267
+ ]);
268
+ statements.push(prefetchExport);
376
269
  }
270
+ const code = (0, babel_ast_1.generateCode)(statements);
271
+ const headerText = reactQueryEnabled
272
+ ? `Custom query hook for ${operation.name}`
273
+ : `Custom query functions for ${operation.name}`;
274
+ const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
275
+ return {
276
+ fileName,
277
+ content,
278
+ operationName: operation.name,
279
+ };
377
280
  }
378
- /**
379
- * Generate all custom query hook files
380
- */
381
281
  function generateAllCustomQueryHooks(options) {
382
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
282
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
383
283
  return operations
384
284
  .filter((op) => op.kind === 'query')
385
285
  .map((operation) => generateCustomQueryHook({
@@ -389,5 +289,6 @@ function generateAllCustomQueryHooks(options) {
389
289
  skipQueryField,
390
290
  reactQueryEnabled,
391
291
  tableTypeNames,
292
+ useCentralizedKeys,
392
293
  }));
393
294
  }