mirror of
https://github.com/toddbluhm/env-cmd.git
synced 2025-12-08 18:23:33 +00:00
feat(esm): convert to using esm modules
This commit is contained in:
parent
ef9665c5fe
commit
f8106ac44a
8
.mocharc.json
Normal file
8
.mocharc.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://json.schemastore.org/mocharc.json",
|
||||||
|
"require": ["tsx/esm", "esmock"],
|
||||||
|
"extensions": ["ts"],
|
||||||
|
"spec": [
|
||||||
|
"test/**/*.ts"
|
||||||
|
]
|
||||||
|
}
|
||||||
2
LICENSE
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2019 Todd Bluhm
|
Copyright (c) Todd Bluhm
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
#! /usr/bin/env node
|
#! /usr/bin/env node
|
||||||
require('../dist').CLI(process.argv.slice(2))
|
import { CLI } from '../dist'
|
||||||
|
CLI(process.argv.slice(2))
|
||||||
|
|||||||
@ -1,43 +1,38 @@
|
|||||||
const eslint = require('@eslint/js')
|
import { default as tseslint } from 'typescript-eslint'
|
||||||
const tseslint = require('typescript-eslint')
|
import { default as globals } from 'globals'
|
||||||
const globals = require('globals')
|
import { default as eslint } from '@eslint/js'
|
||||||
const stylistic = require('@stylistic/eslint-plugin')
|
|
||||||
|
|
||||||
module.exports = tseslint.config(
|
export default tseslint.config(
|
||||||
{
|
{
|
||||||
ignores: ['dist/*', 'bin/*'],
|
// Ignore build folder
|
||||||
rules: {
|
ignores: ['dist/*'],
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
|
||||||
},
|
},
|
||||||
|
eslint.configs.recommended,
|
||||||
|
tseslint.configs.strictTypeChecked,
|
||||||
|
tseslint.configs.stylisticTypeChecked,
|
||||||
|
{
|
||||||
|
// Enable Type generation
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
globals: {
|
globals: {
|
||||||
...globals.node,
|
...globals.node,
|
||||||
},
|
},
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
projectService: {
|
project: ['./tsconfig.json', './test/tsconfig.json'],
|
||||||
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
|
// For test files ignore some rules
|
||||||
files: ['test/*.ts'],
|
files: ['test/**/*'],
|
||||||
rules: {
|
rules: {
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
'@typescript-eslint/no-unsafe-member-access': 'off',
|
'@typescript-eslint/no-unsafe-member-access': 'off',
|
||||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
'@typescript-eslint/no-unsafe-assignment': 'off'
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// Disable Type Checking JS/CJS/MJS files
|
||||||
|
{
|
||||||
|
files: ['**/*.js', '**/*.cjs', '**/*.mjs'],
|
||||||
|
extends: [tseslint.configs.disableTypeChecked],
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
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/'],
|
|
||||||
}
|
|
||||||
]
|
|
||||||
})()
|
|
||||||
62
package.json
62
package.json
@ -4,16 +4,17 @@
|
|||||||
"description": "Executes a command using the environment variables in an env file",
|
"description": "Executes a command using the environment variables in an env file",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/index.d.ts",
|
||||||
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8.0.0"
|
"node": ">=18.0.0"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"env-cmd": "bin/env-cmd.js"
|
"env-cmd": "bin/env-cmd.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"test": "mocha -r ts-node/register ./test/**/*.ts",
|
"test": "mocha",
|
||||||
"test-cover": "nyc npm test",
|
"test-cover": "c8 npm test",
|
||||||
"coveralls": "coveralls < coverage/lcov.info",
|
"coveralls": "coveralls < coverage/lcov.info",
|
||||||
"lint": "npx eslint .",
|
"lint": "npx eslint .",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
@ -54,58 +55,33 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@commitlint/cli": "^19.6.0",
|
"@commitlint/cli": "^19.6.0",
|
||||||
"@commitlint/config-conventional": "^19.6.0",
|
"@commitlint/config-conventional": "^19.6.0",
|
||||||
"@eslint/js": "^9.15.0",
|
"@eslint/js": "^9.16.0",
|
||||||
"@stylistic/eslint-plugin": "^2.11.0",
|
"@types/chai": "^5.0.1",
|
||||||
"@types/chai": "^4.0.0",
|
"@types/cross-spawn": "^6.0.6",
|
||||||
"@types/cross-spawn": "^6.0.0",
|
"@types/mocha": "^10.0.10",
|
||||||
"@types/mocha": "^7.0.0",
|
"@types/node": "^22.10.1",
|
||||||
"@types/node": "^12.0.0",
|
|
||||||
"@types/sinon": "^17.0.3",
|
"@types/sinon": "^17.0.3",
|
||||||
|
"c8": "^10.1.2",
|
||||||
"chai": "^5.1.2",
|
"chai": "^5.1.2",
|
||||||
"coveralls": "^3.0.0",
|
"coveralls": "^3.0.0",
|
||||||
|
"esmock": "^2.6.9",
|
||||||
"globals": "^15.12.0",
|
"globals": "^15.12.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"mocha": "^10.8.2",
|
"mocha": "^11.0.0",
|
||||||
"nyc": "^17.1.0",
|
|
||||||
"sinon": "^19.0.2",
|
"sinon": "^19.0.2",
|
||||||
"ts-node": "^8.0.0",
|
"tsx": "^4.19.2",
|
||||||
"typescript": "^5.7.2",
|
"typescript": "^5.7.2",
|
||||||
"typescript-eslint": "^8.15.0"
|
"typescript-eslint": "^8.15.0"
|
||||||
},
|
},
|
||||||
"nyc": {
|
|
||||||
"include": [
|
|
||||||
"src/**/*.ts"
|
|
||||||
],
|
|
||||||
"extension": [
|
|
||||||
".ts"
|
|
||||||
],
|
|
||||||
"require": [
|
|
||||||
"ts-node/register"
|
|
||||||
],
|
|
||||||
"reporter": [
|
|
||||||
"text",
|
|
||||||
"lcov"
|
|
||||||
],
|
|
||||||
"sourceMap": true,
|
|
||||||
"instrument": true
|
|
||||||
},
|
|
||||||
"greenkeeper": {
|
|
||||||
"ignore": [
|
|
||||||
"@types/node"
|
|
||||||
],
|
|
||||||
"commitMessages": {
|
|
||||||
"initialBadge": "docs: add greenkeeper badge",
|
|
||||||
"initialDependencies": "chore: update dependencies",
|
|
||||||
"initialBranches": "chore: whitelist greenkeeper branches",
|
|
||||||
"dependencyUpdate": "chore: update dependency ${dependency}",
|
|
||||||
"devDependencyUpdate": "chore: update devDependecy ${dependency}",
|
|
||||||
"dependencyPin": "fix: pin dependency ${dependency}",
|
|
||||||
"devDependencyPin": "fix: pin devDependecy ${dependency}"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"commitlint": {
|
"commitlint": {
|
||||||
"extends": [
|
"extends": [
|
||||||
"@commitlint/config-conventional"
|
"@commitlint/config-conventional"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"c8": {
|
||||||
|
"reporter": [
|
||||||
|
"text",
|
||||||
|
"lcov"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/cli.ts
Normal file
25
src/cli.ts
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
import * as processLib from 'node:process'
|
||||||
|
import type { Environment } from './types.ts'
|
||||||
|
import { EnvCmd } from './env-cmd.js'
|
||||||
|
import { parseArgs } from './parse-args.js'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes env - cmd using command line arguments
|
||||||
|
* @export
|
||||||
|
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
||||||
|
* @returns {Promise<Environment>}
|
||||||
|
*/
|
||||||
|
export async function CLI(args: string[]): Promise<Environment> {
|
||||||
|
|
||||||
|
// Parse the args from the command line
|
||||||
|
const parsedArgs = parseArgs(args)
|
||||||
|
|
||||||
|
// Run EnvCmd
|
||||||
|
try {
|
||||||
|
return await EnvCmd(parsedArgs)
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
return processLib.exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,29 +1,9 @@
|
|||||||
import { spawn } from './spawn'
|
import { default as spawn } from 'cross-spawn'
|
||||||
import { EnvCmdOptions, Environment } from './types'
|
import type { EnvCmdOptions, Environment } from './types.ts'
|
||||||
import { TermSignals } from './signal-termination'
|
import { TermSignals } from './signal-termination.js'
|
||||||
import { parseArgs } from './parse-args'
|
import { getEnvVars } from './get-env-vars.js'
|
||||||
import { getEnvVars } from './get-env-vars'
|
import { expandEnvs } from './expand-envs.js'
|
||||||
import { expandEnvs } from './expand-envs'
|
import * as processLib from 'node:process'
|
||||||
|
|
||||||
/**
|
|
||||||
* Executes env - cmd using command line arguments
|
|
||||||
* @export
|
|
||||||
* @param {string[]} args Command line argument to pass in ['-f', './.env']
|
|
||||||
* @returns {Promise<Environment>}
|
|
||||||
*/
|
|
||||||
export async function CLI(args: string[]): Promise<Environment> {
|
|
||||||
// Parse the args from the command line
|
|
||||||
const parsedArgs = parseArgs(args)
|
|
||||||
|
|
||||||
// Run EnvCmd
|
|
||||||
try {
|
|
||||||
return await (exports as { EnvCmd: typeof EnvCmd }).EnvCmd(parsedArgs)
|
|
||||||
}
|
|
||||||
catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
return process.exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
@ -53,11 +33,11 @@ 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, processLib.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({}, processLib.env, env)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.expandEnvs === true) {
|
if (options.expandEnvs === true) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Environment } from './types'
|
import type { Environment } from './types.ts'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* expandEnvs Replaces $var in args and command with environment variables
|
* expandEnvs Replaces $var in args and command with environment variables
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { GetEnvVarOptions, Environment } from './types'
|
import type { GetEnvVarOptions, Environment } from './types.ts'
|
||||||
import { getRCFileVars } from './parse-rc-file'
|
import { getRCFileVars } from './parse-rc-file.js'
|
||||||
import { getEnvFileVars } from './parse-env-file'
|
import { getEnvFileVars } from './parse-env-file.js'
|
||||||
|
|
||||||
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']
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { getEnvVars } from './get-env-vars'
|
import { getEnvVars } from './get-env-vars.js'
|
||||||
|
|
||||||
// Export the core env-cmd API
|
// Export the core env-cmd API
|
||||||
export * from './types'
|
export * from './types.js'
|
||||||
export * from './env-cmd'
|
export * from './cli.js'
|
||||||
|
export * from './env-cmd.js'
|
||||||
export const GetEnvVars = getEnvVars
|
export const GetEnvVars = getEnvVars
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import * as commander from 'commander'
|
import * as commander from 'commander'
|
||||||
import { EnvCmdOptions, CommanderOptions, EnvFileOptions, RCFileOptions } from './types'
|
import type { EnvCmdOptions, CommanderOptions, EnvFileOptions, RCFileOptions } from './types.ts'
|
||||||
import { parseArgList } from './utils'
|
import { parseArgList } from './utils.js'
|
||||||
|
|
||||||
// Use commonjs require to prevent a weird folder hierarchy in dist
|
// Use commonjs require to prevent a weird folder hierarchy in dist
|
||||||
const packageJson: { version: string } = require('../package.json') /* eslint-disable-line */
|
const packageJson = (await import('../package.json')).default
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses the arguments passed into the cli
|
* Parses the arguments passed into the cli
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
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, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js'
|
||||||
import { Environment } from './types'
|
import type { Environment } from './types.ts'
|
||||||
|
|
||||||
const REQUIRE_HOOK_EXTENSIONS = ['.json', '.js', '.cjs']
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the environment vars from an env file
|
* Gets the environment vars from an env file
|
||||||
@ -19,9 +17,17 @@ export async function getEnvFileVars(envFilePath: string): Promise<Environment>
|
|||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = path.extname(absolutePath).toLowerCase()
|
const ext = path.extname(absolutePath).toLowerCase()
|
||||||
let env: Environment = {}
|
let env: Environment = {}
|
||||||
if (REQUIRE_HOOK_EXTENSIONS.includes(ext)) {
|
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||||
const possiblePromise: Environment | Promise<Environment> = require(absolutePath) /* eslint-disable-line */
|
const res = await import(absolutePath) as Environment | { default: Environment }
|
||||||
env = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
if ('default' in res) {
|
||||||
|
env = res.default as Environment
|
||||||
|
} else {
|
||||||
|
env = res
|
||||||
|
}
|
||||||
|
// Check to see if the imported value is a promise
|
||||||
|
if (isPromise(env)) {
|
||||||
|
env = await env
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const file = fs.readFileSync(absolutePath, { encoding: 'utf8' })
|
const file = fs.readFileSync(absolutePath, { encoding: 'utf8' })
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { stat, readFile } from 'fs'
|
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, IMPORT_HOOK_EXTENSIONS, isPromise } from './utils.js'
|
||||||
import { Environment, RCEnvironment } from './types'
|
import type { Environment, RCEnvironment } from './types.ts'
|
||||||
|
|
||||||
const statAsync = promisify(stat)
|
const statAsync = promisify(stat)
|
||||||
const readFileAsync = promisify(readFile)
|
const readFileAsync = promisify(readFile)
|
||||||
@ -26,11 +26,19 @@ export async function getRCFileVars(
|
|||||||
|
|
||||||
// Get the file extension
|
// Get the file extension
|
||||||
const ext = extname(absolutePath).toLowerCase()
|
const ext = extname(absolutePath).toLowerCase()
|
||||||
let parsedData: Partial<RCEnvironment>
|
let parsedData: Partial<RCEnvironment> = {}
|
||||||
try {
|
try {
|
||||||
if (ext === '.json' || ext === '.js' || ext === '.cjs') {
|
if (IMPORT_HOOK_EXTENSIONS.includes(ext)) {
|
||||||
const possiblePromise = require(absolutePath) as PromiseLike<RCEnvironment> | RCEnvironment
|
const res = await import(absolutePath) as RCEnvironment | { default: RCEnvironment }
|
||||||
parsedData = isPromise(possiblePromise) ? await possiblePromise : possiblePromise
|
if ('default' in res) {
|
||||||
|
parsedData = res.default as RCEnvironment
|
||||||
|
} else {
|
||||||
|
parsedData = res
|
||||||
|
}
|
||||||
|
// Check to see if the imported value is a promise
|
||||||
|
if (isPromise(parsedData)) {
|
||||||
|
parsedData = await parsedData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
const file = await readFileAsync(absolutePath, { encoding: 'utf8' })
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
import * as spawn from 'cross-spawn'
|
|
||||||
export {
|
|
||||||
spawn,
|
|
||||||
}
|
|
||||||
12
src/utils.ts
12
src/utils.ts
@ -1,16 +1,20 @@
|
|||||||
import * as path from 'path'
|
import { resolve } from 'node:path'
|
||||||
import * as os from 'os'
|
import { homedir } from 'node:os'
|
||||||
|
import { cwd } from 'node:process'
|
||||||
|
|
||||||
|
// Special file extensions that node can natively import
|
||||||
|
export const IMPORT_HOOK_EXTENSIONS = ['.json', '.js', '.cjs', '.mjs']
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A simple function for resolving the path the user entered
|
* A simple function for resolving the path the user entered
|
||||||
*/
|
*/
|
||||||
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() as string | undefined
|
const home = homedir() as string | undefined
|
||||||
if (home != null) {
|
if (home != null) {
|
||||||
userPath = userPath.replace(/^~($|\/|\\)/, `${home}$1`)
|
userPath = userPath.replace(/^~($|\/|\\)/, `${home}$1`)
|
||||||
}
|
}
|
||||||
return path.resolve(process.cwd(), userPath)
|
return resolve(cwd(), userPath)
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* A simple function that parses a comma separated string into an array of strings
|
* A simple function that parses a comma separated string into an array of strings
|
||||||
|
|||||||
57
test/cli.spec.ts
Normal file
57
test/cli.spec.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { default as sinon } from 'sinon'
|
||||||
|
import { assert } from 'chai'
|
||||||
|
import { default as esmock } from 'esmock'
|
||||||
|
import type { CLI } from '../src/cli.ts'
|
||||||
|
|
||||||
|
describe('CLI', (): void => {
|
||||||
|
let sandbox: sinon.SinonSandbox
|
||||||
|
let parseArgsStub: sinon.SinonStub<any>
|
||||||
|
let envCmdStub: sinon.SinonStub<any>
|
||||||
|
let processExitStub: sinon.SinonStub<any>
|
||||||
|
let cliLib: { CLI: typeof CLI }
|
||||||
|
|
||||||
|
before(async (): Promise<void> => {
|
||||||
|
sandbox = sinon.createSandbox()
|
||||||
|
envCmdStub = sandbox.stub()
|
||||||
|
parseArgsStub = sandbox.stub()
|
||||||
|
processExitStub = sandbox.stub()
|
||||||
|
cliLib = await esmock('../src/cli.ts', {
|
||||||
|
'../src/env-cmd': {
|
||||||
|
EnvCmd: envCmdStub,
|
||||||
|
},
|
||||||
|
'../src/parse-args': {
|
||||||
|
parseArgs: parseArgsStub,
|
||||||
|
},
|
||||||
|
'node:process': {
|
||||||
|
exit: processExitStub,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
after((): void => {
|
||||||
|
sandbox.restore()
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach((): void => {
|
||||||
|
sandbox.resetHistory()
|
||||||
|
sandbox.resetBehavior()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should parse the provided args and execute the EnvCmd', async (): Promise<void> => {
|
||||||
|
parseArgsStub.returns({})
|
||||||
|
await cliLib.CLI(['node', './env-cmd', '-v'])
|
||||||
|
assert.equal(parseArgsStub.callCount, 1)
|
||||||
|
assert.equal(envCmdStub.callCount, 1)
|
||||||
|
assert.equal(processExitStub.callCount, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should catch exception if EnvCmd throws an exception', async (): Promise<void> => {
|
||||||
|
parseArgsStub.returns({})
|
||||||
|
envCmdStub.throwsException('Error')
|
||||||
|
await cliLib.CLI(['node', './env-cmd', '-v'])
|
||||||
|
assert.equal(parseArgsStub.callCount, 1)
|
||||||
|
assert.equal(envCmdStub.callCount, 1)
|
||||||
|
assert.equal(processExitStub.callCount, 1)
|
||||||
|
assert.equal(processExitStub.args[0][0], 1)
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,68 +1,44 @@
|
|||||||
import * as sinon from 'sinon'
|
import { default as sinon } from 'sinon'
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import * as signalTermLib from '../src/signal-termination'
|
import { default as esmock } from 'esmock'
|
||||||
import * as parseArgsLib from '../src/parse-args'
|
import { expandEnvs } from '../src/expand-envs.js'
|
||||||
import * as getEnvVarsLib from '../src/get-env-vars'
|
import type { EnvCmd } from '../src/env-cmd.ts'
|
||||||
import * as expandEnvsLib from '../src/expand-envs'
|
|
||||||
import * as spawnLib from '../src/spawn'
|
|
||||||
import * as envCmdLib from '../src/env-cmd'
|
|
||||||
|
|
||||||
describe('CLI', (): void => {
|
let envCmdLib: { EnvCmd: typeof EnvCmd }
|
||||||
let sandbox: sinon.SinonSandbox
|
|
||||||
let parseArgsStub: sinon.SinonStub<any>
|
|
||||||
let envCmdStub: sinon.SinonStub<any>
|
|
||||||
let processExitStub: sinon.SinonStub<any>
|
|
||||||
before((): void => {
|
|
||||||
sandbox = sinon.createSandbox()
|
|
||||||
parseArgsStub = sandbox.stub(parseArgsLib, 'parseArgs')
|
|
||||||
envCmdStub = sandbox.stub(envCmdLib, 'EnvCmd')
|
|
||||||
processExitStub = sandbox.stub(process, 'exit')
|
|
||||||
})
|
|
||||||
|
|
||||||
after((): void => {
|
|
||||||
sandbox.restore()
|
|
||||||
})
|
|
||||||
|
|
||||||
afterEach((): void => {
|
|
||||||
sandbox.resetHistory()
|
|
||||||
sandbox.resetBehavior()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should parse the provided args and execute the EnvCmd', async (): Promise<void> => {
|
|
||||||
parseArgsStub.returns({})
|
|
||||||
await envCmdLib.CLI(['node', './env-cmd', '-v'])
|
|
||||||
assert.equal(parseArgsStub.callCount, 1)
|
|
||||||
assert.equal(envCmdStub.callCount, 1)
|
|
||||||
assert.equal(processExitStub.callCount, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('should catch exception if EnvCmd throws an exception', async (): Promise<void> => {
|
|
||||||
parseArgsStub.returns({})
|
|
||||||
envCmdStub.throwsException('Error')
|
|
||||||
await envCmdLib.CLI(['node', './env-cmd', '-v'])
|
|
||||||
assert.equal(parseArgsStub.callCount, 1)
|
|
||||||
assert.equal(envCmdStub.callCount, 1)
|
|
||||||
assert.equal(processExitStub.callCount, 1)
|
|
||||||
assert.equal(processExitStub.args[0][0], 1)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('EnvCmd', (): void => {
|
describe('EnvCmd', (): void => {
|
||||||
let sandbox: sinon.SinonSandbox
|
let sandbox: sinon.SinonSandbox
|
||||||
let getEnvVarsStub: sinon.SinonStub<any>
|
let getEnvVarsStub: sinon.SinonStub<any>
|
||||||
let spawnStub: sinon.SinonStub<any>
|
let spawnStub: sinon.SinonStub<any>
|
||||||
let expandEnvsSpy: sinon.SinonSpy<any>
|
let expandEnvsSpy: sinon.SinonSpy<any>
|
||||||
before((): void => {
|
before(async (): Promise<void> => {
|
||||||
sandbox = sinon.createSandbox()
|
sandbox = sinon.createSandbox()
|
||||||
getEnvVarsStub = sandbox.stub(getEnvVarsLib, 'getEnvVars')
|
getEnvVarsStub = sandbox.stub()
|
||||||
spawnStub = sandbox.stub(spawnLib, 'spawn')
|
spawnStub = sandbox.stub()
|
||||||
spawnStub.returns({
|
spawnStub.returns({
|
||||||
on: (): void => { /* Fake the on method */ },
|
on: sinon.stub(),
|
||||||
kill: (): void => { /* Fake the kill method */ },
|
kill: sinon.stub(),
|
||||||
|
})
|
||||||
|
expandEnvsSpy = sandbox.spy(expandEnvs)
|
||||||
|
|
||||||
|
const TermSignals = sandbox.stub()
|
||||||
|
TermSignals.prototype.handleTermSignals = sandbox.stub()
|
||||||
|
TermSignals.prototype.handleUncaughtExceptions = sandbox.stub()
|
||||||
|
|
||||||
|
envCmdLib = await esmock('../src/env-cmd.ts', {
|
||||||
|
'../src/get-env-vars': {
|
||||||
|
getEnvVars: getEnvVarsStub,
|
||||||
|
},
|
||||||
|
'cross-spawn': {
|
||||||
|
default: spawnStub,
|
||||||
|
},
|
||||||
|
'../src/expand-envs': {
|
||||||
|
expandEnvs: expandEnvsSpy,
|
||||||
|
},
|
||||||
|
'../src/signal-termination': {
|
||||||
|
TermSignals,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
expandEnvsSpy = sandbox.spy(expandEnvsLib, 'expandEnvs')
|
|
||||||
sandbox.stub(signalTermLib.TermSignals.prototype, 'handleTermSignals')
|
|
||||||
sandbox.stub(signalTermLib.TermSignals.prototype, 'handleUncaughtExceptions')
|
|
||||||
})
|
})
|
||||||
|
|
||||||
after((): void => {
|
after((): void => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { expandEnvs } from '../src/expand-envs'
|
import { expandEnvs } from '../src/expand-envs.js'
|
||||||
|
|
||||||
describe('expandEnvs', (): void => {
|
describe('expandEnvs', (): void => {
|
||||||
const envs = {
|
const envs = {
|
||||||
|
|||||||
@ -1,17 +1,26 @@
|
|||||||
import * as sinon from 'sinon'
|
import { default as sinon } from 'sinon'
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { getEnvVars } from '../src/get-env-vars'
|
import { default as esmock } from 'esmock'
|
||||||
import * as rcFile from '../src/parse-rc-file'
|
import type { getEnvVars } from '../src/get-env-vars.ts'
|
||||||
import * as envFile from '../src/parse-env-file'
|
|
||||||
|
let getEnvVarsLib: { getEnvVars: typeof getEnvVars }
|
||||||
|
|
||||||
describe('getEnvVars', (): void => {
|
describe('getEnvVars', (): void => {
|
||||||
let getRCFileVarsStub: sinon.SinonStub<any>
|
let getRCFileVarsStub: sinon.SinonStub<any>
|
||||||
let getEnvFileVarsStub: sinon.SinonStub<any>
|
let getEnvFileVarsStub: sinon.SinonStub<any>
|
||||||
let logInfoStub: sinon.SinonStub<any> | undefined
|
let logInfoStub: sinon.SinonStub<any> | undefined
|
||||||
|
|
||||||
before((): void => {
|
before(async (): Promise<void> => {
|
||||||
getRCFileVarsStub = sinon.stub(rcFile, 'getRCFileVars')
|
getRCFileVarsStub = sinon.stub()
|
||||||
getEnvFileVarsStub = sinon.stub(envFile, 'getEnvFileVars')
|
getEnvFileVarsStub = sinon.stub()
|
||||||
|
getEnvVarsLib = await esmock('../src/get-env-vars.ts', {
|
||||||
|
'../src/parse-rc-file': {
|
||||||
|
getRCFileVars: getRCFileVarsStub
|
||||||
|
},
|
||||||
|
'../src/parse-env-file': {
|
||||||
|
getEnvFileVars: getEnvFileVarsStub
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
after((): void => {
|
after((): void => {
|
||||||
@ -27,7 +36,7 @@ describe('getEnvVars', (): void => {
|
|||||||
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',
|
||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
const envs = await getEnvVarsLib.getEnvVars({ rc: { environments: ['production'] } })
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -42,7 +51,7 @@ describe('getEnvVars', (): void => {
|
|||||||
async (): Promise<void> => {
|
async (): Promise<void> => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
await getEnvVarsLib.getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -52,7 +61,7 @@ describe('getEnvVars', (): void => {
|
|||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
getRCFileVarsStub.onThirdCall().returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.onThirdCall().returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars({ rc: { environments: ['production'] } })
|
const envs = await getEnvVarsLib.getEnvVars({ rc: { environments: ['production'] } })
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -67,7 +76,7 @@ describe('getEnvVars', (): void => {
|
|||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] } })
|
await getEnvVarsLib.getEnvVars({ rc: { environments: ['production'] } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@ -84,7 +93,7 @@ describe('getEnvVars', (): void => {
|
|||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
await getEnvVarsLib.getEnvVars({ rc: { environments: ['production'] }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
@ -97,7 +106,7 @@ describe('getEnvVars', (): void => {
|
|||||||
environmentError.name = 'EnvironmentError'
|
environmentError.name = 'EnvironmentError'
|
||||||
getRCFileVarsStub.rejects(environmentError)
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['bad'] } })
|
await getEnvVarsLib.getEnvVars({ rc: { environments: ['bad'] } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@ -113,7 +122,7 @@ describe('getEnvVars', (): void => {
|
|||||||
environmentError.name = 'EnvironmentError'
|
environmentError.name = 'EnvironmentError'
|
||||||
getRCFileVarsStub.rejects(environmentError)
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ rc: { environments: ['bad'] }, verbose: true })
|
await getEnvVarsLib.getEnvVars({ rc: { environments: ['bad'] }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
@ -123,7 +132,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 getEnvVarsLib.getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
})
|
})
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
@ -138,7 +147,7 @@ describe('getEnvVars', (): void => {
|
|||||||
it('should print custom .rc file path to info for verbose', async (): Promise<void> => {
|
it('should print custom .rc file path to info for verbose', async (): Promise<void> => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getRCFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({
|
await getEnvVarsLib.getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
verbose: true,
|
verbose: true,
|
||||||
})
|
})
|
||||||
@ -150,7 +159,7 @@ describe('getEnvVars', (): void => {
|
|||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVarsLib.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.')
|
||||||
@ -168,7 +177,7 @@ describe('getEnvVars', (): void => {
|
|||||||
pathError.name = 'PathError'
|
pathError.name = 'PathError'
|
||||||
getRCFileVarsStub.rejects(pathError)
|
getRCFileVarsStub.rejects(pathError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVarsLib.getEnvVars({
|
||||||
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
rc: { environments: ['production'], filePath: '../.custom-rc' },
|
||||||
verbose: true,
|
verbose: true,
|
||||||
})
|
})
|
||||||
@ -184,7 +193,7 @@ describe('getEnvVars', (): void => {
|
|||||||
environmentError.name = 'EnvironmentError'
|
environmentError.name = 'EnvironmentError'
|
||||||
getRCFileVarsStub.rejects(environmentError)
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVarsLib.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.')
|
||||||
@ -203,7 +212,7 @@ describe('getEnvVars', (): void => {
|
|||||||
environmentError.name = 'EnvironmentError'
|
environmentError.name = 'EnvironmentError'
|
||||||
getRCFileVarsStub.rejects(environmentError)
|
getRCFileVarsStub.rejects(environmentError)
|
||||||
try {
|
try {
|
||||||
await getEnvVars({
|
await getEnvVarsLib.getEnvVars({
|
||||||
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
rc: { environments: ['bad'], filePath: '../.custom-rc' },
|
||||||
verbose: true,
|
verbose: true,
|
||||||
})
|
})
|
||||||
@ -217,7 +226,7 @@ describe('getEnvVars', (): void => {
|
|||||||
|
|
||||||
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> => {
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
const envs = await getEnvVarsLib.getEnvVars({ envFile: { filePath: '../.env-file' } })
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -228,14 +237,14 @@ describe('getEnvVars', (): void => {
|
|||||||
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
await getEnvVarsLib.getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should fail to find env file at custom path', async (): Promise<void> => {
|
it('should fail to find env file at custom path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' } })
|
await getEnvVarsLib.getEnvVars({ envFile: { filePath: '../.env-file' } })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@ -249,7 +258,7 @@ describe('getEnvVars', (): void => {
|
|||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
await getEnvVarsLib.getEnvVars({ envFile: { filePath: '../.env-file' }, verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
@ -263,7 +272,7 @@ describe('getEnvVars', (): void => {
|
|||||||
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' })
|
||||||
const envs = await getEnvVars({ envFile: { filePath: '../.env-file', fallback: true } })
|
const envs = await getEnvVarsLib.getEnvVars({ envFile: { filePath: '../.env-file', fallback: true } })
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -279,14 +288,14 @@ describe('getEnvVars', (): 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 getEnvVarsLib.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> => {
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars()
|
const envs = await getEnvVarsLib.getEnvVars()
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -297,14 +306,14 @@ describe('getEnvVars', (): void => {
|
|||||||
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
it('should print path of .env file to info for verbose', async (): Promise<void> => {
|
||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
await getEnvVars({ verbose: true })
|
await getEnvVarsLib.getEnvVars({ verbose: true })
|
||||||
assert.equal(logInfoStub.callCount, 1)
|
assert.equal(logInfoStub.callCount, 1)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should search all default env file paths', async (): Promise<void> => {
|
it('should search all default env file paths', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.throws('Not found.')
|
getEnvFileVarsStub.throws('Not found.')
|
||||||
getEnvFileVarsStub.onThirdCall().returns({ THANKS: 'FOR ALL THE FISH' })
|
getEnvFileVarsStub.onThirdCall().returns({ THANKS: 'FOR ALL THE FISH' })
|
||||||
const envs = await getEnvVars()
|
const envs = await getEnvVarsLib.getEnvVars()
|
||||||
assert.isOk(envs)
|
assert.isOk(envs)
|
||||||
assert.lengthOf(Object.keys(envs), 1)
|
assert.lengthOf(Object.keys(envs), 1)
|
||||||
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
assert.equal(envs.THANKS, 'FOR ALL THE FISH')
|
||||||
@ -315,7 +324,7 @@ describe('getEnvVars', (): void => {
|
|||||||
it('should fail to find env file at default path', async (): Promise<void> => {
|
it('should fail to find env file at default path', async (): Promise<void> => {
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars()
|
await getEnvVarsLib.getEnvVars()
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@ -332,7 +341,7 @@ describe('getEnvVars', (): void => {
|
|||||||
logInfoStub = sinon.stub(console, 'info')
|
logInfoStub = sinon.stub(console, 'info')
|
||||||
getEnvFileVarsStub.rejects('Not found.')
|
getEnvFileVarsStub.rejects('Not found.')
|
||||||
try {
|
try {
|
||||||
await getEnvVars({ verbose: true })
|
await getEnvVarsLib.getEnvVars({ verbose: true })
|
||||||
assert.fail('should not get here.')
|
assert.fail('should not get here.')
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
/* eslint @typescript-eslint/no-non-null-assertion: 0 */
|
||||||
import * as sinon from 'sinon'
|
import { default as sinon } from 'sinon'
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { parseArgs } from '../src/parse-args'
|
import { parseArgs } from '../src/parse-args.js'
|
||||||
|
|
||||||
describe('parseArgs', (): void => {
|
describe('parseArgs', (): void => {
|
||||||
const command = 'command'
|
const command = 'command'
|
||||||
|
|||||||
@ -2,7 +2,7 @@ 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.js'
|
||||||
|
|
||||||
describe('stripEmptyLines', (): void => {
|
describe('stripEmptyLines', (): void => {
|
||||||
it('should strip out all empty lines', (): void => {
|
it('should strip out all empty lines', (): void => {
|
||||||
@ -125,8 +125,8 @@ describe('getEnvFileVars', (): void => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse a js file', async (): Promise<void> => {
|
it('should parse a js/cjs file', async (): Promise<void> => {
|
||||||
const env = await getEnvFileVars('./test/test-files/test.js')
|
const env = await getEnvFileVars('./test/test-files/test.cjs')
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0,
|
ANSWER: 0,
|
||||||
@ -134,8 +134,25 @@ describe('getEnvFileVars', (): void => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse an async js file', async (): Promise<void> => {
|
it('should parse an async js/cjs file', async (): Promise<void> => {
|
||||||
const env = await getEnvFileVars('./test/test-files/test-async.js')
|
const env = await getEnvFileVars('./test/test-files/test-async.cjs')
|
||||||
|
assert.deepEqual(env, {
|
||||||
|
THANKS: 'FOR ALL THE FISH',
|
||||||
|
ANSWER: 0,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should parse a mjs file', async (): Promise<void> => {
|
||||||
|
const env = await getEnvFileVars('./test/test-files/test.mjs')
|
||||||
|
assert.deepEqual(env, {
|
||||||
|
THANKS: 'FOR ALL THE FISH',
|
||||||
|
ANSWER: 0,
|
||||||
|
GALAXY: 'hitch\nhiking',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should parse an async mjs file', async (): Promise<void> => {
|
||||||
|
const env = await getEnvFileVars('./test/test-files/test-async.mjs')
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
ANSWER: 0,
|
ANSWER: 0,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import { getRCFileVars } from '../src/parse-rc-file'
|
import { getRCFileVars } from '../src/parse-rc-file.js'
|
||||||
|
|
||||||
const rcFilePath = './test/test-files/.rc-test'
|
const rcFilePath = './test/test-files/.rc-test'
|
||||||
const rcJSONFilePath = './test/test-files/.rc-test.json'
|
const rcJSONFilePath = './test/test-files/.rc-test.json'
|
||||||
@ -58,10 +58,23 @@ describe('getRCFileVars', (): void => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should parse an async js .rc file', async (): Promise<void> => {
|
it('should parse an async js/cjs .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.cjs',
|
||||||
|
})
|
||||||
|
assert.deepEqual(env, {
|
||||||
|
THANKS: 'FOR WHAT?!',
|
||||||
|
ANSWER: 42,
|
||||||
|
ONLY: 'IN PRODUCTION',
|
||||||
|
BRINGATOWEL: true,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should parse an async mjs .rc file', async (): Promise<void> => {
|
||||||
|
const env = await getRCFileVars({
|
||||||
|
environments: ['production'],
|
||||||
|
filePath: './test/test-files/.rc-test-async.mjs',
|
||||||
})
|
})
|
||||||
assert.deepEqual(env, {
|
assert.deepEqual(env, {
|
||||||
THANKS: 'FOR WHAT?!',
|
THANKS: 'FOR WHAT?!',
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import * as sinon from 'sinon'
|
import { default as sinon } from 'sinon'
|
||||||
import { TermSignals } from '../src/signal-termination'
|
import { TermSignals } from '../src/signal-termination.js'
|
||||||
import { ChildProcess } from 'child_process'
|
import { ChildProcess } from 'child_process'
|
||||||
|
|
||||||
type ChildExitListener = (code: number | null, signal: NodeJS.Signals | null | number) => void
|
type ChildExitListener = (code: number | null, signal: NodeJS.Signals | null | number) => void
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
module.exports = new Promise((resolve) => {
|
module.exports = new Promise((resolve) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
console.log('resolved')
|
||||||
resolve({
|
resolve({
|
||||||
development: {
|
development: {
|
||||||
THANKS: 'FOR ALL THE FISH',
|
THANKS: 'FOR ALL THE FISH',
|
||||||
20
test/test-files/.rc-test-async.mjs
Normal file
20
test/test-files/.rc-test-async.mjs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
export default new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
development: {
|
||||||
|
THANKS: 'FOR ALL THE FISH',
|
||||||
|
ANSWER: 0,
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
THANKS: 'FOR MORE FISHIES',
|
||||||
|
ANSWER: 21,
|
||||||
|
},
|
||||||
|
production: {
|
||||||
|
THANKS: 'FOR WHAT?!',
|
||||||
|
ANSWER: 42,
|
||||||
|
ONLY: 'IN PRODUCTION',
|
||||||
|
BRINGATOWEL: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
})
|
||||||
8
test/test-files/test-async.mjs
Normal file
8
test/test-files/test-async.mjs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
resolve({
|
||||||
|
THANKS: 'FOR ALL THE FISH',
|
||||||
|
ANSWER: 0,
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
})
|
||||||
5
test/test-files/test.mjs
Normal file
5
test/test-files/test.mjs
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
THANKS: 'FOR ALL THE FISH',
|
||||||
|
ANSWER: 0,
|
||||||
|
GALAXY: 'hitch\nhiking',
|
||||||
|
}
|
||||||
18
test/tsconfig.json
Normal file
18
test/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"esModuleInterop": false,
|
||||||
|
"lib": ["es2023"],
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"noEmit": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strict": true,
|
||||||
|
"target": "ES2022",
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"./**/*",
|
||||||
|
"./test-files/.rc-test-async.cjs",
|
||||||
|
"./test-files/.rc-test-async.mjs",
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,14 +1,31 @@
|
|||||||
import * as os from 'os'
|
import { homedir } from 'node:os'
|
||||||
import * as process from 'process'
|
import { cwd } from 'node:process'
|
||||||
import * as path from 'path'
|
import { normalize } from 'node:path'
|
||||||
import { assert } from 'chai'
|
import { assert } from 'chai'
|
||||||
import * as sinon from 'sinon'
|
import { default as sinon } from 'sinon'
|
||||||
import { resolveEnvFilePath, parseArgList, isPromise } from '../src/utils'
|
import { default as esmock } from 'esmock'
|
||||||
|
import { resolveEnvFilePath, parseArgList, isPromise } from '../src/utils.js'
|
||||||
|
|
||||||
|
let utilsLib: {
|
||||||
|
resolveEnvFilePath: typeof resolveEnvFilePath,
|
||||||
|
parseArgList: typeof parseArgList,
|
||||||
|
isPromise: typeof isPromise
|
||||||
|
}
|
||||||
|
|
||||||
describe('utils', (): void => {
|
describe('utils', (): void => {
|
||||||
describe('resolveEnvFilePath', (): void => {
|
describe('resolveEnvFilePath', (): void => {
|
||||||
const homePath = os.homedir()
|
const homePath = homedir()
|
||||||
const currentDir = process.cwd()
|
const currentDir = cwd()
|
||||||
|
let homedirStub: sinon.SinonStub<any>
|
||||||
|
|
||||||
|
before(async (): Promise<void> => {
|
||||||
|
homedirStub = sinon.stub()
|
||||||
|
utilsLib = await esmock('../src/utils.js', {
|
||||||
|
'node:os': {
|
||||||
|
homedir: homedirStub
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
afterEach((): void => {
|
afterEach((): void => {
|
||||||
sinon.restore()
|
sinon.restore()
|
||||||
@ -16,18 +33,17 @@ describe('utils', (): void => {
|
|||||||
|
|
||||||
it('should return an absolute path, given a relative path', (): void => {
|
it('should return an absolute path, given a relative path', (): void => {
|
||||||
const res = resolveEnvFilePath('./bob')
|
const res = resolveEnvFilePath('./bob')
|
||||||
assert.equal(res, path.normalize(`${currentDir}/bob`))
|
assert.equal(res, normalize(`${currentDir}/bob`))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should return an absolute path, given a path with ~ for home directory', (): void => {
|
it('should return an absolute path, given a path with ~ for home directory', (): void => {
|
||||||
const res = resolveEnvFilePath('~/bob')
|
const res = resolveEnvFilePath('~/bob')
|
||||||
assert.equal(res, path.normalize(`${homePath}/bob`))
|
assert.equal(res, normalize(`${homePath}/bob`))
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should not attempt to replace ~ if home dir does not exist', (): void => {
|
it('should not attempt to replace ~ if home dir does not exist', (): void => {
|
||||||
sinon.stub(os, 'homedir')
|
const res = utilsLib.resolveEnvFilePath('~/bob')
|
||||||
const res = resolveEnvFilePath('~/bob')
|
assert.equal(res, normalize(`${currentDir}/~/bob`))
|
||||||
assert.equal(res, path.normalize(`${currentDir}/~/bob`))
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"declaration": true,
|
||||||
|
"esModuleInterop": false,
|
||||||
|
"lib": ["es2023"],
|
||||||
|
"module": "Node16",
|
||||||
|
"moduleDetection": "force",
|
||||||
"outDir": "./dist",
|
"outDir": "./dist",
|
||||||
"target": "es2017",
|
|
||||||
"module": "commonjs",
|
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"declaration": true,
|
"target": "ES2022",
|
||||||
"lib": [
|
|
||||||
"es2018",
|
|
||||||
"es2019",
|
|
||||||
"es2020"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"./src/**/*"
|
"./src/**/*"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user