@optique/config 1.0.0-dev.427 → 1.0.0-dev.429

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.
@@ -9,6 +9,26 @@ import { Parser } from "@optique/core/parser";
9
9
  * @since 0.10.0
10
10
  */
11
11
  declare const configKey: unique symbol;
12
+ /**
13
+ * Unique symbol for config metadata in annotations.
14
+ * @since 1.0.0
15
+ */
16
+ declare const configMetaKey: unique symbol;
17
+ /**
18
+ * Metadata about the loaded config source.
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ interface ConfigMeta {
23
+ /**
24
+ * Directory containing the config file.
25
+ */
26
+ readonly configDir: string;
27
+ /**
28
+ * Absolute path to the config file.
29
+ */
30
+ readonly configPath: string;
31
+ }
12
32
  /**
13
33
  * Sets active config data for a context.
14
34
  * @internal
@@ -24,6 +44,21 @@ declare function getActiveConfig<T>(contextId: symbol): T | undefined;
24
44
  * @internal
25
45
  */
26
46
  declare function clearActiveConfig(contextId: symbol): void;
47
+ /**
48
+ * Sets active config metadata for a context.
49
+ * @internal
50
+ */
51
+ declare function setActiveConfigMeta<T>(contextId: symbol, meta: T): void;
52
+ /**
53
+ * Gets active config metadata for a context.
54
+ * @internal
55
+ */
56
+ declare function getActiveConfigMeta<T>(contextId: symbol): T | undefined;
57
+ /**
58
+ * Clears active config metadata for a context.
59
+ * @internal
60
+ */
61
+ declare function clearActiveConfigMeta(contextId: symbol): void;
27
62
  /**
28
63
  * Options for creating a config context.
29
64
  *
@@ -64,7 +99,7 @@ interface ConfigContextRequiredOptions {
64
99
  * @template T The validated config data type.
65
100
  * @since 0.10.0
66
101
  */
67
- interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
102
+ interface ConfigContext<T, TConfigMeta = ConfigMeta> extends SourceContext<ConfigContextRequiredOptions> {
68
103
  /**
69
104
  * The Standard Schema validator for the config file.
70
105
  */
@@ -77,6 +112,7 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
77
112
  * with runWith() or runWithConfig() to provide configuration file support.
78
113
  *
79
114
  * @template T The output type of the config schema.
115
+ * @template TConfigMeta The metadata type for config sources.
80
116
  * @param options Configuration options including schema and optional parser.
81
117
  * @returns A config context that can be used with bindConfig() and runWithConfig().
82
118
  * @since 0.10.0
@@ -94,7 +130,7 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
94
130
  * const configContext = createConfigContext({ schema });
95
131
  * ```
96
132
  */
97
- declare function createConfigContext<T>(options: ConfigContextOptions<T>): ConfigContext<T>;
133
+ declare function createConfigContext<T, TConfigMeta = ConfigMeta>(options: ConfigContextOptions<T>): ConfigContext<T, TConfigMeta>;
98
134
  /**
99
135
  * Options for binding a parser to config values.
100
136
  *
@@ -102,17 +138,18 @@ declare function createConfigContext<T>(options: ConfigContextOptions<T>): Confi
102
138
  * @template TValue The value type extracted from config.
103
139
  * @since 0.10.0
104
140
  */
105
- interface BindConfigOptions<T, TValue> {
141
+ interface BindConfigOptions<T, TValue, TConfigMeta = ConfigMeta> {
106
142
  /**
107
143
  * The config context to use for fallback values.
108
144
  */
109
- readonly context: ConfigContext<T>;
145
+ readonly context: ConfigContext<T, TConfigMeta>;
110
146
  /**
111
147
  * Key or accessor function to extract the value from config.
112
148
  * Can be a property key (for top-level config values) or a function
113
- * that extracts nested values.
149
+ * that extracts nested values. Accessor callbacks receive config metadata
150
+ * as the second argument.
114
151
  */
115
- readonly key: keyof T | ((config: T) => TValue);
152
+ readonly key: keyof T | ((config: T, meta: TConfigMeta) => TValue);
116
153
  /**
117
154
  * Default value to use when neither CLI nor config provides a value.
118
155
  * If not specified, the parser will fail when no value is available.
@@ -150,6 +187,6 @@ interface BindConfigOptions<T, TValue> {
150
187
  * });
151
188
  * ```
152
189
  */
153
- declare function bindConfig<M extends "sync" | "async", TValue, TState, T>(parser: Parser<M, TValue, TState>, options: BindConfigOptions<T, TValue>): Parser<M, TValue, TState>;
190
+ declare function bindConfig<M extends "sync" | "async", TValue, TState, T, TConfigMeta = ConfigMeta>(parser: Parser<M, TValue, TState>, options: BindConfigOptions<T, TValue, TConfigMeta>): Parser<M, TValue, TState>;
154
191
  //#endregion
155
- export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
192
+ export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
@@ -9,6 +9,26 @@ import { Parser } from "@optique/core/parser";
9
9
  * @since 0.10.0
10
10
  */
11
11
  declare const configKey: unique symbol;
12
+ /**
13
+ * Unique symbol for config metadata in annotations.
14
+ * @since 1.0.0
15
+ */
16
+ declare const configMetaKey: unique symbol;
17
+ /**
18
+ * Metadata about the loaded config source.
19
+ *
20
+ * @since 1.0.0
21
+ */
22
+ interface ConfigMeta {
23
+ /**
24
+ * Directory containing the config file.
25
+ */
26
+ readonly configDir: string;
27
+ /**
28
+ * Absolute path to the config file.
29
+ */
30
+ readonly configPath: string;
31
+ }
12
32
  /**
13
33
  * Sets active config data for a context.
14
34
  * @internal
@@ -24,6 +44,21 @@ declare function getActiveConfig<T>(contextId: symbol): T | undefined;
24
44
  * @internal
25
45
  */
26
46
  declare function clearActiveConfig(contextId: symbol): void;
47
+ /**
48
+ * Sets active config metadata for a context.
49
+ * @internal
50
+ */
51
+ declare function setActiveConfigMeta<T>(contextId: symbol, meta: T): void;
52
+ /**
53
+ * Gets active config metadata for a context.
54
+ * @internal
55
+ */
56
+ declare function getActiveConfigMeta<T>(contextId: symbol): T | undefined;
57
+ /**
58
+ * Clears active config metadata for a context.
59
+ * @internal
60
+ */
61
+ declare function clearActiveConfigMeta(contextId: symbol): void;
27
62
  /**
28
63
  * Options for creating a config context.
29
64
  *
@@ -64,7 +99,7 @@ interface ConfigContextRequiredOptions {
64
99
  * @template T The validated config data type.
65
100
  * @since 0.10.0
66
101
  */
67
- interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
102
+ interface ConfigContext<T, TConfigMeta = ConfigMeta> extends SourceContext<ConfigContextRequiredOptions> {
68
103
  /**
69
104
  * The Standard Schema validator for the config file.
70
105
  */
@@ -77,6 +112,7 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
77
112
  * with runWith() or runWithConfig() to provide configuration file support.
78
113
  *
79
114
  * @template T The output type of the config schema.
115
+ * @template TConfigMeta The metadata type for config sources.
80
116
  * @param options Configuration options including schema and optional parser.
81
117
  * @returns A config context that can be used with bindConfig() and runWithConfig().
82
118
  * @since 0.10.0
@@ -94,7 +130,7 @@ interface ConfigContext<T> extends SourceContext<ConfigContextRequiredOptions> {
94
130
  * const configContext = createConfigContext({ schema });
95
131
  * ```
96
132
  */
97
- declare function createConfigContext<T>(options: ConfigContextOptions<T>): ConfigContext<T>;
133
+ declare function createConfigContext<T, TConfigMeta = ConfigMeta>(options: ConfigContextOptions<T>): ConfigContext<T, TConfigMeta>;
98
134
  /**
99
135
  * Options for binding a parser to config values.
100
136
  *
@@ -102,17 +138,18 @@ declare function createConfigContext<T>(options: ConfigContextOptions<T>): Confi
102
138
  * @template TValue The value type extracted from config.
103
139
  * @since 0.10.0
104
140
  */
105
- interface BindConfigOptions<T, TValue> {
141
+ interface BindConfigOptions<T, TValue, TConfigMeta = ConfigMeta> {
106
142
  /**
107
143
  * The config context to use for fallback values.
108
144
  */
109
- readonly context: ConfigContext<T>;
145
+ readonly context: ConfigContext<T, TConfigMeta>;
110
146
  /**
111
147
  * Key or accessor function to extract the value from config.
112
148
  * Can be a property key (for top-level config values) or a function
113
- * that extracts nested values.
149
+ * that extracts nested values. Accessor callbacks receive config metadata
150
+ * as the second argument.
114
151
  */
115
- readonly key: keyof T | ((config: T) => TValue);
152
+ readonly key: keyof T | ((config: T, meta: TConfigMeta) => TValue);
116
153
  /**
117
154
  * Default value to use when neither CLI nor config provides a value.
118
155
  * If not specified, the parser will fail when no value is available.
@@ -150,6 +187,6 @@ interface BindConfigOptions<T, TValue> {
150
187
  * });
151
188
  * ```
152
189
  */
153
- declare function bindConfig<M extends "sync" | "async", TValue, TState, T>(parser: Parser<M, TValue, TState>, options: BindConfigOptions<T, TValue>): Parser<M, TValue, TState>;
190
+ declare function bindConfig<M extends "sync" | "async", TValue, TState, T, TConfigMeta = ConfigMeta>(parser: Parser<M, TValue, TState>, options: BindConfigOptions<T, TValue, TConfigMeta>): Parser<M, TValue, TState>;
154
191
  //#endregion
155
- export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
192
+ export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
package/dist/index.cjs CHANGED
@@ -1,8 +1,12 @@
1
- const require_src = require('./src-9MkUoh9z.cjs');
1
+ const require_src = require('./src-loxvrkxq.cjs');
2
2
 
3
3
  exports.bindConfig = require_src.bindConfig;
4
4
  exports.clearActiveConfig = require_src.clearActiveConfig;
5
+ exports.clearActiveConfigMeta = require_src.clearActiveConfigMeta;
5
6
  exports.configKey = require_src.configKey;
7
+ exports.configMetaKey = require_src.configMetaKey;
6
8
  exports.createConfigContext = require_src.createConfigContext;
7
9
  exports.getActiveConfig = require_src.getActiveConfig;
8
- exports.setActiveConfig = require_src.setActiveConfig;
10
+ exports.getActiveConfigMeta = require_src.getActiveConfigMeta;
11
+ exports.setActiveConfig = require_src.setActiveConfig;
12
+ exports.setActiveConfigMeta = require_src.setActiveConfigMeta;
package/dist/index.d.cts CHANGED
@@ -1,2 +1,2 @@
1
- import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-D25zYfjf.cjs";
2
- export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
1
+ import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta } from "./index-BZLEbR0f.cjs";
2
+ export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./index-CYn_0yAG.js";
2
- export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
1
+ import { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta } from "./index-0XaZnIP1.js";
2
+ export { BindConfigOptions, ConfigContext, ConfigContextOptions, ConfigContextRequiredOptions, ConfigMeta, bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- import { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig } from "./src-Dm_17c1d.js";
1
+ import { bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta } from "./src-DaFxoeAp.js";
2
2
 
3
- export { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
3
+ export { bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
package/dist/run.cjs CHANGED
@@ -1,4 +1,4 @@
1
- const require_src = require('./src-9MkUoh9z.cjs');
1
+ const require_src = require('./src-loxvrkxq.cjs');
2
2
  const node_fs_promises = require_src.__toESM(require("node:fs/promises"));
3
3
  const node_path = require_src.__toESM(require("node:path"));
4
4
  const node_process = require_src.__toESM(require("node:process"));
@@ -18,132 +18,69 @@ function createConfigSourceContext(context, options) {
18
18
  async getAnnotations(parsed) {
19
19
  if (!parsed) return {};
20
20
  let configData;
21
+ let configMeta;
21
22
  if ("load" in options) {
22
23
  const customOptions = options;
23
- try {
24
- const rawData = await Promise.resolve(customOptions.load(parsed));
25
- const validation = context.schema["~standard"].validate(rawData);
26
- let validationResult;
27
- if (validation instanceof Promise) validationResult = await validation;
28
- else validationResult = validation;
29
- if (validationResult.issues) {
30
- const firstIssue = validationResult.issues[0];
31
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
32
- }
33
- configData = validationResult.value;
34
- } catch (error) {
35
- if (error instanceof Error && error.message.includes("validation")) throw error;
36
- throw error;
24
+ const loaded = await Promise.resolve(customOptions.load(parsed));
25
+ const validation = context.schema["~standard"].validate(loaded.config);
26
+ let validationResult;
27
+ if (validation instanceof Promise) validationResult = await validation;
28
+ else validationResult = validation;
29
+ if (validationResult.issues) {
30
+ const firstIssue = validationResult.issues[0];
31
+ throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
37
32
  }
33
+ configData = validationResult.value;
34
+ configMeta = loaded.meta;
38
35
  } else {
39
36
  const singleFileOptions = options;
40
37
  const configPath = singleFileOptions.getConfigPath(parsed);
41
- if (configPath) try {
42
- const contents = await (0, node_fs_promises.readFile)(configPath);
43
- let rawData;
44
- if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
45
- else {
46
- const text = new TextDecoder().decode(contents);
47
- rawData = JSON.parse(text);
48
- }
49
- const validation = context.schema["~standard"].validate(rawData);
50
- let validationResult;
51
- if (validation instanceof Promise) validationResult = await validation;
52
- else validationResult = validation;
53
- if (validationResult.issues) {
54
- const firstIssue = validationResult.issues[0];
55
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
38
+ if (configPath) {
39
+ const absoluteConfigPath = (0, node_path.resolve)(configPath);
40
+ const singleFileMeta = {
41
+ configDir: (0, node_path.dirname)(absoluteConfigPath),
42
+ configPath: absoluteConfigPath
43
+ };
44
+ try {
45
+ const contents = await (0, node_fs_promises.readFile)(absoluteConfigPath);
46
+ let rawData;
47
+ if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
48
+ else {
49
+ const text = new TextDecoder().decode(contents);
50
+ rawData = JSON.parse(text);
51
+ }
52
+ const validation = context.schema["~standard"].validate(rawData);
53
+ let validationResult;
54
+ if (validation instanceof Promise) validationResult = await validation;
55
+ else validationResult = validation;
56
+ if (validationResult.issues) {
57
+ const firstIssue = validationResult.issues[0];
58
+ throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
59
+ }
60
+ configData = validationResult.value;
61
+ configMeta = singleFileMeta;
62
+ } catch (error) {
63
+ if (isErrnoException(error) && error.code === "ENOENT") configData = void 0;
64
+ else if (error instanceof SyntaxError) throw new Error(`Failed to parse config file ${absoluteConfigPath}: ${error.message}`);
65
+ else throw error;
56
66
  }
57
- configData = validationResult.value;
58
- } catch (error) {
59
- if (isErrnoException(error) && error.code === "ENOENT") configData = void 0;
60
- else if (error instanceof SyntaxError) throw new Error(`Failed to parse config file ${configPath}: ${error.message}`);
61
- else throw error;
62
67
  }
63
68
  }
64
69
  if (configData !== void 0 && configData !== null) {
65
70
  require_src.setActiveConfig(context.id, configData);
71
+ if (configMeta !== void 0) {
72
+ require_src.setActiveConfigMeta(context.id, configMeta);
73
+ return {
74
+ [require_src.configKey]: configData,
75
+ [require_src.configMetaKey]: configMeta
76
+ };
77
+ }
66
78
  return { [require_src.configKey]: configData };
67
79
  }
68
80
  return {};
69
81
  }
70
82
  };
71
83
  }
72
- /**
73
- * Runs a parser with configuration file support using two-pass parsing.
74
- *
75
- * This function performs the following steps:
76
- * 1. First pass: Parse arguments to extract config path or data
77
- * 2. Load and validate: Load config file(s) and validate using Standard Schema
78
- * 3. Second pass: Parse arguments again with config data as annotations
79
- *
80
- * The priority order for values is: CLI > config file > default.
81
- *
82
- * The function also supports help, version, and completion features. When these
83
- * special commands are detected, config loading is skipped entirely, ensuring
84
- * these features work even when config files don't exist.
85
- *
86
- * @template M The parser mode (sync or async).
87
- * @template TValue The parser value type.
88
- * @template TState The parser state type.
89
- * @template T The config data type.
90
- * @template THelp The return type when help is shown.
91
- * @template TError The return type when an error occurs.
92
- * @param parser The parser to execute.
93
- * @param context The config context with schema.
94
- * @param options Run options - either SingleFileOptions or CustomLoadOptions.
95
- * @returns Promise that resolves to the parsed result.
96
- * @throws Error if config file validation fails.
97
- * @since 0.10.0
98
- *
99
- * @example Single file mode
100
- * ```typescript
101
- * import { z } from "zod";
102
- * import { runWithConfig } from "@optique/config/run";
103
- * import { createConfigContext, bindConfig } from "@optique/config";
104
- *
105
- * const schema = z.object({
106
- * host: z.string(),
107
- * port: z.number(),
108
- * });
109
- *
110
- * const context = createConfigContext({ schema });
111
- *
112
- * const parser = object({
113
- * config: option("--config", string()),
114
- * host: bindConfig(option("--host", string()), {
115
- * context,
116
- * key: "host",
117
- * default: "localhost",
118
- * }),
119
- * });
120
- *
121
- * const result = await runWithConfig(parser, context, {
122
- * getConfigPath: (parsed) => parsed.config,
123
- * args: process.argv.slice(2),
124
- * help: { mode: "option", onShow: () => process.exit(0) },
125
- * version: { value: "1.0.0", onShow: () => process.exit(0) },
126
- * });
127
- * ```
128
- *
129
- * @example Custom load mode (multi-file merging)
130
- * ```typescript
131
- * import { deepMerge } from "es-toolkit";
132
- *
133
- * const result = await runWithConfig(parser, context, {
134
- * load: async (parsed) => {
135
- * const configs = await Promise.all([
136
- * loadToml("/etc/app/config.toml").catch(() => ({})),
137
- * loadToml("~/.config/app/config.toml").catch(() => ({})),
138
- * loadToml("./.app.toml").catch(() => ({})),
139
- * ]);
140
- * return deepMerge(...configs);
141
- * },
142
- * args: process.argv.slice(2),
143
- * help: { mode: "option", onShow: () => process.exit(0) },
144
- * });
145
- * ```
146
- */
147
84
  async function runWithConfig(parser, context, options) {
148
85
  const effectiveProgramName = options.programName ?? (typeof node_process.default !== "undefined" && node_process.default.argv?.[1] ? (0, node_path.basename)(node_process.default.argv[1]) : "cli");
149
86
  const wrapperContext = createConfigSourceContext(context, options);
@@ -182,6 +119,7 @@ async function runWithConfig(parser, context, options) {
182
119
  throw error;
183
120
  } finally {
184
121
  require_src.clearActiveConfig(context.id);
122
+ require_src.clearActiveConfigMeta(context.id);
185
123
  }
186
124
  }
187
125
 
package/dist/run.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigContext } from "./index-D25zYfjf.cjs";
1
+ import { ConfigContext, ConfigMeta } from "./index-BZLEbR0f.cjs";
2
2
  import { Parser } from "@optique/core/parser";
3
3
  import { RunOptions } from "@optique/core/facade";
4
4
 
@@ -109,6 +109,22 @@ interface SingleFileOptions<TValue, THelp = void, TError = never> {
109
109
  */
110
110
  readonly onError?: RunOptions<THelp, TError>["onError"];
111
111
  }
112
+ /**
113
+ * Result type for custom config loading.
114
+ *
115
+ * @template TConfigMeta Metadata type associated with loaded config data.
116
+ * @since 1.0.0
117
+ */
118
+ interface ConfigLoadResult<TConfigMeta = ConfigMeta> {
119
+ /**
120
+ * Raw config data to validate against the schema.
121
+ */
122
+ readonly config: unknown;
123
+ /**
124
+ * Metadata about where the config came from.
125
+ */
126
+ readonly meta: TConfigMeta;
127
+ }
112
128
  /**
113
129
  * Options for custom config loading with multi-file merging support.
114
130
  *
@@ -117,7 +133,7 @@ interface SingleFileOptions<TValue, THelp = void, TError = never> {
117
133
  * @template TError The return type when an error occurs.
118
134
  * @since 0.10.0
119
135
  */
120
- interface CustomLoadOptions<TValue, THelp = void, TError = never> {
136
+ interface CustomLoadOptions<TValue, TConfigMeta = ConfigMeta, THelp = void, TError = never> {
121
137
  /**
122
138
  * Custom loader function that receives the first-pass parse result and
123
139
  * returns the config data (or a Promise of it). This allows full control
@@ -126,9 +142,9 @@ interface CustomLoadOptions<TValue, THelp = void, TError = never> {
126
142
  * The returned data will be validated against the schema.
127
143
  *
128
144
  * @param parsed The result from the first parse pass.
129
- * @returns The raw config data (will be validated by schema).
145
+ * @returns Config data and metadata (config is validated by schema).
130
146
  */
131
- readonly load: (parsed: TValue) => Promise<unknown> | unknown;
147
+ readonly load: (parsed: TValue) => Promise<ConfigLoadResult<TConfigMeta>> | ConfigLoadResult<TConfigMeta>;
132
148
  /**
133
149
  * Command-line arguments to parse.
134
150
  * If not provided, defaults to an empty array.
@@ -216,7 +232,7 @@ interface CustomLoadOptions<TValue, THelp = void, TError = never> {
216
232
  * @template TError The return type when an error occurs.
217
233
  * @since 0.10.0
218
234
  */
219
- type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOptions<TValue, THelp, TError> | CustomLoadOptions<TValue, THelp, TError>;
235
+ type RunWithConfigOptions<TValue, TConfigMeta = ConfigMeta, THelp = void, TError = never> = SingleFileOptions<TValue, THelp, TError> | CustomLoadOptions<TValue, TConfigMeta, THelp, TError>;
220
236
  /**
221
237
  * Runs a parser with configuration file support using two-pass parsing.
222
238
  *
@@ -235,6 +251,7 @@ type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOpti
235
251
  * @template TValue The parser value type.
236
252
  * @template TState The parser state type.
237
253
  * @template T The config data type.
254
+ * @template TConfigMeta The config metadata type.
238
255
  * @template THelp The return type when help is shown.
239
256
  * @template TError The return type when an error occurs.
240
257
  * @param parser The parser to execute.
@@ -285,13 +302,22 @@ type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOpti
285
302
  * loadToml("~/.config/app/config.toml").catch(() => ({})),
286
303
  * loadToml("./.app.toml").catch(() => ({})),
287
304
  * ]);
288
- * return deepMerge(...configs);
305
+ *
306
+ * const configPath = parsed.config ?? "./.app.toml";
307
+ * return {
308
+ * config: deepMerge(...configs),
309
+ * meta: {
310
+ * configPath,
311
+ * configDir: configPath.slice(0, configPath.lastIndexOf("/")),
312
+ * },
313
+ * };
289
314
  * },
290
315
  * args: process.argv.slice(2),
291
316
  * help: { mode: "option", onShow: () => process.exit(0) },
292
317
  * });
293
318
  * ```
294
319
  */
295
- declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T>, options: RunWithConfigOptions<TValue, THelp, TError>): Promise<TValue>;
320
+ declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T, ConfigMeta>, options: SingleFileOptions<TValue, THelp, TError>): Promise<TValue>;
321
+ declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, TConfigMeta = ConfigMeta, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T, TConfigMeta>, options: CustomLoadOptions<TValue, TConfigMeta, THelp, TError>): Promise<TValue>;
296
322
  //#endregion
297
- export { CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
323
+ export { ConfigLoadResult, CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
package/dist/run.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ConfigContext } from "./index-CYn_0yAG.js";
1
+ import { ConfigContext, ConfigMeta } from "./index-0XaZnIP1.js";
2
2
  import { RunOptions } from "@optique/core/facade";
3
3
  import { Parser } from "@optique/core/parser";
4
4
 
@@ -109,6 +109,22 @@ interface SingleFileOptions<TValue, THelp = void, TError = never> {
109
109
  */
110
110
  readonly onError?: RunOptions<THelp, TError>["onError"];
111
111
  }
112
+ /**
113
+ * Result type for custom config loading.
114
+ *
115
+ * @template TConfigMeta Metadata type associated with loaded config data.
116
+ * @since 1.0.0
117
+ */
118
+ interface ConfigLoadResult<TConfigMeta = ConfigMeta> {
119
+ /**
120
+ * Raw config data to validate against the schema.
121
+ */
122
+ readonly config: unknown;
123
+ /**
124
+ * Metadata about where the config came from.
125
+ */
126
+ readonly meta: TConfigMeta;
127
+ }
112
128
  /**
113
129
  * Options for custom config loading with multi-file merging support.
114
130
  *
@@ -117,7 +133,7 @@ interface SingleFileOptions<TValue, THelp = void, TError = never> {
117
133
  * @template TError The return type when an error occurs.
118
134
  * @since 0.10.0
119
135
  */
120
- interface CustomLoadOptions<TValue, THelp = void, TError = never> {
136
+ interface CustomLoadOptions<TValue, TConfigMeta = ConfigMeta, THelp = void, TError = never> {
121
137
  /**
122
138
  * Custom loader function that receives the first-pass parse result and
123
139
  * returns the config data (or a Promise of it). This allows full control
@@ -126,9 +142,9 @@ interface CustomLoadOptions<TValue, THelp = void, TError = never> {
126
142
  * The returned data will be validated against the schema.
127
143
  *
128
144
  * @param parsed The result from the first parse pass.
129
- * @returns The raw config data (will be validated by schema).
145
+ * @returns Config data and metadata (config is validated by schema).
130
146
  */
131
- readonly load: (parsed: TValue) => Promise<unknown> | unknown;
147
+ readonly load: (parsed: TValue) => Promise<ConfigLoadResult<TConfigMeta>> | ConfigLoadResult<TConfigMeta>;
132
148
  /**
133
149
  * Command-line arguments to parse.
134
150
  * If not provided, defaults to an empty array.
@@ -216,7 +232,7 @@ interface CustomLoadOptions<TValue, THelp = void, TError = never> {
216
232
  * @template TError The return type when an error occurs.
217
233
  * @since 0.10.0
218
234
  */
219
- type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOptions<TValue, THelp, TError> | CustomLoadOptions<TValue, THelp, TError>;
235
+ type RunWithConfigOptions<TValue, TConfigMeta = ConfigMeta, THelp = void, TError = never> = SingleFileOptions<TValue, THelp, TError> | CustomLoadOptions<TValue, TConfigMeta, THelp, TError>;
220
236
  /**
221
237
  * Runs a parser with configuration file support using two-pass parsing.
222
238
  *
@@ -235,6 +251,7 @@ type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOpti
235
251
  * @template TValue The parser value type.
236
252
  * @template TState The parser state type.
237
253
  * @template T The config data type.
254
+ * @template TConfigMeta The config metadata type.
238
255
  * @template THelp The return type when help is shown.
239
256
  * @template TError The return type when an error occurs.
240
257
  * @param parser The parser to execute.
@@ -285,13 +302,22 @@ type RunWithConfigOptions<TValue, THelp = void, TError = never> = SingleFileOpti
285
302
  * loadToml("~/.config/app/config.toml").catch(() => ({})),
286
303
  * loadToml("./.app.toml").catch(() => ({})),
287
304
  * ]);
288
- * return deepMerge(...configs);
305
+ *
306
+ * const configPath = parsed.config ?? "./.app.toml";
307
+ * return {
308
+ * config: deepMerge(...configs),
309
+ * meta: {
310
+ * configPath,
311
+ * configDir: configPath.slice(0, configPath.lastIndexOf("/")),
312
+ * },
313
+ * };
289
314
  * },
290
315
  * args: process.argv.slice(2),
291
316
  * help: { mode: "option", onShow: () => process.exit(0) },
292
317
  * });
293
318
  * ```
294
319
  */
295
- declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T>, options: RunWithConfigOptions<TValue, THelp, TError>): Promise<TValue>;
320
+ declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T, ConfigMeta>, options: SingleFileOptions<TValue, THelp, TError>): Promise<TValue>;
321
+ declare function runWithConfig<M extends "sync" | "async", TValue, TState, T, TConfigMeta = ConfigMeta, THelp = void, TError = never>(parser: Parser<M, TValue, TState>, context: ConfigContext<T, TConfigMeta>, options: CustomLoadOptions<TValue, TConfigMeta, THelp, TError>): Promise<TValue>;
296
322
  //#endregion
297
- export { CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
323
+ export { ConfigLoadResult, CustomLoadOptions, RunWithConfigOptions, SingleFileOptions, runWithConfig };
package/dist/run.js CHANGED
@@ -1,6 +1,6 @@
1
- import { clearActiveConfig, configKey, setActiveConfig } from "./src-Dm_17c1d.js";
1
+ import { clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, setActiveConfig, setActiveConfigMeta } from "./src-DaFxoeAp.js";
2
2
  import { readFile } from "node:fs/promises";
3
- import { basename } from "node:path";
3
+ import { basename, dirname, resolve } from "node:path";
4
4
  import process from "node:process";
5
5
  import { runWith } from "@optique/core/facade";
6
6
 
@@ -18,132 +18,69 @@ function createConfigSourceContext(context, options) {
18
18
  async getAnnotations(parsed) {
19
19
  if (!parsed) return {};
20
20
  let configData;
21
+ let configMeta;
21
22
  if ("load" in options) {
22
23
  const customOptions = options;
23
- try {
24
- const rawData = await Promise.resolve(customOptions.load(parsed));
25
- const validation = context.schema["~standard"].validate(rawData);
26
- let validationResult;
27
- if (validation instanceof Promise) validationResult = await validation;
28
- else validationResult = validation;
29
- if (validationResult.issues) {
30
- const firstIssue = validationResult.issues[0];
31
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
32
- }
33
- configData = validationResult.value;
34
- } catch (error) {
35
- if (error instanceof Error && error.message.includes("validation")) throw error;
36
- throw error;
24
+ const loaded = await Promise.resolve(customOptions.load(parsed));
25
+ const validation = context.schema["~standard"].validate(loaded.config);
26
+ let validationResult;
27
+ if (validation instanceof Promise) validationResult = await validation;
28
+ else validationResult = validation;
29
+ if (validationResult.issues) {
30
+ const firstIssue = validationResult.issues[0];
31
+ throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
37
32
  }
33
+ configData = validationResult.value;
34
+ configMeta = loaded.meta;
38
35
  } else {
39
36
  const singleFileOptions = options;
40
37
  const configPath = singleFileOptions.getConfigPath(parsed);
41
- if (configPath) try {
42
- const contents = await readFile(configPath);
43
- let rawData;
44
- if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
45
- else {
46
- const text = new TextDecoder().decode(contents);
47
- rawData = JSON.parse(text);
48
- }
49
- const validation = context.schema["~standard"].validate(rawData);
50
- let validationResult;
51
- if (validation instanceof Promise) validationResult = await validation;
52
- else validationResult = validation;
53
- if (validationResult.issues) {
54
- const firstIssue = validationResult.issues[0];
55
- throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
38
+ if (configPath) {
39
+ const absoluteConfigPath = resolve(configPath);
40
+ const singleFileMeta = {
41
+ configDir: dirname(absoluteConfigPath),
42
+ configPath: absoluteConfigPath
43
+ };
44
+ try {
45
+ const contents = await readFile(absoluteConfigPath);
46
+ let rawData;
47
+ if (singleFileOptions.fileParser) rawData = singleFileOptions.fileParser(contents);
48
+ else {
49
+ const text = new TextDecoder().decode(contents);
50
+ rawData = JSON.parse(text);
51
+ }
52
+ const validation = context.schema["~standard"].validate(rawData);
53
+ let validationResult;
54
+ if (validation instanceof Promise) validationResult = await validation;
55
+ else validationResult = validation;
56
+ if (validationResult.issues) {
57
+ const firstIssue = validationResult.issues[0];
58
+ throw new Error(`Config validation failed: ${firstIssue?.message ?? "Unknown error"}`);
59
+ }
60
+ configData = validationResult.value;
61
+ configMeta = singleFileMeta;
62
+ } catch (error) {
63
+ if (isErrnoException(error) && error.code === "ENOENT") configData = void 0;
64
+ else if (error instanceof SyntaxError) throw new Error(`Failed to parse config file ${absoluteConfigPath}: ${error.message}`);
65
+ else throw error;
56
66
  }
57
- configData = validationResult.value;
58
- } catch (error) {
59
- if (isErrnoException(error) && error.code === "ENOENT") configData = void 0;
60
- else if (error instanceof SyntaxError) throw new Error(`Failed to parse config file ${configPath}: ${error.message}`);
61
- else throw error;
62
67
  }
63
68
  }
64
69
  if (configData !== void 0 && configData !== null) {
65
70
  setActiveConfig(context.id, configData);
71
+ if (configMeta !== void 0) {
72
+ setActiveConfigMeta(context.id, configMeta);
73
+ return {
74
+ [configKey]: configData,
75
+ [configMetaKey]: configMeta
76
+ };
77
+ }
66
78
  return { [configKey]: configData };
67
79
  }
68
80
  return {};
69
81
  }
70
82
  };
71
83
  }
72
- /**
73
- * Runs a parser with configuration file support using two-pass parsing.
74
- *
75
- * This function performs the following steps:
76
- * 1. First pass: Parse arguments to extract config path or data
77
- * 2. Load and validate: Load config file(s) and validate using Standard Schema
78
- * 3. Second pass: Parse arguments again with config data as annotations
79
- *
80
- * The priority order for values is: CLI > config file > default.
81
- *
82
- * The function also supports help, version, and completion features. When these
83
- * special commands are detected, config loading is skipped entirely, ensuring
84
- * these features work even when config files don't exist.
85
- *
86
- * @template M The parser mode (sync or async).
87
- * @template TValue The parser value type.
88
- * @template TState The parser state type.
89
- * @template T The config data type.
90
- * @template THelp The return type when help is shown.
91
- * @template TError The return type when an error occurs.
92
- * @param parser The parser to execute.
93
- * @param context The config context with schema.
94
- * @param options Run options - either SingleFileOptions or CustomLoadOptions.
95
- * @returns Promise that resolves to the parsed result.
96
- * @throws Error if config file validation fails.
97
- * @since 0.10.0
98
- *
99
- * @example Single file mode
100
- * ```typescript
101
- * import { z } from "zod";
102
- * import { runWithConfig } from "@optique/config/run";
103
- * import { createConfigContext, bindConfig } from "@optique/config";
104
- *
105
- * const schema = z.object({
106
- * host: z.string(),
107
- * port: z.number(),
108
- * });
109
- *
110
- * const context = createConfigContext({ schema });
111
- *
112
- * const parser = object({
113
- * config: option("--config", string()),
114
- * host: bindConfig(option("--host", string()), {
115
- * context,
116
- * key: "host",
117
- * default: "localhost",
118
- * }),
119
- * });
120
- *
121
- * const result = await runWithConfig(parser, context, {
122
- * getConfigPath: (parsed) => parsed.config,
123
- * args: process.argv.slice(2),
124
- * help: { mode: "option", onShow: () => process.exit(0) },
125
- * version: { value: "1.0.0", onShow: () => process.exit(0) },
126
- * });
127
- * ```
128
- *
129
- * @example Custom load mode (multi-file merging)
130
- * ```typescript
131
- * import { deepMerge } from "es-toolkit";
132
- *
133
- * const result = await runWithConfig(parser, context, {
134
- * load: async (parsed) => {
135
- * const configs = await Promise.all([
136
- * loadToml("/etc/app/config.toml").catch(() => ({})),
137
- * loadToml("~/.config/app/config.toml").catch(() => ({})),
138
- * loadToml("./.app.toml").catch(() => ({})),
139
- * ]);
140
- * return deepMerge(...configs);
141
- * },
142
- * args: process.argv.slice(2),
143
- * help: { mode: "option", onShow: () => process.exit(0) },
144
- * });
145
- * ```
146
- */
147
84
  async function runWithConfig(parser, context, options) {
148
85
  const effectiveProgramName = options.programName ?? (typeof process !== "undefined" && process.argv?.[1] ? basename(process.argv[1]) : "cli");
149
86
  const wrapperContext = createConfigSourceContext(context, options);
@@ -182,6 +119,7 @@ async function runWithConfig(parser, context, options) {
182
119
  throw error;
183
120
  } finally {
184
121
  clearActiveConfig(context.id);
122
+ clearActiveConfigMeta(context.id);
185
123
  }
186
124
  }
187
125
 
@@ -8,6 +8,11 @@ import { message } from "@optique/core/message";
8
8
  */
9
9
  const configKey = Symbol.for("@optique/config");
10
10
  /**
11
+ * Unique symbol for config metadata in annotations.
12
+ * @since 1.0.0
13
+ */
14
+ const configMetaKey = Symbol.for("@optique/config/meta");
15
+ /**
11
16
  * Internal registry for active config data during runWithConfig execution.
12
17
  * This is a workaround for the limitation that object() doesn't propagate
13
18
  * annotations to child field parsers.
@@ -15,6 +20,11 @@ const configKey = Symbol.for("@optique/config");
15
20
  */
16
21
  const activeConfigRegistry = /* @__PURE__ */ new Map();
17
22
  /**
23
+ * Internal registry for active config metadata during runWithConfig execution.
24
+ * @internal
25
+ */
26
+ const activeConfigMetaRegistry = /* @__PURE__ */ new Map();
27
+ /**
18
28
  * Sets active config data for a context.
19
29
  * @internal
20
30
  */
@@ -36,12 +46,34 @@ function clearActiveConfig(contextId) {
36
46
  activeConfigRegistry.delete(contextId);
37
47
  }
38
48
  /**
49
+ * Sets active config metadata for a context.
50
+ * @internal
51
+ */
52
+ function setActiveConfigMeta(contextId, meta) {
53
+ activeConfigMetaRegistry.set(contextId, meta);
54
+ }
55
+ /**
56
+ * Gets active config metadata for a context.
57
+ * @internal
58
+ */
59
+ function getActiveConfigMeta(contextId) {
60
+ return activeConfigMetaRegistry.get(contextId);
61
+ }
62
+ /**
63
+ * Clears active config metadata for a context.
64
+ * @internal
65
+ */
66
+ function clearActiveConfigMeta(contextId) {
67
+ activeConfigMetaRegistry.delete(contextId);
68
+ }
69
+ /**
39
70
  * Creates a config context for use with Optique parsers.
40
71
  *
41
72
  * The config context implements the SourceContext interface and can be used
42
73
  * with runWith() or runWithConfig() to provide configuration file support.
43
74
  *
44
75
  * @template T The output type of the config schema.
76
+ * @template TConfigMeta The metadata type for config sources.
45
77
  * @param options Configuration options including schema and optional parser.
46
78
  * @returns A config context that can be used with bindConfig() and runWithConfig().
47
79
  * @since 0.10.0
@@ -208,13 +240,15 @@ function bindConfig(parser, options) {
208
240
  function getConfigOrDefault(state, options) {
209
241
  const annotations = getAnnotations(state);
210
242
  let configData = annotations?.[configKey];
243
+ let configMeta = annotations?.[configMetaKey];
211
244
  if (configData === void 0 || configData === null) {
212
245
  const contextId = options.context.id;
213
246
  configData = getActiveConfig(contextId);
247
+ configMeta = getActiveConfigMeta(contextId);
214
248
  }
215
249
  let configValue;
216
250
  if (configData !== void 0 && configData !== null) if (typeof options.key === "function") try {
217
- configValue = options.key(configData);
251
+ configValue = options.key(configData, configMeta);
218
252
  } catch {
219
253
  configValue = void 0;
220
254
  }
@@ -234,4 +268,4 @@ function getConfigOrDefault(state, options) {
234
268
  }
235
269
 
236
270
  //#endregion
237
- export { bindConfig, clearActiveConfig, configKey, createConfigContext, getActiveConfig, setActiveConfig };
271
+ export { bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };
@@ -31,6 +31,11 @@ const __optique_core_message = __toESM(require("@optique/core/message"));
31
31
  */
32
32
  const configKey = Symbol.for("@optique/config");
33
33
  /**
34
+ * Unique symbol for config metadata in annotations.
35
+ * @since 1.0.0
36
+ */
37
+ const configMetaKey = Symbol.for("@optique/config/meta");
38
+ /**
34
39
  * Internal registry for active config data during runWithConfig execution.
35
40
  * This is a workaround for the limitation that object() doesn't propagate
36
41
  * annotations to child field parsers.
@@ -38,6 +43,11 @@ const configKey = Symbol.for("@optique/config");
38
43
  */
39
44
  const activeConfigRegistry = /* @__PURE__ */ new Map();
40
45
  /**
46
+ * Internal registry for active config metadata during runWithConfig execution.
47
+ * @internal
48
+ */
49
+ const activeConfigMetaRegistry = /* @__PURE__ */ new Map();
50
+ /**
41
51
  * Sets active config data for a context.
42
52
  * @internal
43
53
  */
@@ -59,12 +69,34 @@ function clearActiveConfig(contextId) {
59
69
  activeConfigRegistry.delete(contextId);
60
70
  }
61
71
  /**
72
+ * Sets active config metadata for a context.
73
+ * @internal
74
+ */
75
+ function setActiveConfigMeta(contextId, meta) {
76
+ activeConfigMetaRegistry.set(contextId, meta);
77
+ }
78
+ /**
79
+ * Gets active config metadata for a context.
80
+ * @internal
81
+ */
82
+ function getActiveConfigMeta(contextId) {
83
+ return activeConfigMetaRegistry.get(contextId);
84
+ }
85
+ /**
86
+ * Clears active config metadata for a context.
87
+ * @internal
88
+ */
89
+ function clearActiveConfigMeta(contextId) {
90
+ activeConfigMetaRegistry.delete(contextId);
91
+ }
92
+ /**
62
93
  * Creates a config context for use with Optique parsers.
63
94
  *
64
95
  * The config context implements the SourceContext interface and can be used
65
96
  * with runWith() or runWithConfig() to provide configuration file support.
66
97
  *
67
98
  * @template T The output type of the config schema.
99
+ * @template TConfigMeta The metadata type for config sources.
68
100
  * @param options Configuration options including schema and optional parser.
69
101
  * @returns A config context that can be used with bindConfig() and runWithConfig().
70
102
  * @since 0.10.0
@@ -231,13 +263,15 @@ function bindConfig(parser, options) {
231
263
  function getConfigOrDefault(state, options) {
232
264
  const annotations = (0, __optique_core_annotations.getAnnotations)(state);
233
265
  let configData = annotations?.[configKey];
266
+ let configMeta = annotations?.[configMetaKey];
234
267
  if (configData === void 0 || configData === null) {
235
268
  const contextId = options.context.id;
236
269
  configData = getActiveConfig(contextId);
270
+ configMeta = getActiveConfigMeta(contextId);
237
271
  }
238
272
  let configValue;
239
273
  if (configData !== void 0 && configData !== null) if (typeof options.key === "function") try {
240
- configValue = options.key(configData);
274
+ configValue = options.key(configData, configMeta);
241
275
  } catch {
242
276
  configValue = void 0;
243
277
  }
@@ -275,12 +309,24 @@ Object.defineProperty(exports, 'clearActiveConfig', {
275
309
  return clearActiveConfig;
276
310
  }
277
311
  });
312
+ Object.defineProperty(exports, 'clearActiveConfigMeta', {
313
+ enumerable: true,
314
+ get: function () {
315
+ return clearActiveConfigMeta;
316
+ }
317
+ });
278
318
  Object.defineProperty(exports, 'configKey', {
279
319
  enumerable: true,
280
320
  get: function () {
281
321
  return configKey;
282
322
  }
283
323
  });
324
+ Object.defineProperty(exports, 'configMetaKey', {
325
+ enumerable: true,
326
+ get: function () {
327
+ return configMetaKey;
328
+ }
329
+ });
284
330
  Object.defineProperty(exports, 'createConfigContext', {
285
331
  enumerable: true,
286
332
  get: function () {
@@ -293,9 +339,21 @@ Object.defineProperty(exports, 'getActiveConfig', {
293
339
  return getActiveConfig;
294
340
  }
295
341
  });
342
+ Object.defineProperty(exports, 'getActiveConfigMeta', {
343
+ enumerable: true,
344
+ get: function () {
345
+ return getActiveConfigMeta;
346
+ }
347
+ });
296
348
  Object.defineProperty(exports, 'setActiveConfig', {
297
349
  enumerable: true,
298
350
  get: function () {
299
351
  return setActiveConfig;
300
352
  }
353
+ });
354
+ Object.defineProperty(exports, 'setActiveConfigMeta', {
355
+ enumerable: true,
356
+ get: function () {
357
+ return setActiveConfigMeta;
358
+ }
301
359
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optique/config",
3
- "version": "1.0.0-dev.427+497e26fe",
3
+ "version": "1.0.0-dev.429+66edc8ed",
4
4
  "description": "Configuration file support for Optique with Standard Schema validation",
5
5
  "keywords": [
6
6
  "CLI",
@@ -67,7 +67,7 @@
67
67
  "@standard-schema/spec": "^1.1.0"
68
68
  },
69
69
  "dependencies": {
70
- "@optique/core": "1.0.0-dev.427+497e26fe"
70
+ "@optique/core": "1.0.0-dev.429+66edc8ed"
71
71
  },
72
72
  "devDependencies": {
73
73
  "@standard-schema/spec": "^1.1.0",