@constructive-io/graphql-codegen 4.0.1 → 4.1.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 (97) hide show
  1. package/cli/handler.d.ts +13 -0
  2. package/cli/handler.js +74 -0
  3. package/cli/index.js +11 -60
  4. package/cli/shared.d.ts +1 -1
  5. package/cli/shared.js +2 -5
  6. package/core/codegen/barrel.d.ts +1 -0
  7. package/core/codegen/barrel.js +5 -2
  8. package/core/codegen/cli/arg-mapper.d.ts +4 -0
  9. package/core/codegen/cli/arg-mapper.js +117 -0
  10. package/core/codegen/cli/command-map-generator.d.ts +16 -0
  11. package/core/codegen/cli/command-map-generator.js +338 -0
  12. package/core/codegen/cli/custom-command-generator.d.ts +8 -0
  13. package/core/codegen/cli/custom-command-generator.js +155 -0
  14. package/core/codegen/cli/docs-generator.d.ts +26 -0
  15. package/core/codegen/cli/docs-generator.js +1399 -0
  16. package/core/codegen/cli/executor-generator.d.ts +11 -0
  17. package/core/codegen/cli/executor-generator.js +217 -0
  18. package/core/codegen/cli/index.d.ts +53 -0
  19. package/core/codegen/cli/index.js +153 -0
  20. package/core/codegen/cli/infra-generator.d.ts +9 -0
  21. package/core/codegen/cli/infra-generator.js +1195 -0
  22. package/core/codegen/cli/table-command-generator.d.ts +7 -0
  23. package/core/codegen/cli/table-command-generator.js +323 -0
  24. package/core/codegen/docs-utils.d.ts +30 -0
  25. package/core/codegen/docs-utils.js +122 -0
  26. package/core/codegen/hooks-docs-generator.d.ts +6 -0
  27. package/core/codegen/hooks-docs-generator.js +468 -0
  28. package/core/codegen/orm/docs-generator.d.ts +6 -0
  29. package/core/codegen/orm/docs-generator.js +416 -0
  30. package/core/codegen/target-docs-generator.d.ts +20 -0
  31. package/core/codegen/target-docs-generator.js +110 -0
  32. package/core/database/index.d.ts +0 -12
  33. package/core/database/index.js +2 -19
  34. package/core/generate.d.ts +34 -2
  35. package/core/generate.js +453 -12
  36. package/core/index.d.ts +0 -2
  37. package/core/index.js +0 -2
  38. package/core/introspect/source/database.js +2 -2
  39. package/core/introspect/source/pgpm-module.js +2 -2
  40. package/core/output/index.d.ts +1 -1
  41. package/core/output/index.js +1 -2
  42. package/core/output/writer.d.ts +0 -10
  43. package/core/output/writer.js +0 -31
  44. package/esm/cli/handler.d.ts +13 -0
  45. package/esm/cli/handler.js +71 -0
  46. package/esm/cli/index.js +11 -60
  47. package/esm/cli/shared.d.ts +1 -1
  48. package/esm/cli/shared.js +2 -5
  49. package/esm/core/codegen/barrel.d.ts +1 -0
  50. package/esm/core/codegen/barrel.js +5 -2
  51. package/esm/core/codegen/cli/arg-mapper.d.ts +4 -0
  52. package/esm/core/codegen/cli/arg-mapper.js +80 -0
  53. package/esm/core/codegen/cli/command-map-generator.d.ts +16 -0
  54. package/esm/core/codegen/cli/command-map-generator.js +301 -0
  55. package/esm/core/codegen/cli/custom-command-generator.d.ts +8 -0
  56. package/esm/core/codegen/cli/custom-command-generator.js +119 -0
  57. package/esm/core/codegen/cli/docs-generator.d.ts +26 -0
  58. package/esm/core/codegen/cli/docs-generator.js +1387 -0
  59. package/esm/core/codegen/cli/executor-generator.d.ts +11 -0
  60. package/esm/core/codegen/cli/executor-generator.js +180 -0
  61. package/esm/core/codegen/cli/index.d.ts +53 -0
  62. package/esm/core/codegen/cli/index.js +128 -0
  63. package/esm/core/codegen/cli/infra-generator.d.ts +9 -0
  64. package/esm/core/codegen/cli/infra-generator.js +1156 -0
  65. package/esm/core/codegen/cli/table-command-generator.d.ts +7 -0
  66. package/esm/core/codegen/cli/table-command-generator.js +287 -0
  67. package/esm/core/codegen/docs-utils.d.ts +30 -0
  68. package/esm/core/codegen/docs-utils.js +112 -0
  69. package/esm/core/codegen/hooks-docs-generator.d.ts +6 -0
  70. package/esm/core/codegen/hooks-docs-generator.js +462 -0
  71. package/esm/core/codegen/orm/docs-generator.d.ts +6 -0
  72. package/esm/core/codegen/orm/docs-generator.js +410 -0
  73. package/esm/core/codegen/target-docs-generator.d.ts +20 -0
  74. package/esm/core/codegen/target-docs-generator.js +105 -0
  75. package/esm/core/database/index.d.ts +0 -12
  76. package/esm/core/database/index.js +1 -17
  77. package/esm/core/generate.d.ts +34 -2
  78. package/esm/core/generate.js +417 -12
  79. package/esm/core/index.d.ts +0 -2
  80. package/esm/core/index.js +0 -2
  81. package/esm/core/introspect/source/database.js +2 -2
  82. package/esm/core/introspect/source/pgpm-module.js +2 -2
  83. package/esm/core/output/index.d.ts +1 -1
  84. package/esm/core/output/index.js +1 -1
  85. package/esm/core/output/writer.d.ts +0 -10
  86. package/esm/core/output/writer.js +0 -30
  87. package/esm/generators/index.d.ts +0 -3
  88. package/esm/generators/index.js +0 -3
  89. package/esm/index.d.ts +4 -3
  90. package/esm/index.js +4 -2
  91. package/esm/types/config.d.ts +78 -0
  92. package/generators/index.d.ts +0 -3
  93. package/generators/index.js +0 -3
  94. package/index.d.ts +4 -3
  95. package/index.js +7 -2
  96. package/package.json +8 -7
  97. package/types/config.d.ts +78 -0
package/core/generate.js CHANGED
@@ -1,31 +1,72 @@
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
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
36
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
37
  };
5
38
  Object.defineProperty(exports, "__esModule", { value: true });
6
39
  exports.generate = generate;
40
+ exports.expandApiNamesToMultiTarget = expandApiNamesToMultiTarget;
41
+ exports.expandSchemaDirToMultiTarget = expandSchemaDirToMultiTarget;
42
+ exports.generateMulti = generateMulti;
7
43
  /**
8
44
  * Main generate function - orchestrates the entire codegen pipeline
9
45
  *
10
46
  * This is the primary entry point for programmatic usage.
11
47
  * The CLI is a thin wrapper around this function.
12
48
  */
49
+ const fs = __importStar(require("node:fs"));
13
50
  const node_path_1 = __importDefault(require("node:path"));
51
+ const graphql_1 = require("graphql");
52
+ const core_1 = require("@pgpmjs/core");
53
+ const pgsql_client_1 = require("pgsql-client");
54
+ const pgsql_seed_1 = require("pgsql-seed");
14
55
  const config_1 = require("../types/config");
15
56
  const codegen_1 = require("./codegen");
16
57
  const barrel_1 = require("./codegen/barrel");
58
+ const cli_1 = require("./codegen/cli");
59
+ const docs_generator_1 = require("./codegen/cli/docs-generator");
60
+ const docs_utils_1 = require("./codegen/docs-utils");
61
+ const hooks_docs_generator_1 = require("./codegen/hooks-docs-generator");
17
62
  const orm_1 = require("./codegen/orm");
63
+ const docs_generator_2 = require("./codegen/orm/docs-generator");
18
64
  const shared_1 = require("./codegen/shared");
65
+ const target_docs_generator_1 = require("./codegen/target-docs-generator");
19
66
  const introspect_1 = require("./introspect");
20
67
  const output_1 = require("./output");
21
68
  const pipeline_1 = require("./pipeline");
22
- /**
23
- * Main generate function - takes a single config and generates code
24
- *
25
- * This is the primary entry point for programmatic usage.
26
- * For multiple configs, call this function in a loop.
27
- */
28
- async function generate(options = {}) {
69
+ async function generate(options = {}, internalOptions) {
29
70
  // Apply defaults to get resolved config
30
71
  const config = (0, config_1.getConfigOptions)(options);
31
72
  const outputRoot = config.output;
@@ -33,11 +74,12 @@ async function generate(options = {}) {
33
74
  // ORM is always required when React Query is enabled (hooks delegate to ORM)
34
75
  // This handles minimist setting orm=false when --orm flag is absent
35
76
  const runReactQuery = config.reactQuery ?? false;
36
- const runOrm = runReactQuery || (options.orm !== undefined ? !!options.orm : false);
37
- if (!runReactQuery && !runOrm) {
77
+ const runCli = internalOptions?.skipCli ? false : !!config.cli;
78
+ const runOrm = runReactQuery || !!config.cli || (options.orm !== undefined ? !!options.orm : false);
79
+ if (!options.schemaOnly && !runReactQuery && !runOrm && !runCli) {
38
80
  return {
39
81
  success: false,
40
- message: 'No generators enabled. Use reactQuery: true or orm: true in your config.',
82
+ message: 'No generators enabled. Use reactQuery: true, orm: true, or cli: true in your config.',
41
83
  output: outputRoot,
42
84
  };
43
85
  }
@@ -61,6 +103,39 @@ async function generate(options = {}) {
61
103
  authorization: options.authorization || config.headers?.Authorization,
62
104
  headers: config.headers,
63
105
  });
106
+ if (options.schemaOnly) {
107
+ try {
108
+ console.log(`Fetching schema from ${source.describe()}...`);
109
+ const { introspection } = await source.fetch();
110
+ const schema = (0, graphql_1.buildClientSchema)(introspection);
111
+ const sdl = (0, graphql_1.printSchema)(schema);
112
+ if (!sdl.trim()) {
113
+ return {
114
+ success: false,
115
+ message: 'Schema introspection returned empty SDL.',
116
+ output: outputRoot,
117
+ };
118
+ }
119
+ const outDir = node_path_1.default.resolve(options.schemaOnlyOutput || outputRoot || '.');
120
+ await fs.promises.mkdir(outDir, { recursive: true });
121
+ const filename = options.schemaOnlyFilename || 'schema.graphql';
122
+ const filePath = node_path_1.default.join(outDir, filename);
123
+ await fs.promises.writeFile(filePath, sdl, 'utf-8');
124
+ return {
125
+ success: true,
126
+ message: `Schema exported to ${filePath}`,
127
+ output: outDir,
128
+ filesWritten: [filePath],
129
+ };
130
+ }
131
+ catch (err) {
132
+ return {
133
+ success: false,
134
+ message: `Failed to export schema: ${err instanceof Error ? err.message : 'Unknown error'}`,
135
+ output: outputRoot,
136
+ };
137
+ }
138
+ }
64
139
  // Run pipeline
65
140
  let pipelineResult;
66
141
  try {
@@ -142,14 +217,115 @@ async function generate(options = {}) {
142
217
  path: node_path_1.default.posix.join('orm', file.path),
143
218
  })));
144
219
  }
220
+ // Generate CLI commands
221
+ if (runCli) {
222
+ console.log('Generating CLI commands...');
223
+ const { files } = (0, cli_1.generateCli)({
224
+ tables,
225
+ customOperations: {
226
+ queries: customOperations.queries,
227
+ mutations: customOperations.mutations,
228
+ },
229
+ config,
230
+ });
231
+ filesToWrite.push(...files.map((file) => ({
232
+ path: node_path_1.default.posix.join('cli', file.fileName),
233
+ content: file.content,
234
+ })));
235
+ }
145
236
  // Generate barrel file at output root
146
- // This re-exports from the appropriate subdirectories based on which generators are enabled
147
237
  const barrelContent = (0, barrel_1.generateRootBarrel)({
148
238
  hasTypes: bothEnabled,
149
239
  hasHooks: runReactQuery,
150
240
  hasOrm: runOrm,
241
+ hasCli: runCli,
151
242
  });
152
243
  filesToWrite.push({ path: 'index.ts', content: barrelContent });
244
+ // Generate docs for each enabled generator
245
+ const docsConfig = (0, docs_utils_1.resolveDocsConfig)(config.docs);
246
+ const allCustomOps = [
247
+ ...(customOperations.queries ?? []),
248
+ ...(customOperations.mutations ?? []),
249
+ ];
250
+ const allMcpTools = [];
251
+ if (runOrm) {
252
+ if (docsConfig.readme) {
253
+ const readme = (0, docs_generator_2.generateOrmReadme)(tables, allCustomOps);
254
+ filesToWrite.push({ path: node_path_1.default.posix.join('orm', readme.fileName), content: readme.content });
255
+ }
256
+ if (docsConfig.agents) {
257
+ const agents = (0, docs_generator_2.generateOrmAgentsDocs)(tables, allCustomOps);
258
+ filesToWrite.push({ path: node_path_1.default.posix.join('orm', agents.fileName), content: agents.content });
259
+ }
260
+ if (docsConfig.mcp) {
261
+ allMcpTools.push(...(0, docs_generator_2.getOrmMcpTools)(tables, allCustomOps));
262
+ }
263
+ if (docsConfig.skills) {
264
+ for (const skill of (0, docs_generator_2.generateOrmSkills)(tables, allCustomOps)) {
265
+ filesToWrite.push({ path: node_path_1.default.posix.join('orm', skill.fileName), content: skill.content });
266
+ }
267
+ }
268
+ }
269
+ if (runReactQuery) {
270
+ if (docsConfig.readme) {
271
+ const readme = (0, hooks_docs_generator_1.generateHooksReadme)(tables, allCustomOps);
272
+ filesToWrite.push({ path: node_path_1.default.posix.join('hooks', readme.fileName), content: readme.content });
273
+ }
274
+ if (docsConfig.agents) {
275
+ const agents = (0, hooks_docs_generator_1.generateHooksAgentsDocs)(tables, allCustomOps);
276
+ filesToWrite.push({ path: node_path_1.default.posix.join('hooks', agents.fileName), content: agents.content });
277
+ }
278
+ if (docsConfig.mcp) {
279
+ allMcpTools.push(...(0, hooks_docs_generator_1.getHooksMcpTools)(tables, allCustomOps));
280
+ }
281
+ if (docsConfig.skills) {
282
+ for (const skill of (0, hooks_docs_generator_1.generateHooksSkills)(tables, allCustomOps)) {
283
+ filesToWrite.push({ path: node_path_1.default.posix.join('hooks', skill.fileName), content: skill.content });
284
+ }
285
+ }
286
+ }
287
+ if (runCli) {
288
+ const toolName = typeof config.cli === 'object' && config.cli?.toolName
289
+ ? config.cli.toolName
290
+ : 'app';
291
+ if (docsConfig.readme) {
292
+ const readme = (0, docs_generator_1.generateReadme)(tables, allCustomOps, toolName);
293
+ filesToWrite.push({ path: node_path_1.default.posix.join('cli', readme.fileName), content: readme.content });
294
+ }
295
+ if (docsConfig.agents) {
296
+ const agents = (0, docs_generator_1.generateAgentsDocs)(tables, allCustomOps, toolName);
297
+ filesToWrite.push({ path: node_path_1.default.posix.join('cli', agents.fileName), content: agents.content });
298
+ }
299
+ if (docsConfig.mcp) {
300
+ allMcpTools.push(...(0, docs_generator_1.getCliMcpTools)(tables, allCustomOps, toolName));
301
+ }
302
+ if (docsConfig.skills) {
303
+ for (const skill of (0, docs_generator_1.generateSkills)(tables, allCustomOps, toolName)) {
304
+ filesToWrite.push({ path: node_path_1.default.posix.join('cli', skill.fileName), content: skill.content });
305
+ }
306
+ }
307
+ }
308
+ // Generate combined mcp.json at output root
309
+ if (docsConfig.mcp && allMcpTools.length > 0) {
310
+ const mcpName = typeof config.cli === 'object' && config.cli?.toolName
311
+ ? config.cli.toolName
312
+ : 'graphql-sdk';
313
+ const mcpFile = (0, target_docs_generator_1.generateCombinedMcpConfig)(allMcpTools, mcpName);
314
+ filesToWrite.push({ path: mcpFile.fileName, content: mcpFile.content });
315
+ }
316
+ // Generate per-target README at output root
317
+ if (docsConfig.readme) {
318
+ const targetReadme = (0, target_docs_generator_1.generateTargetReadme)({
319
+ hasOrm: runOrm,
320
+ hasHooks: runReactQuery,
321
+ hasCli: runCli,
322
+ tableCount: tables.length,
323
+ customQueryCount: customOperations.queries.length,
324
+ customMutationCount: customOperations.mutations.length,
325
+ config,
326
+ });
327
+ filesToWrite.push({ path: targetReadme.fileName, content: targetReadme.content });
328
+ }
153
329
  if (!options.dryRun) {
154
330
  const writeResult = await (0, output_1.writeGeneratedFiles)(filesToWrite, outputRoot, [], {
155
331
  pruneStaleFiles: true,
@@ -164,7 +340,11 @@ async function generate(options = {}) {
164
340
  }
165
341
  allFilesWritten.push(...(writeResult.filesWritten ?? []));
166
342
  }
167
- const generators = [runReactQuery && 'React Query', runOrm && 'ORM']
343
+ const generators = [
344
+ runReactQuery && 'React Query',
345
+ runOrm && 'ORM',
346
+ runCli && 'CLI',
347
+ ]
168
348
  .filter(Boolean)
169
349
  .join(' and ');
170
350
  return {
@@ -175,5 +355,266 @@ async function generate(options = {}) {
175
355
  output: outputRoot,
176
356
  tables: tables.map((t) => t.name),
177
357
  filesWritten: allFilesWritten,
358
+ pipelineData: {
359
+ tables,
360
+ customOperations: {
361
+ queries: customOperations.queries,
362
+ mutations: customOperations.mutations,
363
+ },
364
+ },
365
+ };
366
+ }
367
+ function expandApiNamesToMultiTarget(config) {
368
+ const apiNames = config.db?.apiNames;
369
+ if (!apiNames || apiNames.length <= 1)
370
+ return null;
371
+ const targets = {};
372
+ for (const apiName of apiNames) {
373
+ targets[apiName] = {
374
+ ...config,
375
+ db: {
376
+ ...config.db,
377
+ apiNames: [apiName],
378
+ },
379
+ output: config.output
380
+ ? `${config.output}/${apiName}`
381
+ : `./generated/graphql/${apiName}`,
382
+ };
383
+ }
384
+ return targets;
385
+ }
386
+ function expandSchemaDirToMultiTarget(config) {
387
+ const schemaDir = config.schemaDir;
388
+ if (!schemaDir)
389
+ return null;
390
+ const resolvedDir = node_path_1.default.resolve(schemaDir);
391
+ if (!fs.existsSync(resolvedDir) || !fs.statSync(resolvedDir).isDirectory()) {
392
+ return null;
393
+ }
394
+ const graphqlFiles = fs.readdirSync(resolvedDir)
395
+ .filter((f) => f.endsWith('.graphql'))
396
+ .sort();
397
+ if (graphqlFiles.length === 0)
398
+ return null;
399
+ const targets = {};
400
+ for (const file of graphqlFiles) {
401
+ const name = node_path_1.default.basename(file, '.graphql');
402
+ targets[name] = {
403
+ ...config,
404
+ schemaDir: undefined,
405
+ schemaFile: node_path_1.default.join(resolvedDir, file),
406
+ output: config.output
407
+ ? `${config.output}/${name}`
408
+ : `./generated/graphql/${name}`,
409
+ };
410
+ }
411
+ return targets;
412
+ }
413
+ function getPgpmSourceKey(pgpm) {
414
+ if (pgpm.modulePath)
415
+ return `module:${node_path_1.default.resolve(pgpm.modulePath)}`;
416
+ if (pgpm.workspacePath && pgpm.moduleName)
417
+ return `workspace:${node_path_1.default.resolve(pgpm.workspacePath)}:${pgpm.moduleName}`;
418
+ return null;
419
+ }
420
+ function getModulePathFromPgpm(pgpm) {
421
+ if (pgpm.modulePath)
422
+ return pgpm.modulePath;
423
+ if (pgpm.workspacePath && pgpm.moduleName) {
424
+ const workspace = new core_1.PgpmPackage(pgpm.workspacePath);
425
+ const moduleProject = workspace.getModuleProject(pgpm.moduleName);
426
+ const modulePath = moduleProject.getModulePath();
427
+ if (!modulePath) {
428
+ throw new Error(`Module "${pgpm.moduleName}" not found in workspace`);
429
+ }
430
+ return modulePath;
431
+ }
432
+ throw new Error('Invalid PGPM config: requires modulePath or workspacePath+moduleName');
433
+ }
434
+ async function prepareSharedPgpmSources(configs, cliOverrides) {
435
+ const sharedSources = new Map();
436
+ const pgpmTargetCount = new Map();
437
+ for (const name of Object.keys(configs)) {
438
+ const merged = { ...configs[name], ...(cliOverrides ?? {}) };
439
+ const pgpm = merged.db?.pgpm;
440
+ if (!pgpm)
441
+ continue;
442
+ const key = getPgpmSourceKey(pgpm);
443
+ if (!key)
444
+ continue;
445
+ pgpmTargetCount.set(key, (pgpmTargetCount.get(key) ?? 0) + 1);
446
+ }
447
+ for (const [key, count] of pgpmTargetCount) {
448
+ if (count < 2)
449
+ continue;
450
+ let pgpmConfig;
451
+ for (const name of Object.keys(configs)) {
452
+ const merged = { ...configs[name], ...(cliOverrides ?? {}) };
453
+ const pgpm = merged.db?.pgpm;
454
+ if (pgpm && getPgpmSourceKey(pgpm) === key) {
455
+ pgpmConfig = pgpm;
456
+ break;
457
+ }
458
+ }
459
+ if (!pgpmConfig)
460
+ continue;
461
+ const ephemeralDb = (0, pgsql_client_1.createEphemeralDb)({
462
+ prefix: 'codegen_pgpm_shared_',
463
+ verbose: false,
464
+ });
465
+ const modulePath = getModulePathFromPgpm(pgpmConfig);
466
+ await (0, pgsql_seed_1.deployPgpm)(ephemeralDb.config, modulePath, false);
467
+ sharedSources.set(key, {
468
+ key,
469
+ ephemeralDb,
470
+ deployed: true,
471
+ });
472
+ console.log(`[multi-target] Shared PGPM source deployed once for ${count} targets: ${key}`);
473
+ }
474
+ return sharedSources;
475
+ }
476
+ function applySharedPgpmDb(config, sharedSources) {
477
+ const pgpm = config.db?.pgpm;
478
+ if (!pgpm)
479
+ return config;
480
+ const key = getPgpmSourceKey(pgpm);
481
+ if (!key)
482
+ return config;
483
+ const shared = sharedSources.get(key);
484
+ if (!shared)
485
+ return config;
486
+ const sharedDbConfig = {
487
+ ...config.db,
488
+ pgpm: undefined,
489
+ config: shared.ephemeralDb.config,
490
+ keepDb: true,
491
+ };
492
+ return {
493
+ ...config,
494
+ db: sharedDbConfig,
178
495
  };
179
496
  }
497
+ async function generateMulti(options) {
498
+ const { configs, cliOverrides, verbose, dryRun, schemaOnly, unifiedCli } = options;
499
+ const names = Object.keys(configs);
500
+ const results = [];
501
+ let hasError = false;
502
+ const targetInfos = [];
503
+ const useUnifiedCli = !schemaOnly && !!unifiedCli && names.length > 1;
504
+ const cliTargets = [];
505
+ const sharedSources = await prepareSharedPgpmSources(configs, cliOverrides);
506
+ try {
507
+ for (const name of names) {
508
+ const baseConfig = {
509
+ ...configs[name],
510
+ ...(cliOverrides ?? {}),
511
+ };
512
+ const targetConfig = applySharedPgpmDb(baseConfig, sharedSources);
513
+ const result = await generate({
514
+ ...targetConfig,
515
+ verbose,
516
+ dryRun,
517
+ schemaOnly,
518
+ schemaOnlyFilename: schemaOnly ? `${name}.graphql` : undefined,
519
+ }, useUnifiedCli ? { skipCli: true } : undefined);
520
+ results.push({ name, result });
521
+ if (!result.success) {
522
+ hasError = true;
523
+ }
524
+ else {
525
+ const resolvedConfig = (0, config_1.getConfigOptions)(targetConfig);
526
+ const gens = [];
527
+ if (resolvedConfig.reactQuery)
528
+ gens.push('React Query');
529
+ if (resolvedConfig.orm || resolvedConfig.reactQuery || !!resolvedConfig.cli)
530
+ gens.push('ORM');
531
+ if (resolvedConfig.cli)
532
+ gens.push('CLI');
533
+ targetInfos.push({
534
+ name,
535
+ output: resolvedConfig.output,
536
+ endpoint: resolvedConfig.endpoint || undefined,
537
+ generators: gens,
538
+ });
539
+ if (useUnifiedCli && result.pipelineData) {
540
+ const isAuthTarget = name === 'auth';
541
+ cliTargets.push({
542
+ name,
543
+ endpoint: resolvedConfig.endpoint || '',
544
+ ormImportPath: `../${resolvedConfig.output.replace(/^\.\//, '')}/orm`,
545
+ tables: result.pipelineData.tables,
546
+ customOperations: result.pipelineData.customOperations,
547
+ isAuthTarget,
548
+ });
549
+ }
550
+ }
551
+ }
552
+ if (useUnifiedCli && cliTargets.length > 0 && !dryRun) {
553
+ const cliConfig = typeof unifiedCli === 'object' ? unifiedCli : {};
554
+ const toolName = cliConfig.toolName ?? 'app';
555
+ const { files } = (0, cli_1.generateMultiTargetCli)({
556
+ toolName,
557
+ builtinNames: cliConfig.builtinNames,
558
+ targets: cliTargets,
559
+ });
560
+ const cliFilesToWrite = files.map((file) => ({
561
+ path: node_path_1.default.posix.join('cli', file.fileName),
562
+ content: file.content,
563
+ }));
564
+ const firstTargetDocsConfig = names.length > 0 && configs[names[0]]?.docs;
565
+ const docsConfig = (0, docs_utils_1.resolveDocsConfig)(firstTargetDocsConfig);
566
+ const { resolveBuiltinNames } = await Promise.resolve().then(() => __importStar(require('./codegen/cli')));
567
+ const builtinNames = resolveBuiltinNames(cliTargets.map((t) => t.name), cliConfig.builtinNames);
568
+ const docsInput = {
569
+ toolName,
570
+ builtinNames,
571
+ targets: cliTargets.map((t) => ({
572
+ name: t.name,
573
+ endpoint: t.endpoint,
574
+ tables: t.tables,
575
+ customOperations: [
576
+ ...(t.customOperations?.queries ?? []),
577
+ ...(t.customOperations?.mutations ?? []),
578
+ ],
579
+ isAuthTarget: t.isAuthTarget,
580
+ })),
581
+ };
582
+ const allMcpTools = [];
583
+ if (docsConfig.readme) {
584
+ const readme = (0, docs_generator_1.generateMultiTargetReadme)(docsInput);
585
+ cliFilesToWrite.push({ path: node_path_1.default.posix.join('cli', readme.fileName), content: readme.content });
586
+ }
587
+ if (docsConfig.agents) {
588
+ const agents = (0, docs_generator_1.generateMultiTargetAgentsDocs)(docsInput);
589
+ cliFilesToWrite.push({ path: node_path_1.default.posix.join('cli', agents.fileName), content: agents.content });
590
+ }
591
+ if (docsConfig.mcp) {
592
+ allMcpTools.push(...(0, docs_generator_1.getMultiTargetCliMcpTools)(docsInput));
593
+ }
594
+ if (docsConfig.skills) {
595
+ for (const skill of (0, docs_generator_1.generateMultiTargetSkills)(docsInput)) {
596
+ cliFilesToWrite.push({ path: node_path_1.default.posix.join('cli', skill.fileName), content: skill.content });
597
+ }
598
+ }
599
+ if (docsConfig.mcp && allMcpTools.length > 0) {
600
+ const mcpFile = (0, target_docs_generator_1.generateCombinedMcpConfig)(allMcpTools, toolName);
601
+ cliFilesToWrite.push({ path: node_path_1.default.posix.join('cli', mcpFile.fileName), content: mcpFile.content });
602
+ }
603
+ const { writeGeneratedFiles: writeFiles } = await Promise.resolve().then(() => __importStar(require('./output')));
604
+ await writeFiles(cliFilesToWrite, '.', [], { pruneStaleFiles: false });
605
+ }
606
+ // Generate root-root README if multi-target
607
+ if (names.length > 1 && targetInfos.length > 0 && !dryRun) {
608
+ const rootReadme = (0, target_docs_generator_1.generateRootRootReadme)(targetInfos);
609
+ const { writeGeneratedFiles: writeFiles } = await Promise.resolve().then(() => __importStar(require('./output')));
610
+ await writeFiles([{ path: rootReadme.fileName, content: rootReadme.content }], '.', [], { pruneStaleFiles: false });
611
+ }
612
+ }
613
+ finally {
614
+ for (const shared of sharedSources.values()) {
615
+ const keepDb = Object.values(configs).some((c) => c.db?.keepDb);
616
+ shared.ephemeralDb.teardown({ keepDb });
617
+ }
618
+ }
619
+ return { results, hasError };
620
+ }
package/core/index.d.ts CHANGED
@@ -9,9 +9,7 @@ export { generate } from './generate';
9
9
  export * from './types';
10
10
  export * from './ast';
11
11
  export * from './custom-ast';
12
- /** @deprecated Legacy v4 query builder — use v5 ORM codegen instead */
13
12
  export { MetaObject, QueryBuilder } from './query-builder';
14
- /** @deprecated Legacy v4 meta-object utilities — v5 uses standard introspection */
15
13
  export { convertFromMetaSchema, validateMetaObject } from './meta-object';
16
14
  export * from './config';
17
15
  export * from './codegen';
package/core/index.js CHANGED
@@ -29,12 +29,10 @@ __exportStar(require("./types"), exports);
29
29
  __exportStar(require("./ast"), exports);
30
30
  __exportStar(require("./custom-ast"), exports);
31
31
  // Query builder
32
- /** @deprecated Legacy v4 query builder — use v5 ORM codegen instead */
33
32
  var query_builder_1 = require("./query-builder");
34
33
  Object.defineProperty(exports, "MetaObject", { enumerable: true, get: function () { return query_builder_1.MetaObject; } });
35
34
  Object.defineProperty(exports, "QueryBuilder", { enumerable: true, get: function () { return query_builder_1.QueryBuilder; } });
36
35
  // Meta object utilities
37
- /** @deprecated Legacy v4 meta-object utilities — v5 uses standard introspection */
38
36
  var meta_object_1 = require("./meta-object");
39
37
  Object.defineProperty(exports, "convertFromMetaSchema", { enumerable: true, get: function () { return meta_object_1.convertFromMetaSchema; } });
40
38
  Object.defineProperty(exports, "validateMetaObject", { enumerable: true, get: function () { return meta_object_1.validateMetaObject; } });
@@ -8,7 +8,7 @@ exports.DatabaseSchemaSource = void 0;
8
8
  * introspection and converts it to introspection format.
9
9
  */
10
10
  const graphql_1 = require("graphql");
11
- const database_1 = require("../../database");
11
+ const graphile_schema_1 = require("graphile-schema");
12
12
  const api_schemas_1 = require("./api-schemas");
13
13
  const types_1 = require("./types");
14
14
  /**
@@ -48,7 +48,7 @@ class DatabaseSchemaSource {
48
48
  // Build SDL from database
49
49
  let sdl;
50
50
  try {
51
- sdl = await (0, database_1.buildSchemaSDLFromDatabase)({
51
+ sdl = await (0, graphile_schema_1.buildSchemaSDL)({
52
52
  database,
53
53
  schemas,
54
54
  });
@@ -17,7 +17,7 @@ const graphql_1 = require("graphql");
17
17
  const pg_cache_1 = require("pg-cache");
18
18
  const pgsql_client_1 = require("pgsql-client");
19
19
  const pgsql_seed_1 = require("pgsql-seed");
20
- const database_1 = require("../../database");
20
+ const graphile_schema_1 = require("graphile-schema");
21
21
  const api_schemas_1 = require("./api-schemas");
22
22
  const types_1 = require("./types");
23
23
  /**
@@ -103,7 +103,7 @@ class PgpmModuleSchemaSource {
103
103
  // Build SDL from the deployed database
104
104
  let sdl;
105
105
  try {
106
- sdl = await (0, database_1.buildSchemaSDLFromDatabase)({
106
+ sdl = await (0, graphile_schema_1.buildSchemaSDL)({
107
107
  database: dbConfig.database,
108
108
  schemas,
109
109
  });
@@ -1,4 +1,4 @@
1
1
  /**
2
2
  * Output module exports
3
3
  */
4
- export { formatOutput, type GeneratedFile, writeGeneratedFiles, type WriteOptions, type WriteResult, } from './writer';
4
+ export { type GeneratedFile, writeGeneratedFiles, type WriteOptions, type WriteResult, } from './writer';
@@ -3,7 +3,6 @@
3
3
  * Output module exports
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.writeGeneratedFiles = exports.formatOutput = void 0;
6
+ exports.writeGeneratedFiles = void 0;
7
7
  var writer_1 = require("./writer");
8
- Object.defineProperty(exports, "formatOutput", { enumerable: true, get: function () { return writer_1.formatOutput; } });
9
8
  Object.defineProperty(exports, "writeGeneratedFiles", { enumerable: true, get: function () { return writer_1.writeGeneratedFiles; } });
@@ -29,13 +29,3 @@ export interface WriteOptions {
29
29
  * @param options - Write options
30
30
  */
31
31
  export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[], options?: WriteOptions): Promise<WriteResult>;
32
- /**
33
- * Format generated files using oxfmt programmatically
34
- *
35
- * @deprecated Use writeGeneratedFiles with formatFiles option instead.
36
- * This function is kept for backwards compatibility.
37
- */
38
- export declare function formatOutput(outputDir: string): Promise<{
39
- success: boolean;
40
- error?: string;
41
- }>;
@@ -34,7 +34,6 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.writeGeneratedFiles = writeGeneratedFiles;
37
- exports.formatOutput = formatOutput;
38
37
  /**
39
38
  * File writing utilities
40
39
  *
@@ -205,33 +204,3 @@ function findTsFiles(dir) {
205
204
  }
206
205
  return files;
207
206
  }
208
- /**
209
- * Format generated files using oxfmt programmatically
210
- *
211
- * @deprecated Use writeGeneratedFiles with formatFiles option instead.
212
- * This function is kept for backwards compatibility.
213
- */
214
- async function formatOutput(outputDir) {
215
- const formatFn = await getOxfmtFormat();
216
- if (!formatFn) {
217
- return {
218
- success: false,
219
- error: 'oxfmt not available. Install it with: npm install oxfmt',
220
- };
221
- }
222
- const absoluteOutputDir = path.resolve(outputDir);
223
- try {
224
- // Find all .ts files in the output directory
225
- const tsFiles = findTsFiles(absoluteOutputDir);
226
- for (const filePath of tsFiles) {
227
- const content = fs.readFileSync(filePath, 'utf-8');
228
- const formatted = await formatFileContent(path.basename(filePath), content, formatFn);
229
- fs.writeFileSync(filePath, formatted, 'utf-8');
230
- }
231
- return { success: true };
232
- }
233
- catch (err) {
234
- const message = err instanceof Error ? err.message : String(err);
235
- return { success: false, error: message };
236
- }
237
- }
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Shared codegen CLI handler
3
+ *
4
+ * Contains the core logic used by both `graphql-codegen` and `cnc codegen`.
5
+ * Both CLIs delegate to runCodegenHandler() after handling their own
6
+ * help/version flags.
7
+ */
8
+ import type { Question } from 'inquirerer';
9
+ interface Prompter {
10
+ prompt(argv: Record<string, unknown>, questions: Question[]): Promise<Record<string, unknown>>;
11
+ }
12
+ export declare function runCodegenHandler(argv: Record<string, unknown>, prompter: Prompter): Promise<void>;
13
+ export {};