@constructive-io/graphql-codegen 2.22.1 → 2.23.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/codegen/barrel.d.ts +5 -1
- package/cli/codegen/barrel.js +13 -11
- package/cli/codegen/index.d.ts +3 -3
- package/cli/codegen/index.js +15 -9
- package/cli/codegen/orm/client-generator.js +3 -2
- package/cli/codegen/orm/custom-ops-generator.js +17 -4
- package/cli/codegen/orm/input-types-generator.js +129 -18
- package/cli/codegen/orm/model-generator.js +2 -1
- package/cli/codegen/orm/query-builder.d.ts +1 -1
- package/cli/codegen/orm/query-builder.js +2 -2
- package/cli/codegen/schema-types-generator.js +5 -5
- package/cli/codegen/utils.d.ts +6 -1
- package/cli/codegen/utils.js +23 -8
- package/cli/commands/generate-orm.d.ts +5 -3
- package/cli/commands/generate-orm.js +65 -84
- package/cli/commands/generate.d.ts +2 -0
- package/cli/commands/generate.js +66 -87
- package/cli/commands/shared.d.ts +74 -0
- package/cli/commands/shared.js +88 -0
- package/cli/index.js +75 -45
- package/cli/introspect/index.d.ts +8 -5
- package/cli/introspect/index.js +19 -7
- package/cli/introspect/infer-tables.d.ts +51 -0
- package/cli/introspect/infer-tables.js +550 -0
- package/cli/introspect/source/endpoint.d.ts +34 -0
- package/cli/introspect/source/endpoint.js +35 -0
- package/cli/introspect/source/file.d.ts +20 -0
- package/cli/introspect/source/file.js +103 -0
- package/cli/introspect/source/index.d.ts +48 -0
- package/cli/introspect/source/index.js +72 -0
- package/cli/introspect/source/types.d.ts +58 -0
- package/cli/introspect/source/types.js +27 -0
- package/cli/introspect/transform.d.ts +5 -6
- package/cli/introspect/transform.js +0 -173
- package/cli/watch/cache.d.ts +3 -4
- package/cli/watch/cache.js +6 -10
- package/cli/watch/poller.d.ts +1 -2
- package/cli/watch/poller.js +27 -45
- package/cli/watch/types.d.ts +0 -3
- package/core/ast.js +4 -4
- package/core/query-builder.js +12 -12
- package/esm/cli/codegen/barrel.d.ts +5 -1
- package/esm/cli/codegen/barrel.js +13 -11
- package/esm/cli/codegen/index.d.ts +3 -3
- package/esm/cli/codegen/index.js +18 -12
- package/esm/cli/codegen/orm/client-generator.js +3 -2
- package/esm/cli/codegen/orm/custom-ops-generator.js +18 -5
- package/esm/cli/codegen/orm/input-types-generator.js +130 -19
- package/esm/cli/codegen/orm/model-generator.js +3 -2
- package/esm/cli/codegen/orm/query-builder.d.ts +1 -1
- package/esm/cli/codegen/orm/query-builder.js +2 -2
- package/esm/cli/codegen/schema-types-generator.js +6 -6
- package/esm/cli/codegen/utils.d.ts +6 -1
- package/esm/cli/codegen/utils.js +22 -8
- package/esm/cli/commands/generate-orm.d.ts +5 -3
- package/esm/cli/commands/generate-orm.js +65 -84
- package/esm/cli/commands/generate.d.ts +2 -0
- package/esm/cli/commands/generate.js +66 -87
- package/esm/cli/commands/shared.d.ts +74 -0
- package/esm/cli/commands/shared.js +84 -0
- package/esm/cli/index.js +76 -46
- package/esm/cli/introspect/index.d.ts +8 -5
- package/esm/cli/introspect/index.js +10 -3
- package/esm/cli/introspect/infer-tables.d.ts +51 -0
- package/esm/cli/introspect/infer-tables.js +547 -0
- package/esm/cli/introspect/source/endpoint.d.ts +34 -0
- package/esm/cli/introspect/source/endpoint.js +31 -0
- package/esm/cli/introspect/source/file.d.ts +20 -0
- package/esm/cli/introspect/source/file.js +66 -0
- package/esm/cli/introspect/source/index.d.ts +48 -0
- package/esm/cli/introspect/source/index.js +54 -0
- package/esm/cli/introspect/source/types.d.ts +58 -0
- package/esm/cli/introspect/source/types.js +23 -0
- package/esm/cli/introspect/transform.d.ts +5 -6
- package/esm/cli/introspect/transform.js +0 -172
- package/esm/cli/watch/cache.d.ts +3 -4
- package/esm/cli/watch/cache.js +7 -11
- package/esm/cli/watch/poller.d.ts +1 -2
- package/esm/cli/watch/poller.js +28 -46
- package/esm/cli/watch/types.d.ts +0 -3
- package/esm/core/ast.js +4 -4
- package/esm/core/query-builder.js +12 -12
- package/esm/generators/mutations.js +3 -3
- package/esm/generators/select.js +7 -7
- package/esm/types/config.d.ts +21 -5
- package/esm/types/config.js +2 -1
- package/generators/mutations.js +3 -3
- package/generators/select.js +7 -7
- package/package.json +5 -3
- package/types/config.d.ts +21 -5
- package/types/config.js +2 -1
- package/cli/introspect/fetch-meta.d.ts +0 -31
- package/cli/introspect/fetch-meta.js +0 -108
- package/cli/introspect/meta-query.d.ts +0 -111
- package/cli/introspect/meta-query.js +0 -191
- package/esm/cli/introspect/fetch-meta.d.ts +0 -31
- package/esm/cli/introspect/fetch-meta.js +0 -104
- package/esm/cli/introspect/meta-query.d.ts +0 -111
- package/esm/cli/introspect/meta-query.js +0 -188
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generate command -
|
|
2
|
+
* Generate command - generates SDK from GraphQL schema
|
|
3
3
|
*
|
|
4
4
|
* This command:
|
|
5
|
-
* 1. Fetches
|
|
6
|
-
* 2.
|
|
7
|
-
* 3.
|
|
8
|
-
* 4. Generates hooks for both table CRUD and custom operations
|
|
5
|
+
* 1. Fetches schema from endpoint or loads from file
|
|
6
|
+
* 2. Infers table metadata from introspection (replaces _meta)
|
|
7
|
+
* 3. Generates hooks for both table CRUD and custom operations
|
|
9
8
|
*/
|
|
10
9
|
import * as fs from 'node:fs';
|
|
11
10
|
import * as path from 'node:path';
|
|
12
11
|
import * as prettier from 'prettier';
|
|
13
12
|
import { resolveConfig } from '../../types/config';
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import { transformMetaToCleanTables, filterTables, } from '../introspect/transform';
|
|
17
|
-
import { transformSchemaToOperations, filterOperations, getTableOperationNames, getCustomOperations, } from '../introspect/transform-schema';
|
|
13
|
+
import { createSchemaSource, validateSourceOptions, } from '../introspect/source';
|
|
14
|
+
import { runCodegenPipeline, validateTablesFound } from './shared';
|
|
18
15
|
import { findConfigFile, loadConfigFile } from './init';
|
|
19
16
|
import { generate } from '../codegen';
|
|
20
17
|
/**
|
|
@@ -32,110 +29,90 @@ export async function generateCommand(options = {}) {
|
|
|
32
29
|
};
|
|
33
30
|
}
|
|
34
31
|
const config = configResult.config;
|
|
35
|
-
|
|
32
|
+
// Log source
|
|
33
|
+
if (config.schema) {
|
|
34
|
+
log(` Schema: ${config.schema}`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
log(` Endpoint: ${config.endpoint}`);
|
|
38
|
+
}
|
|
36
39
|
log(` Output: ${config.output}`);
|
|
37
|
-
// 2.
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
+
// 2. Create schema source
|
|
41
|
+
const sourceValidation = validateSourceOptions({
|
|
42
|
+
endpoint: config.endpoint || undefined,
|
|
43
|
+
schema: config.schema || undefined,
|
|
44
|
+
});
|
|
45
|
+
if (!sourceValidation.valid) {
|
|
40
46
|
return {
|
|
41
47
|
success: false,
|
|
42
|
-
message:
|
|
48
|
+
message: sourceValidation.error,
|
|
43
49
|
};
|
|
44
50
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const metaResult = await fetchMeta({
|
|
50
|
-
endpoint: config.endpoint,
|
|
51
|
-
authorization: authHeader,
|
|
51
|
+
const source = createSchemaSource({
|
|
52
|
+
endpoint: config.endpoint || undefined,
|
|
53
|
+
schema: config.schema || undefined,
|
|
54
|
+
authorization: options.authorization || config.headers['Authorization'],
|
|
52
55
|
headers: config.headers,
|
|
53
|
-
timeout: 30000,
|
|
54
56
|
});
|
|
55
|
-
|
|
57
|
+
// 3. Run the codegen pipeline
|
|
58
|
+
let pipelineResult;
|
|
59
|
+
try {
|
|
60
|
+
pipelineResult = await runCodegenPipeline({
|
|
61
|
+
source,
|
|
62
|
+
config,
|
|
63
|
+
verbose: options.verbose,
|
|
64
|
+
skipCustomOperations: options.skipCustomOperations,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
56
68
|
return {
|
|
57
69
|
success: false,
|
|
58
|
-
message: `Failed to fetch
|
|
70
|
+
message: `Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
59
71
|
};
|
|
60
72
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// 5. Filter tables
|
|
66
|
-
tables = filterTables(tables, config.tables.include, config.tables.exclude);
|
|
67
|
-
log(` After filtering: ${tables.length} tables`);
|
|
68
|
-
if (tables.length === 0) {
|
|
73
|
+
const { tables, customOperations, stats } = pipelineResult;
|
|
74
|
+
// 4. Validate tables found
|
|
75
|
+
const tablesValidation = validateTablesFound(tables);
|
|
76
|
+
if (!tablesValidation.valid) {
|
|
69
77
|
return {
|
|
70
78
|
success: false,
|
|
71
|
-
message:
|
|
79
|
+
message: tablesValidation.error,
|
|
72
80
|
};
|
|
73
81
|
}
|
|
74
|
-
//
|
|
75
|
-
const tableOperationNames = getTableOperationNames(tables);
|
|
76
|
-
// 6. Fetch __schema for custom operations (unless skipped)
|
|
77
|
-
let customQueries = [];
|
|
78
|
-
let customMutations = [];
|
|
79
|
-
let customOperationsData;
|
|
80
|
-
if (!options.skipCustomOperations) {
|
|
81
|
-
log('Fetching schema introspection (__schema)...');
|
|
82
|
-
const schemaResult = await fetchSchema({
|
|
83
|
-
endpoint: config.endpoint,
|
|
84
|
-
authorization: authHeader,
|
|
85
|
-
headers: config.headers,
|
|
86
|
-
timeout: 30000,
|
|
87
|
-
});
|
|
88
|
-
if (schemaResult.success && schemaResult.data) {
|
|
89
|
-
log('Transforming custom operations...');
|
|
90
|
-
// Transform to CleanOperation[]
|
|
91
|
-
const { queries: allQueries, mutations: allMutations, typeRegistry } = transformSchemaToOperations(schemaResult.data);
|
|
92
|
-
log(` Found ${allQueries.length} queries and ${allMutations.length} mutations total`);
|
|
93
|
-
// Filter by config include/exclude
|
|
94
|
-
const filteredQueries = filterOperations(allQueries, config.queries.include, config.queries.exclude);
|
|
95
|
-
const filteredMutations = filterOperations(allMutations, config.mutations.include, config.mutations.exclude);
|
|
96
|
-
log(` After config filtering: ${filteredQueries.length} queries, ${filteredMutations.length} mutations`);
|
|
97
|
-
// Remove table operations (already handled by table generators)
|
|
98
|
-
const customQueriesOps = getCustomOperations(filteredQueries, tableOperationNames);
|
|
99
|
-
const customMutationsOps = getCustomOperations(filteredMutations, tableOperationNames);
|
|
100
|
-
log(` Custom operations: ${customQueriesOps.length} queries, ${customMutationsOps.length} mutations`);
|
|
101
|
-
customQueries = customQueriesOps.map((q) => q.name);
|
|
102
|
-
customMutations = customMutationsOps.map((m) => m.name);
|
|
103
|
-
customOperationsData = {
|
|
104
|
-
queries: customQueriesOps,
|
|
105
|
-
mutations: customMutationsOps,
|
|
106
|
-
typeRegistry,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
else {
|
|
110
|
-
log(` Warning: Could not fetch __schema: ${schemaResult.error}`);
|
|
111
|
-
log(' Continuing with table-only generation...');
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// 7. Generate code
|
|
82
|
+
// 5. Generate code
|
|
115
83
|
console.log('Generating code...');
|
|
116
|
-
const { files: generatedFiles, stats } = generate({
|
|
84
|
+
const { files: generatedFiles, stats: genStats } = generate({
|
|
117
85
|
tables,
|
|
118
|
-
customOperations:
|
|
86
|
+
customOperations: {
|
|
87
|
+
queries: customOperations.queries,
|
|
88
|
+
mutations: customOperations.mutations,
|
|
89
|
+
typeRegistry: customOperations.typeRegistry,
|
|
90
|
+
},
|
|
119
91
|
config,
|
|
120
92
|
});
|
|
121
|
-
console.log(`Generated ${
|
|
122
|
-
log(` ${
|
|
123
|
-
log(` ${
|
|
124
|
-
log(` ${
|
|
125
|
-
log(` ${
|
|
93
|
+
console.log(`Generated ${genStats.totalFiles} files`);
|
|
94
|
+
log(` ${genStats.queryHooks} table query hooks`);
|
|
95
|
+
log(` ${genStats.mutationHooks} table mutation hooks`);
|
|
96
|
+
log(` ${genStats.customQueryHooks} custom query hooks`);
|
|
97
|
+
log(` ${genStats.customMutationHooks} custom mutation hooks`);
|
|
98
|
+
const customQueries = customOperations.queries.map((q) => q.name);
|
|
99
|
+
const customMutations = customOperations.mutations.map((m) => m.name);
|
|
126
100
|
if (options.dryRun) {
|
|
127
101
|
return {
|
|
128
102
|
success: true,
|
|
129
|
-
message: `Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${customQueries
|
|
103
|
+
message: `Dry run complete. Would generate ${generatedFiles.length} files for ${tables.length} tables and ${stats.customQueries + stats.customMutations} custom operations.`,
|
|
130
104
|
tables: tables.map((t) => t.name),
|
|
131
105
|
customQueries,
|
|
132
106
|
customMutations,
|
|
133
107
|
filesWritten: generatedFiles.map((f) => f.path),
|
|
134
108
|
};
|
|
135
109
|
}
|
|
136
|
-
//
|
|
110
|
+
// 6. Write files
|
|
137
111
|
log('Writing files...');
|
|
138
|
-
const writeResult = await writeGeneratedFiles(generatedFiles, config.output, [
|
|
112
|
+
const writeResult = await writeGeneratedFiles(generatedFiles, config.output, [
|
|
113
|
+
'queries',
|
|
114
|
+
'mutations',
|
|
115
|
+
]);
|
|
139
116
|
if (!writeResult.success) {
|
|
140
117
|
return {
|
|
141
118
|
success: false,
|
|
@@ -170,7 +147,8 @@ async function loadConfig(options) {
|
|
|
170
147
|
}
|
|
171
148
|
// Override with CLI options
|
|
172
149
|
const mergedConfig = {
|
|
173
|
-
endpoint: options.endpoint || baseConfig.endpoint
|
|
150
|
+
endpoint: options.endpoint || baseConfig.endpoint,
|
|
151
|
+
schema: options.schema || baseConfig.schema,
|
|
174
152
|
output: options.output || baseConfig.output,
|
|
175
153
|
headers: baseConfig.headers,
|
|
176
154
|
tables: baseConfig.tables,
|
|
@@ -181,10 +159,11 @@ async function loadConfig(options) {
|
|
|
181
159
|
postgraphile: baseConfig.postgraphile,
|
|
182
160
|
codegen: baseConfig.codegen,
|
|
183
161
|
};
|
|
184
|
-
|
|
162
|
+
// Validate at least one source is provided
|
|
163
|
+
if (!mergedConfig.endpoint && !mergedConfig.schema) {
|
|
185
164
|
return {
|
|
186
165
|
success: false,
|
|
187
|
-
error: 'No
|
|
166
|
+
error: 'No source specified. Use --endpoint or --schema, or create a config file with "graphql-codegen init".',
|
|
188
167
|
};
|
|
189
168
|
}
|
|
190
169
|
// Resolve with defaults
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Codegen Pipeline
|
|
3
|
+
*
|
|
4
|
+
* Consolidates the common logic between generate and generate-orm commands.
|
|
5
|
+
* Handles:
|
|
6
|
+
* - Schema fetching from source (endpoint or file)
|
|
7
|
+
* - Table inference from introspection
|
|
8
|
+
* - Operation transformation
|
|
9
|
+
* - Filtering
|
|
10
|
+
*/
|
|
11
|
+
import type { ResolvedConfig } from '../../types/config';
|
|
12
|
+
import type { CleanTable, CleanOperation, TypeRegistry } from '../../types/schema';
|
|
13
|
+
import type { SchemaSource } from '../introspect/source';
|
|
14
|
+
export interface CodegenPipelineOptions {
|
|
15
|
+
/**
|
|
16
|
+
* Schema source (endpoint or file)
|
|
17
|
+
*/
|
|
18
|
+
source: SchemaSource;
|
|
19
|
+
/**
|
|
20
|
+
* Resolved configuration
|
|
21
|
+
*/
|
|
22
|
+
config: ResolvedConfig;
|
|
23
|
+
/**
|
|
24
|
+
* Enable verbose logging
|
|
25
|
+
*/
|
|
26
|
+
verbose?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Skip custom operations (only generate table CRUD)
|
|
29
|
+
*/
|
|
30
|
+
skipCustomOperations?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface CodegenPipelineResult {
|
|
33
|
+
/**
|
|
34
|
+
* Inferred table metadata
|
|
35
|
+
*/
|
|
36
|
+
tables: CleanTable[];
|
|
37
|
+
/**
|
|
38
|
+
* Custom operations (queries and mutations not covered by tables)
|
|
39
|
+
*/
|
|
40
|
+
customOperations: {
|
|
41
|
+
queries: CleanOperation[];
|
|
42
|
+
mutations: CleanOperation[];
|
|
43
|
+
typeRegistry: TypeRegistry;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Statistics about what was found
|
|
47
|
+
*/
|
|
48
|
+
stats: {
|
|
49
|
+
totalTables: number;
|
|
50
|
+
filteredTables: number;
|
|
51
|
+
totalQueries: number;
|
|
52
|
+
totalMutations: number;
|
|
53
|
+
customQueries: number;
|
|
54
|
+
customMutations: number;
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Run the unified codegen pipeline
|
|
59
|
+
*
|
|
60
|
+
* This replaces the duplicated logic in generate.ts and generate-orm.ts:
|
|
61
|
+
* 1. Fetch introspection from source (endpoint or file)
|
|
62
|
+
* 2. Infer tables from introspection (replaces _meta query)
|
|
63
|
+
* 3. Transform to operations
|
|
64
|
+
* 4. Filter by config
|
|
65
|
+
* 5. Separate table operations from custom operations
|
|
66
|
+
*/
|
|
67
|
+
export declare function runCodegenPipeline(options: CodegenPipelineOptions): Promise<CodegenPipelineResult>;
|
|
68
|
+
/**
|
|
69
|
+
* Validate that tables were found
|
|
70
|
+
*/
|
|
71
|
+
export declare function validateTablesFound(tables: CleanTable[]): {
|
|
72
|
+
valid: boolean;
|
|
73
|
+
error?: string;
|
|
74
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { inferTablesFromIntrospection } from '../introspect/infer-tables';
|
|
2
|
+
import { filterTables } from '../introspect/transform';
|
|
3
|
+
import { transformSchemaToOperations, filterOperations, getTableOperationNames, getCustomOperations, } from '../introspect/transform-schema';
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Main Pipeline
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Run the unified codegen pipeline
|
|
9
|
+
*
|
|
10
|
+
* This replaces the duplicated logic in generate.ts and generate-orm.ts:
|
|
11
|
+
* 1. Fetch introspection from source (endpoint or file)
|
|
12
|
+
* 2. Infer tables from introspection (replaces _meta query)
|
|
13
|
+
* 3. Transform to operations
|
|
14
|
+
* 4. Filter by config
|
|
15
|
+
* 5. Separate table operations from custom operations
|
|
16
|
+
*/
|
|
17
|
+
export async function runCodegenPipeline(options) {
|
|
18
|
+
const { source, config, verbose = false, skipCustomOperations = false, } = options;
|
|
19
|
+
const log = verbose ? console.log : () => { };
|
|
20
|
+
// 1. Fetch introspection from source
|
|
21
|
+
log(`Fetching schema from ${source.describe()}...`);
|
|
22
|
+
const { introspection } = await source.fetch();
|
|
23
|
+
// 2. Infer tables from introspection (replaces _meta)
|
|
24
|
+
log('Inferring table metadata from schema...');
|
|
25
|
+
let tables = inferTablesFromIntrospection(introspection);
|
|
26
|
+
const totalTables = tables.length;
|
|
27
|
+
log(` Found ${totalTables} tables`);
|
|
28
|
+
// 3. Filter tables by config
|
|
29
|
+
tables = filterTables(tables, config.tables.include, config.tables.exclude);
|
|
30
|
+
const filteredTables = tables.length;
|
|
31
|
+
log(` After filtering: ${filteredTables} tables`);
|
|
32
|
+
// 4. Transform introspection to operations
|
|
33
|
+
log('Transforming operations...');
|
|
34
|
+
const { queries: allQueries, mutations: allMutations, typeRegistry, } = transformSchemaToOperations(introspection);
|
|
35
|
+
const totalQueries = allQueries.length;
|
|
36
|
+
const totalMutations = allMutations.length;
|
|
37
|
+
log(` Found ${totalQueries} queries and ${totalMutations} mutations total`);
|
|
38
|
+
// 5. Get table operation names for filtering custom ops
|
|
39
|
+
const tableOperationNames = getTableOperationNames(tables);
|
|
40
|
+
// 6. Filter and separate custom operations
|
|
41
|
+
let customQueries = [];
|
|
42
|
+
let customMutations = [];
|
|
43
|
+
if (!skipCustomOperations) {
|
|
44
|
+
// Filter by config include/exclude
|
|
45
|
+
const filteredQueries = filterOperations(allQueries, config.queries.include, config.queries.exclude);
|
|
46
|
+
const filteredMutations = filterOperations(allMutations, config.mutations.include, config.mutations.exclude);
|
|
47
|
+
log(` After config filtering: ${filteredQueries.length} queries, ${filteredMutations.length} mutations`);
|
|
48
|
+
// Remove table operations (already handled by table generators)
|
|
49
|
+
customQueries = getCustomOperations(filteredQueries, tableOperationNames);
|
|
50
|
+
customMutations = getCustomOperations(filteredMutations, tableOperationNames);
|
|
51
|
+
log(` Custom operations: ${customQueries.length} queries, ${customMutations.length} mutations`);
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
tables,
|
|
55
|
+
customOperations: {
|
|
56
|
+
queries: customQueries,
|
|
57
|
+
mutations: customMutations,
|
|
58
|
+
typeRegistry,
|
|
59
|
+
},
|
|
60
|
+
stats: {
|
|
61
|
+
totalTables,
|
|
62
|
+
filteredTables,
|
|
63
|
+
totalQueries,
|
|
64
|
+
totalMutations,
|
|
65
|
+
customQueries: customQueries.length,
|
|
66
|
+
customMutations: customMutations.length,
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Validation Helpers
|
|
72
|
+
// ============================================================================
|
|
73
|
+
/**
|
|
74
|
+
* Validate that tables were found
|
|
75
|
+
*/
|
|
76
|
+
export function validateTablesFound(tables) {
|
|
77
|
+
if (tables.length === 0) {
|
|
78
|
+
return {
|
|
79
|
+
valid: false,
|
|
80
|
+
error: 'No tables found after filtering. Check your include/exclude patterns.',
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return { valid: true };
|
|
84
|
+
}
|
package/esm/cli/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { initCommand, findConfigFile, loadConfigFile } from './commands/init';
|
|
|
6
6
|
import { generateCommand } from './commands/generate';
|
|
7
7
|
import { generateOrmCommand } from './commands/generate-orm';
|
|
8
8
|
import { startWatch } from './watch';
|
|
9
|
-
import { resolveConfig } from '../types/config';
|
|
9
|
+
import { resolveConfig, } from '../types/config';
|
|
10
10
|
const program = new Command();
|
|
11
11
|
/**
|
|
12
12
|
* Load configuration for watch mode, merging CLI options with config file
|
|
@@ -21,7 +21,7 @@ async function loadWatchConfig(options) {
|
|
|
21
21
|
if (configPath) {
|
|
22
22
|
const loadResult = await loadConfigFile(configPath);
|
|
23
23
|
if (!loadResult.success) {
|
|
24
|
-
console.error('
|
|
24
|
+
console.error('x', loadResult.error);
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
27
|
baseConfig = loadResult.config;
|
|
@@ -42,21 +42,23 @@ async function loadWatchConfig(options) {
|
|
|
42
42
|
watch: {
|
|
43
43
|
...baseConfig.watch,
|
|
44
44
|
// CLI options override config
|
|
45
|
-
...(options.pollInterval !== undefined && {
|
|
45
|
+
...(options.pollInterval !== undefined && {
|
|
46
|
+
pollInterval: options.pollInterval,
|
|
47
|
+
}),
|
|
46
48
|
...(options.debounce !== undefined && { debounce: options.debounce }),
|
|
47
49
|
...(options.touch !== undefined && { touchFile: options.touch }),
|
|
48
50
|
...(options.clear !== undefined && { clearScreen: options.clear }),
|
|
49
51
|
},
|
|
50
52
|
};
|
|
51
53
|
if (!mergedConfig.endpoint) {
|
|
52
|
-
console.error('
|
|
54
|
+
console.error('x No endpoint specified. Use --endpoint or create a config file with "graphql-codegen init".');
|
|
53
55
|
return null;
|
|
54
56
|
}
|
|
55
57
|
return resolveConfig(mergedConfig);
|
|
56
58
|
}
|
|
57
59
|
program
|
|
58
60
|
.name('graphql-codegen')
|
|
59
|
-
.description('CLI for generating GraphQL SDK from PostGraphile endpoints')
|
|
61
|
+
.description('CLI for generating GraphQL SDK from PostGraphile endpoints or schema files')
|
|
60
62
|
.version('2.17.48');
|
|
61
63
|
// Init command
|
|
62
64
|
program
|
|
@@ -74,19 +76,20 @@ program
|
|
|
74
76
|
output: options.output,
|
|
75
77
|
});
|
|
76
78
|
if (result.success) {
|
|
77
|
-
console.log('
|
|
79
|
+
console.log('[ok]', result.message);
|
|
78
80
|
}
|
|
79
81
|
else {
|
|
80
|
-
console.error('
|
|
82
|
+
console.error('x', result.message);
|
|
81
83
|
process.exit(1);
|
|
82
84
|
}
|
|
83
85
|
});
|
|
84
86
|
// Generate command
|
|
85
87
|
program
|
|
86
88
|
.command('generate')
|
|
87
|
-
.description('Generate SDK from GraphQL endpoint')
|
|
89
|
+
.description('Generate SDK from GraphQL endpoint or schema file')
|
|
88
90
|
.option('-c, --config <path>', 'Path to config file')
|
|
89
91
|
.option('-e, --endpoint <url>', 'GraphQL endpoint URL (overrides config)')
|
|
92
|
+
.option('-s, --schema <path>', 'Path to GraphQL schema file (.graphql)')
|
|
90
93
|
.option('-o, --output <dir>', 'Output directory (overrides config)')
|
|
91
94
|
.option('-a, --authorization <header>', 'Authorization header value')
|
|
92
95
|
.option('-v, --verbose', 'Verbose output', false)
|
|
@@ -97,8 +100,17 @@ program
|
|
|
97
100
|
.option('--touch <file>', 'File to touch on schema change')
|
|
98
101
|
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
99
102
|
.action(async (options) => {
|
|
100
|
-
//
|
|
103
|
+
// Validate source options
|
|
104
|
+
if (options.endpoint && options.schema) {
|
|
105
|
+
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
// Watch mode (only for endpoint)
|
|
101
109
|
if (options.watch) {
|
|
110
|
+
if (options.schema) {
|
|
111
|
+
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
112
|
+
process.exit(1);
|
|
113
|
+
}
|
|
102
114
|
const config = await loadWatchConfig(options);
|
|
103
115
|
if (!config) {
|
|
104
116
|
process.exit(1);
|
|
@@ -116,13 +128,14 @@ program
|
|
|
116
128
|
const result = await generateCommand({
|
|
117
129
|
config: options.config,
|
|
118
130
|
endpoint: options.endpoint,
|
|
131
|
+
schema: options.schema,
|
|
119
132
|
output: options.output,
|
|
120
133
|
authorization: options.authorization,
|
|
121
134
|
verbose: options.verbose,
|
|
122
135
|
dryRun: options.dryRun,
|
|
123
136
|
});
|
|
124
137
|
if (result.success) {
|
|
125
|
-
console.log('
|
|
138
|
+
console.log('[ok]', result.message);
|
|
126
139
|
if (result.tables && result.tables.length > 0) {
|
|
127
140
|
console.log('\nTables:');
|
|
128
141
|
result.tables.forEach((t) => console.log(` - ${t}`));
|
|
@@ -133,7 +146,7 @@ program
|
|
|
133
146
|
}
|
|
134
147
|
}
|
|
135
148
|
else {
|
|
136
|
-
console.error('
|
|
149
|
+
console.error('x', result.message);
|
|
137
150
|
if (result.errors) {
|
|
138
151
|
result.errors.forEach((e) => console.error(' -', e));
|
|
139
152
|
}
|
|
@@ -143,9 +156,10 @@ program
|
|
|
143
156
|
// Generate ORM command
|
|
144
157
|
program
|
|
145
158
|
.command('generate-orm')
|
|
146
|
-
.description('Generate Prisma-like ORM client from GraphQL endpoint')
|
|
159
|
+
.description('Generate Prisma-like ORM client from GraphQL endpoint or schema file')
|
|
147
160
|
.option('-c, --config <path>', 'Path to config file')
|
|
148
161
|
.option('-e, --endpoint <url>', 'GraphQL endpoint URL (overrides config)')
|
|
162
|
+
.option('-s, --schema <path>', 'Path to GraphQL schema file (.graphql)')
|
|
149
163
|
.option('-o, --output <dir>', 'Output directory (overrides config)', './generated/orm')
|
|
150
164
|
.option('-a, --authorization <header>', 'Authorization header value')
|
|
151
165
|
.option('-v, --verbose', 'Verbose output', false)
|
|
@@ -157,8 +171,17 @@ program
|
|
|
157
171
|
.option('--touch <file>', 'File to touch on schema change')
|
|
158
172
|
.option('--no-clear', 'Do not clear terminal on regeneration')
|
|
159
173
|
.action(async (options) => {
|
|
160
|
-
//
|
|
174
|
+
// Validate source options
|
|
175
|
+
if (options.endpoint && options.schema) {
|
|
176
|
+
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
// Watch mode (only for endpoint)
|
|
161
180
|
if (options.watch) {
|
|
181
|
+
if (options.schema) {
|
|
182
|
+
console.error('x Watch mode is only supported with --endpoint, not --schema.');
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
162
185
|
const config = await loadWatchConfig(options);
|
|
163
186
|
if (!config) {
|
|
164
187
|
process.exit(1);
|
|
@@ -177,6 +200,7 @@ program
|
|
|
177
200
|
const result = await generateOrmCommand({
|
|
178
201
|
config: options.config,
|
|
179
202
|
endpoint: options.endpoint,
|
|
203
|
+
schema: options.schema,
|
|
180
204
|
output: options.output,
|
|
181
205
|
authorization: options.authorization,
|
|
182
206
|
verbose: options.verbose,
|
|
@@ -184,7 +208,7 @@ program
|
|
|
184
208
|
skipCustomOperations: options.skipCustomOperations,
|
|
185
209
|
});
|
|
186
210
|
if (result.success) {
|
|
187
|
-
console.log('
|
|
211
|
+
console.log('[ok]', result.message);
|
|
188
212
|
if (result.tables && result.tables.length > 0) {
|
|
189
213
|
console.log('\nTables:');
|
|
190
214
|
result.tables.forEach((t) => console.log(` - ${t}`));
|
|
@@ -203,54 +227,60 @@ program
|
|
|
203
227
|
}
|
|
204
228
|
}
|
|
205
229
|
else {
|
|
206
|
-
console.error('
|
|
230
|
+
console.error('x', result.message);
|
|
207
231
|
if (result.errors) {
|
|
208
232
|
result.errors.forEach((e) => console.error(' -', e));
|
|
209
233
|
}
|
|
210
234
|
process.exit(1);
|
|
211
235
|
}
|
|
212
236
|
});
|
|
213
|
-
// Introspect command (for debugging)
|
|
237
|
+
// Introspect command (for debugging) - uses the new inference system
|
|
214
238
|
program
|
|
215
239
|
.command('introspect')
|
|
216
|
-
.description('Introspect a GraphQL endpoint and print table info')
|
|
217
|
-
.
|
|
240
|
+
.description('Introspect a GraphQL endpoint or schema file and print table info')
|
|
241
|
+
.option('-e, --endpoint <url>', 'GraphQL endpoint URL')
|
|
242
|
+
.option('-s, --schema <path>', 'Path to GraphQL schema file (.graphql)')
|
|
218
243
|
.option('-a, --authorization <header>', 'Authorization header value')
|
|
219
244
|
.option('--json', 'Output as JSON', false)
|
|
220
245
|
.action(async (options) => {
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const validation = validateEndpoint(options.endpoint);
|
|
225
|
-
if (!validation.valid) {
|
|
226
|
-
console.error('✗ Invalid endpoint:', validation.error);
|
|
246
|
+
// Validate source options
|
|
247
|
+
if (!options.endpoint && !options.schema) {
|
|
248
|
+
console.error('x Either --endpoint or --schema must be provided.');
|
|
227
249
|
process.exit(1);
|
|
228
250
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
endpoint: options.endpoint,
|
|
232
|
-
authorization: options.authorization,
|
|
233
|
-
});
|
|
234
|
-
if (!result.success) {
|
|
235
|
-
console.error('✗ Failed to fetch schema:', result.error);
|
|
251
|
+
if (options.endpoint && options.schema) {
|
|
252
|
+
console.error('x Cannot use both --endpoint and --schema. Choose one source.');
|
|
236
253
|
process.exit(1);
|
|
237
254
|
}
|
|
238
|
-
const
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
tableNames.forEach((name) => {
|
|
246
|
-
const table = tables.find((t) => t.name === name);
|
|
247
|
-
const fieldCount = table.fields.length;
|
|
248
|
-
const relationCount = table.relations.belongsTo.length +
|
|
249
|
-
table.relations.hasOne.length +
|
|
250
|
-
table.relations.hasMany.length +
|
|
251
|
-
table.relations.manyToMany.length;
|
|
252
|
-
console.log(` ${name} (${fieldCount} fields, ${relationCount} relations)`);
|
|
255
|
+
const { createSchemaSource } = await import('./introspect/source');
|
|
256
|
+
const { inferTablesFromIntrospection } = await import('./introspect/infer-tables');
|
|
257
|
+
try {
|
|
258
|
+
const source = createSchemaSource({
|
|
259
|
+
endpoint: options.endpoint,
|
|
260
|
+
schema: options.schema,
|
|
261
|
+
authorization: options.authorization,
|
|
253
262
|
});
|
|
263
|
+
console.log('Fetching schema from', source.describe(), '...');
|
|
264
|
+
const { introspection } = await source.fetch();
|
|
265
|
+
const tables = inferTablesFromIntrospection(introspection);
|
|
266
|
+
if (options.json) {
|
|
267
|
+
console.log(JSON.stringify(tables, null, 2));
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
console.log(`\n[ok] Found ${tables.length} tables:\n`);
|
|
271
|
+
tables.forEach((table) => {
|
|
272
|
+
const fieldCount = table.fields.length;
|
|
273
|
+
const relationCount = table.relations.belongsTo.length +
|
|
274
|
+
table.relations.hasOne.length +
|
|
275
|
+
table.relations.hasMany.length +
|
|
276
|
+
table.relations.manyToMany.length;
|
|
277
|
+
console.log(` ${table.name} (${fieldCount} fields, ${relationCount} relations)`);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
catch (err) {
|
|
282
|
+
console.error('x Failed to introspect schema:', err instanceof Error ? err.message : err);
|
|
283
|
+
process.exit(1);
|
|
254
284
|
}
|
|
255
285
|
});
|
|
256
286
|
program.parse();
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Introspection module exports
|
|
3
3
|
*/
|
|
4
|
-
export {
|
|
5
|
-
export type {
|
|
6
|
-
export {
|
|
7
|
-
export
|
|
8
|
-
export {
|
|
4
|
+
export { inferTablesFromIntrospection } from './infer-tables';
|
|
5
|
+
export type { InferTablesOptions } from './infer-tables';
|
|
6
|
+
export { singularize, pluralize } from 'inflekt';
|
|
7
|
+
export { createSchemaSource, validateSourceOptions, EndpointSchemaSource, FileSchemaSource, SchemaSourceError, } from './source';
|
|
8
|
+
export type { SchemaSource, SchemaSourceResult, CreateSchemaSourceOptions, } from './source';
|
|
9
|
+
export { fetchSchema } from './fetch-schema';
|
|
10
|
+
export type { FetchSchemaOptions, FetchSchemaResult } from './fetch-schema';
|
|
11
|
+
export { getTableNames, findTable, filterTables } from './transform';
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Introspection module exports
|
|
3
3
|
*/
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
|
|
4
|
+
// Table inference from introspection
|
|
5
|
+
export { inferTablesFromIntrospection } from './infer-tables';
|
|
6
|
+
// Pluralization utilities (from inflekt)
|
|
7
|
+
export { singularize, pluralize } from 'inflekt';
|
|
8
|
+
// Schema sources
|
|
9
|
+
export { createSchemaSource, validateSourceOptions, EndpointSchemaSource, FileSchemaSource, SchemaSourceError, } from './source';
|
|
10
|
+
// Schema fetching (still used by watch mode)
|
|
11
|
+
export { fetchSchema } from './fetch-schema';
|
|
12
|
+
// Transform utilities (only filterTables, getTableNames, findTable are still useful)
|
|
13
|
+
export { getTableNames, findTable, filterTables } from './transform';
|