From c803fa5adab948dd770921d633a9b3bf9a82fd5d Mon Sep 17 00:00:00 2001 From: Scott Motte Date: Wed, 13 Nov 2024 16:18:37 -0800 Subject: [PATCH] wip - better expansion to match dotenvx's --- lib/main.js | 202 +++++++++---- tests/main.js | 806 +++++++++++++++++++++++++------------------------- 2 files changed, 549 insertions(+), 459 deletions(-) diff --git a/lib/main.js b/lib/main.js index e57074e..47be414 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,53 +1,130 @@ -'use strict' - -// * / -// * (\\)? # is it escaped with a backslash? -// * (\$) # literal $ -// * (?!\() # shouldnt be followed by parenthesis -// * (\{?) # first brace wrap opening -// * ([\w.]+) # key -// * (?::-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))? # optional default nested 3 times -// * (\}?) # last brace warp closing -// * /xi - -const DOTENV_SUBSTITUTION_REGEX = /(\\)?(\$)(?!\()(\{?)([\w.]+)(?::?-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))?(\}?)/gi +// 'use strict' +// +// // * / +// // * (\\)? # is it escaped with a backslash? +// // * (\$) # literal $ +// // * (?!\() # shouldnt be followed by parenthesis +// // * (\{?) # first brace wrap opening +// // * ([\w.]+) # key +// // * (?::-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))? # optional default nested 3 times +// // * (\}?) # last brace warp closing +// // * /xi +// +// const DOTENV_SUBSTITUTION_REGEX = /(\\)?(\$)(?!\()(\{?)([\w.]+)(?::?-((?:\$\{(?:\$\{(?:\$\{[^}]*\}|[^}])*}|[^}])*}|[^}])+))?(\}?)/gi +// +// function _resolveEscapeSequences (value) { +// return value.replace(/\\\$/g, '$') +// } +// +// function interpolate (value, processEnv, parsed) { +// return value.replace(DOTENV_SUBSTITUTION_REGEX, (match, escaped, dollarSign, openBrace, key, defaultValue, closeBrace) => { +// if (escaped === '\\') { +// return match.slice(1) +// } else { +// if (processEnv[key]) { +// if (processEnv[key] === parsed[key]) { +// return processEnv[key] +// } else { +// // scenario: PASSWORD_EXPAND_NESTED=${PASSWORD_EXPAND} +// return interpolate(processEnv[key], processEnv, parsed) +// } +// } +// +// if (parsed[key]) { +// // avoid recursion from EXPAND_SELF=$EXPAND_SELF +// if (parsed[key] !== value) { +// return interpolate(parsed[key], processEnv, parsed) +// } +// } +// +// if (defaultValue) { +// if (defaultValue.startsWith('$')) { +// return interpolate(defaultValue, processEnv, parsed) +// } else { +// return defaultValue +// } +// } +// +// return '' +// } +// }) +// } +// +// function expand (options) { +// let processEnv = process.env +// if (options && options.processEnv != null) { +// processEnv = options.processEnv +// } +// +// for (const key in options.parsed) { +// let value = options.parsed[key] +// +// const inProcessEnv = Object.prototype.hasOwnProperty.call(processEnv, key) +// if (inProcessEnv) { +// if (processEnv[key] === options.parsed[key]) { +// // assume was set to processEnv from the .env file if the values match and therefore interpolate +// value = interpolate(value, processEnv, options.parsed) +// } else { +// // do not interpolate - assume processEnv had the intended value even if containing a $. +// value = processEnv[key] +// } +// } else { +// // not inProcessEnv so assume interpolation for this .env key +// value = interpolate(value, processEnv, options.parsed) +// } +// +// options.parsed[key] = _resolveEscapeSequences(value) +// } +// +// for (const processKey in options.parsed) { +// processEnv[processKey] = options.parsed[processKey] +// } +// +// return { +// parsed: options.parsed, +// processEnv +// } +// return options +// } +// +// module.exports.expand = expand function _resolveEscapeSequences (value) { return value.replace(/\\\$/g, '$') } -function interpolate (value, processEnv, parsed) { - return value.replace(DOTENV_SUBSTITUTION_REGEX, (match, escaped, dollarSign, openBrace, key, defaultValue, closeBrace) => { - if (escaped === '\\') { - return match.slice(1) - } else { - if (processEnv[key]) { - if (processEnv[key] === parsed[key]) { - return processEnv[key] - } else { - // scenario: PASSWORD_EXPAND_NESTED=${PASSWORD_EXPAND} - return interpolate(processEnv[key], processEnv, parsed) - } - } +function interpolate (value, env) { + const regex = /(? { MACHINE_EXPAND: '$MACHINE' } } - const parsed = dotenvExpand.expand(dotenv).parsed + const { parsed, processEnv } = dotenvExpand.expand(dotenv) - ct.equal(parsed.MACHINE_EXPAND, 'machine') + ct.equal(parsed.MACHINE_EXPAND, 'machine_env') + ct.equal(processEnv.MACHINE_EXPAND, 'machine') + ct.equal(process.env.MACHINE_EXPAND, 'machine') ct.end() }) @@ -137,9 +141,11 @@ t.test('does not overwrite preset variables', ct => { SOME_ENV: 'development' } } - const parsed = dotenvExpand.expand(dotenv).parsed + const { parsed, processEnv } = dotenvExpand.expand(dotenv) - ct.equal(parsed.SOME_ENV, 'production') + ct.equal(parsed.SOME_ENV, 'development') + ct.equal(processEnv.SOME_ENV, 'production') + ct.equal(process.env.SOME_ENV, 'production') ct.end() }) @@ -182,400 +188,402 @@ t.test('expands environment variables (process.env)', ct => { t.test('expands environment variables (process.env)', ct => { const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) + const { parsed, processEnv } = dotenvExpand.expand(dotenv) + ct.equal(parsed.BASIC_EXPAND, '$BASIC') ct.equal(process.env.BASIC_EXPAND, 'basic') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.MACHINE_EXPAND, 'machine') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine (process.env)', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.MACHINE_EXPAND, 'machine') - - ct.end() -}) - -t.test('expands missing environment variables to an empty string', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND, '') - - ct.end() -}) - -t.test('expands missing environment variables to an empty string (process.env)', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND, '') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine even with a default', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.EXPAND_DEFAULT, 'machine') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine even with a default when nested', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.EXPAND_DEFAULT_NESTED, 'machine') - ct.equal(process.env.EXPAND_DEFAULT_NESTED2, 'machine') - - ct.end() -}) - -t.test('expands environment variables undefined with one already on the machine even with a default when nested', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.UNDEFINED_EXPAND_NESTED, 'machine') - - ct.end() -}) - -t.test('expands missing environment variables to an empty string but replaces with default', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT, 'default') - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT2, 'default') - - ct.end() -}) - -t.test('expands environent variables and concats with default nested', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE, 'machine_envdefault') - ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE2, 'machine_envdefault') - - ct.end() -}) - -t.test('expands environent variables and concats with default nested', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE, 'machine_envdefault') - ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE2, 'machine_envdefault') - - ct.end() -}) - -t.test('expands missing environment variables to an empty string but replaces with default nested', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED, 'default') - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED2, 'default') - - ct.end() -}) - -t.test('expands missing environment variables to an empty string but replaces with default nested twice', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED_TWICE, 'default') - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED_TWICE2, 'default') - - ct.end() -}) - -t.test('prioritizes machine key expansion over .env', ct => { - process.env.MACHINE = 'machine' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.MACHINE_EXPAND, 'machine') - - ct.end() -}) - -t.test('multiple expand', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.MONGOLAB_URI, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') - - ct.end() -}) - -t.test('should expand recursively', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.MONGOLAB_URI_RECURSIVELY, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') - - ct.end() -}) - -t.test('multiple expand', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.NO_CURLY_BRACES_URI, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') - - ct.end() -}) - -t.test('should expand recursively', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.NO_CURLY_BRACES_URI_RECURSIVELY, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') - - ct.end() -}) - -t.test('can write to an object rather than process.env if user provides it', ct => { - const myObject = {} - const dotenv = { - processEnv: myObject, - parsed: { - SHOULD_NOT_EXIST: 'testing' - } - } - const parsed = dotenvExpand.expand(dotenv).parsed - const evaluation = typeof process.env.SHOULD_NOT_EXIST - - ct.equal(parsed.SHOULD_NOT_EXIST, 'testing') - ct.equal(myObject.SHOULD_NOT_EXIST, 'testing') - ct.equal(evaluation, 'undefined') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine even with a default with special characters', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS, 'machine_env') - ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS2, 'machine_env') - - ct.end() -}) - -t.test('expands environment variables existing already on the machine even with a default with special characters (process.env)', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS, 'machine_env') - ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS2, 'machine_env') - - ct.end() -}) - -t.test('should expand with default value correctly', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS, '/default/path:with/colon') - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS2, '/default/path:with/colon') - ct.equal(parsed.NO_CURLY_BRACES_UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS, '/default/path:with/colon') - ct.equal(parsed.NO_CURLY_BRACES_UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS2, '/default/path:with/colon') - - ct.end() -}) - -t.test('should expand with default nested value correctly', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS_NESTED, '/default/path:with/colon') - ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS_NESTED2, '/default/path:with/colon') - - ct.end() -}) - -t.test('should expand variables with "." in names correctly', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed['POSTGRESQL.MAIN.USER'], parsed['POSTGRESQL.BASE.USER']) - - ct.end() -}) - -t.test('handles value of only $', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.DOLLAR, '$') - - ct.end() -}) - -t.test('handles $one$two', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.ONETWO, 'onetwo') - ct.equal(parsed.ONETWO_SIMPLE, 'onetwo') - ct.equal(parsed.ONETWO_SIMPLE2, 'onetwo') - ct.equal(parsed.ONETWO_SUPER_SIMPLE, 'onetwo') - - ct.end() -}) - -t.test('handles two dollar signs', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.TWO_DOLLAR_SIGNS, 'abcd$') - - ct.end() -}) - -t.test('does not choke', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.DONT_CHOKE1, '.kZh`>4[,[DDU-*Jt+[;8-,@K=,9%;F9KsoXqOE)gpG^X!{)Q+/9Fc(QF}i[NEi!') - ct.equal(parsed.DONT_CHOKE2, '=;+=CNy3)-D=zI6gRP2w$B@0K;Y]e^EFnCmx$Dx?;.9wf-rgk1BcTR0]JtY&fw;>HEwms`D8E2H') - ct.equal(parsed.DONT_CHOKE4, 'm]zjzfRItw2gs[2:{p{ugENyFw9m)tH6_VCQzer`*noVaIMunx=[1-AMgAcwmPkToxTaB?kgdF5y`A8m=Oa-B!)') - ct.equal(parsed.DONT_CHOKE6, 'xlC&* { - const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.EXPAND_SELF, '') // because it ends up accessing parsed[key]. - - ct.end() -}) - -t.test('expands DOMAIN with ${HOST}', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.HOST, 'something') - ct.equal(parsed.DOMAIN, 'https://something') - - ct.end() -}) - -t.test('does not attempt to expand password if already existed in processEnv', ct => { - process.env.PASSWORD = 'pas$word' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.PASSWORD, 'pas$word') - - ct.end() -}) - -t.test('does not expand dollar sign that are not variables', ct => { - const dotenv = { - parsed: { - NO_VARIABLES: '\\$.$+$-$$' - } - } - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.NO_VARIABLES, '$.$+$-$$') - - ct.end() -}) - -t.test('expands recursively', ct => { - const dotenv = { - parsed: { - MOCK_SERVER_PORT: '8090', - MOCK_SERVER_HOST: 'http://localhost:${MOCK_SERVER_PORT}', - BACKEND_API_HEALTH_CHECK_URL: '${MOCK_SERVER_HOST}/ci-health-check' - } - } - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.MOCK_SERVER_PORT, '8090') - ct.equal(parsed.MOCK_SERVER_HOST, 'http://localhost:8090') - ct.equal(parsed.BACKEND_API_HEALTH_CHECK_URL, 'http://localhost:8090/ci-health-check') - - ct.end() -}) - -t.test('expands recursively reverse order', ct => { - const dotenv = { - parsed: { - BACKEND_API_HEALTH_CHECK_URL: '${MOCK_SERVER_HOST}/ci-health-check', - MOCK_SERVER_HOST: 'http://localhost:${MOCK_SERVER_PORT}', - MOCK_SERVER_PORT: '8090' - } - } - const parsed = dotenvExpand.expand(dotenv).parsed - - ct.equal(parsed.MOCK_SERVER_PORT, '8090') - ct.equal(parsed.MOCK_SERVER_HOST, 'http://localhost:8090') - ct.equal(parsed.BACKEND_API_HEALTH_CHECK_URL, 'http://localhost:8090/ci-health-check') - - ct.end() -}) - -t.test('expands recursively', ct => { - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.PASSWORD_EXPAND, 'password') - ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'password') - ct.equal(process.env.PASSWORD, 'password') - ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') - ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') - - ct.end() -}) - -t.test('expands recursively but is smart enough to not attempt expansion of a pre-set env in process.env', ct => { - process.env.PASSWORD = 'pas$word' - - const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) - dotenvExpand.expand(dotenv) - - ct.equal(process.env.PASSWORD_EXPAND, 'pas$word') - ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'pas$word') - ct.equal(process.env.PASSWORD, 'pas$word') - ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') - ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') - - ct.end() -}) + ct.equal(processEnv.BASIC_EXPAND, 'basic') + + ct.end() +}) + +// t.test('expands environment variables existing already on the machine', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.MACHINE_EXPAND, 'machine') +// +// ct.end() +// }) +// +// t.test('expands environment variables existing already on the machine (process.env)', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.MACHINE_EXPAND, 'machine') +// +// ct.end() +// }) +// +// t.test('expands missing environment variables to an empty string', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND, '') +// +// ct.end() +// }) +// +// t.test('expands missing environment variables to an empty string (process.env)', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND, '') +// +// ct.end() +// }) +// +// t.test('expands environment variables existing already on the machine even with a default', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.EXPAND_DEFAULT, 'machine') +// +// ct.end() +// }) +// +// t.test('expands environment variables existing already on the machine even with a default when nested', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.EXPAND_DEFAULT_NESTED, 'machine') +// ct.equal(process.env.EXPAND_DEFAULT_NESTED2, 'machine') +// +// ct.end() +// }) +// +// t.test('expands environment variables undefined with one already on the machine even with a default when nested', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.UNDEFINED_EXPAND_NESTED, 'machine') +// +// ct.end() +// }) +// +// t.test('expands missing environment variables to an empty string but replaces with default', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT, 'default') +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT2, 'default') +// +// ct.end() +// }) +// +// t.test('expands environent variables and concats with default nested', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE, 'machine_envdefault') +// ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE2, 'machine_envdefault') +// +// ct.end() +// }) +// +// t.test('expands environent variables and concats with default nested', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE, 'machine_envdefault') +// ct.equal(parsed.EXPAND_DEFAULT_NESTED_TWICE2, 'machine_envdefault') +// +// ct.end() +// }) +// +// t.test('expands missing environment variables to an empty string but replaces with default nested', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED, 'default') +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED2, 'default') +// +// ct.end() +// }) +// +// t.test('expands missing environment variables to an empty string but replaces with default nested twice', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED_TWICE, 'default') +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_NESTED_TWICE2, 'default') +// +// ct.end() +// }) +// +// t.test('prioritizes machine key expansion over .env', ct => { +// process.env.MACHINE = 'machine' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.MACHINE_EXPAND, 'machine') +// +// ct.end() +// }) +// +// t.test('multiple expand', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.MONGOLAB_URI, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') +// +// ct.end() +// }) +// +// t.test('should expand recursively', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.MONGOLAB_URI_RECURSIVELY, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') +// +// ct.end() +// }) +// +// t.test('multiple expand', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.NO_CURLY_BRACES_URI, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') +// +// ct.end() +// }) +// +// t.test('should expand recursively', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.NO_CURLY_BRACES_URI_RECURSIVELY, 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db') +// +// ct.end() +// }) +// +// t.test('can write to an object rather than process.env if user provides it', ct => { +// const myObject = {} +// const dotenv = { +// processEnv: myObject, +// parsed: { +// SHOULD_NOT_EXIST: 'testing' +// } +// } +// const parsed = dotenvExpand.expand(dotenv).parsed +// const evaluation = typeof process.env.SHOULD_NOT_EXIST +// +// ct.equal(parsed.SHOULD_NOT_EXIST, 'testing') +// ct.equal(myObject.SHOULD_NOT_EXIST, 'testing') +// ct.equal(evaluation, 'undefined') +// +// ct.end() +// }) +// +// t.test('expands environment variables existing already on the machine even with a default with special characters', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS, 'machine_env') +// ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS2, 'machine_env') +// +// ct.end() +// }) +// +// t.test('expands environment variables existing already on the machine even with a default with special characters (process.env)', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS, 'machine_env') +// ct.equal(parsed.EXPAND_DEFAULT_SPECIAL_CHARACTERS2, 'machine_env') +// +// ct.end() +// }) +// +// t.test('should expand with default value correctly', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS, '/default/path:with/colon') +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS2, '/default/path:with/colon') +// ct.equal(parsed.NO_CURLY_BRACES_UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS, ':-/default/path:with/colon') +// ct.equal(parsed.NO_CURLY_BRACES_UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS2, '-/default/path:with/colon') +// +// ct.end() +// }) +// +// t.test('should expand with default nested value correctly', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS_NESTED, '/default/path:with/colon') +// ct.equal(parsed.UNDEFINED_EXPAND_DEFAULT_SPECIAL_CHARACTERS_NESTED2, '/default/path:with/colon') +// +// ct.end() +// }) +// +// t.test('should expand variables with "." in names correctly', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed['POSTGRESQL.MAIN.USER'], parsed['POSTGRESQL.BASE.USER']) +// +// ct.end() +// }) +// +// t.test('handles value of only $', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.DOLLAR, '$') +// +// ct.end() +// }) +// +// t.test('handles $one$two', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.ONETWO, 'onetwo') +// ct.equal(parsed.ONETWO_SIMPLE, 'onetwo') +// ct.equal(parsed.ONETWO_SIMPLE2, 'onetwo') +// ct.equal(parsed.ONETWO_SUPER_SIMPLE, 'onetwo') +// +// ct.end() +// }) +// +// t.test('handles two dollar signs', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.TWO_DOLLAR_SIGNS, 'abcd$') +// +// ct.end() +// }) +// +// t.test('does not choke', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.DONT_CHOKE1, '.kZh`>4[,[DDU-*Jt+[;8-,@K=,9%;F9KsoXqOE)gpG^X!{)Q+/9Fc(QF}i[NEi!') +// ct.equal(parsed.DONT_CHOKE2, '=;+=CNy3)-D=zI6gRP2w$B@0K;Y]e^EFnCmx$Dx?;.9wf-rgk1BcTR0]JtY&fw;>HEwms`D8E2H') +// ct.equal(parsed.DONT_CHOKE4, 'm]zjzfRItw2gs[2:{p{ugENyFw9m)tH6_VCQzer`*noVaIMunx=[1-AMgAcwmPkToxTaB?kgdF5y`A8m=Oa-B!)') +// ct.equal(parsed.DONT_CHOKE6, 'xlC&* { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test', processEnv: {} }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.EXPAND_SELF, '') // because it ends up accessing parsed[key]. +// +// ct.end() +// }) +// +// t.test('expands DOMAIN with ${HOST}', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.HOST, 'something') +// ct.equal(parsed.DOMAIN, 'https://something') +// +// ct.end() +// }) +// +// t.test('does not attempt to expand password if already existed in processEnv', ct => { +// process.env.PASSWORD = 'pas$word' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.PASSWORD, 'pas$word') +// +// ct.end() +// }) +// +// t.test('does not expand dollar sign that are not variables', ct => { +// const dotenv = { +// parsed: { +// NO_VARIABLES: '\\$.$+$-$$' +// } +// } +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.NO_VARIABLES, '$.$+$-$$') +// +// ct.end() +// }) +// +// t.test('expands recursively', ct => { +// const dotenv = { +// parsed: { +// MOCK_SERVER_PORT: '8090', +// MOCK_SERVER_HOST: 'http://localhost:${MOCK_SERVER_PORT}', +// BACKEND_API_HEALTH_CHECK_URL: '${MOCK_SERVER_HOST}/ci-health-check' +// } +// } +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.MOCK_SERVER_PORT, '8090') +// ct.equal(parsed.MOCK_SERVER_HOST, 'http://localhost:8090') +// ct.equal(parsed.BACKEND_API_HEALTH_CHECK_URL, 'http://localhost:8090/ci-health-check') +// +// ct.end() +// }) +// +// t.test('expands recursively reverse order', ct => { +// const dotenv = { +// parsed: { +// BACKEND_API_HEALTH_CHECK_URL: '${MOCK_SERVER_HOST}/ci-health-check', +// MOCK_SERVER_HOST: 'http://localhost:${MOCK_SERVER_PORT}', +// MOCK_SERVER_PORT: '8090' +// } +// } +// const parsed = dotenvExpand.expand(dotenv).parsed +// +// ct.equal(parsed.MOCK_SERVER_PORT, '8090') +// ct.equal(parsed.MOCK_SERVER_HOST, 'http://localhost:8090') +// ct.equal(parsed.BACKEND_API_HEALTH_CHECK_URL, 'http://localhost:8090/ci-health-check') +// +// ct.end() +// }) +// +// t.test('expands recursively', ct => { +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.PASSWORD_EXPAND, 'password') +// ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'password') +// ct.equal(process.env.PASSWORD, 'password') +// ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') +// ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'password') +// +// ct.end() +// }) +// +// t.test('expands recursively but is smart enough to not attempt expansion of a pre-set env in process.env', ct => { +// process.env.PASSWORD = 'pas$word' +// +// const dotenv = require('dotenv').config({ path: 'tests/.env.test' }) +// dotenvExpand.expand(dotenv) +// +// ct.equal(process.env.PASSWORD_EXPAND, 'pas$word') +// ct.equal(process.env.PASSWORD_EXPAND_SIMPLE, 'pas$word') +// ct.equal(process.env.PASSWORD, 'pas$word') +// ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') +// ct.equal(process.env.PASSWORD_EXPAND_NESTED, 'pas$word') +// +// ct.end() +// })