@constructive-io/graphql-codegen 2.27.2 → 2.27.3
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/index.d.ts +5 -1
- package/cli/index.js +345 -146
- package/esm/cli/index.d.ts +5 -1
- package/esm/cli/index.js +343 -146
- package/package.json +7 -3
package/cli/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
/**
|
|
2
3
|
* CLI entry point for graphql-codegen
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
+
import { CLIOptions, Inquirerer } from 'inquirerer';
|
|
6
|
+
import { ParsedArgs } from 'minimist';
|
|
7
|
+
export declare const commands: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
|
|
8
|
+
export declare const options: Partial<CLIOptions>;
|
package/cli/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
"use strict";
|
|
2
3
|
/**
|
|
3
4
|
* CLI entry point for graphql-codegen
|
|
@@ -36,12 +37,104 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
36
37
|
};
|
|
37
38
|
})();
|
|
38
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
|
|
40
|
+
exports.options = exports.commands = void 0;
|
|
41
|
+
const find_and_require_package_json_1 = require("find-and-require-package-json");
|
|
42
|
+
const utils_1 = require("@inquirerer/utils");
|
|
43
|
+
const inquirerer_1 = require("inquirerer");
|
|
40
44
|
const init_1 = require("./commands/init");
|
|
41
45
|
const generate_1 = require("./commands/generate");
|
|
42
46
|
const generate_orm_1 = require("./commands/generate-orm");
|
|
43
47
|
const watch_1 = require("./watch");
|
|
44
48
|
const config_1 = require("../types/config");
|
|
49
|
+
const usageText = `
|
|
50
|
+
graphql-codegen - CLI for generating GraphQL SDK from PostGraphile endpoints or schema files
|
|
51
|
+
|
|
52
|
+
Usage:
|
|
53
|
+
graphql-codegen <command> [options]
|
|
54
|
+
|
|
55
|
+
Commands:
|
|
56
|
+
init Initialize a new graphql-codegen configuration file
|
|
57
|
+
generate Generate SDK from GraphQL endpoint or schema file
|
|
58
|
+
generate-orm Generate Prisma-like ORM client from GraphQL endpoint or schema file
|
|
59
|
+
introspect Introspect a GraphQL endpoint or schema file and print table info
|
|
60
|
+
|
|
61
|
+
Options:
|
|
62
|
+
--help, -h Show this help message
|
|
63
|
+
--version, -v Show version number
|
|
64
|
+
|
|
65
|
+
Run 'graphql-codegen <command> --help' for more information on a command.
|
|
66
|
+
`;
|
|
67
|
+
const initUsageText = `
|
|
68
|
+
graphql-codegen init - Initialize a new graphql-codegen configuration file
|
|
69
|
+
|
|
70
|
+
Usage:
|
|
71
|
+
graphql-codegen init [options]
|
|
72
|
+
|
|
73
|
+
Options:
|
|
74
|
+
--directory, -d <dir> Target directory for the config file (default: .)
|
|
75
|
+
--force, -f Force overwrite existing config
|
|
76
|
+
--endpoint, -e <url> GraphQL endpoint URL to pre-populate
|
|
77
|
+
--output, -o <dir> Output directory to pre-populate (default: ./generated)
|
|
78
|
+
--help, -h Show this help message
|
|
79
|
+
`;
|
|
80
|
+
const generateUsageText = `
|
|
81
|
+
graphql-codegen generate - Generate SDK from GraphQL endpoint or schema file
|
|
82
|
+
|
|
83
|
+
Usage:
|
|
84
|
+
graphql-codegen generate [options]
|
|
85
|
+
|
|
86
|
+
Options:
|
|
87
|
+
--config, -c <path> Path to config file
|
|
88
|
+
--target, -t <name> Target name in config file
|
|
89
|
+
--endpoint, -e <url> GraphQL endpoint URL (overrides config)
|
|
90
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
91
|
+
--output, -o <dir> Output directory (overrides config)
|
|
92
|
+
--authorization, -a <header> Authorization header value
|
|
93
|
+
--verbose, -v Verbose output
|
|
94
|
+
--dry-run Dry run - show what would be generated without writing files
|
|
95
|
+
--watch, -w Watch mode - poll endpoint for schema changes (in-memory)
|
|
96
|
+
--poll-interval <ms> Polling interval in milliseconds (default: 3000)
|
|
97
|
+
--debounce <ms> Debounce delay before regenerating (default: 800)
|
|
98
|
+
--touch <file> File to touch on schema change
|
|
99
|
+
--no-clear Do not clear terminal on regeneration
|
|
100
|
+
--help, -h Show this help message
|
|
101
|
+
`;
|
|
102
|
+
const generateOrmUsageText = `
|
|
103
|
+
graphql-codegen generate-orm - Generate Prisma-like ORM client from GraphQL endpoint or schema file
|
|
104
|
+
|
|
105
|
+
Usage:
|
|
106
|
+
graphql-codegen generate-orm [options]
|
|
107
|
+
|
|
108
|
+
Options:
|
|
109
|
+
--config, -c <path> Path to config file
|
|
110
|
+
--target, -t <name> Target name in config file
|
|
111
|
+
--endpoint, -e <url> GraphQL endpoint URL (overrides config)
|
|
112
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
113
|
+
--output, -o <dir> Output directory (overrides config)
|
|
114
|
+
--authorization, -a <header> Authorization header value
|
|
115
|
+
--verbose, -v Verbose output
|
|
116
|
+
--dry-run Dry run - show what would be generated without writing files
|
|
117
|
+
--skip-custom-operations Skip custom operations (only generate table CRUD)
|
|
118
|
+
--watch, -w Watch mode - poll endpoint for schema changes (in-memory)
|
|
119
|
+
--poll-interval <ms> Polling interval in milliseconds (default: 3000)
|
|
120
|
+
--debounce <ms> Debounce delay before regenerating (default: 800)
|
|
121
|
+
--touch <file> File to touch on schema change
|
|
122
|
+
--no-clear Do not clear terminal on regeneration
|
|
123
|
+
--help, -h Show this help message
|
|
124
|
+
`;
|
|
125
|
+
const introspectUsageText = `
|
|
126
|
+
graphql-codegen introspect - Introspect a GraphQL endpoint or schema file and print table info
|
|
127
|
+
|
|
128
|
+
Usage:
|
|
129
|
+
graphql-codegen introspect [options]
|
|
130
|
+
|
|
131
|
+
Options:
|
|
132
|
+
--endpoint, -e <url> GraphQL endpoint URL
|
|
133
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
134
|
+
--authorization, -a <header> Authorization header value
|
|
135
|
+
--json Output as JSON
|
|
136
|
+
--help, -h Show this help message
|
|
137
|
+
`;
|
|
45
138
|
/**
|
|
46
139
|
* Format duration in a human-readable way
|
|
47
140
|
* - Under 1 second: show milliseconds (e.g., "123ms")
|
|
@@ -53,12 +146,10 @@ function formatDuration(ms) {
|
|
|
53
146
|
}
|
|
54
147
|
return `${(ms / 1000).toFixed(2)}s`;
|
|
55
148
|
}
|
|
56
|
-
const program = new commander_1.Command();
|
|
57
149
|
/**
|
|
58
150
|
* Load configuration for watch mode, merging CLI options with config file
|
|
59
151
|
*/
|
|
60
152
|
async function loadWatchConfig(options) {
|
|
61
|
-
// Find config file
|
|
62
153
|
let configPath = options.config;
|
|
63
154
|
if (!configPath) {
|
|
64
155
|
configPath = (0, init_1.findConfigFile)() ?? undefined;
|
|
@@ -122,25 +213,20 @@ async function loadWatchConfig(options) {
|
|
|
122
213
|
}
|
|
123
214
|
return (0, config_1.resolveConfig)(mergedTarget);
|
|
124
215
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
.option('-d, --directory <dir>', 'Target directory for the config file', '.')
|
|
134
|
-
.option('-f, --force', 'Force overwrite existing config', false)
|
|
135
|
-
.option('-e, --endpoint <url>', 'GraphQL endpoint URL to pre-populate')
|
|
136
|
-
.option('-o, --output <dir>', 'Output directory to pre-populate', './generated')
|
|
137
|
-
.action(async (options) => {
|
|
216
|
+
/**
|
|
217
|
+
* Init command handler
|
|
218
|
+
*/
|
|
219
|
+
async function handleInit(argv) {
|
|
220
|
+
if (argv.help || argv.h) {
|
|
221
|
+
console.log(initUsageText);
|
|
222
|
+
process.exit(0);
|
|
223
|
+
}
|
|
138
224
|
const startTime = performance.now();
|
|
139
225
|
const result = await (0, init_1.initCommand)({
|
|
140
|
-
directory:
|
|
141
|
-
force:
|
|
142
|
-
endpoint:
|
|
143
|
-
output:
|
|
226
|
+
directory: argv.directory || argv.d || '.',
|
|
227
|
+
force: !!(argv.force || argv.f),
|
|
228
|
+
endpoint: argv.endpoint || argv.e,
|
|
229
|
+
output: argv.output || argv.o || './generated',
|
|
144
230
|
});
|
|
145
231
|
const duration = formatDuration(performance.now() - startTime);
|
|
146
232
|
if (result.success) {
|
|
@@ -150,62 +236,75 @@ program
|
|
|
150
236
|
console.error('x', result.message, `(${duration})`);
|
|
151
237
|
process.exit(1);
|
|
152
238
|
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
163
|
-
.option('-a, --authorization <header>', 'Authorization header value')
|
|
164
|
-
.option('-v, --verbose', 'Verbose output', false)
|
|
165
|
-
.option('--dry-run', 'Dry run - show what would be generated without writing files', false)
|
|
166
|
-
.option('-w, --watch', 'Watch mode - poll endpoint for schema changes (in-memory)', false)
|
|
167
|
-
.option('--poll-interval <ms>', 'Polling interval in milliseconds (default: 3000)', parseInt)
|
|
168
|
-
.option('--debounce <ms>', 'Debounce delay before regenerating (default: 800)', parseInt)
|
|
169
|
-
.option('--touch <file>', 'File to touch on schema change')
|
|
170
|
-
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
171
|
-
.action(async (options) => {
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Generate command handler
|
|
242
|
+
*/
|
|
243
|
+
async function handleGenerate(argv) {
|
|
244
|
+
if (argv.help || argv.h) {
|
|
245
|
+
console.log(generateUsageText);
|
|
246
|
+
process.exit(0);
|
|
247
|
+
}
|
|
172
248
|
const startTime = performance.now();
|
|
173
|
-
|
|
174
|
-
|
|
249
|
+
const config = argv.config || argv.c;
|
|
250
|
+
const target = argv.target || argv.t;
|
|
251
|
+
const endpoint = argv.endpoint || argv.e;
|
|
252
|
+
const schema = argv.schema || argv.s;
|
|
253
|
+
const output = argv.output || argv.o;
|
|
254
|
+
const authorization = argv.authorization || argv.a;
|
|
255
|
+
const verbose = !!(argv.verbose || argv.v);
|
|
256
|
+
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
257
|
+
const watch = !!(argv.watch || argv.w);
|
|
258
|
+
const pollInterval = argv['poll-interval'] !== undefined
|
|
259
|
+
? parseInt(argv['poll-interval'], 10)
|
|
260
|
+
: undefined;
|
|
261
|
+
const debounce = argv.debounce !== undefined
|
|
262
|
+
? parseInt(argv.debounce, 10)
|
|
263
|
+
: undefined;
|
|
264
|
+
const touch = argv.touch;
|
|
265
|
+
const clear = argv.clear !== false;
|
|
266
|
+
if (endpoint && schema) {
|
|
175
267
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
176
268
|
process.exit(1);
|
|
177
269
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
if (options.schema) {
|
|
270
|
+
if (watch) {
|
|
271
|
+
if (schema) {
|
|
181
272
|
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
182
273
|
process.exit(1);
|
|
183
274
|
}
|
|
184
|
-
const
|
|
185
|
-
|
|
275
|
+
const watchConfig = await loadWatchConfig({
|
|
276
|
+
config,
|
|
277
|
+
target,
|
|
278
|
+
endpoint,
|
|
279
|
+
output,
|
|
280
|
+
pollInterval,
|
|
281
|
+
debounce,
|
|
282
|
+
touch,
|
|
283
|
+
clear,
|
|
284
|
+
});
|
|
285
|
+
if (!watchConfig) {
|
|
186
286
|
process.exit(1);
|
|
187
287
|
}
|
|
188
288
|
await (0, watch_1.startWatch)({
|
|
189
|
-
config,
|
|
289
|
+
config: watchConfig,
|
|
190
290
|
generatorType: 'generate',
|
|
191
|
-
verbose
|
|
192
|
-
authorization
|
|
193
|
-
configPath:
|
|
194
|
-
target
|
|
195
|
-
outputDir:
|
|
291
|
+
verbose,
|
|
292
|
+
authorization,
|
|
293
|
+
configPath: config,
|
|
294
|
+
target,
|
|
295
|
+
outputDir: output,
|
|
196
296
|
});
|
|
197
297
|
return;
|
|
198
298
|
}
|
|
199
|
-
// Normal one-shot generation
|
|
200
299
|
const result = await (0, generate_1.generateCommand)({
|
|
201
|
-
config
|
|
202
|
-
target
|
|
203
|
-
endpoint
|
|
204
|
-
schema
|
|
205
|
-
output
|
|
206
|
-
authorization
|
|
207
|
-
verbose
|
|
208
|
-
dryRun
|
|
300
|
+
config,
|
|
301
|
+
target,
|
|
302
|
+
endpoint,
|
|
303
|
+
schema,
|
|
304
|
+
output,
|
|
305
|
+
authorization,
|
|
306
|
+
verbose,
|
|
307
|
+
dryRun,
|
|
209
308
|
});
|
|
210
309
|
const duration = formatDuration(performance.now() - startTime);
|
|
211
310
|
const targetResults = result.targets ?? [];
|
|
@@ -213,19 +312,19 @@ program
|
|
|
213
312
|
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
214
313
|
if (hasNamedTargets) {
|
|
215
314
|
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
216
|
-
targetResults.forEach((
|
|
217
|
-
const status =
|
|
218
|
-
console.log(`\n${status} ${
|
|
219
|
-
if (
|
|
315
|
+
targetResults.forEach((t) => {
|
|
316
|
+
const status = t.success ? '[ok]' : 'x';
|
|
317
|
+
console.log(`\n${status} ${t.message}`);
|
|
318
|
+
if (t.tables && t.tables.length > 0) {
|
|
220
319
|
console.log(' Tables:');
|
|
221
|
-
|
|
320
|
+
t.tables.forEach((table) => console.log(` - ${table}`));
|
|
222
321
|
}
|
|
223
|
-
if (
|
|
322
|
+
if (t.filesWritten && t.filesWritten.length > 0) {
|
|
224
323
|
console.log(' Files written:');
|
|
225
|
-
|
|
324
|
+
t.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
226
325
|
}
|
|
227
|
-
if (!
|
|
228
|
-
|
|
326
|
+
if (!t.success && t.errors) {
|
|
327
|
+
t.errors.forEach((error) => console.error(` - ${error}`));
|
|
229
328
|
}
|
|
230
329
|
});
|
|
231
330
|
if (!result.success) {
|
|
@@ -251,65 +350,78 @@ program
|
|
|
251
350
|
}
|
|
252
351
|
process.exit(1);
|
|
253
352
|
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
264
|
-
.option('-a, --authorization <header>', 'Authorization header value')
|
|
265
|
-
.option('-v, --verbose', 'Verbose output', false)
|
|
266
|
-
.option('--dry-run', 'Dry run - show what would be generated without writing files', false)
|
|
267
|
-
.option('--skip-custom-operations', 'Skip custom operations (only generate table CRUD)', false)
|
|
268
|
-
.option('-w, --watch', 'Watch mode - poll endpoint for schema changes (in-memory)', false)
|
|
269
|
-
.option('--poll-interval <ms>', 'Polling interval in milliseconds (default: 3000)', parseInt)
|
|
270
|
-
.option('--debounce <ms>', 'Debounce delay before regenerating (default: 800)', parseInt)
|
|
271
|
-
.option('--touch <file>', 'File to touch on schema change')
|
|
272
|
-
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
273
|
-
.action(async (options) => {
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Generate ORM command handler
|
|
356
|
+
*/
|
|
357
|
+
async function handleGenerateOrm(argv) {
|
|
358
|
+
if (argv.help || argv.h) {
|
|
359
|
+
console.log(generateOrmUsageText);
|
|
360
|
+
process.exit(0);
|
|
361
|
+
}
|
|
274
362
|
const startTime = performance.now();
|
|
275
|
-
|
|
276
|
-
|
|
363
|
+
const config = argv.config || argv.c;
|
|
364
|
+
const target = argv.target || argv.t;
|
|
365
|
+
const endpoint = argv.endpoint || argv.e;
|
|
366
|
+
const schema = argv.schema || argv.s;
|
|
367
|
+
const output = argv.output || argv.o;
|
|
368
|
+
const authorization = argv.authorization || argv.a;
|
|
369
|
+
const verbose = !!(argv.verbose || argv.v);
|
|
370
|
+
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
371
|
+
const skipCustomOperations = !!(argv['skip-custom-operations'] || argv.skipCustomOperations);
|
|
372
|
+
const watch = !!(argv.watch || argv.w);
|
|
373
|
+
const pollInterval = argv['poll-interval'] !== undefined
|
|
374
|
+
? parseInt(argv['poll-interval'], 10)
|
|
375
|
+
: undefined;
|
|
376
|
+
const debounce = argv.debounce !== undefined
|
|
377
|
+
? parseInt(argv.debounce, 10)
|
|
378
|
+
: undefined;
|
|
379
|
+
const touch = argv.touch;
|
|
380
|
+
const clear = argv.clear !== false;
|
|
381
|
+
if (endpoint && schema) {
|
|
277
382
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
278
383
|
process.exit(1);
|
|
279
384
|
}
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (options.schema) {
|
|
385
|
+
if (watch) {
|
|
386
|
+
if (schema) {
|
|
283
387
|
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
284
388
|
process.exit(1);
|
|
285
389
|
}
|
|
286
|
-
const
|
|
287
|
-
|
|
390
|
+
const watchConfig = await loadWatchConfig({
|
|
391
|
+
config,
|
|
392
|
+
target,
|
|
393
|
+
endpoint,
|
|
394
|
+
output,
|
|
395
|
+
pollInterval,
|
|
396
|
+
debounce,
|
|
397
|
+
touch,
|
|
398
|
+
clear,
|
|
399
|
+
});
|
|
400
|
+
if (!watchConfig) {
|
|
288
401
|
process.exit(1);
|
|
289
402
|
}
|
|
290
403
|
await (0, watch_1.startWatch)({
|
|
291
|
-
config,
|
|
404
|
+
config: watchConfig,
|
|
292
405
|
generatorType: 'generate-orm',
|
|
293
|
-
verbose
|
|
294
|
-
authorization
|
|
295
|
-
configPath:
|
|
296
|
-
target
|
|
297
|
-
outputDir:
|
|
298
|
-
skipCustomOperations
|
|
406
|
+
verbose,
|
|
407
|
+
authorization,
|
|
408
|
+
configPath: config,
|
|
409
|
+
target,
|
|
410
|
+
outputDir: output,
|
|
411
|
+
skipCustomOperations,
|
|
299
412
|
});
|
|
300
413
|
return;
|
|
301
414
|
}
|
|
302
|
-
// Normal one-shot generation
|
|
303
415
|
const result = await (0, generate_orm_1.generateOrmCommand)({
|
|
304
|
-
config
|
|
305
|
-
target
|
|
306
|
-
endpoint
|
|
307
|
-
schema
|
|
308
|
-
output
|
|
309
|
-
authorization
|
|
310
|
-
verbose
|
|
311
|
-
dryRun
|
|
312
|
-
skipCustomOperations
|
|
416
|
+
config,
|
|
417
|
+
target,
|
|
418
|
+
endpoint,
|
|
419
|
+
schema,
|
|
420
|
+
output,
|
|
421
|
+
authorization,
|
|
422
|
+
verbose,
|
|
423
|
+
dryRun,
|
|
424
|
+
skipCustomOperations,
|
|
313
425
|
});
|
|
314
426
|
const duration = formatDuration(performance.now() - startTime);
|
|
315
427
|
const targetResults = result.targets ?? [];
|
|
@@ -317,27 +429,27 @@ program
|
|
|
317
429
|
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
318
430
|
if (hasNamedTargets) {
|
|
319
431
|
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
320
|
-
targetResults.forEach((
|
|
321
|
-
const status =
|
|
322
|
-
console.log(`\n${status} ${
|
|
323
|
-
if (
|
|
432
|
+
targetResults.forEach((t) => {
|
|
433
|
+
const status = t.success ? '[ok]' : 'x';
|
|
434
|
+
console.log(`\n${status} ${t.message}`);
|
|
435
|
+
if (t.tables && t.tables.length > 0) {
|
|
324
436
|
console.log(' Tables:');
|
|
325
|
-
|
|
437
|
+
t.tables.forEach((table) => console.log(` - ${table}`));
|
|
326
438
|
}
|
|
327
|
-
if (
|
|
439
|
+
if (t.customQueries && t.customQueries.length > 0) {
|
|
328
440
|
console.log(' Custom Queries:');
|
|
329
|
-
|
|
441
|
+
t.customQueries.forEach((query) => console.log(` - ${query}`));
|
|
330
442
|
}
|
|
331
|
-
if (
|
|
443
|
+
if (t.customMutations && t.customMutations.length > 0) {
|
|
332
444
|
console.log(' Custom Mutations:');
|
|
333
|
-
|
|
445
|
+
t.customMutations.forEach((mutation) => console.log(` - ${mutation}`));
|
|
334
446
|
}
|
|
335
|
-
if (
|
|
447
|
+
if (t.filesWritten && t.filesWritten.length > 0) {
|
|
336
448
|
console.log(' Files written:');
|
|
337
|
-
|
|
449
|
+
t.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
338
450
|
}
|
|
339
|
-
if (!
|
|
340
|
-
|
|
451
|
+
if (!t.success && t.errors) {
|
|
452
|
+
t.errors.forEach((error) => console.error(` - ${error}`));
|
|
341
453
|
}
|
|
342
454
|
});
|
|
343
455
|
if (!result.success) {
|
|
@@ -371,23 +483,25 @@ program
|
|
|
371
483
|
}
|
|
372
484
|
process.exit(1);
|
|
373
485
|
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
.
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
.action(async (options) => {
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Introspect command handler
|
|
489
|
+
*/
|
|
490
|
+
async function handleIntrospect(argv) {
|
|
491
|
+
if (argv.help || argv.h) {
|
|
492
|
+
console.log(introspectUsageText);
|
|
493
|
+
process.exit(0);
|
|
494
|
+
}
|
|
384
495
|
const startTime = performance.now();
|
|
385
|
-
|
|
386
|
-
|
|
496
|
+
const endpoint = argv.endpoint || argv.e;
|
|
497
|
+
const schema = argv.schema || argv.s;
|
|
498
|
+
const authorization = argv.authorization || argv.a;
|
|
499
|
+
const json = !!argv.json;
|
|
500
|
+
if (!endpoint && !schema) {
|
|
387
501
|
console.error('x Either --endpoint or --schema must be provided.');
|
|
388
502
|
process.exit(1);
|
|
389
503
|
}
|
|
390
|
-
if (
|
|
504
|
+
if (endpoint && schema) {
|
|
391
505
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
392
506
|
process.exit(1);
|
|
393
507
|
}
|
|
@@ -395,15 +509,15 @@ program
|
|
|
395
509
|
const { inferTablesFromIntrospection } = await Promise.resolve().then(() => __importStar(require('./introspect/infer-tables')));
|
|
396
510
|
try {
|
|
397
511
|
const source = createSchemaSource({
|
|
398
|
-
endpoint
|
|
399
|
-
schema
|
|
400
|
-
authorization
|
|
512
|
+
endpoint,
|
|
513
|
+
schema,
|
|
514
|
+
authorization,
|
|
401
515
|
});
|
|
402
516
|
console.log('Fetching schema from', source.describe(), '...');
|
|
403
517
|
const { introspection } = await source.fetch();
|
|
404
518
|
const tables = inferTablesFromIntrospection(introspection);
|
|
405
519
|
const duration = formatDuration(performance.now() - startTime);
|
|
406
|
-
if (
|
|
520
|
+
if (json) {
|
|
407
521
|
console.log(JSON.stringify(tables, null, 2));
|
|
408
522
|
}
|
|
409
523
|
else {
|
|
@@ -423,5 +537,90 @@ program
|
|
|
423
537
|
console.error('x Failed to introspect schema:', err instanceof Error ? err.message : err, `(${duration})`);
|
|
424
538
|
process.exit(1);
|
|
425
539
|
}
|
|
426
|
-
}
|
|
427
|
-
|
|
540
|
+
}
|
|
541
|
+
const createCommandMap = () => {
|
|
542
|
+
return {
|
|
543
|
+
init: handleInit,
|
|
544
|
+
generate: handleGenerate,
|
|
545
|
+
'generate-orm': handleGenerateOrm,
|
|
546
|
+
introspect: handleIntrospect,
|
|
547
|
+
};
|
|
548
|
+
};
|
|
549
|
+
const commands = async (argv, prompter, _options) => {
|
|
550
|
+
if (argv.version || argv.v) {
|
|
551
|
+
const pkg = (0, find_and_require_package_json_1.findAndRequirePackageJson)(__dirname);
|
|
552
|
+
console.log(pkg.version);
|
|
553
|
+
process.exit(0);
|
|
554
|
+
}
|
|
555
|
+
const { first: command, newArgv } = (0, utils_1.extractFirst)(argv);
|
|
556
|
+
if ((argv.help || argv.h) && !command) {
|
|
557
|
+
console.log(usageText);
|
|
558
|
+
process.exit(0);
|
|
559
|
+
}
|
|
560
|
+
if (command === 'help') {
|
|
561
|
+
console.log(usageText);
|
|
562
|
+
process.exit(0);
|
|
563
|
+
}
|
|
564
|
+
const commandMap = createCommandMap();
|
|
565
|
+
if (!command) {
|
|
566
|
+
const answer = await prompter.prompt(argv, [
|
|
567
|
+
{
|
|
568
|
+
type: 'autocomplete',
|
|
569
|
+
name: 'command',
|
|
570
|
+
message: 'What do you want to do?',
|
|
571
|
+
options: Object.keys(commandMap),
|
|
572
|
+
},
|
|
573
|
+
]);
|
|
574
|
+
const selectedCommand = answer.command;
|
|
575
|
+
const commandFn = commandMap[selectedCommand];
|
|
576
|
+
if (commandFn) {
|
|
577
|
+
await commandFn(newArgv);
|
|
578
|
+
}
|
|
579
|
+
prompter.close();
|
|
580
|
+
return argv;
|
|
581
|
+
}
|
|
582
|
+
const commandFn = commandMap[command];
|
|
583
|
+
if (!commandFn) {
|
|
584
|
+
console.log(usageText);
|
|
585
|
+
await (0, utils_1.cliExitWithError)(`Unknown command: ${command}`);
|
|
586
|
+
}
|
|
587
|
+
await commandFn(newArgv);
|
|
588
|
+
prompter.close();
|
|
589
|
+
return argv;
|
|
590
|
+
};
|
|
591
|
+
exports.commands = commands;
|
|
592
|
+
exports.options = {
|
|
593
|
+
minimistOpts: {
|
|
594
|
+
alias: {
|
|
595
|
+
v: 'version',
|
|
596
|
+
h: 'help',
|
|
597
|
+
c: 'config',
|
|
598
|
+
t: 'target',
|
|
599
|
+
e: 'endpoint',
|
|
600
|
+
s: 'schema',
|
|
601
|
+
o: 'output',
|
|
602
|
+
a: 'authorization',
|
|
603
|
+
d: 'directory',
|
|
604
|
+
f: 'force',
|
|
605
|
+
w: 'watch',
|
|
606
|
+
},
|
|
607
|
+
boolean: ['help', 'version', 'force', 'verbose', 'dry-run', 'watch', 'json', 'skip-custom-operations', 'clear'],
|
|
608
|
+
string: ['config', 'target', 'endpoint', 'schema', 'output', 'authorization', 'directory', 'touch', 'poll-interval', 'debounce'],
|
|
609
|
+
default: {
|
|
610
|
+
clear: true,
|
|
611
|
+
},
|
|
612
|
+
},
|
|
613
|
+
};
|
|
614
|
+
if (require.main === module) {
|
|
615
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
616
|
+
const pkg = (0, find_and_require_package_json_1.findAndRequirePackageJson)(__dirname);
|
|
617
|
+
console.log(pkg.version);
|
|
618
|
+
process.exit(0);
|
|
619
|
+
}
|
|
620
|
+
const app = new inquirerer_1.CLI(exports.commands, exports.options);
|
|
621
|
+
app.run().then(() => {
|
|
622
|
+
}).catch((error) => {
|
|
623
|
+
console.error('Unexpected error:', error);
|
|
624
|
+
process.exit(1);
|
|
625
|
+
});
|
|
626
|
+
}
|
package/esm/cli/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
/**
|
|
2
3
|
* CLI entry point for graphql-codegen
|
|
3
4
|
*/
|
|
4
|
-
|
|
5
|
+
import { CLIOptions, Inquirerer } from 'inquirerer';
|
|
6
|
+
import { ParsedArgs } from 'minimist';
|
|
7
|
+
export declare const commands: (argv: Partial<ParsedArgs>, prompter: Inquirerer, _options: CLIOptions) => Promise<Partial<ParsedArgs>>;
|
|
8
|
+
export declare const options: Partial<CLIOptions>;
|
package/esm/cli/index.js
CHANGED
|
@@ -1,12 +1,104 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
1
2
|
/**
|
|
2
3
|
* CLI entry point for graphql-codegen
|
|
3
4
|
*/
|
|
4
|
-
import {
|
|
5
|
+
import { findAndRequirePackageJson } from 'find-and-require-package-json';
|
|
6
|
+
import { cliExitWithError, extractFirst } from '@inquirerer/utils';
|
|
7
|
+
import { CLI } from 'inquirerer';
|
|
5
8
|
import { initCommand, findConfigFile, loadConfigFile } from './commands/init';
|
|
6
9
|
import { generateCommand } from './commands/generate';
|
|
7
10
|
import { generateOrmCommand } from './commands/generate-orm';
|
|
8
11
|
import { startWatch } from './watch';
|
|
9
12
|
import { isMultiConfig, mergeConfig, resolveConfig, } from '../types/config';
|
|
13
|
+
const usageText = `
|
|
14
|
+
graphql-codegen - CLI for generating GraphQL SDK from PostGraphile endpoints or schema files
|
|
15
|
+
|
|
16
|
+
Usage:
|
|
17
|
+
graphql-codegen <command> [options]
|
|
18
|
+
|
|
19
|
+
Commands:
|
|
20
|
+
init Initialize a new graphql-codegen configuration file
|
|
21
|
+
generate Generate SDK from GraphQL endpoint or schema file
|
|
22
|
+
generate-orm Generate Prisma-like ORM client from GraphQL endpoint or schema file
|
|
23
|
+
introspect Introspect a GraphQL endpoint or schema file and print table info
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--help, -h Show this help message
|
|
27
|
+
--version, -v Show version number
|
|
28
|
+
|
|
29
|
+
Run 'graphql-codegen <command> --help' for more information on a command.
|
|
30
|
+
`;
|
|
31
|
+
const initUsageText = `
|
|
32
|
+
graphql-codegen init - Initialize a new graphql-codegen configuration file
|
|
33
|
+
|
|
34
|
+
Usage:
|
|
35
|
+
graphql-codegen init [options]
|
|
36
|
+
|
|
37
|
+
Options:
|
|
38
|
+
--directory, -d <dir> Target directory for the config file (default: .)
|
|
39
|
+
--force, -f Force overwrite existing config
|
|
40
|
+
--endpoint, -e <url> GraphQL endpoint URL to pre-populate
|
|
41
|
+
--output, -o <dir> Output directory to pre-populate (default: ./generated)
|
|
42
|
+
--help, -h Show this help message
|
|
43
|
+
`;
|
|
44
|
+
const generateUsageText = `
|
|
45
|
+
graphql-codegen generate - Generate SDK from GraphQL endpoint or schema file
|
|
46
|
+
|
|
47
|
+
Usage:
|
|
48
|
+
graphql-codegen generate [options]
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
--config, -c <path> Path to config file
|
|
52
|
+
--target, -t <name> Target name in config file
|
|
53
|
+
--endpoint, -e <url> GraphQL endpoint URL (overrides config)
|
|
54
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
55
|
+
--output, -o <dir> Output directory (overrides config)
|
|
56
|
+
--authorization, -a <header> Authorization header value
|
|
57
|
+
--verbose, -v Verbose output
|
|
58
|
+
--dry-run Dry run - show what would be generated without writing files
|
|
59
|
+
--watch, -w Watch mode - poll endpoint for schema changes (in-memory)
|
|
60
|
+
--poll-interval <ms> Polling interval in milliseconds (default: 3000)
|
|
61
|
+
--debounce <ms> Debounce delay before regenerating (default: 800)
|
|
62
|
+
--touch <file> File to touch on schema change
|
|
63
|
+
--no-clear Do not clear terminal on regeneration
|
|
64
|
+
--help, -h Show this help message
|
|
65
|
+
`;
|
|
66
|
+
const generateOrmUsageText = `
|
|
67
|
+
graphql-codegen generate-orm - Generate Prisma-like ORM client from GraphQL endpoint or schema file
|
|
68
|
+
|
|
69
|
+
Usage:
|
|
70
|
+
graphql-codegen generate-orm [options]
|
|
71
|
+
|
|
72
|
+
Options:
|
|
73
|
+
--config, -c <path> Path to config file
|
|
74
|
+
--target, -t <name> Target name in config file
|
|
75
|
+
--endpoint, -e <url> GraphQL endpoint URL (overrides config)
|
|
76
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
77
|
+
--output, -o <dir> Output directory (overrides config)
|
|
78
|
+
--authorization, -a <header> Authorization header value
|
|
79
|
+
--verbose, -v Verbose output
|
|
80
|
+
--dry-run Dry run - show what would be generated without writing files
|
|
81
|
+
--skip-custom-operations Skip custom operations (only generate table CRUD)
|
|
82
|
+
--watch, -w Watch mode - poll endpoint for schema changes (in-memory)
|
|
83
|
+
--poll-interval <ms> Polling interval in milliseconds (default: 3000)
|
|
84
|
+
--debounce <ms> Debounce delay before regenerating (default: 800)
|
|
85
|
+
--touch <file> File to touch on schema change
|
|
86
|
+
--no-clear Do not clear terminal on regeneration
|
|
87
|
+
--help, -h Show this help message
|
|
88
|
+
`;
|
|
89
|
+
const introspectUsageText = `
|
|
90
|
+
graphql-codegen introspect - Introspect a GraphQL endpoint or schema file and print table info
|
|
91
|
+
|
|
92
|
+
Usage:
|
|
93
|
+
graphql-codegen introspect [options]
|
|
94
|
+
|
|
95
|
+
Options:
|
|
96
|
+
--endpoint, -e <url> GraphQL endpoint URL
|
|
97
|
+
--schema, -s <path> Path to GraphQL schema file (.graphql)
|
|
98
|
+
--authorization, -a <header> Authorization header value
|
|
99
|
+
--json Output as JSON
|
|
100
|
+
--help, -h Show this help message
|
|
101
|
+
`;
|
|
10
102
|
/**
|
|
11
103
|
* Format duration in a human-readable way
|
|
12
104
|
* - Under 1 second: show milliseconds (e.g., "123ms")
|
|
@@ -18,12 +110,10 @@ function formatDuration(ms) {
|
|
|
18
110
|
}
|
|
19
111
|
return `${(ms / 1000).toFixed(2)}s`;
|
|
20
112
|
}
|
|
21
|
-
const program = new Command();
|
|
22
113
|
/**
|
|
23
114
|
* Load configuration for watch mode, merging CLI options with config file
|
|
24
115
|
*/
|
|
25
116
|
async function loadWatchConfig(options) {
|
|
26
|
-
// Find config file
|
|
27
117
|
let configPath = options.config;
|
|
28
118
|
if (!configPath) {
|
|
29
119
|
configPath = findConfigFile() ?? undefined;
|
|
@@ -87,25 +177,20 @@ async function loadWatchConfig(options) {
|
|
|
87
177
|
}
|
|
88
178
|
return resolveConfig(mergedTarget);
|
|
89
179
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
.option('-d, --directory <dir>', 'Target directory for the config file', '.')
|
|
99
|
-
.option('-f, --force', 'Force overwrite existing config', false)
|
|
100
|
-
.option('-e, --endpoint <url>', 'GraphQL endpoint URL to pre-populate')
|
|
101
|
-
.option('-o, --output <dir>', 'Output directory to pre-populate', './generated')
|
|
102
|
-
.action(async (options) => {
|
|
180
|
+
/**
|
|
181
|
+
* Init command handler
|
|
182
|
+
*/
|
|
183
|
+
async function handleInit(argv) {
|
|
184
|
+
if (argv.help || argv.h) {
|
|
185
|
+
console.log(initUsageText);
|
|
186
|
+
process.exit(0);
|
|
187
|
+
}
|
|
103
188
|
const startTime = performance.now();
|
|
104
189
|
const result = await initCommand({
|
|
105
|
-
directory:
|
|
106
|
-
force:
|
|
107
|
-
endpoint:
|
|
108
|
-
output:
|
|
190
|
+
directory: argv.directory || argv.d || '.',
|
|
191
|
+
force: !!(argv.force || argv.f),
|
|
192
|
+
endpoint: argv.endpoint || argv.e,
|
|
193
|
+
output: argv.output || argv.o || './generated',
|
|
109
194
|
});
|
|
110
195
|
const duration = formatDuration(performance.now() - startTime);
|
|
111
196
|
if (result.success) {
|
|
@@ -115,62 +200,75 @@ program
|
|
|
115
200
|
console.error('x', result.message, `(${duration})`);
|
|
116
201
|
process.exit(1);
|
|
117
202
|
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
128
|
-
.option('-a, --authorization <header>', 'Authorization header value')
|
|
129
|
-
.option('-v, --verbose', 'Verbose output', false)
|
|
130
|
-
.option('--dry-run', 'Dry run - show what would be generated without writing files', false)
|
|
131
|
-
.option('-w, --watch', 'Watch mode - poll endpoint for schema changes (in-memory)', false)
|
|
132
|
-
.option('--poll-interval <ms>', 'Polling interval in milliseconds (default: 3000)', parseInt)
|
|
133
|
-
.option('--debounce <ms>', 'Debounce delay before regenerating (default: 800)', parseInt)
|
|
134
|
-
.option('--touch <file>', 'File to touch on schema change')
|
|
135
|
-
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
136
|
-
.action(async (options) => {
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Generate command handler
|
|
206
|
+
*/
|
|
207
|
+
async function handleGenerate(argv) {
|
|
208
|
+
if (argv.help || argv.h) {
|
|
209
|
+
console.log(generateUsageText);
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
137
212
|
const startTime = performance.now();
|
|
138
|
-
|
|
139
|
-
|
|
213
|
+
const config = argv.config || argv.c;
|
|
214
|
+
const target = argv.target || argv.t;
|
|
215
|
+
const endpoint = argv.endpoint || argv.e;
|
|
216
|
+
const schema = argv.schema || argv.s;
|
|
217
|
+
const output = argv.output || argv.o;
|
|
218
|
+
const authorization = argv.authorization || argv.a;
|
|
219
|
+
const verbose = !!(argv.verbose || argv.v);
|
|
220
|
+
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
221
|
+
const watch = !!(argv.watch || argv.w);
|
|
222
|
+
const pollInterval = argv['poll-interval'] !== undefined
|
|
223
|
+
? parseInt(argv['poll-interval'], 10)
|
|
224
|
+
: undefined;
|
|
225
|
+
const debounce = argv.debounce !== undefined
|
|
226
|
+
? parseInt(argv.debounce, 10)
|
|
227
|
+
: undefined;
|
|
228
|
+
const touch = argv.touch;
|
|
229
|
+
const clear = argv.clear !== false;
|
|
230
|
+
if (endpoint && schema) {
|
|
140
231
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
141
232
|
process.exit(1);
|
|
142
233
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if (options.schema) {
|
|
234
|
+
if (watch) {
|
|
235
|
+
if (schema) {
|
|
146
236
|
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
147
237
|
process.exit(1);
|
|
148
238
|
}
|
|
149
|
-
const
|
|
150
|
-
|
|
239
|
+
const watchConfig = await loadWatchConfig({
|
|
240
|
+
config,
|
|
241
|
+
target,
|
|
242
|
+
endpoint,
|
|
243
|
+
output,
|
|
244
|
+
pollInterval,
|
|
245
|
+
debounce,
|
|
246
|
+
touch,
|
|
247
|
+
clear,
|
|
248
|
+
});
|
|
249
|
+
if (!watchConfig) {
|
|
151
250
|
process.exit(1);
|
|
152
251
|
}
|
|
153
252
|
await startWatch({
|
|
154
|
-
config,
|
|
253
|
+
config: watchConfig,
|
|
155
254
|
generatorType: 'generate',
|
|
156
|
-
verbose
|
|
157
|
-
authorization
|
|
158
|
-
configPath:
|
|
159
|
-
target
|
|
160
|
-
outputDir:
|
|
255
|
+
verbose,
|
|
256
|
+
authorization,
|
|
257
|
+
configPath: config,
|
|
258
|
+
target,
|
|
259
|
+
outputDir: output,
|
|
161
260
|
});
|
|
162
261
|
return;
|
|
163
262
|
}
|
|
164
|
-
// Normal one-shot generation
|
|
165
263
|
const result = await generateCommand({
|
|
166
|
-
config
|
|
167
|
-
target
|
|
168
|
-
endpoint
|
|
169
|
-
schema
|
|
170
|
-
output
|
|
171
|
-
authorization
|
|
172
|
-
verbose
|
|
173
|
-
dryRun
|
|
264
|
+
config,
|
|
265
|
+
target,
|
|
266
|
+
endpoint,
|
|
267
|
+
schema,
|
|
268
|
+
output,
|
|
269
|
+
authorization,
|
|
270
|
+
verbose,
|
|
271
|
+
dryRun,
|
|
174
272
|
});
|
|
175
273
|
const duration = formatDuration(performance.now() - startTime);
|
|
176
274
|
const targetResults = result.targets ?? [];
|
|
@@ -178,19 +276,19 @@ program
|
|
|
178
276
|
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
179
277
|
if (hasNamedTargets) {
|
|
180
278
|
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
181
|
-
targetResults.forEach((
|
|
182
|
-
const status =
|
|
183
|
-
console.log(`\n${status} ${
|
|
184
|
-
if (
|
|
279
|
+
targetResults.forEach((t) => {
|
|
280
|
+
const status = t.success ? '[ok]' : 'x';
|
|
281
|
+
console.log(`\n${status} ${t.message}`);
|
|
282
|
+
if (t.tables && t.tables.length > 0) {
|
|
185
283
|
console.log(' Tables:');
|
|
186
|
-
|
|
284
|
+
t.tables.forEach((table) => console.log(` - ${table}`));
|
|
187
285
|
}
|
|
188
|
-
if (
|
|
286
|
+
if (t.filesWritten && t.filesWritten.length > 0) {
|
|
189
287
|
console.log(' Files written:');
|
|
190
|
-
|
|
288
|
+
t.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
191
289
|
}
|
|
192
|
-
if (!
|
|
193
|
-
|
|
290
|
+
if (!t.success && t.errors) {
|
|
291
|
+
t.errors.forEach((error) => console.error(` - ${error}`));
|
|
194
292
|
}
|
|
195
293
|
});
|
|
196
294
|
if (!result.success) {
|
|
@@ -216,65 +314,78 @@ program
|
|
|
216
314
|
}
|
|
217
315
|
process.exit(1);
|
|
218
316
|
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
229
|
-
.option('-a, --authorization <header>', 'Authorization header value')
|
|
230
|
-
.option('-v, --verbose', 'Verbose output', false)
|
|
231
|
-
.option('--dry-run', 'Dry run - show what would be generated without writing files', false)
|
|
232
|
-
.option('--skip-custom-operations', 'Skip custom operations (only generate table CRUD)', false)
|
|
233
|
-
.option('-w, --watch', 'Watch mode - poll endpoint for schema changes (in-memory)', false)
|
|
234
|
-
.option('--poll-interval <ms>', 'Polling interval in milliseconds (default: 3000)', parseInt)
|
|
235
|
-
.option('--debounce <ms>', 'Debounce delay before regenerating (default: 800)', parseInt)
|
|
236
|
-
.option('--touch <file>', 'File to touch on schema change')
|
|
237
|
-
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
238
|
-
.action(async (options) => {
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Generate ORM command handler
|
|
320
|
+
*/
|
|
321
|
+
async function handleGenerateOrm(argv) {
|
|
322
|
+
if (argv.help || argv.h) {
|
|
323
|
+
console.log(generateOrmUsageText);
|
|
324
|
+
process.exit(0);
|
|
325
|
+
}
|
|
239
326
|
const startTime = performance.now();
|
|
240
|
-
|
|
241
|
-
|
|
327
|
+
const config = argv.config || argv.c;
|
|
328
|
+
const target = argv.target || argv.t;
|
|
329
|
+
const endpoint = argv.endpoint || argv.e;
|
|
330
|
+
const schema = argv.schema || argv.s;
|
|
331
|
+
const output = argv.output || argv.o;
|
|
332
|
+
const authorization = argv.authorization || argv.a;
|
|
333
|
+
const verbose = !!(argv.verbose || argv.v);
|
|
334
|
+
const dryRun = !!(argv['dry-run'] || argv.dryRun);
|
|
335
|
+
const skipCustomOperations = !!(argv['skip-custom-operations'] || argv.skipCustomOperations);
|
|
336
|
+
const watch = !!(argv.watch || argv.w);
|
|
337
|
+
const pollInterval = argv['poll-interval'] !== undefined
|
|
338
|
+
? parseInt(argv['poll-interval'], 10)
|
|
339
|
+
: undefined;
|
|
340
|
+
const debounce = argv.debounce !== undefined
|
|
341
|
+
? parseInt(argv.debounce, 10)
|
|
342
|
+
: undefined;
|
|
343
|
+
const touch = argv.touch;
|
|
344
|
+
const clear = argv.clear !== false;
|
|
345
|
+
if (endpoint && schema) {
|
|
242
346
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
243
347
|
process.exit(1);
|
|
244
348
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (options.schema) {
|
|
349
|
+
if (watch) {
|
|
350
|
+
if (schema) {
|
|
248
351
|
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
249
352
|
process.exit(1);
|
|
250
353
|
}
|
|
251
|
-
const
|
|
252
|
-
|
|
354
|
+
const watchConfig = await loadWatchConfig({
|
|
355
|
+
config,
|
|
356
|
+
target,
|
|
357
|
+
endpoint,
|
|
358
|
+
output,
|
|
359
|
+
pollInterval,
|
|
360
|
+
debounce,
|
|
361
|
+
touch,
|
|
362
|
+
clear,
|
|
363
|
+
});
|
|
364
|
+
if (!watchConfig) {
|
|
253
365
|
process.exit(1);
|
|
254
366
|
}
|
|
255
367
|
await startWatch({
|
|
256
|
-
config,
|
|
368
|
+
config: watchConfig,
|
|
257
369
|
generatorType: 'generate-orm',
|
|
258
|
-
verbose
|
|
259
|
-
authorization
|
|
260
|
-
configPath:
|
|
261
|
-
target
|
|
262
|
-
outputDir:
|
|
263
|
-
skipCustomOperations
|
|
370
|
+
verbose,
|
|
371
|
+
authorization,
|
|
372
|
+
configPath: config,
|
|
373
|
+
target,
|
|
374
|
+
outputDir: output,
|
|
375
|
+
skipCustomOperations,
|
|
264
376
|
});
|
|
265
377
|
return;
|
|
266
378
|
}
|
|
267
|
-
// Normal one-shot generation
|
|
268
379
|
const result = await generateOrmCommand({
|
|
269
|
-
config
|
|
270
|
-
target
|
|
271
|
-
endpoint
|
|
272
|
-
schema
|
|
273
|
-
output
|
|
274
|
-
authorization
|
|
275
|
-
verbose
|
|
276
|
-
dryRun
|
|
277
|
-
skipCustomOperations
|
|
380
|
+
config,
|
|
381
|
+
target,
|
|
382
|
+
endpoint,
|
|
383
|
+
schema,
|
|
384
|
+
output,
|
|
385
|
+
authorization,
|
|
386
|
+
verbose,
|
|
387
|
+
dryRun,
|
|
388
|
+
skipCustomOperations,
|
|
278
389
|
});
|
|
279
390
|
const duration = formatDuration(performance.now() - startTime);
|
|
280
391
|
const targetResults = result.targets ?? [];
|
|
@@ -282,27 +393,27 @@ program
|
|
|
282
393
|
(targetResults.length > 1 || targetResults[0]?.name !== 'default');
|
|
283
394
|
if (hasNamedTargets) {
|
|
284
395
|
console.log(result.success ? '[ok]' : 'x', result.message);
|
|
285
|
-
targetResults.forEach((
|
|
286
|
-
const status =
|
|
287
|
-
console.log(`\n${status} ${
|
|
288
|
-
if (
|
|
396
|
+
targetResults.forEach((t) => {
|
|
397
|
+
const status = t.success ? '[ok]' : 'x';
|
|
398
|
+
console.log(`\n${status} ${t.message}`);
|
|
399
|
+
if (t.tables && t.tables.length > 0) {
|
|
289
400
|
console.log(' Tables:');
|
|
290
|
-
|
|
401
|
+
t.tables.forEach((table) => console.log(` - ${table}`));
|
|
291
402
|
}
|
|
292
|
-
if (
|
|
403
|
+
if (t.customQueries && t.customQueries.length > 0) {
|
|
293
404
|
console.log(' Custom Queries:');
|
|
294
|
-
|
|
405
|
+
t.customQueries.forEach((query) => console.log(` - ${query}`));
|
|
295
406
|
}
|
|
296
|
-
if (
|
|
407
|
+
if (t.customMutations && t.customMutations.length > 0) {
|
|
297
408
|
console.log(' Custom Mutations:');
|
|
298
|
-
|
|
409
|
+
t.customMutations.forEach((mutation) => console.log(` - ${mutation}`));
|
|
299
410
|
}
|
|
300
|
-
if (
|
|
411
|
+
if (t.filesWritten && t.filesWritten.length > 0) {
|
|
301
412
|
console.log(' Files written:');
|
|
302
|
-
|
|
413
|
+
t.filesWritten.forEach((file) => console.log(` - ${file}`));
|
|
303
414
|
}
|
|
304
|
-
if (!
|
|
305
|
-
|
|
415
|
+
if (!t.success && t.errors) {
|
|
416
|
+
t.errors.forEach((error) => console.error(` - ${error}`));
|
|
306
417
|
}
|
|
307
418
|
});
|
|
308
419
|
if (!result.success) {
|
|
@@ -336,23 +447,25 @@ program
|
|
|
336
447
|
}
|
|
337
448
|
process.exit(1);
|
|
338
449
|
}
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
.
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
.action(async (options) => {
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Introspect command handler
|
|
453
|
+
*/
|
|
454
|
+
async function handleIntrospect(argv) {
|
|
455
|
+
if (argv.help || argv.h) {
|
|
456
|
+
console.log(introspectUsageText);
|
|
457
|
+
process.exit(0);
|
|
458
|
+
}
|
|
349
459
|
const startTime = performance.now();
|
|
350
|
-
|
|
351
|
-
|
|
460
|
+
const endpoint = argv.endpoint || argv.e;
|
|
461
|
+
const schema = argv.schema || argv.s;
|
|
462
|
+
const authorization = argv.authorization || argv.a;
|
|
463
|
+
const json = !!argv.json;
|
|
464
|
+
if (!endpoint && !schema) {
|
|
352
465
|
console.error('x Either --endpoint or --schema must be provided.');
|
|
353
466
|
process.exit(1);
|
|
354
467
|
}
|
|
355
|
-
if (
|
|
468
|
+
if (endpoint && schema) {
|
|
356
469
|
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
357
470
|
process.exit(1);
|
|
358
471
|
}
|
|
@@ -360,15 +473,15 @@ program
|
|
|
360
473
|
const { inferTablesFromIntrospection } = await import('./introspect/infer-tables');
|
|
361
474
|
try {
|
|
362
475
|
const source = createSchemaSource({
|
|
363
|
-
endpoint
|
|
364
|
-
schema
|
|
365
|
-
authorization
|
|
476
|
+
endpoint,
|
|
477
|
+
schema,
|
|
478
|
+
authorization,
|
|
366
479
|
});
|
|
367
480
|
console.log('Fetching schema from', source.describe(), '...');
|
|
368
481
|
const { introspection } = await source.fetch();
|
|
369
482
|
const tables = inferTablesFromIntrospection(introspection);
|
|
370
483
|
const duration = formatDuration(performance.now() - startTime);
|
|
371
|
-
if (
|
|
484
|
+
if (json) {
|
|
372
485
|
console.log(JSON.stringify(tables, null, 2));
|
|
373
486
|
}
|
|
374
487
|
else {
|
|
@@ -388,5 +501,89 @@ program
|
|
|
388
501
|
console.error('x Failed to introspect schema:', err instanceof Error ? err.message : err, `(${duration})`);
|
|
389
502
|
process.exit(1);
|
|
390
503
|
}
|
|
391
|
-
}
|
|
392
|
-
|
|
504
|
+
}
|
|
505
|
+
const createCommandMap = () => {
|
|
506
|
+
return {
|
|
507
|
+
init: handleInit,
|
|
508
|
+
generate: handleGenerate,
|
|
509
|
+
'generate-orm': handleGenerateOrm,
|
|
510
|
+
introspect: handleIntrospect,
|
|
511
|
+
};
|
|
512
|
+
};
|
|
513
|
+
export const commands = async (argv, prompter, _options) => {
|
|
514
|
+
if (argv.version || argv.v) {
|
|
515
|
+
const pkg = findAndRequirePackageJson(__dirname);
|
|
516
|
+
console.log(pkg.version);
|
|
517
|
+
process.exit(0);
|
|
518
|
+
}
|
|
519
|
+
const { first: command, newArgv } = extractFirst(argv);
|
|
520
|
+
if ((argv.help || argv.h) && !command) {
|
|
521
|
+
console.log(usageText);
|
|
522
|
+
process.exit(0);
|
|
523
|
+
}
|
|
524
|
+
if (command === 'help') {
|
|
525
|
+
console.log(usageText);
|
|
526
|
+
process.exit(0);
|
|
527
|
+
}
|
|
528
|
+
const commandMap = createCommandMap();
|
|
529
|
+
if (!command) {
|
|
530
|
+
const answer = await prompter.prompt(argv, [
|
|
531
|
+
{
|
|
532
|
+
type: 'autocomplete',
|
|
533
|
+
name: 'command',
|
|
534
|
+
message: 'What do you want to do?',
|
|
535
|
+
options: Object.keys(commandMap),
|
|
536
|
+
},
|
|
537
|
+
]);
|
|
538
|
+
const selectedCommand = answer.command;
|
|
539
|
+
const commandFn = commandMap[selectedCommand];
|
|
540
|
+
if (commandFn) {
|
|
541
|
+
await commandFn(newArgv);
|
|
542
|
+
}
|
|
543
|
+
prompter.close();
|
|
544
|
+
return argv;
|
|
545
|
+
}
|
|
546
|
+
const commandFn = commandMap[command];
|
|
547
|
+
if (!commandFn) {
|
|
548
|
+
console.log(usageText);
|
|
549
|
+
await cliExitWithError(`Unknown command: ${command}`);
|
|
550
|
+
}
|
|
551
|
+
await commandFn(newArgv);
|
|
552
|
+
prompter.close();
|
|
553
|
+
return argv;
|
|
554
|
+
};
|
|
555
|
+
export const options = {
|
|
556
|
+
minimistOpts: {
|
|
557
|
+
alias: {
|
|
558
|
+
v: 'version',
|
|
559
|
+
h: 'help',
|
|
560
|
+
c: 'config',
|
|
561
|
+
t: 'target',
|
|
562
|
+
e: 'endpoint',
|
|
563
|
+
s: 'schema',
|
|
564
|
+
o: 'output',
|
|
565
|
+
a: 'authorization',
|
|
566
|
+
d: 'directory',
|
|
567
|
+
f: 'force',
|
|
568
|
+
w: 'watch',
|
|
569
|
+
},
|
|
570
|
+
boolean: ['help', 'version', 'force', 'verbose', 'dry-run', 'watch', 'json', 'skip-custom-operations', 'clear'],
|
|
571
|
+
string: ['config', 'target', 'endpoint', 'schema', 'output', 'authorization', 'directory', 'touch', 'poll-interval', 'debounce'],
|
|
572
|
+
default: {
|
|
573
|
+
clear: true,
|
|
574
|
+
},
|
|
575
|
+
},
|
|
576
|
+
};
|
|
577
|
+
if (require.main === module) {
|
|
578
|
+
if (process.argv.includes('--version') || process.argv.includes('-v')) {
|
|
579
|
+
const pkg = findAndRequirePackageJson(__dirname);
|
|
580
|
+
console.log(pkg.version);
|
|
581
|
+
process.exit(0);
|
|
582
|
+
}
|
|
583
|
+
const app = new CLI(commands, options);
|
|
584
|
+
app.run().then(() => {
|
|
585
|
+
}).catch((error) => {
|
|
586
|
+
console.error('Unexpected error:', error);
|
|
587
|
+
process.exit(1);
|
|
588
|
+
});
|
|
589
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructive-io/graphql-codegen",
|
|
3
|
-
"version": "2.27.
|
|
3
|
+
"version": "2.27.3",
|
|
4
4
|
"description": "CLI-based GraphQL SDK generator for PostGraphile endpoints with React Query hooks",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"graphql",
|
|
@@ -54,12 +54,15 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@babel/generator": "^7.28.6",
|
|
56
56
|
"@babel/types": "^7.28.6",
|
|
57
|
+
"@inquirerer/utils": "^3.1.3",
|
|
57
58
|
"ajv": "^8.17.1",
|
|
58
|
-
"
|
|
59
|
+
"find-and-require-package-json": "^0.8.6",
|
|
59
60
|
"gql-ast": "^2.6.0",
|
|
60
61
|
"graphql": "15.10.1",
|
|
61
62
|
"inflekt": "^0.2.0",
|
|
63
|
+
"inquirerer": "^4.3.1",
|
|
62
64
|
"jiti": "^2.6.1",
|
|
65
|
+
"minimist": "^1.2.8",
|
|
63
66
|
"oxfmt": "^0.13.0"
|
|
64
67
|
},
|
|
65
68
|
"peerDependencies": {
|
|
@@ -78,6 +81,7 @@
|
|
|
78
81
|
"@tanstack/react-query": "^5.90.16",
|
|
79
82
|
"@types/babel__generator": "^7.27.0",
|
|
80
83
|
"@types/jest": "^29.5.14",
|
|
84
|
+
"@types/minimist": "^1.2.5",
|
|
81
85
|
"@types/node": "^20.19.27",
|
|
82
86
|
"@types/react": "^19.2.7",
|
|
83
87
|
"jest": "^29.7.0",
|
|
@@ -86,5 +90,5 @@
|
|
|
86
90
|
"tsx": "^4.21.0",
|
|
87
91
|
"typescript": "^5.9.3"
|
|
88
92
|
},
|
|
89
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "5ec5f1eb56490ffcf38fbc9949abc6905832083c"
|
|
90
94
|
}
|