@karmaniverous/get-dotenv 5.2.0 → 5.2.2
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 +37 -1
- package/dist/getdotenv.cli.mjs +163 -15
- package/dist/index.cjs +3589 -1455
- package/dist/index.d.cts +43 -2
- package/dist/index.d.mts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.mjs +3590 -1457
- package/dist/plugins-cmd.cjs +2501 -0
- package/dist/plugins-cmd.d.cts +311 -0
- package/dist/plugins-cmd.d.mts +311 -0
- package/dist/plugins-cmd.d.ts +311 -0
- package/dist/plugins-cmd.mjs +2498 -0
- package/dist/plugins-demo.cjs +330 -0
- package/dist/plugins-demo.d.cts +291 -0
- package/dist/plugins-demo.d.mts +291 -0
- package/dist/plugins-demo.d.ts +291 -0
- package/dist/plugins-demo.mjs +328 -0
- package/package.json +23 -3
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
>
|
|
1
|
+
> Load, expand, and compose environment variables from a deterministic dotenv cascade, then execute commands under that context. Use `get-dotenv` as a library, a CLI, or a plugin-first host to build dotenv-aware tooling with cross‑platform shell control, CI‑friendly capture, and clear diagnostics.
|
|
2
2
|
|
|
3
3
|
# get-dotenv
|
|
4
4
|
|
|
@@ -132,6 +132,42 @@ Options can be passed programmatically or set in a `getdotenv.config.json` file
|
|
|
132
132
|
|
|
133
133
|
See the [child CLI example repo](https://github.com/karmaniverous/get-dotenv-child#configuration) for an extensive discussion of the various config options and how & where to set them.
|
|
134
134
|
|
|
135
|
+
## CLI embedding (createCli)
|
|
136
|
+
|
|
137
|
+
Prefer the named factory when you want to embed the get‑dotenv CLI in your own tool. It wires the plugin‑first host with the included plugins and returns a small runner.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
#!/usr/bin/env node
|
|
141
|
+
import { createCli } from '@karmaniverous/get-dotenv';
|
|
142
|
+
|
|
143
|
+
// Build a CLI and run with your argv; alias appears in help.
|
|
144
|
+
await createCli({
|
|
145
|
+
alias: 'mycli',
|
|
146
|
+
// Optional: override the help header (otherwise “mycli v<version>” is used).
|
|
147
|
+
branding: 'mycli v1.2.3',
|
|
148
|
+
}).run(process.argv.slice(2));
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Notes:
|
|
152
|
+
|
|
153
|
+
- The host resolves dotenv context once per invocation and exposes subcommands: cmd, batch, aws, and init (see Guides below).
|
|
154
|
+
- Use `--trace [keys...]` and `--redact` for diagnostics without altering runtime values.
|
|
155
|
+
- Default shells are normalized across platforms: `/bin/bash` on POSIX and `powershell.exe` on Windows (overridable per‑script or globally).
|
|
156
|
+
- Help/exit behavior (important for embedding and tests):
|
|
157
|
+
- To keep `-h/--help` deterministic across ESM/CJS and avoid Commander’s default `process.exit`, `createCli().run(['-h'])` prints help and returns without exiting the process.
|
|
158
|
+
- Because help is printed before the internal `brand()` call runs, the optional branding header may be omitted when `-h/--help` is used at the top level. If you need a branded header, prefer `mycli help` (which runs through normal parsing) or construct and brand a host directly (see “Branding the host CLI” in Guides).
|
|
159
|
+
- Interop matrix (embedding in different module systems):
|
|
160
|
+
- ESM dynamic:
|
|
161
|
+
```ts
|
|
162
|
+
const { createCli } = await import('@karmaniverous/get-dotenv');
|
|
163
|
+
await createCli({ alias: 'mycli' }).run(['-h']);
|
|
164
|
+
```
|
|
165
|
+
- CommonJS require (using built outputs for smoke checks):
|
|
166
|
+
```js
|
|
167
|
+
const { createCli } = require('@karmaniverous/get-dotenv/dist/index.cjs');
|
|
168
|
+
createCli({ alias: 'mycli' }).run(['-h']);
|
|
169
|
+
```
|
|
170
|
+
|
|
135
171
|
## Dynamic Processing
|
|
136
172
|
|
|
137
173
|
This package supports the full [`dotenv-expand`](https://www.npmjs.com/package/dotenv-expand) syntax, with some internal performance improvements. Dynamic variables can be authored in JS or TS.
|
package/dist/getdotenv.cli.mjs
CHANGED
|
@@ -3691,19 +3691,167 @@ const initPlugin = (opts = {}) => definePlugin({
|
|
|
3691
3691
|
},
|
|
3692
3692
|
});
|
|
3693
3693
|
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3694
|
+
const cmdCommand = new Command()
|
|
3695
|
+
.name('cmd')
|
|
3696
|
+
.description('execute command, conflicts with --command option (default subcommand)')
|
|
3697
|
+
.enablePositionalOptions()
|
|
3698
|
+
.passThroughOptions()
|
|
3699
|
+
.argument('[command...]')
|
|
3700
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
3701
|
+
if (!thisCommand.parent)
|
|
3702
|
+
throw new Error(`unable to resolve parent command`);
|
|
3703
|
+
if (!thisCommand.parent.parent)
|
|
3704
|
+
throw new Error(`unable to resolve root command`);
|
|
3705
|
+
const { getDotenvCliOptions: { logger = console, ...getDotenvCliOptions }, } = thisCommand.parent.parent;
|
|
3706
|
+
const raw = thisCommand.parent.opts();
|
|
3707
|
+
const ignoreErrors = !!raw.ignoreErrors;
|
|
3708
|
+
const globs = typeof raw.globs === 'string' ? raw.globs : '*';
|
|
3709
|
+
const list = !!raw.list;
|
|
3710
|
+
const pkgCwd = !!raw.pkgCwd;
|
|
3711
|
+
const rootPath = typeof raw.rootPath === 'string' ? raw.rootPath : './';
|
|
3712
|
+
// Execute command.
|
|
3713
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
3714
|
+
// When no positional tokens are provided (e.g., option form `-c/--command`),
|
|
3715
|
+
// the preSubcommand hook handles execution. Avoid a duplicate call here.
|
|
3716
|
+
if (args.length === 0)
|
|
3717
|
+
return;
|
|
3718
|
+
const command = args.map(String).join(' ');
|
|
3719
|
+
await execShellCommandBatch({
|
|
3720
|
+
command: resolveCommand(getDotenvCliOptions.scripts, command),
|
|
3721
|
+
getDotenvCliOptions,
|
|
3722
|
+
globs,
|
|
3723
|
+
ignoreErrors,
|
|
3724
|
+
list,
|
|
3725
|
+
logger,
|
|
3726
|
+
pkgCwd,
|
|
3727
|
+
rootPath,
|
|
3728
|
+
// execa expects string | boolean | URL for `shell`. We normalize earlier;
|
|
3729
|
+
// scripts[name].shell overrides take precedence and may be boolean or string.
|
|
3730
|
+
shell: resolveShell(getDotenvCliOptions.scripts, command, getDotenvCliOptions.shell),
|
|
3731
|
+
});
|
|
3732
|
+
});
|
|
3733
|
+
|
|
3734
|
+
new Command()
|
|
3735
|
+
.name('batch')
|
|
3736
|
+
.description('Batch command execution across multiple working directories.')
|
|
3737
|
+
.enablePositionalOptions()
|
|
3738
|
+
.passThroughOptions()
|
|
3739
|
+
.option('-p, --pkg-cwd', 'use nearest package directory as current working directory')
|
|
3740
|
+
.option('-r, --root-path <string>', 'path to batch root directory from current working directory', './')
|
|
3741
|
+
.option('-g, --globs <string>', 'space-delimited globs from root path', '*')
|
|
3742
|
+
.option('-c, --command <string>', 'command executed according to the base --shell option, conflicts with cmd subcommand (dotenv-expanded)', dotenvExpandFromProcessEnv)
|
|
3743
|
+
.option('-l, --list', 'list working directories without executing command')
|
|
3744
|
+
.option('-e, --ignore-errors', 'ignore errors and continue with next path')
|
|
3745
|
+
.hook('preSubcommand', async (thisCommand) => {
|
|
3746
|
+
if (!thisCommand.parent)
|
|
3747
|
+
throw new Error(`unable to resolve root command`);
|
|
3748
|
+
const { getDotenvCliOptions: { logger = console, ...getDotenvCliOptions }, } = thisCommand.parent;
|
|
3749
|
+
const raw = thisCommand.opts();
|
|
3750
|
+
const commandOpt = typeof raw.command === 'string' ? raw.command : undefined;
|
|
3751
|
+
const ignoreErrors = !!raw.ignoreErrors;
|
|
3752
|
+
const globs = typeof raw.globs === 'string' ? raw.globs : '*';
|
|
3753
|
+
const list = !!raw.list;
|
|
3754
|
+
const pkgCwd = !!raw.pkgCwd;
|
|
3755
|
+
const rootPath = typeof raw.rootPath === 'string' ? raw.rootPath : './';
|
|
3756
|
+
const argCount = thisCommand.args.length;
|
|
3757
|
+
if (typeof commandOpt === 'string' && argCount > 0) {
|
|
3758
|
+
logger.error(`--command option conflicts with cmd subcommand.`);
|
|
3759
|
+
process.exit(0);
|
|
3760
|
+
}
|
|
3761
|
+
// Execute command.
|
|
3762
|
+
if (typeof commandOpt === 'string')
|
|
3763
|
+
await execShellCommandBatch({
|
|
3764
|
+
command: resolveCommand(getDotenvCliOptions.scripts, commandOpt),
|
|
3765
|
+
getDotenvCliOptions,
|
|
3766
|
+
globs,
|
|
3767
|
+
ignoreErrors,
|
|
3768
|
+
list,
|
|
3769
|
+
logger,
|
|
3770
|
+
pkgCwd,
|
|
3771
|
+
rootPath,
|
|
3772
|
+
// execa expects string | boolean | URL for `shell`. We normalize earlier;
|
|
3773
|
+
// scripts[name].shell overrides take precedence and may be boolean or string.
|
|
3774
|
+
shell: resolveShell(getDotenvCliOptions.scripts, commandOpt, getDotenvCliOptions.shell),
|
|
3775
|
+
});
|
|
3776
|
+
})
|
|
3777
|
+
.addCommand(cmdCommand, { isDefault: true });
|
|
3778
|
+
|
|
3779
|
+
new Command()
|
|
3780
|
+
.name('cmd')
|
|
3781
|
+
.description('Batch execute command according to the --shell option, conflicts with --command option (default subcommand)')
|
|
3782
|
+
.configureHelp({ showGlobalOptions: true })
|
|
3783
|
+
.enablePositionalOptions()
|
|
3784
|
+
.passThroughOptions()
|
|
3785
|
+
.argument('[command...]')
|
|
3786
|
+
.action(async (commandParts, _options, thisCommand) => {
|
|
3787
|
+
const args = Array.isArray(commandParts) ? commandParts : [];
|
|
3788
|
+
if (args.length === 0)
|
|
3789
|
+
return;
|
|
3790
|
+
if (!thisCommand.parent)
|
|
3791
|
+
throw new Error('parent command not found');
|
|
3792
|
+
const { getDotenvCliOptions: { logger = console, ...getDotenvCliOptions }, } = thisCommand.parent;
|
|
3793
|
+
const command = args.map(String).join(' ');
|
|
3794
|
+
const cmd = resolveCommand(getDotenvCliOptions.scripts, command);
|
|
3795
|
+
if (getDotenvCliOptions.debug)
|
|
3796
|
+
logger.log('\n*** command ***\n', `'${cmd}'`);
|
|
3797
|
+
await execaCommand(cmd, {
|
|
3798
|
+
env: {
|
|
3799
|
+
...process.env,
|
|
3800
|
+
getDotenvCliOptions: JSON.stringify(getDotenvCliOptions),
|
|
3801
|
+
},
|
|
3802
|
+
// execa expects string | boolean | URL; we normalize in generator
|
|
3803
|
+
// and allow script-level overrides.
|
|
3804
|
+
shell: resolveShell(getDotenvCliOptions.scripts, command, getDotenvCliOptions.shell),
|
|
3805
|
+
stdio: 'inherit',
|
|
3806
|
+
});
|
|
3700
3807
|
});
|
|
3701
|
-
|
|
3702
|
-
|
|
3703
|
-
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
.
|
|
3708
|
-
|
|
3709
|
-
|
|
3808
|
+
|
|
3809
|
+
function createCli(opts = {}) {
|
|
3810
|
+
const alias = typeof opts.alias === 'string' && opts.alias.length > 0
|
|
3811
|
+
? opts.alias
|
|
3812
|
+
: 'getdotenv';
|
|
3813
|
+
const program = new GetDotenvCli(alias);
|
|
3814
|
+
// Install base root flags and included plugins; resolve context once per run.
|
|
3815
|
+
program
|
|
3816
|
+
.attachRootOptions({ loadProcess: false })
|
|
3817
|
+
.use(cmdPlugin({ asDefault: true, optionAlias: '-c, --cmd <command...>' }))
|
|
3818
|
+
.use(batchPlugin())
|
|
3819
|
+
.use(awsPlugin())
|
|
3820
|
+
.use(demoPlugin())
|
|
3821
|
+
.use(initPlugin())
|
|
3822
|
+
.passOptions({ loadProcess: false });
|
|
3823
|
+
// Tests-only: avoid process.exit during help/version flows under Vitest.
|
|
3824
|
+
const underTests = process.env.GETDOTENV_TEST === '1' ||
|
|
3825
|
+
typeof process.env.VITEST_WORKER_ID === 'string';
|
|
3826
|
+
if (underTests) {
|
|
3827
|
+
program.exitOverride((err) => {
|
|
3828
|
+
const code = err?.code;
|
|
3829
|
+
if (code === 'commander.helpDisplayed' || code === 'commander.version')
|
|
3830
|
+
return;
|
|
3831
|
+
throw err;
|
|
3832
|
+
});
|
|
3833
|
+
}
|
|
3834
|
+
return {
|
|
3835
|
+
async run(argv) {
|
|
3836
|
+
// Always short-circuit help to avoid Commander-triggered process.exit
|
|
3837
|
+
// across environments (CJS/ESM) and to return immediately under dynamic
|
|
3838
|
+
// ESM without performing extra IO. Prints help and returns.
|
|
3839
|
+
if (argv.some((a) => a === '-h' || a === '--help')) {
|
|
3840
|
+
program.outputHelp();
|
|
3841
|
+
return;
|
|
3842
|
+
}
|
|
3843
|
+
await program.brand({
|
|
3844
|
+
name: alias,
|
|
3845
|
+
importMetaUrl: import.meta.url,
|
|
3846
|
+
description: 'Base CLI.',
|
|
3847
|
+
...(typeof opts.branding === 'string' && opts.branding.length > 0
|
|
3848
|
+
? { helpHeader: opts.branding }
|
|
3849
|
+
: {}),
|
|
3850
|
+
});
|
|
3851
|
+
await program.parseAsync(['node', alias, ...argv]);
|
|
3852
|
+
},
|
|
3853
|
+
};
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
// Delegate to the canonical host factory.
|
|
3857
|
+
await createCli({ alias: 'getdotenv' }).run(process.argv.slice(2));
|