@optique/config 0.10.0-dev.335 → 0.10.0-dev.342
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/dist/{index-CZZEDay7.d.cts → index-D25zYfjf.d.cts} +0 -12
- package/dist/{index-DiDpcijz.d.ts → index-D_lTcz4s.d.ts} +0 -12
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/run.cjs +62 -25
- package/dist/run.d.cts +65 -9
- package/dist/run.d.ts +65 -9
- package/dist/run.js +62 -25
- package/dist/{src-iXO5MxwN.js → src-C9h3sfAM.js} +0 -1
- package/dist/{src-DVH5fJU9.cjs → src-CTH1AjFs.cjs} +0 -1
- package/package.json +1 -1
|
@@ -36,14 +36,6 @@ interface ConfigContextOptions<T> {
|
|
|
36
36
|
* Accepts any Standard Schema-compatible library (Zod, Valibot, ArkType, etc.).
|
|
37
37
|
*/
|
|
38
38
|
readonly schema: StandardSchemaV1<unknown, T>;
|
|
39
|
-
/**
|
|
40
|
-
* Custom parser function for reading config file contents.
|
|
41
|
-
* If not provided, defaults to JSON.parse.
|
|
42
|
-
*
|
|
43
|
-
* @param contents The raw file contents as Uint8Array.
|
|
44
|
-
* @returns The parsed config data (will be validated by schema).
|
|
45
|
-
*/
|
|
46
|
-
readonly parser?: (contents: Uint8Array) => unknown;
|
|
47
39
|
}
|
|
48
40
|
/**
|
|
49
41
|
* Required options for ConfigContext when used with runWith().
|
|
@@ -77,10 +69,6 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
|
|
|
77
69
|
* The Standard Schema validator for the config file.
|
|
78
70
|
*/
|
|
79
71
|
readonly schema: StandardSchemaV1<unknown, T>;
|
|
80
|
-
/**
|
|
81
|
-
* Custom parser function for reading config file contents.
|
|
82
|
-
*/
|
|
83
|
-
readonly parser?: (contents: Uint8Array) => unknown;
|
|
84
72
|
}
|
|
85
73
|
/**
|
|
86
74
|
* Creates a config context for use with Optique parsers.
|
|
@@ -36,14 +36,6 @@ interface ConfigContextOptions<T> {
|
|
|
36
36
|
* Accepts any Standard Schema-compatible library (Zod, Valibot, ArkType, etc.).
|
|
37
37
|
*/
|
|
38
38
|
readonly schema: StandardSchemaV1<unknown, T>;
|
|
39
|
-
/**
|
|
40
|
-
* Custom parser function for reading config file contents.
|
|
41
|
-
* If not provided, defaults to JSON.parse.
|
|
42
|
-
*
|
|
43
|
-
* @param contents The raw file contents as Uint8Array.
|
|
44
|
-
* @returns The parsed config data (will be validated by schema).
|
|
45
|
-
*/
|
|
46
|
-
readonly parser?: (contents: Uint8Array) => unknown;
|
|
47
39
|
}
|
|
48
40
|
/**
|
|
49
41
|
* Required options for ConfigContext when used with runWith().
|
|
@@ -77,10 +69,6 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
|
|
|
77
69
|
* The Standard Schema validator for the config file.
|
|
78
70
|
*/
|
|
79
71
|
readonly schema: StandardSchemaV1<unknown, T>;
|
|
80
|
-
/**
|
|
81
|
-
* Custom parser function for reading config file contents.
|
|
82
|
-
*/
|
|
83
|
-
readonly parser?: (contents: Uint8Array) => unknown;
|
|
84
72
|
}
|
|
85
73
|
/**
|
|
86
74
|
* Creates a config context for use with Optique parsers.
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-
|
|
1
|
+
import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-D25zYfjf.cjs";
|
|
2
2
|
export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-
|
|
1
|
+
import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-D_lTcz4s.js";
|
|
2
2
|
export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./src-
|
|
1
|
+
import { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./src-C9h3sfAM.js";
|
|
2
2
|
|
|
3
3
|
export { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
|
package/dist/run.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const require_src = require('./src-
|
|
1
|
+
const require_src = require('./src-CTH1AjFs.cjs');
|
|
2
2
|
const node_fs_promises = require_src.__toESM(require("node:fs/promises"));
|
|
3
3
|
const __optique_core_parser = require_src.__toESM(require("@optique/core/parser"));
|
|
4
4
|
|
|
@@ -7,8 +7,8 @@ const __optique_core_parser = require_src.__toESM(require("@optique/core/parser"
|
|
|
7
7
|
* Runs a parser with configuration file support using two-pass parsing.
|
|
8
8
|
*
|
|
9
9
|
* This function performs the following steps:
|
|
10
|
-
* 1. First pass: Parse arguments to extract
|
|
11
|
-
* 2. Load and validate:
|
|
10
|
+
* 1. First pass: Parse arguments to extract config path or data
|
|
11
|
+
* 2. Load and validate: Load config file(s) and validate using Standard Schema
|
|
12
12
|
* 3. Second pass: Parse arguments again with config data as annotations
|
|
13
13
|
*
|
|
14
14
|
* The priority order for values is: CLI > config file > default.
|
|
@@ -18,13 +18,13 @@ const __optique_core_parser = require_src.__toESM(require("@optique/core/parser"
|
|
|
18
18
|
* @template TState The parser state type.
|
|
19
19
|
* @template T The config data type.
|
|
20
20
|
* @param parser The parser to execute.
|
|
21
|
-
* @param context The config context with schema
|
|
22
|
-
* @param options Run options
|
|
21
|
+
* @param context The config context with schema.
|
|
22
|
+
* @param options Run options - either SingleFileOptions or CustomLoadOptions.
|
|
23
23
|
* @returns Promise that resolves to the parsed result.
|
|
24
24
|
* @throws Error if config file validation fails.
|
|
25
25
|
* @since 0.10.0
|
|
26
26
|
*
|
|
27
|
-
* @example
|
|
27
|
+
* @example Single file mode
|
|
28
28
|
* ```typescript
|
|
29
29
|
* import { z } from "zod";
|
|
30
30
|
* import { runWithConfig } from "@optique/config/run";
|
|
@@ -51,6 +51,23 @@ const __optique_core_parser = require_src.__toESM(require("@optique/core/parser"
|
|
|
51
51
|
* args: process.argv.slice(2),
|
|
52
52
|
* });
|
|
53
53
|
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example Custom load mode (multi-file merging)
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { deepMerge } from "es-toolkit";
|
|
58
|
+
*
|
|
59
|
+
* const result = await runWithConfig(parser, context, {
|
|
60
|
+
* load: async (parsed) => {
|
|
61
|
+
* const configs = await Promise.all([
|
|
62
|
+
* loadToml("/etc/app/config.toml").catch(() => ({})),
|
|
63
|
+
* loadToml("~/.config/app/config.toml").catch(() => ({})),
|
|
64
|
+
* loadToml("./.app.toml").catch(() => ({})),
|
|
65
|
+
* ]);
|
|
66
|
+
* return deepMerge(...configs);
|
|
67
|
+
* },
|
|
68
|
+
* args: process.argv.slice(2),
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
54
71
|
*/
|
|
55
72
|
async function runWithConfig(parser, context, options) {
|
|
56
73
|
const args = options.args ?? [];
|
|
@@ -73,28 +90,48 @@ async function runWithConfig(parser, context, options) {
|
|
|
73
90
|
});
|
|
74
91
|
throw new Error(`Parsing failed: ${errorParts.join("")}`);
|
|
75
92
|
}
|
|
76
|
-
const configPath = options.getConfigPath(firstPassResult.value);
|
|
77
93
|
let configData;
|
|
78
|
-
if (
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
if ("load" in options) {
|
|
95
|
+
const customOptions = options;
|
|
96
|
+
try {
|
|
97
|
+
const rawData = await Promise.resolve(customOptions.load(firstPassResult.value));
|
|
98
|
+
const validation = context.schema["~standard"].validate(rawData);
|
|
99
|
+
let validationResult;
|
|
100
|
+
if (validation instanceof Promise) validationResult = await validation;
|
|
101
|
+
else validationResult = validation;
|
|
102
|
+
if (validationResult.issues) {
|
|
103
|
+
const firstIssue = validationResult.issues[0];
|
|
104
|
+
throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
|
|
105
|
+
}
|
|
106
|
+
configData = validationResult.value;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
109
|
+
throw error;
|
|
85
110
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
} else {
|
|
112
|
+
const singleFileOptions = options;
|
|
113
|
+
const configPath = singleFileOptions.getConfigPath(firstPassResult.value);
|
|
114
|
+
if (configPath) try {
|
|
115
|
+
const contents = await (0, node_fs_promises.readFile)(configPath);
|
|
116
|
+
let rawData;
|
|
117
|
+
if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
|
|
118
|
+
else {
|
|
119
|
+
const text = new TextDecoder().decode(contents);
|
|
120
|
+
rawData = JSON.parse(text);
|
|
121
|
+
}
|
|
122
|
+
const validation = context.schema["~standard"].validate(rawData);
|
|
123
|
+
let validationResult;
|
|
124
|
+
if (validation instanceof Promise) validationResult = await validation;
|
|
125
|
+
else validationResult = validation;
|
|
126
|
+
if (validationResult.issues) {
|
|
127
|
+
const firstIssue = validationResult.issues[0];
|
|
128
|
+
throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
|
|
129
|
+
}
|
|
130
|
+
configData = validationResult.value;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
133
|
+
configData = void 0;
|
|
93
134
|
}
|
|
94
|
-
configData = validationResult.value;
|
|
95
|
-
} catch (error) {
|
|
96
|
-
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
97
|
-
configData = void 0;
|
|
98
135
|
}
|
|
99
136
|
const annotations = configData ? { [require_src.configKey]: configData } : {};
|
|
100
137
|
if (configData) require_src.setActiveConfig(context.id, configData);
|
package/dist/run.d.cts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { ConfigContext } from "./index-
|
|
1
|
+
import { ConfigContext } from "./index-D25zYfjf.cjs";
|
|
2
2
|
import { Parser } from "@optique/core/parser";
|
|
3
3
|
|
|
4
4
|
//#region src/run.d.ts
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Options for
|
|
7
|
+
* Options for single-file config loading.
|
|
8
8
|
*
|
|
9
9
|
* @template TValue The parser value type, inferred from the parser.
|
|
10
10
|
* @since 0.10.0
|
|
11
11
|
*/
|
|
12
|
-
interface
|
|
12
|
+
interface SingleFileOptions<TValue> {
|
|
13
13
|
/**
|
|
14
14
|
* Function to extract the config file path from parsed CLI arguments.
|
|
15
15
|
* This function receives the result of the first parse pass and should
|
|
@@ -19,18 +19,57 @@ interface RunWithConfigOptions<TValue> {
|
|
|
19
19
|
* providing full type safety without manual type assertions.
|
|
20
20
|
*/
|
|
21
21
|
readonly getConfigPath: (parsed: TValue) => string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Custom parser function for reading config file contents.
|
|
24
|
+
* If not provided, defaults to JSON.parse.
|
|
25
|
+
*
|
|
26
|
+
* @param contents The raw file contents as Uint8Array.
|
|
27
|
+
* @returns The parsed config data (will be validated by schema).
|
|
28
|
+
*/
|
|
29
|
+
readonly fileParser?: (contents: Uint8Array) => unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Command-line arguments to parse.
|
|
32
|
+
* If not provided, defaults to an empty array.
|
|
33
|
+
*/
|
|
34
|
+
readonly args?: readonly string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for custom config loading with multi-file merging support.
|
|
38
|
+
*
|
|
39
|
+
* @template TValue The parser value type, inferred from the parser.
|
|
40
|
+
* @since 0.10.0
|
|
41
|
+
*/
|
|
42
|
+
interface CustomLoadOptions<TValue> {
|
|
43
|
+
/**
|
|
44
|
+
* Custom loader function that receives the first-pass parse result and
|
|
45
|
+
* returns the config data (or a Promise of it). This allows full control
|
|
46
|
+
* over file discovery, loading, merging, and error handling.
|
|
47
|
+
*
|
|
48
|
+
* The returned data will be validated against the schema.
|
|
49
|
+
*
|
|
50
|
+
* @param parsed The result from the first parse pass.
|
|
51
|
+
* @returns The raw config data (will be validated by schema).
|
|
52
|
+
*/
|
|
53
|
+
readonly load: (parsed: TValue) => Promise<unknown> | unknown;
|
|
22
54
|
/**
|
|
23
55
|
* Command-line arguments to parse.
|
|
24
56
|
* If not provided, defaults to an empty array.
|
|
25
57
|
*/
|
|
26
58
|
readonly args?: readonly string[];
|
|
27
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Options for runWithConfig.
|
|
62
|
+
*
|
|
63
|
+
* @template TValue The parser value type, inferred from the parser.
|
|
64
|
+
* @since 0.10.0
|
|
65
|
+
*/
|
|
66
|
+
type RunWithConfigOptions<TValue> = SingleFileOptions<TValue> | CustomLoadOptions<TValue>;
|
|
28
67
|
/**
|
|
29
68
|
* Runs a parser with configuration file support using two-pass parsing.
|
|
30
69
|
*
|
|
31
70
|
* This function performs the following steps:
|
|
32
|
-
* 1. First pass: Parse arguments to extract
|
|
33
|
-
* 2. Load and validate:
|
|
71
|
+
* 1. First pass: Parse arguments to extract config path or data
|
|
72
|
+
* 2. Load and validate: Load config file(s) and validate using Standard Schema
|
|
34
73
|
* 3. Second pass: Parse arguments again with config data as annotations
|
|
35
74
|
*
|
|
36
75
|
* The priority order for values is: CLI > config file > default.
|
|
@@ -40,13 +79,13 @@ interface RunWithConfigOptions<TValue> {
|
|
|
40
79
|
* @template TState The parser state type.
|
|
41
80
|
* @template T The config data type.
|
|
42
81
|
* @param parser The parser to execute.
|
|
43
|
-
* @param context The config context with schema
|
|
44
|
-
* @param options Run options
|
|
82
|
+
* @param context The config context with schema.
|
|
83
|
+
* @param options Run options - either SingleFileOptions or CustomLoadOptions.
|
|
45
84
|
* @returns Promise that resolves to the parsed result.
|
|
46
85
|
* @throws Error if config file validation fails.
|
|
47
86
|
* @since 0.10.0
|
|
48
87
|
*
|
|
49
|
-
* @example
|
|
88
|
+
* @example Single file mode
|
|
50
89
|
* ```typescript
|
|
51
90
|
* import { z } from "zod";
|
|
52
91
|
* import { runWithConfig } from "@optique/config/run";
|
|
@@ -73,7 +112,24 @@ interface RunWithConfigOptions<TValue> {
|
|
|
73
112
|
* args: process.argv.slice(2),
|
|
74
113
|
* });
|
|
75
114
|
* ```
|
|
115
|
+
*
|
|
116
|
+
* @example Custom load mode (multi-file merging)
|
|
117
|
+
* ```typescript
|
|
118
|
+
* import { deepMerge } from "es-toolkit";
|
|
119
|
+
*
|
|
120
|
+
* const result = await runWithConfig(parser, context, {
|
|
121
|
+
* load: async (parsed) => {
|
|
122
|
+
* const configs = await Promise.all([
|
|
123
|
+
* loadToml("/etc/app/config.toml").catch(() => ({})),
|
|
124
|
+
* loadToml("~/.config/app/config.toml").catch(() => ({})),
|
|
125
|
+
* loadToml("./.app.toml").catch(() => ({})),
|
|
126
|
+
* ]);
|
|
127
|
+
* return deepMerge(...configs);
|
|
128
|
+
* },
|
|
129
|
+
* args: process.argv.slice(2),
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
76
132
|
*/
|
|
77
133
|
declare function runWithConfig<M extends "sync" | "async", TValue, TState, T>(parser: Parser<M, TValue, TState>, context: ConfigContext<T>, options: RunWithConfigOptions<TValue>): Promise<TValue>;
|
|
78
134
|
//#endregion
|
|
79
|
-
export { RunWithConfigOptions, runWithConfig };
|
|
135
|
+
export { CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
|
package/dist/run.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { ConfigContext } from "./index-
|
|
1
|
+
import { ConfigContext } from "./index-D_lTcz4s.js";
|
|
2
2
|
import { Parser } from "@optique/core/parser";
|
|
3
3
|
|
|
4
4
|
//#region src/run.d.ts
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
* Options for
|
|
7
|
+
* Options for single-file config loading.
|
|
8
8
|
*
|
|
9
9
|
* @template TValue The parser value type, inferred from the parser.
|
|
10
10
|
* @since 0.10.0
|
|
11
11
|
*/
|
|
12
|
-
interface
|
|
12
|
+
interface SingleFileOptions<TValue> {
|
|
13
13
|
/**
|
|
14
14
|
* Function to extract the config file path from parsed CLI arguments.
|
|
15
15
|
* This function receives the result of the first parse pass and should
|
|
@@ -19,18 +19,57 @@ interface RunWithConfigOptions<TValue> {
|
|
|
19
19
|
* providing full type safety without manual type assertions.
|
|
20
20
|
*/
|
|
21
21
|
readonly getConfigPath: (parsed: TValue) => string | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Custom parser function for reading config file contents.
|
|
24
|
+
* If not provided, defaults to JSON.parse.
|
|
25
|
+
*
|
|
26
|
+
* @param contents The raw file contents as Uint8Array.
|
|
27
|
+
* @returns The parsed config data (will be validated by schema).
|
|
28
|
+
*/
|
|
29
|
+
readonly fileParser?: (contents: Uint8Array) => unknown;
|
|
30
|
+
/**
|
|
31
|
+
* Command-line arguments to parse.
|
|
32
|
+
* If not provided, defaults to an empty array.
|
|
33
|
+
*/
|
|
34
|
+
readonly args?: readonly string[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Options for custom config loading with multi-file merging support.
|
|
38
|
+
*
|
|
39
|
+
* @template TValue The parser value type, inferred from the parser.
|
|
40
|
+
* @since 0.10.0
|
|
41
|
+
*/
|
|
42
|
+
interface CustomLoadOptions<TValue> {
|
|
43
|
+
/**
|
|
44
|
+
* Custom loader function that receives the first-pass parse result and
|
|
45
|
+
* returns the config data (or a Promise of it). This allows full control
|
|
46
|
+
* over file discovery, loading, merging, and error handling.
|
|
47
|
+
*
|
|
48
|
+
* The returned data will be validated against the schema.
|
|
49
|
+
*
|
|
50
|
+
* @param parsed The result from the first parse pass.
|
|
51
|
+
* @returns The raw config data (will be validated by schema).
|
|
52
|
+
*/
|
|
53
|
+
readonly load: (parsed: TValue) => Promise<unknown> | unknown;
|
|
22
54
|
/**
|
|
23
55
|
* Command-line arguments to parse.
|
|
24
56
|
* If not provided, defaults to an empty array.
|
|
25
57
|
*/
|
|
26
58
|
readonly args?: readonly string[];
|
|
27
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Options for runWithConfig.
|
|
62
|
+
*
|
|
63
|
+
* @template TValue The parser value type, inferred from the parser.
|
|
64
|
+
* @since 0.10.0
|
|
65
|
+
*/
|
|
66
|
+
type RunWithConfigOptions<TValue> = SingleFileOptions<TValue> | CustomLoadOptions<TValue>;
|
|
28
67
|
/**
|
|
29
68
|
* Runs a parser with configuration file support using two-pass parsing.
|
|
30
69
|
*
|
|
31
70
|
* This function performs the following steps:
|
|
32
|
-
* 1. First pass: Parse arguments to extract
|
|
33
|
-
* 2. Load and validate:
|
|
71
|
+
* 1. First pass: Parse arguments to extract config path or data
|
|
72
|
+
* 2. Load and validate: Load config file(s) and validate using Standard Schema
|
|
34
73
|
* 3. Second pass: Parse arguments again with config data as annotations
|
|
35
74
|
*
|
|
36
75
|
* The priority order for values is: CLI > config file > default.
|
|
@@ -40,13 +79,13 @@ interface RunWithConfigOptions<TValue> {
|
|
|
40
79
|
* @template TState The parser state type.
|
|
41
80
|
* @template T The config data type.
|
|
42
81
|
* @param parser The parser to execute.
|
|
43
|
-
* @param context The config context with schema
|
|
44
|
-
* @param options Run options
|
|
82
|
+
* @param context The config context with schema.
|
|
83
|
+
* @param options Run options - either SingleFileOptions or CustomLoadOptions.
|
|
45
84
|
* @returns Promise that resolves to the parsed result.
|
|
46
85
|
* @throws Error if config file validation fails.
|
|
47
86
|
* @since 0.10.0
|
|
48
87
|
*
|
|
49
|
-
* @example
|
|
88
|
+
* @example Single file mode
|
|
50
89
|
* ```typescript
|
|
51
90
|
* import { z } from "zod";
|
|
52
91
|
* import { runWithConfig } from "@optique/config/run";
|
|
@@ -73,7 +112,24 @@ interface RunWithConfigOptions<TValue> {
|
|
|
73
112
|
* args: process.argv.slice(2),
|
|
74
113
|
* });
|
|
75
114
|
* ```
|
|
115
|
+
*
|
|
116
|
+
* @example Custom load mode (multi-file merging)
|
|
117
|
+
* ```typescript
|
|
118
|
+
* import { deepMerge } from "es-toolkit";
|
|
119
|
+
*
|
|
120
|
+
* const result = await runWithConfig(parser, context, {
|
|
121
|
+
* load: async (parsed) => {
|
|
122
|
+
* const configs = await Promise.all([
|
|
123
|
+
* loadToml("/etc/app/config.toml").catch(() => ({})),
|
|
124
|
+
* loadToml("~/.config/app/config.toml").catch(() => ({})),
|
|
125
|
+
* loadToml("./.app.toml").catch(() => ({})),
|
|
126
|
+
* ]);
|
|
127
|
+
* return deepMerge(...configs);
|
|
128
|
+
* },
|
|
129
|
+
* args: process.argv.slice(2),
|
|
130
|
+
* });
|
|
131
|
+
* ```
|
|
76
132
|
*/
|
|
77
133
|
declare function runWithConfig<M extends "sync" | "async", TValue, TState, T>(parser: Parser<M, TValue, TState>, context: ConfigContext<T>, options: RunWithConfigOptions<TValue>): Promise<TValue>;
|
|
78
134
|
//#endregion
|
|
79
|
-
export { RunWithConfigOptions, runWithConfig };
|
|
135
|
+
export { CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
|
package/dist/run.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { clearActiveConfig, configKey, setActiveConfig } from "./src-
|
|
1
|
+
import { clearActiveConfig, configKey, setActiveConfig } from "./src-C9h3sfAM.js";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { parse } from "@optique/core/parser";
|
|
4
4
|
|
|
@@ -7,8 +7,8 @@ import { parse } from "@optique/core/parser";
|
|
|
7
7
|
* Runs a parser with configuration file support using two-pass parsing.
|
|
8
8
|
*
|
|
9
9
|
* This function performs the following steps:
|
|
10
|
-
* 1. First pass: Parse arguments to extract
|
|
11
|
-
* 2. Load and validate:
|
|
10
|
+
* 1. First pass: Parse arguments to extract config path or data
|
|
11
|
+
* 2. Load and validate: Load config file(s) and validate using Standard Schema
|
|
12
12
|
* 3. Second pass: Parse arguments again with config data as annotations
|
|
13
13
|
*
|
|
14
14
|
* The priority order for values is: CLI > config file > default.
|
|
@@ -18,13 +18,13 @@ import { parse } from "@optique/core/parser";
|
|
|
18
18
|
* @template TState The parser state type.
|
|
19
19
|
* @template T The config data type.
|
|
20
20
|
* @param parser The parser to execute.
|
|
21
|
-
* @param context The config context with schema
|
|
22
|
-
* @param options Run options
|
|
21
|
+
* @param context The config context with schema.
|
|
22
|
+
* @param options Run options - either SingleFileOptions or CustomLoadOptions.
|
|
23
23
|
* @returns Promise that resolves to the parsed result.
|
|
24
24
|
* @throws Error if config file validation fails.
|
|
25
25
|
* @since 0.10.0
|
|
26
26
|
*
|
|
27
|
-
* @example
|
|
27
|
+
* @example Single file mode
|
|
28
28
|
* ```typescript
|
|
29
29
|
* import { z } from "zod";
|
|
30
30
|
* import { runWithConfig } from "@optique/config/run";
|
|
@@ -51,6 +51,23 @@ import { parse } from "@optique/core/parser";
|
|
|
51
51
|
* args: process.argv.slice(2),
|
|
52
52
|
* });
|
|
53
53
|
* ```
|
|
54
|
+
*
|
|
55
|
+
* @example Custom load mode (multi-file merging)
|
|
56
|
+
* ```typescript
|
|
57
|
+
* import { deepMerge } from "es-toolkit";
|
|
58
|
+
*
|
|
59
|
+
* const result = await runWithConfig(parser, context, {
|
|
60
|
+
* load: async (parsed) => {
|
|
61
|
+
* const configs = await Promise.all([
|
|
62
|
+
* loadToml("/etc/app/config.toml").catch(() => ({})),
|
|
63
|
+
* loadToml("~/.config/app/config.toml").catch(() => ({})),
|
|
64
|
+
* loadToml("./.app.toml").catch(() => ({})),
|
|
65
|
+
* ]);
|
|
66
|
+
* return deepMerge(...configs);
|
|
67
|
+
* },
|
|
68
|
+
* args: process.argv.slice(2),
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
54
71
|
*/
|
|
55
72
|
async function runWithConfig(parser, context, options) {
|
|
56
73
|
const args = options.args ?? [];
|
|
@@ -73,28 +90,48 @@ async function runWithConfig(parser, context, options) {
|
|
|
73
90
|
});
|
|
74
91
|
throw new Error(`Parsing failed: ${errorParts.join("")}`);
|
|
75
92
|
}
|
|
76
|
-
const configPath = options.getConfigPath(firstPassResult.value);
|
|
77
93
|
let configData;
|
|
78
|
-
if (
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
94
|
+
if ("load" in options) {
|
|
95
|
+
const customOptions = options;
|
|
96
|
+
try {
|
|
97
|
+
const rawData = await Promise.resolve(customOptions.load(firstPassResult.value));
|
|
98
|
+
const validation = context.schema["~standard"].validate(rawData);
|
|
99
|
+
let validationResult;
|
|
100
|
+
if (validation instanceof Promise) validationResult = await validation;
|
|
101
|
+
else validationResult = validation;
|
|
102
|
+
if (validationResult.issues) {
|
|
103
|
+
const firstIssue = validationResult.issues[0];
|
|
104
|
+
throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
|
|
105
|
+
}
|
|
106
|
+
configData = validationResult.value;
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
109
|
+
throw error;
|
|
85
110
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
111
|
+
} else {
|
|
112
|
+
const singleFileOptions = options;
|
|
113
|
+
const configPath = singleFileOptions.getConfigPath(firstPassResult.value);
|
|
114
|
+
if (configPath) try {
|
|
115
|
+
const contents = await readFile(configPath);
|
|
116
|
+
let rawData;
|
|
117
|
+
if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
|
|
118
|
+
else {
|
|
119
|
+
const text = new TextDecoder().decode(contents);
|
|
120
|
+
rawData = JSON.parse(text);
|
|
121
|
+
}
|
|
122
|
+
const validation = context.schema["~standard"].validate(rawData);
|
|
123
|
+
let validationResult;
|
|
124
|
+
if (validation instanceof Promise) validationResult = await validation;
|
|
125
|
+
else validationResult = validation;
|
|
126
|
+
if (validationResult.issues) {
|
|
127
|
+
const firstIssue = validationResult.issues[0];
|
|
128
|
+
throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
|
|
129
|
+
}
|
|
130
|
+
configData = validationResult.value;
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
133
|
+
configData = void 0;
|
|
93
134
|
}
|
|
94
|
-
configData = validationResult.value;
|
|
95
|
-
} catch (error) {
|
|
96
|
-
if (error instanceof Error && error.message.includes("validation")) throw error;
|
|
97
|
-
configData = void 0;
|
|
98
135
|
}
|
|
99
136
|
const annotations = configData ? { [configKey]: configData } : {};
|
|
100
137
|
if (configData) setActiveConfig(context.id, configData);
|