@depup/env-cmd 11.0.0-depup.25
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/.editorconfig +14 -0
- package/.husky/commit-msg +1 -0
- package/.mocharc.json +8 -0
- package/CHANGELOG.md +162 -0
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/bin/env-cmd.js +3 -0
- package/changes.json +14 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +21 -0
- package/dist/env-cmd.d.ts +10 -0
- package/dist/env-cmd.js +58 -0
- package/dist/expand-envs.d.ts +6 -0
- package/dist/expand-envs.js +10 -0
- package/dist/get-env-vars.d.ts +12 -0
- package/dist/get-env-vars.js +122 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/loaders/typescript.d.ts +1 -0
- package/dist/loaders/typescript.js +8 -0
- package/dist/parse-args.d.ts +6 -0
- package/dist/parse-args.js +105 -0
- package/dist/parse-env-file.d.ts +30 -0
- package/dist/parse-env-file.js +119 -0
- package/dist/parse-rc-file.d.ts +8 -0
- package/dist/parse-rc-file.js +78 -0
- package/dist/signal-termination.d.ts +27 -0
- package/dist/signal-termination.js +116 -0
- package/dist/types.d.ts +39 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +15 -0
- package/dist/utils.js +46 -0
- package/eslint.config.js +38 -0
- package/package.json +118 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { Environment } from './types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Gets the environment vars from an env file
|
|
4
|
+
*/
|
|
5
|
+
export declare function getEnvFileVars(envFilePath: string): Promise<Environment>;
|
|
6
|
+
/**
|
|
7
|
+
* Parse out all env vars from a given env file string and return an object
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseEnvString(envFileString: string): Environment;
|
|
10
|
+
/**
|
|
11
|
+
* Parse out all env vars from an env file string
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnvVars(envString: string): Environment;
|
|
14
|
+
/**
|
|
15
|
+
* Strips out comments from env file string
|
|
16
|
+
*/
|
|
17
|
+
export declare function stripComments(envString: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Strips out newlines from env file string
|
|
20
|
+
*/
|
|
21
|
+
export declare function stripEmptyLines(envString: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* If we load data from a file like .js, the user
|
|
24
|
+
* might export something which is not an object.
|
|
25
|
+
*
|
|
26
|
+
* This function ensures that the input is valid,
|
|
27
|
+
* and converts the object's values to strings, for
|
|
28
|
+
* consistincy. See issue #125 for details.
|
|
29
|
+
*/
|
|
30
|
+
export declare function normalizeEnvObject(input: unknown, absolutePath: string): Environment;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { extname } from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js';
|
|
5
|
+
import { checkIfTypescriptSupported } from './loaders/typescript.js';
|
|
6
|
+
/**
|
|
7
|
+
* Gets the environment vars from an env file
|
|
8
|
+
*/
|
|
9
|
+
export async function getEnvFileVars(envFilePath) {
|
|
10
|
+
const absolutePath = resolveEnvFilePath(envFilePath);
|
|
11
|
+
if (!existsSync(absolutePath)) {
|
|
12
|
+
const pathError = new Error(`Invalid env file path (${envFilePath}).`);
|
|
13
|
+
pathError.name = 'PathError';
|
|
14
|
+
throw pathError;
|
|
15
|
+
}
|
|
16
|
+
// Get the file extension
|
|
17
|
+
const ext = extname(absolutePath).toLowerCase();
|
|
18
|
+
let env;
|
|
19
|
+
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
|
20
|
+
if (/tsx?$/.test(ext))
|
|
21
|
+
checkIfTypescriptSupported();
|
|
22
|
+
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
|
23
|
+
let attributeTypes = {};
|
|
24
|
+
if (ext === '.json') {
|
|
25
|
+
attributeTypes = { with: { type: 'json' } };
|
|
26
|
+
}
|
|
27
|
+
const res = await import(pathToFileURL(absolutePath).href, attributeTypes);
|
|
28
|
+
if (typeof res === 'object' && res && 'default' in res) {
|
|
29
|
+
env = res.default;
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
env = res;
|
|
33
|
+
}
|
|
34
|
+
// Check to see if the imported value is a promise
|
|
35
|
+
if (isPromise(env)) {
|
|
36
|
+
env = await env;
|
|
37
|
+
}
|
|
38
|
+
return normalizeEnvObject(env, absolutePath);
|
|
39
|
+
}
|
|
40
|
+
const file = readFileSync(absolutePath, { encoding: 'utf8' });
|
|
41
|
+
switch (ext) {
|
|
42
|
+
// other loaders can be added here
|
|
43
|
+
default:
|
|
44
|
+
return parseEnvString(file);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse out all env vars from a given env file string and return an object
|
|
49
|
+
*/
|
|
50
|
+
export function parseEnvString(envFileString) {
|
|
51
|
+
// First thing we do is stripe out all comments
|
|
52
|
+
envFileString = stripComments(envFileString);
|
|
53
|
+
// Next we stripe out all the empty lines
|
|
54
|
+
envFileString = stripEmptyLines(envFileString);
|
|
55
|
+
// Merge the file env vars with the current process env vars (the file vars overwrite process vars)
|
|
56
|
+
return parseEnvVars(envFileString);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse out all env vars from an env file string
|
|
60
|
+
*/
|
|
61
|
+
export function parseEnvVars(envString) {
|
|
62
|
+
const envParseRegex = /^((.+?)[=](.*))$/gim;
|
|
63
|
+
const matches = {};
|
|
64
|
+
let match;
|
|
65
|
+
while ((match = envParseRegex.exec(envString)) !== null) {
|
|
66
|
+
// Note: match[1] is the full env=var line
|
|
67
|
+
const key = match[2].trim();
|
|
68
|
+
let value = match[3].trim();
|
|
69
|
+
// if the string is quoted, remove everything after the final
|
|
70
|
+
// quote. This implicitly removes inline comments.
|
|
71
|
+
if (value.startsWith("'") || value.startsWith('"')) {
|
|
72
|
+
value = value.slice(1, value.lastIndexOf(value[0]));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
// if the string is not quoted, we need to explicitly remove
|
|
76
|
+
// inline comments.
|
|
77
|
+
value = value.split('#')[0].trim();
|
|
78
|
+
}
|
|
79
|
+
value = value.replace(/\\n/g, '\n');
|
|
80
|
+
matches[key] = value;
|
|
81
|
+
}
|
|
82
|
+
return JSON.parse(JSON.stringify(matches));
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Strips out comments from env file string
|
|
86
|
+
*/
|
|
87
|
+
export function stripComments(envString) {
|
|
88
|
+
const commentsRegex = /(^\s*#.*$)/gim;
|
|
89
|
+
return envString.replace(commentsRegex, '');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Strips out newlines from env file string
|
|
93
|
+
*/
|
|
94
|
+
export function stripEmptyLines(envString) {
|
|
95
|
+
const emptyLinesRegex = /(^\n)/gim;
|
|
96
|
+
return envString.replace(emptyLinesRegex, '');
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* If we load data from a file like .js, the user
|
|
100
|
+
* might export something which is not an object.
|
|
101
|
+
*
|
|
102
|
+
* This function ensures that the input is valid,
|
|
103
|
+
* and converts the object's values to strings, for
|
|
104
|
+
* consistincy. See issue #125 for details.
|
|
105
|
+
*/
|
|
106
|
+
export function normalizeEnvObject(input, absolutePath) {
|
|
107
|
+
if (typeof input !== 'object' || !input) {
|
|
108
|
+
throw new Error(`env-cmd cannot load “${absolutePath}” because it does not export an object.`);
|
|
109
|
+
}
|
|
110
|
+
const env = {};
|
|
111
|
+
for (const [key, value] of Object.entries(input)) {
|
|
112
|
+
// we're intentionally stringifying the value here, to
|
|
113
|
+
// match what `child_process.spawn` does when loading
|
|
114
|
+
// env variables.
|
|
115
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
116
|
+
env[key] = `${value}`;
|
|
117
|
+
}
|
|
118
|
+
return env;
|
|
119
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { stat, readFile } from 'node:fs';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { extname } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { resolveEnvFilePath, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js';
|
|
6
|
+
import { checkIfTypescriptSupported } from './loaders/typescript.js';
|
|
7
|
+
const statAsync = promisify(stat);
|
|
8
|
+
const readFileAsync = promisify(readFile);
|
|
9
|
+
/**
|
|
10
|
+
* Gets the env vars from the rc file and rc environments
|
|
11
|
+
*/
|
|
12
|
+
export async function getRCFileVars({ environments, filePath }) {
|
|
13
|
+
const absolutePath = resolveEnvFilePath(filePath);
|
|
14
|
+
try {
|
|
15
|
+
await statAsync(absolutePath);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
const pathError = new Error(`Failed to find .rc file at path: ${absolutePath}`);
|
|
19
|
+
pathError.name = 'PathError';
|
|
20
|
+
throw pathError;
|
|
21
|
+
}
|
|
22
|
+
// Get the file extension
|
|
23
|
+
const ext = extname(absolutePath).toLowerCase();
|
|
24
|
+
let parsedData = {};
|
|
25
|
+
try {
|
|
26
|
+
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
|
27
|
+
if (/tsx?$/.test(ext))
|
|
28
|
+
checkIfTypescriptSupported();
|
|
29
|
+
// For some reason in ES Modules, only JSON file types need to be specifically delinated when importing them
|
|
30
|
+
let attributeTypes = {};
|
|
31
|
+
if (ext === '.json') {
|
|
32
|
+
attributeTypes = { with: { type: 'json' } };
|
|
33
|
+
}
|
|
34
|
+
const res = await import(pathToFileURL(absolutePath).href, attributeTypes);
|
|
35
|
+
if ('default' in res) {
|
|
36
|
+
parsedData = res.default;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
parsedData = res;
|
|
40
|
+
}
|
|
41
|
+
// Check to see if the imported value is a promise
|
|
42
|
+
if (isPromise(parsedData)) {
|
|
43
|
+
parsedData = await parsedData;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
const file = await readFileAsync(absolutePath, { encoding: 'utf8' });
|
|
48
|
+
parsedData = JSON.parse(file);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
const errorMessage = e instanceof Error ? e.message : 'Unknown error';
|
|
53
|
+
const parseError = new Error(`Failed to parse .rc file at path: ${absolutePath}.\n${errorMessage}`);
|
|
54
|
+
parseError.name = 'ParseError';
|
|
55
|
+
throw parseError;
|
|
56
|
+
}
|
|
57
|
+
// Parse and merge multiple rc environments together
|
|
58
|
+
let result = {};
|
|
59
|
+
let environmentFound = false;
|
|
60
|
+
for (const name of environments) {
|
|
61
|
+
if (name in parsedData) {
|
|
62
|
+
const envVars = parsedData[name];
|
|
63
|
+
if (envVars != null && typeof envVars === 'object') {
|
|
64
|
+
environmentFound = true;
|
|
65
|
+
result = {
|
|
66
|
+
...result,
|
|
67
|
+
...envVars,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!environmentFound) {
|
|
73
|
+
const environmentError = new Error(`Failed to find environments [${environments.join(',')}] at .rc file location: ${absolutePath}`);
|
|
74
|
+
environmentError.name = 'EnvironmentError';
|
|
75
|
+
throw environmentError;
|
|
76
|
+
}
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ChildProcess } from 'child_process';
|
|
2
|
+
export declare class TermSignals {
|
|
3
|
+
private readonly terminateSpawnedProcessFuncHandlers;
|
|
4
|
+
private terminateSpawnedProcessFuncExitHandler?;
|
|
5
|
+
private readonly verbose;
|
|
6
|
+
_exitCalled: boolean;
|
|
7
|
+
constructor(options?: {
|
|
8
|
+
verbose?: boolean;
|
|
9
|
+
});
|
|
10
|
+
handleTermSignals(proc: ChildProcess): void;
|
|
11
|
+
/**
|
|
12
|
+
* Enables catching of unhandled exceptions
|
|
13
|
+
*/
|
|
14
|
+
handleUncaughtExceptions(): void;
|
|
15
|
+
/**
|
|
16
|
+
* Terminate parent process helper
|
|
17
|
+
*/
|
|
18
|
+
_terminateProcess(signal?: NodeJS.Signals | number): void;
|
|
19
|
+
/**
|
|
20
|
+
* Exit event listener clean up helper
|
|
21
|
+
*/
|
|
22
|
+
_removeProcessListeners(): void;
|
|
23
|
+
/**
|
|
24
|
+
* General exception handler
|
|
25
|
+
*/
|
|
26
|
+
_uncaughtExceptionHandler(e: Error): void;
|
|
27
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
const SIGNALS_TO_HANDLE = [
|
|
2
|
+
'SIGINT', 'SIGTERM', 'SIGHUP',
|
|
3
|
+
];
|
|
4
|
+
export class TermSignals {
|
|
5
|
+
terminateSpawnedProcessFuncHandlers = {};
|
|
6
|
+
terminateSpawnedProcessFuncExitHandler;
|
|
7
|
+
verbose = false;
|
|
8
|
+
_exitCalled = false;
|
|
9
|
+
constructor(options = {}) {
|
|
10
|
+
this.verbose = options.verbose === true;
|
|
11
|
+
}
|
|
12
|
+
handleTermSignals(proc) {
|
|
13
|
+
// Terminate child process if parent process receives termination events
|
|
14
|
+
const terminationFunc = (signal) => {
|
|
15
|
+
this._removeProcessListeners();
|
|
16
|
+
if (!this._exitCalled) {
|
|
17
|
+
if (this.verbose) {
|
|
18
|
+
console.info('Parent process exited with signal: '
|
|
19
|
+
+ signal.toString()
|
|
20
|
+
+ '. Terminating child process...');
|
|
21
|
+
}
|
|
22
|
+
// Mark shared state so we do not run into a signal/exit loop
|
|
23
|
+
this._exitCalled = true;
|
|
24
|
+
// Use the signal code if it is an error code
|
|
25
|
+
// let correctSignal: NodeJS.Signals | undefined
|
|
26
|
+
if (typeof signal === 'number') {
|
|
27
|
+
if (signal > 0) {
|
|
28
|
+
// code = signal
|
|
29
|
+
signal = 'SIGINT';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
// else {
|
|
33
|
+
// correctSignal = signal
|
|
34
|
+
// }
|
|
35
|
+
// Kill the child process
|
|
36
|
+
proc.kill(signal);
|
|
37
|
+
// Terminate the parent process
|
|
38
|
+
this._terminateProcess(signal);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
for (const signal of SIGNALS_TO_HANDLE) {
|
|
42
|
+
this.terminateSpawnedProcessFuncHandlers[signal] = terminationFunc;
|
|
43
|
+
process.once(signal, this.terminateSpawnedProcessFuncHandlers[signal]);
|
|
44
|
+
}
|
|
45
|
+
this.terminateSpawnedProcessFuncExitHandler = terminationFunc;
|
|
46
|
+
process.once('exit', this.terminateSpawnedProcessFuncExitHandler);
|
|
47
|
+
// Terminate parent process if child process receives termination events
|
|
48
|
+
proc.on('exit', (code, signal) => {
|
|
49
|
+
this._removeProcessListeners();
|
|
50
|
+
if (!this._exitCalled) {
|
|
51
|
+
if (this.verbose) {
|
|
52
|
+
console.info(`Child process exited with code: ${(code ?? '').toString()} and signal:`
|
|
53
|
+
+ (signal ?? '').toString()
|
|
54
|
+
+ '. Terminating parent process...');
|
|
55
|
+
}
|
|
56
|
+
// Mark shared state so we do not run into a signal/exit loop
|
|
57
|
+
this._exitCalled = true;
|
|
58
|
+
// Use the signal code if it is an error code
|
|
59
|
+
let correctSignal;
|
|
60
|
+
if (typeof signal === 'number') {
|
|
61
|
+
if (signal > (code ?? 0)) {
|
|
62
|
+
code = signal;
|
|
63
|
+
correctSignal = 'SIGINT';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
correctSignal = signal ?? undefined;
|
|
68
|
+
}
|
|
69
|
+
// Terminate the parent process
|
|
70
|
+
this._terminateProcess(correctSignal ?? code);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Enables catching of unhandled exceptions
|
|
76
|
+
*/
|
|
77
|
+
handleUncaughtExceptions() {
|
|
78
|
+
process.on('uncaughtException', (e) => {
|
|
79
|
+
this._uncaughtExceptionHandler(e);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Terminate parent process helper
|
|
84
|
+
*/
|
|
85
|
+
_terminateProcess(signal) {
|
|
86
|
+
if (signal != null) {
|
|
87
|
+
if (typeof signal === 'string') {
|
|
88
|
+
process.kill(process.pid, signal);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (typeof signal === 'number') {
|
|
92
|
+
process.exit(signal);
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
throw new Error('Unable to terminate parent process successfully');
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Exit event listener clean up helper
|
|
100
|
+
*/
|
|
101
|
+
_removeProcessListeners() {
|
|
102
|
+
SIGNALS_TO_HANDLE.forEach((signal) => {
|
|
103
|
+
process.removeListener(signal, this.terminateSpawnedProcessFuncHandlers[signal]);
|
|
104
|
+
});
|
|
105
|
+
if (this.terminateSpawnedProcessFuncExitHandler != null) {
|
|
106
|
+
process.removeListener('exit', this.terminateSpawnedProcessFuncExitHandler);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* General exception handler
|
|
111
|
+
*/
|
|
112
|
+
_uncaughtExceptionHandler(e) {
|
|
113
|
+
console.error(e.message);
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { Command } from '@commander-js/extra-typings';
|
|
2
|
+
export type Environment = Partial<Record<string, string>>;
|
|
3
|
+
export type RCEnvironment = Partial<Record<string, Environment>>;
|
|
4
|
+
export type CommanderOptions = Command<[], {
|
|
5
|
+
environments?: true | string[];
|
|
6
|
+
expandEnvs?: boolean;
|
|
7
|
+
recursive?: boolean;
|
|
8
|
+
fallback?: boolean;
|
|
9
|
+
file?: true | string;
|
|
10
|
+
override?: boolean;
|
|
11
|
+
silent?: boolean;
|
|
12
|
+
useShell?: boolean;
|
|
13
|
+
verbose?: boolean;
|
|
14
|
+
}>;
|
|
15
|
+
export interface RCFileOptions {
|
|
16
|
+
environments: string[];
|
|
17
|
+
filePath?: string;
|
|
18
|
+
}
|
|
19
|
+
export interface EnvFileOptions {
|
|
20
|
+
filePath?: string;
|
|
21
|
+
fallback?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export interface GetEnvVarOptions {
|
|
24
|
+
envFile?: EnvFileOptions;
|
|
25
|
+
rc?: RCFileOptions;
|
|
26
|
+
verbose?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export interface EnvCmdOptions extends GetEnvVarOptions {
|
|
29
|
+
command: string;
|
|
30
|
+
commandArgs: string[];
|
|
31
|
+
options?: {
|
|
32
|
+
expandEnvs?: boolean;
|
|
33
|
+
recursive?: boolean;
|
|
34
|
+
noOverride?: boolean;
|
|
35
|
+
silent?: boolean;
|
|
36
|
+
useShell?: boolean;
|
|
37
|
+
verbose?: boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const IMPORT_HOOK_EXTENSIONS: string[];
|
|
2
|
+
/**
|
|
3
|
+
* A simple function for resolving the path the user entered
|
|
4
|
+
*/
|
|
5
|
+
export declare function resolveEnvFilePath(userPath: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* A simple function that parses a comma separated string into an array of strings
|
|
8
|
+
*/
|
|
9
|
+
export declare function parseArgList(list: string): string[];
|
|
10
|
+
/**
|
|
11
|
+
* A simple function to test if the value is a promise/thenable
|
|
12
|
+
*/
|
|
13
|
+
export declare function isPromise<T>(value?: T | PromiseLike<T>): value is PromiseLike<T>;
|
|
14
|
+
/** @returns true if the error is `ERR_UNKNOWN_FILE_EXTENSION` */
|
|
15
|
+
export declare function isLoaderError(error: unknown): error is Error;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { cwd } from 'node:process';
|
|
4
|
+
// Special file extensions that node can natively import
|
|
5
|
+
export const IMPORT_HOOK_EXTENSIONS = [
|
|
6
|
+
'.json',
|
|
7
|
+
'.js',
|
|
8
|
+
'.cjs',
|
|
9
|
+
'.mjs',
|
|
10
|
+
'.ts',
|
|
11
|
+
'.mts',
|
|
12
|
+
'.cts',
|
|
13
|
+
'.tsx',
|
|
14
|
+
];
|
|
15
|
+
/**
|
|
16
|
+
* A simple function for resolving the path the user entered
|
|
17
|
+
*/
|
|
18
|
+
export function resolveEnvFilePath(userPath) {
|
|
19
|
+
// Make sure a home directory exist
|
|
20
|
+
const home = homedir();
|
|
21
|
+
if (home != null) {
|
|
22
|
+
userPath = userPath.replace(/^~($|\/|\\)/, `${home}$1`);
|
|
23
|
+
}
|
|
24
|
+
return resolve(cwd(), userPath);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A simple function that parses a comma separated string into an array of strings
|
|
28
|
+
*/
|
|
29
|
+
export function parseArgList(list) {
|
|
30
|
+
return list.split(',');
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A simple function to test if the value is a promise/thenable
|
|
34
|
+
*/
|
|
35
|
+
export function isPromise(value) {
|
|
36
|
+
return value != null
|
|
37
|
+
&& typeof value === 'object'
|
|
38
|
+
&& 'then' in value
|
|
39
|
+
&& typeof value.then === 'function';
|
|
40
|
+
}
|
|
41
|
+
/** @returns true if the error is `ERR_UNKNOWN_FILE_EXTENSION` */
|
|
42
|
+
export function isLoaderError(error) {
|
|
43
|
+
return (error instanceof Error &&
|
|
44
|
+
'code' in error &&
|
|
45
|
+
error.code === 'ERR_UNKNOWN_FILE_EXTENSION');
|
|
46
|
+
}
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { default as tseslint } from 'typescript-eslint'
|
|
2
|
+
import { default as globals } from 'globals'
|
|
3
|
+
import { default as eslint } from '@eslint/js'
|
|
4
|
+
|
|
5
|
+
export default tseslint.config(
|
|
6
|
+
{
|
|
7
|
+
// Ignore build folder
|
|
8
|
+
ignores: ['dist/*'],
|
|
9
|
+
},
|
|
10
|
+
eslint.configs.recommended,
|
|
11
|
+
tseslint.configs.strictTypeChecked,
|
|
12
|
+
tseslint.configs.stylisticTypeChecked,
|
|
13
|
+
{
|
|
14
|
+
// Enable Type generation
|
|
15
|
+
languageOptions: {
|
|
16
|
+
globals: {
|
|
17
|
+
...globals.node,
|
|
18
|
+
},
|
|
19
|
+
parserOptions: {
|
|
20
|
+
project: ['./tsconfig.json', './test/tsconfig.json'],
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
// For test files ignore some rules
|
|
26
|
+
files: ['test/**/*'],
|
|
27
|
+
rules: {
|
|
28
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
29
|
+
'@typescript-eslint/no-unsafe-member-access': 'off',
|
|
30
|
+
'@typescript-eslint/no-unsafe-assignment': 'off'
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
// Disable Type Checking JS/CJS/MJS files
|
|
34
|
+
{
|
|
35
|
+
files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
|
|
36
|
+
extends: [tseslint.configs.disableTypeChecked],
|
|
37
|
+
},
|
|
38
|
+
)
|
package/package.json
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@depup/env-cmd",
|
|
3
|
+
"version": "11.0.0-depup.25",
|
|
4
|
+
"description": "Executes a command using the environment variables in an env file (with updated dependencies)",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"engines": {
|
|
9
|
+
"node": ">=20.10.0"
|
|
10
|
+
},
|
|
11
|
+
"bin": {
|
|
12
|
+
"env-cmd": "bin/env-cmd.js"
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"test": "mocha",
|
|
16
|
+
"test-cover": "c8 npm test",
|
|
17
|
+
"coveralls": "coveralls < coverage/lcov.info",
|
|
18
|
+
"lint": "npx eslint .",
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"watch": "tsc -w"
|
|
21
|
+
},
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+ssh://git@github.com/toddbluhm/env-cmd.git"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"env-cmd",
|
|
28
|
+
"depup",
|
|
29
|
+
"updated-dependencies",
|
|
30
|
+
"security",
|
|
31
|
+
"latest",
|
|
32
|
+
"patched",
|
|
33
|
+
"env",
|
|
34
|
+
"environment",
|
|
35
|
+
"cli",
|
|
36
|
+
"command",
|
|
37
|
+
"cmd",
|
|
38
|
+
"execute",
|
|
39
|
+
"run",
|
|
40
|
+
"file",
|
|
41
|
+
"variables",
|
|
42
|
+
"config"
|
|
43
|
+
],
|
|
44
|
+
"author": "Todd Bluhm",
|
|
45
|
+
"contributors": [
|
|
46
|
+
"Anton Versal <ant.ver@gmail.com>",
|
|
47
|
+
"Eric Lanehart <eric@pushred.co>",
|
|
48
|
+
"Jon Scheiding <jonscheiding@gmail.com>",
|
|
49
|
+
"Kyle Hensel <me@kyle.kiwi>",
|
|
50
|
+
"Nicholas Krul <nicholas.krul@gmail.com>",
|
|
51
|
+
"serapath (Alexander Praetorius) <dev@serapath.de>"
|
|
52
|
+
],
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"bugs": {
|
|
55
|
+
"url": "https://github.com/toddbluhm/env-cmd/issues"
|
|
56
|
+
},
|
|
57
|
+
"homepage": "https://github.com/toddbluhm/env-cmd#readme",
|
|
58
|
+
"dependencies": {
|
|
59
|
+
"@commander-js/extra-typings": "^15.0.0",
|
|
60
|
+
"commander": "^15.0.0",
|
|
61
|
+
"cross-spawn": "^7.0.6"
|
|
62
|
+
},
|
|
63
|
+
"devDependencies": {
|
|
64
|
+
"@commitlint/cli": "^19.6.0",
|
|
65
|
+
"@commitlint/config-conventional": "^19.6.0",
|
|
66
|
+
"@eslint/js": "^9.16.0",
|
|
67
|
+
"@types/chai": "^5.0.1",
|
|
68
|
+
"@types/cross-spawn": "^6.0.6",
|
|
69
|
+
"@types/mocha": "^10.0.10",
|
|
70
|
+
"@types/node": "^24.0.10",
|
|
71
|
+
"@types/sinon": "^17.0.3",
|
|
72
|
+
"c8": "^10.1.2",
|
|
73
|
+
"chai": "^5.1.2",
|
|
74
|
+
"coveralls": "^3.0.0",
|
|
75
|
+
"esmock": "^2.6.9",
|
|
76
|
+
"globals": "^16.0.0",
|
|
77
|
+
"husky": "^9.1.7",
|
|
78
|
+
"mocha": "^11.0.0",
|
|
79
|
+
"sinon": "^21.0.0",
|
|
80
|
+
"tsx": "^4.19.2",
|
|
81
|
+
"typescript": "^5.7.2",
|
|
82
|
+
"typescript-eslint": "^8.15.0"
|
|
83
|
+
},
|
|
84
|
+
"commitlint": {
|
|
85
|
+
"extends": [
|
|
86
|
+
"@commitlint/config-conventional"
|
|
87
|
+
]
|
|
88
|
+
},
|
|
89
|
+
"c8": {
|
|
90
|
+
"reporter": [
|
|
91
|
+
"text",
|
|
92
|
+
"lcov"
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"release": {
|
|
96
|
+
"branches": [
|
|
97
|
+
"master"
|
|
98
|
+
],
|
|
99
|
+
"tagFormat": "${version}"
|
|
100
|
+
},
|
|
101
|
+
"depup": {
|
|
102
|
+
"changes": {
|
|
103
|
+
"@commander-js/extra-typings": {
|
|
104
|
+
"from": "^13.1.0",
|
|
105
|
+
"to": "^15.0.0"
|
|
106
|
+
},
|
|
107
|
+
"commander": {
|
|
108
|
+
"from": "^13.1.0",
|
|
109
|
+
"to": "^15.0.0"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"depsUpdated": 2,
|
|
113
|
+
"originalPackage": "env-cmd",
|
|
114
|
+
"originalVersion": "11.0.0",
|
|
115
|
+
"processedAt": "2026-07-21T17:22:46.794Z",
|
|
116
|
+
"smokeTest": "passed"
|
|
117
|
+
}
|
|
118
|
+
}
|