diff --git a/README.md b/README.md index 519297a..7e3d753 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Use the following properties to configure your instance. * **path** (`'./.env'`) - The path to your environment variables. * **safe** (`false`) - If true, load '.env.example' to verify the '.env' variables are all set. Can also be a string to a different file. +* **allowEmptyValues** (`false`) - Whether to allow empty strings in safe mode. If false, will throw an error if any env variables are empty (but only if safe mode is enabled). * **systemvars** (`false`) - Set to true if you would rather load all system variables as well (useful for CI purposes). * **silent** (`false`) - If true, all warnings will be suppressed. * **expand** (`false`) - Allows your variables to be "expanded" for reusability within your `.env` file. @@ -106,6 +107,7 @@ module.exports = { new Dotenv({ path: './some.other.env', // load this now instead of the ones in '.env' safe: true, // load '.env.example' to verify the '.env' variables are all set. Can also be a string to a different file. + allowEmptyValues: true, // allow empty variables (e.g. `FOO=`) (treat it as empty string, rather than missing) systemvars: true, // load all the predefined 'process.env' variables which will trump anything local per dotenv specs. silent: true, // hide any errors defaults: false // load '.env.defaults' as the default values if empty. diff --git a/src/index.js b/src/index.js index fa58d3d..b9fd0be 100644 --- a/src/index.js +++ b/src/index.js @@ -48,14 +48,18 @@ class Dotenv { } gatherVariables () { - const { safe } = this.config + const { safe, allowEmptyValues } = this.config const vars = this.initializeVars() const { env, blueprint } = this.getEnvs() Object.keys(blueprint).map(key => { const value = Object.prototype.hasOwnProperty.call(vars, key) ? vars[key] : env[key] - if (!value && safe) { + + const isMissing = typeof value === 'undefined' || value === null || + (!allowEmptyValues && value === '') + + if (safe && isMissing) { throw new Error(`Missing environment variable: ${key}`) } else { vars[key] = value diff --git a/test/envs/.missingone b/test/envs/.missingone index 03451d7..87639b2 100644 --- a/test/envs/.missingone +++ b/test/envs/.missingone @@ -1,2 +1 @@ -TEST= TEST2=Hello diff --git a/test/envs/.oneempty b/test/envs/.oneempty new file mode 100644 index 0000000..03451d7 --- /dev/null +++ b/test/envs/.oneempty @@ -0,0 +1,2 @@ +TEST= +TEST2=Hello diff --git a/test/envs/.oneempty.example b/test/envs/.oneempty.example new file mode 100644 index 0000000..9ba3886 --- /dev/null +++ b/test/envs/.oneempty.example @@ -0,0 +1,2 @@ +TEST= +TEST2= diff --git a/test/main.spec.js b/test/main.spec.js index 4fcbad9..76a1ca1 100644 --- a/test/main.spec.js +++ b/test/main.spec.js @@ -13,6 +13,8 @@ const envEmpty = path.resolve(__dirname, './envs/.empty') const envEmptyExample = path.resolve(__dirname, './envs/.empty.example') const envSimple = path.resolve(__dirname, './envs/.simple') const envSimpleExample = path.resolve(__dirname, './envs/.simple.example') +const envOneEmpty = path.resolve(__dirname, './envs/.oneempty') +const envOneEmptyExample = path.resolve(__dirname, './envs/.oneempty.example') const envMissingOne = path.resolve(__dirname, './envs/.missingone') const envMissingOneExample = path.resolve(__dirname, './envs/.missingone.example') const envSystemvars = path.resolve(__dirname, './envs/.systemvars') @@ -28,7 +30,8 @@ const buildExpectation = (obj) => Object.keys(obj).reduce((all, key) => { const envDefJson = buildExpectation({ TEST: 'hi' }) const envEmptyJson = buildExpectation({}) const envSimpleJson = buildExpectation({ TEST: 'testing' }) -const envMissingOneJson = buildExpectation({ TEST: '', TEST2: 'Hello' }) +const envOneEmptyJson = buildExpectation({ TEST: '', TEST2: 'Hello' }) +const envMissingOneJson = buildExpectation({ TEST2: 'Hello' }) const envDefaultsJson = buildExpectation({ TEST: 'hi', TEST2: 'hidefault' }) const envDefaultsJson2 = buildExpectation({ TEST: 'hi', TEST2: 'youcanseethis' }) @@ -208,12 +211,30 @@ function runTests (Obj, name) { }) }) + describe('Empty variables', () => { + it('Should load fine (not-safe)', () => { + envTest({ path: envOneEmpty }).should.deep.equal(envOneEmptyJson) + }) + + it('Should fail on safe mode', () => { + function errorTest () { + envTest({ path: envOneEmpty, safe: envOneEmptyExample }) + } + + errorTest.should.throw('Missing environment variable') + }) + + it('Should succeed in safe mode if allowEmptyValues is true', () => { + envTest({ path: envOneEmpty, safe: envOneEmptyExample, allowEmptyValues: true }).should.deep.equal(envOneEmptyJson) + }) + }) + describe('Missing a variable', () => { it('Should load fine (not-safe)', () => { envTest({ path: envMissingOne }).should.deep.equal(envMissingOneJson) }) - it('Should fail on safe mode', () => { + it('Should fail on safe mode (if allowEmptyValues is false)', () => { function errorTest () { envTest({ path: envMissingOne, safe: envMissingOneExample }) }