@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.
Files changed (66) hide show
  1. package/README.md +403 -279
  2. package/cli/codegen/babel-ast.d.ts +7 -0
  3. package/cli/codegen/babel-ast.js +15 -0
  4. package/cli/codegen/barrel.js +43 -14
  5. package/cli/codegen/custom-mutations.js +4 -4
  6. package/cli/codegen/custom-queries.js +12 -22
  7. package/cli/codegen/gql-ast.js +22 -1
  8. package/cli/codegen/index.js +1 -0
  9. package/cli/codegen/mutations.d.ts +2 -0
  10. package/cli/codegen/mutations.js +26 -13
  11. package/cli/codegen/orm/client-generator.js +475 -136
  12. package/cli/codegen/orm/custom-ops-generator.js +8 -3
  13. package/cli/codegen/orm/input-types-generator.js +22 -0
  14. package/cli/codegen/orm/model-generator.js +18 -5
  15. package/cli/codegen/orm/select-types.d.ts +33 -0
  16. package/cli/codegen/queries.d.ts +1 -1
  17. package/cli/codegen/queries.js +112 -35
  18. package/cli/codegen/utils.d.ts +6 -0
  19. package/cli/codegen/utils.js +19 -0
  20. package/cli/commands/generate-orm.d.ts +14 -0
  21. package/cli/commands/generate-orm.js +160 -44
  22. package/cli/commands/generate.d.ts +22 -0
  23. package/cli/commands/generate.js +195 -55
  24. package/cli/commands/init.js +29 -9
  25. package/cli/index.js +133 -28
  26. package/cli/watch/orchestrator.d.ts +4 -0
  27. package/cli/watch/orchestrator.js +4 -0
  28. package/esm/cli/codegen/babel-ast.d.ts +7 -0
  29. package/esm/cli/codegen/babel-ast.js +14 -0
  30. package/esm/cli/codegen/barrel.js +44 -15
  31. package/esm/cli/codegen/custom-mutations.js +5 -5
  32. package/esm/cli/codegen/custom-queries.js +13 -23
  33. package/esm/cli/codegen/gql-ast.js +23 -2
  34. package/esm/cli/codegen/index.js +1 -0
  35. package/esm/cli/codegen/mutations.d.ts +2 -0
  36. package/esm/cli/codegen/mutations.js +27 -14
  37. package/esm/cli/codegen/orm/client-generator.js +475 -136
  38. package/esm/cli/codegen/orm/custom-ops-generator.js +8 -3
  39. package/esm/cli/codegen/orm/input-types-generator.js +22 -0
  40. package/esm/cli/codegen/orm/model-generator.js +18 -5
  41. package/esm/cli/codegen/orm/select-types.d.ts +33 -0
  42. package/esm/cli/codegen/queries.d.ts +1 -1
  43. package/esm/cli/codegen/queries.js +114 -37
  44. package/esm/cli/codegen/utils.d.ts +6 -0
  45. package/esm/cli/codegen/utils.js +18 -0
  46. package/esm/cli/commands/generate-orm.d.ts +14 -0
  47. package/esm/cli/commands/generate-orm.js +161 -45
  48. package/esm/cli/commands/generate.d.ts +22 -0
  49. package/esm/cli/commands/generate.js +195 -56
  50. package/esm/cli/commands/init.js +29 -9
  51. package/esm/cli/index.js +134 -29
  52. package/esm/cli/watch/orchestrator.d.ts +4 -0
  53. package/esm/cli/watch/orchestrator.js +5 -1
  54. package/esm/types/config.d.ts +39 -2
  55. package/esm/types/config.js +88 -4
  56. package/esm/types/index.d.ts +2 -2
  57. package/esm/types/index.js +1 -1
  58. package/package.json +10 -7
  59. package/types/config.d.ts +39 -2
  60. package/types/config.js +91 -4
  61. package/types/index.d.ts +2 -2
  62. package/types/index.js +2 -1
  63. package/cli/codegen/orm/query-builder.d.ts +0 -161
  64. package/cli/codegen/orm/query-builder.js +0 -366
  65. package/esm/cli/codegen/orm/query-builder.d.ts +0 -161
  66. package/esm/cli/codegen/orm/query-builder.js +0 -353
@@ -19,9 +19,9 @@ const orm_1 = require("../codegen/orm");
19
19
  * Execute the generate-orm command
20
20
  */
21
21
  async function generateOrmCommand(options = {}) {
22
- const log = options.verbose ? console.log : () => { };
23
- // 1. Load config
24
- log('Loading configuration...');
22
+ if (options.verbose) {
23
+ console.log('Loading configuration...');
24
+ }
25
25
  const configResult = await loadConfig(options);
26
26
  if (!configResult.success) {
27
27
  return {
@@ -29,26 +29,73 @@ async function generateOrmCommand(options = {}) {
29
29
  message: configResult.error,
30
30
  };
31
31
  }
32
- const config = configResult.config;
33
- // Use ORM output directory if specified, otherwise default
34
- const outputDir = options.output || config.orm?.output || './generated/orm';
35
- // Log source
36
- if (config.schema) {
37
- log(` Schema: ${config.schema}`);
32
+ const targets = configResult.targets ?? [];
33
+ if (targets.length === 0) {
34
+ return {
35
+ success: false,
36
+ message: 'No targets resolved from configuration.',
37
+ };
38
+ }
39
+ const isMultiTarget = configResult.isMulti ?? targets.length > 1;
40
+ const results = [];
41
+ for (const target of targets) {
42
+ const result = await generateOrmForTarget(target, options, isMultiTarget);
43
+ results.push(result);
44
+ }
45
+ if (!isMultiTarget) {
46
+ const [result] = results;
47
+ return {
48
+ success: result.success,
49
+ message: result.message,
50
+ targets: results,
51
+ tables: result.tables,
52
+ customQueries: result.customQueries,
53
+ customMutations: result.customMutations,
54
+ filesWritten: result.filesWritten,
55
+ errors: result.errors,
56
+ };
38
57
  }
39
- else {
40
- log(` Endpoint: ${config.endpoint}`);
58
+ const successCount = results.filter((result) => result.success).length;
59
+ const failedCount = results.length - successCount;
60
+ const summaryMessage = failedCount === 0
61
+ ? `Generated ORM clients for ${results.length} targets.`
62
+ : `Generated ORM clients for ${successCount} of ${results.length} targets.`;
63
+ return {
64
+ success: failedCount === 0,
65
+ message: summaryMessage,
66
+ targets: results,
67
+ errors: failedCount > 0
68
+ ? results.flatMap((result) => result.errors ?? [])
69
+ : undefined,
70
+ };
71
+ }
72
+ async function generateOrmForTarget(target, options, isMultiTarget) {
73
+ const config = target.config;
74
+ const outputDir = options.output || config.orm?.output || './generated/orm';
75
+ const prefix = isMultiTarget ? `[${target.name}] ` : '';
76
+ const log = options.verbose
77
+ ? (message) => console.log(`${prefix}${message}`)
78
+ : () => { };
79
+ const formatMessage = (message) => isMultiTarget ? `Target "${target.name}": ${message}` : message;
80
+ if (isMultiTarget) {
81
+ console.log(`\nTarget "${target.name}"`);
82
+ const sourceLabel = config.schema
83
+ ? `schema: ${config.schema}`
84
+ : `endpoint: ${config.endpoint}`;
85
+ console.log(` Source: ${sourceLabel}`);
86
+ console.log(` Output: ${outputDir}`);
41
87
  }
42
- log(` Output: ${outputDir}`);
43
- // 2. Create schema source
88
+ // 1. Validate source
44
89
  const sourceValidation = (0, source_1.validateSourceOptions)({
45
90
  endpoint: config.endpoint || undefined,
46
91
  schema: config.schema || undefined,
47
92
  });
48
93
  if (!sourceValidation.valid) {
49
94
  return {
95
+ name: target.name,
96
+ output: outputDir,
50
97
  success: false,
51
- message: sourceValidation.error,
98
+ message: formatMessage(sourceValidation.error),
52
99
  };
53
100
  }
54
101
  const source = (0, source_1.createSchemaSource)({
@@ -57,7 +104,7 @@ async function generateOrmCommand(options = {}) {
57
104
  authorization: options.authorization || config.headers['Authorization'],
58
105
  headers: config.headers,
59
106
  });
60
- // 3. Run the codegen pipeline
107
+ // 2. Run the codegen pipeline
61
108
  let pipelineResult;
62
109
  try {
63
110
  pipelineResult = await (0, shared_1.runCodegenPipeline)({
@@ -69,21 +116,25 @@ async function generateOrmCommand(options = {}) {
69
116
  }
70
117
  catch (err) {
71
118
  return {
119
+ name: target.name,
120
+ output: outputDir,
72
121
  success: false,
73
- message: `Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}`,
122
+ message: formatMessage(`Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}`),
74
123
  };
75
124
  }
76
125
  const { tables, customOperations, stats } = pipelineResult;
77
- // 4. Validate tables found
126
+ // 3. Validate tables found
78
127
  const tablesValidation = (0, shared_1.validateTablesFound)(tables);
79
128
  if (!tablesValidation.valid) {
80
129
  return {
130
+ name: target.name,
131
+ output: outputDir,
81
132
  success: false,
82
- message: tablesValidation.error,
133
+ message: formatMessage(tablesValidation.error),
83
134
  };
84
135
  }
85
- // 5. Generate ORM code
86
- console.log('Generating code...');
136
+ // 4. Generate ORM code
137
+ console.log(`${prefix}Generating code...`);
87
138
  const { files: generatedFiles, stats: genStats } = (0, orm_1.generateOrm)({
88
139
  tables,
89
140
  customOperations: {
@@ -93,7 +144,7 @@ async function generateOrmCommand(options = {}) {
93
144
  },
94
145
  config,
95
146
  });
96
- console.log(`Generated ${genStats.totalFiles} files`);
147
+ console.log(`${prefix}Generated ${genStats.totalFiles} files`);
97
148
  log(` ${genStats.tables} table models`);
98
149
  log(` ${genStats.customQueries} custom query operations`);
99
150
  log(` ${genStats.customMutations} custom mutation operations`);
@@ -101,15 +152,17 @@ async function generateOrmCommand(options = {}) {
101
152
  const customMutations = customOperations.mutations.map((m) => m.name);
102
153
  if (options.dryRun) {
103
154
  return {
155
+ name: target.name,
156
+ output: outputDir,
104
157
  success: true,
105
- message: `Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${stats.customQueries + stats.customMutations} custom operations.`,
158
+ message: formatMessage(`Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${stats.customQueries + stats.customMutations} custom operations.`),
106
159
  tables: tables.map((t) => t.name),
107
160
  customQueries,
108
161
  customMutations,
109
162
  filesWritten: generatedFiles.map((f) => f.path),
110
163
  };
111
164
  }
112
- // 6. Write files
165
+ // 5. Write files
113
166
  log('Writing files...');
114
167
  const writeResult = await (0, generate_1.writeGeneratedFiles)(generatedFiles, outputDir, [
115
168
  'models',
@@ -118,23 +171,45 @@ async function generateOrmCommand(options = {}) {
118
171
  ]);
119
172
  if (!writeResult.success) {
120
173
  return {
174
+ name: target.name,
175
+ output: outputDir,
121
176
  success: false,
122
- message: `Failed to write files: ${writeResult.errors?.join(', ')}`,
177
+ message: formatMessage(`Failed to write files: ${writeResult.errors?.join(', ')}`),
123
178
  errors: writeResult.errors,
124
179
  };
125
180
  }
126
181
  const totalOps = customQueries.length + customMutations.length;
127
182
  const customOpsMsg = totalOps > 0 ? ` and ${totalOps} custom operations` : '';
128
183
  return {
184
+ name: target.name,
185
+ output: outputDir,
129
186
  success: true,
130
- message: `Generated ORM client for ${tables.length} tables${customOpsMsg}. Files written to ${outputDir}`,
187
+ message: formatMessage(`Generated ORM client for ${tables.length} tables${customOpsMsg}. Files written to ${outputDir}`),
131
188
  tables: tables.map((t) => t.name),
132
189
  customQueries,
133
190
  customMutations,
134
191
  filesWritten: writeResult.filesWritten,
135
192
  };
136
193
  }
194
+ function buildTargetOverrides(options) {
195
+ const overrides = {};
196
+ if (options.endpoint) {
197
+ overrides.endpoint = options.endpoint;
198
+ overrides.schema = undefined;
199
+ }
200
+ if (options.schema) {
201
+ overrides.schema = options.schema;
202
+ overrides.endpoint = undefined;
203
+ }
204
+ return overrides;
205
+ }
137
206
  async function loadConfig(options) {
207
+ if (options.endpoint && options.schema) {
208
+ return {
209
+ success: false,
210
+ error: 'Cannot use both --endpoint and --schema. Choose one source.',
211
+ };
212
+ }
138
213
  // Find config file
139
214
  let configPath = options.config;
140
215
  if (!configPath) {
@@ -148,29 +223,70 @@ async function loadConfig(options) {
148
223
  }
149
224
  baseConfig = loadResult.config;
150
225
  }
151
- // Override with CLI options
152
- const mergedConfig = {
153
- endpoint: options.endpoint || baseConfig.endpoint,
154
- schema: options.schema || baseConfig.schema,
155
- output: options.output || baseConfig.output,
156
- headers: baseConfig.headers,
157
- tables: baseConfig.tables,
158
- queries: baseConfig.queries,
159
- mutations: baseConfig.mutations,
160
- excludeFields: baseConfig.excludeFields,
161
- hooks: baseConfig.hooks,
162
- postgraphile: baseConfig.postgraphile,
163
- codegen: baseConfig.codegen,
164
- orm: baseConfig.orm,
165
- };
166
- // Validate at least one source is provided
226
+ const overrides = buildTargetOverrides(options);
227
+ if ((0, config_1.isMultiConfig)(baseConfig)) {
228
+ if (Object.keys(baseConfig.targets).length === 0) {
229
+ return {
230
+ success: false,
231
+ error: 'Config file defines no targets.',
232
+ };
233
+ }
234
+ if (!options.target &&
235
+ (options.endpoint || options.schema || options.output)) {
236
+ return {
237
+ success: false,
238
+ error: 'Multiple targets configured. Use --target with --endpoint, --schema, or --output.',
239
+ };
240
+ }
241
+ if (options.target && !baseConfig.targets[options.target]) {
242
+ return {
243
+ success: false,
244
+ error: `Target "${options.target}" not found in config file.`,
245
+ };
246
+ }
247
+ const selectedTargets = options.target
248
+ ? { [options.target]: baseConfig.targets[options.target] }
249
+ : baseConfig.targets;
250
+ const defaults = baseConfig.defaults ?? {};
251
+ const resolvedTargets = [];
252
+ for (const [name, target] of Object.entries(selectedTargets)) {
253
+ let mergedTarget = (0, config_1.mergeConfig)(defaults, target);
254
+ if (options.target && name === options.target) {
255
+ mergedTarget = (0, config_1.mergeConfig)(mergedTarget, overrides);
256
+ }
257
+ if (!mergedTarget.endpoint && !mergedTarget.schema) {
258
+ return {
259
+ success: false,
260
+ error: `Target "${name}" is missing an endpoint or schema.`,
261
+ };
262
+ }
263
+ resolvedTargets.push({
264
+ name,
265
+ config: (0, config_1.resolveConfig)(mergedTarget),
266
+ });
267
+ }
268
+ return {
269
+ success: true,
270
+ targets: resolvedTargets,
271
+ isMulti: true,
272
+ };
273
+ }
274
+ if (options.target) {
275
+ return {
276
+ success: false,
277
+ error: 'Config file does not define targets. Remove --target to continue.',
278
+ };
279
+ }
280
+ const mergedConfig = (0, config_1.mergeConfig)(baseConfig, overrides);
167
281
  if (!mergedConfig.endpoint && !mergedConfig.schema) {
168
282
  return {
169
283
  success: false,
170
284
  error: 'No source specified. Use --endpoint or --schema, or create a config file with "graphql-codegen init".',
171
285
  };
172
286
  }
173
- // Resolve with defaults
174
- const config = (0, config_1.resolveConfig)(mergedConfig);
175
- return { success: true, config };
287
+ return {
288
+ success: true,
289
+ targets: [{ name: 'default', config: (0, config_1.resolveConfig)(mergedConfig) }],
290
+ isMulti: false,
291
+ };
176
292
  }
@@ -1,6 +1,8 @@
1
1
  export interface GenerateOptions {
2
2
  /** Path to config file */
3
3
  config?: string;
4
+ /** Named target in a multi-target config */
5
+ target?: string;
4
6
  /** GraphQL endpoint URL (overrides config) */
5
7
  endpoint?: string;
6
8
  /** Path to GraphQL schema file (.graphql) */
@@ -16,9 +18,21 @@ export interface GenerateOptions {
16
18
  /** Skip custom operations (only generate table CRUD) */
17
19
  skipCustomOperations?: boolean;
18
20
  }
21
+ export interface GenerateTargetResult {
22
+ name: string;
23
+ output: string;
24
+ success: boolean;
25
+ message: string;
26
+ tables?: string[];
27
+ customQueries?: string[];
28
+ customMutations?: string[];
29
+ filesWritten?: string[];
30
+ errors?: string[];
31
+ }
19
32
  export interface GenerateResult {
20
33
  success: boolean;
21
34
  message: string;
35
+ targets?: GenerateTargetResult[];
22
36
  tables?: string[];
23
37
  customQueries?: string[];
24
38
  customMutations?: string[];
@@ -42,3 +56,11 @@ export interface WriteOptions {
42
56
  showProgress?: boolean;
43
57
  }
44
58
  export declare function writeGeneratedFiles(files: GeneratedFile[], outputDir: string, subdirs: string[], options?: WriteOptions): Promise<WriteResult>;
59
+ /**
60
+ * Format generated files using oxfmt
61
+ * Runs oxfmt on the output directory after all files are written
62
+ */
63
+ export declare function formatOutput(outputDir: string): {
64
+ success: boolean;
65
+ error?: string;
66
+ };