Skip to content

Commit

Permalink
Merge pull request #116 from mrsteele/feature/dotenv-expand
Browse files Browse the repository at this point in the history
feat: Adding dotenv-expand functionality.
  • Loading branch information
mrsteele committed Dec 27, 2018
2 parents 509d1cb + 63219bc commit f322be8
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 12 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,13 @@ A secure webpack plugin that supports dotenv and other environment variables and
<a href="https://travis-ci.org/mrsteele/dotenv-webpack" target="_blank">
<img alt="Travis" src="https://travis-ci.org/mrsteele/dotenv-webpack.svg?branch=master" />
</a>
<a href="https://codecov.io/gh/mrsteele/dotenv-webpack" target="_blank">
<img alt="codecov" src="https://codecov.io/gh/mrsteele/dotenv-webpack/branch/master/graph/badge.svg" />
</a>
<a href="https://david-dm.org/mrsteele/dotenv-webpack" target="_blank">
<img alt="Dependency Status" src="https://david-dm.org/mrsteele/dotenv-webpack.svg" />
</a>
<a href="https://david-dm.org/mrsteele/dotenv-webpack?type=dev" target="_blank">
<img alt="devDependency Status" src="https://david-dm.org/mrsteele/dotenv-webpack/dev-status.svg" />
</a>

<h1>
<img width="30" heigth="30" src="https://raw.githubusercontent.com/motdotla/dotenv/master/dotenv.png" alt="dotenv" />
<img width="30" heigth="30" src="https://webpack.js.org/assets/icon-square-big.svg" alt="webpack">
Expand Down Expand Up @@ -97,6 +94,7 @@ Use the following properties to configure your instance.
* **safe** (`false`) - If false ignore safe-mode, if true load `'./.env.example'`, if a string load that file as the sample.
* **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 surpressed.
* **expand** (`false`) - Allows your variables to be "expanded" for reusability within your `.env` file.

The following example shows how to set any/all arguments.

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"webpack": "^1 || ^2 || ^3 || ^4"
},
"dependencies": {
"dotenv": "^5.0.1"
"dotenv": "^5.0.1",
"dotenv-expand": "^4.0.1"
},
"devDependencies": {
"babel-cli": "^6.26.0",
Expand Down
35 changes: 33 additions & 2 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ import dotenv from 'dotenv'
import fs from 'fs'
import { DefinePlugin } from 'webpack'

// Mostly taken from here: https://github.com/motdotla/dotenv-expand/blob/master/lib/main.js#L4
const interpolate = (env, vars) => {
const matches = env.match(/\$([a-zA-Z0-9_]+)|\${([a-zA-Z0-9_]+)}/g) || []

matches.forEach((match) => {
const key = match.replace(/\$|{|}/g, '')
let variable = vars[key] || ''
variable = interpolate(variable, vars)
env = env.replace(match, variable)
})

return env
}

class Dotenv {
/**
* The dotenv-webpack plugin.
Expand All @@ -17,7 +31,8 @@ class Dotenv {
safe,
systemvars,
silent,
sample
sample,
expand = false
} = {}) {
// Catch older packages, but hold their hand (just for a bit)
if (sample) {
Expand Down Expand Up @@ -55,7 +70,23 @@ class Dotenv {
})

const formatData = Object.keys(vars).reduce((obj, key) => {
obj[`process.env.${key}`] = JSON.stringify(vars[key])
const v = vars[key]
const vKey = `process.env.${key}`
let vValue
if (expand) {
if (v.substring(0, 2) === '\\$') {
vValue = v.substring(1)
} else if (v.indexOf('\\$') > 0) {
vValue = v.replace(/\\\$/g, '$')
} else {
vValue = interpolate(v, vars)
}
} else {
vValue = v
}

obj[vKey] = JSON.stringify(vValue)

return obj
}, {})

Expand Down
20 changes: 20 additions & 0 deletions test/envs/.expanded
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
NODE_ENV=test
BASIC=basic
BASIC_EXPAND=$BASIC
MACHINE=machine_env
MACHINE_EXPAND=$MACHINE
UNDEFINED_EXPAND=$UNDEFINED_ENV_KEY
ESCAPED_EXPAND=\$ESCAPED
MONGOLAB_DATABASE=heroku_db
MONGOLAB_USER=username
MONGOLAB_PASSWORD=password
MONGOLAB_DOMAIN=abcd1234.mongolab.com
MONGOLAB_PORT=12345
MONGOLAB_URI=mongodb://${MONGOLAB_USER}:${MONGOLAB_PASSWORD}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}

MONGOLAB_USER_RECURSIVELY=${MONGOLAB_USER}:${MONGOLAB_PASSWORD}
MONGOLAB_URI_RECURSIVELY=mongodb://${MONGOLAB_USER_RECURSIVELY}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}

WITHOUT_CURLY_BRACES_URI=mongodb://$MONGOLAB_USER:$MONGOLAB_PASSWORD@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE
WITHOUT_CURLY_BRACES_USER_RECURSIVELY=$MONGOLAB_USER:$MONGOLAB_PASSWORD
WITHOUT_CURLY_BRACES_URI_RECURSIVELY=mongodb://$MONGOLAB_USER_RECURSIVELY@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE
92 changes: 87 additions & 5 deletions test/main.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,85 @@ const envMissingOne = path.resolve(__dirname, './envs/.missingone')
const envMissingOneExample = path.resolve(__dirname, './envs/.missingone.example')
const envSystemvars = path.resolve(__dirname, './envs/.systemvars')
const envSystemvarsExample = path.resolve(__dirname, './envs/.systemvars.example')

const envDefJson = { 'process.env.TEST': '"hi"' }
const envEmptyJson = {}
const envSimpleJson = { 'process.env.TEST': '"testing"' }
const envMissingOneJson = { 'process.env.TEST': '""', 'process.env.TEST2': '"Hello"' }
const envExpanded = path.resolve(__dirname, './envs/.expanded')

const buildExpectation = (obj) => Object.keys(obj).reduce((all, key) => {
all[`process.env.${key}`] = JSON.stringify(obj[key])
return all
}, {})

const envDefJson = buildExpectation({ TEST: 'hi' })
const envEmptyJson = buildExpectation({})
const envSimpleJson = buildExpectation({ TEST: 'testing' })
const envMissingOneJson = buildExpectation({ TEST: '', TEST2: 'Hello' })

/*
NODE_ENV=test
BASIC=basic
BASIC_EXPAND=$BASIC
MACHINE=machine_env
MACHINE_EXPAND=$MACHINE
UNDEFINED_EXPAND=$UNDEFINED_ENV_KEY
ESCAPED_EXPAND=\$ESCAPED
MONGOLAB_DATABASE=heroku_db
MONGOLAB_USER=username
MONGOLAB_PASSWORD=password
MONGOLAB_DOMAIN=abcd1234.mongolab.com
MONGOLAB_PORT=12345
MONGOLAB_URI=mongodb://${MONGOLAB_USER}:${MONGOLAB_PASSWORD}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}
MONGOLAB_USER_RECURSIVELY=${MONGOLAB_USER}:${MONGOLAB_PASSWORD}
MONGOLAB_URI_RECURSIVELY=mongodb://${MONGOLAB_USER_RECURSIVELY}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}
WITHOUT_CURLY_BRACES_URI=mongodb://$MONGOLAB_USER:$MONGOLAB_PASSWORD@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE
WITHOUT_CURLY_BRACES_USER_RECURSIVELY=$MONGOLAB_USER:$MONGOLAB_PASSWORD
WITHOUT_CURLY_BRACES_URI_RECURSIVELY=mongodb://$MONGOLAB_USER_RECURSIVELY@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE
*/
const envExpandedNotJson = buildExpectation({
NODE_ENV: 'test',
BASIC: 'basic',
BASIC_EXPAND: '$BASIC',
MACHINE: 'machine_env',
MACHINE_EXPAND: '$MACHINE',
UNDEFINED_EXPAND: '$UNDEFINED_ENV_KEY',
// eslint-disable-next-line
ESCAPED_EXPAND: '\\$ESCAPED',
MONGOLAB_DATABASE: 'heroku_db',
MONGOLAB_USER: 'username',
MONGOLAB_PASSWORD: 'password',
MONGOLAB_DOMAIN: 'abcd1234.mongolab.com',
MONGOLAB_PORT: '12345',
// eslint-disable-next-line
MONGOLAB_URI: 'mongodb://${MONGOLAB_USER}:${MONGOLAB_PASSWORD}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}',
// eslint-disable-next-line
MONGOLAB_USER_RECURSIVELY: '${MONGOLAB_USER}:${MONGOLAB_PASSWORD}',
// eslint-disable-next-line
MONGOLAB_URI_RECURSIVELY: 'mongodb://${MONGOLAB_USER_RECURSIVELY}@${MONGOLAB_DOMAIN}:${MONGOLAB_PORT}/${MONGOLAB_DATABASE}',
WITHOUT_CURLY_BRACES_URI: 'mongodb://$MONGOLAB_USER:$MONGOLAB_PASSWORD@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE',
WITHOUT_CURLY_BRACES_USER_RECURSIVELY: '$MONGOLAB_USER:$MONGOLAB_PASSWORD',
WITHOUT_CURLY_BRACES_URI_RECURSIVELY: 'mongodb://$MONGOLAB_USER_RECURSIVELY@$MONGOLAB_DOMAIN:$MONGOLAB_PORT/$MONGOLAB_DATABASE'
})
const envExpandedJson = buildExpectation({
NODE_ENV: 'test',
BASIC: 'basic',
BASIC_EXPAND: 'basic',
MACHINE: 'machine_env',
MACHINE_EXPAND: 'machine_env',
UNDEFINED_EXPAND: '',
// eslint-disable-next-line
ESCAPED_EXPAND: '\$ESCAPED',
MONGOLAB_DATABASE: 'heroku_db',
MONGOLAB_USER: 'username',
MONGOLAB_PASSWORD: 'password',
MONGOLAB_DOMAIN: 'abcd1234.mongolab.com',
MONGOLAB_PORT: '12345',
MONGOLAB_URI: 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db',
MONGOLAB_USER_RECURSIVELY: 'username:password',
MONGOLAB_URI_RECURSIVELY: 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db',
WITHOUT_CURLY_BRACES_URI: 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db',
WITHOUT_CURLY_BRACES_USER_RECURSIVELY: 'username:password',
WITHOUT_CURLY_BRACES_URI_RECURSIVELY: 'mongodb://username:password@abcd1234.mongolab.com:12345/heroku_db'
})

const consoleSpy = sinon.spy(console, 'warn')

Expand Down Expand Up @@ -49,6 +123,14 @@ function runTests (Obj, name) {
it('Should include environment variables that exist in .env file.', () => {
envTest().should.deep.equal(envDefJson)
})

it('Should not expand variables by default', () => {
envTest({ path: envExpanded }).should.deep.equal(envExpandedNotJson)
})

it('Should expand variables when configured', () => {
envTest({ path: envExpanded, expand: true }).should.deep.equal(envExpandedJson)
})
})

describe('Simple configuration', () => {
Expand Down

0 comments on commit f322be8

Please sign in to comment.