@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.
@@ -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
@@ -1,4 +1,4 @@
1
- const require_src = require('./src-DVH5fJU9.cjs');
1
+ const require_src = require('./src-CTH1AjFs.cjs');
2
2
 
3
3
  exports.bindConfig = require_src.bindConfig;
4
4
  exports.clearActiveConfig = require_src.clearActiveConfig;
package/dist/index.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-CZZEDay7.cjs";
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-DiDpcijz.js";
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-iXO5MxwN.js";
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-DVH5fJU9.cjs');
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 the config file path
11
- * 2. Load and validate: Read the config file and validate using Standard Schema
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 and optional custom parser.
22
- * @param options Run options including getConfigPath and args.
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 (configPath) try {
79
- const contents = await (0, node_fs_promises.readFile)(configPath);
80
- let rawData;
81
- if (context.parser) rawData = context.parser(contents);
82
- else {
83
- const text = new TextDecoder().decode(contents);
84
- rawData = JSON.parse(text);
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
- const validation = context.schema["~standard"].validate(rawData);
87
- let validationResult;
88
- if (validation instanceof Promise) validationResult = await validation;
89
- else validationResult = validation;
90
- if (validationResult.issues) {
91
- const firstIssue = validationResult.issues[0];
92
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
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-CZZEDay7.cjs";
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 runWithConfig.
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 RunWithConfigOptions<TValue> {
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 the config file path
33
- * 2. Load and validate: Read the config file and validate using Standard Schema
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 and optional custom parser.
44
- * @param options Run options including getConfigPath and args.
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-DiDpcijz.js";
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 runWithConfig.
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 RunWithConfigOptions<TValue> {
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 the config file path
33
- * 2. Load and validate: Read the config file and validate using Standard Schema
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 and optional custom parser.
44
- * @param options Run options including getConfigPath and args.
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-iXO5MxwN.js";
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 the config file path
11
- * 2. Load and validate: Read the config file and validate using Standard Schema
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 and optional custom parser.
22
- * @param options Run options including getConfigPath and args.
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 (configPath) try {
79
- const contents = await readFile(configPath);
80
- let rawData;
81
- if (context.parser) rawData = context.parser(contents);
82
- else {
83
- const text = new TextDecoder().decode(contents);
84
- rawData = JSON.parse(text);
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
- const validation = context.schema["~standard"].validate(rawData);
87
- let validationResult;
88
- if (validation instanceof Promise) validationResult = await validation;
89
- else validationResult = validation;
90
- if (validationResult.issues) {
91
- const firstIssue = validationResult.issues[0];
92
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
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);
@@ -63,7 +63,6 @@ function createConfigContext(options) {
63
63
  return {
64
64
  id: configKey,
65
65
  schema: options.schema,
66
- parser: options.parser,
67
66
  getAnnotations(parsed) {
68
67
  if (!parsed) return {};
69
68
  return {};
@@ -86,7 +86,6 @@ function createConfigContext(options) {
86
86
  return {
87
87
  id: configKey,
88
88
  schema: options.schema,
89
- parser: options.parser,
90
89
  getAnnotations(parsed) {
91
90
  if (!parsed) return {};
92
91
  return {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/config",
3
- "version": "0.10.0-dev.335+bfcb880a",
3
+ "version": "0.10.0-dev.342+b6648cfd",
4
4
  "description": "Configuration file support for Optique with Standard Schema validation",
5
5
  "keywords": [
6
6
  "CLI",