mirror of
https://github.com/toddbluhm/env-cmd.git
synced 2025-12-08 18:23:33 +00:00
Merge pull request #382 from toddbluhm/dependabot/npm_and_yarn/typescript-5.7.2
chore(deps-dev): bump typescript from 3.9.10 to 5.7.2
This commit is contained in:
commit
175b9f4e3f
2
.github/workflows/linux-tests.yml
vendored
2
.github/workflows/linux-tests.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [10.x, 12.x, 18.x, 20.x, 22.x]
|
node-version: [18.x, 20.x, 22.x]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Project
|
- name: Checkout Project
|
||||||
|
|||||||
2
.github/workflows/windows-tests.yml
vendored
2
.github/workflows/windows-tests.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
|||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node-version: [10.x, 12.x, 18.x, 20.x, 22.x]
|
node-version: [18.x, 20.x, 22.x]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout Project
|
- name: Checkout Project
|
||||||
|
|||||||
8
dist/env-cmd.d.ts
vendored
8
dist/env-cmd.d.ts
vendored
@ -5,9 +5,7 @@ import { EnvCmdOptions } from './types';
|
|||||||
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
||||||
* @returns {Promise<{ [key: string]: any }>}
|
* @returns {Promise<{ [key: string]: any }>}
|
||||||
*/
|
*/
|
||||||
export declare function CLI(args: string[]): Promise<{
|
export declare function CLI(args: string[]): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
/**
|
/**
|
||||||
* The main env-cmd program. This will spawn a new process and run the given command using
|
* The main env-cmd program. This will spawn a new process and run the given command using
|
||||||
* various environment file solutions.
|
* various environment file solutions.
|
||||||
@ -16,6 +14,4 @@ export declare function CLI(args: string[]): Promise<{
|
|||||||
* @param {EnvCmdOptions} { command, commandArgs, envFile, rc, options }
|
* @param {EnvCmdOptions} { command, commandArgs, envFile, rc, options }
|
||||||
* @returns {Promise<{ [key: string]: any }>} Returns an object containing [environment variable name]: value
|
* @returns {Promise<{ [key: string]: any }>} Returns an object containing [environment variable name]: value
|
||||||
*/
|
*/
|
||||||
export declare function EnvCmd({ command, commandArgs, envFile, rc, options }: EnvCmdOptions): Promise<{
|
export declare function EnvCmd({ command, commandArgs, envFile, rc, options }: EnvCmdOptions): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
|
|||||||
4
dist/expand-envs.d.ts
vendored
4
dist/expand-envs.d.ts
vendored
@ -2,6 +2,4 @@
|
|||||||
* expandEnvs Replaces $var in args and command with environment variables
|
* expandEnvs Replaces $var in args and command with environment variables
|
||||||
* the environment variable doesn't exist, it leaves it as is.
|
* the environment variable doesn't exist, it leaves it as is.
|
||||||
*/
|
*/
|
||||||
export declare function expandEnvs(str: string, envs: {
|
export declare function expandEnvs(str: string, envs: Record<string, any>): string;
|
||||||
[key: string]: any;
|
|
||||||
}): string;
|
|
||||||
|
|||||||
12
dist/get-env-vars.d.ts
vendored
12
dist/get-env-vars.d.ts
vendored
@ -1,18 +1,12 @@
|
|||||||
import { GetEnvVarOptions } from './types';
|
import { GetEnvVarOptions } from './types';
|
||||||
export declare function getEnvVars(options?: GetEnvVarOptions): Promise<{
|
export declare function getEnvVars(options?: GetEnvVarOptions): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
export declare function getEnvFile({ filePath, fallback, verbose }: {
|
export declare function getEnvFile({ filePath, fallback, verbose }: {
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
fallback?: boolean;
|
fallback?: boolean;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
}): Promise<{
|
}): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
export declare function getRCFile({ environments, filePath, verbose }: {
|
export declare function getRCFile({ environments, filePath, verbose }: {
|
||||||
environments: string[];
|
environments: string[];
|
||||||
filePath?: string;
|
filePath?: string;
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
}): Promise<{
|
}): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
|
|||||||
2
dist/parse-args.js
vendored
2
dist/parse-args.js
vendored
@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||||||
const commander = require("commander");
|
const commander = require("commander");
|
||||||
const utils_1 = require("./utils");
|
const utils_1 = require("./utils");
|
||||||
// Use commonjs require to prevent a weird folder hierarchy in dist
|
// Use commonjs require to prevent a weird folder hierarchy in dist
|
||||||
const packageJson = require('../package.json'); /* eslint-disable-line */
|
const packageJson = require('../package.json');
|
||||||
/**
|
/**
|
||||||
* Parses the arguments passed into the cli
|
* Parses the arguments passed into the cli
|
||||||
*/
|
*/
|
||||||
|
|||||||
12
dist/parse-env-file.d.ts
vendored
12
dist/parse-env-file.d.ts
vendored
@ -1,21 +1,15 @@
|
|||||||
/**
|
/**
|
||||||
* Gets the environment vars from an env file
|
* Gets the environment vars from an env file
|
||||||
*/
|
*/
|
||||||
export declare function getEnvFileVars(envFilePath: string): Promise<{
|
export declare function getEnvFileVars(envFilePath: string): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
/**
|
/**
|
||||||
* Parse out all env vars from a given env file string and return an object
|
* Parse out all env vars from a given env file string and return an object
|
||||||
*/
|
*/
|
||||||
export declare function parseEnvString(envFileString: string): {
|
export declare function parseEnvString(envFileString: string): Record<string, string>;
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* Parse out all env vars from an env file string
|
* Parse out all env vars from an env file string
|
||||||
*/
|
*/
|
||||||
export declare function parseEnvVars(envString: string): {
|
export declare function parseEnvVars(envString: string): Record<string, string>;
|
||||||
[key: string]: string;
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* Strips out comments from env file string
|
* Strips out comments from env file string
|
||||||
*/
|
*/
|
||||||
|
|||||||
2
dist/parse-env-file.js
vendored
2
dist/parse-env-file.js
vendored
@ -18,7 +18,7 @@ async function getEnvFileVars(envFilePath) {
|
|||||||
const ext = path.extname(absolutePath).toLowerCase();
|
const ext = path.extname(absolutePath).toLowerCase();
|
||||||
let env = {};
|
let env = {};
|
||||||
if (REQUIRE_HOOK_EXTENSIONS.includes(ext)) {
|
if (REQUIRE_HOOK_EXTENSIONS.includes(ext)) {
|
||||||
const possiblePromise = require(absolutePath); /* eslint-disable-line */
|
const possiblePromise = require(absolutePath);
|
||||||
env = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
env = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
4
dist/parse-rc-file.d.ts
vendored
4
dist/parse-rc-file.d.ts
vendored
@ -4,6 +4,4 @@
|
|||||||
export declare function getRCFileVars({ environments, filePath }: {
|
export declare function getRCFileVars({ environments, filePath }: {
|
||||||
environments: string[];
|
environments: string[];
|
||||||
filePath: string;
|
filePath: string;
|
||||||
}): Promise<{
|
}): Promise<Record<string, any>>;
|
||||||
[key: string]: any;
|
|
||||||
}>;
|
|
||||||
|
|||||||
2
dist/parse-rc-file.js
vendored
2
dist/parse-rc-file.js
vendored
@ -24,7 +24,7 @@ async function getRCFileVars({ environments, filePath }) {
|
|||||||
let parsedData;
|
let parsedData;
|
||||||
try {
|
try {
|
||||||
if (ext === '.json' || ext === '.js' || ext === '.cjs') {
|
if (ext === '.json' || ext === '.js' || ext === '.cjs') {
|
||||||
const possiblePromise = require(absolutePath); /* eslint-disable-line */
|
const possiblePromise = require(absolutePath);
|
||||||
parsedData = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
parsedData = utils_1.isPromise(possiblePromise) ? await possiblePromise : possiblePromise;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
2
dist/utils.d.ts
vendored
2
dist/utils.d.ts
vendored
@ -9,4 +9,4 @@ export declare function parseArgList(list: string): string[];
|
|||||||
/**
|
/**
|
||||||
* A simple function to test if the value is a promise
|
* A simple function to test if the value is a promise
|
||||||
*/
|
*/
|
||||||
export declare function isPromise(value: any | PromiseLike<Object>): value is Promise<any>;
|
export declare function isPromise(value: any | PromiseLike<object>): value is Promise<any>;
|
||||||
|
|||||||
43
eslint.config.js
Normal file
43
eslint.config.js
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
const eslint = require('@eslint/js')
|
||||||
|
const tseslint = require('typescript-eslint')
|
||||||
|
const globals = require('globals')
|
||||||
|
const stylistic = require('@stylistic/eslint-plugin')
|
||||||
|
|
||||||
|
module.exports = tseslint.config(
|
||||||
|
{
|
||||||
|
ignores: ['dist/*', 'bin/*'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-require-imports': 'off',
|
||||||
|
},
|
||||||
|
languageOptions: {
|
||||||
|
globals: {
|
||||||
|
...globals.node,
|
||||||
|
},
|
||||||
|
parserOptions: {
|
||||||
|
projectService: {
|
||||||
|
allowDefaultProject: ['test/*.ts'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
eslint.configs.recommended,
|
||||||
|
stylistic.configs['recommended-flat'],
|
||||||
|
tseslint.configs.strictTypeChecked,
|
||||||
|
tseslint.configs.stylisticTypeChecked,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// Disable Type Checking JS files
|
||||||
|
{
|
||||||
|
files: ['**/*.js'],
|
||||||
|
extends: [tseslint.configs.disableTypeChecked],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
// For test files ignore some rules
|
||||||
|
files: ['test/*.ts'],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||||
|
'@typescript-eslint/no-unsafe-assignment': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
)
|
||||||
26
eslint.config.js.test
Normal file
26
eslint.config.js.test
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
module.exports = (async function config() {
|
||||||
|
const { default: love } = await import('eslint-config-love')
|
||||||
|
|
||||||
|
return [
|
||||||
|
love,
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'src/**/*.[j|t]s',
|
||||||
|
// 'src/**/*.ts',
|
||||||
|
'test/**/*.[j|t]s',
|
||||||
|
// 'test/**/*.ts'
|
||||||
|
],
|
||||||
|
languageOptions: {
|
||||||
|
parserOptions: {
|
||||||
|
projectService: {
|
||||||
|
allowDefaultProject: ['eslint.config.js', 'bin/env-cmd.js'],
|
||||||
|
defaultProject: './tsconfig.json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ignores: ['dist/'],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})()
|
||||||
15
package.json
15
package.json
@ -14,7 +14,7 @@
|
|||||||
"test": "mocha -r ts-node/register ./test/**/*.ts",
|
"test": "mocha -r ts-node/register ./test/**/*.ts",
|
||||||
"test-cover": "nyc npm test",
|
"test-cover": "nyc npm test",
|
||||||
"coveralls": "coveralls < coverage/lcov.info",
|
"coveralls": "coveralls < coverage/lcov.info",
|
||||||
"lint": "ts-standard --fix && tsc --noEmit",
|
"lint": "npx eslint .",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"watch": "tsc -w"
|
"watch": "tsc -w"
|
||||||
},
|
},
|
||||||
@ -53,6 +53,8 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^8.0.0",
|
"@commitlint/cli": "^8.0.0",
|
||||||
"@commitlint/config-conventional": "^8.0.0",
|
"@commitlint/config-conventional": "^8.0.0",
|
||||||
|
"@eslint/js": "^9.15.0",
|
||||||
|
"@stylistic/eslint-plugin": "^2.11.0",
|
||||||
"@types/chai": "^4.0.0",
|
"@types/chai": "^4.0.0",
|
||||||
"@types/cross-spawn": "^6.0.0",
|
"@types/cross-spawn": "^6.0.0",
|
||||||
"@types/mocha": "^7.0.0",
|
"@types/mocha": "^7.0.0",
|
||||||
@ -60,13 +62,14 @@
|
|||||||
"@types/sinon": "^9.0.0",
|
"@types/sinon": "^9.0.0",
|
||||||
"chai": "^4.0.0",
|
"chai": "^4.0.0",
|
||||||
"coveralls": "^3.0.0",
|
"coveralls": "^3.0.0",
|
||||||
|
"globals": "^15.12.0",
|
||||||
"husky": "^4.0.0",
|
"husky": "^4.0.0",
|
||||||
"mocha": "^7.0.0",
|
"mocha": "^7.0.0",
|
||||||
"nyc": "^15.0.0",
|
"nyc": "^15.0.0",
|
||||||
"sinon": "^9.0.0",
|
"sinon": "^9.0.0",
|
||||||
"ts-node": "^8.0.0",
|
"ts-node": "^8.0.0",
|
||||||
"ts-standard": "^8.0.0",
|
"typescript": "^5.7.2",
|
||||||
"typescript": "^3.7.0"
|
"typescript-eslint": "^8.15.0"
|
||||||
},
|
},
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"include": [
|
"include": [
|
||||||
@ -85,12 +88,6 @@
|
|||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
"instrument": true
|
"instrument": true
|
||||||
},
|
},
|
||||||
"ts-standard": {
|
|
||||||
"project": "./tsconfig.eslint.json",
|
|
||||||
"ignore": [
|
|
||||||
"dist"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"greenkeeper": {
|
"greenkeeper": {
|
||||||
"ignore": [
|
"ignore": [
|
||||||
"@types/node"
|
"@types/node"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { spawn } from './spawn'
|
import { spawn } from './spawn'
|
||||||
import { EnvCmdOptions } from './types'
|
import { EnvCmdOptions, Environment } from './types'
|
||||||
import { TermSignals } from './signal-termination'
|
import { TermSignals } from './signal-termination'
|
||||||
import { parseArgs } from './parse-args'
|
import { parseArgs } from './parse-args'
|
||||||
import { getEnvVars } from './get-env-vars'
|
import { getEnvVars } from './get-env-vars'
|
||||||
@ -9,16 +9,17 @@ import { expandEnvs } from './expand-envs'
|
|||||||
* Executes env - cmd using command line arguments
|
* Executes env - cmd using command line arguments
|
||||||
* @export
|
* @export
|
||||||
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
||||||
* @returns {Promise<{ [key: string]: any }>}
|
* @returns {Promise<Environment>}
|
||||||
*/
|
*/
|
||||||
export async function CLI (args: string[]): Promise<{ [key: string]: any }> {
|
export async function CLI(args: string[]): Promise<Environment> {
|
||||||
// Parse the args from the command line
|
// Parse the args from the command line
|
||||||
const parsedArgs = parseArgs(args)
|
const parsedArgs = parseArgs(args)
|
||||||
|
|
||||||
// Run EnvCmd
|
// Run EnvCmd
|
||||||
try {
|
try {
|
||||||
return await (exports.EnvCmd(parsedArgs) as Promise<{ [key: string]: any }>)
|
return await (exports as { EnvCmd: typeof EnvCmd }).EnvCmd(parsedArgs)
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
return process.exit(1)
|
return process.exit(1)
|
||||||
}
|
}
|
||||||
@ -30,7 +31,7 @@ export async function CLI (args: string[]): Promise<{ [key: string]: any }> {
|
|||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @param {EnvCmdOptions} { command, commandArgs, envFile, rc, options }
|
* @param {EnvCmdOptions} { command, commandArgs, envFile, rc, options }
|
||||||
* @returns {Promise<{ [key: string]: any }>} Returns an object containing [environment variable name]: value
|
* @returns {Promise<Environment>} Returns an object containing [environment variable name]: value
|
||||||
*/
|
*/
|
||||||
export async function EnvCmd(
|
export async function EnvCmd(
|
||||||
{
|
{
|
||||||
@ -38,13 +39,14 @@ export async function EnvCmd (
|
|||||||
commandArgs,
|
commandArgs,
|
||||||
envFile,
|
envFile,
|
||||||
rc,
|
rc,
|
||||||
options = {}
|
options = {},
|
||||||
}: EnvCmdOptions
|
}: EnvCmdOptions,
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<Environment> {
|
||||||
let env: { [name: string]: string } = {}
|
let env: Environment = {}
|
||||||
try {
|
try {
|
||||||
env = await getEnvVars({ envFile, rc, verbose: options.verbose })
|
env = await getEnvVars({ envFile, rc, verbose: options.verbose })
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
if (!(options.silent ?? false)) {
|
if (!(options.silent ?? false)) {
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
@ -52,7 +54,8 @@ export async function EnvCmd (
|
|||||||
// Override the merge order if --no-override flag set
|
// Override the merge order if --no-override flag set
|
||||||
if (options.noOverride === true) {
|
if (options.noOverride === true) {
|
||||||
env = Object.assign({}, env, process.env)
|
env = Object.assign({}, env, process.env)
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
// Add in the system environment variables to our environment list
|
// Add in the system environment variables to our environment list
|
||||||
env = Object.assign({}, process.env, env)
|
env = Object.assign({}, process.env, env)
|
||||||
}
|
}
|
||||||
@ -66,7 +69,7 @@ export async function EnvCmd (
|
|||||||
const proc = spawn(command, commandArgs, {
|
const proc = spawn(command, commandArgs, {
|
||||||
stdio: 'inherit',
|
stdio: 'inherit',
|
||||||
shell: options.useShell,
|
shell: options.useShell,
|
||||||
env
|
env: env as Record<string, string>,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Handle any termination signals for parent and child proceses
|
// Handle any termination signals for parent and child proceses
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
|
import { Environment } from './types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* expandEnvs Replaces $var in args and command with environment variables
|
* expandEnvs Replaces $var in args and command with environment variables
|
||||||
* the environment variable doesn't exist, it leaves it as is.
|
* if the environment variable doesn't exist, it leaves it as is.
|
||||||
*/
|
*/
|
||||||
export function expandEnvs (str: string, envs: { [key: string]: any }): string {
|
export function expandEnvs(str: string, envs: Environment): string {
|
||||||
return str.replace(/(?<!\\)\$[a-zA-Z0-9_]+/g, varName => {
|
return str.replace(/(?<!\\)\$[a-zA-Z0-9_]+/g, (varName) => {
|
||||||
const varValue = envs[varName.slice(1)]
|
const varValue = envs[varName.slice(1)]
|
||||||
return varValue === undefined ? varName : varValue
|
// const test = 42;
|
||||||
|
return varValue === undefined ? varName : varValue.toString()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,30 +1,30 @@
|
|||||||
import { GetEnvVarOptions } from './types'
|
import { GetEnvVarOptions, Environment } from './types'
|
||||||
import { getRCFileVars } from './parse-rc-file'
|
import { getRCFileVars } from './parse-rc-file'
|
||||||
import { getEnvFileVars } from './parse-env-file'
|
import { getEnvFileVars } from './parse-env-file'
|
||||||
|
|
||||||
const RC_FILE_DEFAULT_LOCATIONS = ['./.env-cmdrc', './.env-cmdrc.js', './.env-cmdrc.json']
|
const RC_FILE_DEFAULT_LOCATIONS = ['./.env-cmdrc', './.env-cmdrc.js', './.env-cmdrc.json']
|
||||||
const ENV_FILE_DEFAULT_LOCATIONS = ['./.env', './.env.js', './.env.json']
|
const ENV_FILE_DEFAULT_LOCATIONS = ['./.env', './.env.js', './.env.json']
|
||||||
|
|
||||||
export async function getEnvVars (options: GetEnvVarOptions = {}): Promise<{ [key: string]: any }> {
|
export async function getEnvVars(options: GetEnvVarOptions = {}): Promise<Environment> {
|
||||||
options.envFile = options.envFile !== undefined ? options.envFile : {}
|
options.envFile = options.envFile ?? {}
|
||||||
// Check for rc file usage
|
// Check for rc file usage
|
||||||
if (options.rc !== undefined) {
|
if (options.rc !== undefined) {
|
||||||
return await getRCFile({
|
return await getRCFile({
|
||||||
environments: options.rc.environments,
|
environments: options.rc.environments,
|
||||||
filePath: options.rc.filePath,
|
filePath: options.rc.filePath,
|
||||||
verbose: options.verbose
|
verbose: options.verbose,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return await getEnvFile({
|
return await getEnvFile({
|
||||||
filePath: options.envFile.filePath,
|
filePath: options.envFile.filePath,
|
||||||
fallback: options.envFile.fallback,
|
fallback: options.envFile.fallback,
|
||||||
verbose: options.verbose
|
verbose: options.verbose,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getEnvFile(
|
export async function getEnvFile(
|
||||||
{ filePath, fallback, verbose }: { filePath?: string, fallback?: boolean, verbose?: boolean }
|
{ filePath, fallback, verbose }: { filePath?: string, fallback?: boolean, verbose?: boolean },
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<Environment> {
|
||||||
// Use env file
|
// Use env file
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
@ -33,10 +33,12 @@ export async function getEnvFile (
|
|||||||
console.info(`Found .env file at path: ${filePath}`)
|
console.info(`Found .env file at path: ${filePath}`)
|
||||||
}
|
}
|
||||||
return env
|
return env
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
if (verbose === true) {
|
if (verbose === true) {
|
||||||
console.info(`Failed to find .env file at path: ${filePath}`)
|
console.info(`Failed to find .env file at path: ${filePath}`)
|
||||||
}
|
}
|
||||||
|
// Ignore error as we are just trying this location
|
||||||
}
|
}
|
||||||
if (fallback !== true) {
|
if (fallback !== true) {
|
||||||
throw new Error(`Failed to find .env file at path: ${filePath}`)
|
throw new Error(`Failed to find .env file at path: ${filePath}`)
|
||||||
@ -51,7 +53,10 @@ export async function getEnvFile (
|
|||||||
console.info(`Found .env file at default path: ${path}`)
|
console.info(`Found .env file at default path: ${path}`)
|
||||||
}
|
}
|
||||||
return env
|
return env
|
||||||
} catch (e) { }
|
}
|
||||||
|
catch {
|
||||||
|
// Ignore error because we are just trying this location
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const error = `Failed to find .env file at default paths: [${ENV_FILE_DEFAULT_LOCATIONS.join(',')}]`
|
const error = `Failed to find .env file at default paths: [${ENV_FILE_DEFAULT_LOCATIONS.join(',')}]`
|
||||||
@ -62,8 +67,8 @@ export async function getEnvFile (
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getRCFile(
|
export async function getRCFile(
|
||||||
{ environments, filePath, verbose }: { environments: string[], filePath?: string, verbose?: boolean }
|
{ environments, filePath, verbose }: { environments: string[], filePath?: string, verbose?: boolean },
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<Environment> {
|
||||||
// User provided an .rc file path
|
// User provided an .rc file path
|
||||||
if (filePath !== undefined) {
|
if (filePath !== undefined) {
|
||||||
try {
|
try {
|
||||||
@ -72,7 +77,9 @@ export async function getRCFile (
|
|||||||
console.info(`Found environments: [${environments.join(',')}] for .rc file at path: ${filePath}`)
|
console.info(`Found environments: [${environments.join(',')}] for .rc file at path: ${filePath}`)
|
||||||
}
|
}
|
||||||
return env
|
return env
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
if (e.name === 'PathError') {
|
if (e.name === 'PathError') {
|
||||||
if (verbose === true) {
|
if (verbose === true) {
|
||||||
console.info(`Failed to find .rc file at path: ${filePath}`)
|
console.info(`Failed to find .rc file at path: ${filePath}`)
|
||||||
@ -83,6 +90,7 @@ export async function getRCFile (
|
|||||||
console.info(`Failed to find environments: [${environments.join(',')}] for .rc file at path: ${filePath}`)
|
console.info(`Failed to find environments: [${environments.join(',')}] for .rc file at path: ${filePath}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +103,9 @@ export async function getRCFile (
|
|||||||
console.info(`Found environments: [${environments.join(',')}] for default .rc file at path: ${path}`)
|
console.info(`Found environments: [${environments.join(',')}] for default .rc file at path: ${path}`)
|
||||||
}
|
}
|
||||||
return env
|
return env
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
if (e instanceof Error) {
|
||||||
if (e.name === 'EnvironmentError') {
|
if (e.name === 'EnvironmentError') {
|
||||||
const errorText = `Failed to find environments: [${environments.join(',')}] for .rc file at path: ${path}`
|
const errorText = `Failed to find environments: [${environments.join(',')}] for .rc file at path: ${path}`
|
||||||
if (verbose === true) {
|
if (verbose === true) {
|
||||||
@ -111,6 +121,7 @@ export async function getRCFile (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const errorText = `Failed to find .rc file at default paths: [${RC_FILE_DEFAULT_LOCATIONS.join(',')}]`
|
const errorText = `Failed to find .rc file at default paths: [${RC_FILE_DEFAULT_LOCATIONS.join(',')}]`
|
||||||
if (verbose === true) {
|
if (verbose === true) {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import * as commander from 'commander'
|
import * as commander from 'commander'
|
||||||
import { EnvCmdOptions } from './types'
|
import { EnvCmdOptions, CommanderOptions, EnvFileOptions, RCFileOptions } from './types'
|
||||||
import { parseArgList } from './utils'
|
import { parseArgList } from './utils'
|
||||||
|
|
||||||
// Use commonjs require to prevent a weird folder hierarchy in dist
|
// Use commonjs require to prevent a weird folder hierarchy in dist
|
||||||
const packageJson = require('../package.json') /* eslint-disable-line */
|
const packageJson: { version: string } = require('../package.json') /* eslint-disable-line */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the arguments passed into the cli
|
* Parses the arguments passed into the cli
|
||||||
@ -42,23 +42,27 @@ export function parseArgs (args: string[]): EnvCmdOptions {
|
|||||||
silent = true
|
silent = true
|
||||||
}
|
}
|
||||||
|
|
||||||
let rc: any
|
let rc: RCFileOptions | undefined
|
||||||
if (program.environments !== undefined && program.environments.length !== 0) {
|
if (
|
||||||
|
program.environments !== undefined
|
||||||
|
&& Array.isArray(program.environments)
|
||||||
|
&& program.environments.length !== 0
|
||||||
|
) {
|
||||||
rc = {
|
rc = {
|
||||||
environments: program.environments,
|
environments: program.environments,
|
||||||
filePath: program.rcFile
|
filePath: program.rcFile,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let envFile: any
|
let envFile: EnvFileOptions | undefined
|
||||||
if (program.file !== undefined) {
|
if (program.file !== undefined) {
|
||||||
envFile = {
|
envFile = {
|
||||||
filePath: program.file,
|
filePath: program.file,
|
||||||
fallback: program.fallback
|
fallback: program.fallback,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const options = {
|
const options: EnvCmdOptions = {
|
||||||
command,
|
command,
|
||||||
commandArgs,
|
commandArgs,
|
||||||
envFile,
|
envFile,
|
||||||
@ -68,8 +72,8 @@ export function parseArgs (args: string[]): EnvCmdOptions {
|
|||||||
noOverride,
|
noOverride,
|
||||||
silent,
|
silent,
|
||||||
useShell,
|
useShell,
|
||||||
verbose
|
verbose,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
console.info(`Options: ${JSON.stringify(options, null, 0)}`)
|
console.info(`Options: ${JSON.stringify(options, null, 0)}`)
|
||||||
@ -77,8 +81,8 @@ export function parseArgs (args: string[]): EnvCmdOptions {
|
|||||||
return options
|
return options
|
||||||
}
|
}
|
||||||
|
|
||||||
export function parseArgsUsingCommander (args: string[]): commander.Command {
|
export function parseArgsUsingCommander(args: string[]): CommanderOptions {
|
||||||
const program = new commander.Command()
|
const program = new commander.Command() as CommanderOptions
|
||||||
return program
|
return program
|
||||||
.version(packageJson.version, '-v, --version')
|
.version(packageJson.version, '-v, --version')
|
||||||
.usage('[options] <command> [...args]')
|
.usage('[options] <command> [...args]')
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { resolveEnvFilePath, isPromise } from './utils'
|
import { resolveEnvFilePath, isPromise } from './utils'
|
||||||
|
import { Environment } from './types'
|
||||||
|
|
||||||
const REQUIRE_HOOK_EXTENSIONS = ['.json', '.js', '.cjs']
|
const REQUIRE_HOOK_EXTENSIONS = ['.json', '.js', '.cjs']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the environment vars from an env file
|
* Gets the environment vars from an env file
|
||||||
*/
|
*/
|
||||||
export async function getEnvFileVars (envFilePath: string): Promise<{ [key: string]: any }> {
|
export async function getEnvFileVars(envFilePath: string): Promise<Environment> {
|
||||||
const absolutePath = resolveEnvFilePath(envFilePath)
|
const absolutePath = resolveEnvFilePath(envFilePath)
|
||||||
if (!fs.existsSync(absolutePath)) {
|
if (!fs.existsSync(absolutePath)) {
|
||||||
const pathError = new Error(`Invalid env file path (${envFilePath}).`)
|
const pathError = new Error(`Invalid env file path (${envFilePath}).`)
|
||||||
@ -17,11 +18,12 @@ export async function getEnvFileVars (envFilePath: string): Promise<{ [key: stri
|
|||||||
|
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = path.extname(absolutePath).toLowerCase()
|
const ext = path.extname(absolutePath).toLowerCase()
|
||||||
let env = {}
|
let env: Environment = {}
|
||||||
if (REQUIRE_HOOK_EXTENSIONS.includes(ext)) {
|
if (REQUIRE_HOOK_EXTENSIONS.includes(ext)) {
|
||||||
const possiblePromise = require(absolutePath) /* eslint-disable-line */
|
const possiblePromise: Environment | Promise<Environment> = require(absolutePath) /* eslint-disable-line */
|
||||||
env = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
env = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
const file = fs.readFileSync(absolutePath, { encoding: 'utf8' })
|
const file = fs.readFileSync(absolutePath, { encoding: 'utf8' })
|
||||||
env = parseEnvString(file)
|
env = parseEnvString(file)
|
||||||
}
|
}
|
||||||
@ -31,7 +33,7 @@ export async function getEnvFileVars (envFilePath: string): Promise<{ [key: stri
|
|||||||
/**
|
/**
|
||||||
* Parse out all env vars from a given env file string and return an object
|
* Parse out all env vars from a given env file string and return an object
|
||||||
*/
|
*/
|
||||||
export function parseEnvString (envFileString: string): { [key: string]: string } {
|
export function parseEnvString(envFileString: string): Environment {
|
||||||
// First thing we do is stripe out all comments
|
// First thing we do is stripe out all comments
|
||||||
envFileString = stripComments(envFileString.toString())
|
envFileString = stripComments(envFileString.toString())
|
||||||
|
|
||||||
@ -45,21 +47,35 @@ export function parseEnvString (envFileString: string): { [key: string]: string
|
|||||||
/**
|
/**
|
||||||
* Parse out all env vars from an env file string
|
* Parse out all env vars from an env file string
|
||||||
*/
|
*/
|
||||||
export function parseEnvVars (envString: string): { [key: string]: string } {
|
export function parseEnvVars(envString: string): Environment {
|
||||||
const envParseRegex = /^((.+?)[=](.*))$/gim
|
const envParseRegex = /^((.+?)[=](.*))$/gim
|
||||||
const matches: { [key: string]: string } = {}
|
const matches: Environment = {}
|
||||||
let match
|
let match
|
||||||
while ((match = envParseRegex.exec(envString)) !== null) {
|
while ((match = envParseRegex.exec(envString)) !== null) {
|
||||||
// Note: match[1] is the full env=var line
|
// Note: match[1] is the full env=var line
|
||||||
const key = match[2].trim()
|
const key = match[2].trim()
|
||||||
const value = match[3].trim()
|
let value: string | number | boolean = match[3].trim()
|
||||||
|
|
||||||
// remove any surrounding quotes
|
// remove any surrounding quotes
|
||||||
matches[key] = value
|
value = value
|
||||||
.replace(/(^['"]|['"]$)/g, '')
|
.replace(/(^['"]|['"]$)/g, '')
|
||||||
.replace(/\\n/g, '\n')
|
.replace(/\\n/g, '\n')
|
||||||
|
|
||||||
|
// Convert string to JS type if appropriate
|
||||||
|
if (value !== '' && !isNaN(+value)) {
|
||||||
|
matches[key] = +value
|
||||||
}
|
}
|
||||||
return matches
|
else if (value === 'true') {
|
||||||
|
matches[key] = true
|
||||||
|
}
|
||||||
|
else if (value === 'false') {
|
||||||
|
matches[key] = false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
matches[key] = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return JSON.parse(JSON.stringify(matches)) as Environment
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { stat, readFile } from 'fs'
|
|||||||
import { promisify } from 'util'
|
import { promisify } from 'util'
|
||||||
import { extname } from 'path'
|
import { extname } from 'path'
|
||||||
import { resolveEnvFilePath, isPromise } from './utils'
|
import { resolveEnvFilePath, isPromise } from './utils'
|
||||||
|
import { Environment, RCEnvironment } from './types'
|
||||||
|
|
||||||
const statAsync = promisify(stat)
|
const statAsync = promisify(stat)
|
||||||
const readFileAsync = promisify(readFile)
|
const readFileAsync = promisify(readFile)
|
||||||
@ -11,12 +12,13 @@ const readFileAsync = promisify(readFile)
|
|||||||
*/
|
*/
|
||||||
export async function getRCFileVars(
|
export async function getRCFileVars(
|
||||||
{ environments, filePath }:
|
{ environments, filePath }:
|
||||||
{ environments: string[], filePath: string }
|
{ environments: string[], filePath: string },
|
||||||
): Promise<{ [key: string]: any }> {
|
): Promise<Environment> {
|
||||||
const absolutePath = resolveEnvFilePath(filePath)
|
const absolutePath = resolveEnvFilePath(filePath)
|
||||||
try {
|
try {
|
||||||
await statAsync(absolutePath)
|
await statAsync(absolutePath)
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
const pathError = new Error(`Failed to find .rc file at path: ${absolutePath}`)
|
const pathError = new Error(`Failed to find .rc file at path: ${absolutePath}`)
|
||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
throw pathError
|
throw pathError
|
||||||
@ -24,41 +26,45 @@ export async function getRCFileVars (
|
|||||||
|
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = extname(absolutePath).toLowerCase()
|
const ext = extname(absolutePath).toLowerCase()
|
||||||
let parsedData: { [key: string]: any }
|
let parsedData: Partial<RCEnvironment>
|
||||||
try {
|
try {
|
||||||
if (ext === '.json' || ext === '.js' || ext === '.cjs') {
|
if (ext === '.json' || ext === '.js' || ext === '.cjs') {
|
||||||
const possiblePromise = require(absolutePath) /* eslint-disable-line */
|
const possiblePromise = require(absolutePath) as PromiseLike<RCEnvironment> | RCEnvironment
|
||||||
parsedData = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
parsedData = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
||||||
} else {
|
|
||||||
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
|
||||||
parsedData = JSON.parse(file)
|
|
||||||
}
|
}
|
||||||
} catch (e) {
|
else {
|
||||||
|
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
||||||
|
parsedData = JSON.parse(file) as Partial<RCEnvironment>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
const errorMessage = e instanceof Error ? e.message : 'Unknown error'
|
const errorMessage = e instanceof Error ? e.message : 'Unknown error'
|
||||||
const parseError = new Error(
|
const parseError = new Error(
|
||||||
`Failed to parse .rc file at path: ${absolutePath}.\n${errorMessage}`
|
`Failed to parse .rc file at path: ${absolutePath}.\n${errorMessage}`,
|
||||||
)
|
)
|
||||||
parseError.name = 'ParseError'
|
parseError.name = 'ParseError'
|
||||||
throw parseError
|
throw parseError
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse and merge multiple rc environments together
|
// Parse and merge multiple rc environments together
|
||||||
let result = {}
|
let result: Environment = {}
|
||||||
let environmentFound = false
|
let environmentFound = false
|
||||||
environments.forEach((name): void => {
|
for (const name of environments) {
|
||||||
|
if (name in parsedData) {
|
||||||
const envVars = parsedData[name]
|
const envVars = parsedData[name]
|
||||||
if (envVars !== undefined) {
|
if (envVars != null && typeof envVars === 'object') {
|
||||||
environmentFound = true
|
environmentFound = true
|
||||||
result = {
|
result = {
|
||||||
...result,
|
...result,
|
||||||
...envVars
|
...envVars,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
if (!environmentFound) {
|
if (!environmentFound) {
|
||||||
const environmentError = new Error(
|
const environmentError = new Error(
|
||||||
`Failed to find environments [${environments.join(',')}] at .rc file location: ${absolutePath}`
|
`Failed to find environments [${environments.join(',')}] at .rc file location: ${absolutePath}`,
|
||||||
)
|
)
|
||||||
environmentError.name = 'EnvironmentError'
|
environmentError.name = 'EnvironmentError'
|
||||||
throw environmentError
|
throw environmentError
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import { ChildProcess } from 'child_process'
|
import { ChildProcess } from 'child_process'
|
||||||
|
|
||||||
const SIGNALS_TO_HANDLE: NodeJS.Signals[] = [
|
const SIGNALS_TO_HANDLE: NodeJS.Signals[] = [
|
||||||
'SIGINT', 'SIGTERM', 'SIGHUP'
|
'SIGINT', 'SIGTERM', 'SIGHUP',
|
||||||
]
|
]
|
||||||
|
|
||||||
export class TermSignals {
|
export class TermSignals {
|
||||||
private readonly terminateSpawnedProcessFuncHandlers: { [key: string]: any } = {}
|
private readonly terminateSpawnedProcessFuncHandlers: Record<string, NodeJS.SignalsListener> = {}
|
||||||
|
private terminateSpawnedProcessFuncExitHandler?: NodeJS.ExitListener
|
||||||
private readonly verbose: boolean = false
|
private readonly verbose: boolean = false
|
||||||
public _exitCalled = false
|
public _exitCalled = false
|
||||||
|
|
||||||
@ -15,38 +16,41 @@ export class TermSignals {
|
|||||||
|
|
||||||
public handleTermSignals(proc: ChildProcess): void {
|
public handleTermSignals(proc: ChildProcess): void {
|
||||||
// Terminate child process if parent process receives termination events
|
// Terminate child process if parent process receives termination events
|
||||||
SIGNALS_TO_HANDLE.forEach((signal): void => {
|
const terminationFunc = (signal: NodeJS.Signals | number): void => {
|
||||||
this.terminateSpawnedProcessFuncHandlers[signal] =
|
|
||||||
(signal: NodeJS.Signals | number, code: number): void => {
|
|
||||||
this._removeProcessListeners()
|
this._removeProcessListeners()
|
||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
if (this.verbose) {
|
if (this.verbose) {
|
||||||
console.info(
|
console.info(
|
||||||
'Parent process exited with signal: ' +
|
'Parent process exited with signal: '
|
||||||
signal.toString() +
|
+ signal.toString()
|
||||||
'. Terminating child process...')
|
+ '. Terminating child process...')
|
||||||
}
|
}
|
||||||
// Mark shared state so we do not run into a signal/exit loop
|
// Mark shared state so we do not run into a signal/exit loop
|
||||||
this._exitCalled = true
|
this._exitCalled = true
|
||||||
// Use the signal code if it is an error code
|
// Use the signal code if it is an error code
|
||||||
let correctSignal: NodeJS.Signals | undefined
|
// let correctSignal: NodeJS.Signals | undefined
|
||||||
if (typeof signal === 'number') {
|
if (typeof signal === 'number') {
|
||||||
if (signal > (code ?? 0)) {
|
if (signal > 0) {
|
||||||
code = signal
|
// code = signal
|
||||||
correctSignal = 'SIGINT'
|
signal = 'SIGINT'
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
correctSignal = signal
|
|
||||||
}
|
}
|
||||||
|
// else {
|
||||||
|
// correctSignal = signal
|
||||||
|
// }
|
||||||
// Kill the child process
|
// Kill the child process
|
||||||
proc.kill(correctSignal ?? code)
|
proc.kill(signal)
|
||||||
// Terminate the parent process
|
// Terminate the parent process
|
||||||
this._terminateProcess(code, correctSignal)
|
this._terminateProcess(signal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const signal of SIGNALS_TO_HANDLE) {
|
||||||
|
this.terminateSpawnedProcessFuncHandlers[signal] = terminationFunc
|
||||||
process.once(signal, this.terminateSpawnedProcessFuncHandlers[signal])
|
process.once(signal, this.terminateSpawnedProcessFuncHandlers[signal])
|
||||||
})
|
}
|
||||||
process.once('exit', this.terminateSpawnedProcessFuncHandlers.SIGTERM)
|
this.terminateSpawnedProcessFuncExitHandler = terminationFunc
|
||||||
|
process.once('exit', this.terminateSpawnedProcessFuncExitHandler)
|
||||||
|
|
||||||
// Terminate parent process if child process receives termination events
|
// Terminate parent process if child process receives termination events
|
||||||
proc.on('exit', (code: number | undefined, signal: NodeJS.Signals | number | null): void => {
|
proc.on('exit', (code: number | undefined, signal: NodeJS.Signals | number | null): void => {
|
||||||
@ -54,9 +58,9 @@ export class TermSignals {
|
|||||||
if (!this._exitCalled) {
|
if (!this._exitCalled) {
|
||||||
if (this.verbose) {
|
if (this.verbose) {
|
||||||
console.info(
|
console.info(
|
||||||
`Child process exited with code: ${(code ?? '').toString()} and signal:` +
|
`Child process exited with code: ${(code ?? '').toString()} and signal:`
|
||||||
(signal ?? '').toString() +
|
+ (signal ?? '').toString()
|
||||||
'. Terminating parent process...'
|
+ '. Terminating parent process...',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// Mark shared state so we do not run into a signal/exit loop
|
// Mark shared state so we do not run into a signal/exit loop
|
||||||
@ -68,11 +72,12 @@ export class TermSignals {
|
|||||||
code = signal
|
code = signal
|
||||||
correctSignal = 'SIGINT'
|
correctSignal = 'SIGINT'
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
correctSignal = signal ?? undefined
|
correctSignal = signal ?? undefined
|
||||||
}
|
}
|
||||||
// Terminate the parent process
|
// Terminate the parent process
|
||||||
this._terminateProcess(code, correctSignal)
|
this._terminateProcess(correctSignal ?? code)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -81,20 +86,24 @@ export class TermSignals {
|
|||||||
* Enables catching of unhandled exceptions
|
* Enables catching of unhandled exceptions
|
||||||
*/
|
*/
|
||||||
public handleUncaughtExceptions(): void {
|
public handleUncaughtExceptions(): void {
|
||||||
process.on('uncaughtException', (e): void => this._uncaughtExceptionHandler(e))
|
process.on('uncaughtException', (e): void => {
|
||||||
|
this._uncaughtExceptionHandler(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Terminate parent process helper
|
* Terminate parent process helper
|
||||||
*/
|
*/
|
||||||
public _terminateProcess (code?: number, signal?: NodeJS.Signals): void {
|
public _terminateProcess(signal?: NodeJS.Signals | number): void {
|
||||||
if (signal !== undefined) {
|
if (signal != null) {
|
||||||
|
if (typeof signal === 'string') {
|
||||||
process.kill(process.pid, signal)
|
process.kill(process.pid, signal)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (code !== undefined) {
|
if (typeof signal === 'number') {
|
||||||
process.exit(code)
|
process.exit(signal)
|
||||||
return // eslint-disable-line no-unreachable
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
throw new Error('Unable to terminate parent process successfully')
|
throw new Error('Unable to terminate parent process successfully')
|
||||||
}
|
}
|
||||||
@ -106,7 +115,9 @@ export class TermSignals {
|
|||||||
SIGNALS_TO_HANDLE.forEach((signal): void => {
|
SIGNALS_TO_HANDLE.forEach((signal): void => {
|
||||||
process.removeListener(signal, this.terminateSpawnedProcessFuncHandlers[signal])
|
process.removeListener(signal, this.terminateSpawnedProcessFuncHandlers[signal])
|
||||||
})
|
})
|
||||||
process.removeListener('exit', this.terminateSpawnedProcessFuncHandlers.SIGTERM)
|
if (this.terminateSpawnedProcessFuncExitHandler != null) {
|
||||||
|
process.removeListener('exit', this.terminateSpawnedProcessFuncExitHandler)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import * as spawn from 'cross-spawn'
|
import * as spawn from 'cross-spawn'
|
||||||
export {
|
export {
|
||||||
spawn
|
spawn,
|
||||||
}
|
}
|
||||||
|
|||||||
35
src/types.ts
35
src/types.ts
@ -1,16 +1,39 @@
|
|||||||
export interface GetEnvVarOptions {
|
import { Command } from 'commander'
|
||||||
envFile?: {
|
|
||||||
filePath?: string
|
// Define an export type
|
||||||
fallback?: boolean
|
export type Environment = Partial<Record<string, string | number | boolean>>
|
||||||
|
|
||||||
|
export type RCEnvironment = Partial<Record<string, Environment>>
|
||||||
|
|
||||||
|
export interface CommanderOptions extends Command {
|
||||||
|
override?: boolean // Default: false
|
||||||
|
useShell?: boolean // Default: false
|
||||||
|
expandEnvs?: boolean // Default: false
|
||||||
|
verbose?: boolean // Default: false
|
||||||
|
silent?: boolean // Default: false
|
||||||
|
fallback?: boolean // Default false
|
||||||
|
environments?: string[]
|
||||||
|
rcFile?: string
|
||||||
|
file?: string
|
||||||
}
|
}
|
||||||
rc?: {
|
|
||||||
|
export interface RCFileOptions {
|
||||||
environments: string[]
|
environments: string[]
|
||||||
filePath?: string
|
filePath?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EnvFileOptions {
|
||||||
|
filePath?: string
|
||||||
|
fallback?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetEnvVarOptions {
|
||||||
|
envFile?: EnvFileOptions
|
||||||
|
rc?: RCFileOptions
|
||||||
verbose?: boolean
|
verbose?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EnvCmdOptions extends Pick<GetEnvVarOptions, 'envFile' | 'rc'> {
|
export interface EnvCmdOptions extends GetEnvVarOptions {
|
||||||
command: string
|
command: string
|
||||||
commandArgs: string[]
|
commandArgs: string[]
|
||||||
options?: {
|
options?: {
|
||||||
|
|||||||
13
src/utils.ts
13
src/utils.ts
@ -6,8 +6,8 @@ import * as os from 'os'
|
|||||||
*/
|
*/
|
||||||
export function resolveEnvFilePath(userPath: string): string {
|
export function resolveEnvFilePath(userPath: string): string {
|
||||||
// Make sure a home directory exist
|
// Make sure a home directory exist
|
||||||
const home = os.homedir()
|
const home = os.homedir() as string | undefined
|
||||||
if (home !== undefined) {
|
if (home != null) {
|
||||||
userPath = userPath.replace(/^~($|\/|\\)/, `${home}$1`)
|
userPath = userPath.replace(/^~($|\/|\\)/, `${home}$1`)
|
||||||
}
|
}
|
||||||
return path.resolve(process.cwd(), userPath)
|
return path.resolve(process.cwd(), userPath)
|
||||||
@ -20,8 +20,11 @@ export function parseArgList (list: string): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple function to test if the value is a promise
|
* A simple function to test if the value is a promise/thenable
|
||||||
*/
|
*/
|
||||||
export function isPromise (value: any | PromiseLike<Object>): value is Promise<any> {
|
export function isPromise<T>(value?: T | PromiseLike<T>): value is PromiseLike<T> {
|
||||||
return value != null && typeof value.then === 'function'
|
return value != null
|
||||||
|
&& typeof value === 'object'
|
||||||
|
&& 'then' in value
|
||||||
|
&& typeof value.then === 'function'
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,9 +9,9 @@ import * as envCmdLib from '../src/env-cmd'
|
|||||||
|
|
||||||
describe('CLI', (): void => {
|
describe('CLI', (): void => {
|
||||||
let sandbox: sinon.SinonSandbox
|
let sandbox: sinon.SinonSandbox
|
||||||
let parseArgsStub: sinon.SinonStub<any, any>
|
let parseArgsStub: sinon.SinonStub<any>
|
||||||
let envCmdStub: sinon.SinonStub<any, any>
|
let envCmdStub: sinon.SinonStub<any>
|
||||||
let processExitStub: sinon.SinonStub<any, any>
|
let processExitStub: sinon.SinonStub<any>
|
||||||
before((): void => {
|
before((): void => {
|
||||||
sandbox = sinon.createSandbox()
|
sandbox = sinon.createSandbox()
|
||||||
parseArgsStub = sandbox.stub(parseArgsLib, 'parseArgs')
|
parseArgsStub = sandbox.stub(parseArgsLib, 'parseArgs')
|
||||||
@ -49,16 +49,16 @@ describe('CLI', (): void => {
|
|||||||
|
|
||||||
describe('EnvCmd', (): void => {
|
describe('EnvCmd', (): void => {
|
||||||
let sandbox: sinon.SinonSandbox
|
let sandbox: sinon.SinonSandbox
|
||||||
let getEnvVarsStub: sinon.SinonStub<any, any>
|
let getEnvVarsStub: sinon.SinonStub<any>
|
||||||
let spawnStub: sinon.SinonStub<any, any>
|
let spawnStub: sinon.SinonStub<any>
|
||||||
let expandEnvsSpy: sinon.SinonSpy<any, any>
|
let expandEnvsSpy: sinon.SinonSpy<any>
|
||||||
before((): void => {
|
before((): void => {
|
||||||
sandbox = sinon.createSandbox()
|
sandbox = sinon.createSandbox()
|
||||||
getEnvVarsStub = sandbox.stub(getEnvVarsLib, 'getEnvVars')
|
getEnvVarsStub = sandbox.stub(getEnvVarsLib, 'getEnvVars')
|
||||||
spawnStub = sandbox.stub(spawnLib, 'spawn')
|
spawnStub = sandbox.stub(spawnLib, 'spawn')
|
||||||
spawnStub.returns({
|
spawnStub.returns({
|
||||||
on: (): void => { /* Fake the on method */ },
|
on: (): void => { /* Fake the on method */ },
|
||||||
kill: (): void => { /* Fake the kill method */ }
|
kill: (): void => { /* Fake the kill method */ },
|
||||||
})
|
})
|
||||||
expandEnvsSpy = sandbox.spy(expandEnvsLib, 'expandEnvs')
|
expandEnvsSpy = sandbox.spy(expandEnvsLib, 'expandEnvs')
|
||||||
sandbox.stub(signalTermLib.TermSignals.prototype, 'handleTermSignals')
|
sandbox.stub(signalTermLib.TermSignals.prototype, 'handleTermSignals')
|
||||||
@ -80,12 +80,12 @@ describe('EnvCmd', (): void => {
|
|||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env',
|
filePath: './.env',
|
||||||
fallback: true
|
fallback: true,
|
||||||
},
|
},
|
||||||
rc: {
|
rc: {
|
||||||
environments: ['dev'],
|
environments: ['dev'],
|
||||||
filePath: './.rc'
|
filePath: './.rc',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
assert.equal(getEnvVarsStub.callCount, 1)
|
assert.equal(getEnvVarsStub.callCount, 1)
|
||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
@ -100,17 +100,17 @@ describe('EnvCmd', (): void => {
|
|||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env',
|
filePath: './.env',
|
||||||
fallback: true
|
fallback: true,
|
||||||
},
|
},
|
||||||
rc: {
|
rc: {
|
||||||
environments: ['dev'],
|
environments: ['dev'],
|
||||||
filePath: './.rc'
|
filePath: './.rc',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
assert.equal(getEnvVarsStub.callCount, 1)
|
assert.equal(getEnvVarsStub.callCount, 1)
|
||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
assert.equal(spawnStub.args[0][2].env.BOB, 'test')
|
assert.equal(spawnStub.args[0][2].env.BOB, 'test')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should not override existing env vars if noOverride option is true',
|
it('should not override existing env vars if noOverride option is true',
|
||||||
@ -122,20 +122,20 @@ describe('EnvCmd', (): void => {
|
|||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env',
|
filePath: './.env',
|
||||||
fallback: true
|
fallback: true,
|
||||||
},
|
},
|
||||||
rc: {
|
rc: {
|
||||||
environments: ['dev'],
|
environments: ['dev'],
|
||||||
filePath: './.rc'
|
filePath: './.rc',
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
noOverride: true
|
noOverride: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
assert.equal(getEnvVarsStub.callCount, 1)
|
assert.equal(getEnvVarsStub.callCount, 1)
|
||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
assert.equal(spawnStub.args[0][2].env.BOB, 'cool')
|
assert.equal(spawnStub.args[0][2].env.BOB, 'cool')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should spawn process with shell option if useShell option is true',
|
it('should spawn process with shell option if useShell option is true',
|
||||||
@ -147,20 +147,20 @@ describe('EnvCmd', (): void => {
|
|||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env',
|
filePath: './.env',
|
||||||
fallback: true
|
fallback: true,
|
||||||
},
|
},
|
||||||
rc: {
|
rc: {
|
||||||
environments: ['dev'],
|
environments: ['dev'],
|
||||||
filePath: './.rc'
|
filePath: './.rc',
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
useShell: true
|
useShell: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
assert.equal(getEnvVarsStub.callCount, 1)
|
assert.equal(getEnvVarsStub.callCount, 1)
|
||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
assert.equal(spawnStub.args[0][2].shell, true)
|
assert.equal(spawnStub.args[0][2].shell, true)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should spawn process with command and args expanded if expandEnvs option is true',
|
it('should spawn process with command and args expanded if expandEnvs option is true',
|
||||||
@ -171,15 +171,15 @@ describe('EnvCmd', (): void => {
|
|||||||
commandArgs: ['$PING', '\\$IP'],
|
commandArgs: ['$PING', '\\$IP'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env',
|
filePath: './.env',
|
||||||
fallback: true
|
fallback: true,
|
||||||
},
|
},
|
||||||
rc: {
|
rc: {
|
||||||
environments: ['dev'],
|
environments: ['dev'],
|
||||||
filePath: './.rc'
|
filePath: './.rc',
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
expandEnvs: true
|
expandEnvs: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const spawnArgs = spawnStub.args[0]
|
const spawnArgs = spawnStub.args[0]
|
||||||
@ -188,9 +188,9 @@ describe('EnvCmd', (): void => {
|
|||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
assert.equal(expandEnvsSpy.callCount, 3, 'command + number of args')
|
assert.equal(expandEnvsSpy.callCount, 3, 'command + number of args')
|
||||||
assert.equal(spawnArgs[0], 'node')
|
assert.equal(spawnArgs[0], 'node')
|
||||||
assert.sameOrderedMembers(spawnArgs[1], ['PONG', '\\$IP'])
|
assert.sameOrderedMembers(spawnArgs[1] as string[], ['PONG', '\\$IP'])
|
||||||
assert.equal(spawnArgs[2].env.PING, 'PONG')
|
assert.equal(spawnArgs[2].env.PING, 'PONG')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should ignore errors if silent flag provided',
|
it('should ignore errors if silent flag provided',
|
||||||
@ -201,16 +201,16 @@ describe('EnvCmd', (): void => {
|
|||||||
command: 'node',
|
command: 'node',
|
||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env'
|
filePath: './.env',
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
silent: true
|
silent: true,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
assert.equal(getEnvVarsStub.callCount, 1)
|
assert.equal(getEnvVarsStub.callCount, 1)
|
||||||
assert.equal(spawnStub.callCount, 1)
|
assert.equal(spawnStub.callCount, 1)
|
||||||
assert.isUndefined(spawnStub.args[0][2].env.BOB)
|
assert.isUndefined(spawnStub.args[0][2].env.BOB)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should allow errors if silent flag not provided',
|
it('should allow errors if silent flag not provided',
|
||||||
@ -221,14 +221,16 @@ describe('EnvCmd', (): void => {
|
|||||||
command: 'node',
|
command: 'node',
|
||||||
commandArgs: ['-v'],
|
commandArgs: ['-v'],
|
||||||
envFile: {
|
envFile: {
|
||||||
filePath: './.env'
|
filePath: './.env',
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.equal(e.name, 'MissingFile')
|
assert.equal(e.name, 'MissingFile')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
assert.fail('Should not get here.')
|
assert.fail('Should not get here.')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,7 +7,9 @@ describe('expandEnvs', (): void => {
|
|||||||
notvar: 'this is not used',
|
notvar: 'this is not used',
|
||||||
dollar: 'money',
|
dollar: 'money',
|
||||||
PING: 'PONG',
|
PING: 'PONG',
|
||||||
IP1: '127.0.0.1'
|
IP1: '127.0.0.1',
|
||||||
|
THANKSFORALLTHEFISH: 42,
|
||||||
|
BRINGATOWEL: true,
|
||||||
}
|
}
|
||||||
const args = ['notvar', '$dollar', '\\$notvar', '-4', '$PING', '$IP1', '\\$IP1', '$NONEXIST']
|
const args = ['notvar', '$dollar', '\\$notvar', '-4', '$PING', '$IP1', '\\$IP1', '$NONEXIST']
|
||||||
const argsExpanded = ['notvar', 'money', '\\$notvar', '-4', 'PONG', '127.0.0.1', '\\$IP1', '$NONEXIST']
|
const argsExpanded = ['notvar', 'money', '\\$notvar', '-4', 'PONG', '127.0.0.1', '\\$IP1', '$NONEXIST']
|
||||||
@ -15,5 +17,8 @@ describe('expandEnvs', (): void => {
|
|||||||
it('should replace environment variables in args', (): void => {
|
it('should replace environment variables in args', (): void => {
|
||||||
const res = args.map(arg => expandEnvs(arg, envs))
|
const res = args.map(arg => expandEnvs(arg, envs))
|
||||||
assert.sameOrderedMembers(res, argsExpanded)
|
assert.sameOrderedMembers(res, argsExpanded)
|
||||||
|
for (const arg of args) {
|
||||||
|
assert.typeOf(arg, 'string')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,9 +5,9 @@ import * as rcFile from '../src/parse-rc-file'
|
|||||||
import * as envFile from '../src/parse-env-file'
|
import * as envFile from '../src/parse-env-file'
|
||||||
|
|
||||||
describe('getEnvVars', (): void => {
|
describe('getEnvVars', (): void => {
|
||||||
let getRCFileVarsStub: sinon.SinonStub<any, any>
|
let getRCFileVarsStub: sinon.SinonStub<any>
|
||||||
let getEnvFileVarsStub: sinon.SinonStub<any, any>
|
let getEnvFileVarsStub: sinon.SinonStub<any>
|
||||||
let logInfoStub: sinon.SinonStub<any, any>
|
let logInfoStub: sinon.SinonStub<any> | undefined
|
||||||
|
|
||||||
before((): void => {
|
before((): void => {
|
||||||
getRCFileVarsStub = sinon.stub(rcFile, 'getRCFileVars')
|
getRCFileVarsStub = sinon.stub(rcFile, 'getRCFileVars')
|
||||||
@ -21,9 +21,7 @@ describe('getEnvVars', (): void => {
|
|||||||
afterEach((): void => {
|
afterEach((): void => {
|
||||||
sinon.resetHistory()
|
sinon.resetHistory()
|
||||||
sinon.resetBehavior()
|
sinon.resetBehavior()
|
||||||
if (logInfoStub !== undefined) {
|
logInfoStub?.restore()
|
||||||
logInfoStub.restore()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse the json .rc file from the default path with the given environment',
|
it('should parse the json .rc file from the default path with the given environment',
|
||||||
@ -37,7 +35,7 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.lengthOf(getRCFileVarsStub.args[0][0].environments, 1)
|
assert.lengthOf(getRCFileVarsStub.args[0][0].environments, 1)
|
||||||
assert.equal(getRCFileVarsStub.args[0][0].environments[0], 'production')
|
assert.equal(getRCFileVarsStub.args[0][0].environments[0], 'production')
|
||||||
assert.equal(getRCFileVarsStub.args[0][0].filePath, './.env-cmdrc')
|
assert.equal(getRCFileVarsStub.args[0][0].filePath, './.env-cmdrc')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should print path of custom .rc file and environments to info for verbose',
|
it('should print path of custom .rc file and environments to info for verbose',
|
||||||
@ -46,7 +44,7 @@ describe('getEnvVars', (): void => {
|
|||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should search all default .rc file paths', async (): Promise<void> => {
|
it('should search all default .rc file paths', async (): Promise<void> => {
|
||||||
@ -71,7 +69,9 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] } })
|
await getEnvVars({ rc: { environments: ['production'] } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
assert.match(e.message, /\.rc file/gi)
|
assert.match(e.message, /\.rc file/gi)
|
||||||
assert.match(e.message, /default paths/gi)
|
assert.match(e.message, /default paths/gi)
|
||||||
@ -86,7 +86,8 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -98,7 +99,9 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['bad'] } })
|
await getEnvVars({ rc: { environments: ['bad'] } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find environments/gi)
|
assert.match(e.message, /failed to find environments/gi)
|
||||||
assert.match(e.message, /\.rc file at path/gi)
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
}
|
}
|
||||||
@ -112,7 +115,8 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['bad'] }, verbose: true })
|
await getEnvVars({ rc: { environments: ['bad'] }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -120,7 +124,7 @@ describe('getEnvVars', (): void => {
|
|||||||
it('should find .rc file at custom path path', async (): Promise<void> => {
|
it('should find .rc file at custom path path', async (): Promise<void> => {
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars({
|
const envs = await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' }
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
})
|
})
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
@ -136,7 +140,7 @@ describe('getEnvVars', (): void => {
|
|||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
verbose: true
|
verbose: true,
|
||||||
})
|
})
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
})
|
})
|
||||||
@ -147,10 +151,12 @@ describe('getEnvVars', (): void => {
|
|||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' }
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
assert.match(e.message, /\.rc file at path/gi)
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
}
|
}
|
||||||
@ -164,10 +170,11 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
verbose: true
|
verbose: true,
|
||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -178,10 +185,12 @@ describe('getEnvVars', (): void => {
|
|||||||
getRCFileVarsStub.rejects(environmentError)
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['bad'], filePath: '../.custom-rc' }
|
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find environments/gi)
|
assert.match(e.message, /failed to find environments/gi)
|
||||||
assert.match(e.message, /\.rc file at path/gi)
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
}
|
}
|
||||||
@ -196,13 +205,14 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVars({
|
||||||
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
||||||
verbose: true
|
verbose: true,
|
||||||
})
|
})
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should parse the env file from a custom path', async (): Promise<void> => {
|
it('should parse the env file from a custom path', async (): Promise<void> => {
|
||||||
@ -227,7 +237,9 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
assert.match(e.message, /\.env file at path/gi)
|
assert.match(e.message, /\.env file at path/gi)
|
||||||
}
|
}
|
||||||
@ -239,14 +251,15 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'should parse the env file from the default path if custom ' +
|
'should parse the env file from the default path if custom '
|
||||||
'path not found and fallback option provided',
|
+ 'path not found and fallback option provided',
|
||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
@ -256,19 +269,19 @@ describe('getEnvVars', (): void => {
|
|||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
assert.equal(getEnvFileVarsStub.callCount, 2)
|
assert.equal(getEnvFileVarsStub.callCount, 2)
|
||||||
assert.equal(getEnvFileVarsStub.args[1][0], './.env')
|
assert.equal(getEnvFileVarsStub.args[1][0], './.env')
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'should print multiple times for failure to find .env file and ' +
|
'should print multiple times for failure to find .env file and '
|
||||||
'failure to find fallback file to infor for verbose',
|
+ 'failure to find fallback file to infor for verbose',
|
||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
getEnvFileVarsStub.onFirstCall().rejects('File not found.')
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true }, verbose: true })
|
await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true }, verbose: true })
|
||||||
assert.equal(logInfoStub.callCount, 2)
|
assert.equal(logInfoStub.callCount, 2)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should parse the env file from the default path', async (): Promise<void> => {
|
it('should parse the env file from the default path', async (): Promise<void> => {
|
||||||
@ -304,7 +317,9 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars()
|
await getEnvVars()
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /failed to find/gi)
|
assert.match(e.message, /failed to find/gi)
|
||||||
assert.match(e.message, /\.env file/gi)
|
assert.match(e.message, /\.env file/gi)
|
||||||
assert.match(e.message, /default paths/gi)
|
assert.match(e.message, /default paths/gi)
|
||||||
@ -319,9 +334,10 @@ describe('getEnvVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvVars({ verbose: true })
|
await getEnvVars({ verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch {
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -9,7 +9,7 @@ describe('parseArgs', (): void => {
|
|||||||
const environments = ['development', 'production']
|
const environments = ['development', 'production']
|
||||||
const rcFilePath = './.env-cmdrc'
|
const rcFilePath = './.env-cmdrc'
|
||||||
const envFilePath = './.env'
|
const envFilePath = './.env'
|
||||||
let logInfoStub: sinon.SinonStub<any, any>
|
let logInfoStub: sinon.SinonStub<any>
|
||||||
|
|
||||||
before((): void => {
|
before((): void => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
@ -53,7 +53,7 @@ describe('parseArgs', (): void => {
|
|||||||
assert.sameOrderedMembers(res.commandArgs, commandFlags)
|
assert.sameOrderedMembers(res.commandArgs, commandFlags)
|
||||||
assert.notOk(res.options!.useShell)
|
assert.notOk(res.options!.useShell)
|
||||||
assert.notOk(res.envFile)
|
assert.notOk(res.envFile)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should parse override option', (): void => {
|
it('should parse override option', (): void => {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import {
|
import {
|
||||||
stripEmptyLines, stripComments, parseEnvVars,
|
stripEmptyLines, stripComments, parseEnvVars,
|
||||||
parseEnvString, getEnvFileVars
|
parseEnvString, getEnvFileVars,
|
||||||
} from '../src/parse-env-file'
|
} from '../src/parse-env-file'
|
||||||
|
|
||||||
describe('stripEmptyLines', (): void => {
|
describe('stripEmptyLines', (): void => {
|
||||||
@ -20,10 +20,12 @@ describe('stripComments', (): void => {
|
|||||||
|
|
||||||
describe('parseEnvVars', (): void => {
|
describe('parseEnvVars', (): void => {
|
||||||
it('should parse out all env vars in string when not ending with \'\\n\'', (): void => {
|
it('should parse out all env vars in string when not ending with \'\\n\'', (): void => {
|
||||||
const envVars = parseEnvVars('BOB=COOL\nNODE_ENV=dev\nANSWER=42 AND COUNTING')
|
const envVars = parseEnvVars('BOB=COOL\nNODE_ENV=dev\nANSWER=42 AND COUNTING\nNUMBER=42\nBOOLEAN=true')
|
||||||
assert(envVars.BOB === 'COOL')
|
assert(envVars.BOB === 'COOL')
|
||||||
assert(envVars.NODE_ENV === 'dev')
|
assert(envVars.NODE_ENV === 'dev')
|
||||||
assert(envVars.ANSWER === '42 AND COUNTING')
|
assert(envVars.ANSWER === '42 AND COUNTING')
|
||||||
|
assert(envVars.NUMBER === 42)
|
||||||
|
assert(envVars.BOOLEAN === true)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse out all env vars in string with format \'key=value\'', (): void => {
|
it('should parse out all env vars in string with format \'key=value\'', (): void => {
|
||||||
@ -96,7 +98,7 @@ describe('parseEnvString', (): void => {
|
|||||||
const env = parseEnvString('BOB=COOL\nNODE_ENV=dev\nANSWER=42\n')
|
const env = parseEnvString('BOB=COOL\nNODE_ENV=dev\nANSWER=42\n')
|
||||||
assert(env.BOB === 'COOL')
|
assert(env.BOB === 'COOL')
|
||||||
assert(env.NODE_ENV === 'dev')
|
assert(env.NODE_ENV === 'dev')
|
||||||
assert(env.ANSWER === '42')
|
assert(env.ANSWER === 42)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -107,7 +109,8 @@ describe('getEnvFileVars', (): void => {
|
|||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
ANSWER: 42,
|
ANSWER: 42,
|
||||||
ONLY: 'IN PRODUCTION',
|
ONLY: 'IN PRODUCTION',
|
||||||
GALAXY: 'hitch\nhiking'
|
GALAXY: 'hitch\nhiking',
|
||||||
|
BRINGATOWEL: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -117,7 +120,8 @@ describe('getEnvFileVars', (): void => {
|
|||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
ANSWER: 42,
|
ANSWER: 42,
|
||||||
ONLY: 'IN\n PRODUCTION',
|
ONLY: 'IN\n PRODUCTION',
|
||||||
GALAXY: 'hitch\nhiking\n\n'
|
GALAXY: 'hitch\nhiking\n\n',
|
||||||
|
BRINGATOWEL: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -126,7 +130,7 @@ describe('getEnvFileVars', (): void => {
|
|||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0,
|
ANSWER: 0,
|
||||||
GALAXY: 'hitch\nhiking'
|
GALAXY: 'hitch\nhiking',
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -134,7 +138,7 @@ describe('getEnvFileVars', (): void => {
|
|||||||
const env = await getEnvFileVars('./test/test-files/test-async.js')
|
const env = await getEnvFileVars('./test/test-files/test-async.js')
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0
|
ANSWER: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -142,9 +146,10 @@ describe('getEnvFileVars', (): void => {
|
|||||||
const env = await getEnvFileVars('./test/test-files/test')
|
const env = await getEnvFileVars('./test/test-files/test')
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
ANSWER: '42',
|
ANSWER: 42,
|
||||||
ONLY: 'IN=PRODUCTION',
|
ONLY: 'IN=PRODUCTION',
|
||||||
GALAXY: 'hitch\nhiking'
|
GALAXY: 'hitch\nhiking',
|
||||||
|
BRINGATOWEL: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -152,7 +157,9 @@ describe('getEnvFileVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getEnvFileVars('./test/test-files/non-existent-file')
|
await getEnvFileVars('./test/test-files/non-existent-file')
|
||||||
assert.fail('Should not get here!')
|
assert.fail('Should not get here!')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /file path/gi)
|
assert.match(e.message, /file path/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -11,7 +11,8 @@ describe('getRCFileVars', (): void => {
|
|||||||
assert.deepEqual(res, {
|
assert.deepEqual(res, {
|
||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
ANSWER: 42,
|
ANSWER: 42,
|
||||||
ONLY: 'IN PRODUCTION'
|
ONLY: 'IN PRODUCTION',
|
||||||
|
BRINGATOWEL: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -20,7 +21,7 @@ describe('getRCFileVars', (): void => {
|
|||||||
assert.exists(res)
|
assert.exists(res)
|
||||||
assert.deepEqual(res, {
|
assert.deepEqual(res, {
|
||||||
THANKS: 'FOR MORE FISHIES',
|
THANKS: 'FOR MORE FISHIES',
|
||||||
ANSWER: 21
|
ANSWER: 21,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -28,7 +29,9 @@ describe('getRCFileVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getRCFileVars({ environments: ['bad'], filePath: 'bad-path' })
|
await getRCFileVars({ environments: ['bad'], filePath: 'bad-path' })
|
||||||
assert.fail('Should not get here!')
|
assert.fail('Should not get here!')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /\.rc file at path/gi)
|
assert.match(e.message, /\.rc file at path/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -37,7 +40,9 @@ describe('getRCFileVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getRCFileVars({ environments: ['bad'], filePath: rcFilePath })
|
await getRCFileVars({ environments: ['bad'], filePath: rcFilePath })
|
||||||
assert.fail('Should not get here!')
|
assert.fail('Should not get here!')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /environments/gi)
|
assert.match(e.message, /environments/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -46,7 +51,9 @@ describe('getRCFileVars', (): void => {
|
|||||||
try {
|
try {
|
||||||
await getRCFileVars({ environments: ['bad'], filePath: './test/test-files/.rc-test-bad-format' })
|
await getRCFileVars({ environments: ['bad'], filePath: './test/test-files/.rc-test-bad-format' })
|
||||||
assert.fail('Should not get here!')
|
assert.fail('Should not get here!')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /parse/gi)
|
assert.match(e.message, /parse/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -54,12 +61,13 @@ describe('getRCFileVars', (): void => {
|
|||||||
it('should parse an async js .rc file', async (): Promise<void> => {
|
it('should parse an async js .rc file', async (): Promise<void> => {
|
||||||
const env = await getRCFileVars({
|
const env = await getRCFileVars({
|
||||||
environments: ['production'],
|
environments: ['production'],
|
||||||
filePath: './test/test-files/.rc-test-async.js'
|
filePath: './test/test-files/.rc-test-async.js',
|
||||||
})
|
})
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
ANSWER: 42,
|
ANSWER: 42,
|
||||||
ONLY: 'IN PRODUCTION'
|
ONLY: 'IN PRODUCTION',
|
||||||
|
BRINGATOWEL: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import * as sinon from 'sinon'
|
import * as sinon from 'sinon'
|
||||||
import { TermSignals } from '../src/signal-termination'
|
import { TermSignals } from '../src/signal-termination'
|
||||||
|
import { ChildProcess } from 'child_process'
|
||||||
|
|
||||||
|
type ChildExitListener = (code: number | null, signal: NodeJS.Signals | null | number) => void
|
||||||
|
|
||||||
describe('signal-termination', (): void => {
|
describe('signal-termination', (): void => {
|
||||||
let sandbox: sinon.SinonSandbox
|
let sandbox: sinon.SinonSandbox
|
||||||
@ -15,8 +18,8 @@ describe('signal-termination', (): void => {
|
|||||||
describe('TermSignals', (): void => {
|
describe('TermSignals', (): void => {
|
||||||
describe('_uncaughtExceptionHandler', (): void => {
|
describe('_uncaughtExceptionHandler', (): void => {
|
||||||
const term = new TermSignals()
|
const term = new TermSignals()
|
||||||
let logStub: sinon.SinonStub<any, any>
|
let logStub: sinon.SinonStub<any>
|
||||||
let processStub: sinon.SinonStub<any, any>
|
let processStub: sinon.SinonStub<any>
|
||||||
|
|
||||||
beforeEach((): void => {
|
beforeEach((): void => {
|
||||||
logStub = sandbox.stub(console, 'error')
|
logStub = sandbox.stub(console, 'error')
|
||||||
@ -39,7 +42,7 @@ describe('signal-termination', (): void => {
|
|||||||
|
|
||||||
describe('_removeProcessListeners', (): void => {
|
describe('_removeProcessListeners', (): void => {
|
||||||
const term = new TermSignals()
|
const term = new TermSignals()
|
||||||
let removeListenerStub: sinon.SinonStub<any, any>
|
let removeListenerStub: sinon.SinonStub<any>
|
||||||
before((): void => {
|
before((): void => {
|
||||||
removeListenerStub = sandbox.stub(process, 'removeListener')
|
removeListenerStub = sandbox.stub(process, 'removeListener')
|
||||||
})
|
})
|
||||||
@ -50,15 +53,15 @@ describe('signal-termination', (): void => {
|
|||||||
|
|
||||||
it('should remove all listeners from default signals and exit signal', (): void => {
|
it('should remove all listeners from default signals and exit signal', (): void => {
|
||||||
term._removeProcessListeners()
|
term._removeProcessListeners()
|
||||||
assert.equal(removeListenerStub.callCount, 4)
|
assert.equal(removeListenerStub.callCount, 3)
|
||||||
assert.equal(removeListenerStub.args[3][0], 'exit')
|
assert.oneOf(removeListenerStub.args[2][0], ['SIGTERM', 'SIGINT', 'SIGHUP'])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('_terminateProcess', (): void => {
|
describe('_terminateProcess', (): void => {
|
||||||
const term = new TermSignals()
|
const term = new TermSignals()
|
||||||
let exitStub: sinon.SinonStub<any, any>
|
let exitStub: sinon.SinonStub<any>
|
||||||
let killStub: sinon.SinonStub<any, any>
|
let killStub: sinon.SinonStub<any>
|
||||||
|
|
||||||
beforeEach((): void => {
|
beforeEach((): void => {
|
||||||
exitStub = sandbox.stub(process, 'exit')
|
exitStub = sandbox.stub(process, 'exit')
|
||||||
@ -83,7 +86,7 @@ describe('signal-termination', (): void => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('should call kill method with correct kill signal', (): void => {
|
it('should call kill method with correct kill signal', (): void => {
|
||||||
term._terminateProcess(1, 'SIGINT')
|
term._terminateProcess('SIGINT')
|
||||||
assert.equal(killStub.callCount, 1)
|
assert.equal(killStub.callCount, 1)
|
||||||
assert.equal(exitStub.callCount, 0)
|
assert.equal(exitStub.callCount, 0)
|
||||||
assert.equal(killStub.args[0][1], 'SIGINT')
|
assert.equal(killStub.args[0][1], 'SIGINT')
|
||||||
@ -93,7 +96,9 @@ describe('signal-termination', (): void => {
|
|||||||
try {
|
try {
|
||||||
term._terminateProcess()
|
term._terminateProcess()
|
||||||
assert.fail('should not get here')
|
assert.fail('should not get here')
|
||||||
} catch (e) {
|
}
|
||||||
|
catch (e) {
|
||||||
|
assert.instanceOf(e, Error)
|
||||||
assert.match(e.message, /unable to terminate parent process/gi)
|
assert.match(e.message, /unable to terminate parent process/gi)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -101,8 +106,8 @@ describe('signal-termination', (): void => {
|
|||||||
|
|
||||||
describe('handleUncaughtExceptions', (): void => {
|
describe('handleUncaughtExceptions', (): void => {
|
||||||
const term = new TermSignals()
|
const term = new TermSignals()
|
||||||
let processOnStub: sinon.SinonStub<any, any>
|
let processOnStub: sinon.SinonStub<any>
|
||||||
let _uncaughtExceptionHandlerStub: sinon.SinonStub<any, any>
|
let _uncaughtExceptionHandlerStub: sinon.SinonStub<any>
|
||||||
|
|
||||||
before((): void => {
|
before((): void => {
|
||||||
processOnStub = sandbox.stub(process, 'on')
|
processOnStub = sandbox.stub(process, 'on')
|
||||||
@ -117,22 +122,22 @@ describe('signal-termination', (): void => {
|
|||||||
term.handleUncaughtExceptions()
|
term.handleUncaughtExceptions()
|
||||||
assert.equal(processOnStub.callCount, 1)
|
assert.equal(processOnStub.callCount, 1)
|
||||||
assert.equal(_uncaughtExceptionHandlerStub.callCount, 0)
|
assert.equal(_uncaughtExceptionHandlerStub.callCount, 0)
|
||||||
processOnStub.args[0][1]()
|
;(processOnStub.args[0][1] as () => void)()
|
||||||
assert.equal(_uncaughtExceptionHandlerStub.callCount, 1)
|
assert.equal(_uncaughtExceptionHandlerStub.callCount, 1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('handleTermSignals', (): void => {
|
describe('handleTermSignals', (): void => {
|
||||||
let term: TermSignals
|
let term: TermSignals
|
||||||
let procKillStub: sinon.SinonStub<any, any>
|
let procKillStub: sinon.SinonStub<any>
|
||||||
let procOnStub: sinon.SinonStub<any, any>
|
let procOnStub: sinon.SinonStub<any>
|
||||||
let processOnceStub: sinon.SinonStub<any, any>
|
let processOnceStub: sinon.SinonStub<any>
|
||||||
let _removeProcessListenersStub: sinon.SinonStub<any, any>
|
let _removeProcessListenersStub: sinon.SinonStub<any>
|
||||||
let _terminateProcessStub: sinon.SinonStub<any, any>
|
let _terminateProcessStub: sinon.SinonStub<any>
|
||||||
let logInfoStub: sinon.SinonStub<any, any>
|
let logInfoStub: sinon.SinonStub<any>
|
||||||
let proc: any
|
let proc: ChildProcess
|
||||||
|
|
||||||
function setup (verbose: boolean = false): void {
|
function setup(verbose = false): void {
|
||||||
term = new TermSignals({ verbose })
|
term = new TermSignals({ verbose })
|
||||||
procKillStub = sandbox.stub()
|
procKillStub = sandbox.stub()
|
||||||
procOnStub = sandbox.stub()
|
procOnStub = sandbox.stub()
|
||||||
@ -141,8 +146,8 @@ describe('signal-termination', (): void => {
|
|||||||
_terminateProcessStub = sandbox.stub(term, '_terminateProcess')
|
_terminateProcessStub = sandbox.stub(term, '_terminateProcess')
|
||||||
proc = {
|
proc = {
|
||||||
kill: procKillStub,
|
kill: procKillStub,
|
||||||
on: procOnStub
|
on: procOnStub,
|
||||||
}
|
} as unknown as ChildProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeEach((): void => {
|
beforeEach((): void => {
|
||||||
@ -163,7 +168,7 @@ describe('signal-termination', (): void => {
|
|||||||
it('should terminate child process if parent process terminated', (): void => {
|
it('should terminate child process if parent process terminated', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1]('SIGTERM', 1)
|
;(processOnceStub.args[0][1] as NodeJS.SignalsListener)('SIGTERM')
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(procKillStub.callCount, 1)
|
assert.equal(procKillStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
@ -176,17 +181,17 @@ describe('signal-termination', (): void => {
|
|||||||
logInfoStub = sandbox.stub(console, 'info')
|
logInfoStub = sandbox.stub(console, 'info')
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1]('SIGTERM', 1)
|
;(processOnceStub.args[0][1] as NodeJS.SignalsListener)('SIGTERM')
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not terminate child process if child process termination ' +
|
it('should not terminate child process if child process termination '
|
||||||
'has already been called by parent', (): void => {
|
+ 'has already been called by parent', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1]('SIGINT', 1)
|
;(processOnceStub.args[0][1] as NodeJS.SignalsListener)('SIGINT')
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
processOnceStub.args[0][1]('SIGTERM', 1)
|
;(processOnceStub.args[0][1] as NodeJS.SignalsListener)('SIGTERM')
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 2)
|
assert.equal(_removeProcessListenersStub.callCount, 2)
|
||||||
assert.equal(procKillStub.callCount, 1)
|
assert.equal(procKillStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
@ -196,7 +201,7 @@ describe('signal-termination', (): void => {
|
|||||||
it('should convert and use number signal as code', (): void => {
|
it('should convert and use number signal as code', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1](4, 1)
|
;(processOnceStub.args[0][1] as NodeJS.ExitListener)(1)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(procKillStub.callCount, 1)
|
assert.equal(procKillStub.callCount, 1)
|
||||||
assert.equal(procKillStub.args[0][0], 'SIGINT')
|
assert.equal(procKillStub.args[0][0], 'SIGINT')
|
||||||
@ -204,13 +209,13 @@ describe('signal-termination', (): void => {
|
|||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not use signal number as code if value is 0', (): void => {
|
it('should not use default signal if code is 0', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1](0, 1)
|
;(processOnceStub.args[0][1] as NodeJS.ExitListener)(0)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(procKillStub.callCount, 1)
|
assert.equal(procKillStub.callCount, 1)
|
||||||
assert.equal(procKillStub.args[0], 1)
|
assert.equal(procKillStub.args[0], 0)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
@ -218,7 +223,7 @@ describe('signal-termination', (): void => {
|
|||||||
it('should use signal value and default SIGINT signal if code is undefined', (): void => {
|
it('should use signal value and default SIGINT signal if code is undefined', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
processOnceStub.args[0][1](4, undefined)
|
;(processOnceStub.args[0][1] as NodeJS.ExitListener)(4)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(procKillStub.callCount, 1)
|
assert.equal(procKillStub.callCount, 1)
|
||||||
assert.equal(procKillStub.args[0][0], 'SIGINT')
|
assert.equal(procKillStub.args[0][0], 'SIGINT')
|
||||||
@ -229,7 +234,7 @@ describe('signal-termination', (): void => {
|
|||||||
it('should terminate parent process if child process terminated', (): void => {
|
it('should terminate parent process if child process terminated', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](1, 'SIGTERM')
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 'SIGTERM')
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
@ -241,31 +246,31 @@ describe('signal-termination', (): void => {
|
|||||||
logInfoStub = sandbox.stub(console, 'info')
|
logInfoStub = sandbox.stub(console, 'info')
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](1, 'SIGTERM')
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 'SIGTERM')
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it(
|
it(
|
||||||
'should print parent process terminated to info for verbose when ' +
|
'should print parent process terminated to info for verbose when '
|
||||||
'code and signal are undefined',
|
+ 'code and signal are undefined',
|
||||||
(): void => {
|
(): void => {
|
||||||
sandbox.restore()
|
sandbox.restore()
|
||||||
setup(true)
|
setup(true)
|
||||||
logInfoStub = sandbox.stub(console, 'info')
|
logInfoStub = sandbox.stub(console, 'info')
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](undefined, null)
|
;(procOnStub.args[0][1] as ChildExitListener)(null, null)
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
it('should not terminate parent process if parent process already terminating', (): void => {
|
it('should not terminate parent process if parent process already terminating', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](1, 'SIGINT')
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 'SIGINT')
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
procOnStub.args[0][1](1, 'SIGTERM')
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 'SIGTERM')
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 2)
|
assert.equal(_removeProcessListenersStub.callCount, 2)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
@ -274,7 +279,7 @@ describe('signal-termination', (): void => {
|
|||||||
it('should convert null signal value to undefined', (): void => {
|
it('should convert null signal value to undefined', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](0, null)
|
;(procOnStub.args[0][1] as ChildExitListener)(0, null)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[1], undefined)
|
assert.strictEqual(_terminateProcessStub.firstCall.args[1], undefined)
|
||||||
@ -284,33 +289,30 @@ describe('signal-termination', (): void => {
|
|||||||
it('should convert and use number signal as code', (): void => {
|
it('should convert and use number signal as code', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](1, 4)
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 4)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 4)
|
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 'SIGINT')
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[1], 'SIGINT')
|
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not use signal number as code if value is 0', (): void => {
|
it('should not use signal number as code if value is 0', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](1, 0)
|
;(procOnStub.args[0][1] as ChildExitListener)(1, 0)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 1)
|
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 1)
|
||||||
assert.isUndefined(_terminateProcessStub.firstCall.args[1])
|
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should use signal value and default SIGINT signal if code is undefined', (): void => {
|
it('should use signal value and default SIGINT signal if code is undefined', (): void => {
|
||||||
assert.notOk(term._exitCalled)
|
assert.notOk(term._exitCalled)
|
||||||
term.handleTermSignals(proc)
|
term.handleTermSignals(proc)
|
||||||
procOnStub.args[0][1](null, 1)
|
;(procOnStub.args[0][1] as ChildExitListener)(null, 1)
|
||||||
assert.equal(_removeProcessListenersStub.callCount, 1)
|
assert.equal(_removeProcessListenersStub.callCount, 1)
|
||||||
assert.equal(_terminateProcessStub.callCount, 1)
|
assert.equal(_terminateProcessStub.callCount, 1)
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 1)
|
assert.strictEqual(_terminateProcessStub.firstCall.args[0], 'SIGINT')
|
||||||
assert.strictEqual(_terminateProcessStub.firstCall.args[1], 'SIGINT')
|
|
||||||
assert.isOk(term._exitCalled)
|
assert.isOk(term._exitCalled)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"production": {
|
"production": {
|
||||||
"THANKS": "FOR WHAT?!",
|
"THANKS": "FOR WHAT?!",
|
||||||
"ANSWER": 42,
|
"ANSWER": 42,
|
||||||
"ONLY": "IN PRODUCTION"
|
"ONLY": "IN PRODUCTION",
|
||||||
|
"BRINGATOWEL": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,19 +1,20 @@
|
|||||||
module.exports = new Promise((resolve) => {
|
module.exports = new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({
|
resolve({
|
||||||
'development': {
|
development: {
|
||||||
'THANKS': 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
'ANSWER': 0
|
ANSWER: 0,
|
||||||
},
|
},
|
||||||
'test': {
|
test: {
|
||||||
'THANKS': 'FOR MORE FISHIES',
|
THANKS: 'FOR MORE FISHIES',
|
||||||
'ANSWER': 21
|
ANSWER: 21,
|
||||||
|
},
|
||||||
|
production: {
|
||||||
|
THANKS: 'FOR WHAT?!',
|
||||||
|
ANSWER: 42,
|
||||||
|
ONLY: 'IN PRODUCTION',
|
||||||
|
BRINGATOWEL: true,
|
||||||
},
|
},
|
||||||
'production': {
|
|
||||||
'THANKS': 'FOR WHAT?!',
|
|
||||||
'ANSWER': 42,
|
|
||||||
'ONLY': 'IN PRODUCTION'
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}, 200)
|
}, 200)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"production": {
|
"production": {
|
||||||
"THANKS": "FOR WHAT?!",
|
"THANKS": "FOR WHAT?!",
|
||||||
"ANSWER": 42,
|
"ANSWER": 42,
|
||||||
"ONLY": "IN PRODUCTION"
|
"ONLY": "IN PRODUCTION",
|
||||||
|
"BRINGATOWEL": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,3 +2,4 @@ THANKS = FOR WHAT?!
|
|||||||
ANSWER=42
|
ANSWER=42
|
||||||
ONLY= "IN=PRODUCTION"
|
ONLY= "IN=PRODUCTION"
|
||||||
GALAXY="hitch\nhiking"
|
GALAXY="hitch\nhiking"
|
||||||
|
BRINGATOWEL=true
|
||||||
|
|||||||
@ -2,7 +2,7 @@ module.exports = new Promise((resolve) => {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve({
|
resolve({
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0
|
ANSWER: 0,
|
||||||
})
|
})
|
||||||
}, 200)
|
}, 200)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -2,5 +2,6 @@
|
|||||||
"THANKS": "FOR WHAT?!",
|
"THANKS": "FOR WHAT?!",
|
||||||
"ANSWER": 42,
|
"ANSWER": 42,
|
||||||
"ONLY": "IN\n PRODUCTION",
|
"ONLY": "IN\n PRODUCTION",
|
||||||
"GALAXY": "hitch\nhiking\n\n"
|
"GALAXY": "hitch\nhiking\n\n",
|
||||||
|
"BRINGATOWEL": true
|
||||||
}
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0,
|
ANSWER: 0,
|
||||||
GALAXY: 'hitch\nhiking'
|
GALAXY: 'hitch\nhiking',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,5 +2,6 @@
|
|||||||
"THANKS": "FOR WHAT?!",
|
"THANKS": "FOR WHAT?!",
|
||||||
"ANSWER": 42,
|
"ANSWER": 42,
|
||||||
"ONLY": "IN PRODUCTION",
|
"ONLY": "IN PRODUCTION",
|
||||||
"GALAXY": "hitch\nhiking"
|
"GALAXY": "hitch\nhiking",
|
||||||
|
"BRINGATOWEL": true
|
||||||
}
|
}
|
||||||
@ -48,5 +48,13 @@ describe('utils', (): void => {
|
|||||||
const res = isPromise({})
|
const res = isPromise({})
|
||||||
assert.isFalse(res)
|
assert.isFalse(res)
|
||||||
})
|
})
|
||||||
|
it('should return false for string', (): void => {
|
||||||
|
const res = isPromise('test')
|
||||||
|
assert.isFalse(res)
|
||||||
|
})
|
||||||
|
it('should return false for undefined', (): void => {
|
||||||
|
const res = isPromise(undefined)
|
||||||
|
assert.isFalse(res)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"allowJs": true,
|
|
||||||
"checkJs": true
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"src/**/*",
|
|
||||||
"test/**/*",
|
|
||||||
"bin/**/*"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
Loading…
x
Reference in New Issue
Block a user