scenv 0.8.0 → 1.0.0
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/README.md +2 -2
- package/dist/index.cjs +17 -17
- package/dist/index.d.cts +44 -23
- package/dist/index.d.ts +44 -23
- package/dist/index.js +17 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -42,13 +42,13 @@ await apiUrl.save(); // write current value to a context file
|
|
|
42
42
|
|
|
43
43
|
Any string value matching **`@<context>:<key>`** (e.g. `@prod:core_server_url`) is resolved from that context file first—in set, env, context, default, and prompts.
|
|
44
44
|
|
|
45
|
-
Prompting
|
|
45
|
+
Prompting is off by default (`prompt: "never"`). To enable it, set config `prompt` to `always`, `fallback`, or `no-env` (via config file, `SCENV_PROMPT`, or `configure()`).
|
|
46
46
|
|
|
47
47
|
## Optional integrations
|
|
48
48
|
|
|
49
49
|
| Package | Purpose |
|
|
50
50
|
| -------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
51
|
-
| [scenv-zod](https://www.npmjs.com/package/scenv-zod) | `
|
|
51
|
+
| [scenv-zod](https://www.npmjs.com/package/scenv-zod) | `parser(zodSchema)` for type-safe parsing and coercion. |
|
|
52
52
|
| [scenv-inquirer](https://www.npmjs.com/package/scenv-inquirer) | `prompt()` and callbacks for interactive prompts. |
|
|
53
53
|
|
|
54
54
|
## Documentation
|
package/dist/index.cjs
CHANGED
|
@@ -477,7 +477,7 @@ function defaultKeyFromName(name) {
|
|
|
477
477
|
function defaultEnvFromKey(key) {
|
|
478
478
|
return key.toUpperCase().replace(/-/g, "_");
|
|
479
479
|
}
|
|
480
|
-
function
|
|
480
|
+
function normalizeParserResult(result) {
|
|
481
481
|
if (typeof result === "boolean") {
|
|
482
482
|
return result ? { success: true } : { success: false };
|
|
483
483
|
}
|
|
@@ -487,7 +487,7 @@ function normalizeValidatorResult(result) {
|
|
|
487
487
|
function scenv(name, options = {}) {
|
|
488
488
|
const key = options.key ?? defaultKeyFromName(name);
|
|
489
489
|
const envKey = options.env ?? defaultEnvFromKey(key);
|
|
490
|
-
const
|
|
490
|
+
const parserFn = options.parser;
|
|
491
491
|
const promptFn = options.prompt;
|
|
492
492
|
const defaultValue = options.default;
|
|
493
493
|
async function resolveRaw() {
|
|
@@ -526,7 +526,7 @@ function scenv(name, options = {}) {
|
|
|
526
526
|
return { raw: void 0, source: void 0 };
|
|
527
527
|
}
|
|
528
528
|
function shouldPrompt(config, hadValue, hadEnv) {
|
|
529
|
-
const mode = config.prompt ?? "
|
|
529
|
+
const mode = config.prompt ?? "never";
|
|
530
530
|
if (mode === "never") return false;
|
|
531
531
|
if (mode === "always") return true;
|
|
532
532
|
if (mode === "fallback") return !hadValue;
|
|
@@ -542,7 +542,7 @@ function scenv(name, options = {}) {
|
|
|
542
542
|
const doPrompt = shouldPrompt(config, hadValue, hadEnv);
|
|
543
543
|
log(
|
|
544
544
|
"debug",
|
|
545
|
-
`prompt decision key=${key} prompt=${config.prompt ?? "
|
|
545
|
+
`prompt decision key=${key} prompt=${config.prompt ?? "never"} hadValue=${hadValue} hadEnv=${hadEnv} -> ${doPrompt ? "prompt" : "no prompt"}`
|
|
546
546
|
);
|
|
547
547
|
const effectiveDefault = overrides?.default !== void 0 ? overrides.default : defaultValue;
|
|
548
548
|
const resolvedDefault = effectiveDefault === void 0 ? void 0 : typeof effectiveDefault === "string" ? resolveContextReference(effectiveDefault, key) : effectiveDefault;
|
|
@@ -574,10 +574,10 @@ function scenv(name, options = {}) {
|
|
|
574
574
|
log("info", `variable "${name}" (key=${key}) resolved from ${resolvedFrom}`);
|
|
575
575
|
return { value, raw, hadEnv, wasPrompted };
|
|
576
576
|
}
|
|
577
|
-
function
|
|
578
|
-
if (!
|
|
579
|
-
const result =
|
|
580
|
-
const normalized =
|
|
577
|
+
function parse(value) {
|
|
578
|
+
if (!parserFn) return { success: true, data: value };
|
|
579
|
+
const result = parserFn(value);
|
|
580
|
+
const normalized = normalizeParserResult(result);
|
|
581
581
|
if (normalized.success) {
|
|
582
582
|
const data = "data" in normalized && normalized.data !== void 0 ? normalized.data : value;
|
|
583
583
|
return { success: true, data };
|
|
@@ -589,13 +589,13 @@ function scenv(name, options = {}) {
|
|
|
589
589
|
}
|
|
590
590
|
async function get(options2) {
|
|
591
591
|
const { value, wasPrompted } = await getResolvedValue(options2);
|
|
592
|
-
const
|
|
593
|
-
if (!
|
|
594
|
-
const errMsg = `
|
|
592
|
+
const parsed = parse(value);
|
|
593
|
+
if (!parsed.success) {
|
|
594
|
+
const errMsg = `Parsing failed for "${name}": ${parsed.error ?? "unknown"}`;
|
|
595
595
|
log("error", errMsg);
|
|
596
596
|
throw new Error(errMsg);
|
|
597
597
|
}
|
|
598
|
-
const final =
|
|
598
|
+
const final = parsed.data;
|
|
599
599
|
const config = loadConfig();
|
|
600
600
|
if (wasPrompted) setInMemoryContext(key, String(final));
|
|
601
601
|
if (config.saveContextTo) {
|
|
@@ -617,16 +617,16 @@ function scenv(name, options = {}) {
|
|
|
617
617
|
}
|
|
618
618
|
async function save(value) {
|
|
619
619
|
const toSave = value ?? (await getResolvedValue()).value;
|
|
620
|
-
const
|
|
621
|
-
if (!
|
|
622
|
-
const errMsg = `
|
|
620
|
+
const parsed = parse(toSave);
|
|
621
|
+
if (!parsed.success) {
|
|
622
|
+
const errMsg = `Parsing failed for "${name}": ${parsed.error ?? "unknown"}`;
|
|
623
623
|
log("error", errMsg);
|
|
624
624
|
throw new Error(errMsg);
|
|
625
625
|
}
|
|
626
626
|
const config = loadConfig();
|
|
627
|
-
setInMemoryContext(key, String(
|
|
627
|
+
setInMemoryContext(key, String(parsed.data));
|
|
628
628
|
if (config.saveContextTo) {
|
|
629
|
-
writeToContext(config.saveContextTo, key, String(
|
|
629
|
+
writeToContext(config.saveContextTo, key, String(parsed.data));
|
|
630
630
|
log("info", `Saved key=${key} to saveContextTo ${config.saveContextTo}`);
|
|
631
631
|
}
|
|
632
632
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -29,7 +29,7 @@ interface ScenvConfig {
|
|
|
29
29
|
context?: string[];
|
|
30
30
|
/** Merge these context names with existing (CLI: `--add-context a,b,c`). Ignored if `context` is set in the same layer. */
|
|
31
31
|
addContext?: string[];
|
|
32
|
-
/** When to prompt for a variable value. See {@link PromptMode}. Default is `"
|
|
32
|
+
/** When to prompt for a variable value. See {@link PromptMode}. Default is `"never"`; set to `always`, `fallback`, or `no-env` to enable prompting (via config file, SCENV_PROMPT, or configure()). */
|
|
33
33
|
prompt?: PromptMode;
|
|
34
34
|
/** If true, environment variables are not used during resolution. */
|
|
35
35
|
ignoreEnv?: boolean;
|
|
@@ -154,18 +154,35 @@ declare function getMergedContextValues(): Record<string, string>;
|
|
|
154
154
|
declare function getContextWritePath(contextName: string): string;
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* Return type for a variable's optional `
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* - `
|
|
157
|
+
* Return type for a variable's optional `parser` function. Input is always the raw string
|
|
158
|
+
* (from set/env/context) or the default. Use a boolean for simple pass/fail, or an object
|
|
159
|
+
* to pass a parsed/transformed value or a custom error.
|
|
160
|
+
* - `true` or `{ success: true, data?: T }` – parsing passed; optional `data` is the output value (type T).
|
|
161
|
+
* - `false` or `{ success: false, error?: unknown }` – parsing failed; `.get()` throws with the error.
|
|
161
162
|
*/
|
|
162
|
-
type
|
|
163
|
+
type ParserResult<T> = boolean | {
|
|
163
164
|
success: true;
|
|
164
165
|
data?: T;
|
|
165
166
|
} | {
|
|
166
167
|
success: false;
|
|
167
168
|
error?: unknown;
|
|
168
169
|
};
|
|
170
|
+
/**
|
|
171
|
+
* Infers the variable's value type (output type) from options: when a parser returns
|
|
172
|
+
* `{ success: true, data: D }`, that D is used; otherwise the type comes from `default` or defaults to string.
|
|
173
|
+
*/
|
|
174
|
+
type InferVariableType<O> = O extends {
|
|
175
|
+
parser: (v: unknown) => infer R;
|
|
176
|
+
} ? R extends {
|
|
177
|
+
success: true;
|
|
178
|
+
data: infer D;
|
|
179
|
+
} ? D extends undefined ? O extends {
|
|
180
|
+
default: infer Def;
|
|
181
|
+
} ? Def : string : D : O extends {
|
|
182
|
+
default: infer Def;
|
|
183
|
+
} ? Def : string : O extends {
|
|
184
|
+
default: infer Def;
|
|
185
|
+
} ? Def : string;
|
|
169
186
|
/**
|
|
170
187
|
* Prompt function signature. Called when config requests prompting for this variable.
|
|
171
188
|
* Receives the variable's display name and the current default (from set/env/context or option default).
|
|
@@ -175,17 +192,18 @@ type PromptFn<T> = (name: string, defaultValue: T) => T | Promise<T>;
|
|
|
175
192
|
/**
|
|
176
193
|
* Options when creating a variable with {@link scenv}. All properties are optional.
|
|
177
194
|
* If you omit `key` and `env`, they are derived from `name`: e.g. "API URL" → key `api_url`, env `API_URL`.
|
|
195
|
+
* Input from set/env/context is always string; `default` and the variable's value type are the output type T.
|
|
178
196
|
*/
|
|
179
|
-
interface ScenvVariableOptions<T> {
|
|
197
|
+
interface ScenvVariableOptions<T = string> {
|
|
180
198
|
/** Internal key for --set, context files, and env. Default: name lowercased, spaces → underscores, non-alphanumeric stripped (e.g. "API URL" → "api_url"). */
|
|
181
199
|
key?: string;
|
|
182
200
|
/** Environment variable name (e.g. API_URL). Default: key uppercased, hyphens → underscores. */
|
|
183
201
|
env?: string;
|
|
184
|
-
/** Fallback when nothing is provided via --set, env, or context (and we're not prompting). */
|
|
202
|
+
/** Fallback when nothing is provided via --set, env, or context (and we're not prompting). Same type T as the variable's output (not parsed). */
|
|
185
203
|
default?: T;
|
|
186
|
-
/** Optional.
|
|
187
|
-
|
|
188
|
-
/** Optional. Called when config
|
|
204
|
+
/** Optional. Parses the raw string (or default) into output type T. Receives raw value (typically string). Return { success: true, data } with the parsed value; variable type is inferred from data. */
|
|
205
|
+
parser?: (val: unknown) => ParserResult<T>;
|
|
206
|
+
/** Optional. Called when config has enabled prompting (e.g. prompt: "fallback" and no value found). Overrides callbacks.defaultPrompt for this variable. */
|
|
189
207
|
prompt?: PromptFn<T>;
|
|
190
208
|
}
|
|
191
209
|
/**
|
|
@@ -204,8 +222,8 @@ interface GetOptions<T> {
|
|
|
204
222
|
*/
|
|
205
223
|
interface ScenvVariable<T> {
|
|
206
224
|
/**
|
|
207
|
-
* Resolve and return the value. Uses resolution order (set > env > context > default) and any prompt/
|
|
208
|
-
* @throws If no value is found and no default/prompt, or if
|
|
225
|
+
* Resolve and return the value. Uses resolution order (set > env > context > default) and any prompt/parser.
|
|
226
|
+
* @throws If no value is found and no default/prompt, or if parsing fails.
|
|
209
227
|
*/
|
|
210
228
|
get(options?: GetOptions<T>): Promise<T>;
|
|
211
229
|
/**
|
|
@@ -236,16 +254,15 @@ interface ScenvVariable<T> {
|
|
|
236
254
|
* - Environment variable (e.g. API_URL for key "api_url")
|
|
237
255
|
* - Context files (merged key-value from the context list in config, e.g. dev.context.json)
|
|
238
256
|
*
|
|
239
|
-
* If
|
|
257
|
+
* If prompting is enabled in config (prompt: "always", "fallback", or "no-env"), the prompt callback
|
|
240
258
|
* may run. When it runs, it receives the variable name and a suggested value (the raw value if any, otherwise
|
|
241
259
|
* the default option). The callback's return value is used as the value. When we don't prompt, we use the
|
|
242
260
|
* raw value if present, otherwise the default option, otherwise get() throws (no value).
|
|
243
261
|
*
|
|
244
|
-
* ##
|
|
262
|
+
* ## Parser
|
|
245
263
|
*
|
|
246
|
-
* If you pass a
|
|
247
|
-
* { success: true }
|
|
248
|
-
* Use it to coerce types (e.g. string to number) or enforce rules.
|
|
264
|
+
* If you pass a parser option, it is called with the raw value (typically string from set/env/context) or the default.
|
|
265
|
+
* Return { success: true, data } with the parsed output; the variable's type is inferred from data. On { success: false }, get() throws.
|
|
249
266
|
*
|
|
250
267
|
* ## save()
|
|
251
268
|
*
|
|
@@ -254,16 +271,20 @@ interface ScenvVariable<T> {
|
|
|
254
271
|
* When the user is prompted during get(), the value is always saved (to saveContextTo file if set, and always to in-memory)
|
|
255
272
|
* so a second get() on the same variable does not prompt again.
|
|
256
273
|
*
|
|
257
|
-
* @typeParam T -
|
|
274
|
+
* @typeParam T - Output (value) type of the variable, e.g. string, number, URL. Defaults to string.
|
|
258
275
|
* @param name - Display name used in prompts and errors. If you omit key/env, key is derived from name (e.g. "API URL" → "api_url") and env from key (e.g. "API_URL").
|
|
259
|
-
* @param options - Optional. key, env, default,
|
|
260
|
-
* @returns A {@link ScenvVariable} with get(), safeGet(), and save().
|
|
276
|
+
* @param options - Optional. key, env, default, parser, prompt. See {@link ScenvVariableOptions}.
|
|
277
|
+
* @returns A {@link ScenvVariable<T>} with get(), safeGet(), and save().
|
|
261
278
|
*
|
|
262
279
|
* @example
|
|
263
280
|
* const apiUrl = scenv("API URL", { default: "http://localhost:4000" });
|
|
264
281
|
* const url = await apiUrl.get();
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* const port = scenv<number>("Port", { parser: parser(z.coerce.number()), default: 3000 });
|
|
285
|
+
* const n = await port.get(); // number
|
|
265
286
|
*/
|
|
266
|
-
declare function scenv<T>(name: string, options?: ScenvVariableOptions<T>): ScenvVariable<T>;
|
|
287
|
+
declare function scenv<T = string>(name: string, options?: ScenvVariableOptions<T>): ScenvVariable<T>;
|
|
267
288
|
|
|
268
289
|
/**
|
|
269
290
|
* Parses command-line arguments into a partial {@link ScenvConfig} suitable for {@link configure}.
|
|
@@ -286,4 +307,4 @@ declare function scenv<T>(name: string, options?: ScenvVariableOptions<T>): Scen
|
|
|
286
307
|
*/
|
|
287
308
|
declare function parseScenvArgs(argv: string[]): Partial<ScenvConfig>;
|
|
288
309
|
|
|
289
|
-
export { type DefaultPromptFn, type GetOptions, LOG_LEVELS, type LogLevel, type PromptMode, type SaveMode, type ScenvCallbacks, type ScenvConfig, type ScenvVariable, configure, discoverContextPaths, getCallbacks, getContext, getContextWritePath, getInMemoryContext, getMergedContextValues, loadConfig, parseScenvArgs, resetConfig, resetInMemoryContext, resetLogState, scenv, setInMemoryContext };
|
|
310
|
+
export { type DefaultPromptFn, type GetOptions, type InferVariableType, LOG_LEVELS, type LogLevel, type ParserResult, type PromptMode, type SaveMode, type ScenvCallbacks, type ScenvConfig, type ScenvVariable, type ScenvVariableOptions, configure, discoverContextPaths, getCallbacks, getContext, getContextWritePath, getInMemoryContext, getMergedContextValues, loadConfig, parseScenvArgs, resetConfig, resetInMemoryContext, resetLogState, scenv, setInMemoryContext };
|
package/dist/index.d.ts
CHANGED
|
@@ -29,7 +29,7 @@ interface ScenvConfig {
|
|
|
29
29
|
context?: string[];
|
|
30
30
|
/** Merge these context names with existing (CLI: `--add-context a,b,c`). Ignored if `context` is set in the same layer. */
|
|
31
31
|
addContext?: string[];
|
|
32
|
-
/** When to prompt for a variable value. See {@link PromptMode}. Default is `"
|
|
32
|
+
/** When to prompt for a variable value. See {@link PromptMode}. Default is `"never"`; set to `always`, `fallback`, or `no-env` to enable prompting (via config file, SCENV_PROMPT, or configure()). */
|
|
33
33
|
prompt?: PromptMode;
|
|
34
34
|
/** If true, environment variables are not used during resolution. */
|
|
35
35
|
ignoreEnv?: boolean;
|
|
@@ -154,18 +154,35 @@ declare function getMergedContextValues(): Record<string, string>;
|
|
|
154
154
|
declare function getContextWritePath(contextName: string): string;
|
|
155
155
|
|
|
156
156
|
/**
|
|
157
|
-
* Return type for a variable's optional `
|
|
158
|
-
*
|
|
159
|
-
*
|
|
160
|
-
* - `
|
|
157
|
+
* Return type for a variable's optional `parser` function. Input is always the raw string
|
|
158
|
+
* (from set/env/context) or the default. Use a boolean for simple pass/fail, or an object
|
|
159
|
+
* to pass a parsed/transformed value or a custom error.
|
|
160
|
+
* - `true` or `{ success: true, data?: T }` – parsing passed; optional `data` is the output value (type T).
|
|
161
|
+
* - `false` or `{ success: false, error?: unknown }` – parsing failed; `.get()` throws with the error.
|
|
161
162
|
*/
|
|
162
|
-
type
|
|
163
|
+
type ParserResult<T> = boolean | {
|
|
163
164
|
success: true;
|
|
164
165
|
data?: T;
|
|
165
166
|
} | {
|
|
166
167
|
success: false;
|
|
167
168
|
error?: unknown;
|
|
168
169
|
};
|
|
170
|
+
/**
|
|
171
|
+
* Infers the variable's value type (output type) from options: when a parser returns
|
|
172
|
+
* `{ success: true, data: D }`, that D is used; otherwise the type comes from `default` or defaults to string.
|
|
173
|
+
*/
|
|
174
|
+
type InferVariableType<O> = O extends {
|
|
175
|
+
parser: (v: unknown) => infer R;
|
|
176
|
+
} ? R extends {
|
|
177
|
+
success: true;
|
|
178
|
+
data: infer D;
|
|
179
|
+
} ? D extends undefined ? O extends {
|
|
180
|
+
default: infer Def;
|
|
181
|
+
} ? Def : string : D : O extends {
|
|
182
|
+
default: infer Def;
|
|
183
|
+
} ? Def : string : O extends {
|
|
184
|
+
default: infer Def;
|
|
185
|
+
} ? Def : string;
|
|
169
186
|
/**
|
|
170
187
|
* Prompt function signature. Called when config requests prompting for this variable.
|
|
171
188
|
* Receives the variable's display name and the current default (from set/env/context or option default).
|
|
@@ -175,17 +192,18 @@ type PromptFn<T> = (name: string, defaultValue: T) => T | Promise<T>;
|
|
|
175
192
|
/**
|
|
176
193
|
* Options when creating a variable with {@link scenv}. All properties are optional.
|
|
177
194
|
* If you omit `key` and `env`, they are derived from `name`: e.g. "API URL" → key `api_url`, env `API_URL`.
|
|
195
|
+
* Input from set/env/context is always string; `default` and the variable's value type are the output type T.
|
|
178
196
|
*/
|
|
179
|
-
interface ScenvVariableOptions<T> {
|
|
197
|
+
interface ScenvVariableOptions<T = string> {
|
|
180
198
|
/** Internal key for --set, context files, and env. Default: name lowercased, spaces → underscores, non-alphanumeric stripped (e.g. "API URL" → "api_url"). */
|
|
181
199
|
key?: string;
|
|
182
200
|
/** Environment variable name (e.g. API_URL). Default: key uppercased, hyphens → underscores. */
|
|
183
201
|
env?: string;
|
|
184
|
-
/** Fallback when nothing is provided via --set, env, or context (and we're not prompting). */
|
|
202
|
+
/** Fallback when nothing is provided via --set, env, or context (and we're not prompting). Same type T as the variable's output (not parsed). */
|
|
185
203
|
default?: T;
|
|
186
|
-
/** Optional.
|
|
187
|
-
|
|
188
|
-
/** Optional. Called when config
|
|
204
|
+
/** Optional. Parses the raw string (or default) into output type T. Receives raw value (typically string). Return { success: true, data } with the parsed value; variable type is inferred from data. */
|
|
205
|
+
parser?: (val: unknown) => ParserResult<T>;
|
|
206
|
+
/** Optional. Called when config has enabled prompting (e.g. prompt: "fallback" and no value found). Overrides callbacks.defaultPrompt for this variable. */
|
|
189
207
|
prompt?: PromptFn<T>;
|
|
190
208
|
}
|
|
191
209
|
/**
|
|
@@ -204,8 +222,8 @@ interface GetOptions<T> {
|
|
|
204
222
|
*/
|
|
205
223
|
interface ScenvVariable<T> {
|
|
206
224
|
/**
|
|
207
|
-
* Resolve and return the value. Uses resolution order (set > env > context > default) and any prompt/
|
|
208
|
-
* @throws If no value is found and no default/prompt, or if
|
|
225
|
+
* Resolve and return the value. Uses resolution order (set > env > context > default) and any prompt/parser.
|
|
226
|
+
* @throws If no value is found and no default/prompt, or if parsing fails.
|
|
209
227
|
*/
|
|
210
228
|
get(options?: GetOptions<T>): Promise<T>;
|
|
211
229
|
/**
|
|
@@ -236,16 +254,15 @@ interface ScenvVariable<T> {
|
|
|
236
254
|
* - Environment variable (e.g. API_URL for key "api_url")
|
|
237
255
|
* - Context files (merged key-value from the context list in config, e.g. dev.context.json)
|
|
238
256
|
*
|
|
239
|
-
* If
|
|
257
|
+
* If prompting is enabled in config (prompt: "always", "fallback", or "no-env"), the prompt callback
|
|
240
258
|
* may run. When it runs, it receives the variable name and a suggested value (the raw value if any, otherwise
|
|
241
259
|
* the default option). The callback's return value is used as the value. When we don't prompt, we use the
|
|
242
260
|
* raw value if present, otherwise the default option, otherwise get() throws (no value).
|
|
243
261
|
*
|
|
244
|
-
* ##
|
|
262
|
+
* ## Parser
|
|
245
263
|
*
|
|
246
|
-
* If you pass a
|
|
247
|
-
* { success: true }
|
|
248
|
-
* Use it to coerce types (e.g. string to number) or enforce rules.
|
|
264
|
+
* If you pass a parser option, it is called with the raw value (typically string from set/env/context) or the default.
|
|
265
|
+
* Return { success: true, data } with the parsed output; the variable's type is inferred from data. On { success: false }, get() throws.
|
|
249
266
|
*
|
|
250
267
|
* ## save()
|
|
251
268
|
*
|
|
@@ -254,16 +271,20 @@ interface ScenvVariable<T> {
|
|
|
254
271
|
* When the user is prompted during get(), the value is always saved (to saveContextTo file if set, and always to in-memory)
|
|
255
272
|
* so a second get() on the same variable does not prompt again.
|
|
256
273
|
*
|
|
257
|
-
* @typeParam T -
|
|
274
|
+
* @typeParam T - Output (value) type of the variable, e.g. string, number, URL. Defaults to string.
|
|
258
275
|
* @param name - Display name used in prompts and errors. If you omit key/env, key is derived from name (e.g. "API URL" → "api_url") and env from key (e.g. "API_URL").
|
|
259
|
-
* @param options - Optional. key, env, default,
|
|
260
|
-
* @returns A {@link ScenvVariable} with get(), safeGet(), and save().
|
|
276
|
+
* @param options - Optional. key, env, default, parser, prompt. See {@link ScenvVariableOptions}.
|
|
277
|
+
* @returns A {@link ScenvVariable<T>} with get(), safeGet(), and save().
|
|
261
278
|
*
|
|
262
279
|
* @example
|
|
263
280
|
* const apiUrl = scenv("API URL", { default: "http://localhost:4000" });
|
|
264
281
|
* const url = await apiUrl.get();
|
|
282
|
+
*
|
|
283
|
+
* @example
|
|
284
|
+
* const port = scenv<number>("Port", { parser: parser(z.coerce.number()), default: 3000 });
|
|
285
|
+
* const n = await port.get(); // number
|
|
265
286
|
*/
|
|
266
|
-
declare function scenv<T>(name: string, options?: ScenvVariableOptions<T>): ScenvVariable<T>;
|
|
287
|
+
declare function scenv<T = string>(name: string, options?: ScenvVariableOptions<T>): ScenvVariable<T>;
|
|
267
288
|
|
|
268
289
|
/**
|
|
269
290
|
* Parses command-line arguments into a partial {@link ScenvConfig} suitable for {@link configure}.
|
|
@@ -286,4 +307,4 @@ declare function scenv<T>(name: string, options?: ScenvVariableOptions<T>): Scen
|
|
|
286
307
|
*/
|
|
287
308
|
declare function parseScenvArgs(argv: string[]): Partial<ScenvConfig>;
|
|
288
309
|
|
|
289
|
-
export { type DefaultPromptFn, type GetOptions, LOG_LEVELS, type LogLevel, type PromptMode, type SaveMode, type ScenvCallbacks, type ScenvConfig, type ScenvVariable, configure, discoverContextPaths, getCallbacks, getContext, getContextWritePath, getInMemoryContext, getMergedContextValues, loadConfig, parseScenvArgs, resetConfig, resetInMemoryContext, resetLogState, scenv, setInMemoryContext };
|
|
310
|
+
export { type DefaultPromptFn, type GetOptions, type InferVariableType, LOG_LEVELS, type LogLevel, type ParserResult, type PromptMode, type SaveMode, type ScenvCallbacks, type ScenvConfig, type ScenvVariable, type ScenvVariableOptions, configure, discoverContextPaths, getCallbacks, getContext, getContextWritePath, getInMemoryContext, getMergedContextValues, loadConfig, parseScenvArgs, resetConfig, resetInMemoryContext, resetLogState, scenv, setInMemoryContext };
|
package/dist/index.js
CHANGED
|
@@ -444,7 +444,7 @@ function defaultKeyFromName(name) {
|
|
|
444
444
|
function defaultEnvFromKey(key) {
|
|
445
445
|
return key.toUpperCase().replace(/-/g, "_");
|
|
446
446
|
}
|
|
447
|
-
function
|
|
447
|
+
function normalizeParserResult(result) {
|
|
448
448
|
if (typeof result === "boolean") {
|
|
449
449
|
return result ? { success: true } : { success: false };
|
|
450
450
|
}
|
|
@@ -454,7 +454,7 @@ function normalizeValidatorResult(result) {
|
|
|
454
454
|
function scenv(name, options = {}) {
|
|
455
455
|
const key = options.key ?? defaultKeyFromName(name);
|
|
456
456
|
const envKey = options.env ?? defaultEnvFromKey(key);
|
|
457
|
-
const
|
|
457
|
+
const parserFn = options.parser;
|
|
458
458
|
const promptFn = options.prompt;
|
|
459
459
|
const defaultValue = options.default;
|
|
460
460
|
async function resolveRaw() {
|
|
@@ -493,7 +493,7 @@ function scenv(name, options = {}) {
|
|
|
493
493
|
return { raw: void 0, source: void 0 };
|
|
494
494
|
}
|
|
495
495
|
function shouldPrompt(config, hadValue, hadEnv) {
|
|
496
|
-
const mode = config.prompt ?? "
|
|
496
|
+
const mode = config.prompt ?? "never";
|
|
497
497
|
if (mode === "never") return false;
|
|
498
498
|
if (mode === "always") return true;
|
|
499
499
|
if (mode === "fallback") return !hadValue;
|
|
@@ -509,7 +509,7 @@ function scenv(name, options = {}) {
|
|
|
509
509
|
const doPrompt = shouldPrompt(config, hadValue, hadEnv);
|
|
510
510
|
log(
|
|
511
511
|
"debug",
|
|
512
|
-
`prompt decision key=${key} prompt=${config.prompt ?? "
|
|
512
|
+
`prompt decision key=${key} prompt=${config.prompt ?? "never"} hadValue=${hadValue} hadEnv=${hadEnv} -> ${doPrompt ? "prompt" : "no prompt"}`
|
|
513
513
|
);
|
|
514
514
|
const effectiveDefault = overrides?.default !== void 0 ? overrides.default : defaultValue;
|
|
515
515
|
const resolvedDefault = effectiveDefault === void 0 ? void 0 : typeof effectiveDefault === "string" ? resolveContextReference(effectiveDefault, key) : effectiveDefault;
|
|
@@ -541,10 +541,10 @@ function scenv(name, options = {}) {
|
|
|
541
541
|
log("info", `variable "${name}" (key=${key}) resolved from ${resolvedFrom}`);
|
|
542
542
|
return { value, raw, hadEnv, wasPrompted };
|
|
543
543
|
}
|
|
544
|
-
function
|
|
545
|
-
if (!
|
|
546
|
-
const result =
|
|
547
|
-
const normalized =
|
|
544
|
+
function parse(value) {
|
|
545
|
+
if (!parserFn) return { success: true, data: value };
|
|
546
|
+
const result = parserFn(value);
|
|
547
|
+
const normalized = normalizeParserResult(result);
|
|
548
548
|
if (normalized.success) {
|
|
549
549
|
const data = "data" in normalized && normalized.data !== void 0 ? normalized.data : value;
|
|
550
550
|
return { success: true, data };
|
|
@@ -556,13 +556,13 @@ function scenv(name, options = {}) {
|
|
|
556
556
|
}
|
|
557
557
|
async function get(options2) {
|
|
558
558
|
const { value, wasPrompted } = await getResolvedValue(options2);
|
|
559
|
-
const
|
|
560
|
-
if (!
|
|
561
|
-
const errMsg = `
|
|
559
|
+
const parsed = parse(value);
|
|
560
|
+
if (!parsed.success) {
|
|
561
|
+
const errMsg = `Parsing failed for "${name}": ${parsed.error ?? "unknown"}`;
|
|
562
562
|
log("error", errMsg);
|
|
563
563
|
throw new Error(errMsg);
|
|
564
564
|
}
|
|
565
|
-
const final =
|
|
565
|
+
const final = parsed.data;
|
|
566
566
|
const config = loadConfig();
|
|
567
567
|
if (wasPrompted) setInMemoryContext(key, String(final));
|
|
568
568
|
if (config.saveContextTo) {
|
|
@@ -584,16 +584,16 @@ function scenv(name, options = {}) {
|
|
|
584
584
|
}
|
|
585
585
|
async function save(value) {
|
|
586
586
|
const toSave = value ?? (await getResolvedValue()).value;
|
|
587
|
-
const
|
|
588
|
-
if (!
|
|
589
|
-
const errMsg = `
|
|
587
|
+
const parsed = parse(toSave);
|
|
588
|
+
if (!parsed.success) {
|
|
589
|
+
const errMsg = `Parsing failed for "${name}": ${parsed.error ?? "unknown"}`;
|
|
590
590
|
log("error", errMsg);
|
|
591
591
|
throw new Error(errMsg);
|
|
592
592
|
}
|
|
593
593
|
const config = loadConfig();
|
|
594
|
-
setInMemoryContext(key, String(
|
|
594
|
+
setInMemoryContext(key, String(parsed.data));
|
|
595
595
|
if (config.saveContextTo) {
|
|
596
|
-
writeToContext(config.saveContextTo, key, String(
|
|
596
|
+
writeToContext(config.saveContextTo, key, String(parsed.data));
|
|
597
597
|
log("info", `Saved key=${key} to saveContextTo ${config.saveContextTo}`);
|
|
598
598
|
}
|
|
599
599
|
}
|