Skip to content

Commit

Permalink
Merge pull request #159 from mrsteele/feature/defaults
Browse files Browse the repository at this point in the history
feat: Adding support for defaults (need tests)
  • Loading branch information
mrsteele committed Jan 18, 2019
2 parents 45378c2 + a1d63f6 commit 14da142
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 35 deletions.
2 changes: 2 additions & 0 deletions .env.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TEST=nope
TEST2=hidefault
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ Use the following properties to configure your instance.
* **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.
* **defaults** (`false`) - Adds support for `dotenv-defaults`. If set to `true`, uses `./.env.defaults`. If a string, uses that location for a defaults file. Read more at https://www.npmjs.com/package/dotenv-defaults.

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

Expand All @@ -106,7 +107,8 @@ module.exports = {
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.
systemvars: true, // load all the predefined 'process.env' variables which will trump anything local per dotenv specs.
silent: true // hide any errors
silent: true, // hide any errors
defaults: false // load '.env.defaults' as the default values if empty.
})
]
...
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"webpack": "^1 || ^2 || ^3 || ^4"
},
"dependencies": {
"dotenv": "^5.0.1"
"dotenv-defaults": "^1.0.2"
},
"devDependencies": {
"babel-cli": "^6.26.0",
Expand Down
110 changes: 77 additions & 33 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import dotenv from 'dotenv'
import dotenv from 'dotenv-defaults'
import fs from 'fs'
import { DefinePlugin } from 'webpack'

Expand Down Expand Up @@ -26,50 +26,96 @@ class Dotenv {
* @param {Boolean} [options.silent=false] - If true, suppress warnings, if false, display warnings.
* @returns {webpack.DefinePlugin}
*/
constructor ({
path = './.env',
safe,
systemvars,
silent,
sample,
expand = false
} = {}) {
constructor (config = {}) {
this.config = Object.assign({}, {
path: './.env'
}, config)

this.checkDeprecation()

return new DefinePlugin(this.formatData(this.gatherVariables()))
}

checkDeprecation () {
const { sample, safe, silent } = this.config
// Catch older packages, but hold their hand (just for a bit)
if (sample) {
if (safe) {
safe = sample
this.config.safe = sample
}
this.warn('dotenv-webpack: "options.sample" is a deprecated property. Please update your configuration to use "options.safe" instead.', silent)
}
}

let vars = {}
if (systemvars) {
Object.keys(process.env).map(key => {
vars[key] = process.env[key]
})
gatherVariables () {
const { safe } = this.config
let vars = this.initializeVars()

const { env, blueprint } = this.getEnvs()

Object.keys(blueprint).map(key => {
const value = vars.hasOwnProperty(key) ? vars[key] : env[key]
if (!value && safe) {
throw new Error(`Missing environment variable: ${key}`)
} else {
vars[key] = value
}
})

// add the leftovers
if (safe) {
Object.assign(vars, env)
}

const env = this.loadFile(path, silent)
return vars
}

initializeVars () {
return (this.config.systemvars) ? Object.assign({}, process.env) : {}
}

getEnvs () {
const { path, silent, safe } = this.config

const env = dotenv.parse(this.loadFile({
file: path,
silent
}), this.getDefaults())

let blueprint = env
if (safe) {
let file = './.env.example'
if (safe !== true) {
file = safe
}
blueprint = this.loadFile(file, silent)
blueprint = dotenv.parse(this.loadFile({
file,
silent
}))
}

Object.keys(blueprint).map(key => {
const value = vars.hasOwnProperty(key) ? vars[key] : env[key]
if (!value && safe) {
throw new Error(`Missing environment variable: ${key}`)
} else {
vars[key] = value
}
})
return {
env,
blueprint
}
}

getDefaults () {
const { silent, defaults } = this.config

if (defaults) {
return this.loadFile({
file: defaults === true ? './.env.defaults' : defaults,
silent
})
}

const formatData = Object.keys(vars).reduce((obj, key) => {
return ''
}

formatData (vars = {}) {
const { expand } = this.config
return Object.keys(vars).reduce((obj, key) => {
const v = vars[key]
const vKey = `process.env.${key}`
let vValue
Expand All @@ -89,19 +135,17 @@ class Dotenv {

return obj
}, {})

return new DefinePlugin(formatData)
}

/**
* Load and parses a file.
* @param {String} file - The file to load.
* @param {Boolean} silent - If true, suppress warnings, if false, display warnings.
* Load a file.
* @param {String} config.file - The file to load.
* @param {Boolean} config.silent - If true, suppress warnings, if false, display warnings.
* @returns {Object}
*/
loadFile (file, silent) {
loadFile ({ file, silent }) {
try {
return dotenv.parse(fs.readFileSync(file))
return fs.readFileSync(file, 'utf8')
} catch (err) {
this.warn(`Failed to load ${file}.`, silent)
return {}
Expand Down
2 changes: 2 additions & 0 deletions test/envs/.defaults
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
TEST=nope
TEST2=youcanseethis
18 changes: 18 additions & 0 deletions test/main.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const envMissingOneExample = path.resolve(__dirname, './envs/.missingone.example
const envSystemvars = path.resolve(__dirname, './envs/.systemvars')
const envSystemvarsExample = path.resolve(__dirname, './envs/.systemvars.example')
const envExpanded = path.resolve(__dirname, './envs/.expanded')
const envDefaults = path.resolve(__dirname, './envs/.defaults')

const buildExpectation = (obj) => Object.keys(obj).reduce((all, key) => {
all[`process.env.${key}`] = JSON.stringify(obj[key])
Expand All @@ -28,6 +29,8 @@ const envDefJson = buildExpectation({ TEST: 'hi' })
const envEmptyJson = buildExpectation({})
const envSimpleJson = buildExpectation({ TEST: 'testing' })
const envMissingOneJson = buildExpectation({ TEST: '', TEST2: 'Hello' })
const envDefaultsJson = buildExpectation({ TEST: 'hi', TEST2: 'hidefault' })
const envDefaultsJson2 = buildExpectation({ TEST: 'hi', TEST2: 'youcanseethis' })

/*
NODE_ENV=test
Expand Down Expand Up @@ -170,6 +173,21 @@ function runTests (Obj, name) {
})
})

describe('Defaults configuration', () => {
it('should support default configurations', () => {
envTest({ defaults: true }).should.deep.equal(envDefaultsJson)
})

it('should support string configurations', () => {
envTest({ defaults: envDefaults }).should.deep.equal(envDefaultsJson2)
})

it('Should display warning when default cannot be loaded', () => {
envTest({ defaults: '.does.not.exist' }).should.deep.equal(envDefJson)
consoleSpy.calledOnce.should.equal(true)
})
})

describe('System variables', () => {
it('Should allow system env variables', () => {
const test = envTest({ path: envSimple, systemvars: true })
Expand Down

0 comments on commit 14da142

Please sign in to comment.