@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,9 +1,43 @@
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.collectInputTypeNames = collectInputTypeNames;
4
37
  exports.collectPayloadTypeNames = collectPayloadTypeNames;
5
38
  exports.generateInputTypesFile = generateInputTypesFile;
6
- const ts_ast_1 = require("../ts-ast");
39
+ const t = __importStar(require("@babel/types"));
40
+ const babel_ast_1 = require("../babel-ast");
7
41
  const utils_1 = require("../utils");
8
42
  const inflekt_1 = require("inflekt");
9
43
  const type_resolver_1 = require("../type-resolver");
@@ -62,6 +96,86 @@ function typeRefToTs(typeRef) {
62
96
  function isRequired(typeRef) {
63
97
  return typeRef.kind === 'NON_NULL';
64
98
  }
99
+ // ============================================================================
100
+ // Babel AST Helper Functions
101
+ // ============================================================================
102
+ /**
103
+ * Parse a type string into a TSType node
104
+ */
105
+ function parseTypeString(typeStr) {
106
+ // Handle union types like "string | null"
107
+ if (typeStr.includes(' | ')) {
108
+ const parts = typeStr.split(' | ').map((p) => p.trim());
109
+ return t.tsUnionType(parts.map((p) => parseTypeString(p)));
110
+ }
111
+ // Handle array types like "string[]"
112
+ if (typeStr.endsWith('[]')) {
113
+ const elementType = typeStr.slice(0, -2);
114
+ return t.tsArrayType(parseTypeString(elementType));
115
+ }
116
+ // Handle generic types like "Record<string, unknown>"
117
+ if (typeStr.includes('<')) {
118
+ const match = typeStr.match(/^([^<]+)<(.+)>$/);
119
+ if (match) {
120
+ const [, baseName, params] = match;
121
+ const typeParams = params.split(',').map((p) => parseTypeString(p.trim()));
122
+ return t.tsTypeReference(t.identifier(baseName), t.tsTypeParameterInstantiation(typeParams));
123
+ }
124
+ }
125
+ // Handle primitive types
126
+ switch (typeStr) {
127
+ case 'string':
128
+ return t.tsStringKeyword();
129
+ case 'number':
130
+ return t.tsNumberKeyword();
131
+ case 'boolean':
132
+ return t.tsBooleanKeyword();
133
+ case 'null':
134
+ return t.tsNullKeyword();
135
+ case 'unknown':
136
+ return t.tsUnknownKeyword();
137
+ default:
138
+ return t.tsTypeReference(t.identifier(typeStr));
139
+ }
140
+ }
141
+ /**
142
+ * Create an interface property signature
143
+ */
144
+ function createPropertySignature(name, typeStr, optional) {
145
+ const prop = t.tsPropertySignature(t.identifier(name), t.tsTypeAnnotation(parseTypeString(typeStr)));
146
+ prop.optional = optional;
147
+ return prop;
148
+ }
149
+ /**
150
+ * Create an exported interface declaration
151
+ */
152
+ function createExportedInterface(name, properties) {
153
+ const props = properties.map((p) => createPropertySignature(p.name, p.type, p.optional));
154
+ const body = t.tsInterfaceBody(props);
155
+ const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(name), null, null, body);
156
+ return t.exportNamedDeclaration(interfaceDecl);
157
+ }
158
+ /**
159
+ * Create an exported type alias declaration
160
+ */
161
+ function createExportedTypeAlias(name, typeStr) {
162
+ const typeAlias = t.tsTypeAliasDeclaration(t.identifier(name), null, parseTypeString(typeStr));
163
+ return t.exportNamedDeclaration(typeAlias);
164
+ }
165
+ /**
166
+ * Create a union type from string literals
167
+ */
168
+ function createStringLiteralUnion(values) {
169
+ return t.tsUnionType(values.map((v) => t.tsLiteralType(t.stringLiteral(v))));
170
+ }
171
+ /**
172
+ * Add a section comment to the first statement in an array
173
+ */
174
+ function addSectionComment(statements, sectionName) {
175
+ if (statements.length > 0) {
176
+ (0, babel_ast_1.addLineComment)(statements[0], `============ ${sectionName} ============`);
177
+ }
178
+ }
65
179
  /** Configuration for all scalar filter types - matches PostGraphile's generated filters */
66
180
  const SCALAR_FILTER_CONFIGS = [
67
181
  {
@@ -159,13 +273,15 @@ function buildScalarFilterProperties(config) {
159
273
  return props;
160
274
  }
161
275
  /**
162
- * Add scalar filter types to source file using ts-morph
276
+ * Generate scalar filter type statements
163
277
  */
164
- function addScalarFilterTypes(sourceFile) {
165
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Scalar Filter Types');
278
+ function generateScalarFilterTypes() {
279
+ const statements = [];
166
280
  for (const config of SCALAR_FILTER_CONFIGS) {
167
- sourceFile.addInterface((0, ts_ast_1.createInterface)(config.name, buildScalarFilterProperties(config)));
281
+ statements.push(createExportedInterface(config.name, buildScalarFilterProperties(config)));
168
282
  }
283
+ addSectionComment(statements, 'Scalar Filter Types');
284
+ return statements;
169
285
  }
170
286
  // ============================================================================
171
287
  // Enum Types Collector
@@ -194,19 +310,24 @@ function collectEnumTypesFromTables(tables, typeRegistry) {
194
310
  return enumTypes;
195
311
  }
196
312
  /**
197
- * Add enum types to source file
313
+ * Generate enum type statements
198
314
  */
199
- function addEnumTypes(sourceFile, typeRegistry, enumTypeNames) {
315
+ function generateEnumTypes(typeRegistry, enumTypeNames) {
200
316
  if (enumTypeNames.size === 0)
201
- return;
202
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Enum Types');
317
+ return [];
318
+ const statements = [];
203
319
  for (const typeName of Array.from(enumTypeNames).sort()) {
204
320
  const typeInfo = typeRegistry.get(typeName);
205
321
  if (!typeInfo || typeInfo.kind !== 'ENUM' || !typeInfo.enumValues)
206
322
  continue;
207
- const values = typeInfo.enumValues.map((v) => `'${v}'`).join(' | ');
208
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(typeName, values));
323
+ const unionType = createStringLiteralUnion(typeInfo.enumValues);
324
+ const typeAlias = t.tsTypeAliasDeclaration(t.identifier(typeName), null, unionType);
325
+ statements.push(t.exportNamedDeclaration(typeAlias));
326
+ }
327
+ if (statements.length > 0) {
328
+ addSectionComment(statements, 'Enum Types');
209
329
  }
330
+ return statements;
210
331
  }
211
332
  // ============================================================================
212
333
  // Entity Types Generator (AST-based)
@@ -231,40 +352,47 @@ function buildEntityProperties(table) {
231
352
  return properties;
232
353
  }
233
354
  /**
234
- * Add entity type interface for a table
235
- */
236
- function addEntityType(sourceFile, table) {
237
- const { typeName } = (0, utils_1.getTableNames)(table);
238
- sourceFile.addInterface((0, ts_ast_1.createInterface)(typeName, buildEntityProperties(table)));
239
- }
240
- /**
241
- * Add all entity types
355
+ * Generate entity type statements
242
356
  */
243
- function addEntityTypes(sourceFile, tables) {
244
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Entity Types');
357
+ function generateEntityTypes(tables) {
358
+ const statements = [];
245
359
  for (const table of tables) {
246
- addEntityType(sourceFile, table);
360
+ const { typeName } = (0, utils_1.getTableNames)(table);
361
+ statements.push(createExportedInterface(typeName, buildEntityProperties(table)));
362
+ }
363
+ if (statements.length > 0) {
364
+ addSectionComment(statements, 'Entity Types');
247
365
  }
366
+ return statements;
248
367
  }
249
368
  // ============================================================================
250
369
  // Relation Helper Types Generator (AST-based)
251
370
  // ============================================================================
252
371
  /**
253
- * Add relation helper types (ConnectionResult, PageInfo)
372
+ * Generate relation helper type statements (ConnectionResult, PageInfo)
254
373
  */
255
- function addRelationHelperTypes(sourceFile) {
256
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Relation Helper Types');
257
- sourceFile.addInterface((0, ts_ast_1.createInterface)('ConnectionResult<T>', [
258
- { name: 'nodes', type: 'T[]', optional: false },
259
- { name: 'totalCount', type: 'number', optional: false },
260
- { name: 'pageInfo', type: 'PageInfo', optional: false },
261
- ]));
262
- sourceFile.addInterface((0, ts_ast_1.createInterface)('PageInfo', [
374
+ function generateRelationHelperTypes() {
375
+ const statements = [];
376
+ // ConnectionResult<T> interface with type parameter
377
+ const connectionResultProps = [
378
+ createPropertySignature('nodes', 'T[]', false),
379
+ createPropertySignature('totalCount', 'number', false),
380
+ createPropertySignature('pageInfo', 'PageInfo', false),
381
+ ];
382
+ const connectionResultBody = t.tsInterfaceBody(connectionResultProps);
383
+ const connectionResultDecl = t.tsInterfaceDeclaration(t.identifier('ConnectionResult'), t.tsTypeParameterDeclaration([
384
+ t.tsTypeParameter(null, null, 'T'),
385
+ ]), null, connectionResultBody);
386
+ statements.push(t.exportNamedDeclaration(connectionResultDecl));
387
+ // PageInfo interface
388
+ statements.push(createExportedInterface('PageInfo', [
263
389
  { name: 'hasNextPage', type: 'boolean', optional: false },
264
390
  { name: 'hasPreviousPage', type: 'boolean', optional: false },
265
391
  { name: 'startCursor', type: 'string | null', optional: true },
266
392
  { name: 'endCursor', type: 'string | null', optional: true },
267
393
  ]));
394
+ addSectionComment(statements, 'Relation Helper Types');
395
+ return statements;
268
396
  }
269
397
  // ============================================================================
270
398
  // Entity Relation Types Generator (AST-based)
@@ -337,44 +465,65 @@ function buildEntityRelationProperties(table, tableByName) {
337
465
  return properties;
338
466
  }
339
467
  /**
340
- * Add entity relation types
468
+ * Generate entity relation type statements
341
469
  */
342
- function addEntityRelationTypes(sourceFile, tables, tableByName) {
343
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Entity Relation Types');
470
+ function generateEntityRelationTypes(tables, tableByName) {
471
+ const statements = [];
344
472
  for (const table of tables) {
345
473
  const { typeName } = (0, utils_1.getTableNames)(table);
346
- sourceFile.addInterface((0, ts_ast_1.createInterface)(`${typeName}Relations`, buildEntityRelationProperties(table, tableByName)));
474
+ statements.push(createExportedInterface(`${typeName}Relations`, buildEntityRelationProperties(table, tableByName)));
475
+ }
476
+ if (statements.length > 0) {
477
+ addSectionComment(statements, 'Entity Relation Types');
347
478
  }
479
+ return statements;
348
480
  }
349
481
  /**
350
- * Add entity types with relations (intersection types)
482
+ * Generate entity types with relations (intersection types)
351
483
  */
352
- function addEntityWithRelations(sourceFile, tables) {
353
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Entity Types With Relations');
484
+ function generateEntityWithRelations(tables) {
485
+ const statements = [];
354
486
  for (const table of tables) {
355
487
  const { typeName } = (0, utils_1.getTableNames)(table);
356
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(`${typeName}WithRelations`, `${typeName} & ${typeName}Relations`));
488
+ statements.push(createExportedTypeAlias(`${typeName}WithRelations`, `${typeName} & ${typeName}Relations`));
489
+ }
490
+ if (statements.length > 0) {
491
+ addSectionComment(statements, 'Entity Types With Relations');
357
492
  }
493
+ return statements;
358
494
  }
359
495
  // ============================================================================
360
496
  // Entity Select Types Generator (AST-based)
361
497
  // ============================================================================
362
498
  /**
363
- * Build the type string for a Select type (as object type literal)
499
+ * Build the Select type as a TSTypeLiteral
364
500
  */
365
- function buildSelectTypeBody(table, tableByName) {
366
- const lines = ['{'];
501
+ function buildSelectTypeLiteral(table, tableByName) {
502
+ const members = [];
367
503
  // Add scalar fields
368
504
  for (const field of table.fields) {
369
505
  if (!(0, utils_1.isRelationField)(field.name, table)) {
370
- lines.push(`${field.name}?: boolean;`);
506
+ const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(t.tsBooleanKeyword()));
507
+ prop.optional = true;
508
+ members.push(prop);
371
509
  }
372
510
  }
373
511
  // Add belongsTo relations
374
512
  for (const relation of table.relations.belongsTo) {
375
513
  if (relation.fieldName) {
376
514
  const relatedTypeName = getRelatedTypeName(relation.referencesTable, tableByName);
377
- lines.push(`${relation.fieldName}?: boolean | { select?: ${relatedTypeName}Select };`);
515
+ const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsUnionType([
516
+ t.tsBooleanKeyword(),
517
+ t.tsTypeLiteral([
518
+ (() => {
519
+ const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
520
+ selectProp.optional = true;
521
+ return selectProp;
522
+ })(),
523
+ ]),
524
+ ])));
525
+ prop.optional = true;
526
+ members.push(prop);
378
527
  }
379
528
  }
380
529
  // Add hasMany relations
@@ -383,12 +532,33 @@ function buildSelectTypeBody(table, tableByName) {
383
532
  const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
384
533
  const filterName = getRelatedFilterName(relation.referencedByTable, tableByName);
385
534
  const orderByName = getRelatedOrderByName(relation.referencedByTable, tableByName);
386
- lines.push(`${relation.fieldName}?: boolean | {`);
387
- lines.push(` select?: ${relatedTypeName}Select;`);
388
- lines.push(` first?: number;`);
389
- lines.push(` filter?: ${filterName};`);
390
- lines.push(` orderBy?: ${orderByName}[];`);
391
- lines.push(`};`);
535
+ const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsUnionType([
536
+ t.tsBooleanKeyword(),
537
+ t.tsTypeLiteral([
538
+ (() => {
539
+ const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
540
+ p.optional = true;
541
+ return p;
542
+ })(),
543
+ (() => {
544
+ const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
545
+ p.optional = true;
546
+ return p;
547
+ })(),
548
+ (() => {
549
+ const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))));
550
+ p.optional = true;
551
+ return p;
552
+ })(),
553
+ (() => {
554
+ const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByName)))));
555
+ p.optional = true;
556
+ return p;
557
+ })(),
558
+ ]),
559
+ ])));
560
+ prop.optional = true;
561
+ members.push(prop);
392
562
  }
393
563
  }
394
564
  // Add manyToMany relations
@@ -397,33 +567,69 @@ function buildSelectTypeBody(table, tableByName) {
397
567
  const relatedTypeName = getRelatedTypeName(relation.rightTable, tableByName);
398
568
  const filterName = getRelatedFilterName(relation.rightTable, tableByName);
399
569
  const orderByName = getRelatedOrderByName(relation.rightTable, tableByName);
400
- lines.push(`${relation.fieldName}?: boolean | {`);
401
- lines.push(` select?: ${relatedTypeName}Select;`);
402
- lines.push(` first?: number;`);
403
- lines.push(` filter?: ${filterName};`);
404
- lines.push(` orderBy?: ${orderByName}[];`);
405
- lines.push(`};`);
570
+ const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsUnionType([
571
+ t.tsBooleanKeyword(),
572
+ t.tsTypeLiteral([
573
+ (() => {
574
+ const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
575
+ p.optional = true;
576
+ return p;
577
+ })(),
578
+ (() => {
579
+ const p = t.tsPropertySignature(t.identifier('first'), t.tsTypeAnnotation(t.tsNumberKeyword()));
580
+ p.optional = true;
581
+ return p;
582
+ })(),
583
+ (() => {
584
+ const p = t.tsPropertySignature(t.identifier('filter'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(filterName))));
585
+ p.optional = true;
586
+ return p;
587
+ })(),
588
+ (() => {
589
+ const p = t.tsPropertySignature(t.identifier('orderBy'), t.tsTypeAnnotation(t.tsArrayType(t.tsTypeReference(t.identifier(orderByName)))));
590
+ p.optional = true;
591
+ return p;
592
+ })(),
593
+ ]),
594
+ ])));
595
+ prop.optional = true;
596
+ members.push(prop);
406
597
  }
407
598
  }
408
599
  // Add hasOne relations
409
600
  for (const relation of table.relations.hasOne) {
410
601
  if (relation.fieldName) {
411
602
  const relatedTypeName = getRelatedTypeName(relation.referencedByTable, tableByName);
412
- lines.push(`${relation.fieldName}?: boolean | { select?: ${relatedTypeName}Select };`);
603
+ const prop = t.tsPropertySignature(t.identifier(relation.fieldName), t.tsTypeAnnotation(t.tsUnionType([
604
+ t.tsBooleanKeyword(),
605
+ t.tsTypeLiteral([
606
+ (() => {
607
+ const selectProp = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${relatedTypeName}Select`))));
608
+ selectProp.optional = true;
609
+ return selectProp;
610
+ })(),
611
+ ]),
612
+ ])));
613
+ prop.optional = true;
614
+ members.push(prop);
413
615
  }
414
616
  }
415
- lines.push('}');
416
- return lines.join('\n');
617
+ return t.tsTypeLiteral(members);
417
618
  }
418
619
  /**
419
- * Add entity Select types
620
+ * Generate entity Select type statements
420
621
  */
421
- function addEntitySelectTypes(sourceFile, tables, tableByName) {
422
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Entity Select Types');
622
+ function generateEntitySelectTypes(tables, tableByName) {
623
+ const statements = [];
423
624
  for (const table of tables) {
424
625
  const { typeName } = (0, utils_1.getTableNames)(table);
425
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(`${typeName}Select`, buildSelectTypeBody(table, tableByName)));
626
+ const typeAlias = t.tsTypeAliasDeclaration(t.identifier(`${typeName}Select`), null, buildSelectTypeLiteral(table, tableByName));
627
+ statements.push(t.exportNamedDeclaration(typeAlias));
426
628
  }
629
+ if (statements.length > 0) {
630
+ addSectionComment(statements, 'Entity Select Types');
631
+ }
632
+ return statements;
427
633
  }
428
634
  // ============================================================================
429
635
  // Table Filter Types Generator (AST-based)
@@ -454,14 +660,18 @@ function buildTableFilterProperties(table) {
454
660
  return properties;
455
661
  }
456
662
  /**
457
- * Add table filter types
663
+ * Generate table filter type statements
458
664
  */
459
- function addTableFilterTypes(sourceFile, tables) {
460
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Table Filter Types');
665
+ function generateTableFilterTypes(tables) {
666
+ const statements = [];
461
667
  for (const table of tables) {
462
668
  const filterName = (0, utils_1.getFilterTypeName)(table);
463
- sourceFile.addInterface((0, ts_ast_1.createInterface)(filterName, buildTableFilterProperties(table)));
669
+ statements.push(createExportedInterface(filterName, buildTableFilterProperties(table)));
670
+ }
671
+ if (statements.length > 0) {
672
+ addSectionComment(statements, 'Table Filter Types');
464
673
  }
674
+ return statements;
465
675
  }
466
676
  // ============================================================================
467
677
  // Condition Types Generator (AST-based)
@@ -487,22 +697,26 @@ function buildTableConditionProperties(table) {
487
697
  return properties;
488
698
  }
489
699
  /**
490
- * Add table condition types
700
+ * Generate table condition type statements
491
701
  */
492
- function addTableConditionTypes(sourceFile, tables) {
493
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Table Condition Types');
702
+ function generateTableConditionTypes(tables) {
703
+ const statements = [];
494
704
  for (const table of tables) {
495
705
  const conditionName = (0, utils_1.getConditionTypeName)(table);
496
- sourceFile.addInterface((0, ts_ast_1.createInterface)(conditionName, buildTableConditionProperties(table)));
706
+ statements.push(createExportedInterface(conditionName, buildTableConditionProperties(table)));
707
+ }
708
+ if (statements.length > 0) {
709
+ addSectionComment(statements, 'Table Condition Types');
497
710
  }
711
+ return statements;
498
712
  }
499
713
  // ============================================================================
500
714
  // OrderBy Types Generator (AST-based)
501
715
  // ============================================================================
502
716
  /**
503
- * Build OrderBy union type string
717
+ * Build OrderBy union type values
504
718
  */
505
- function buildOrderByUnion(table) {
719
+ function buildOrderByValues(table) {
506
720
  const values = ['PRIMARY_KEY_ASC', 'PRIMARY_KEY_DESC', 'NATURAL'];
507
721
  for (const field of table.fields) {
508
722
  if ((0, utils_1.isRelationField)(field.name, table))
@@ -511,19 +725,24 @@ function buildOrderByUnion(table) {
511
725
  values.push(`${upperSnake}_ASC`);
512
726
  values.push(`${upperSnake}_DESC`);
513
727
  }
514
- return values.map((v) => `'${v}'`).join(' | ');
728
+ return values;
515
729
  }
516
730
  /**
517
- * Add OrderBy types
518
- * Uses inflection from table metadata for correct pluralization
731
+ * Generate OrderBy type statements
519
732
  */
520
- function addOrderByTypes(sourceFile, tables) {
521
- (0, ts_ast_1.addSectionComment)(sourceFile, 'OrderBy Types');
733
+ function generateOrderByTypes(tables) {
734
+ const statements = [];
522
735
  for (const table of tables) {
523
- // Use getOrderByTypeName which respects table.inflection.orderByType
524
736
  const enumName = (0, utils_1.getOrderByTypeName)(table);
525
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(enumName, buildOrderByUnion(table)));
737
+ const values = buildOrderByValues(table);
738
+ const unionType = createStringLiteralUnion(values);
739
+ const typeAlias = t.tsTypeAliasDeclaration(t.identifier(enumName), null, unionType);
740
+ statements.push(t.exportNamedDeclaration(typeAlias));
526
741
  }
742
+ if (statements.length > 0) {
743
+ addSectionComment(statements, 'OrderBy Types');
744
+ }
745
+ return statements;
527
746
  }
528
747
  // ============================================================================
529
748
  // CRUD Input Types Generator (AST-based)
@@ -546,27 +765,30 @@ function buildCreateDataFields(table) {
546
765
  return fields;
547
766
  }
548
767
  /**
549
- * Generate Create input interface as formatted string.
550
- *
551
- * ts-morph doesn't handle nested object types in interface properties well,
552
- * so we build this manually with pre-doubled indentation (4→2, 8→4) since
553
- * getMinimalFormattedOutput halves all indentation.
768
+ * Build Create input interface as AST
554
769
  */
555
770
  function buildCreateInputInterface(table) {
556
771
  const { typeName, singularName } = (0, utils_1.getTableNames)(table);
557
772
  const fields = buildCreateDataFields(table);
558
- const lines = [
559
- `export interface Create${typeName}Input {`,
560
- ` clientMutationId?: string;`,
561
- ` ${singularName}: {`,
773
+ // Build the nested object type for the entity data
774
+ const nestedProps = fields.map((field) => {
775
+ const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(parseTypeString(field.type)));
776
+ prop.optional = field.optional;
777
+ return prop;
778
+ });
779
+ const nestedObjectType = t.tsTypeLiteral(nestedProps);
780
+ // Build the main interface properties
781
+ const mainProps = [
782
+ (() => {
783
+ const prop = t.tsPropertySignature(t.identifier('clientMutationId'), t.tsTypeAnnotation(t.tsStringKeyword()));
784
+ prop.optional = true;
785
+ return prop;
786
+ })(),
787
+ t.tsPropertySignature(t.identifier(singularName), t.tsTypeAnnotation(nestedObjectType)),
562
788
  ];
563
- for (const field of fields) {
564
- const opt = field.optional ? '?' : '';
565
- lines.push(` ${field.name}${opt}: ${field.type};`);
566
- }
567
- lines.push(' };');
568
- lines.push('}');
569
- return lines.join('\n');
789
+ const body = t.tsInterfaceBody(mainProps);
790
+ const interfaceDecl = t.tsInterfaceDeclaration(t.identifier(`Create${typeName}Input`), null, null, body);
791
+ return t.exportNamedDeclaration(interfaceDecl);
570
792
  }
571
793
  /**
572
794
  * Build Patch type properties
@@ -589,35 +811,41 @@ function buildPatchProperties(table) {
589
811
  return properties;
590
812
  }
591
813
  /**
592
- * Add CRUD input types for a table
814
+ * Generate CRUD input type statements for a table
593
815
  */
594
- function addCrudInputTypes(sourceFile, table) {
816
+ function generateCrudInputTypes(table) {
817
+ const statements = [];
595
818
  const { typeName } = (0, utils_1.getTableNames)(table);
596
819
  const patchName = `${typeName}Patch`;
597
- // Create input - build as raw statement due to nested object type formatting
598
- sourceFile.addStatements(buildCreateInputInterface(table));
820
+ // Create input
821
+ statements.push(buildCreateInputInterface(table));
599
822
  // Patch interface
600
- sourceFile.addInterface((0, ts_ast_1.createInterface)(patchName, buildPatchProperties(table)));
823
+ statements.push(createExportedInterface(patchName, buildPatchProperties(table)));
601
824
  // Update input
602
- sourceFile.addInterface((0, ts_ast_1.createInterface)(`Update${typeName}Input`, [
825
+ statements.push(createExportedInterface(`Update${typeName}Input`, [
603
826
  { name: 'clientMutationId', type: 'string', optional: true },
604
827
  { name: 'id', type: 'string', optional: false },
605
828
  { name: 'patch', type: patchName, optional: false },
606
829
  ]));
607
830
  // Delete input
608
- sourceFile.addInterface((0, ts_ast_1.createInterface)(`Delete${typeName}Input`, [
831
+ statements.push(createExportedInterface(`Delete${typeName}Input`, [
609
832
  { name: 'clientMutationId', type: 'string', optional: true },
610
833
  { name: 'id', type: 'string', optional: false },
611
834
  ]));
835
+ return statements;
612
836
  }
613
837
  /**
614
- * Add all CRUD input types
838
+ * Generate all CRUD input type statements
615
839
  */
616
- function addAllCrudInputTypes(sourceFile, tables) {
617
- (0, ts_ast_1.addSectionComment)(sourceFile, 'CRUD Input Types');
840
+ function generateAllCrudInputTypes(tables) {
841
+ const statements = [];
618
842
  for (const table of tables) {
619
- addCrudInputTypes(sourceFile, table);
843
+ statements.push(...generateCrudInputTypes(table));
620
844
  }
845
+ if (statements.length > 0) {
846
+ addSectionComment(statements, 'CRUD Input Types');
847
+ }
848
+ return statements;
621
849
  }
622
850
  // ============================================================================
623
851
  // Custom Input Types Generator (AST-based)
@@ -645,7 +873,7 @@ function collectInputTypeNames(operations) {
645
873
  }
646
874
  /**
647
875
  * Build a set of exact table CRUD input type names to skip
648
- * These are generated by addAllCrudInputTypes, so we don't need to regenerate them
876
+ * These are generated by generateAllCrudInputTypes, so we don't need to regenerate them
649
877
  */
650
878
  function buildTableCrudTypeNames(tables) {
651
879
  const crudTypes = new Set();
@@ -660,10 +888,10 @@ function buildTableCrudTypeNames(tables) {
660
888
  return crudTypes;
661
889
  }
662
890
  /**
663
- * Add custom input types from TypeRegistry
891
+ * Generate custom input type statements from TypeRegistry
664
892
  */
665
- function addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes, tableCrudTypes) {
666
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Custom Input Types (from schema)');
893
+ function generateCustomInputTypes(typeRegistry, usedInputTypes, tableCrudTypes) {
894
+ const statements = [];
667
895
  const generatedTypes = new Set();
668
896
  const typesToGenerate = new Set(Array.from(usedInputTypes));
669
897
  // Filter out types we've already generated (exact matches for table CRUD types only)
@@ -686,8 +914,11 @@ function addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes, tableCrud
686
914
  generatedTypes.add(typeName);
687
915
  const typeInfo = typeRegistry.get(typeName);
688
916
  if (!typeInfo) {
689
- sourceFile.addStatements(`// Type '${typeName}' not found in schema`);
690
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(typeName, 'Record<string, unknown>'));
917
+ // Add comment for missing type
918
+ const commentStmt = t.emptyStatement();
919
+ (0, babel_ast_1.addLineComment)(commentStmt, ` Type '${typeName}' not found in schema`);
920
+ statements.push(commentStmt);
921
+ statements.push(createExportedTypeAlias(typeName, 'Record<string, unknown>'));
691
922
  continue;
692
923
  }
693
924
  if (typeInfo.kind === 'INPUT_OBJECT' && typeInfo.inputFields) {
@@ -704,17 +935,25 @@ function addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes, tableCrud
704
935
  typesToGenerate.add(baseType);
705
936
  }
706
937
  }
707
- sourceFile.addInterface((0, ts_ast_1.createInterface)(typeName, properties));
938
+ statements.push(createExportedInterface(typeName, properties));
708
939
  }
709
940
  else if (typeInfo.kind === 'ENUM' && typeInfo.enumValues) {
710
- const values = typeInfo.enumValues.map((v) => `'${v}'`).join(' | ');
711
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(typeName, values));
941
+ const unionType = createStringLiteralUnion(typeInfo.enumValues);
942
+ const typeAlias = t.tsTypeAliasDeclaration(t.identifier(typeName), null, unionType);
943
+ statements.push(t.exportNamedDeclaration(typeAlias));
712
944
  }
713
945
  else {
714
- sourceFile.addStatements(`// Type '${typeName}' is ${typeInfo.kind}`);
715
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(typeName, 'unknown'));
946
+ // Add comment for unsupported type kind
947
+ const commentStmt = t.emptyStatement();
948
+ (0, babel_ast_1.addLineComment)(commentStmt, ` Type '${typeName}' is ${typeInfo.kind}`);
949
+ statements.push(commentStmt);
950
+ statements.push(createExportedTypeAlias(typeName, 'unknown'));
716
951
  }
717
952
  }
953
+ if (statements.length > 0) {
954
+ addSectionComment(statements, 'Custom Input Types (from schema)');
955
+ }
956
+ return statements;
718
957
  }
719
958
  // ============================================================================
720
959
  // Payload/Return Types Generator (AST-based)
@@ -734,10 +973,10 @@ function collectPayloadTypeNames(operations) {
734
973
  return payloadTypes;
735
974
  }
736
975
  /**
737
- * Add payload/return types
976
+ * Generate payload/return type statements
738
977
  */
739
- function addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGeneratedTypes) {
740
- (0, ts_ast_1.addSectionComment)(sourceFile, 'Payload/Return Types (for custom operations)');
978
+ function generatePayloadTypes(typeRegistry, usedPayloadTypes, alreadyGeneratedTypes) {
979
+ const statements = [];
741
980
  const generatedTypes = new Set(alreadyGeneratedTypes);
742
981
  const typesToGenerate = new Set(Array.from(usedPayloadTypes));
743
982
  const skipTypes = new Set([
@@ -795,63 +1034,77 @@ function addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGene
795
1034
  }
796
1035
  }
797
1036
  }
798
- sourceFile.addInterface((0, ts_ast_1.createInterface)(typeName, interfaceProps));
799
- // Build Select type (no indentation - ts-morph adds it)
800
- const selectLines = ['{'];
1037
+ statements.push(createExportedInterface(typeName, interfaceProps));
1038
+ // Build Select type
1039
+ const selectMembers = [];
801
1040
  for (const field of typeInfo.fields) {
802
1041
  const baseType = (0, type_resolver_1.getTypeBaseName)(field.type);
803
1042
  if (baseType === 'Query' || baseType === 'Mutation')
804
1043
  continue;
805
1044
  const nestedType = baseType ? typeRegistry.get(baseType) : null;
1045
+ let propType;
806
1046
  if (nestedType?.kind === 'OBJECT') {
807
- selectLines.push(`${field.name}?: boolean | { select?: ${baseType}Select };`);
1047
+ propType = t.tsUnionType([
1048
+ t.tsBooleanKeyword(),
1049
+ t.tsTypeLiteral([
1050
+ (() => {
1051
+ const p = t.tsPropertySignature(t.identifier('select'), t.tsTypeAnnotation(t.tsTypeReference(t.identifier(`${baseType}Select`))));
1052
+ p.optional = true;
1053
+ return p;
1054
+ })(),
1055
+ ]),
1056
+ ]);
808
1057
  }
809
1058
  else {
810
- selectLines.push(`${field.name}?: boolean;`);
1059
+ propType = t.tsBooleanKeyword();
811
1060
  }
1061
+ const prop = t.tsPropertySignature(t.identifier(field.name), t.tsTypeAnnotation(propType));
1062
+ prop.optional = true;
1063
+ selectMembers.push(prop);
812
1064
  }
813
- selectLines.push('}');
814
- sourceFile.addTypeAlias((0, ts_ast_1.createTypeAlias)(`${typeName}Select`, selectLines.join('\n')));
1065
+ const selectTypeAlias = t.tsTypeAliasDeclaration(t.identifier(`${typeName}Select`), null, t.tsTypeLiteral(selectMembers));
1066
+ statements.push(t.exportNamedDeclaration(selectTypeAlias));
1067
+ }
1068
+ if (statements.length > 0) {
1069
+ addSectionComment(statements, 'Payload/Return Types (for custom operations)');
815
1070
  }
1071
+ return statements;
816
1072
  }
817
1073
  // ============================================================================
818
1074
  // Main Generator (AST-based)
819
1075
  // ============================================================================
820
1076
  /**
821
- * Generate comprehensive input-types.ts file using ts-morph AST
1077
+ * Generate comprehensive input-types.ts file using Babel AST
822
1078
  */
823
1079
  function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloadTypes) {
824
- const project = (0, ts_ast_1.createProject)();
825
- const sourceFile = (0, ts_ast_1.createSourceFile)(project, 'input-types.ts');
826
- // Add file header
827
- sourceFile.insertText(0, (0, ts_ast_1.createFileHeader)('GraphQL types for ORM client') + '\n');
1080
+ const statements = [];
828
1081
  // 1. Scalar filter types
829
- addScalarFilterTypes(sourceFile);
1082
+ statements.push(...generateScalarFilterTypes());
830
1083
  // 2. Enum types used by table fields
831
1084
  if (tables && tables.length > 0) {
832
1085
  const enumTypes = collectEnumTypesFromTables(tables, typeRegistry);
833
- addEnumTypes(sourceFile, typeRegistry, enumTypes);
1086
+ statements.push(...generateEnumTypes(typeRegistry, enumTypes));
834
1087
  }
835
1088
  // 3. Entity and relation types (if tables provided)
836
1089
  if (tables && tables.length > 0) {
837
1090
  const tableByName = new Map(tables.map((table) => [table.name, table]));
838
- addEntityTypes(sourceFile, tables);
839
- addRelationHelperTypes(sourceFile);
840
- addEntityRelationTypes(sourceFile, tables, tableByName);
841
- addEntityWithRelations(sourceFile, tables);
842
- addEntitySelectTypes(sourceFile, tables, tableByName);
1091
+ statements.push(...generateEntityTypes(tables));
1092
+ statements.push(...generateRelationHelperTypes());
1093
+ statements.push(...generateEntityRelationTypes(tables, tableByName));
1094
+ statements.push(...generateEntityWithRelations(tables));
1095
+ statements.push(...generateEntitySelectTypes(tables, tableByName));
843
1096
  // 4. Table filter types
844
- addTableFilterTypes(sourceFile, tables);
1097
+ statements.push(...generateTableFilterTypes(tables));
845
1098
  // 4b. Table condition types (simple equality filter)
846
- addTableConditionTypes(sourceFile, tables);
1099
+ statements.push(...generateTableConditionTypes(tables));
847
1100
  // 5. OrderBy types
848
- addOrderByTypes(sourceFile, tables);
1101
+ statements.push(...generateOrderByTypes(tables));
849
1102
  // 6. CRUD input types
850
- addAllCrudInputTypes(sourceFile, tables);
1103
+ statements.push(...generateAllCrudInputTypes(tables));
851
1104
  }
852
1105
  // 7. Custom input types from TypeRegistry
853
1106
  const tableCrudTypes = tables ? buildTableCrudTypeNames(tables) : undefined;
854
- addCustomInputTypes(sourceFile, typeRegistry, usedInputTypes, tableCrudTypes);
1107
+ statements.push(...generateCustomInputTypes(typeRegistry, usedInputTypes, tableCrudTypes));
855
1108
  // 8. Payload/return types for custom operations
856
1109
  if (usedPayloadTypes && usedPayloadTypes.size > 0) {
857
1110
  const alreadyGeneratedTypes = new Set();
@@ -861,10 +1114,13 @@ function generateInputTypesFile(typeRegistry, usedInputTypes, tables, usedPayloa
861
1114
  alreadyGeneratedTypes.add(typeName);
862
1115
  }
863
1116
  }
864
- addPayloadTypes(sourceFile, typeRegistry, usedPayloadTypes, alreadyGeneratedTypes);
1117
+ statements.push(...generatePayloadTypes(typeRegistry, usedPayloadTypes, alreadyGeneratedTypes));
865
1118
  }
1119
+ // Generate code with file header
1120
+ const header = (0, utils_1.getGeneratedFileHeader)('GraphQL types for ORM client');
1121
+ const code = (0, babel_ast_1.generateCode)(statements);
866
1122
  return {
867
1123
  fileName: 'input-types.ts',
868
- content: (0, ts_ast_1.getMinimalFormattedOutput)(sourceFile),
1124
+ content: header + '\n' + code,
869
1125
  };
870
1126
  }