@karmaniverous/get-dotenv 7.0.7 → 7.0.9
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/chunks/{createCli-DRgcaM2D.mjs → createCli-CCxTLJ1j.mjs} +57 -10
- package/dist/chunks/index-Cay5Gzhu.mjs +111 -0
- package/dist/chunks/{index-BzoCat8h.mjs → index-xqvxTkr9.mjs} +6 -6
- package/dist/chunks/{loader-V1vbmtyw.mjs → loader-C3DtD6HB.mjs} +4 -2
- package/dist/chunks/{readDotenvCascade-Dgx4SC1p.mjs → readDotenvCascade-CfFPgLCp.mjs} +52 -21
- package/dist/chunks/{readMergedOptions-x80ltQO_.mjs → readMergedOptions-_hjyCNZ7.mjs} +54 -14
- package/dist/chunks/{resolveCliOptions-CR-BEUmS.mjs → resolveCliOptions-Dp7wPY1K.mjs} +1 -1
- package/dist/chunks/{spawnEnv-CKgnHGpr.mjs → spawnEnv-DvisqPiU.mjs} +28 -3
- package/dist/chunks/{types-poB1VAs_.mjs → types-zXDNhcST.mjs} +1 -1
- package/dist/cli.d.ts +9 -5
- package/dist/cli.mjs +10 -15
- package/dist/cliHost.d.ts +9 -5
- package/dist/cliHost.mjs +6 -6
- package/dist/config.d.ts +1 -1
- package/dist/config.mjs +1 -1
- package/dist/env-overlay.d.ts +13 -9
- package/dist/env-overlay.mjs +2 -2
- package/dist/getdotenv.cli.mjs +10 -15
- package/dist/index.d.ts +10 -6
- package/dist/index.mjs +30 -23
- package/dist/plugins-aws.d.ts +1 -1
- package/dist/plugins-aws.mjs +4 -4
- package/dist/plugins-batch.d.ts +17 -1
- package/dist/plugins-batch.mjs +202 -68
- package/dist/plugins-cmd.d.ts +1 -1
- package/dist/plugins-cmd.mjs +6 -6
- package/dist/plugins-init.d.ts +1 -1
- package/dist/plugins-init.mjs +3 -3
- package/dist/plugins.d.ts +3 -1
- package/dist/plugins.mjs +9 -14
- package/package.json +40 -40
- package/schema/getdotenv.config.schema.json +207 -0
- package/dist/chunks/AwsRestJsonProtocol-BWWvLZiw.mjs +0 -1026
- package/dist/chunks/externalDataInterceptor-Bbvq4sdd.mjs +0 -19
- package/dist/chunks/getSSOTokenFromFile-ClTzvS3i.mjs +0 -22
- package/dist/chunks/index-4kbkrHS9.mjs +0 -12529
- package/dist/chunks/index-B5GwHCSX.mjs +0 -669
- package/dist/chunks/index-Cl6wXPYD.mjs +0 -82
- package/dist/chunks/index-D7Lv-lxm.mjs +0 -349
- package/dist/chunks/index-DFNP_Nrx.mjs +0 -188
- package/dist/chunks/index-DO68RbZ8.mjs +0 -103
- package/dist/chunks/index-Db08BBL5.mjs +0 -519
- package/dist/chunks/index-De2jIOhi.mjs +0 -541
- package/dist/chunks/index-IOQ1o3w3.mjs +0 -290
- package/dist/chunks/index-Tm4WDj9R.mjs +0 -383
- package/dist/chunks/index-fNrNPp4e.mjs +0 -946
- package/dist/chunks/index-w8gK2SKP.mjs +0 -31
- package/dist/chunks/loadSso-Ce3ChPPj.mjs +0 -488
- package/dist/chunks/package-DbbYaehr.mjs +0 -5
- package/dist/chunks/parseKnownFiles-BCL0L7aP.mjs +0 -23
- package/dist/chunks/sdk-stream-mixin-B_ajKWho.mjs +0 -307
|
@@ -1,24 +1,24 @@
|
|
|
1
1
|
import 'zod';
|
|
2
2
|
import 'path';
|
|
3
|
-
import { r as resolveGetDotenvConfigSources } from './loader-
|
|
3
|
+
import { r as resolveGetDotenvConfigSources } from './loader-C3DtD6HB.mjs';
|
|
4
4
|
import 'nanoid';
|
|
5
5
|
import 'fs-extra';
|
|
6
6
|
import 'node:path';
|
|
7
7
|
import 'radash';
|
|
8
8
|
import 'node:buffer';
|
|
9
|
-
import {
|
|
9
|
+
import { a as defaultsDeep, g as getDotenvCliOptions2Options, b as baseRootOptionDefaults, G as GetDotenvCli, c as attachRootOptions } from './readMergedOptions-_hjyCNZ7.mjs';
|
|
10
10
|
import 'crypto';
|
|
11
11
|
import 'url';
|
|
12
12
|
import '@commander-js/extra-typings';
|
|
13
13
|
import 'dotenv';
|
|
14
14
|
import 'execa';
|
|
15
15
|
import { t as toHelpConfig } from './helpConfig-CGejgwWW.mjs';
|
|
16
|
-
import { r as resolveCliOptions } from './resolveCliOptions-
|
|
16
|
+
import { r as resolveCliOptions } from './resolveCliOptions-Dp7wPY1K.mjs';
|
|
17
17
|
import { v as validateEnvAgainstSources } from './validate-CDl0rE6k.mjs';
|
|
18
18
|
import { awsPlugin } from '../plugins-aws.mjs';
|
|
19
|
-
import {
|
|
19
|
+
import { a as awsWhoamiPlugin } from './index-Cay5Gzhu.mjs';
|
|
20
20
|
import { batchPlugin } from '../plugins-batch.mjs';
|
|
21
|
-
import { c as cmdPlugin } from './index-
|
|
21
|
+
import { c as cmdPlugin } from './index-xqvxTkr9.mjs';
|
|
22
22
|
import { initPlugin } from '../plugins-init.mjs';
|
|
23
23
|
|
|
24
24
|
const dbg = (...args) => {
|
|
@@ -66,7 +66,7 @@ function installRootHooks(program, defaults) {
|
|
|
66
66
|
}
|
|
67
67
|
};
|
|
68
68
|
// Hook: preSubcommand — always runs for subcommand flows.
|
|
69
|
-
program.hook('preSubcommand', async (thisCommand,
|
|
69
|
+
program.hook('preSubcommand', async (thisCommand, _actionCommand) => {
|
|
70
70
|
const sources = await resolveGetDotenvConfigSources(import.meta.url);
|
|
71
71
|
const rawArgs = thisCommand.rawArgs ?? [];
|
|
72
72
|
dbg('preSubcommand:rawArgs', rawArgs);
|
|
@@ -82,11 +82,16 @@ function installRootHooks(program, defaults) {
|
|
|
82
82
|
thisCommand.getDotenvCliOptions = merged;
|
|
83
83
|
program._setOptionsBag(merged);
|
|
84
84
|
// Resolve context for this run via programmatic converter.
|
|
85
|
+
// afterResolve is deferred to preAction where the full command path is known.
|
|
85
86
|
const serviceOptions = getDotenvCliOptions2Options(merged);
|
|
86
87
|
await program.resolveAndLoad(serviceOptions, {
|
|
87
|
-
|
|
88
|
+
runAfterResolve: false,
|
|
88
89
|
});
|
|
89
90
|
propagateResolvedEnv(merged);
|
|
91
|
+
// Propagate debug flag to env so dbg() helpers and error boundary see it.
|
|
92
|
+
if (merged.debug) {
|
|
93
|
+
process.env.GETDOTENV_DEBUG = '1';
|
|
94
|
+
}
|
|
90
95
|
// Refresh dynamic help text using the resolved config slices.
|
|
91
96
|
try {
|
|
92
97
|
const ctx = program.getCtx();
|
|
@@ -115,8 +120,8 @@ function installRootHooks(program, defaults) {
|
|
|
115
120
|
/* tolerate non-strict flows */
|
|
116
121
|
}
|
|
117
122
|
});
|
|
118
|
-
// Hook: preAction — root-only and parent-alias flows.
|
|
119
|
-
program.hook('preAction', async (thisCommand) => {
|
|
123
|
+
// Hook: preAction — root-only and parent-alias flows + scoped afterResolve.
|
|
124
|
+
program.hook('preAction', async (thisCommand, actionCommand) => {
|
|
120
125
|
const sources = await resolveGetDotenvConfigSources(import.meta.url);
|
|
121
126
|
const rawArgs = thisCommand.rawArgs ?? [];
|
|
122
127
|
dbg('preAction:rawArgs', rawArgs);
|
|
@@ -139,6 +144,10 @@ function installRootHooks(program, defaults) {
|
|
|
139
144
|
// builds a fresh `merged` and overwrites the options bag, so the env
|
|
140
145
|
// propagated by preSubcommand is lost without this call.
|
|
141
146
|
propagateResolvedEnv(merged);
|
|
147
|
+
// Propagate debug flag to env so dbg() helpers and error boundary see it.
|
|
148
|
+
if (merged.debug) {
|
|
149
|
+
process.env.GETDOTENV_DEBUG = '1';
|
|
150
|
+
}
|
|
142
151
|
try {
|
|
143
152
|
const ctx = program.getCtx();
|
|
144
153
|
const helpCfg = toHelpConfig(merged, ctx.pluginConfigs);
|
|
@@ -162,6 +171,20 @@ function installRootHooks(program, defaults) {
|
|
|
162
171
|
catch {
|
|
163
172
|
/* tolerate non-strict flows */
|
|
164
173
|
}
|
|
174
|
+
// Run afterResolve scoped to the invoked command branch.
|
|
175
|
+
// Walk actionCommand.parent chain to build the full plugin path.
|
|
176
|
+
// Always true after resolution above, but satisfies the type checker.
|
|
177
|
+
const ctx = program.hasCtx() ? program.getCtx() : undefined;
|
|
178
|
+
if (ctx) {
|
|
179
|
+
const segments = [];
|
|
180
|
+
let node = actionCommand;
|
|
181
|
+
while (node && node !== thisCommand) {
|
|
182
|
+
segments.unshift(node.name());
|
|
183
|
+
node = node
|
|
184
|
+
.parent;
|
|
185
|
+
}
|
|
186
|
+
await program._runAfterResolve(ctx, segments.length > 0 ? segments : undefined);
|
|
187
|
+
}
|
|
165
188
|
});
|
|
166
189
|
return program;
|
|
167
190
|
}
|
|
@@ -258,6 +281,25 @@ function applyRootVisibility(program, visibility) {
|
|
|
258
281
|
}
|
|
259
282
|
}
|
|
260
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Top-level error boundary for the CLI runner.
|
|
286
|
+
*
|
|
287
|
+
* Presents errors as clean one-line messages by default.
|
|
288
|
+
* When GETDOTENV_DEBUG is set, prints the full stack trace.
|
|
289
|
+
*/
|
|
290
|
+
function handleCliError(err, argv) {
|
|
291
|
+
const isDebug = process.env.GETDOTENV_DEBUG === '1' ||
|
|
292
|
+
process.env.GETDOTENV_DEBUG === 'true' ||
|
|
293
|
+
(Array.isArray(argv) && argv.includes('--debug'));
|
|
294
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
295
|
+
if (isDebug) {
|
|
296
|
+
console.error(err instanceof Error ? (err.stack ?? message) : message);
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
console.error(`Error: ${message}`);
|
|
300
|
+
}
|
|
301
|
+
process.exitCode = 1;
|
|
302
|
+
}
|
|
261
303
|
/**
|
|
262
304
|
* Create a configured get-dotenv CLI host.
|
|
263
305
|
* Applies defaults, installs root hooks, and composes plugins.
|
|
@@ -453,7 +495,12 @@ function createCli(opts = {}) {
|
|
|
453
495
|
? { helpHeader: opts.branding }
|
|
454
496
|
: {}),
|
|
455
497
|
});
|
|
456
|
-
|
|
498
|
+
try {
|
|
499
|
+
await program.parseAsync(['node', alias, ...argv]);
|
|
500
|
+
}
|
|
501
|
+
catch (err) {
|
|
502
|
+
handleCliError(err, argv);
|
|
503
|
+
}
|
|
457
504
|
};
|
|
458
505
|
}
|
|
459
506
|
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { d as definePlugin } from './readMergedOptions-_hjyCNZ7.mjs';
|
|
2
|
+
import 'execa';
|
|
3
|
+
import 'radash';
|
|
4
|
+
import 'node:buffer';
|
|
5
|
+
import 'fs-extra';
|
|
6
|
+
import 'node:path';
|
|
7
|
+
import 'crypto';
|
|
8
|
+
import 'path';
|
|
9
|
+
import 'url';
|
|
10
|
+
import '@commander-js/extra-typings';
|
|
11
|
+
import 'nanoid';
|
|
12
|
+
import 'dotenv';
|
|
13
|
+
import './loader-C3DtD6HB.mjs';
|
|
14
|
+
import 'package-directory';
|
|
15
|
+
import 'yaml';
|
|
16
|
+
import 'zod';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Attach the default action for the `aws whoami` command.
|
|
20
|
+
*
|
|
21
|
+
* This behavior executes only when `aws whoami` is invoked without a subcommand.
|
|
22
|
+
*
|
|
23
|
+
* @param cli - The `whoami` command mount.
|
|
24
|
+
* @returns Nothing.
|
|
25
|
+
*/
|
|
26
|
+
function attachWhoamiDefaultAction(cli) {
|
|
27
|
+
cli.action(async () => {
|
|
28
|
+
// Dynamic import: @aws-sdk/client-sts is an optional peer dependency.
|
|
29
|
+
// A static import would cause Node to fail at startup (even for -h)
|
|
30
|
+
// when the SDK is not installed in the consumer's project.
|
|
31
|
+
let GetCallerIdentityCommand;
|
|
32
|
+
let STSClient;
|
|
33
|
+
try {
|
|
34
|
+
const mod = await import('@aws-sdk/client-sts');
|
|
35
|
+
GetCallerIdentityCommand = mod.GetCallerIdentityCommand;
|
|
36
|
+
STSClient = mod.STSClient;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
console.error('The aws whoami command requires @aws-sdk/client-sts.\n' +
|
|
40
|
+
'Install it with: npm install @aws-sdk/client-sts');
|
|
41
|
+
process.exitCode = 1;
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
// The AWS SDK default providers will read credentials from process.env,
|
|
45
|
+
// which the aws parent has already populated.
|
|
46
|
+
const client = new STSClient();
|
|
47
|
+
const result = await client.send(new GetCallerIdentityCommand());
|
|
48
|
+
console.log(JSON.stringify(result, null, 2));
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Attach options/arguments for the `aws whoami` plugin mount.
|
|
54
|
+
*
|
|
55
|
+
* This subcommand currently takes no flags/args; this module exists to keep the
|
|
56
|
+
* wiring layout consistent across shipped plugins (options vs actions).
|
|
57
|
+
*
|
|
58
|
+
* Note: the plugin description is owned by `src/plugins/aws/whoami/index.ts` and
|
|
59
|
+
* must not be set here.
|
|
60
|
+
*
|
|
61
|
+
* @param cli - The `whoami` command mount under `aws`.
|
|
62
|
+
* @returns The same `cli` instance for chaining.
|
|
63
|
+
*
|
|
64
|
+
* @internal
|
|
65
|
+
*/
|
|
66
|
+
function attachWhoamiOptions(cli) {
|
|
67
|
+
return cli;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Attach the `really` subcommand under `aws whoami`.
|
|
72
|
+
*
|
|
73
|
+
* Reads `SECRET_IDENTITY` from the resolved get-dotenv context (`cli.getCtx().dotenv`).
|
|
74
|
+
*
|
|
75
|
+
* @param cli - The `whoami` command mount.
|
|
76
|
+
* @returns Nothing.
|
|
77
|
+
*/
|
|
78
|
+
function attachWhoamiReallyAction(cli) {
|
|
79
|
+
const really = cli
|
|
80
|
+
.ns('really')
|
|
81
|
+
.description('Print SECRET_IDENTITY from the resolved dotenv context');
|
|
82
|
+
really.action(() => {
|
|
83
|
+
const secretIdentity = really.getCtx().dotenv.SECRET_IDENTITY;
|
|
84
|
+
console.log(`Your secret identity is ${secretIdentity ?? 'still a secret'}.`);
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* AWS Whoami plugin factory.
|
|
90
|
+
*
|
|
91
|
+
* This plugin demonstrates a “bucket of subcommands” pattern:
|
|
92
|
+
* - Subcommand behavior is articulated in separate modules as `attach*` helpers.
|
|
93
|
+
* - Those helpers are not individually composable plugins; they are internal wiring for one plugin instance.
|
|
94
|
+
*
|
|
95
|
+
* @returns A plugin instance mounted at `aws whoami`.
|
|
96
|
+
*/
|
|
97
|
+
const awsWhoamiPlugin = () => definePlugin({
|
|
98
|
+
ns: 'whoami',
|
|
99
|
+
setup(cli) {
|
|
100
|
+
cli.description('Print AWS caller identity (uses parent aws session)');
|
|
101
|
+
// Options/args (none today, but keep layout consistent with other plugins).
|
|
102
|
+
const whoami = attachWhoamiOptions(cli);
|
|
103
|
+
// Default behavior: `getdotenv aws whoami`
|
|
104
|
+
attachWhoamiDefaultAction(whoami);
|
|
105
|
+
// Subcommand behavior: `getdotenv aws whoami really`
|
|
106
|
+
attachWhoamiReallyAction(whoami);
|
|
107
|
+
return undefined;
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
export { awsWhoamiPlugin as a };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { camel } from 'radash';
|
|
2
|
-
import { r as readMergedOptions,
|
|
2
|
+
import { r as readMergedOptions, a as defaultsDeep, g as getDotenvCliOptions2Options, d as definePlugin } from './readMergedOptions-_hjyCNZ7.mjs';
|
|
3
3
|
import 'execa';
|
|
4
4
|
import 'node:buffer';
|
|
5
5
|
import 'fs-extra';
|
|
@@ -10,14 +10,14 @@ import 'url';
|
|
|
10
10
|
import '@commander-js/extra-typings';
|
|
11
11
|
import 'nanoid';
|
|
12
12
|
import 'dotenv';
|
|
13
|
-
import { r as resolveGetDotenvConfigSources } from './loader-
|
|
13
|
+
import { r as resolveGetDotenvConfigSources } from './loader-C3DtD6HB.mjs';
|
|
14
14
|
import 'package-directory';
|
|
15
15
|
import 'yaml';
|
|
16
16
|
import { z } from 'zod';
|
|
17
|
-
import { r as resolveCommand, a as resolveShell, t as tokenize, s as shouldCapture, c as runCommand, b as buildSpawnEnv } from './spawnEnv-
|
|
17
|
+
import { r as resolveCommand, a as resolveShell, t as tokenize, s as shouldCapture, c as runCommand, b as buildSpawnEnv } from './spawnEnv-DvisqPiU.mjs';
|
|
18
18
|
import { m as maybePreserveNodeEvalArgv, c as composeNestedEnv, s as stripOne } from './invoke-DuRPU1oC.mjs';
|
|
19
|
-
import { f as dotenvExpandFromProcessEnv } from './readDotenvCascade-
|
|
20
|
-
import { b as baseGetDotenvCliOptions, r as resolveCliOptions } from './resolveCliOptions-
|
|
19
|
+
import { f as dotenvExpandFromProcessEnv } from './readDotenvCascade-CfFPgLCp.mjs';
|
|
20
|
+
import { b as baseGetDotenvCliOptions, r as resolveCliOptions } from './resolveCliOptions-Dp7wPY1K.mjs';
|
|
21
21
|
|
|
22
22
|
/** src/diagnostics/entropy.ts
|
|
23
23
|
* Entropy diagnostics (presentation-only).
|
|
@@ -480,4 +480,4 @@ const cmdPlugin = (options = {}) => {
|
|
|
480
480
|
return plugin;
|
|
481
481
|
};
|
|
482
482
|
|
|
483
|
-
export {
|
|
483
|
+
export { redactDisplay as a, cmdPlugin as c, maybeWarnEntropy as m, redactObject as r, traceChildEnv as t };
|
|
@@ -288,7 +288,7 @@ const discoverConfigFiles = async (importMetaUrl) => {
|
|
|
288
288
|
* For JS/TS: default export is loaded; "dynamic" is allowed.
|
|
289
289
|
*/
|
|
290
290
|
const loadConfigFile = async (filePath) => {
|
|
291
|
-
let raw
|
|
291
|
+
let raw;
|
|
292
292
|
try {
|
|
293
293
|
const abs = path.resolve(filePath);
|
|
294
294
|
if (isJsOrTs(abs)) {
|
|
@@ -302,7 +302,9 @@ const loadConfigFile = async (filePath) => {
|
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
304
|
catch (err) {
|
|
305
|
-
throw new Error(`Failed to read/parse config: ${filePath}
|
|
305
|
+
throw new Error(`Failed to read/parse config: ${filePath}.`, {
|
|
306
|
+
cause: err,
|
|
307
|
+
});
|
|
306
308
|
}
|
|
307
309
|
// Validate RAW
|
|
308
310
|
const parsed = getDotenvConfigSchemaRaw.safeParse(raw);
|
|
@@ -189,21 +189,31 @@ function pushDotenvProvenance(prov, key, entry) {
|
|
|
189
189
|
*/
|
|
190
190
|
/**
|
|
191
191
|
* Apply a dynamic map to the target progressively.
|
|
192
|
-
* - Functions receive (target, env) and may return string | undefined.
|
|
193
|
-
* -
|
|
192
|
+
* - Functions receive (target, env) and may return string | null | undefined.
|
|
193
|
+
* - string → set the key to that value.
|
|
194
|
+
* - undefined → no-op, leave existing value unchanged.
|
|
195
|
+
* - null → delete the key from the target.
|
|
194
196
|
*
|
|
195
197
|
* @param target - Mutable target environment to assign into.
|
|
196
198
|
* @param map - Dynamic map to apply (functions and/or literal values).
|
|
197
199
|
* @param env - Selected environment name (if any) passed through to dynamic functions.
|
|
198
|
-
* @returns
|
|
200
|
+
* @returns Set of keys that were deleted (value was null).
|
|
199
201
|
*/
|
|
200
202
|
function applyDynamicMap(target, map, env) {
|
|
203
|
+
const deleted = new Set();
|
|
201
204
|
if (!map)
|
|
202
|
-
return;
|
|
205
|
+
return deleted;
|
|
203
206
|
for (const key of Object.keys(map)) {
|
|
204
207
|
const val = typeof map[key] === 'function' ? map[key](target, env) : map[key];
|
|
205
|
-
|
|
208
|
+
if (val === null) {
|
|
209
|
+
Reflect.deleteProperty(target, key);
|
|
210
|
+
deleted.add(key);
|
|
211
|
+
}
|
|
212
|
+
else if (val !== undefined)
|
|
213
|
+
target[key] = val;
|
|
214
|
+
// undefined → no-op
|
|
206
215
|
}
|
|
216
|
+
return deleted;
|
|
207
217
|
}
|
|
208
218
|
/**
|
|
209
219
|
* Load a default-export dynamic map from a JS/TS file (without applying it).
|
|
@@ -245,25 +255,46 @@ async function loadDynamicModuleDefault(absPath, cacheDirName) {
|
|
|
245
255
|
* @param prov - Provenance map to append into.
|
|
246
256
|
* @param meta - Dynamic provenance metadata (source tier and optional dynamicPath).
|
|
247
257
|
*
|
|
258
|
+
* @returns Set of keys that were deleted (value was null).
|
|
259
|
+
*
|
|
248
260
|
* @public
|
|
249
261
|
*/
|
|
250
262
|
function applyDynamicMapWithProvenance(target, map, env, prov, meta) {
|
|
263
|
+
const deleted = new Set();
|
|
251
264
|
if (!map)
|
|
252
|
-
return;
|
|
265
|
+
return deleted;
|
|
253
266
|
for (const key of Object.keys(map)) {
|
|
254
267
|
const val = typeof map[key] === 'function' ? map[key](target, env) : map[key];
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
meta.dynamicPath
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
268
|
+
if (val === null) {
|
|
269
|
+
Reflect.deleteProperty(target, key);
|
|
270
|
+
deleted.add(key);
|
|
271
|
+
pushDotenvProvenance(prov, key, {
|
|
272
|
+
kind: 'dynamic',
|
|
273
|
+
op: 'unset',
|
|
274
|
+
dynamicSource: meta.dynamicSource,
|
|
275
|
+
...(meta.dynamicSource === 'dynamicPath' &&
|
|
276
|
+
typeof meta.dynamicPath === 'string' &&
|
|
277
|
+
meta.dynamicPath.length > 0
|
|
278
|
+
? { dynamicPath: meta.dynamicPath }
|
|
279
|
+
: {}),
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
else if (val !== undefined) {
|
|
283
|
+
target[key] = val;
|
|
284
|
+
pushDotenvProvenance(prov, key, {
|
|
285
|
+
kind: 'dynamic',
|
|
286
|
+
op: 'set',
|
|
287
|
+
dynamicSource: meta.dynamicSource,
|
|
288
|
+
...(meta.dynamicSource === 'dynamicPath' &&
|
|
289
|
+
typeof meta.dynamicPath === 'string' &&
|
|
290
|
+
meta.dynamicPath.length > 0
|
|
291
|
+
? { dynamicPath: meta.dynamicPath }
|
|
292
|
+
: {}),
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
// undefined → no-op, no provenance entry
|
|
266
296
|
}
|
|
297
|
+
return deleted;
|
|
267
298
|
}
|
|
268
299
|
/**
|
|
269
300
|
* Load a default-export dynamic map from a JS/TS file and apply it.
|
|
@@ -278,13 +309,13 @@ function applyDynamicMapWithProvenance(target, map, env, prov, meta) {
|
|
|
278
309
|
* @param absPath - Absolute path to the dynamic module file.
|
|
279
310
|
* @param env - Selected environment name (if any).
|
|
280
311
|
* @param cacheDirName - Cache subdirectory under `.tsbuild/` for compiled artifacts.
|
|
281
|
-
* @returns A `Promise\<
|
|
312
|
+
* @returns A `Promise\<Set\<string\>\>` resolving to the set of deleted keys.
|
|
282
313
|
*/
|
|
283
314
|
async function loadAndApplyDynamic(target, absPath, env, cacheDirName) {
|
|
284
315
|
const dyn = await loadDynamicModuleDefault(absPath, cacheDirName);
|
|
285
316
|
if (!dyn)
|
|
286
|
-
return;
|
|
287
|
-
applyDynamicMap(target, dyn, env);
|
|
317
|
+
return new Set();
|
|
318
|
+
return applyDynamicMap(target, dyn, env);
|
|
288
319
|
}
|
|
289
320
|
|
|
290
321
|
/**
|
|
@@ -542,4 +573,4 @@ async function readDotenvCascadeWithProvenance(args) {
|
|
|
542
573
|
return { dotenv: expanded, provenance: prov };
|
|
543
574
|
}
|
|
544
575
|
|
|
545
|
-
export { applyDynamicMap as a, applyDynamicMapWithProvenance as b, createDotenvProvenance as c,
|
|
576
|
+
export { applyDynamicMap as a, applyDynamicMapWithProvenance as b, createDotenvProvenance as c, dotenvExpandAll as d, loadDynamicModuleDefault as e, dotenvExpandFromProcessEnv as f, readDotenv as g, dotenvExpand as h, loadAndApplyDynamic as l, overlayEnvWithProvenance as o, pushDotenvProvenance as p, readDotenvCascadeWithProvenance as r };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { Option, Command } from '@commander-js/extra-typings';
|
|
3
|
-
import {
|
|
3
|
+
import { h as dotenvExpand, r as readDotenvCascadeWithProvenance, o as overlayEnvWithProvenance, b as applyDynamicMapWithProvenance, e as loadDynamicModuleDefault, f as dotenvExpandFromProcessEnv } from './readDotenvCascade-CfFPgLCp.mjs';
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'nanoid';
|
|
@@ -10,7 +10,7 @@ import 'node:buffer';
|
|
|
10
10
|
import 'crypto';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
import 'dotenv';
|
|
13
|
-
import { g as getDotenvOptionsSchemaResolved, r as resolveGetDotenvConfigSources } from './loader-
|
|
13
|
+
import { g as getDotenvOptionsSchemaResolved, r as resolveGetDotenvConfigSources } from './loader-C3DtD6HB.mjs';
|
|
14
14
|
import { packageDirectory } from 'package-directory';
|
|
15
15
|
|
|
16
16
|
/**
|
|
@@ -737,6 +737,19 @@ const attachRootOptions = (program, defaults) => {
|
|
|
737
737
|
program.addOption(lf);
|
|
738
738
|
program.setOptionGroup(lf, GROUP);
|
|
739
739
|
}
|
|
740
|
+
// Debug ON/OFF (dynamic)
|
|
741
|
+
{
|
|
742
|
+
const dOn = program
|
|
743
|
+
.createDynamicOption('--debug', (cfg) => `enable debug logging to stderr ${onOff(true, Boolean(cfg.debug))}`)
|
|
744
|
+
.conflicts('debugOff');
|
|
745
|
+
program.addOption(dOn);
|
|
746
|
+
program.setOptionGroup(dOn, GROUP);
|
|
747
|
+
const dOff = program
|
|
748
|
+
.createDynamicOption('--debug-off', (cfg) => `enable debug logging to stderr ${onOff(false, !cfg.debug)}`)
|
|
749
|
+
.conflicts('debug');
|
|
750
|
+
program.addOption(dOff);
|
|
751
|
+
program.setOptionGroup(dOff, GROUP);
|
|
752
|
+
}
|
|
740
753
|
// Capture flag (no default display; static)
|
|
741
754
|
{
|
|
742
755
|
const opt = new Option('--capture', 'capture child process stdio for commands (tests/CI)');
|
|
@@ -947,7 +960,7 @@ function buildHelpInformation(base, cmd) {
|
|
|
947
960
|
}
|
|
948
961
|
const marker = '\nCommands:';
|
|
949
962
|
const idx = base.indexOf(marker);
|
|
950
|
-
let out
|
|
963
|
+
let out;
|
|
951
964
|
if (idx >= 0) {
|
|
952
965
|
const toInsert = groups.startsWith('\n') ? groups : `\n${groups}`;
|
|
953
966
|
out = `${base.slice(0, idx)}${toInsert}${base.slice(idx)}`;
|
|
@@ -1278,7 +1291,10 @@ class GetDotenvCli extends Command {
|
|
|
1278
1291
|
// Ensure plugins are installed exactly once, then run afterResolve.
|
|
1279
1292
|
await this.install();
|
|
1280
1293
|
if (opts?.runAfterResolve ?? true) {
|
|
1281
|
-
|
|
1294
|
+
const path = opts?.invokedSubcommand
|
|
1295
|
+
? [opts.invokedSubcommand]
|
|
1296
|
+
: undefined;
|
|
1297
|
+
await this._runAfterResolve(ctx, path);
|
|
1282
1298
|
}
|
|
1283
1299
|
return ctx;
|
|
1284
1300
|
}
|
|
@@ -1438,16 +1454,40 @@ class GetDotenvCli extends Command {
|
|
|
1438
1454
|
}
|
|
1439
1455
|
/**
|
|
1440
1456
|
* Run afterResolve hooks for registered plugins (parent → children).
|
|
1441
|
-
* When {@link
|
|
1442
|
-
*
|
|
1457
|
+
* When {@link commandPath} is provided, only the matching branch of the
|
|
1458
|
+
* plugin tree runs; otherwise all plugins run (backward compatibility).
|
|
1459
|
+
*
|
|
1460
|
+
* The path is walked segment-by-segment against the plugin tree.
|
|
1461
|
+
* Intermediate matches run their own afterResolve hook.
|
|
1462
|
+
* The deepest match runs afterResolve for itself and all its descendants.
|
|
1443
1463
|
*/
|
|
1444
|
-
async _runAfterResolve(ctx,
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1464
|
+
async _runAfterResolve(ctx, commandPath) {
|
|
1465
|
+
if (!commandPath || commandPath.length === 0) {
|
|
1466
|
+
await runAfterResolveTree(this, this._plugins.map((e) => e.plugin), ctx);
|
|
1467
|
+
return;
|
|
1468
|
+
}
|
|
1469
|
+
// Walk the plugin tree along the command path, scoping to the invoked branch.
|
|
1470
|
+
let entries = this._plugins;
|
|
1471
|
+
for (let i = 0; i < commandPath.length; i++) {
|
|
1472
|
+
const segment = commandPath[i];
|
|
1473
|
+
const entry = entries.find((e) => effectiveNs(e) === segment);
|
|
1474
|
+
if (!entry)
|
|
1475
|
+
return;
|
|
1476
|
+
const isLast = i === commandPath.length - 1;
|
|
1477
|
+
const nextSegment = commandPath[i + 1];
|
|
1478
|
+
const hasMatchingChild = !isLast &&
|
|
1479
|
+
entry.plugin.children.some((e) => effectiveNs(e) === nextSegment);
|
|
1480
|
+
if (isLast || !hasMatchingChild) {
|
|
1481
|
+
// Deepest match: run this plugin + all its descendants.
|
|
1482
|
+
await runAfterResolveTree(this, [entry.plugin], ctx);
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
// Intermediate match: run only this plugin's own afterResolve.
|
|
1486
|
+
if (entry.plugin.afterResolve) {
|
|
1487
|
+
await entry.plugin.afterResolve(this, ctx);
|
|
1488
|
+
}
|
|
1489
|
+
entries = entry.plugin.children;
|
|
1490
|
+
}
|
|
1451
1491
|
}
|
|
1452
1492
|
}
|
|
1453
1493
|
|
|
@@ -1477,4 +1517,4 @@ const readMergedOptions = (cmd) => {
|
|
|
1477
1517
|
return bag;
|
|
1478
1518
|
};
|
|
1479
1519
|
|
|
1480
|
-
export { GetDotenvCli as G,
|
|
1520
|
+
export { GetDotenvCli as G, defaultsDeep as a, baseRootOptionDefaults as b, attachRootOptions as c, definePlugin as d, resolveGetDotenvOptions as e, assertLogger as f, getDotenvCliOptions2Options as g, defineDynamic as h, defineGetDotenvConfig as i, interpolateDeep as j, readMergedOptions as r, writeDotenvFile as w };
|
|
@@ -84,6 +84,26 @@ const shouldCapture = (bagCapture) => process.env.GETDOTENV_STDIO === 'pipe' ||
|
|
|
84
84
|
// This is safe for argv arrays passed to execa (no quoting needed) and avoids
|
|
85
85
|
// passing quote characters through to Node (e.g., for `node -e "<code>"`).
|
|
86
86
|
// Handles stacked quotes from shells like PowerShell: """code""" -> code.
|
|
87
|
+
// Shell-quote a single token for safe interpolation when joining an argv
|
|
88
|
+
// array into a command string destined for a shell. On Windows (cmd.exe)
|
|
89
|
+
// wrap in double quotes when the token contains shell metacharacters; on
|
|
90
|
+
// Unix wrap in single quotes with escaped embedded singles.
|
|
91
|
+
const shellQuoteToken = (s) => {
|
|
92
|
+
if (process.platform === 'win32') {
|
|
93
|
+
// cmd.exe: double-quote tokens with special chars. Inner double
|
|
94
|
+
// quotes are escaped with backslash (Node/libuv convention).
|
|
95
|
+
if (/[\s"'&|<>^()!%+,;=]/.test(s)) {
|
|
96
|
+
return '"' + s.replace(/"/g, '\\"') + '"';
|
|
97
|
+
}
|
|
98
|
+
return s;
|
|
99
|
+
}
|
|
100
|
+
// POSIX: single-quote tokens with special chars. Embedded single
|
|
101
|
+
// quotes break out, add an escaped single, and re-enter.
|
|
102
|
+
if (/[\s"'&|<>()!$\\`~#;{}[\]*?+]/.test(s)) {
|
|
103
|
+
return "'" + s.replace(/'/g, "'\\''") + "'";
|
|
104
|
+
}
|
|
105
|
+
return s;
|
|
106
|
+
};
|
|
87
107
|
const stripOuterQuotes = (s) => {
|
|
88
108
|
let out = s;
|
|
89
109
|
// Repeatedly trim only when the entire string is wrapped in matching quotes.
|
|
@@ -129,7 +149,7 @@ async function _execNormalized(command, shell, opts = {}) {
|
|
|
129
149
|
const stdio = opts.stdio ?? 'pipe';
|
|
130
150
|
if (shell === false) {
|
|
131
151
|
let file;
|
|
132
|
-
let args
|
|
152
|
+
let args;
|
|
133
153
|
if (typeof command === 'string') {
|
|
134
154
|
const tokens = tokenize(command);
|
|
135
155
|
file = tokens[0];
|
|
@@ -158,8 +178,13 @@ async function _execNormalized(command, shell, opts = {}) {
|
|
|
158
178
|
return out;
|
|
159
179
|
}
|
|
160
180
|
}
|
|
161
|
-
// Shell path (string|true|URL):
|
|
162
|
-
|
|
181
|
+
// Shell path (string|true|URL): build a single command string for the
|
|
182
|
+
// target shell. When the command is an array we shell-quote each token
|
|
183
|
+
// individually before joining so that metacharacters (spaces, quotes, +,
|
|
184
|
+
// parentheses, etc.) survive the round-trip through cmd.exe / sh.
|
|
185
|
+
const commandStr = typeof command === 'string'
|
|
186
|
+
? command
|
|
187
|
+
: command.map(shellQuoteToken).join(' ');
|
|
163
188
|
dbg('exec (shell)', {
|
|
164
189
|
command: commandStr,
|
|
165
190
|
shell: typeof shell === 'string' ? shell : 'custom',
|
package/dist/cli.d.ts
CHANGED
|
@@ -286,7 +286,7 @@ interface RootOptionsShape {
|
|
|
286
286
|
*/
|
|
287
287
|
trace?: boolean | string[];
|
|
288
288
|
/** Paths to search for dotenv files (space-delimited string or array). */
|
|
289
|
-
paths?: string;
|
|
289
|
+
paths?: string | string[];
|
|
290
290
|
/** Delimiter for paths string (default: space). */
|
|
291
291
|
pathsDelimiter?: string;
|
|
292
292
|
/** Regex pattern for paths delimiter. */
|
|
@@ -378,7 +378,7 @@ type ProcessEnv = Record<string, string | undefined>;
|
|
|
378
378
|
* and the selected environment (if any), and returns either a string to set
|
|
379
379
|
* or `undefined` to unset/skip the variable.
|
|
380
380
|
*/
|
|
381
|
-
type GetDotenvDynamicFunction = (vars: ProcessEnv, env: string | undefined) => string | undefined;
|
|
381
|
+
type GetDotenvDynamicFunction = (vars: ProcessEnv, env: string | undefined) => string | null | undefined;
|
|
382
382
|
/**
|
|
383
383
|
* A map of dynamic variable definitions.
|
|
384
384
|
* Keys are variable names; values are either literal strings or functions.
|
|
@@ -713,10 +713,14 @@ declare class GetDotenvCli<TOptions extends GetDotenvOptions = GetDotenvOptions,
|
|
|
713
713
|
install(): Promise<void>;
|
|
714
714
|
/**
|
|
715
715
|
* Run afterResolve hooks for registered plugins (parent → children).
|
|
716
|
-
* When {@link
|
|
717
|
-
*
|
|
716
|
+
* When {@link commandPath} is provided, only the matching branch of the
|
|
717
|
+
* plugin tree runs; otherwise all plugins run (backward compatibility).
|
|
718
|
+
*
|
|
719
|
+
* The path is walked segment-by-segment against the plugin tree.
|
|
720
|
+
* Intermediate matches run their own afterResolve hook.
|
|
721
|
+
* The deepest match runs afterResolve for itself and all its descendants.
|
|
718
722
|
*/
|
|
719
|
-
|
|
723
|
+
_runAfterResolve(ctx: GetDotenvCliCtx<TOptions>, commandPath?: string[]): Promise<void>;
|
|
720
724
|
}
|
|
721
725
|
|
|
722
726
|
/**
|