@constructive-io/graphql-codegen 4.0.2 → 4.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/handler.d.ts +13 -0
- package/cli/handler.js +74 -0
- package/cli/index.js +11 -57
- package/core/codegen/barrel.d.ts +1 -0
- package/core/codegen/barrel.js +5 -2
- package/core/codegen/cli/arg-mapper.d.ts +4 -0
- package/core/codegen/cli/arg-mapper.js +117 -0
- package/core/codegen/cli/command-map-generator.d.ts +16 -0
- package/core/codegen/cli/command-map-generator.js +338 -0
- package/core/codegen/cli/custom-command-generator.d.ts +8 -0
- package/core/codegen/cli/custom-command-generator.js +155 -0
- package/core/codegen/cli/docs-generator.d.ts +26 -0
- package/core/codegen/cli/docs-generator.js +1399 -0
- package/core/codegen/cli/executor-generator.d.ts +11 -0
- package/core/codegen/cli/executor-generator.js +217 -0
- package/core/codegen/cli/index.d.ts +53 -0
- package/core/codegen/cli/index.js +153 -0
- package/core/codegen/cli/infra-generator.d.ts +9 -0
- package/core/codegen/cli/infra-generator.js +1195 -0
- package/core/codegen/cli/table-command-generator.d.ts +7 -0
- package/core/codegen/cli/table-command-generator.js +323 -0
- package/core/codegen/docs-utils.d.ts +30 -0
- package/core/codegen/docs-utils.js +122 -0
- package/core/codegen/hooks-docs-generator.d.ts +6 -0
- package/core/codegen/hooks-docs-generator.js +468 -0
- package/core/codegen/orm/docs-generator.d.ts +6 -0
- package/core/codegen/orm/docs-generator.js +416 -0
- package/core/codegen/target-docs-generator.d.ts +20 -0
- package/core/codegen/target-docs-generator.js +110 -0
- package/core/database/index.d.ts +0 -12
- package/core/database/index.js +2 -19
- package/core/generate.d.ts +34 -2
- package/core/generate.js +453 -12
- package/core/index.d.ts +0 -2
- package/core/index.js +0 -2
- package/core/introspect/source/database.js +2 -2
- package/core/introspect/source/pgpm-module.js +2 -2
- package/core/output/index.d.ts +1 -1
- package/core/output/index.js +1 -2
- package/core/output/writer.d.ts +0 -10
- package/core/output/writer.js +0 -31
- package/esm/cli/handler.d.ts +13 -0
- package/esm/cli/handler.js +71 -0
- package/esm/cli/index.js +11 -57
- package/esm/core/codegen/barrel.d.ts +1 -0
- package/esm/core/codegen/barrel.js +5 -2
- package/esm/core/codegen/cli/arg-mapper.d.ts +4 -0
- package/esm/core/codegen/cli/arg-mapper.js +80 -0
- package/esm/core/codegen/cli/command-map-generator.d.ts +16 -0
- package/esm/core/codegen/cli/command-map-generator.js +301 -0
- package/esm/core/codegen/cli/custom-command-generator.d.ts +8 -0
- package/esm/core/codegen/cli/custom-command-generator.js +119 -0
- package/esm/core/codegen/cli/docs-generator.d.ts +26 -0
- package/esm/core/codegen/cli/docs-generator.js +1387 -0
- package/esm/core/codegen/cli/executor-generator.d.ts +11 -0
- package/esm/core/codegen/cli/executor-generator.js +180 -0
- package/esm/core/codegen/cli/index.d.ts +53 -0
- package/esm/core/codegen/cli/index.js +128 -0
- package/esm/core/codegen/cli/infra-generator.d.ts +9 -0
- package/esm/core/codegen/cli/infra-generator.js +1156 -0
- package/esm/core/codegen/cli/table-command-generator.d.ts +7 -0
- package/esm/core/codegen/cli/table-command-generator.js +287 -0
- package/esm/core/codegen/docs-utils.d.ts +30 -0
- package/esm/core/codegen/docs-utils.js +112 -0
- package/esm/core/codegen/hooks-docs-generator.d.ts +6 -0
- package/esm/core/codegen/hooks-docs-generator.js +462 -0
- package/esm/core/codegen/orm/docs-generator.d.ts +6 -0
- package/esm/core/codegen/orm/docs-generator.js +410 -0
- package/esm/core/codegen/target-docs-generator.d.ts +20 -0
- package/esm/core/codegen/target-docs-generator.js +105 -0
- package/esm/core/database/index.d.ts +0 -12
- package/esm/core/database/index.js +1 -17
- package/esm/core/generate.d.ts +34 -2
- package/esm/core/generate.js +417 -12
- package/esm/core/index.d.ts +0 -2
- package/esm/core/index.js +0 -2
- package/esm/core/introspect/source/database.js +2 -2
- package/esm/core/introspect/source/pgpm-module.js +2 -2
- package/esm/core/output/index.d.ts +1 -1
- package/esm/core/output/index.js +1 -1
- package/esm/core/output/writer.d.ts +0 -10
- package/esm/core/output/writer.js +0 -30
- package/esm/generators/index.d.ts +0 -3
- package/esm/generators/index.js +0 -3
- package/esm/index.d.ts +4 -3
- package/esm/index.js +4 -2
- package/esm/types/config.d.ts +78 -0
- package/generators/index.d.ts +0 -3
- package/generators/index.js +0 -3
- package/index.d.ts +4 -3
- package/index.js +7 -2
- package/package.json +8 -7
- 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
|
|
37
|
-
|
|
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
|
|
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 = [
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
106
|
+
sdl = await (0, graphile_schema_1.buildSchemaSDL)({
|
|
107
107
|
database: dbConfig.database,
|
|
108
108
|
schemas,
|
|
109
109
|
});
|
package/core/output/index.d.ts
CHANGED
package/core/output/index.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
* Output module exports
|
|
4
4
|
*/
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.writeGeneratedFiles =
|
|
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; } });
|
package/core/output/writer.d.ts
CHANGED
|
@@ -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
|
-
}>;
|
package/core/output/writer.js
CHANGED
|
@@ -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 {};
|