@constructive-io/graphql-codegen 2.32.0 → 3.0.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/README.md +429 -1691
- package/cli/index.d.ts +5 -2
- package/cli/index.js +98 -581
- package/cli/shared.d.ts +35 -0
- package/cli/shared.js +106 -0
- package/{esm/cli → core}/codegen/barrel.d.ts +1 -1
- package/{cli → core}/codegen/barrel.js +1 -4
- package/{esm/cli → core}/codegen/index.d.ts +15 -5
- package/{cli → core}/codegen/index.js +44 -24
- package/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{esm/cli → core}/codegen/mutation-keys.d.ts +2 -2
- package/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{esm/cli → core}/codegen/orm/index.d.ts +9 -2
- package/{cli → core}/codegen/orm/index.js +3 -2
- package/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/core/codegen/shared/index.d.ts +39 -0
- package/core/codegen/shared/index.js +118 -0
- package/core/config/index.d.ts +5 -0
- package/core/config/index.js +13 -0
- package/core/config/loader.d.ts +18 -0
- package/{cli/commands/init.js → core/config/loader.js} +7 -94
- package/core/config/resolver.d.ts +46 -0
- package/core/config/resolver.js +104 -0
- package/core/database/index.d.ts +43 -0
- package/core/database/index.js +85 -0
- package/core/generate.d.ts +22 -0
- package/core/generate.js +192 -0
- package/core/index.d.ts +13 -1
- package/core/index.js +22 -2
- package/{cli → core}/introspect/fetch-schema.js +58 -9
- package/core/introspect/source/api-schemas.d.ts +44 -0
- package/core/introspect/source/api-schemas.js +122 -0
- package/core/introspect/source/database.d.ts +32 -0
- package/core/introspect/source/database.js +91 -0
- package/core/introspect/source/index.d.ts +112 -0
- package/core/introspect/source/index.js +173 -0
- package/core/introspect/source/pgpm-module.d.ts +83 -0
- package/core/introspect/source/pgpm-module.js +200 -0
- package/core/output/index.d.ts +4 -0
- package/core/output/index.js +9 -0
- package/core/output/writer.d.ts +38 -0
- package/core/output/writer.js +156 -0
- package/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/{cli/commands/shared.js → core/pipeline/index.js} +4 -0
- package/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/{cli → core}/watch/orchestrator.js +35 -27
- package/{cli → core}/watch/types.d.ts +1 -1
- package/esm/cli/index.d.ts +5 -2
- package/esm/cli/index.js +97 -547
- package/esm/cli/shared.d.ts +35 -0
- package/esm/cli/shared.js +101 -0
- package/{cli → esm/core}/codegen/barrel.d.ts +1 -1
- package/esm/{cli → core}/codegen/barrel.js +1 -4
- package/{cli → esm/core}/codegen/index.d.ts +15 -5
- package/esm/{cli → core}/codegen/index.js +44 -24
- package/esm/{cli → core}/codegen/invalidation.d.ts +2 -2
- package/{cli → esm/core}/codegen/mutation-keys.d.ts +2 -2
- package/esm/{cli → core}/codegen/orm/client-generator.js +2 -3
- package/{cli → esm/core}/codegen/orm/index.d.ts +9 -2
- package/esm/{cli → core}/codegen/orm/index.js +3 -2
- package/esm/{cli → core}/codegen/query-keys.d.ts +2 -2
- package/esm/core/codegen/shared/index.d.ts +39 -0
- package/esm/core/codegen/shared/index.js +79 -0
- package/esm/core/config/index.d.ts +5 -0
- package/esm/core/config/index.js +5 -0
- package/esm/core/config/loader.d.ts +18 -0
- package/esm/core/config/loader.js +71 -0
- package/esm/core/config/resolver.d.ts +46 -0
- package/esm/core/config/resolver.js +100 -0
- package/esm/core/database/index.d.ts +43 -0
- package/esm/core/database/index.js +48 -0
- package/esm/core/generate.d.ts +22 -0
- package/esm/core/generate.js +186 -0
- package/esm/core/index.d.ts +13 -1
- package/esm/core/index.js +20 -1
- package/esm/{cli → core}/introspect/fetch-schema.js +55 -9
- package/esm/core/introspect/source/api-schemas.d.ts +44 -0
- package/esm/core/introspect/source/api-schemas.js +117 -0
- package/esm/core/introspect/source/database.d.ts +32 -0
- package/esm/core/introspect/source/database.js +87 -0
- package/esm/core/introspect/source/index.d.ts +112 -0
- package/esm/core/introspect/source/index.js +154 -0
- package/esm/core/introspect/source/pgpm-module.d.ts +83 -0
- package/esm/core/introspect/source/pgpm-module.js +194 -0
- package/esm/core/output/index.d.ts +4 -0
- package/esm/core/output/index.js +4 -0
- package/esm/core/output/writer.d.ts +38 -0
- package/esm/core/output/writer.js +119 -0
- package/esm/{cli/commands/shared.d.ts → core/pipeline/index.d.ts} +5 -3
- package/esm/{cli/commands/shared.js → core/pipeline/index.js} +1 -0
- package/esm/{cli → core}/watch/orchestrator.d.ts +25 -3
- package/esm/{cli → core}/watch/orchestrator.js +35 -27
- package/esm/{cli → core}/watch/types.d.ts +1 -1
- package/esm/index.d.ts +8 -3
- package/esm/index.js +9 -3
- package/esm/types/config.d.ts +101 -138
- package/esm/types/config.js +8 -35
- package/esm/types/index.d.ts +2 -2
- package/esm/types/index.js +1 -1
- package/index.d.ts +8 -3
- package/index.js +18 -8
- package/package.json +18 -11
- package/types/config.d.ts +101 -138
- package/types/config.js +9 -38
- package/types/index.d.ts +2 -2
- package/types/index.js +3 -3
- package/cli/commands/generate-orm.d.ts +0 -53
- package/cli/commands/generate-orm.js +0 -292
- package/cli/commands/generate.d.ts +0 -66
- package/cli/commands/generate.js +0 -431
- package/cli/commands/index.d.ts +0 -9
- package/cli/commands/index.js +0 -14
- package/cli/commands/init.d.ts +0 -35
- package/cli/introspect/source/index.d.ts +0 -48
- package/cli/introspect/source/index.js +0 -72
- package/esm/cli/commands/generate-orm.d.ts +0 -53
- package/esm/cli/commands/generate-orm.js +0 -289
- package/esm/cli/commands/generate.d.ts +0 -66
- package/esm/cli/commands/generate.js +0 -393
- package/esm/cli/commands/index.d.ts +0 -9
- package/esm/cli/commands/index.js +0 -6
- package/esm/cli/commands/init.d.ts +0 -35
- package/esm/cli/commands/init.js +0 -158
- package/esm/cli/introspect/source/index.d.ts +0 -48
- package/esm/cli/introspect/source/index.js +0 -54
- /package/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/{cli → core}/codegen/babel-ast.js +0 -0
- /package/{cli → core}/codegen/client.d.ts +0 -0
- /package/{cli → core}/codegen/client.js +0 -0
- /package/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/{cli → core}/codegen/custom-queries.js +0 -0
- /package/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/gql-ast.js +0 -0
- /package/{cli → core}/codegen/invalidation.js +0 -0
- /package/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/{cli → core}/codegen/mutations.js +0 -0
- /package/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/{cli → core}/codegen/orm/client.js +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/{cli → core}/codegen/orm/query-builder.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/{cli → core}/codegen/queries.d.ts +0 -0
- /package/{cli → core}/codegen/queries.js +0 -0
- /package/{cli → core}/codegen/query-keys.js +0 -0
- /package/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/{cli → core}/codegen/scalars.js +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/{cli → core}/codegen/type-resolver.js +0 -0
- /package/{cli → core}/codegen/types.d.ts +0 -0
- /package/{cli → core}/codegen/types.js +0 -0
- /package/{cli → core}/codegen/utils.d.ts +0 -0
- /package/{cli → core}/codegen/utils.js +0 -0
- /package/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/{cli → core}/introspect/index.d.ts +0 -0
- /package/{cli → core}/introspect/index.js +0 -0
- /package/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/{cli → core}/introspect/infer-tables.js +0 -0
- /package/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/{cli → core}/introspect/schema-query.js +0 -0
- /package/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/{cli → core}/introspect/source/file.js +0 -0
- /package/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/{cli → core}/introspect/source/types.js +0 -0
- /package/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/{cli → core}/introspect/transform-schema.js +0 -0
- /package/{cli → core}/introspect/transform.d.ts +0 -0
- /package/{cli → core}/introspect/transform.js +0 -0
- /package/{cli → core}/watch/cache.d.ts +0 -0
- /package/{cli → core}/watch/cache.js +0 -0
- /package/{cli → core}/watch/debounce.d.ts +0 -0
- /package/{cli → core}/watch/debounce.js +0 -0
- /package/{cli → core}/watch/hash.d.ts +0 -0
- /package/{cli → core}/watch/hash.js +0 -0
- /package/{cli → core}/watch/index.d.ts +0 -0
- /package/{cli → core}/watch/index.js +0 -0
- /package/{cli → core}/watch/poller.d.ts +0 -0
- /package/{cli → core}/watch/poller.js +0 -0
- /package/{cli → core}/watch/types.js +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/babel-ast.js +0 -0
- /package/esm/{cli → core}/codegen/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/client.js +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-mutations.js +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/custom-queries.js +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/invalidation.js +0 -0
- /package/esm/{cli → core}/codegen/mutation-keys.js +0 -0
- /package/esm/{cli → core}/codegen/mutations.d.ts +0 -0
- /package/esm/{cli → core}/codegen/mutations.js +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/barrel.js +0 -0
- /package/esm/{cli → core}/codegen/orm/client-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/client.js +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/custom-ops-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/input-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/model-generator.js +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/query-builder.js +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/orm/select-types.js +0 -0
- /package/esm/{cli → core}/codegen/queries.d.ts +0 -0
- /package/esm/{cli → core}/codegen/queries.js +0 -0
- /package/esm/{cli → core}/codegen/query-keys.js +0 -0
- /package/esm/{cli → core}/codegen/scalars.d.ts +0 -0
- /package/esm/{cli → core}/codegen/scalars.js +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-gql-ast.js +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.d.ts +0 -0
- /package/esm/{cli → core}/codegen/schema-types-generator.js +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.d.ts +0 -0
- /package/esm/{cli → core}/codegen/type-resolver.js +0 -0
- /package/esm/{cli → core}/codegen/types.d.ts +0 -0
- /package/esm/{cli → core}/codegen/types.js +0 -0
- /package/esm/{cli → core}/codegen/utils.d.ts +0 -0
- /package/esm/{cli → core}/codegen/utils.js +0 -0
- /package/esm/{cli → core}/introspect/fetch-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.d.ts +0 -0
- /package/esm/{cli → core}/introspect/index.js +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.d.ts +0 -0
- /package/esm/{cli → core}/introspect/infer-tables.js +0 -0
- /package/esm/{cli → core}/introspect/schema-query.d.ts +0 -0
- /package/esm/{cli → core}/introspect/schema-query.js +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/endpoint.js +0 -0
- /package/esm/{cli → core}/introspect/source/file.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/file.js +0 -0
- /package/esm/{cli → core}/introspect/source/types.d.ts +0 -0
- /package/esm/{cli → core}/introspect/source/types.js +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform-schema.js +0 -0
- /package/esm/{cli → core}/introspect/transform.d.ts +0 -0
- /package/esm/{cli → core}/introspect/transform.js +0 -0
- /package/esm/{cli → core}/watch/cache.d.ts +0 -0
- /package/esm/{cli → core}/watch/cache.js +0 -0
- /package/esm/{cli → core}/watch/debounce.d.ts +0 -0
- /package/esm/{cli → core}/watch/debounce.js +0 -0
- /package/esm/{cli → core}/watch/hash.d.ts +0 -0
- /package/esm/{cli → core}/watch/hash.js +0 -0
- /package/esm/{cli → core}/watch/index.d.ts +0 -0
- /package/esm/{cli → core}/watch/index.js +0 -0
- /package/esm/{cli → core}/watch/poller.d.ts +0 -0
- /package/esm/{cli → core}/watch/poller.js +0 -0
- /package/esm/{cli → core}/watch/types.js +0 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { mergeConfig, getConfigOptions } from '../../types/config';
|
|
2
|
+
import { findConfigFile, loadConfigFile } from './loader';
|
|
3
|
+
/**
|
|
4
|
+
* Load and resolve configuration from file and/or options
|
|
5
|
+
*
|
|
6
|
+
* This is the main entry point for configuration loading. It:
|
|
7
|
+
* 1. Finds and loads the config file (if any)
|
|
8
|
+
* 2. Applies CLI option overrides
|
|
9
|
+
* 3. Returns fully resolved configuration ready for use
|
|
10
|
+
*/
|
|
11
|
+
export async function loadAndResolveConfig(options) {
|
|
12
|
+
// Destructure CLI-only fields, rest is config overrides
|
|
13
|
+
const { config: configPath, ...overrides } = options;
|
|
14
|
+
// Validate that at most one source is specified
|
|
15
|
+
const sources = [
|
|
16
|
+
overrides.endpoint,
|
|
17
|
+
overrides.schemaFile,
|
|
18
|
+
overrides.db,
|
|
19
|
+
].filter(Boolean);
|
|
20
|
+
if (sources.length > 1) {
|
|
21
|
+
return {
|
|
22
|
+
success: false,
|
|
23
|
+
error: 'Multiple sources specified. Use only one of: endpoint, schemaFile, or db.',
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
// Find config file
|
|
27
|
+
let resolvedConfigPath = configPath;
|
|
28
|
+
if (!resolvedConfigPath) {
|
|
29
|
+
resolvedConfigPath = findConfigFile() ?? undefined;
|
|
30
|
+
}
|
|
31
|
+
let baseConfig = {};
|
|
32
|
+
if (resolvedConfigPath) {
|
|
33
|
+
const loadResult = await loadConfigFile(resolvedConfigPath);
|
|
34
|
+
if (!loadResult.success) {
|
|
35
|
+
return { success: false, error: loadResult.error };
|
|
36
|
+
}
|
|
37
|
+
baseConfig = loadResult.config;
|
|
38
|
+
}
|
|
39
|
+
const mergedConfig = mergeConfig(baseConfig, overrides);
|
|
40
|
+
// Check if we have a source (endpoint, schemaFile, or db)
|
|
41
|
+
const hasSource = mergedConfig.endpoint ||
|
|
42
|
+
mergedConfig.schemaFile ||
|
|
43
|
+
mergedConfig.db;
|
|
44
|
+
if (!hasSource) {
|
|
45
|
+
return {
|
|
46
|
+
success: false,
|
|
47
|
+
error: 'No source specified. Use --endpoint, --schema-file, or --db, or create a config file with "graphql-codegen init".',
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
success: true,
|
|
52
|
+
config: getConfigOptions(mergedConfig),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Build watch configuration from options
|
|
57
|
+
*
|
|
58
|
+
* Used by watch mode to resolve configuration with watch-specific overrides.
|
|
59
|
+
*/
|
|
60
|
+
export async function loadWatchConfig(options) {
|
|
61
|
+
let configPath = options.config;
|
|
62
|
+
if (!configPath) {
|
|
63
|
+
configPath = findConfigFile() ?? undefined;
|
|
64
|
+
}
|
|
65
|
+
let baseConfig = {};
|
|
66
|
+
if (configPath) {
|
|
67
|
+
const loadResult = await loadConfigFile(configPath);
|
|
68
|
+
if (!loadResult.success) {
|
|
69
|
+
console.error('x', loadResult.error);
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
baseConfig = loadResult.config;
|
|
73
|
+
}
|
|
74
|
+
const sourceOverrides = {};
|
|
75
|
+
if (options.endpoint) {
|
|
76
|
+
sourceOverrides.endpoint = options.endpoint;
|
|
77
|
+
sourceOverrides.schemaFile = undefined;
|
|
78
|
+
}
|
|
79
|
+
const watchOverrides = {
|
|
80
|
+
watch: {
|
|
81
|
+
...(options.pollInterval !== undefined && {
|
|
82
|
+
pollInterval: options.pollInterval,
|
|
83
|
+
}),
|
|
84
|
+
...(options.debounce !== undefined && { debounce: options.debounce }),
|
|
85
|
+
...(options.touch !== undefined && { touchFile: options.touch }),
|
|
86
|
+
...(options.clear !== undefined && { clearScreen: options.clear }),
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
let mergedConfig = mergeConfig(baseConfig, sourceOverrides);
|
|
90
|
+
mergedConfig = mergeConfig(mergedConfig, watchOverrides);
|
|
91
|
+
if (!mergedConfig.endpoint) {
|
|
92
|
+
console.error('x No endpoint specified. Watch mode only supports live endpoints.');
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
if (mergedConfig.schemaFile) {
|
|
96
|
+
console.error('x Watch mode is only supported with an endpoint, not schemaFile.');
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return getConfigOptions(mergedConfig);
|
|
100
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database schema utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for building GraphQL schemas directly from PostgreSQL databases.
|
|
5
|
+
*/
|
|
6
|
+
export interface BuildSchemaFromDatabaseOptions {
|
|
7
|
+
/** Database name */
|
|
8
|
+
database: string;
|
|
9
|
+
/** PostgreSQL schemas to include */
|
|
10
|
+
schemas: string[];
|
|
11
|
+
/** Output directory for the schema file */
|
|
12
|
+
outDir: string;
|
|
13
|
+
/** Optional filename (default: schema.graphql) */
|
|
14
|
+
filename?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface BuildSchemaFromDatabaseResult {
|
|
17
|
+
/** Path to the generated schema file */
|
|
18
|
+
schemaPath: string;
|
|
19
|
+
/** The SDL content */
|
|
20
|
+
sdl: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Build a GraphQL schema from a PostgreSQL database and write it to a file.
|
|
24
|
+
*
|
|
25
|
+
* This function introspects the database using PostGraphile and generates
|
|
26
|
+
* a GraphQL SDL file that can be used for code generation.
|
|
27
|
+
*
|
|
28
|
+
* @param options - Configuration options
|
|
29
|
+
* @returns The path to the generated schema file and the SDL content
|
|
30
|
+
*/
|
|
31
|
+
export declare function buildSchemaFromDatabase(options: BuildSchemaFromDatabaseOptions): Promise<BuildSchemaFromDatabaseResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Build a GraphQL schema SDL string from a PostgreSQL database without writing to file.
|
|
34
|
+
*
|
|
35
|
+
* This is a convenience wrapper around buildSchemaSDL from graphql-server.
|
|
36
|
+
*
|
|
37
|
+
* @param options - Configuration options
|
|
38
|
+
* @returns The SDL content as a string
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildSchemaSDLFromDatabase(options: {
|
|
41
|
+
database: string;
|
|
42
|
+
schemas: string[];
|
|
43
|
+
}): Promise<string>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database schema utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides functions for building GraphQL schemas directly from PostgreSQL databases.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from 'node:fs';
|
|
7
|
+
import * as path from 'node:path';
|
|
8
|
+
import { buildSchemaSDL } from '@constructive-io/graphql-server';
|
|
9
|
+
/**
|
|
10
|
+
* Build a GraphQL schema from a PostgreSQL database and write it to a file.
|
|
11
|
+
*
|
|
12
|
+
* This function introspects the database using PostGraphile and generates
|
|
13
|
+
* a GraphQL SDL file that can be used for code generation.
|
|
14
|
+
*
|
|
15
|
+
* @param options - Configuration options
|
|
16
|
+
* @returns The path to the generated schema file and the SDL content
|
|
17
|
+
*/
|
|
18
|
+
export async function buildSchemaFromDatabase(options) {
|
|
19
|
+
const { database, schemas, outDir, filename = 'schema.graphql' } = options;
|
|
20
|
+
// Ensure output directory exists
|
|
21
|
+
await fs.promises.mkdir(outDir, { recursive: true });
|
|
22
|
+
// Build schema SDL from database
|
|
23
|
+
const sdl = await buildSchemaSDL({
|
|
24
|
+
database,
|
|
25
|
+
schemas,
|
|
26
|
+
graphile: { pgSettings: async () => ({ role: 'administrator' }) },
|
|
27
|
+
});
|
|
28
|
+
// Write schema to file
|
|
29
|
+
const schemaPath = path.join(outDir, filename);
|
|
30
|
+
await fs.promises.writeFile(schemaPath, sdl, 'utf-8');
|
|
31
|
+
return { schemaPath, sdl };
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Build a GraphQL schema SDL string from a PostgreSQL database without writing to file.
|
|
35
|
+
*
|
|
36
|
+
* This is a convenience wrapper around buildSchemaSDL from graphql-server.
|
|
37
|
+
*
|
|
38
|
+
* @param options - Configuration options
|
|
39
|
+
* @returns The SDL content as a string
|
|
40
|
+
*/
|
|
41
|
+
export async function buildSchemaSDLFromDatabase(options) {
|
|
42
|
+
const { database, schemas } = options;
|
|
43
|
+
return buildSchemaSDL({
|
|
44
|
+
database,
|
|
45
|
+
schemas,
|
|
46
|
+
graphile: { pgSettings: async () => ({ role: 'administrator' }) },
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { GraphQLSDKConfigTarget } from '../types/config';
|
|
2
|
+
export interface GenerateOptions extends GraphQLSDKConfigTarget {
|
|
3
|
+
authorization?: string;
|
|
4
|
+
verbose?: boolean;
|
|
5
|
+
dryRun?: boolean;
|
|
6
|
+
skipCustomOperations?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface GenerateResult {
|
|
9
|
+
success: boolean;
|
|
10
|
+
message: string;
|
|
11
|
+
output?: string;
|
|
12
|
+
tables?: string[];
|
|
13
|
+
filesWritten?: string[];
|
|
14
|
+
errors?: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Main generate function - takes a single config and generates code
|
|
18
|
+
*
|
|
19
|
+
* This is the primary entry point for programmatic usage.
|
|
20
|
+
* For multiple configs, call this function in a loop.
|
|
21
|
+
*/
|
|
22
|
+
export declare function generate(options?: GenerateOptions): Promise<GenerateResult>;
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main generate function - orchestrates the entire codegen pipeline
|
|
3
|
+
*
|
|
4
|
+
* This is the primary entry point for programmatic usage.
|
|
5
|
+
* The CLI is a thin wrapper around this function.
|
|
6
|
+
*/
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { createSchemaSource, validateSourceOptions } from './introspect';
|
|
9
|
+
import { runCodegenPipeline, validateTablesFound } from './pipeline';
|
|
10
|
+
import { generate as generateReactQueryFiles } from './codegen';
|
|
11
|
+
import { generateOrm as generateOrmFiles } from './codegen/orm';
|
|
12
|
+
import { generateSharedTypes } from './codegen/shared';
|
|
13
|
+
import { writeGeneratedFiles } from './output';
|
|
14
|
+
import { getConfigOptions } from '../types/config';
|
|
15
|
+
/**
|
|
16
|
+
* Main generate function - takes a single config and generates code
|
|
17
|
+
*
|
|
18
|
+
* This is the primary entry point for programmatic usage.
|
|
19
|
+
* For multiple configs, call this function in a loop.
|
|
20
|
+
*/
|
|
21
|
+
export async function generate(options = {}) {
|
|
22
|
+
// Apply defaults to get resolved config
|
|
23
|
+
const config = getConfigOptions(options);
|
|
24
|
+
const outputRoot = config.output;
|
|
25
|
+
// Determine which generators to run
|
|
26
|
+
const runReactQuery = config.reactQuery ?? false;
|
|
27
|
+
const runOrm = config.orm ?? false;
|
|
28
|
+
if (!runReactQuery && !runOrm) {
|
|
29
|
+
return {
|
|
30
|
+
success: false,
|
|
31
|
+
message: 'No generators enabled. Use reactQuery: true or orm: true in your config.',
|
|
32
|
+
output: outputRoot,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
// Validate source
|
|
36
|
+
const sourceValidation = validateSourceOptions({
|
|
37
|
+
endpoint: config.endpoint || undefined,
|
|
38
|
+
schemaFile: config.schemaFile || undefined,
|
|
39
|
+
db: config.db,
|
|
40
|
+
});
|
|
41
|
+
if (!sourceValidation.valid) {
|
|
42
|
+
return {
|
|
43
|
+
success: false,
|
|
44
|
+
message: sourceValidation.error,
|
|
45
|
+
output: outputRoot,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const source = createSchemaSource({
|
|
49
|
+
endpoint: config.endpoint || undefined,
|
|
50
|
+
schemaFile: config.schemaFile || undefined,
|
|
51
|
+
db: config.db,
|
|
52
|
+
authorization: options.authorization || config.headers?.['Authorization'],
|
|
53
|
+
headers: config.headers,
|
|
54
|
+
});
|
|
55
|
+
// Run pipeline
|
|
56
|
+
let pipelineResult;
|
|
57
|
+
try {
|
|
58
|
+
console.log(`Fetching schema from ${source.describe()}...`);
|
|
59
|
+
pipelineResult = await runCodegenPipeline({
|
|
60
|
+
source,
|
|
61
|
+
config,
|
|
62
|
+
verbose: options.verbose,
|
|
63
|
+
skipCustomOperations: options.skipCustomOperations,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
return {
|
|
68
|
+
success: false,
|
|
69
|
+
message: `Failed to fetch schema: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
70
|
+
output: outputRoot,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const { tables, customOperations } = pipelineResult;
|
|
74
|
+
// Validate tables
|
|
75
|
+
const tablesValidation = validateTablesFound(tables);
|
|
76
|
+
if (!tablesValidation.valid) {
|
|
77
|
+
return {
|
|
78
|
+
success: false,
|
|
79
|
+
message: tablesValidation.error,
|
|
80
|
+
output: outputRoot,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const allFilesWritten = [];
|
|
84
|
+
const bothEnabled = runReactQuery && runOrm;
|
|
85
|
+
// Generate shared types when both are enabled
|
|
86
|
+
if (bothEnabled) {
|
|
87
|
+
console.log('Generating shared types...');
|
|
88
|
+
const sharedResult = generateSharedTypes({
|
|
89
|
+
tables,
|
|
90
|
+
customOperations: {
|
|
91
|
+
queries: customOperations.queries,
|
|
92
|
+
mutations: customOperations.mutations,
|
|
93
|
+
typeRegistry: customOperations.typeRegistry,
|
|
94
|
+
},
|
|
95
|
+
config,
|
|
96
|
+
});
|
|
97
|
+
if (!options.dryRun) {
|
|
98
|
+
const writeResult = await writeGeneratedFiles(sharedResult.files, outputRoot, []);
|
|
99
|
+
if (!writeResult.success) {
|
|
100
|
+
return {
|
|
101
|
+
success: false,
|
|
102
|
+
message: `Failed to write shared types: ${writeResult.errors?.join(', ')}`,
|
|
103
|
+
output: outputRoot,
|
|
104
|
+
errors: writeResult.errors,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
allFilesWritten.push(...(writeResult.filesWritten ?? []));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
// Generate React Query hooks
|
|
111
|
+
if (runReactQuery) {
|
|
112
|
+
const hooksDir = path.join(outputRoot, 'hooks');
|
|
113
|
+
console.log('Generating React Query hooks...');
|
|
114
|
+
const { files } = generateReactQueryFiles({
|
|
115
|
+
tables,
|
|
116
|
+
customOperations: {
|
|
117
|
+
queries: customOperations.queries,
|
|
118
|
+
mutations: customOperations.mutations,
|
|
119
|
+
typeRegistry: customOperations.typeRegistry,
|
|
120
|
+
},
|
|
121
|
+
config,
|
|
122
|
+
sharedTypesPath: bothEnabled ? '..' : undefined,
|
|
123
|
+
});
|
|
124
|
+
if (!options.dryRun) {
|
|
125
|
+
const writeResult = await writeGeneratedFiles(files, hooksDir, ['queries', 'mutations']);
|
|
126
|
+
if (!writeResult.success) {
|
|
127
|
+
return {
|
|
128
|
+
success: false,
|
|
129
|
+
message: `Failed to write React Query hooks: ${writeResult.errors?.join(', ')}`,
|
|
130
|
+
output: outputRoot,
|
|
131
|
+
errors: writeResult.errors,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
allFilesWritten.push(...(writeResult.filesWritten ?? []));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Generate ORM client
|
|
138
|
+
if (runOrm) {
|
|
139
|
+
const ormDir = path.join(outputRoot, 'orm');
|
|
140
|
+
console.log('Generating ORM client...');
|
|
141
|
+
const { files } = generateOrmFiles({
|
|
142
|
+
tables,
|
|
143
|
+
customOperations: {
|
|
144
|
+
queries: customOperations.queries,
|
|
145
|
+
mutations: customOperations.mutations,
|
|
146
|
+
typeRegistry: customOperations.typeRegistry,
|
|
147
|
+
},
|
|
148
|
+
config,
|
|
149
|
+
sharedTypesPath: bothEnabled ? '..' : undefined,
|
|
150
|
+
});
|
|
151
|
+
if (!options.dryRun) {
|
|
152
|
+
const writeResult = await writeGeneratedFiles(files, ormDir, ['models', 'query', 'mutation']);
|
|
153
|
+
if (!writeResult.success) {
|
|
154
|
+
return {
|
|
155
|
+
success: false,
|
|
156
|
+
message: `Failed to write ORM client: ${writeResult.errors?.join(', ')}`,
|
|
157
|
+
output: outputRoot,
|
|
158
|
+
errors: writeResult.errors,
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
allFilesWritten.push(...(writeResult.filesWritten ?? []));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Generate unified barrel when both are enabled
|
|
165
|
+
if (bothEnabled && !options.dryRun) {
|
|
166
|
+
const barrelContent = `/**
|
|
167
|
+
* Generated SDK - auto-generated, do not edit
|
|
168
|
+
* @generated by @constructive-io/graphql-codegen
|
|
169
|
+
*/
|
|
170
|
+
export * from './types';
|
|
171
|
+
export * from './hooks';
|
|
172
|
+
export * from './orm';
|
|
173
|
+
`;
|
|
174
|
+
await writeGeneratedFiles([{ path: 'index.ts', content: barrelContent }], outputRoot, []);
|
|
175
|
+
}
|
|
176
|
+
const generators = [runReactQuery && 'React Query', runOrm && 'ORM'].filter(Boolean).join(' and ');
|
|
177
|
+
return {
|
|
178
|
+
success: true,
|
|
179
|
+
message: options.dryRun
|
|
180
|
+
? `Dry run complete. Would generate ${generators} for ${tables.length} tables.`
|
|
181
|
+
: `Generated ${generators} for ${tables.length} tables. Files written to ${outputRoot}`,
|
|
182
|
+
output: outputRoot,
|
|
183
|
+
tables: tables.map((t) => t.name),
|
|
184
|
+
filesWritten: allFilesWritten,
|
|
185
|
+
};
|
|
186
|
+
}
|
package/esm/core/index.d.ts
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Core
|
|
2
|
+
* Core module exports
|
|
3
|
+
*
|
|
4
|
+
* This module contains all the core business logic for graphql-codegen.
|
|
5
|
+
* The CLI is a thin wrapper around these core functions.
|
|
3
6
|
*/
|
|
7
|
+
export { generate } from './generate';
|
|
8
|
+
export type { GenerateOptions, GenerateResult } from './generate';
|
|
4
9
|
export * from './types';
|
|
5
10
|
export * from './ast';
|
|
6
11
|
export * from './custom-ast';
|
|
7
12
|
export { QueryBuilder, MetaObject } from './query-builder';
|
|
8
13
|
export { validateMetaObject, convertFromMetaSchema } from './meta-object';
|
|
14
|
+
export * from './config';
|
|
15
|
+
export * from './codegen';
|
|
16
|
+
export * from './introspect';
|
|
17
|
+
export * from './pipeline';
|
|
18
|
+
export * from './output';
|
|
19
|
+
export * from './watch';
|
|
20
|
+
export * from './database';
|
package/esm/core/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Core
|
|
2
|
+
* Core module exports
|
|
3
|
+
*
|
|
4
|
+
* This module contains all the core business logic for graphql-codegen.
|
|
5
|
+
* The CLI is a thin wrapper around these core functions.
|
|
3
6
|
*/
|
|
7
|
+
// Main generate function (orchestrates the entire pipeline)
|
|
8
|
+
export { generate } from './generate';
|
|
4
9
|
// Types
|
|
5
10
|
export * from './types';
|
|
6
11
|
// AST generation
|
|
@@ -10,3 +15,17 @@ export * from './custom-ast';
|
|
|
10
15
|
export { QueryBuilder, MetaObject } from './query-builder';
|
|
11
16
|
// Meta object utilities
|
|
12
17
|
export { validateMetaObject, convertFromMetaSchema } from './meta-object';
|
|
18
|
+
// Configuration loading and resolution
|
|
19
|
+
export * from './config';
|
|
20
|
+
// Code generation
|
|
21
|
+
export * from './codegen';
|
|
22
|
+
// Schema introspection
|
|
23
|
+
export * from './introspect';
|
|
24
|
+
// Codegen pipeline
|
|
25
|
+
export * from './pipeline';
|
|
26
|
+
// File output
|
|
27
|
+
export * from './output';
|
|
28
|
+
// Watch mode
|
|
29
|
+
export * from './watch';
|
|
30
|
+
// Database schema utilities
|
|
31
|
+
export * from './database';
|
|
@@ -1,34 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Fetch GraphQL schema introspection from an endpoint
|
|
3
3
|
*/
|
|
4
|
+
import dns from 'node:dns';
|
|
5
|
+
import { Agent } from 'undici';
|
|
4
6
|
import { SCHEMA_INTROSPECTION_QUERY } from './schema-query';
|
|
7
|
+
/**
|
|
8
|
+
* Check if a hostname is localhost or a localhost subdomain
|
|
9
|
+
*/
|
|
10
|
+
function isLocalhostHostname(hostname) {
|
|
11
|
+
return hostname === 'localhost' || hostname.endsWith('.localhost');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Create an undici Agent that resolves *.localhost to 127.0.0.1
|
|
15
|
+
* This fixes DNS resolution issues on macOS where subdomains like api.localhost
|
|
16
|
+
* don't resolve automatically (unlike browsers which handle *.localhost).
|
|
17
|
+
*/
|
|
18
|
+
function createLocalhostAgent() {
|
|
19
|
+
return new Agent({
|
|
20
|
+
connect: {
|
|
21
|
+
lookup(hostname, opts, cb) {
|
|
22
|
+
if (isLocalhostHostname(hostname)) {
|
|
23
|
+
cb(null, '127.0.0.1', 4);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
dns.lookup(hostname, opts, cb);
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
let localhostAgent = null;
|
|
32
|
+
function getLocalhostAgent() {
|
|
33
|
+
if (!localhostAgent) {
|
|
34
|
+
localhostAgent = createLocalhostAgent();
|
|
35
|
+
}
|
|
36
|
+
return localhostAgent;
|
|
37
|
+
}
|
|
5
38
|
/**
|
|
6
39
|
* Fetch the full schema introspection from a GraphQL endpoint
|
|
7
40
|
*/
|
|
8
41
|
export async function fetchSchema(options) {
|
|
9
42
|
const { endpoint, authorization, headers = {}, timeout = 30000 } = options;
|
|
43
|
+
// Parse the endpoint URL to check for localhost
|
|
44
|
+
const url = new URL(endpoint);
|
|
45
|
+
const useLocalhostAgent = isLocalhostHostname(url.hostname);
|
|
10
46
|
// Build headers
|
|
11
47
|
const requestHeaders = {
|
|
12
48
|
'Content-Type': 'application/json',
|
|
13
49
|
Accept: 'application/json',
|
|
14
50
|
...headers,
|
|
15
51
|
};
|
|
52
|
+
// Set Host header for localhost subdomains to preserve routing
|
|
53
|
+
if (useLocalhostAgent && url.hostname !== 'localhost') {
|
|
54
|
+
requestHeaders['Host'] = url.hostname;
|
|
55
|
+
}
|
|
16
56
|
if (authorization) {
|
|
17
57
|
requestHeaders['Authorization'] = authorization;
|
|
18
58
|
}
|
|
19
59
|
// Create abort controller for timeout
|
|
20
60
|
const controller = new AbortController();
|
|
21
61
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
62
|
+
// Build fetch options
|
|
63
|
+
const fetchOptions = {
|
|
64
|
+
method: 'POST',
|
|
65
|
+
headers: requestHeaders,
|
|
66
|
+
body: JSON.stringify({
|
|
67
|
+
query: SCHEMA_INTROSPECTION_QUERY,
|
|
68
|
+
variables: {},
|
|
69
|
+
}),
|
|
70
|
+
signal: controller.signal,
|
|
71
|
+
};
|
|
72
|
+
// Use custom agent for localhost to fix DNS resolution on macOS
|
|
73
|
+
if (useLocalhostAgent) {
|
|
74
|
+
fetchOptions.dispatcher = getLocalhostAgent();
|
|
75
|
+
}
|
|
22
76
|
try {
|
|
23
|
-
const response = await fetch(endpoint,
|
|
24
|
-
method: 'POST',
|
|
25
|
-
headers: requestHeaders,
|
|
26
|
-
body: JSON.stringify({
|
|
27
|
-
query: SCHEMA_INTROSPECTION_QUERY,
|
|
28
|
-
variables: {},
|
|
29
|
-
}),
|
|
30
|
-
signal: controller.signal,
|
|
31
|
-
});
|
|
77
|
+
const response = await fetch(endpoint, fetchOptions);
|
|
32
78
|
clearTimeout(timeoutId);
|
|
33
79
|
if (!response.ok) {
|
|
34
80
|
return {
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Schemas Resolution
|
|
3
|
+
*
|
|
4
|
+
* Utilities for resolving PostgreSQL schema names from API names
|
|
5
|
+
* by querying the services_public.api_schemas table.
|
|
6
|
+
*/
|
|
7
|
+
import { Pool } from 'pg';
|
|
8
|
+
/**
|
|
9
|
+
* Result of validating services schema requirements
|
|
10
|
+
*/
|
|
11
|
+
export interface ServicesSchemaValidation {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
error?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate that the required services schemas exist in the database
|
|
17
|
+
*
|
|
18
|
+
* Checks for:
|
|
19
|
+
* - services_public schema with apis and api_schemas tables
|
|
20
|
+
* - metaschema_public schema with schema table
|
|
21
|
+
*
|
|
22
|
+
* @param pool - Database connection pool
|
|
23
|
+
* @returns Validation result
|
|
24
|
+
*/
|
|
25
|
+
export declare function validateServicesSchemas(pool: Pool): Promise<ServicesSchemaValidation>;
|
|
26
|
+
/**
|
|
27
|
+
* Resolve schema names from API names by querying services_public.api_schemas
|
|
28
|
+
*
|
|
29
|
+
* Joins services_public.apis, services_public.api_schemas, and metaschema_public.schema
|
|
30
|
+
* to get the actual PostgreSQL schema names for the given API names.
|
|
31
|
+
*
|
|
32
|
+
* @param pool - Database connection pool
|
|
33
|
+
* @param apiNames - Array of API names to resolve
|
|
34
|
+
* @returns Array of PostgreSQL schema names
|
|
35
|
+
* @throws Error if validation fails or no schemas found
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveApiSchemas(pool: Pool, apiNames: string[]): Promise<string[]>;
|
|
38
|
+
/**
|
|
39
|
+
* Create a database pool for the given database name or connection string
|
|
40
|
+
*
|
|
41
|
+
* @param database - Database name or connection string
|
|
42
|
+
* @returns Database connection pool
|
|
43
|
+
*/
|
|
44
|
+
export declare function createDatabasePool(database: string): Pool;
|