Skip to content

Commit

Permalink
Merge 743d304 into ad86907
Browse files Browse the repository at this point in the history
  • Loading branch information
yTakkar committed Mar 6, 2018
2 parents ad86907 + 743d304 commit 7fc0d56
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 77 deletions.
4 changes: 2 additions & 2 deletions config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(function () {
(() => {
var options = {}
process.argv.forEach(function (val, idx, arr) {
process.argv.forEach((val, idx, arr) => {
var matches = val.match(/^dotenv_config_(.+)=(.+)/)
if (matches) {
options[matches[1]] = matches[2]
Expand Down
69 changes: 39 additions & 30 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,36 @@ const path = require('path')
* @param {(string|Buffer)} src - source to be parsed
* @returns {Object} keys and values from src
*/
function parse (src) {
const parse = src => {
const obj = {}

// convert Buffers before splitting into lines and processing
src.toString().split('\n').forEach(function (line) {
// matching "KEY' and 'VAL' in 'KEY=VAL'
const keyValueArr = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/)
// matched?
if (keyValueArr != null) {
const key = keyValueArr[1]

// default undefined or missing values to empty string
let value = keyValueArr[2] || ''

// expand newlines in quoted values
const len = value ? value.length : 0
if (len > 0 && value.charAt(0) === '"' && value.charAt(len - 1) === '"') {
value = value.replace(/\\n/gm, '\n')
}
src
.toString()
.split('\n')
.forEach(line => {
// matching "KEY' and 'VAL' in 'KEY=VAL'
const keyValueArr = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/)

// remove any surrounding quotes and extra spaces
value = value.replace(/(^['"]|['"]$)/g, '').trim()
// matched?
if (keyValueArr != null) {
const key = keyValueArr[1]

obj[key] = value
}
})
// default undefined or missing values to empty string
let value = keyValueArr[2] || ''

// expand newlines in quoted values
const len = value ? value.length : 0
if (len > 0 && value.charAt(0) === '"' && value.charAt(len - 1) === '"') {
value = value.replace(/\\n/gm, '\n')
}

// remove any surrounding quotes and extra spaces
value = value.replace(/(^['"]|['"]$)/g, '').trim()

obj[key] = value
}
})

return obj
}
Expand All @@ -45,24 +49,27 @@ function parse (src) {
* @param {string} [options.encoding=utf8] - encoding of .env file
* @returns {Object} parsed object or error
*/
function config (options) {
const config = options => {
let dotenvPath = path.resolve(process.cwd(), '.env')
let encoding = 'utf8'

if (options) {
if (options.path) {
dotenvPath = options.path
let optPath = options.path
let optEncoding = options.encoding

if (optPath) {
dotenvPath = optPath
}
if (options.encoding) {
encoding = options.encoding
if (optEncoding) {
encoding = optEncoding
}
}

try {
// specifying an encoding returns a string instead of a buffer
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }))

Object.keys(parsed).forEach(function (key) {
Object.keys(parsed).forEach(key => {
if (!process.env.hasOwnProperty(key)) {
process.env[key] = parsed[key]
}
Expand All @@ -74,6 +81,8 @@ function config (options) {
}
}

module.exports.config = config
module.exports.load = config
module.exports.parse = parse
module.exports = {
config,
load: config,
parse
}
9 changes: 4 additions & 5 deletions test/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ var describe = lab.experiment
var it = lab.test
var nodeBinary = process.argv[0]

describe('config', function () {
describe('preload', function () {
it('loads .env', function (done) {
describe('config', () => {
describe('preload', () => {
it('loads .env', done => {
// NB: `nodeBinary` is quoted for Windows
cp.exec(
'"' + nodeBinary + '" -r ../config -e "console.log(process.env.BASIC)" dotenv_config_path=./test/.env',
function (err, stdout, stderr) {
(err, stdout, stderr) => {
if (err) {
return done(err)
}

stdout.trim().should.eql('basic')

done()
}
)
Expand Down
80 changes: 40 additions & 40 deletions test/main.js
Original file line number Diff line number Diff line change
@@ -1,65 +1,65 @@
'use strict'

require('should')
var sinon = require('sinon')
let sinon = require('sinon')
var Lab = require('lab')
var lab = exports.lab = Lab.script()
var describe = lab.experiment
var before = lab.before
var beforeEach = lab.beforeEach
var afterEach = lab.afterEach
var it = lab.test
var fs = require('fs')
var dotenv = require('../lib/main')
var s
let fs = require('fs')
let dotenv = require('../lib/main')
let s

describe('dotenv', function () {
beforeEach(function (done) {
describe('dotenv', () => {
beforeEach(done => {
s = sinon.sandbox.create()
done()
})

afterEach(function (done) {
afterEach(done => {
s.restore()
done()
})

const mockParseResponse = {test: 'val'}

describe('config', function () {
var readFileSyncStub
describe('config', () => {
let readFileSyncStub

beforeEach(function (done) {
beforeEach(done => {
readFileSyncStub = s.stub(fs, 'readFileSync').returns('test=val')
s.stub(dotenv, 'parse').returns(mockParseResponse)
done()
})

it('takes option for path', function (done) {
var testPath = 'test/.env'
it('takes option for path', done => {
let testPath = 'test/.env'
dotenv.config({path: testPath})

readFileSyncStub.args[0][0].should.eql(testPath)
done()
})

it('takes option for encoding', function (done) {
var testEncoding = 'base64'
it('takes option for encoding', done => {
let testEncoding = 'base64'
dotenv.config({encoding: testEncoding})

readFileSyncStub.args[0][1].should.have.property('encoding', testEncoding)
done()
})

it('reads path with encoding, parsing output to process.env', function (done) {
it('reads path with encoding, parsing output to process.env', done => {
const res = dotenv.config()
res.parsed.should.deepEqual(mockParseResponse)

readFileSyncStub.callCount.should.eql(1)
done()
})

it('makes load a synonym of config', function (done) {
it('makes load a synonym of config', done => {
const env = dotenv.load()
env.should.have.property('parsed')
env.parsed.should.deepEqual(mockParseResponse)
Expand All @@ -68,7 +68,7 @@ describe('dotenv', function () {
done()
})

it('does not write over keys already in process.env', function (done) {
it('does not write over keys already in process.env', done => {
process.env.test = 'test'
// 'val' returned as value in `beforeEach`. should keep this 'test'
const env = dotenv.config()
Expand All @@ -82,7 +82,7 @@ describe('dotenv', function () {
done()
})

it('does not write over keys already in process.env if the key has a falsy value', function (done) {
it('does not write over keys already in process.env if the key has a falsy value', done => {
process.env.test = ''
// 'val' returned as value in `beforeEach`. should keep this ''
const env = dotenv.config()
Expand All @@ -97,99 +97,99 @@ describe('dotenv', function () {
done()
})

it('returns parsed object', function (done) {
var env = dotenv.config()
it('returns parsed object', done => {
let env = dotenv.config()

env.should.not.have.property('error')
env.parsed.should.eql(mockParseResponse)
done()
})

it('returns any errors thrown from reading file or parsing', function (done) {
it('returns any errors thrown from reading file or parsing', done => {
readFileSyncStub.throws()

var env = dotenv.config()
let env = dotenv.config()
env.should.have.property('error')
env.error.should.be.instanceOf(Error)
done()
})
})

describe('parse', function () {
var parsed
before(function (done) {
describe('parse', () => {
let parsed
before(done => {
process.env.TEST = 'test'
parsed = dotenv.parse(fs.readFileSync('test/.env', {encoding: 'utf8'}))
done()
})

it('should return an object', function (done) {
it('should return an object', done => {
parsed.should.be.an.instanceOf(Object)
done()
})

it('should parse a buffer from a file into an object', function (done) {
var buffer = new Buffer('BASIC=basic')
it('should parse a buffer from a file into an object', done => {
let buffer = new Buffer('BASIC=basic')

var payload = dotenv.parse(buffer)
let payload = dotenv.parse(buffer)
payload.should.have.property('BASIC', 'basic')
done()
})

it('sets basic environment variable', function (done) {
it('sets basic environment letiable', done => {
parsed.BASIC.should.eql('basic')
done()
})

it('reads after a skipped line', function (done) {
it('reads after a skipped line', done => {
parsed.AFTER_LINE.should.eql('after_line')
done()
})

it('defaults empty values to empty string', function (done) {
it('defaults empty values to empty string', done => {
parsed.EMPTY.should.eql('')
done()
})

it('escapes double quoted values', function (done) {
it('escapes double quoted values', done => {
parsed.DOUBLE_QUOTES.should.eql('double_quotes')
done()
})

it('escapes single quoted values', function (done) {
it('escapes single quoted values', done => {
parsed.SINGLE_QUOTES.should.eql('single_quotes')
done()
})

it('expands newlines but only if double quoted', function (done) {
it('expands newlines but only if double quoted', done => {
parsed.EXPAND_NEWLINES.should.eql('expand\nnewlines')
parsed.DONT_EXPAND_NEWLINES_1.should.eql('dontexpand\\nnewlines')
parsed.DONT_EXPAND_NEWLINES_2.should.eql('dontexpand\\nnewlines')
done()
})

it('ignores commented lines', function (done) {
it('ignores commented lines', done => {
parsed.should.not.have.property('COMMENTS')
done()
})

it('respects equals signs in values', function (done) {
it('respects equals signs in values', done => {
parsed.EQUAL_SIGNS.should.eql('equals==')
done()
})

it('retains inner quotes', function (done) {
it('retains inner quotes', done => {
parsed.RETAIN_INNER_QUOTES.should.eql('{"foo": "bar"}')
parsed.RETAIN_INNER_QUOTES_AS_STRING.should.eql('{"foo": "bar"}')
done()
})

it('retains spaces in string', function (done) {
it('retains spaces in string', done => {
parsed.INCLUDE_SPACE.should.eql('some spaced out string')
done()
})

it('parses email addresses completely', function (done) {
it('parses email addresses completely', done => {
parsed.should.have.property('USERNAME', 'therealnerdybeast@example.tld')
done()
})
Expand Down

0 comments on commit 7fc0d56

Please sign in to comment.