@soda-gql/config 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Shota Hatada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,275 @@
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ let __soda_gql_common = require("@soda-gql/common");
25
+ __soda_gql_common = __toESM(__soda_gql_common);
26
+ let neverthrow = require("neverthrow");
27
+ neverthrow = __toESM(neverthrow);
28
+ let zod = require("zod");
29
+ zod = __toESM(zod);
30
+ let node_fs = require("node:fs");
31
+ node_fs = __toESM(node_fs);
32
+ let node_path = require("node:path");
33
+ node_path = __toESM(node_path);
34
+ let node_module = require("node:module");
35
+ node_module = __toESM(node_module);
36
+ let node_path_posix = require("node:path/posix");
37
+ node_path_posix = __toESM(node_path_posix);
38
+ let node_vm = require("node:vm");
39
+ node_vm = __toESM(node_vm);
40
+ let __swc_core = require("@swc/core");
41
+ __swc_core = __toESM(__swc_core);
42
+ let node_os = require("node:os");
43
+ node_os = __toESM(node_os);
44
+
45
+ //#region packages/config/src/errors.ts
46
+ const configError = ({ code, message, filePath, cause }) => ({
47
+ code,
48
+ message,
49
+ filePath,
50
+ cause
51
+ });
52
+
53
+ //#endregion
54
+ //#region packages/config/src/helper.ts
55
+ /**
56
+ * Thin wrapper class to simplify the validation of exported value from config file.
57
+ * As we use SWC + VM to execute the config file, the exported value is not typed.
58
+ * This wrapper class ensures the exported value is a valid soda-gql config object.
59
+ */
60
+ var SodaGqlConfigContainer = class SodaGqlConfigContainer {
61
+ constructor(config) {
62
+ this.config = config;
63
+ }
64
+ static create(config) {
65
+ return new SodaGqlConfigContainer(config);
66
+ }
67
+ };
68
+ function defineConfig(config) {
69
+ const validated = validateConfig(typeof config === "function" ? config() : config);
70
+ if (validated.isErr()) {
71
+ throw validated.error;
72
+ }
73
+ return SodaGqlConfigContainer.create(validated.value);
74
+ }
75
+ const SchemaConfigSchema = (0, __soda_gql_common.defineSchemaFor)()({
76
+ schema: zod.default.string().min(1),
77
+ runtimeAdapter: zod.default.string().min(1),
78
+ scalars: zod.default.string().min(1)
79
+ });
80
+ const SodaGqlConfigSchema = (0, __soda_gql_common.defineSchemaFor)()({
81
+ analyzer: zod.default.enum(["ts", "swc"]).optional(),
82
+ outdir: zod.default.string().min(1),
83
+ graphqlSystemAliases: zod.default.array(zod.default.string()).optional(),
84
+ include: zod.default.array(zod.default.string().min(1)),
85
+ exclude: zod.default.array(zod.default.string().min(1)).optional(),
86
+ schemas: zod.default.record(zod.default.string(), SchemaConfigSchema),
87
+ plugins: zod.default.record(zod.default.string(), zod.default.unknown()).optional()
88
+ });
89
+ function validateConfig(config) {
90
+ const result = SodaGqlConfigSchema.safeParse(config);
91
+ if (!result.success) {
92
+ return (0, neverthrow.err)(configError({
93
+ code: "CONFIG_VALIDATION_FAILED",
94
+ message: `Invalid config: ${result.error.message}`
95
+ }));
96
+ }
97
+ return (0, neverthrow.ok)(result.data);
98
+ }
99
+
100
+ //#endregion
101
+ //#region packages/config/src/evaluation.ts
102
+ /**
103
+ * Load and execute TypeScript config file synchronously using SWC + VM.
104
+ */
105
+ function executeConfigFile(configPath) {
106
+ const filePath = (0, node_path_posix.resolve)(configPath);
107
+ try {
108
+ const source = (0, node_fs.readFileSync)(filePath, "utf-8");
109
+ const result = (0, __swc_core.transformSync)(source, {
110
+ filename: filePath,
111
+ jsc: { parser: { syntax: "typescript" } },
112
+ module: { type: "commonjs" },
113
+ sourceMaps: false,
114
+ minify: false
115
+ });
116
+ const mod = { exports: {} };
117
+ const requireInner = (0, node_module.createRequire)(filePath);
118
+ const require$1 = (specifier) => {
119
+ if (!specifier.startsWith(".")) {
120
+ return requireInner(specifier);
121
+ }
122
+ const resolvedPath = (0, __soda_gql_common.resolveRelativeImportWithExistenceCheck)({
123
+ filePath,
124
+ specifier
125
+ });
126
+ if (!resolvedPath) {
127
+ throw new Error(`Module not found: ${specifier}`);
128
+ }
129
+ return requireInner(resolvedPath);
130
+ };
131
+ new node_vm.Script(result.code, { filename: filePath }).runInNewContext({
132
+ require: require$1,
133
+ module: mod,
134
+ exports: mod.exports,
135
+ __dirname: (0, node_path_posix.dirname)(filePath),
136
+ __filename: filePath,
137
+ console,
138
+ process
139
+ });
140
+ const config = mod.exports && typeof mod.exports === "object" && "default" in mod.exports && mod.exports.default instanceof SodaGqlConfigContainer ? mod.exports.default.config : null;
141
+ if (!config) {
142
+ throw new Error("Invalid config module");
143
+ }
144
+ return config;
145
+ } catch (error) {
146
+ throw configError({
147
+ code: "CONFIG_LOAD_FAILED",
148
+ message: `Failed to load config: ${error instanceof Error ? error.message : String(error)}`,
149
+ filePath,
150
+ cause: error
151
+ });
152
+ }
153
+ }
154
+
155
+ //#endregion
156
+ //#region packages/config/src/normalize.ts
157
+ /**
158
+ * Resolve and normalize config with defaults.
159
+ */
160
+ function normalizeConfig(config) {
161
+ const analyzer = config.analyzer ?? "ts";
162
+ const graphqlSystemAliases = config.graphqlSystemAliases ?? ["@/graphql-system"];
163
+ const exclude = config.exclude ?? [];
164
+ const resolved = {
165
+ analyzer,
166
+ outdir: (0, node_path.resolve)(config.outdir),
167
+ graphqlSystemAliases,
168
+ include: config.include.map((pattern) => (0, node_path.resolve)(pattern)),
169
+ exclude: exclude.map((pattern) => (0, node_path.resolve)(pattern)),
170
+ schemas: Object.fromEntries(Object.entries(config.schemas).map(([name, schemaConfig]) => [name, {
171
+ schema: (0, node_path.resolve)(schemaConfig.schema),
172
+ runtimeAdapter: (0, node_path.resolve)(schemaConfig.runtimeAdapter),
173
+ scalars: (0, node_path.resolve)(schemaConfig.scalars)
174
+ }])),
175
+ plugins: config.plugins ?? {}
176
+ };
177
+ return (0, neverthrow.ok)(resolved);
178
+ }
179
+
180
+ //#endregion
181
+ //#region packages/config/src/loader.ts
182
+ const DEFAULT_CONFIG_FILENAMES = [
183
+ "soda-gql.config.ts",
184
+ "soda-gql.config.mts",
185
+ "soda-gql.config.js",
186
+ "soda-gql.config.mjs"
187
+ ];
188
+ /**
189
+ * Find config file by walking up directory tree.
190
+ */
191
+ function findConfigFile(startDir = process.cwd()) {
192
+ let currentDir = startDir;
193
+ while (currentDir !== (0, node_path.dirname)(currentDir)) {
194
+ for (const filename of DEFAULT_CONFIG_FILENAMES) {
195
+ const configPath = (0, node_path.join)(currentDir, filename);
196
+ if ((0, node_fs.existsSync)(configPath)) {
197
+ return configPath;
198
+ }
199
+ }
200
+ currentDir = (0, node_path.dirname)(currentDir);
201
+ }
202
+ return null;
203
+ }
204
+ /**
205
+ * Load config with Result type (for library use).
206
+ */
207
+ function loadConfig(configPath) {
208
+ const resolvedPath = configPath ?? findConfigFile();
209
+ if (!resolvedPath) {
210
+ return (0, neverthrow.err)(configError({
211
+ code: "CONFIG_NOT_FOUND",
212
+ message: "Config file not found"
213
+ }));
214
+ }
215
+ try {
216
+ return normalizeConfig(executeConfigFile(resolvedPath));
217
+ } catch (error) {
218
+ return (0, neverthrow.err)(configError({
219
+ code: "CONFIG_LOAD_FAILED",
220
+ message: `Failed to load config: ${error}`,
221
+ filePath: resolvedPath,
222
+ cause: error
223
+ }));
224
+ }
225
+ }
226
+ /**
227
+ * Load config from specific directory.
228
+ */
229
+ function loadConfigFrom(dir) {
230
+ const configPath = findConfigFile(dir);
231
+ return loadConfig(configPath ?? undefined);
232
+ }
233
+
234
+ //#endregion
235
+ //#region packages/config/src/test-utils.ts
236
+ /**
237
+ * Create temporary config file with proper formatting.
238
+ * Uses template literals to support functions, regex, etc.
239
+ */
240
+ async function withTempConfig(config, fn) {
241
+ const tmpDir = (0, node_fs.mkdtempSync)((0, node_path.join)((0, node_os.tmpdir)(), "soda-gql-test-"));
242
+ const configPath = (0, node_path.join)(tmpDir, "soda-gql.config.ts");
243
+ const configContent = `
244
+ import { defineConfig } from "@soda-gql/config";
245
+
246
+ export default defineConfig(${JSON.stringify(config, null, 2)});
247
+ `.trim();
248
+ (0, node_fs.writeFileSync)(configPath, configContent);
249
+ return fn(configPath).finally(() => {
250
+ (0, node_fs.rmSync)(tmpDir, {
251
+ recursive: true,
252
+ force: true
253
+ });
254
+ });
255
+ }
256
+ /**
257
+ * Simple temp config creation (without auto-cleanup).
258
+ */
259
+ function createTempConfigFile(dir, config) {
260
+ const configPath = (0, node_path.join)(dir, "soda-gql.config.ts");
261
+ const configContent = `export default ${JSON.stringify(config, null, 2)};`;
262
+ (0, node_fs.writeFileSync)(configPath, configContent);
263
+ return configPath;
264
+ }
265
+
266
+ //#endregion
267
+ exports.configError = configError;
268
+ exports.createTempConfigFile = createTempConfigFile;
269
+ exports.defineConfig = defineConfig;
270
+ exports.findConfigFile = findConfigFile;
271
+ exports.loadConfig = loadConfig;
272
+ exports.loadConfigFrom = loadConfigFrom;
273
+ exports.normalizeConfig = normalizeConfig;
274
+ exports.validateConfig = validateConfig;
275
+ exports.withTempConfig = withTempConfig;
@@ -0,0 +1,167 @@
1
+ import { Result } from "neverthrow";
2
+
3
+ //#region packages/config/src/errors.d.ts
4
+ type ConfigErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_LOAD_FAILED" | "CONFIG_VALIDATION_FAILED" | "CONFIG_INVALID_PATH";
5
+ type ConfigError = {
6
+ readonly code: ConfigErrorCode;
7
+ readonly message: string;
8
+ readonly filePath?: string;
9
+ readonly cause?: unknown;
10
+ };
11
+ declare const configError: ({
12
+ code,
13
+ message,
14
+ filePath,
15
+ cause
16
+ }: {
17
+ code: ConfigErrorCode;
18
+ message: string;
19
+ filePath?: string;
20
+ cause?: unknown;
21
+ }) => ConfigError;
22
+ //#endregion
23
+ //#region packages/config/src/types.d.ts
24
+ type SchemaConfig = {
25
+ readonly schema: string;
26
+ readonly runtimeAdapter: string;
27
+ readonly scalars: string;
28
+ };
29
+ type PluginConfig = Record<string, unknown>;
30
+ type SodaGqlConfig = {
31
+ /**
32
+ * The analyzer to use for the project.
33
+ * @default "ts"
34
+ */
35
+ readonly analyzer?: "ts" | "swc";
36
+ /**
37
+ * The directory for the graphql system.
38
+ * This is where the graphql system will be generated, and where the builder/plugin will reference the graphql system.
39
+ *
40
+ * @example "graphql-system" or "src/graphql-system"
41
+ */
42
+ readonly outdir: string;
43
+ /**
44
+ * The graphql system aliases to use for the project.
45
+ * This is necessary if you set paths in your tsconfig.json to reference the graphql system.
46
+ *
47
+ * @example ["@/graphql-system"]
48
+ */
49
+ readonly graphqlSystemAliases?: readonly string[];
50
+ /**
51
+ * The files to include in the project.
52
+ *
53
+ * @example ["src/∗∗/∗.{ts,tsx}"]
54
+ * @note We use `∗` (Mathematical Asterisk) instead of `*` (Asterisk) in the above example to avoid syntax highlighting issues.
55
+ */
56
+ readonly include: readonly string[];
57
+ /**
58
+ * The files to exclude from the project.
59
+ *
60
+ * @example ["src/∗∗/∗.{js,json}"]
61
+ * @note We use `∗` (Mathematical Asterisk) instead of `*` (Asterisk) in the above example to avoid syntax highlighting issues.
62
+ */
63
+ readonly exclude?: readonly string[];
64
+ /**
65
+ * The schemas to generate for the project.
66
+ */
67
+ readonly schemas: Readonly<Record<string, SchemaConfig>>;
68
+ /**
69
+ * The plugins to use for the project.
70
+ */
71
+ readonly plugins?: PluginConfig;
72
+ };
73
+ type ResolvedSodaGqlConfig = {
74
+ readonly analyzer: "ts" | "swc";
75
+ readonly outdir: string;
76
+ readonly graphqlSystemAliases: readonly string[];
77
+ readonly include: readonly string[];
78
+ readonly exclude: readonly string[];
79
+ readonly schemas: Readonly<Record<string, SchemaConfig>>;
80
+ readonly plugins: PluginConfig;
81
+ };
82
+ //#endregion
83
+ //#region packages/config/src/helper.d.ts
84
+ /**
85
+ * Thin wrapper class to simplify the validation of exported value from config file.
86
+ * As we use SWC + VM to execute the config file, the exported value is not typed.
87
+ * This wrapper class ensures the exported value is a valid soda-gql config object.
88
+ */
89
+ declare class SodaGqlConfigContainer {
90
+ readonly config: SodaGqlConfig;
91
+ private constructor();
92
+ static create(config: SodaGqlConfig): SodaGqlConfigContainer;
93
+ }
94
+ /**
95
+ * Type-safe helper for defining soda-gql configuration.
96
+ * Supports both static and dynamic (async) configs.
97
+ *
98
+ * @example Static config
99
+ * ```ts
100
+ * import { defineConfig } from "@soda-gql/config";
101
+ *
102
+ * export default defineConfig({
103
+ * outdir: "./graphql-system",
104
+ * include: ["./src/**\/*.ts"],
105
+ * schemas: {
106
+ * default: {
107
+ * schema: "./schema.graphql",
108
+ * runtimeAdapter: "./runtime-adapter.ts",
109
+ * scalars: "./scalars.ts",
110
+ * },
111
+ * },
112
+ * });
113
+ * ```
114
+ *
115
+ * @example Async config
116
+ * ```ts
117
+ * export default defineConfig(async () => ({
118
+ * outdir: await resolveOutputDir(),
119
+ * include: ["./src/**\/*.ts"],
120
+ * schemas: {
121
+ * default: {
122
+ * schema: "./schema.graphql",
123
+ * runtimeAdapter: "./runtime-adapter.ts",
124
+ * scalars: "./scalars.ts",
125
+ * },
126
+ * },
127
+ * }));
128
+ * ```
129
+ */
130
+ declare function defineConfig(config: SodaGqlConfig): SodaGqlConfigContainer;
131
+ declare function defineConfig(config: () => SodaGqlConfig): SodaGqlConfigContainer;
132
+ declare function validateConfig(config: unknown): Result<SodaGqlConfig, ConfigError>;
133
+ //#endregion
134
+ //#region packages/config/src/loader.d.ts
135
+ declare const DEFAULT_CONFIG_FILENAMES: readonly ["soda-gql.config.ts", "soda-gql.config.mts", "soda-gql.config.js", "soda-gql.config.mjs"];
136
+ /**
137
+ * Find config file by walking up directory tree.
138
+ */
139
+ declare function findConfigFile(startDir?: string): string | null;
140
+ /**
141
+ * Load config with Result type (for library use).
142
+ */
143
+ declare function loadConfig(configPath: string | undefined): Result<ResolvedSodaGqlConfig, ConfigError>;
144
+ /**
145
+ * Load config from specific directory.
146
+ */
147
+ declare function loadConfigFrom(dir: string): Result<ResolvedSodaGqlConfig, ConfigError>;
148
+ //#endregion
149
+ //#region packages/config/src/normalize.d.ts
150
+ /**
151
+ * Resolve and normalize config with defaults.
152
+ */
153
+ declare function normalizeConfig(config: SodaGqlConfig): Result<ResolvedSodaGqlConfig, ConfigError>;
154
+ //#endregion
155
+ //#region packages/config/src/test-utils.d.ts
156
+ /**
157
+ * Create temporary config file with proper formatting.
158
+ * Uses template literals to support functions, regex, etc.
159
+ */
160
+ declare function withTempConfig<T>(config: Partial<SodaGqlConfig>, fn: (configPath: string) => Promise<T>): Promise<T>;
161
+ /**
162
+ * Simple temp config creation (without auto-cleanup).
163
+ */
164
+ declare function createTempConfigFile(dir: string, config: Partial<SodaGqlConfig>): string;
165
+ //#endregion
166
+ export { type ConfigError, type ConfigErrorCode, type PluginConfig, type ResolvedSodaGqlConfig, type SchemaConfig, type SodaGqlConfig, configError, createTempConfigFile, defineConfig, findConfigFile, loadConfig, loadConfigFrom, normalizeConfig, validateConfig, withTempConfig };
167
+ //# sourceMappingURL=index.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/helper.ts","../src/loader.ts","../src/normalize.ts","../src/test-utils.ts"],"sourcesContent":[],"mappings":"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"}
@@ -0,0 +1,167 @@
1
+ import { Result } from "neverthrow";
2
+
3
+ //#region packages/config/src/errors.d.ts
4
+ type ConfigErrorCode = "CONFIG_NOT_FOUND" | "CONFIG_LOAD_FAILED" | "CONFIG_VALIDATION_FAILED" | "CONFIG_INVALID_PATH";
5
+ type ConfigError = {
6
+ readonly code: ConfigErrorCode;
7
+ readonly message: string;
8
+ readonly filePath?: string;
9
+ readonly cause?: unknown;
10
+ };
11
+ declare const configError: ({
12
+ code,
13
+ message,
14
+ filePath,
15
+ cause
16
+ }: {
17
+ code: ConfigErrorCode;
18
+ message: string;
19
+ filePath?: string;
20
+ cause?: unknown;
21
+ }) => ConfigError;
22
+ //#endregion
23
+ //#region packages/config/src/types.d.ts
24
+ type SchemaConfig = {
25
+ readonly schema: string;
26
+ readonly runtimeAdapter: string;
27
+ readonly scalars: string;
28
+ };
29
+ type PluginConfig = Record<string, unknown>;
30
+ type SodaGqlConfig = {
31
+ /**
32
+ * The analyzer to use for the project.
33
+ * @default "ts"
34
+ */
35
+ readonly analyzer?: "ts" | "swc";
36
+ /**
37
+ * The directory for the graphql system.
38
+ * This is where the graphql system will be generated, and where the builder/plugin will reference the graphql system.
39
+ *
40
+ * @example "graphql-system" or "src/graphql-system"
41
+ */
42
+ readonly outdir: string;
43
+ /**
44
+ * The graphql system aliases to use for the project.
45
+ * This is necessary if you set paths in your tsconfig.json to reference the graphql system.
46
+ *
47
+ * @example ["@/graphql-system"]
48
+ */
49
+ readonly graphqlSystemAliases?: readonly string[];
50
+ /**
51
+ * The files to include in the project.
52
+ *
53
+ * @example ["src/∗∗/∗.{ts,tsx}"]
54
+ * @note We use `∗` (Mathematical Asterisk) instead of `*` (Asterisk) in the above example to avoid syntax highlighting issues.
55
+ */
56
+ readonly include: readonly string[];
57
+ /**
58
+ * The files to exclude from the project.
59
+ *
60
+ * @example ["src/∗∗/∗.{js,json}"]
61
+ * @note We use `∗` (Mathematical Asterisk) instead of `*` (Asterisk) in the above example to avoid syntax highlighting issues.
62
+ */
63
+ readonly exclude?: readonly string[];
64
+ /**
65
+ * The schemas to generate for the project.
66
+ */
67
+ readonly schemas: Readonly<Record<string, SchemaConfig>>;
68
+ /**
69
+ * The plugins to use for the project.
70
+ */
71
+ readonly plugins?: PluginConfig;
72
+ };
73
+ type ResolvedSodaGqlConfig = {
74
+ readonly analyzer: "ts" | "swc";
75
+ readonly outdir: string;
76
+ readonly graphqlSystemAliases: readonly string[];
77
+ readonly include: readonly string[];
78
+ readonly exclude: readonly string[];
79
+ readonly schemas: Readonly<Record<string, SchemaConfig>>;
80
+ readonly plugins: PluginConfig;
81
+ };
82
+ //#endregion
83
+ //#region packages/config/src/helper.d.ts
84
+ /**
85
+ * Thin wrapper class to simplify the validation of exported value from config file.
86
+ * As we use SWC + VM to execute the config file, the exported value is not typed.
87
+ * This wrapper class ensures the exported value is a valid soda-gql config object.
88
+ */
89
+ declare class SodaGqlConfigContainer {
90
+ readonly config: SodaGqlConfig;
91
+ private constructor();
92
+ static create(config: SodaGqlConfig): SodaGqlConfigContainer;
93
+ }
94
+ /**
95
+ * Type-safe helper for defining soda-gql configuration.
96
+ * Supports both static and dynamic (async) configs.
97
+ *
98
+ * @example Static config
99
+ * ```ts
100
+ * import { defineConfig } from "@soda-gql/config";
101
+ *
102
+ * export default defineConfig({
103
+ * outdir: "./graphql-system",
104
+ * include: ["./src/**\/*.ts"],
105
+ * schemas: {
106
+ * default: {
107
+ * schema: "./schema.graphql",
108
+ * runtimeAdapter: "./runtime-adapter.ts",
109
+ * scalars: "./scalars.ts",
110
+ * },
111
+ * },
112
+ * });
113
+ * ```
114
+ *
115
+ * @example Async config
116
+ * ```ts
117
+ * export default defineConfig(async () => ({
118
+ * outdir: await resolveOutputDir(),
119
+ * include: ["./src/**\/*.ts"],
120
+ * schemas: {
121
+ * default: {
122
+ * schema: "./schema.graphql",
123
+ * runtimeAdapter: "./runtime-adapter.ts",
124
+ * scalars: "./scalars.ts",
125
+ * },
126
+ * },
127
+ * }));
128
+ * ```
129
+ */
130
+ declare function defineConfig(config: SodaGqlConfig): SodaGqlConfigContainer;
131
+ declare function defineConfig(config: () => SodaGqlConfig): SodaGqlConfigContainer;
132
+ declare function validateConfig(config: unknown): Result<SodaGqlConfig, ConfigError>;
133
+ //#endregion
134
+ //#region packages/config/src/loader.d.ts
135
+ declare const DEFAULT_CONFIG_FILENAMES: readonly ["soda-gql.config.ts", "soda-gql.config.mts", "soda-gql.config.js", "soda-gql.config.mjs"];
136
+ /**
137
+ * Find config file by walking up directory tree.
138
+ */
139
+ declare function findConfigFile(startDir?: string): string | null;
140
+ /**
141
+ * Load config with Result type (for library use).
142
+ */
143
+ declare function loadConfig(configPath: string | undefined): Result<ResolvedSodaGqlConfig, ConfigError>;
144
+ /**
145
+ * Load config from specific directory.
146
+ */
147
+ declare function loadConfigFrom(dir: string): Result<ResolvedSodaGqlConfig, ConfigError>;
148
+ //#endregion
149
+ //#region packages/config/src/normalize.d.ts
150
+ /**
151
+ * Resolve and normalize config with defaults.
152
+ */
153
+ declare function normalizeConfig(config: SodaGqlConfig): Result<ResolvedSodaGqlConfig, ConfigError>;
154
+ //#endregion
155
+ //#region packages/config/src/test-utils.d.ts
156
+ /**
157
+ * Create temporary config file with proper formatting.
158
+ * Uses template literals to support functions, regex, etc.
159
+ */
160
+ declare function withTempConfig<T>(config: Partial<SodaGqlConfig>, fn: (configPath: string) => Promise<T>): Promise<T>;
161
+ /**
162
+ * Simple temp config creation (without auto-cleanup).
163
+ */
164
+ declare function createTempConfigFile(dir: string, config: Partial<SodaGqlConfig>): string;
165
+ //#endregion
166
+ export { type ConfigError, type ConfigErrorCode, type PluginConfig, type ResolvedSodaGqlConfig, type SchemaConfig, type SodaGqlConfig, configError, createTempConfigFile, defineConfig, findConfigFile, loadConfig, loadConfigFrom, normalizeConfig, validateConfig, withTempConfig };
167
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/helper.ts","../src/loader.ts","../src/normalize.ts","../src/test-utils.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,235 @@
1
+ import { createRequire } from "node:module";
2
+ import { defineSchemaFor, resolveRelativeImportWithExistenceCheck } from "@soda-gql/common";
3
+ import { err, ok } from "neverthrow";
4
+ import z from "zod";
5
+ import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
6
+ import { dirname, join, resolve } from "node:path";
7
+ import { dirname as dirname$1, resolve as resolve$1 } from "node:path/posix";
8
+ import { Script } from "node:vm";
9
+ import { transformSync } from "@swc/core";
10
+ import { tmpdir } from "node:os";
11
+
12
+ //#region packages/config/src/errors.ts
13
+ const configError = ({ code, message, filePath, cause }) => ({
14
+ code,
15
+ message,
16
+ filePath,
17
+ cause
18
+ });
19
+
20
+ //#endregion
21
+ //#region packages/config/src/helper.ts
22
+ /**
23
+ * Thin wrapper class to simplify the validation of exported value from config file.
24
+ * As we use SWC + VM to execute the config file, the exported value is not typed.
25
+ * This wrapper class ensures the exported value is a valid soda-gql config object.
26
+ */
27
+ var SodaGqlConfigContainer = class SodaGqlConfigContainer {
28
+ constructor(config) {
29
+ this.config = config;
30
+ }
31
+ static create(config) {
32
+ return new SodaGqlConfigContainer(config);
33
+ }
34
+ };
35
+ function defineConfig(config) {
36
+ const validated = validateConfig(typeof config === "function" ? config() : config);
37
+ if (validated.isErr()) {
38
+ throw validated.error;
39
+ }
40
+ return SodaGqlConfigContainer.create(validated.value);
41
+ }
42
+ const SchemaConfigSchema = defineSchemaFor()({
43
+ schema: z.string().min(1),
44
+ runtimeAdapter: z.string().min(1),
45
+ scalars: z.string().min(1)
46
+ });
47
+ const SodaGqlConfigSchema = defineSchemaFor()({
48
+ analyzer: z.enum(["ts", "swc"]).optional(),
49
+ outdir: z.string().min(1),
50
+ graphqlSystemAliases: z.array(z.string()).optional(),
51
+ include: z.array(z.string().min(1)),
52
+ exclude: z.array(z.string().min(1)).optional(),
53
+ schemas: z.record(z.string(), SchemaConfigSchema),
54
+ plugins: z.record(z.string(), z.unknown()).optional()
55
+ });
56
+ function validateConfig(config) {
57
+ const result = SodaGqlConfigSchema.safeParse(config);
58
+ if (!result.success) {
59
+ return err(configError({
60
+ code: "CONFIG_VALIDATION_FAILED",
61
+ message: `Invalid config: ${result.error.message}`
62
+ }));
63
+ }
64
+ return ok(result.data);
65
+ }
66
+
67
+ //#endregion
68
+ //#region packages/config/src/evaluation.ts
69
+ /**
70
+ * Load and execute TypeScript config file synchronously using SWC + VM.
71
+ */
72
+ function executeConfigFile(configPath) {
73
+ const filePath = resolve$1(configPath);
74
+ try {
75
+ const source = readFileSync(filePath, "utf-8");
76
+ const result = transformSync(source, {
77
+ filename: filePath,
78
+ jsc: { parser: { syntax: "typescript" } },
79
+ module: { type: "commonjs" },
80
+ sourceMaps: false,
81
+ minify: false
82
+ });
83
+ const mod = { exports: {} };
84
+ const requireInner = createRequire(filePath);
85
+ const require = (specifier) => {
86
+ if (!specifier.startsWith(".")) {
87
+ return requireInner(specifier);
88
+ }
89
+ const resolvedPath = resolveRelativeImportWithExistenceCheck({
90
+ filePath,
91
+ specifier
92
+ });
93
+ if (!resolvedPath) {
94
+ throw new Error(`Module not found: ${specifier}`);
95
+ }
96
+ return requireInner(resolvedPath);
97
+ };
98
+ new Script(result.code, { filename: filePath }).runInNewContext({
99
+ require,
100
+ module: mod,
101
+ exports: mod.exports,
102
+ __dirname: dirname$1(filePath),
103
+ __filename: filePath,
104
+ console,
105
+ process
106
+ });
107
+ const config = mod.exports && typeof mod.exports === "object" && "default" in mod.exports && mod.exports.default instanceof SodaGqlConfigContainer ? mod.exports.default.config : null;
108
+ if (!config) {
109
+ throw new Error("Invalid config module");
110
+ }
111
+ return config;
112
+ } catch (error) {
113
+ throw configError({
114
+ code: "CONFIG_LOAD_FAILED",
115
+ message: `Failed to load config: ${error instanceof Error ? error.message : String(error)}`,
116
+ filePath,
117
+ cause: error
118
+ });
119
+ }
120
+ }
121
+
122
+ //#endregion
123
+ //#region packages/config/src/normalize.ts
124
+ /**
125
+ * Resolve and normalize config with defaults.
126
+ */
127
+ function normalizeConfig(config) {
128
+ const analyzer = config.analyzer ?? "ts";
129
+ const graphqlSystemAliases = config.graphqlSystemAliases ?? ["@/graphql-system"];
130
+ const exclude = config.exclude ?? [];
131
+ const resolved = {
132
+ analyzer,
133
+ outdir: resolve(config.outdir),
134
+ graphqlSystemAliases,
135
+ include: config.include.map((pattern) => resolve(pattern)),
136
+ exclude: exclude.map((pattern) => resolve(pattern)),
137
+ schemas: Object.fromEntries(Object.entries(config.schemas).map(([name, schemaConfig]) => [name, {
138
+ schema: resolve(schemaConfig.schema),
139
+ runtimeAdapter: resolve(schemaConfig.runtimeAdapter),
140
+ scalars: resolve(schemaConfig.scalars)
141
+ }])),
142
+ plugins: config.plugins ?? {}
143
+ };
144
+ return ok(resolved);
145
+ }
146
+
147
+ //#endregion
148
+ //#region packages/config/src/loader.ts
149
+ const DEFAULT_CONFIG_FILENAMES = [
150
+ "soda-gql.config.ts",
151
+ "soda-gql.config.mts",
152
+ "soda-gql.config.js",
153
+ "soda-gql.config.mjs"
154
+ ];
155
+ /**
156
+ * Find config file by walking up directory tree.
157
+ */
158
+ function findConfigFile(startDir = process.cwd()) {
159
+ let currentDir = startDir;
160
+ while (currentDir !== dirname(currentDir)) {
161
+ for (const filename of DEFAULT_CONFIG_FILENAMES) {
162
+ const configPath = join(currentDir, filename);
163
+ if (existsSync(configPath)) {
164
+ return configPath;
165
+ }
166
+ }
167
+ currentDir = dirname(currentDir);
168
+ }
169
+ return null;
170
+ }
171
+ /**
172
+ * Load config with Result type (for library use).
173
+ */
174
+ function loadConfig(configPath) {
175
+ const resolvedPath = configPath ?? findConfigFile();
176
+ if (!resolvedPath) {
177
+ return err(configError({
178
+ code: "CONFIG_NOT_FOUND",
179
+ message: "Config file not found"
180
+ }));
181
+ }
182
+ try {
183
+ return normalizeConfig(executeConfigFile(resolvedPath));
184
+ } catch (error) {
185
+ return err(configError({
186
+ code: "CONFIG_LOAD_FAILED",
187
+ message: `Failed to load config: ${error}`,
188
+ filePath: resolvedPath,
189
+ cause: error
190
+ }));
191
+ }
192
+ }
193
+ /**
194
+ * Load config from specific directory.
195
+ */
196
+ function loadConfigFrom(dir) {
197
+ const configPath = findConfigFile(dir);
198
+ return loadConfig(configPath ?? undefined);
199
+ }
200
+
201
+ //#endregion
202
+ //#region packages/config/src/test-utils.ts
203
+ /**
204
+ * Create temporary config file with proper formatting.
205
+ * Uses template literals to support functions, regex, etc.
206
+ */
207
+ async function withTempConfig(config, fn) {
208
+ const tmpDir = mkdtempSync(join(tmpdir(), "soda-gql-test-"));
209
+ const configPath = join(tmpDir, "soda-gql.config.ts");
210
+ const configContent = `
211
+ import { defineConfig } from "@soda-gql/config";
212
+
213
+ export default defineConfig(${JSON.stringify(config, null, 2)});
214
+ `.trim();
215
+ writeFileSync(configPath, configContent);
216
+ return fn(configPath).finally(() => {
217
+ rmSync(tmpDir, {
218
+ recursive: true,
219
+ force: true
220
+ });
221
+ });
222
+ }
223
+ /**
224
+ * Simple temp config creation (without auto-cleanup).
225
+ */
226
+ function createTempConfigFile(dir, config) {
227
+ const configPath = join(dir, "soda-gql.config.ts");
228
+ const configContent = `export default ${JSON.stringify(config, null, 2)};`;
229
+ writeFileSync(configPath, configContent);
230
+ return configPath;
231
+ }
232
+
233
+ //#endregion
234
+ export { configError, createTempConfigFile, defineConfig, findConfigFile, loadConfig, loadConfigFrom, normalizeConfig, validateConfig, withTempConfig };
235
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":["config: SodaGqlConfig","resolve","mod: { exports: unknown }","dirname","resolved: ResolvedSodaGqlConfig"],"sources":["../src/errors.ts","../src/helper.ts","../src/evaluation.ts","../src/normalize.ts","../src/loader.ts","../src/test-utils.ts"],"sourcesContent":["export type ConfigErrorCode = \"CONFIG_NOT_FOUND\" | \"CONFIG_LOAD_FAILED\" | \"CONFIG_VALIDATION_FAILED\" | \"CONFIG_INVALID_PATH\";\n\nexport type ConfigError = {\n readonly code: ConfigErrorCode;\n readonly message: string;\n readonly filePath?: string;\n readonly cause?: unknown;\n};\n\nexport const configError = ({\n code,\n message,\n filePath,\n cause,\n}: {\n code: ConfigErrorCode;\n message: string;\n filePath?: string;\n cause?: unknown;\n}): ConfigError => ({\n code,\n message,\n filePath,\n cause,\n});\n","import { defineSchemaFor } from \"@soda-gql/common\";\nimport { err, ok, type Result } from \"neverthrow\";\nimport z from \"zod\";\nimport { type ConfigError, configError } from \"./errors\";\nimport type { SchemaConfig, SodaGqlConfig } from \"./types\";\n\n/**\n * Thin wrapper class to simplify the validation of exported value from config file.\n * As we use SWC + VM to execute the config file, the exported value is not typed.\n * This wrapper class ensures the exported value is a valid soda-gql config object.\n */\nexport class SodaGqlConfigContainer {\n private constructor(public readonly config: SodaGqlConfig) {}\n\n public static create(config: SodaGqlConfig): SodaGqlConfigContainer {\n return new SodaGqlConfigContainer(config);\n }\n}\n\n/**\n * Type-safe helper for defining soda-gql configuration.\n * Supports both static and dynamic (async) configs.\n *\n * @example Static config\n * ```ts\n * import { defineConfig } from \"@soda-gql/config\";\n *\n * export default defineConfig({\n * outdir: \"./graphql-system\",\n * include: [\"./src/**\\/*.ts\"],\n * schemas: {\n * default: {\n * schema: \"./schema.graphql\",\n * runtimeAdapter: \"./runtime-adapter.ts\",\n * scalars: \"./scalars.ts\",\n * },\n * },\n * });\n * ```\n *\n * @example Async config\n * ```ts\n * export default defineConfig(async () => ({\n * outdir: await resolveOutputDir(),\n * include: [\"./src/**\\/*.ts\"],\n * schemas: {\n * default: {\n * schema: \"./schema.graphql\",\n * runtimeAdapter: \"./runtime-adapter.ts\",\n * scalars: \"./scalars.ts\",\n * },\n * },\n * }));\n * ```\n */\nexport function defineConfig(config: SodaGqlConfig): SodaGqlConfigContainer;\nexport function defineConfig(config: () => SodaGqlConfig): SodaGqlConfigContainer;\nexport function defineConfig(config: SodaGqlConfig | (() => SodaGqlConfig)): SodaGqlConfigContainer {\n const validated = validateConfig(typeof config === \"function\" ? config() : config);\n if (validated.isErr()) {\n throw validated.error;\n }\n return SodaGqlConfigContainer.create(validated.value);\n}\n\nconst SchemaConfigSchema = defineSchemaFor<SchemaConfig>()({\n schema: z.string().min(1),\n runtimeAdapter: z.string().min(1),\n scalars: z.string().min(1),\n});\n\nconst SodaGqlConfigSchema = defineSchemaFor<SodaGqlConfig>()({\n analyzer: z.enum([\"ts\", \"swc\"]).optional(),\n outdir: z.string().min(1),\n graphqlSystemAliases: z.array(z.string()).optional(),\n include: z.array(z.string().min(1)),\n exclude: z.array(z.string().min(1)).optional(),\n schemas: z.record(z.string(), SchemaConfigSchema),\n plugins: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport function validateConfig(config: unknown): Result<SodaGqlConfig, ConfigError> {\n const result = SodaGqlConfigSchema.safeParse(config);\n\n if (!result.success) {\n return err(\n configError({\n code: \"CONFIG_VALIDATION_FAILED\",\n message: `Invalid config: ${result.error.message}`,\n }),\n );\n }\n\n return ok(result.data satisfies SodaGqlConfig);\n}\n","import { readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport { dirname, resolve } from \"node:path/posix\";\nimport { Script } from \"node:vm\";\nimport { resolveRelativeImportWithExistenceCheck } from \"@soda-gql/common\";\nimport { transformSync } from \"@swc/core\";\nimport { configError } from \"./errors\";\nimport { SodaGqlConfigContainer } from \"./helper\";\nimport type { SodaGqlConfig } from \"./types\";\n\n/**\n * Load and execute TypeScript config file synchronously using SWC + VM.\n */\nexport function executeConfigFile(configPath: string): SodaGqlConfig {\n const filePath = resolve(configPath);\n try {\n // Read the config file\n const source = readFileSync(filePath, \"utf-8\");\n\n // Transform TypeScript to CommonJS using SWC\n const result = transformSync(source, {\n filename: filePath,\n jsc: {\n parser: {\n syntax: \"typescript\",\n },\n },\n module: {\n type: \"commonjs\",\n },\n sourceMaps: false,\n minify: false,\n });\n\n // Create CommonJS context\n const mod: { exports: unknown } = { exports: {} };\n\n const requireInner = createRequire(filePath);\n const require = (specifier: string) => {\n // Handle external modules normally\n if (!specifier.startsWith(\".\")) {\n return requireInner(specifier);\n }\n\n // Resolve relative imports with existence check\n const resolvedPath = resolveRelativeImportWithExistenceCheck({ filePath, specifier });\n if (!resolvedPath) {\n throw new Error(`Module not found: ${specifier}`);\n }\n return requireInner(resolvedPath);\n };\n\n // Execute in VM context\n new Script(result.code, { filename: filePath }).runInNewContext({\n require,\n module: mod,\n exports: mod.exports,\n __dirname: dirname(filePath),\n __filename: filePath,\n console,\n process,\n });\n\n const config =\n mod.exports &&\n typeof mod.exports === \"object\" &&\n \"default\" in mod.exports &&\n mod.exports.default instanceof SodaGqlConfigContainer\n ? mod.exports.default.config\n : null;\n\n if (!config) {\n throw new Error(\"Invalid config module\");\n }\n\n return config;\n } catch (error) {\n throw configError({\n code: \"CONFIG_LOAD_FAILED\",\n message: `Failed to load config: ${error instanceof Error ? error.message : String(error)}`,\n filePath: filePath,\n cause: error,\n });\n }\n}\n","import { resolve } from \"node:path\";\nimport type { Result } from \"neverthrow\";\nimport { ok } from \"neverthrow\";\nimport type { ConfigError } from \"./errors\";\nimport type { ResolvedSodaGqlConfig, SodaGqlConfig } from \"./types\";\n\n/**\n * Resolve and normalize config with defaults.\n */\nexport function normalizeConfig(config: SodaGqlConfig): Result<ResolvedSodaGqlConfig, ConfigError> {\n // Default analyzer to \"ts\"\n const analyzer = config.analyzer ?? \"ts\";\n\n // Default graphqlSystemAliases to [\"@/graphql-system\"]\n const graphqlSystemAliases = config.graphqlSystemAliases ?? [\"@/graphql-system\"];\n\n // Default exclude to empty array\n const exclude = config.exclude ?? [];\n\n const resolved: ResolvedSodaGqlConfig = {\n analyzer,\n outdir: resolve(config.outdir),\n graphqlSystemAliases,\n include: config.include.map((pattern) => resolve(pattern)),\n exclude: exclude.map((pattern) => resolve(pattern)),\n schemas: Object.fromEntries(\n Object.entries(config.schemas).map(([name, schemaConfig]) => [\n name,\n {\n schema: resolve(schemaConfig.schema),\n runtimeAdapter: resolve(schemaConfig.runtimeAdapter),\n scalars: resolve(schemaConfig.scalars),\n },\n ]),\n ),\n plugins: config.plugins ?? {},\n };\n\n return ok(resolved);\n}\n","import { existsSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { Result } from \"neverthrow\";\nimport { err } from \"neverthrow\";\nimport type { ConfigError } from \"./errors\";\nimport { configError } from \"./errors\";\nimport { executeConfigFile } from \"./evaluation\";\nimport { normalizeConfig } from \"./normalize\";\nimport type { ResolvedSodaGqlConfig } from \"./types\";\n\nexport const DEFAULT_CONFIG_FILENAMES = [\n \"soda-gql.config.ts\",\n \"soda-gql.config.mts\",\n \"soda-gql.config.js\",\n \"soda-gql.config.mjs\",\n] as const;\n\n/**\n * Find config file by walking up directory tree.\n */\nexport function findConfigFile(startDir: string = process.cwd()): string | null {\n let currentDir = startDir;\n while (currentDir !== dirname(currentDir)) {\n for (const filename of DEFAULT_CONFIG_FILENAMES) {\n const configPath = join(currentDir, filename);\n if (existsSync(configPath)) {\n return configPath;\n }\n }\n currentDir = dirname(currentDir);\n }\n return null;\n}\n\n/**\n * Load config with Result type (for library use).\n */\nexport function loadConfig(configPath: string | undefined): Result<ResolvedSodaGqlConfig, ConfigError> {\n const resolvedPath = configPath ?? findConfigFile();\n\n if (!resolvedPath) {\n return err(configError({ code: \"CONFIG_NOT_FOUND\", message: \"Config file not found\" }));\n }\n\n try {\n return normalizeConfig(executeConfigFile(resolvedPath));\n } catch (error) {\n return err(\n configError({\n code: \"CONFIG_LOAD_FAILED\",\n message: `Failed to load config: ${error}`,\n filePath: resolvedPath,\n cause: error,\n }),\n );\n }\n}\n\n/**\n * Load config from specific directory.\n */\nexport function loadConfigFrom(dir: string): Result<ResolvedSodaGqlConfig, ConfigError> {\n const configPath = findConfigFile(dir);\n return loadConfig(configPath ?? undefined);\n}\n","import { mkdtempSync, rmSync, writeFileSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { SodaGqlConfig } from \"./types\";\n\n/**\n * Create temporary config file with proper formatting.\n * Uses template literals to support functions, regex, etc.\n */\nexport async function withTempConfig<T>(config: Partial<SodaGqlConfig>, fn: (configPath: string) => Promise<T>): Promise<T> {\n const tmpDir = mkdtempSync(join(tmpdir(), \"soda-gql-test-\"));\n const configPath = join(tmpDir, \"soda-gql.config.ts\");\n\n // Generate config file using template\n const configContent = `\nimport { defineConfig } from \"@soda-gql/config\";\n\nexport default defineConfig(${JSON.stringify(config, null, 2)});\n`.trim();\n\n writeFileSync(configPath, configContent);\n\n return fn(configPath).finally(() => {\n rmSync(tmpDir, { recursive: true, force: true });\n });\n}\n\n/**\n * Simple temp config creation (without auto-cleanup).\n */\nexport function createTempConfigFile(dir: string, config: Partial<SodaGqlConfig>): string {\n const configPath = join(dir, \"soda-gql.config.ts\");\n\n // Write config as direct export (no imports needed for simple configs)\n const configContent = `export default ${JSON.stringify(config, null, 2)};`;\n\n writeFileSync(configPath, configContent);\n return configPath;\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "@soda-gql/config",
3
+ "version": "0.0.1",
4
+ "description": "Centralized configuration loader and helpers for soda-gql tooling.",
5
+ "type": "module",
6
+ "private": false,
7
+ "license": "MIT",
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "author": {
12
+ "name": "Shota Hatada",
13
+ "email": "shota.hatada@whatasoda.me",
14
+ "url": "https://github.com/whatasoda"
15
+ },
16
+ "main": "./dist/index.js",
17
+ "module": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "development": "./src/index.ts",
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "require": "./dist/index.cjs",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./package.json": "./package.json"
28
+ },
29
+ "dependencies": {
30
+ "@soda-gql/common": "0.0.1",
31
+ "@swc/core": "^1.10.0",
32
+ "neverthrow": "^8.2.0",
33
+ "zod": "^4.1.11"
34
+ },
35
+ "devDependencies": {},
36
+ "peerDependencies": {}
37
+ }