@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,5 +1,6 @@
1
- import { createProject, createSourceFile, getFormattedOutput, createFileHeader, createImport, } from '../ts-ast';
2
- import { ucFirst } from '../utils';
1
+ import * as t from '@babel/types';
2
+ import { generateCode } from '../babel-ast';
3
+ import { ucFirst, getGeneratedFileHeader } from '../utils';
3
4
  import { typeRefToTsType, isTypeRequired, getTypeBaseName, } from '../type-resolver';
4
5
  import { SCALAR_NAMES } from '../scalars';
5
6
  /**
@@ -61,274 +62,197 @@ function getSelectTypeName(returnType) {
61
62
  }
62
63
  return null;
63
64
  }
65
+ function createImportDeclaration(moduleSpecifier, namedImports, typeOnly = false) {
66
+ const specifiers = namedImports.map((name) => t.importSpecifier(t.identifier(name), t.identifier(name)));
67
+ const decl = t.importDeclaration(specifiers, t.stringLiteral(moduleSpecifier));
68
+ decl.importKind = typeOnly ? 'type' : 'value';
69
+ return decl;
70
+ }
71
+ function createVariablesInterface(op) {
72
+ if (op.args.length === 0)
73
+ return null;
74
+ const varTypeName = `${ucFirst(op.name)}Variables`;
75
+ const props = op.args.map((arg) => {
76
+ const optional = !isTypeRequired(arg.type);
77
+ const prop = t.tsPropertySignature(t.identifier(arg.name), t.tsTypeAnnotation(parseTypeAnnotation(typeRefToTsType(arg.type))));
78
+ prop.optional = optional;
79
+ return prop;
80
+ });
81
+ const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(varTypeName), null, null, t.tsInterfaceBody(props));
82
+ return t.exportNamedDeclaration(interfaceDecl);
83
+ }
84
+ function parseTypeAnnotation(typeStr) {
85
+ if (typeStr === 'string')
86
+ return t.tsStringKeyword();
87
+ if (typeStr === 'number')
88
+ return t.tsNumberKeyword();
89
+ if (typeStr === 'boolean')
90
+ return t.tsBooleanKeyword();
91
+ if (typeStr === 'null')
92
+ return t.tsNullKeyword();
93
+ if (typeStr === 'undefined')
94
+ return t.tsUndefinedKeyword();
95
+ if (typeStr === 'unknown')
96
+ return t.tsUnknownKeyword();
97
+ if (typeStr.includes(' | ')) {
98
+ const parts = typeStr.split(' | ').map((p) => parseTypeAnnotation(p.trim()));
99
+ return t.tsUnionType(parts);
100
+ }
101
+ if (typeStr.endsWith('[]')) {
102
+ return t.tsArrayType(parseTypeAnnotation(typeStr.slice(0, -2)));
103
+ }
104
+ return t.tsTypeReference(t.identifier(typeStr));
105
+ }
106
+ function buildOperationMethod(op, operationType) {
107
+ const hasArgs = op.args.length > 0;
108
+ const varTypeName = `${ucFirst(op.name)}Variables`;
109
+ const varDefs = op.args.map((arg) => ({
110
+ name: arg.name,
111
+ type: formatGraphQLType(arg.type),
112
+ }));
113
+ const selectTypeName = getSelectTypeName(op.returnType);
114
+ const payloadTypeName = getTypeBaseName(op.returnType);
115
+ // Build the arrow function parameters
116
+ const params = [];
117
+ if (hasArgs) {
118
+ const argsParam = t.identifier('args');
119
+ argsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier(varTypeName)));
120
+ params.push(argsParam);
121
+ }
122
+ const optionsParam = t.identifier('options');
123
+ optionsParam.optional = true;
124
+ if (selectTypeName) {
125
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
126
+ (() => {
127
+ const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('S'))));
128
+ prop.optional = true;
129
+ return prop;
130
+ })(),
131
+ ]));
132
+ }
133
+ else {
134
+ optionsParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeLiteral([
135
+ (() => {
136
+ const prop = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('Record'), t.tsTypeParameterInstantiation([t.tsStringKeyword(), t.tsUnknownKeyword()]))));
137
+ prop.optional = true;
138
+ return prop;
139
+ })(),
140
+ ]));
141
+ }
142
+ params.push(optionsParam);
143
+ // Build the QueryBuilder call
144
+ const queryBuilderArgs = t.objectExpression([
145
+ t.objectProperty(t.identifier('client'), t.identifier('client'), false, true),
146
+ t.objectProperty(t.identifier('operation'), t.stringLiteral(operationType)),
147
+ t.objectProperty(t.identifier('operationName'), t.stringLiteral(ucFirst(op.name))),
148
+ t.objectProperty(t.identifier('fieldName'), t.stringLiteral(op.name)),
149
+ t.spreadElement(t.callExpression(t.identifier('buildCustomDocument'), [
150
+ t.stringLiteral(operationType),
151
+ t.stringLiteral(ucFirst(op.name)),
152
+ t.stringLiteral(op.name),
153
+ t.optionalMemberExpression(t.identifier('options'), t.identifier('select'), false, true),
154
+ hasArgs ? t.identifier('args') : t.identifier('undefined'),
155
+ t.arrayExpression(varDefs.map((v) => t.objectExpression([
156
+ t.objectProperty(t.identifier('name'), t.stringLiteral(v.name)),
157
+ t.objectProperty(t.identifier('type'), t.stringLiteral(v.type)),
158
+ ]))),
159
+ ])),
160
+ ]);
161
+ const newExpr = t.newExpression(t.identifier('QueryBuilder'), [queryBuilderArgs]);
162
+ // Add type parameter if we have a select type
163
+ if (selectTypeName && payloadTypeName) {
164
+ newExpr.typeParameters = t.tsTypeParameterInstantiation([
165
+ t.tsTypeLiteral([
166
+ t.tsPropertySignature(t.identifier(op.name), t.tsTypeAnnotation(t.tsTypeReference(t.identifier('InferSelectResult'), t.tsTypeParameterInstantiation([
167
+ t.tsTypeReference(t.identifier(payloadTypeName)),
168
+ t.tsTypeReference(t.identifier('S')),
169
+ ])))),
170
+ ]),
171
+ ]);
172
+ }
173
+ const arrowFunc = t.arrowFunctionExpression(params, newExpr);
174
+ // Add type parameters to arrow function if we have a select type
175
+ if (selectTypeName) {
176
+ const typeParam = t.tsTypeParameter(t.tsTypeReference(t.identifier(selectTypeName)), null, 'S');
177
+ typeParam.const = true;
178
+ arrowFunc.typeParameters = t.tsTypeParameterDeclaration([typeParam]);
179
+ }
180
+ return t.objectProperty(t.identifier(op.name), arrowFunc);
181
+ }
64
182
  /**
65
183
  * Generate the query/index.ts file for custom query operations
66
184
  */
67
185
  export function generateCustomQueryOpsFile(operations) {
68
- const project = createProject();
69
- const sourceFile = createSourceFile(project, 'index.ts');
186
+ const statements = [];
70
187
  // Collect all input type names and payload type names
71
188
  const inputTypeNames = collectInputTypeNamesFromOps(operations);
72
189
  const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
73
- // Generate Select type names for payloads
74
190
  const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
75
- // Combine all type imports
76
- const allTypeImports = [
77
- ...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
78
- ];
79
- // Add file header
80
- sourceFile.insertText(0, createFileHeader('Custom query operations') + '\n\n');
191
+ const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
81
192
  // Add imports
82
- sourceFile.addImportDeclarations([
83
- createImport({
84
- moduleSpecifier: '../client',
85
- namedImports: ['OrmClient'],
86
- }),
87
- createImport({
88
- moduleSpecifier: '../query-builder',
89
- namedImports: ['QueryBuilder', 'buildCustomDocument'],
90
- }),
91
- createImport({
92
- moduleSpecifier: '../select-types',
93
- typeOnlyNamedImports: ['InferSelectResult'],
94
- }),
95
- ]);
96
- // Import types from input-types if we have any
193
+ statements.push(createImportDeclaration('../client', ['OrmClient']));
194
+ statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument']));
195
+ statements.push(createImportDeclaration('../select-types', ['InferSelectResult'], true));
97
196
  if (allTypeImports.length > 0) {
98
- sourceFile.addImportDeclarations([
99
- createImport({
100
- moduleSpecifier: '../input-types',
101
- typeOnlyNamedImports: allTypeImports,
102
- }),
103
- ]);
197
+ statements.push(createImportDeclaration('../input-types', allTypeImports, true));
104
198
  }
105
- // Generate variable definitions type for each operation
106
- sourceFile.addStatements('\n// ============================================================================');
107
- sourceFile.addStatements('// Variable Types');
108
- sourceFile.addStatements('// ============================================================================\n');
199
+ // Generate variable interfaces
109
200
  for (const op of operations) {
110
- if (op.args.length > 0) {
111
- const varTypeName = `${ucFirst(op.name)}Variables`;
112
- const props = op.args.map((arg) => {
113
- const optional = !isTypeRequired(arg.type);
114
- return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
115
- });
116
- sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
117
- }
201
+ const varInterface = createVariablesInterface(op);
202
+ if (varInterface)
203
+ statements.push(varInterface);
118
204
  }
119
205
  // Generate factory function
120
- sourceFile.addStatements('\n// ============================================================================');
121
- sourceFile.addStatements('// Query Operations Factory');
122
- sourceFile.addStatements('// ============================================================================\n');
123
- // Build the operations object
124
- const operationMethods = operations.map((op) => {
125
- const hasArgs = op.args.length > 0;
126
- const varTypeName = `${ucFirst(op.name)}Variables`;
127
- const varDefs = op.args.map((arg) => ({
128
- name: arg.name,
129
- type: formatGraphQLType(arg.type),
130
- }));
131
- const varDefsJson = JSON.stringify(varDefs);
132
- // Get Select type for return type
133
- const selectTypeName = getSelectTypeName(op.returnType);
134
- const payloadTypeName = getTypeBaseName(op.returnType);
135
- // Use typed select if available, otherwise fall back to Record<string, unknown>
136
- const selectType = selectTypeName ?? 'Record<string, unknown>';
137
- const returnTypePart = selectTypeName && payloadTypeName
138
- ? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
139
- : 'unknown';
140
- if (hasArgs) {
141
- if (selectTypeName) {
142
- return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
143
- new QueryBuilder<${returnTypePart}>({
144
- client,
145
- operation: 'query',
146
- operationName: '${ucFirst(op.name)}',
147
- fieldName: '${op.name}',
148
- ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
149
- })`;
150
- }
151
- else {
152
- return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
153
- new QueryBuilder({
154
- client,
155
- operation: 'query',
156
- operationName: '${ucFirst(op.name)}',
157
- fieldName: '${op.name}',
158
- ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
159
- })`;
160
- }
161
- }
162
- else {
163
- // No args - still provide typed select
164
- if (selectTypeName) {
165
- return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
166
- new QueryBuilder<${returnTypePart}>({
167
- client,
168
- operation: 'query',
169
- operationName: '${ucFirst(op.name)}',
170
- fieldName: '${op.name}',
171
- ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
172
- })`;
173
- }
174
- else {
175
- return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
176
- new QueryBuilder({
177
- client,
178
- operation: 'query',
179
- operationName: '${ucFirst(op.name)}',
180
- fieldName: '${op.name}',
181
- ...buildCustomDocument('query', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
182
- })`;
183
- }
184
- }
185
- });
186
- sourceFile.addFunction({
187
- name: 'createQueryOperations',
188
- isExported: true,
189
- parameters: [{ name: 'client', type: 'OrmClient' }],
190
- statements: `return {
191
- ${operationMethods.join(',\n ')},
192
- };`,
193
- });
206
+ const operationProperties = operations.map((op) => buildOperationMethod(op, 'query'));
207
+ const returnObj = t.objectExpression(operationProperties);
208
+ const returnStmt = t.returnStatement(returnObj);
209
+ const clientParam = t.identifier('client');
210
+ clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient')));
211
+ const factoryFunc = t.functionDeclaration(t.identifier('createQueryOperations'), [clientParam], t.blockStatement([returnStmt]));
212
+ statements.push(t.exportNamedDeclaration(factoryFunc));
213
+ const header = getGeneratedFileHeader('Custom query operations');
214
+ const code = generateCode(statements);
194
215
  return {
195
216
  fileName: 'query/index.ts',
196
- content: getFormattedOutput(sourceFile),
217
+ content: header + '\n' + code,
197
218
  };
198
219
  }
199
220
  /**
200
221
  * Generate the mutation/index.ts file for custom mutation operations
201
222
  */
202
223
  export function generateCustomMutationOpsFile(operations) {
203
- const project = createProject();
204
- const sourceFile = createSourceFile(project, 'index.ts');
224
+ const statements = [];
205
225
  // Collect all input type names and payload type names
206
226
  const inputTypeNames = collectInputTypeNamesFromOps(operations);
207
227
  const payloadTypeNames = collectPayloadTypeNamesFromOps(operations);
208
- // Generate Select type names for payloads
209
228
  const selectTypeNames = payloadTypeNames.map((p) => `${p}Select`);
210
- // Combine all type imports
211
- const allTypeImports = [
212
- ...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames]),
213
- ];
214
- // Add file header
215
- sourceFile.insertText(0, createFileHeader('Custom mutation operations') + '\n\n');
229
+ const allTypeImports = [...new Set([...inputTypeNames, ...payloadTypeNames, ...selectTypeNames])];
216
230
  // Add imports
217
- sourceFile.addImportDeclarations([
218
- createImport({
219
- moduleSpecifier: '../client',
220
- namedImports: ['OrmClient'],
221
- }),
222
- createImport({
223
- moduleSpecifier: '../query-builder',
224
- namedImports: ['QueryBuilder', 'buildCustomDocument'],
225
- }),
226
- createImport({
227
- moduleSpecifier: '../select-types',
228
- typeOnlyNamedImports: ['InferSelectResult'],
229
- }),
230
- ]);
231
- // Import types from input-types if we have any
231
+ statements.push(createImportDeclaration('../client', ['OrmClient']));
232
+ statements.push(createImportDeclaration('../query-builder', ['QueryBuilder', 'buildCustomDocument']));
233
+ statements.push(createImportDeclaration('../select-types', ['InferSelectResult'], true));
232
234
  if (allTypeImports.length > 0) {
233
- sourceFile.addImportDeclarations([
234
- createImport({
235
- moduleSpecifier: '../input-types',
236
- typeOnlyNamedImports: allTypeImports,
237
- }),
238
- ]);
235
+ statements.push(createImportDeclaration('../input-types', allTypeImports, true));
239
236
  }
240
- // Generate variable definitions type for each operation
241
- sourceFile.addStatements('\n// ============================================================================');
242
- sourceFile.addStatements('// Variable Types');
243
- sourceFile.addStatements('// ============================================================================\n');
237
+ // Generate variable interfaces
244
238
  for (const op of operations) {
245
- if (op.args.length > 0) {
246
- const varTypeName = `${ucFirst(op.name)}Variables`;
247
- const props = op.args.map((arg) => {
248
- const optional = !isTypeRequired(arg.type);
249
- return `${arg.name}${optional ? '?' : ''}: ${typeRefToTsType(arg.type)};`;
250
- });
251
- sourceFile.addStatements(`export interface ${varTypeName} {\n ${props.join('\n ')}\n}\n`);
252
- }
239
+ const varInterface = createVariablesInterface(op);
240
+ if (varInterface)
241
+ statements.push(varInterface);
253
242
  }
254
243
  // Generate factory function
255
- sourceFile.addStatements('\n// ============================================================================');
256
- sourceFile.addStatements('// Mutation Operations Factory');
257
- sourceFile.addStatements('// ============================================================================\n');
258
- // Build the operations object
259
- const operationMethods = operations.map((op) => {
260
- const hasArgs = op.args.length > 0;
261
- const varTypeName = `${ucFirst(op.name)}Variables`;
262
- const varDefs = op.args.map((arg) => ({
263
- name: arg.name,
264
- type: formatGraphQLType(arg.type),
265
- }));
266
- const varDefsJson = JSON.stringify(varDefs);
267
- // Get Select type for return type
268
- const selectTypeName = getSelectTypeName(op.returnType);
269
- const payloadTypeName = getTypeBaseName(op.returnType);
270
- // Use typed select if available, otherwise fall back to Record<string, unknown>
271
- const selectType = selectTypeName ?? 'Record<string, unknown>';
272
- const returnTypePart = selectTypeName && payloadTypeName
273
- ? `{ ${op.name}: InferSelectResult<${payloadTypeName}, S> }`
274
- : 'unknown';
275
- if (hasArgs) {
276
- if (selectTypeName) {
277
- return `${op.name}: <const S extends ${selectType}>(args: ${varTypeName}, options?: { select?: S }) =>
278
- new QueryBuilder<${returnTypePart}>({
279
- client,
280
- operation: 'mutation',
281
- operationName: '${ucFirst(op.name)}',
282
- fieldName: '${op.name}',
283
- ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
284
- })`;
285
- }
286
- else {
287
- return `${op.name}: (args: ${varTypeName}, options?: { select?: Record<string, unknown> }) =>
288
- new QueryBuilder({
289
- client,
290
- operation: 'mutation',
291
- operationName: '${ucFirst(op.name)}',
292
- fieldName: '${op.name}',
293
- ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, args, ${varDefsJson}),
294
- })`;
295
- }
296
- }
297
- else {
298
- // No args - still provide typed select
299
- if (selectTypeName) {
300
- return `${op.name}: <const S extends ${selectType}>(options?: { select?: S }) =>
301
- new QueryBuilder<${returnTypePart}>({
302
- client,
303
- operation: 'mutation',
304
- operationName: '${ucFirst(op.name)}',
305
- fieldName: '${op.name}',
306
- ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
307
- })`;
308
- }
309
- else {
310
- return `${op.name}: (options?: { select?: Record<string, unknown> }) =>
311
- new QueryBuilder({
312
- client,
313
- operation: 'mutation',
314
- operationName: '${ucFirst(op.name)}',
315
- fieldName: '${op.name}',
316
- ...buildCustomDocument('mutation', '${ucFirst(op.name)}', '${op.name}', options?.select, undefined, []),
317
- })`;
318
- }
319
- }
320
- });
321
- sourceFile.addFunction({
322
- name: 'createMutationOperations',
323
- isExported: true,
324
- parameters: [{ name: 'client', type: 'OrmClient' }],
325
- statements: `return {
326
- ${operationMethods.join(',\n ')},
327
- };`,
328
- });
244
+ const operationProperties = operations.map((op) => buildOperationMethod(op, 'mutation'));
245
+ const returnObj = t.objectExpression(operationProperties);
246
+ const returnStmt = t.returnStatement(returnObj);
247
+ const clientParam = t.identifier('client');
248
+ clientParam.typeAnnotation = t.tsTypeAnnotation(t.tsTypeReference(t.identifier('OrmClient')));
249
+ const factoryFunc = t.functionDeclaration(t.identifier('createMutationOperations'), [clientParam], t.blockStatement([returnStmt]));
250
+ statements.push(t.exportNamedDeclaration(factoryFunc));
251
+ const header = getGeneratedFileHeader('Custom mutation operations');
252
+ const code = generateCode(statements);
329
253
  return {
330
254
  fileName: 'mutation/index.ts',
331
- content: getFormattedOutput(sourceFile),
255
+ content: header + '\n' + code,
332
256
  };
333
257
  }
334
258
  /**
@@ -1,3 +1,15 @@
1
+ /**
2
+ * Input types generator for ORM client (Babel AST-based)
3
+ *
4
+ * Generates TypeScript interfaces for:
5
+ * 1. Scalar filter types (StringFilter, IntFilter, UUIDFilter, etc.)
6
+ * 2. Entity interfaces (User, Order, etc.)
7
+ * 3. Table filter types (UserFilter, OrderFilter, etc.)
8
+ * 4. OrderBy enums (UsersOrderBy, OrdersOrderBy, etc.)
9
+ * 5. Input types (LoginInput, CreateUserInput, etc.)
10
+ *
11
+ * Uses Babel AST for robust code generation.
12
+ */
1
13
  import type { TypeRegistry, CleanArgument, CleanTable } from '../../../types/schema';
2
14
  export interface GeneratedInputTypesFile {
3
15
  fileName: string;
@@ -16,6 +28,6 @@ export declare function collectPayloadTypeNames(operations: Array<{
16
28
  returnType: CleanArgument['type'];
17
29
  }>): Set<string>;
18
30
  /**
19
- * Generate comprehensive input-types.ts file using ts-morph AST
31
+ * Generate comprehensive input-types.ts file using Babel AST
20
32
  */
21
33
  export declare function generateInputTypesFile(typeRegistry: TypeRegistry, usedInputTypes: Set<string>, tables?: CleanTable[], usedPayloadTypes?: Set<string>): GeneratedInputTypesFile;