@constructive-io/graphql-codegen 2.23.2 → 2.24.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 (90) hide show
  1. package/README.md +147 -2
  2. package/cli/codegen/babel-ast.d.ts +46 -0
  3. package/cli/codegen/babel-ast.js +145 -0
  4. package/cli/codegen/barrel.d.ts +7 -2
  5. package/cli/codegen/barrel.js +159 -97
  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 +246 -335
  11. package/cli/codegen/index.d.ts +3 -0
  12. package/cli/codegen/index.js +72 -3
  13. package/cli/codegen/invalidation.d.ts +20 -0
  14. package/cli/codegen/invalidation.js +327 -0
  15. package/cli/codegen/mutation-keys.d.ts +24 -0
  16. package/cli/codegen/mutation-keys.js +247 -0
  17. package/cli/codegen/mutations.d.ts +3 -19
  18. package/cli/codegen/mutations.js +372 -383
  19. package/cli/codegen/orm/barrel.d.ts +1 -1
  20. package/cli/codegen/orm/barrel.js +42 -10
  21. package/cli/codegen/orm/client-generator.d.ts +1 -19
  22. package/cli/codegen/orm/client-generator.js +108 -77
  23. package/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  24. package/cli/codegen/orm/custom-ops-generator.js +192 -235
  25. package/cli/codegen/orm/input-types-generator.d.ts +13 -1
  26. package/cli/codegen/orm/input-types-generator.js +403 -147
  27. package/cli/codegen/orm/model-generator.d.ts +1 -19
  28. package/cli/codegen/orm/model-generator.js +229 -234
  29. package/cli/codegen/queries.d.ts +3 -11
  30. package/cli/codegen/queries.js +582 -389
  31. package/cli/codegen/query-keys.d.ts +15 -0
  32. package/cli/codegen/query-keys.js +477 -0
  33. package/cli/codegen/scalars.js +1 -0
  34. package/cli/codegen/schema-types-generator.d.ts +15 -10
  35. package/cli/codegen/schema-types-generator.js +87 -175
  36. package/cli/codegen/type-resolver.d.ts +1 -30
  37. package/cli/codegen/type-resolver.js +0 -53
  38. package/cli/codegen/types.d.ts +1 -1
  39. package/cli/codegen/types.js +76 -21
  40. package/cli/commands/generate.js +1 -0
  41. package/cli/index.js +1 -0
  42. package/esm/cli/codegen/babel-ast.d.ts +46 -0
  43. package/esm/cli/codegen/babel-ast.js +97 -0
  44. package/esm/cli/codegen/barrel.d.ts +7 -2
  45. package/esm/cli/codegen/barrel.js +126 -97
  46. package/esm/cli/codegen/client.js +61 -0
  47. package/esm/cli/codegen/custom-mutations.d.ts +2 -12
  48. package/esm/cli/codegen/custom-mutations.js +83 -124
  49. package/esm/cli/codegen/custom-queries.d.ts +2 -10
  50. package/esm/cli/codegen/custom-queries.js +214 -336
  51. package/esm/cli/codegen/index.d.ts +3 -0
  52. package/esm/cli/codegen/index.js +68 -2
  53. package/esm/cli/codegen/invalidation.d.ts +20 -0
  54. package/esm/cli/codegen/invalidation.js +291 -0
  55. package/esm/cli/codegen/mutation-keys.d.ts +24 -0
  56. package/esm/cli/codegen/mutation-keys.js +211 -0
  57. package/esm/cli/codegen/mutations.d.ts +3 -19
  58. package/esm/cli/codegen/mutations.js +340 -384
  59. package/esm/cli/codegen/orm/barrel.d.ts +1 -1
  60. package/esm/cli/codegen/orm/barrel.js +10 -11
  61. package/esm/cli/codegen/orm/client-generator.d.ts +1 -19
  62. package/esm/cli/codegen/orm/client-generator.js +76 -78
  63. package/esm/cli/codegen/orm/custom-ops-generator.d.ts +1 -12
  64. package/esm/cli/codegen/orm/custom-ops-generator.js +160 -236
  65. package/esm/cli/codegen/orm/input-types-generator.d.ts +13 -1
  66. package/esm/cli/codegen/orm/input-types-generator.js +371 -148
  67. package/esm/cli/codegen/orm/model-generator.d.ts +1 -19
  68. package/esm/cli/codegen/orm/model-generator.js +197 -235
  69. package/esm/cli/codegen/queries.d.ts +3 -11
  70. package/esm/cli/codegen/queries.js +550 -390
  71. package/esm/cli/codegen/query-keys.d.ts +15 -0
  72. package/esm/cli/codegen/query-keys.js +441 -0
  73. package/esm/cli/codegen/scalars.js +1 -0
  74. package/esm/cli/codegen/schema-types-generator.d.ts +15 -10
  75. package/esm/cli/codegen/schema-types-generator.js +54 -175
  76. package/esm/cli/codegen/type-resolver.d.ts +1 -30
  77. package/esm/cli/codegen/type-resolver.js +0 -49
  78. package/esm/cli/codegen/types.d.ts +1 -1
  79. package/esm/cli/codegen/types.js +44 -22
  80. package/esm/cli/commands/generate.js +1 -0
  81. package/esm/cli/index.js +1 -0
  82. package/esm/types/config.d.ts +75 -0
  83. package/esm/types/config.js +19 -1
  84. package/package.json +6 -4
  85. package/types/config.d.ts +75 -0
  86. package/types/config.js +20 -2
  87. package/cli/codegen/ts-ast.d.ts +0 -124
  88. package/cli/codegen/ts-ast.js +0 -280
  89. package/esm/cli/codegen/ts-ast.d.ts +0 -124
  90. package/esm/cli/codegen/ts-ast.js +0 -260
@@ -1,385 +1,295 @@
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([], t.callExpression(t.identifier('execute'), [
156
+ t.identifier(documentConstName),
157
+ t.identifier('variables'),
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([], t.callExpression(t.identifier('execute'), [t.identifier(documentConstName)]))));
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(t.callExpression(t.identifier('execute'), [
203
+ t.identifier(documentConstName),
204
+ t.identifier('variables'),
205
+ t.identifier('options'),
206
+ ])));
207
207
  }
208
208
  else {
209
- // No variables
210
- return `return useQuery({
211
- queryKey: ${queryKeyName}(),
212
- queryFn: () => execute<${resultTypeName}>(${documentConstName}),
213
- ...options,
214
- });`;
209
+ fetchBodyStatements.push(t.returnStatement(t.callExpression(t.identifier('execute'), [
210
+ t.identifier(documentConstName),
211
+ t.identifier('undefined'),
212
+ t.identifier('options'),
213
+ ])));
215
214
  }
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;
215
+ const fetchParams = [];
226
216
  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
- \`\`\``;
217
+ fetchParams.push((0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
248
218
  }
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
- \`\`\``;
219
+ fetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
220
+ const fetchFunc = t.functionDeclaration(t.identifier(fetchFnName), fetchParams, t.blockStatement(fetchBodyStatements));
221
+ fetchFunc.async = true;
222
+ fetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsTypeReference(t.identifier(resultTypeName))])));
223
+ const fetchExport = t.exportNamedDeclaration(fetchFunc);
224
+ const argNames = operation.args.map((a) => a.name).join(', ');
225
+ const fetchExampleCall = hasArgs ? `${fetchFnName}({ ${argNames} })` : `${fetchFnName}()`;
226
+ (0, babel_ast_1.addJSDocComment)(fetchExport, [
227
+ `Fetch ${operation.name} without React hooks`,
228
+ '',
229
+ '@example',
230
+ '```ts',
231
+ `const data = await ${fetchExampleCall};`,
232
+ '```',
233
+ ]);
234
+ statements.push(fetchExport);
235
+ if (reactQueryEnabled) {
236
+ const prefetchFnName = `prefetch${(0, utils_1.ucFirst)(operation.name)}Query`;
237
+ const prefetchBodyStatements = [];
238
+ const prefetchQueryOptions = [];
239
+ if (hasArgs) {
240
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [t.identifier('variables')])));
241
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
242
+ t.identifier(documentConstName),
243
+ t.identifier('variables'),
244
+ t.identifier('options'),
245
+ ]))));
246
+ }
247
+ else {
248
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryKey'), t.callExpression(t.identifier(queryKeyName), [])));
249
+ prefetchQueryOptions.push(t.objectProperty(t.identifier('queryFn'), t.arrowFunctionExpression([], t.callExpression(t.identifier('execute'), [
250
+ t.identifier(documentConstName),
251
+ t.identifier('undefined'),
252
+ t.identifier('options'),
253
+ ]))));
254
+ }
255
+ prefetchBodyStatements.push(t.expressionStatement(t.awaitExpression(t.callExpression(t.memberExpression(t.identifier('queryClient'), t.identifier('prefetchQuery')), [t.objectExpression(prefetchQueryOptions)]))));
256
+ const prefetchParams = [
257
+ (0, babel_ast_1.typedParam)('queryClient', t.tsTypeReference(t.identifier('QueryClient'))),
258
+ ];
259
+ if (hasArgs) {
260
+ prefetchParams.push((0, babel_ast_1.typedParam)('variables', t.tsTypeReference(t.identifier(variablesTypeName)), !hasRequiredArgs));
261
+ }
262
+ prefetchParams.push((0, babel_ast_1.typedParam)('options', t.tsTypeReference(t.identifier('ExecuteOptions')), true));
263
+ const prefetchFunc = t.functionDeclaration(t.identifier(prefetchFnName), prefetchParams, t.blockStatement(prefetchBodyStatements));
264
+ prefetchFunc.async = true;
265
+ prefetchFunc.returnType = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Promise'), t.tsTypeParameterInstantiation([t.tsVoidKeyword()])));
266
+ const prefetchExport = t.exportNamedDeclaration(prefetchFunc);
267
+ const prefetchExampleCall = hasArgs
268
+ ? `${prefetchFnName}(queryClient, { ${argNames} })`
269
+ : `${prefetchFnName}(queryClient)`;
270
+ (0, babel_ast_1.addJSDocComment)(prefetchExport, [
271
+ `Prefetch ${operation.name} for SSR or cache warming`,
272
+ '',
273
+ '@example',
274
+ '```ts',
275
+ `await ${prefetchExampleCall};`,
276
+ '```',
277
+ ]);
278
+ statements.push(prefetchExport);
376
279
  }
280
+ const code = (0, babel_ast_1.generateCode)(statements);
281
+ const headerText = reactQueryEnabled
282
+ ? `Custom query hook for ${operation.name}`
283
+ : `Custom query functions for ${operation.name}`;
284
+ const content = (0, utils_1.getGeneratedFileHeader)(headerText) + '\n\n' + code;
285
+ return {
286
+ fileName,
287
+ content,
288
+ operationName: operation.name,
289
+ };
377
290
  }
378
- /**
379
- * Generate all custom query hook files
380
- */
381
291
  function generateAllCustomQueryHooks(options) {
382
- const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames } = options;
292
+ const { operations, typeRegistry, maxDepth = 2, skipQueryField = true, reactQueryEnabled = true, tableTypeNames, useCentralizedKeys = true, } = options;
383
293
  return operations
384
294
  .filter((op) => op.kind === 'query')
385
295
  .map((operation) => generateCustomQueryHook({
@@ -389,5 +299,6 @@ function generateAllCustomQueryHooks(options) {
389
299
  skipQueryField,
390
300
  reactQueryEnabled,
391
301
  tableTypeNames,
302
+ useCentralizedKeys,
392
303
  }));
393
304
  }
@@ -69,3 +69,6 @@ export { generateAllMutationHooks, generateCreateMutationHook, generateUpdateMut
69
69
  export { generateAllCustomQueryHooks, generateCustomQueryHook, } from './custom-queries';
70
70
  export { generateAllCustomMutationHooks, generateCustomMutationHook, } from './custom-mutations';
71
71
  export { generateQueriesBarrel, generateMutationsBarrel, generateMainBarrel, generateCustomQueriesBarrel, generateCustomMutationsBarrel, } from './barrel';
72
+ export { generateQueryKeysFile } from './query-keys';
73
+ export { generateMutationKeysFile } from './mutation-keys';
74
+ export { generateInvalidationFile } from './invalidation';