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

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/run.js DELETED
@@ -1,127 +0,0 @@
1
- import { clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, setActiveConfig, setActiveConfigMeta } from "./src-DaFxoeAp.js";
2
- import { readFile } from "node:fs/promises";
3
- import { basename, dirname, resolve } from "node:path";
4
- import process from "node:process";
5
- import { runWith } from "@optique/core/facade";
6
-
7
- //#region src/run.ts
8
- function isErrnoException(error) {
9
- return typeof error === "object" && error !== null && "code" in error;
10
- }
11
- /**
12
- * Helper function to create a wrapper SourceContext for config loading.
13
- * @internal
14
- */
15
- function createConfigSourceContext(context, options) {
16
- return {
17
- id: context.id,
18
- async getAnnotations(parsed) {
19
- if (!parsed) return {};
20
- let configData;
21
- let configMeta;
22
- if ("load" in options) {
23
- const customOptions = options;
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"}`);
32
- }
33
- configData = validationResult.value;
34
- configMeta = loaded.meta;
35
- } else {
36
- const singleFileOptions = options;
37
- const configPath = singleFileOptions.getConfigPath(parsed);
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;
66
- }
67
- }
68
- }
69
- if (configData !== void 0 && configData !== null) {
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
- }
78
- return { [configKey]: configData };
79
- }
80
- return {};
81
- }
82
- };
83
- }
84
- async function runWithConfig(parser, context, options) {
85
- const effectiveProgramName = options.programName ?? (typeof process !== "undefined" && process.argv?.[1] ? basename(process.argv[1]) : "cli");
86
- const wrapperContext = createConfigSourceContext(context, options);
87
- try {
88
- return await runWith(parser, effectiveProgramName, [wrapperContext], {
89
- args: options.args ?? [],
90
- help: options.help,
91
- version: options.version,
92
- completion: options.completion,
93
- stdout: options.stdout,
94
- stderr: options.stderr,
95
- colors: options.colors,
96
- maxWidth: options.maxWidth,
97
- showDefault: options.showDefault,
98
- showChoices: options.showChoices,
99
- aboveError: options.aboveError,
100
- brief: options.brief,
101
- description: options.description,
102
- examples: options.examples,
103
- author: options.author,
104
- bugs: options.bugs,
105
- footer: options.footer,
106
- onError: options.onError
107
- });
108
- } catch (error) {
109
- if (error instanceof Error && error.message.startsWith("Failed to parse config file ")) {
110
- const stderr = options.stderr ?? console.error;
111
- stderr(`Error: ${error.message}`);
112
- if (options.onError) try {
113
- options.onError(1);
114
- } catch {
115
- options.onError();
116
- }
117
- throw error;
118
- }
119
- throw error;
120
- } finally {
121
- clearActiveConfig(context.id);
122
- clearActiveConfigMeta(context.id);
123
- }
124
- }
125
-
126
- //#endregion
127
- export { runWithConfig };
@@ -1,271 +0,0 @@
1
- import { annotationKey, getAnnotations } from "@optique/core/annotations";
2
- import { message } from "@optique/core/message";
3
-
4
- //#region src/index.ts
5
- /**
6
- * Unique symbol for config data in annotations.
7
- * @since 0.10.0
8
- */
9
- const configKey = Symbol.for("@optique/config");
10
- /**
11
- * Unique symbol for config metadata in annotations.
12
- * @since 1.0.0
13
- */
14
- const configMetaKey = Symbol.for("@optique/config/meta");
15
- /**
16
- * Internal registry for active config data during runWithConfig execution.
17
- * This is a workaround for the limitation that object() doesn't propagate
18
- * annotations to child field parsers.
19
- * @internal
20
- */
21
- const activeConfigRegistry = /* @__PURE__ */ new Map();
22
- /**
23
- * Internal registry for active config metadata during runWithConfig execution.
24
- * @internal
25
- */
26
- const activeConfigMetaRegistry = /* @__PURE__ */ new Map();
27
- /**
28
- * Sets active config data for a context.
29
- * @internal
30
- */
31
- function setActiveConfig(contextId, data) {
32
- activeConfigRegistry.set(contextId, data);
33
- }
34
- /**
35
- * Gets active config data for a context.
36
- * @internal
37
- */
38
- function getActiveConfig(contextId) {
39
- return activeConfigRegistry.get(contextId);
40
- }
41
- /**
42
- * Clears active config data for a context.
43
- * @internal
44
- */
45
- function clearActiveConfig(contextId) {
46
- activeConfigRegistry.delete(contextId);
47
- }
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
- /**
70
- * Creates a config context for use with Optique parsers.
71
- *
72
- * The config context implements the SourceContext interface and can be used
73
- * with runWith() or runWithConfig() to provide configuration file support.
74
- *
75
- * @template T The output type of the config schema.
76
- * @template TConfigMeta The metadata type for config sources.
77
- * @param options Configuration options including schema and optional parser.
78
- * @returns A config context that can be used with bindConfig() and runWithConfig().
79
- * @since 0.10.0
80
- *
81
- * @example
82
- * ```typescript
83
- * import { z } from "zod";
84
- * import { createConfigContext } from "@optique/config";
85
- *
86
- * const schema = z.object({
87
- * host: z.string(),
88
- * port: z.number(),
89
- * });
90
- *
91
- * const configContext = createConfigContext({ schema });
92
- * ```
93
- */
94
- function createConfigContext(options) {
95
- const contextId = Symbol.for(`@optique/config:${Math.random()}`);
96
- return {
97
- id: contextId,
98
- schema: options.schema,
99
- getAnnotations(parsed) {
100
- if (!parsed) return {};
101
- return {};
102
- }
103
- };
104
- }
105
- /**
106
- * Binds a parser to configuration values with fallback priority.
107
- *
108
- * The binding implements the following priority order:
109
- * 1. CLI argument (if provided)
110
- * 2. Config file value (if available)
111
- * 3. Default value (if specified)
112
- * 4. Error (if none of the above)
113
- *
114
- * @template M The parser mode (sync or async).
115
- * @template TValue The parser value type.
116
- * @template TState The parser state type.
117
- * @template T The config data type.
118
- * @param parser The parser to bind to config values.
119
- * @param options Binding options including context, key, and default.
120
- * @returns A new parser with config fallback behavior.
121
- * @since 0.10.0
122
- *
123
- * @example
124
- * ```typescript
125
- * import { bindConfig } from "@optique/config";
126
- * import { option } from "@optique/core/primitives";
127
- * import { string } from "@optique/core/valueparser";
128
- *
129
- * const hostParser = bindConfig(option("--host", string()), {
130
- * context: configContext,
131
- * key: "host",
132
- * default: "localhost",
133
- * });
134
- * ```
135
- */
136
- function bindConfig(parser, options) {
137
- return {
138
- $mode: parser.$mode,
139
- $valueType: parser.$valueType,
140
- $stateType: parser.$stateType,
141
- priority: parser.priority,
142
- usage: options.default !== void 0 ? [{
143
- type: "optional",
144
- terms: parser.usage
145
- }] : parser.usage,
146
- initialState: parser.initialState,
147
- parse: (context) => {
148
- const annotations = getAnnotations(context.state);
149
- const result = parser.parse(context);
150
- if (!(result instanceof Promise)) {
151
- if (result.success) {
152
- const newState$1 = {
153
- hasCliValue: true,
154
- cliState: result.next.state,
155
- ...annotations && { [annotationKey]: annotations }
156
- };
157
- return {
158
- success: true,
159
- next: {
160
- ...result.next,
161
- state: newState$1
162
- },
163
- consumed: result.consumed
164
- };
165
- }
166
- const newState = {
167
- hasCliValue: false,
168
- ...annotations && { [annotationKey]: annotations }
169
- };
170
- return {
171
- success: true,
172
- next: {
173
- ...context,
174
- state: newState
175
- },
176
- consumed: []
177
- };
178
- }
179
- return result.then((res) => {
180
- if (res.success) {
181
- const newState$1 = {
182
- hasCliValue: true,
183
- cliState: res.next.state,
184
- ...annotations && { [annotationKey]: annotations }
185
- };
186
- return {
187
- success: true,
188
- next: {
189
- ...res.next,
190
- state: newState$1
191
- },
192
- consumed: res.consumed
193
- };
194
- }
195
- const newState = {
196
- hasCliValue: false,
197
- ...annotations && { [annotationKey]: annotations }
198
- };
199
- return {
200
- success: true,
201
- next: {
202
- ...context,
203
- state: newState
204
- },
205
- consumed: []
206
- };
207
- });
208
- },
209
- complete: (state) => {
210
- const bindState = state;
211
- if (bindState?.hasCliValue && bindState.cliState !== void 0) {
212
- const innerResult = parser.complete(bindState.cliState);
213
- if (innerResult instanceof Promise) return innerResult.then((res) => {
214
- if (res.success) return {
215
- success: true,
216
- value: res.value
217
- };
218
- return res;
219
- });
220
- if (innerResult.success) return {
221
- success: true,
222
- value: innerResult.value
223
- };
224
- return innerResult;
225
- }
226
- return getConfigOrDefault(state, options);
227
- },
228
- suggest: parser.suggest,
229
- getDocFragments(state, upperDefaultValue) {
230
- const defaultValue = upperDefaultValue ?? options.default;
231
- return parser.getDocFragments(state, defaultValue);
232
- }
233
- };
234
- }
235
- /**
236
- * Helper function to get value from config or default.
237
- * Checks both annotations (for top-level parsers) and the active config
238
- * registry (for parsers nested inside object() when used with runWithConfig).
239
- */
240
- function getConfigOrDefault(state, options) {
241
- const annotations = getAnnotations(state);
242
- let configData = annotations?.[configKey];
243
- let configMeta = annotations?.[configMetaKey];
244
- if (configData === void 0 || configData === null) {
245
- const contextId = options.context.id;
246
- configData = getActiveConfig(contextId);
247
- configMeta = getActiveConfigMeta(contextId);
248
- }
249
- let configValue;
250
- if (configData !== void 0 && configData !== null) if (typeof options.key === "function") try {
251
- configValue = options.key(configData, configMeta);
252
- } catch {
253
- configValue = void 0;
254
- }
255
- else configValue = configData[options.key];
256
- if (configValue !== void 0) return {
257
- success: true,
258
- value: configValue
259
- };
260
- if (options.default !== void 0) return {
261
- success: true,
262
- value: options.default
263
- };
264
- return {
265
- success: false,
266
- error: message`Missing required configuration value.`
267
- };
268
- }
269
-
270
- //#endregion
271
- export { bindConfig, clearActiveConfig, clearActiveConfigMeta, configKey, configMetaKey, createConfigContext, getActiveConfig, getActiveConfigMeta, setActiveConfig, setActiveConfigMeta };