@constructive-io/graphql-codegen 2.24.0 → 2.26.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.
- package/README.md +403 -279
- package/cli/codegen/babel-ast.d.ts +7 -0
- package/cli/codegen/babel-ast.js +15 -0
- package/cli/codegen/barrel.js +43 -14
- package/cli/codegen/custom-mutations.js +4 -4
- package/cli/codegen/custom-queries.js +12 -22
- package/cli/codegen/gql-ast.js +22 -1
- package/cli/codegen/index.js +1 -0
- package/cli/codegen/mutations.d.ts +2 -0
- package/cli/codegen/mutations.js +26 -13
- package/cli/codegen/orm/client-generator.js +475 -136
- package/cli/codegen/orm/custom-ops-generator.js +8 -3
- package/cli/codegen/orm/input-types-generator.js +22 -0
- package/cli/codegen/orm/model-generator.js +18 -5
- package/cli/codegen/orm/select-types.d.ts +33 -0
- package/cli/codegen/queries.d.ts +1 -1
- package/cli/codegen/queries.js +112 -35
- package/cli/codegen/utils.d.ts +6 -0
- package/cli/codegen/utils.js +19 -0
- package/cli/commands/generate-orm.d.ts +14 -0
- package/cli/commands/generate-orm.js +160 -44
- package/cli/commands/generate.d.ts +22 -0
- package/cli/commands/generate.js +195 -55
- package/cli/commands/init.js +29 -9
- package/cli/index.js +133 -28
- package/cli/watch/orchestrator.d.ts +4 -0
- package/cli/watch/orchestrator.js +4 -0
- package/esm/cli/codegen/babel-ast.d.ts +7 -0
- package/esm/cli/codegen/babel-ast.js +14 -0
- package/esm/cli/codegen/barrel.js +44 -15
- package/esm/cli/codegen/custom-mutations.js +5 -5
- package/esm/cli/codegen/custom-queries.js +13 -23
- package/esm/cli/codegen/gql-ast.js +23 -2
- package/esm/cli/codegen/index.js +1 -0
- package/esm/cli/codegen/mutations.d.ts +2 -0
- package/esm/cli/codegen/mutations.js +27 -14
- package/esm/cli/codegen/orm/client-generator.js +475 -136
- package/esm/cli/codegen/orm/custom-ops-generator.js +8 -3
- package/esm/cli/codegen/orm/input-types-generator.js +22 -0
- package/esm/cli/codegen/orm/model-generator.js +18 -5
- package/esm/cli/codegen/orm/select-types.d.ts +33 -0
- package/esm/cli/codegen/queries.d.ts +1 -1
- package/esm/cli/codegen/queries.js +114 -37
- package/esm/cli/codegen/utils.d.ts +6 -0
- package/esm/cli/codegen/utils.js +18 -0
- package/esm/cli/commands/generate-orm.d.ts +14 -0
- package/esm/cli/commands/generate-orm.js +161 -45
- package/esm/cli/commands/generate.d.ts +22 -0
- package/esm/cli/commands/generate.js +195 -56
- package/esm/cli/commands/init.js +29 -9
- package/esm/cli/index.js +134 -29
- package/esm/cli/watch/orchestrator.d.ts +4 -0
- package/esm/cli/watch/orchestrator.js +5 -1
- package/esm/types/config.d.ts +39 -2
- package/esm/types/config.js +88 -4
- package/esm/types/index.d.ts +2 -2
- package/esm/types/index.js +1 -1
- package/package.json +10 -7
- package/types/config.d.ts +39 -2
- package/types/config.js +91 -4
- package/types/index.d.ts +2 -2
- package/types/index.js +2 -1
- package/cli/codegen/orm/query-builder.d.ts +0 -161
- package/cli/codegen/orm/query-builder.js +0 -366
- package/esm/cli/codegen/orm/query-builder.d.ts +0 -161
- package/esm/cli/codegen/orm/query-builder.js +0 -353
package/cli/commands/generate.js
CHANGED
|
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.generateCommand = generateCommand;
|
|
37
37
|
exports.writeGeneratedFiles = writeGeneratedFiles;
|
|
38
|
+
exports.formatOutput = formatOutput;
|
|
38
39
|
/**
|
|
39
40
|
* Generate command - generates SDK from GraphQL schema
|
|
40
41
|
*
|
|
@@ -45,7 +46,7 @@ exports.writeGeneratedFiles = writeGeneratedFiles;
|
|
|
45
46
|
*/
|
|
46
47
|
const fs = __importStar(require("node:fs"));
|
|
47
48
|
const path = __importStar(require("node:path"));
|
|
48
|
-
const
|
|
49
|
+
const node_child_process_1 = require("node:child_process");
|
|
49
50
|
const config_1 = require("../../types/config");
|
|
50
51
|
const source_1 = require("../introspect/source");
|
|
51
52
|
const shared_1 = require("./shared");
|
|
@@ -55,9 +56,9 @@ const codegen_1 = require("../codegen");
|
|
|
55
56
|
* Execute the generate command
|
|
56
57
|
*/
|
|
57
58
|
async function generateCommand(options = {}) {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
59
|
+
if (options.verbose) {
|
|
60
|
+
console.log('Loading configuration...');
|
|
61
|
+
}
|
|
61
62
|
const configResult = await loadConfig(options);
|
|
62
63
|
if (!configResult.success) {
|
|
63
64
|
return {
|
|
@@ -65,24 +66,72 @@ async function generateCommand(options = {}) {
|
|
|
65
66
|
message: configResult.error,
|
|
66
67
|
};
|
|
67
68
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
const targets = configResult.targets ?? [];
|
|
70
|
+
if (targets.length === 0) {
|
|
71
|
+
return {
|
|
72
|
+
success: false,
|
|
73
|
+
message: 'No targets resolved from configuration.',
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const isMultiTarget = configResult.isMulti ?? targets.length > 1;
|
|
77
|
+
const results = [];
|
|
78
|
+
for (const target of targets) {
|
|
79
|
+
const result = await generateForTarget(target, options, isMultiTarget);
|
|
80
|
+
results.push(result);
|
|
81
|
+
}
|
|
82
|
+
if (!isMultiTarget) {
|
|
83
|
+
const [result] = results;
|
|
84
|
+
return {
|
|
85
|
+
success: result.success,
|
|
86
|
+
message: result.message,
|
|
87
|
+
targets: results,
|
|
88
|
+
tables: result.tables,
|
|
89
|
+
customQueries: result.customQueries,
|
|
90
|
+
customMutations: result.customMutations,
|
|
91
|
+
filesWritten: result.filesWritten,
|
|
92
|
+
errors: result.errors,
|
|
93
|
+
};
|
|
72
94
|
}
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
const successCount = results.filter((result) => result.success).length;
|
|
96
|
+
const failedCount = results.length - successCount;
|
|
97
|
+
const summaryMessage = failedCount === 0
|
|
98
|
+
? `Generated SDK for ${results.length} targets.`
|
|
99
|
+
: `Generated SDK for ${successCount} of ${results.length} targets.`;
|
|
100
|
+
return {
|
|
101
|
+
success: failedCount === 0,
|
|
102
|
+
message: summaryMessage,
|
|
103
|
+
targets: results,
|
|
104
|
+
errors: failedCount > 0
|
|
105
|
+
? results.flatMap((result) => result.errors ?? [])
|
|
106
|
+
: undefined,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
async function generateForTarget(target, options, isMultiTarget) {
|
|
110
|
+
const config = target.config;
|
|
111
|
+
const prefix = isMultiTarget ? `[${target.name}] ` : '';
|
|
112
|
+
const log = options.verbose
|
|
113
|
+
? (message) => console.log(`${prefix}${message}`)
|
|
114
|
+
: () => { };
|
|
115
|
+
const formatMessage = (message) => isMultiTarget ? `Target "${target.name}": ${message}` : message;
|
|
116
|
+
if (isMultiTarget) {
|
|
117
|
+
console.log(`\nTarget "${target.name}"`);
|
|
118
|
+
const sourceLabel = config.schema
|
|
119
|
+
? `schema: ${config.schema}`
|
|
120
|
+
: `endpoint: ${config.endpoint}`;
|
|
121
|
+
console.log(` Source: ${sourceLabel}`);
|
|
122
|
+
console.log(` Output: ${config.output}`);
|
|
75
123
|
}
|
|
76
|
-
|
|
77
|
-
// 2. Create schema source
|
|
124
|
+
// 1. Validate source
|
|
78
125
|
const sourceValidation = (0, source_1.validateSourceOptions)({
|
|
79
126
|
endpoint: config.endpoint || undefined,
|
|
80
127
|
schema: config.schema || undefined,
|
|
81
128
|
});
|
|
82
129
|
if (!sourceValidation.valid) {
|
|
83
130
|
return {
|
|
131
|
+
name: target.name,
|
|
132
|
+
output: config.output,
|
|
84
133
|
success: false,
|
|
85
|
-
message: sourceValidation.error,
|
|
134
|
+
message: formatMessage(sourceValidation.error),
|
|
86
135
|
};
|
|
87
136
|
}
|
|
88
137
|
const source = (0, source_1.createSchemaSource)({
|
|
@@ -91,7 +140,7 @@ async function generateCommand(options = {}) {
|
|
|
91
140
|
authorization: options.authorization || config.headers['Authorization'],
|
|
92
141
|
headers: config.headers,
|
|
93
142
|
});
|
|
94
|
-
//
|
|
143
|
+
// 2. Run the codegen pipeline
|
|
95
144
|
let pipelineResult;
|
|
96
145
|
try {
|
|
97
146
|
pipelineResult = await (0, shared_1.runCodegenPipeline)({
|
|
@@ -103,21 +152,25 @@ async function generateCommand(options = {}) {
|
|
|
103
152
|
}
|
|
104
153
|
catch (err) {
|
|
105
154
|
return {
|
|
155
|
+
name: target.name,
|
|
156
|
+
output: config.output,
|
|
106
157
|
success: false,
|
|
107
|
-
message: `Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}
|
|
158
|
+
message: formatMessage(`Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}`),
|
|
108
159
|
};
|
|
109
160
|
}
|
|
110
161
|
const { tables, customOperations, stats } = pipelineResult;
|
|
111
|
-
//
|
|
162
|
+
// 3. Validate tables found
|
|
112
163
|
const tablesValidation = (0, shared_1.validateTablesFound)(tables);
|
|
113
164
|
if (!tablesValidation.valid) {
|
|
114
165
|
return {
|
|
166
|
+
name: target.name,
|
|
167
|
+
output: config.output,
|
|
115
168
|
success: false,
|
|
116
|
-
message: tablesValidation.error,
|
|
169
|
+
message: formatMessage(tablesValidation.error),
|
|
117
170
|
};
|
|
118
171
|
}
|
|
119
|
-
//
|
|
120
|
-
console.log(
|
|
172
|
+
// 4. Generate code
|
|
173
|
+
console.log(`${prefix}Generating code...`);
|
|
121
174
|
const { files: generatedFiles, stats: genStats } = (0, codegen_1.generate)({
|
|
122
175
|
tables,
|
|
123
176
|
customOperations: {
|
|
@@ -127,7 +180,7 @@ async function generateCommand(options = {}) {
|
|
|
127
180
|
},
|
|
128
181
|
config,
|
|
129
182
|
});
|
|
130
|
-
console.log(
|
|
183
|
+
console.log(`${prefix}Generated ${genStats.totalFiles} files`);
|
|
131
184
|
log(` ${genStats.queryHooks} table query hooks`);
|
|
132
185
|
log(` ${genStats.mutationHooks} table mutation hooks`);
|
|
133
186
|
log(` ${genStats.customQueryHooks} custom query hooks`);
|
|
@@ -136,15 +189,17 @@ async function generateCommand(options = {}) {
|
|
|
136
189
|
const customMutations = customOperations.mutations.map((m) => m.name);
|
|
137
190
|
if (options.dryRun) {
|
|
138
191
|
return {
|
|
192
|
+
name: target.name,
|
|
193
|
+
output: config.output,
|
|
139
194
|
success: true,
|
|
140
|
-
message: `Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${stats.customQueries + stats.customMutations} custom operations
|
|
195
|
+
message: formatMessage(`Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${stats.customQueries + stats.customMutations} custom operations.`),
|
|
141
196
|
tables: tables.map((t) => t.name),
|
|
142
197
|
customQueries,
|
|
143
198
|
customMutations,
|
|
144
199
|
filesWritten: generatedFiles.map((f) => f.path),
|
|
145
200
|
};
|
|
146
201
|
}
|
|
147
|
-
//
|
|
202
|
+
// 5. Write files
|
|
148
203
|
log('Writing files...');
|
|
149
204
|
const writeResult = await writeGeneratedFiles(generatedFiles, config.output, [
|
|
150
205
|
'queries',
|
|
@@ -152,23 +207,48 @@ async function generateCommand(options = {}) {
|
|
|
152
207
|
]);
|
|
153
208
|
if (!writeResult.success) {
|
|
154
209
|
return {
|
|
210
|
+
name: target.name,
|
|
211
|
+
output: config.output,
|
|
155
212
|
success: false,
|
|
156
|
-
message: `Failed to write files: ${writeResult.errors?.join(', ')}
|
|
213
|
+
message: formatMessage(`Failed to write files: ${writeResult.errors?.join(', ')}`),
|
|
157
214
|
errors: writeResult.errors,
|
|
158
215
|
};
|
|
159
216
|
}
|
|
160
217
|
const totalOps = customQueries.length + customMutations.length;
|
|
161
218
|
const customOpsMsg = totalOps > 0 ? ` and ${totalOps} custom operations` : '';
|
|
162
219
|
return {
|
|
220
|
+
name: target.name,
|
|
221
|
+
output: config.output,
|
|
163
222
|
success: true,
|
|
164
|
-
message: `Generated SDK for ${tables.length} tables${customOpsMsg}. Files written to ${config.output}
|
|
223
|
+
message: formatMessage(`Generated SDK for ${tables.length} tables${customOpsMsg}. Files written to ${config.output}`),
|
|
165
224
|
tables: tables.map((t) => t.name),
|
|
166
225
|
customQueries,
|
|
167
226
|
customMutations,
|
|
168
227
|
filesWritten: writeResult.filesWritten,
|
|
169
228
|
};
|
|
170
229
|
}
|
|
230
|
+
function buildTargetOverrides(options) {
|
|
231
|
+
const overrides = {};
|
|
232
|
+
if (options.endpoint) {
|
|
233
|
+
overrides.endpoint = options.endpoint;
|
|
234
|
+
overrides.schema = undefined;
|
|
235
|
+
}
|
|
236
|
+
if (options.schema) {
|
|
237
|
+
overrides.schema = options.schema;
|
|
238
|
+
overrides.endpoint = undefined;
|
|
239
|
+
}
|
|
240
|
+
if (options.output) {
|
|
241
|
+
overrides.output = options.output;
|
|
242
|
+
}
|
|
243
|
+
return overrides;
|
|
244
|
+
}
|
|
171
245
|
async function loadConfig(options) {
|
|
246
|
+
if (options.endpoint && options.schema) {
|
|
247
|
+
return {
|
|
248
|
+
success: false,
|
|
249
|
+
error: 'Cannot use both --endpoint and --schema. Choose one source.',
|
|
250
|
+
};
|
|
251
|
+
}
|
|
172
252
|
// Find config file
|
|
173
253
|
let configPath = options.config;
|
|
174
254
|
if (!configPath) {
|
|
@@ -182,31 +262,72 @@ async function loadConfig(options) {
|
|
|
182
262
|
}
|
|
183
263
|
baseConfig = loadResult.config;
|
|
184
264
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
265
|
+
const overrides = buildTargetOverrides(options);
|
|
266
|
+
if ((0, config_1.isMultiConfig)(baseConfig)) {
|
|
267
|
+
if (Object.keys(baseConfig.targets).length === 0) {
|
|
268
|
+
return {
|
|
269
|
+
success: false,
|
|
270
|
+
error: 'Config file defines no targets.',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (!options.target &&
|
|
274
|
+
(options.endpoint || options.schema || options.output)) {
|
|
275
|
+
return {
|
|
276
|
+
success: false,
|
|
277
|
+
error: 'Multiple targets configured. Use --target with --endpoint, --schema, or --output.',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
if (options.target && !baseConfig.targets[options.target]) {
|
|
281
|
+
return {
|
|
282
|
+
success: false,
|
|
283
|
+
error: `Target "${options.target}" not found in config file.`,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const selectedTargets = options.target
|
|
287
|
+
? { [options.target]: baseConfig.targets[options.target] }
|
|
288
|
+
: baseConfig.targets;
|
|
289
|
+
const defaults = baseConfig.defaults ?? {};
|
|
290
|
+
const resolvedTargets = [];
|
|
291
|
+
for (const [name, target] of Object.entries(selectedTargets)) {
|
|
292
|
+
let mergedTarget = (0, config_1.mergeConfig)(defaults, target);
|
|
293
|
+
if (options.target && name === options.target) {
|
|
294
|
+
mergedTarget = (0, config_1.mergeConfig)(mergedTarget, overrides);
|
|
295
|
+
}
|
|
296
|
+
if (!mergedTarget.endpoint && !mergedTarget.schema) {
|
|
297
|
+
return {
|
|
298
|
+
success: false,
|
|
299
|
+
error: `Target "${name}" is missing an endpoint or schema.`,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
resolvedTargets.push({
|
|
303
|
+
name,
|
|
304
|
+
config: (0, config_1.resolveConfig)(mergedTarget),
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
return {
|
|
308
|
+
success: true,
|
|
309
|
+
targets: resolvedTargets,
|
|
310
|
+
isMulti: true,
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
if (options.target) {
|
|
314
|
+
return {
|
|
315
|
+
success: false,
|
|
316
|
+
error: 'Config file does not define targets. Remove --target to continue.',
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
const mergedConfig = (0, config_1.mergeConfig)(baseConfig, overrides);
|
|
201
320
|
if (!mergedConfig.endpoint && !mergedConfig.schema) {
|
|
202
321
|
return {
|
|
203
322
|
success: false,
|
|
204
323
|
error: 'No source specified. Use --endpoint or --schema, or create a config file with "graphql-codegen init".',
|
|
205
324
|
};
|
|
206
325
|
}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
326
|
+
return {
|
|
327
|
+
success: true,
|
|
328
|
+
targets: [{ name: 'default', config: (0, config_1.resolveConfig)(mergedConfig) }],
|
|
329
|
+
isMulti: false,
|
|
330
|
+
};
|
|
210
331
|
}
|
|
211
332
|
async function writeGeneratedFiles(files, outputDir, subdirs, options = {}) {
|
|
212
333
|
const { showProgress = true } = options;
|
|
@@ -262,9 +383,7 @@ async function writeGeneratedFiles(files, outputDir, subdirs, options = {}) {
|
|
|
262
383
|
// Ignore if already exists
|
|
263
384
|
}
|
|
264
385
|
try {
|
|
265
|
-
|
|
266
|
-
const formattedContent = await formatCode(file.content);
|
|
267
|
-
fs.writeFileSync(filePath, formattedContent, 'utf-8');
|
|
386
|
+
fs.writeFileSync(filePath, file.content, 'utf-8');
|
|
268
387
|
written.push(filePath);
|
|
269
388
|
}
|
|
270
389
|
catch (err) {
|
|
@@ -276,23 +395,44 @@ async function writeGeneratedFiles(files, outputDir, subdirs, options = {}) {
|
|
|
276
395
|
if (showProgress && isTTY) {
|
|
277
396
|
process.stdout.write('\r' + ' '.repeat(40) + '\r');
|
|
278
397
|
}
|
|
398
|
+
// Format all generated files with oxfmt
|
|
399
|
+
if (errors.length === 0) {
|
|
400
|
+
if (showProgress) {
|
|
401
|
+
console.log('Formatting generated files...');
|
|
402
|
+
}
|
|
403
|
+
const formatResult = formatOutput(outputDir);
|
|
404
|
+
if (!formatResult.success && showProgress) {
|
|
405
|
+
console.warn('Warning: Failed to format generated files:', formatResult.error);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
279
408
|
return {
|
|
280
409
|
success: errors.length === 0,
|
|
281
410
|
filesWritten: written,
|
|
282
411
|
errors: errors.length > 0 ? errors : undefined,
|
|
283
412
|
};
|
|
284
413
|
}
|
|
285
|
-
|
|
414
|
+
/**
|
|
415
|
+
* Format generated files using oxfmt
|
|
416
|
+
* Runs oxfmt on the output directory after all files are written
|
|
417
|
+
*/
|
|
418
|
+
function formatOutput(outputDir) {
|
|
419
|
+
// Resolve to absolute path for reliable execution
|
|
420
|
+
const absoluteOutputDir = path.resolve(outputDir);
|
|
286
421
|
try {
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
422
|
+
// Find oxfmt binary from this package's node_modules/.bin
|
|
423
|
+
// oxfmt is a dependency of @constructive-io/graphql-codegen
|
|
424
|
+
const oxfmtPkgPath = require.resolve('oxfmt/package.json');
|
|
425
|
+
const oxfmtDir = path.dirname(oxfmtPkgPath);
|
|
426
|
+
const oxfmtBin = path.join(oxfmtDir, 'bin', 'oxfmt');
|
|
427
|
+
(0, node_child_process_1.execSync)(`"${oxfmtBin}" "${absoluteOutputDir}"`, {
|
|
428
|
+
stdio: 'pipe',
|
|
429
|
+
encoding: 'utf-8',
|
|
292
430
|
});
|
|
431
|
+
return { success: true };
|
|
293
432
|
}
|
|
294
|
-
catch {
|
|
295
|
-
//
|
|
296
|
-
|
|
433
|
+
catch (err) {
|
|
434
|
+
// oxfmt may fail if files have syntax errors or if not installed
|
|
435
|
+
const message = err instanceof Error ? err.message : 'Unknown error';
|
|
436
|
+
return { success: false, error: message };
|
|
297
437
|
}
|
|
298
438
|
}
|
package/cli/commands/init.js
CHANGED
|
@@ -52,6 +52,15 @@ export default defineConfig({
|
|
|
52
52
|
// Output directory for generated files
|
|
53
53
|
output: '{{OUTPUT}}',
|
|
54
54
|
|
|
55
|
+
// Optional: Multi-target config (use instead of endpoint/output)
|
|
56
|
+
// defaults: {
|
|
57
|
+
// headers: { Authorization: 'Bearer YOUR_TOKEN' },
|
|
58
|
+
// },
|
|
59
|
+
// targets: {
|
|
60
|
+
// public: { endpoint: 'https://api.example.com/graphql', output: './generated/public' },
|
|
61
|
+
// admin: { schema: './admin.schema.graphql', output: './generated/admin' },
|
|
62
|
+
// },
|
|
63
|
+
|
|
55
64
|
// Optional: Tables to include/exclude (supports glob patterns)
|
|
56
65
|
// tables: {
|
|
57
66
|
// include: ['*'],
|
|
@@ -76,7 +85,7 @@ export default defineConfig({
|
|
|
76
85
|
* Execute the init command
|
|
77
86
|
*/
|
|
78
87
|
async function initCommand(options = {}) {
|
|
79
|
-
const { directory = process.cwd(), force = false, endpoint = '', output = './generated' } = options;
|
|
88
|
+
const { directory = process.cwd(), force = false, endpoint = '', output = './generated', } = options;
|
|
80
89
|
const configPath = path.join(directory, CONFIG_FILENAME);
|
|
81
90
|
// Check if config already exists
|
|
82
91
|
if (fs.existsSync(configPath) && !force) {
|
|
@@ -86,9 +95,7 @@ async function initCommand(options = {}) {
|
|
|
86
95
|
};
|
|
87
96
|
}
|
|
88
97
|
// Generate config content
|
|
89
|
-
const content = CONFIG_TEMPLATE
|
|
90
|
-
.replace('{{ENDPOINT}}', endpoint || 'http://localhost:5000/graphql')
|
|
91
|
-
.replace('{{OUTPUT}}', output);
|
|
98
|
+
const content = CONFIG_TEMPLATE.replace('{{ENDPOINT}}', endpoint || 'http://localhost:5000/graphql').replace('{{OUTPUT}}', output);
|
|
92
99
|
try {
|
|
93
100
|
// Ensure directory exists
|
|
94
101
|
fs.mkdirSync(directory, { recursive: true });
|
|
@@ -134,10 +141,11 @@ function findConfigFile(startDir = process.cwd()) {
|
|
|
134
141
|
* tsx or ts-node installed.
|
|
135
142
|
*/
|
|
136
143
|
async function loadConfigFile(configPath) {
|
|
137
|
-
|
|
144
|
+
const resolvedPath = path.resolve(configPath);
|
|
145
|
+
if (!fs.existsSync(resolvedPath)) {
|
|
138
146
|
return {
|
|
139
147
|
success: false,
|
|
140
|
-
error: `Config file not found: ${
|
|
148
|
+
error: `Config file not found: ${resolvedPath}`,
|
|
141
149
|
};
|
|
142
150
|
}
|
|
143
151
|
try {
|
|
@@ -148,19 +156,31 @@ async function loadConfigFile(configPath) {
|
|
|
148
156
|
debug: process.env.JITI_DEBUG === '1',
|
|
149
157
|
});
|
|
150
158
|
// jiti.import() with { default: true } returns mod?.default ?? mod
|
|
151
|
-
const config = await jiti.import(
|
|
159
|
+
const config = await jiti.import(resolvedPath, { default: true });
|
|
152
160
|
if (!config || typeof config !== 'object') {
|
|
153
161
|
return {
|
|
154
162
|
success: false,
|
|
155
163
|
error: 'Config file must export a configuration object',
|
|
156
164
|
};
|
|
157
165
|
}
|
|
158
|
-
|
|
166
|
+
const hasEndpoint = 'endpoint' in config;
|
|
167
|
+
const hasSchema = 'schema' in config;
|
|
168
|
+
const hasTargets = 'targets' in config;
|
|
169
|
+
if (!hasEndpoint && !hasSchema && !hasTargets) {
|
|
159
170
|
return {
|
|
160
171
|
success: false,
|
|
161
|
-
error: 'Config file
|
|
172
|
+
error: 'Config file must define "endpoint", "schema", or "targets".',
|
|
162
173
|
};
|
|
163
174
|
}
|
|
175
|
+
if (hasTargets) {
|
|
176
|
+
const targets = config.targets;
|
|
177
|
+
if (!targets || typeof targets !== 'object' || Array.isArray(targets)) {
|
|
178
|
+
return {
|
|
179
|
+
success: false,
|
|
180
|
+
error: 'Config file "targets" must be an object of named configs.',
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
}
|
|
164
184
|
return {
|
|
165
185
|
success: true,
|
|
166
186
|
config,
|