diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 00000000..69ec8356 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,23 @@ +[ignore] + +[include] + +[libs] + +[lints] +all=warn + +[options] +emoji=true +include_warnings=true + +[strict] +nonstrict-import +sketchy-null +unclear-type +unsafe-getters-setters +untyped-import +untyped-type-import + +[version] +^0.82.0 diff --git a/.gitignore b/.gitignore index 11894ca3..7d7e2bc1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,7 @@ -# Coverage directory used by tools like istanbul -coverage +# Coverage directory .nyc_output # Dependency directory -# Commenting this out is preferred by some people, see -# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules -# Users Environment Variables -.lock-wscript - .DS_Store diff --git a/README.md b/README.md index 887bf9f2..4bb6add4 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ You can additionally, pass options to `config`. Default: `path.resolve(process.cwd(), '.env')` -You can specify a custom path if your file containing environment variables is +You may specify a custom path if your file containing environment variables is named or located differently. ```js @@ -109,6 +109,16 @@ using this option. require('dotenv').config({ encoding: 'base64' }) ``` +#### Debug + +Default: `false` + +You may turn on logging to help debug why certain keys or values are not being set as you expect. + +```js +require('dotenv').config({ debug: process.env.DEBUG }) +``` + ## Parse The engine which parses the contents of your file containing environment @@ -122,6 +132,22 @@ const config = dotenv.parse(buf) // will return an object console.log(typeof config, config) // object { BASIC : 'basic' } ``` +### Options + +#### Debug + +Default: `false` + +You may turn on logging to help debug why certain keys or values are not being set as you expect. + +```js +const dotenv = require('dotenv') +const buf = Buffer.from('hello world') +const opt = { debug: true } +const config = dotenv.parse(buf, opt) +// expect a debug message because the buffer is not in KEY=VAL form +``` + ### Rules The parsing engine currently supports the following rules: diff --git a/config.js b/config.js index 8ac2a360..77641220 100644 --- a/config.js +++ b/config.js @@ -1,3 +1,5 @@ +/* @flow */ + (function () { require('./lib/main').config( require('./lib/cli-options')(process.argv) diff --git a/flow-typed/npm/sinon_vx.x.x.js b/flow-typed/npm/sinon_vx.x.x.js new file mode 100644 index 00000000..183358be --- /dev/null +++ b/flow-typed/npm/sinon_vx.x.x.js @@ -0,0 +1,361 @@ +// flow-typed signature: fd98cafe7bb28287e51ca85d49a17379 +// flow-typed version: <>/sinon_v6.3.5/flow_v0.82.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'sinon' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'sinon' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'sinon/lib/sinon' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/assert' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/behavior' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/blob' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/call' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/collect-own-methods' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/color' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/create-sandbox' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/default-behaviors' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/fake' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/match' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/mock-expectation' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/mock' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/sandbox' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/spy-formatters' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/spy' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/stub-entire-object' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/stub-non-function-property' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/stub' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/throw-on-falsy-object' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/called-in-order' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/deep-equal' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/default-config' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/deprecated' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/every' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/extend' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/format' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/function-to-string' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/get-config' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/get-next-tick' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/get-property-descriptor' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/is-es-module' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/is-non-existent-own-property' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/is-property-configurable' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/is-restorable' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/iterable-to-string' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/next-tick' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/order-by-first-call' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/restore' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/times-in-words' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/typeOf' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/use-promise-library' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/walk' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/core/wrap-method' { + declare module.exports: any; +} + +declare module 'sinon/lib/sinon/util/fake_timers' { + declare module.exports: any; +} + +declare module 'sinon/pkg/sinon-esm' { + declare module.exports: any; +} + +declare module 'sinon/pkg/sinon-no-sourcemaps' { + declare module.exports: any; +} + +declare module 'sinon/pkg/sinon' { + declare module.exports: any; +} + +// Filename aliases +declare module 'sinon/lib/sinon.js' { + declare module.exports: $Exports<'sinon/lib/sinon'>; +} +declare module 'sinon/lib/sinon/assert.js' { + declare module.exports: $Exports<'sinon/lib/sinon/assert'>; +} +declare module 'sinon/lib/sinon/behavior.js' { + declare module.exports: $Exports<'sinon/lib/sinon/behavior'>; +} +declare module 'sinon/lib/sinon/blob.js' { + declare module.exports: $Exports<'sinon/lib/sinon/blob'>; +} +declare module 'sinon/lib/sinon/call.js' { + declare module.exports: $Exports<'sinon/lib/sinon/call'>; +} +declare module 'sinon/lib/sinon/collect-own-methods.js' { + declare module.exports: $Exports<'sinon/lib/sinon/collect-own-methods'>; +} +declare module 'sinon/lib/sinon/color.js' { + declare module.exports: $Exports<'sinon/lib/sinon/color'>; +} +declare module 'sinon/lib/sinon/create-sandbox.js' { + declare module.exports: $Exports<'sinon/lib/sinon/create-sandbox'>; +} +declare module 'sinon/lib/sinon/default-behaviors.js' { + declare module.exports: $Exports<'sinon/lib/sinon/default-behaviors'>; +} +declare module 'sinon/lib/sinon/fake.js' { + declare module.exports: $Exports<'sinon/lib/sinon/fake'>; +} +declare module 'sinon/lib/sinon/match.js' { + declare module.exports: $Exports<'sinon/lib/sinon/match'>; +} +declare module 'sinon/lib/sinon/mock-expectation.js' { + declare module.exports: $Exports<'sinon/lib/sinon/mock-expectation'>; +} +declare module 'sinon/lib/sinon/mock.js' { + declare module.exports: $Exports<'sinon/lib/sinon/mock'>; +} +declare module 'sinon/lib/sinon/sandbox.js' { + declare module.exports: $Exports<'sinon/lib/sinon/sandbox'>; +} +declare module 'sinon/lib/sinon/spy-formatters.js' { + declare module.exports: $Exports<'sinon/lib/sinon/spy-formatters'>; +} +declare module 'sinon/lib/sinon/spy.js' { + declare module.exports: $Exports<'sinon/lib/sinon/spy'>; +} +declare module 'sinon/lib/sinon/stub-entire-object.js' { + declare module.exports: $Exports<'sinon/lib/sinon/stub-entire-object'>; +} +declare module 'sinon/lib/sinon/stub-non-function-property.js' { + declare module.exports: $Exports<'sinon/lib/sinon/stub-non-function-property'>; +} +declare module 'sinon/lib/sinon/stub.js' { + declare module.exports: $Exports<'sinon/lib/sinon/stub'>; +} +declare module 'sinon/lib/sinon/throw-on-falsy-object.js' { + declare module.exports: $Exports<'sinon/lib/sinon/throw-on-falsy-object'>; +} +declare module 'sinon/lib/sinon/util/core/called-in-order.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/called-in-order'>; +} +declare module 'sinon/lib/sinon/util/core/deep-equal.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/deep-equal'>; +} +declare module 'sinon/lib/sinon/util/core/default-config.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/default-config'>; +} +declare module 'sinon/lib/sinon/util/core/deprecated.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/deprecated'>; +} +declare module 'sinon/lib/sinon/util/core/every.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/every'>; +} +declare module 'sinon/lib/sinon/util/core/extend.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/extend'>; +} +declare module 'sinon/lib/sinon/util/core/format.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/format'>; +} +declare module 'sinon/lib/sinon/util/core/function-to-string.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/function-to-string'>; +} +declare module 'sinon/lib/sinon/util/core/get-config.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/get-config'>; +} +declare module 'sinon/lib/sinon/util/core/get-next-tick.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/get-next-tick'>; +} +declare module 'sinon/lib/sinon/util/core/get-property-descriptor.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/get-property-descriptor'>; +} +declare module 'sinon/lib/sinon/util/core/is-es-module.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/is-es-module'>; +} +declare module 'sinon/lib/sinon/util/core/is-non-existent-own-property.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/is-non-existent-own-property'>; +} +declare module 'sinon/lib/sinon/util/core/is-property-configurable.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/is-property-configurable'>; +} +declare module 'sinon/lib/sinon/util/core/is-restorable.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/is-restorable'>; +} +declare module 'sinon/lib/sinon/util/core/iterable-to-string.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/iterable-to-string'>; +} +declare module 'sinon/lib/sinon/util/core/next-tick.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/next-tick'>; +} +declare module 'sinon/lib/sinon/util/core/order-by-first-call.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/order-by-first-call'>; +} +declare module 'sinon/lib/sinon/util/core/restore.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/restore'>; +} +declare module 'sinon/lib/sinon/util/core/times-in-words.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/times-in-words'>; +} +declare module 'sinon/lib/sinon/util/core/typeOf.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/typeOf'>; +} +declare module 'sinon/lib/sinon/util/core/use-promise-library.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/use-promise-library'>; +} +declare module 'sinon/lib/sinon/util/core/walk.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/walk'>; +} +declare module 'sinon/lib/sinon/util/core/wrap-method.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/core/wrap-method'>; +} +declare module 'sinon/lib/sinon/util/fake_timers.js' { + declare module.exports: $Exports<'sinon/lib/sinon/util/fake_timers'>; +} +declare module 'sinon/pkg/sinon-esm.js' { + declare module.exports: $Exports<'sinon/pkg/sinon-esm'>; +} +declare module 'sinon/pkg/sinon-no-sourcemaps.js' { + declare module.exports: $Exports<'sinon/pkg/sinon-no-sourcemaps'>; +} +declare module 'sinon/pkg/sinon.js' { + declare module.exports: $Exports<'sinon/pkg/sinon'>; +} diff --git a/flow-typed/npm/tap_vx.x.x.js b/flow-typed/npm/tap_vx.x.x.js new file mode 100644 index 00000000..069b481a --- /dev/null +++ b/flow-typed/npm/tap_vx.x.x.js @@ -0,0 +1,144 @@ +// flow-typed signature: babbe08a031ef4f7eb2f8d9812098a53 +// flow-typed version: <>/tap_v12.0.1/flow_v0.82.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'tap' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'tap' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'tap/bin/mochatap' { + declare module.exports: any; +} + +declare module 'tap/bin/run' { + declare module.exports: any; +} + +declare module 'tap/lib/base' { + declare module.exports: any; +} + +declare module 'tap/lib/clean-yaml-object' { + declare module.exports: any; +} + +declare module 'tap/lib/diags' { + declare module.exports: any; +} + +declare module 'tap/lib/extra-from-error' { + declare module.exports: any; +} + +declare module 'tap/lib/mocha' { + declare module.exports: any; +} + +declare module 'tap/lib/obj-to-yaml' { + declare module.exports: any; +} + +declare module 'tap/lib/parse-test-args' { + declare module.exports: any; +} + +declare module 'tap/lib/point' { + declare module.exports: any; +} + +declare module 'tap/lib/snapshot' { + declare module.exports: any; +} + +declare module 'tap/lib/spawn' { + declare module.exports: any; +} + +declare module 'tap/lib/stack' { + declare module.exports: any; +} + +declare module 'tap/lib/stdin' { + declare module.exports: any; +} + +declare module 'tap/lib/synonyms' { + declare module.exports: any; +} + +declare module 'tap/lib/tap' { + declare module.exports: any; +} + +declare module 'tap/lib/test' { + declare module.exports: any; +} + +// Filename aliases +declare module 'tap/bin/mochatap.js' { + declare module.exports: $Exports<'tap/bin/mochatap'>; +} +declare module 'tap/bin/run.js' { + declare module.exports: $Exports<'tap/bin/run'>; +} +declare module 'tap/lib/base.js' { + declare module.exports: $Exports<'tap/lib/base'>; +} +declare module 'tap/lib/clean-yaml-object.js' { + declare module.exports: $Exports<'tap/lib/clean-yaml-object'>; +} +declare module 'tap/lib/diags.js' { + declare module.exports: $Exports<'tap/lib/diags'>; +} +declare module 'tap/lib/extra-from-error.js' { + declare module.exports: $Exports<'tap/lib/extra-from-error'>; +} +declare module 'tap/lib/mocha.js' { + declare module.exports: $Exports<'tap/lib/mocha'>; +} +declare module 'tap/lib/obj-to-yaml.js' { + declare module.exports: $Exports<'tap/lib/obj-to-yaml'>; +} +declare module 'tap/lib/parse-test-args.js' { + declare module.exports: $Exports<'tap/lib/parse-test-args'>; +} +declare module 'tap/lib/point.js' { + declare module.exports: $Exports<'tap/lib/point'>; +} +declare module 'tap/lib/snapshot.js' { + declare module.exports: $Exports<'tap/lib/snapshot'>; +} +declare module 'tap/lib/spawn.js' { + declare module.exports: $Exports<'tap/lib/spawn'>; +} +declare module 'tap/lib/stack.js' { + declare module.exports: $Exports<'tap/lib/stack'>; +} +declare module 'tap/lib/stdin.js' { + declare module.exports: $Exports<'tap/lib/stdin'>; +} +declare module 'tap/lib/synonyms.js' { + declare module.exports: $Exports<'tap/lib/synonyms'>; +} +declare module 'tap/lib/tap.js' { + declare module.exports: $Exports<'tap/lib/tap'>; +} +declare module 'tap/lib/test.js' { + declare module.exports: $Exports<'tap/lib/test'>; +} diff --git a/lib/cli-options.js b/lib/cli-options.js index 36ecdf61..ad69fabd 100644 --- a/lib/cli-options.js +++ b/lib/cli-options.js @@ -1,6 +1,8 @@ -const re = /^dotenv_config_(encoding|path)=(.+)$/ +/* @flow */ -module.exports = function optionMatcher (args) { +const re = /^dotenv_config_(encoding|path|debug)=(.+)$/ + +module.exports = function optionMatcher (args /*: Array */) { return args.reduce(function (acc, cur) { const matches = cur.match(re) if (matches) { diff --git a/lib/main.js b/lib/main.js index ae61a3d1..4da2961b 100644 --- a/lib/main.js +++ b/lib/main.js @@ -1,16 +1,40 @@ +/* @flow */ +/*:: + +type DotenvParseOptions = { + debug?: boolean +} + +// keys and values from src +type DotenvParseOutput = { [string]: string } + +type DotenvConfigOptions = { + path?: string, // path to .env file + encoding?: string, // encoding of .env file + debug?: string // turn on logging for debugging purposes +} + +type DotenvConfigOutput = { + parsed?: DotenvParseOutput, + error?: Error +} + +*/ + const fs = require('fs') const path = require('path') -/* - * Parses a string or buffer into an object - * @param {(string|Buffer)} src - source to be parsed - * @returns {Object} keys and values from src -*/ -function parse (src) { +function log (message /*: string */) { + console.log(`[dotenv][DEBUG] ${message}`) +} + +// Parses src into an Object +function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ { + const debug = Boolean(options && options.debug) const obj = {} // convert Buffers before splitting into lines and processing - src.toString().split('\n').forEach(function (line) { + src.toString().split('\n').forEach(function (line, idx) { // matching "KEY' and 'VAL' in 'KEY=VAL' const keyValueArr = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/) // matched? @@ -30,39 +54,41 @@ function parse (src) { value = value.replace(/(^['"]|['"]$)/g, '').trim() obj[key] = value + } else if (debug) { + log(`did not match key and value when parsing line ${idx + 1}: ${line}`) } }) return obj } -/* - * Main entry point into dotenv. Allows configuration before loading .env - * @param {Object} options - options for parsing .env file - * @param {string} [options.path=.env] - path to .env file - * @param {string} [options.encoding=utf8] - encoding of .env file - * @returns {Object} parsed object or error -*/ -function config (options) { +// Populates process.env from .env file +function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ { let dotenvPath = path.resolve(process.cwd(), '.env') - let encoding = 'utf8' + let encoding /*: string */ = 'utf8' + let debug = false if (options) { - if (options.path) { + if (options.path != null) { dotenvPath = options.path } - if (options.encoding) { + if (options.encoding != null) { encoding = options.encoding } + if (options.debug != null) { + debug = true + } } try { // specifying an encoding returns a string instead of a buffer - const parsed = parse(fs.readFileSync(dotenvPath, { encoding })) + const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug }) Object.keys(parsed).forEach(function (key) { if (!process.env.hasOwnProperty(key)) { process.env[key] = parsed[key] + } else if (debug) { + log(`"${key}" is already defined in \`process.env\` and will not be overwritten`) } }) diff --git a/package-lock.json b/package-lock.json index ee758862..9ae1c6e7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,13 +50,10 @@ } }, "@sinonjs/samsam": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.1.tgz", - "integrity": "sha512-7oX6PXMulvdN37h88dvlvRyu61GYZau40fL4wEZvPEHvrjpJc3lDv6xDM5n4Z0StufUVB5nDvVZUM+jZHdMOOQ==", - "dev": true, - "requires": { - "array-from": "^2.1.1" - } + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-2.1.2.tgz", + "integrity": "sha512-ZwTHAlC9akprWDinwEPD4kOuwaYZlyMwVJIANsKNC3QVp0AHB04m7RnB4eqeWfgmxw8MGTzS9uMaw93Z3QcZbw==", + "dev": true }, "acorn": { "version": "5.7.3", @@ -237,7 +234,7 @@ "dependencies": { "chalk": { "version": "1.1.3", - "resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", "dev": true, "requires": { @@ -250,7 +247,7 @@ }, "strip-ansi": { "version": "3.0.1", - "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", "dev": true, "requires": { @@ -1247,7 +1244,7 @@ }, "external-editor": { "version": "2.2.0", - "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", "dev": true, "requires": { @@ -1429,6 +1426,12 @@ "write": "^0.2.1" } }, + "flow-bin": { + "version": "0.82.0", + "resolved": "https://registry.npmjs.org/flow-bin/-/flow-bin-0.82.0.tgz", + "integrity": "sha512-D7ViTCVJSVv19CB6dFWS9k2iKQlavtkRXn9el0ofVTTpGuybe+EPE8DZwdyohzEt6wRhHV8gwkteWvxdcVuOzg==", + "dev": true + }, "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", @@ -1805,7 +1808,7 @@ }, "is-builtin-module": { "version": "1.0.0", - "resolved": "http://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", "dev": true, "requires": { @@ -2113,7 +2116,7 @@ }, "load-json-file": { "version": "2.0.0", - "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", "dev": true, "requires": { @@ -5705,17 +5708,17 @@ "dev": true }, "sinon": { - "version": "6.3.4", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.3.4.tgz", - "integrity": "sha512-NIaR56Z1mefuRBXYrf4otqBxkWiKveX+fvqs3HzFq2b07HcgpkMgIwmQM/owNjNFAHkx0kJXW+Q0mDthiuslXw==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-6.3.5.tgz", + "integrity": "sha512-xgoZ2gKjyVRcF08RrIQc+srnSyY1JDJtxu3Nsz07j1ffjgXoY6uPLf/qja6nDBZgzYYEovVkFryw2+KiZz11xQ==", "dev": true, "requires": { "@sinonjs/commons": "^1.0.2", "@sinonjs/formatio": "^3.0.0", - "@sinonjs/samsam": "^2.1.1", + "@sinonjs/samsam": "^2.1.2", "diff": "^3.5.0", "lodash.get": "^4.4.2", - "lolex": "^2.7.4", + "lolex": "^2.7.5", "nise": "^1.4.5", "supports-color": "^5.5.0", "type-detect": "^4.0.8" @@ -6267,7 +6270,7 @@ }, "through": { "version": "2.3.8", - "resolved": "http://registry.npmjs.org/through/-/through-2.3.8.tgz", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", "dev": true }, diff --git a/package.json b/package.json index a1b49a1a..f0ee2253 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "description": "Loads environment variables from .env file", "main": "lib/main.js", "scripts": { + "flow": "flow", "pretest": "npm run lint", "test": "tap tests/*.js --100", "lint": "standard", @@ -26,7 +27,8 @@ "readmeFilename": "README.md", "license": "BSD-2-Clause", "devDependencies": { - "sinon": "^6.3.4", + "flow-bin": "^0.82.0", + "sinon": "^6.3.5", "standard": "^12.0.1", "standard-markdown": "^5.0.1", "tap": "^12.0.1" @@ -34,5 +36,10 @@ "dependencies": {}, "engines": { "node": ">=6" + }, + "standard": { + "ignore": [ + "flow-typed/" + ] } } diff --git a/tests/test-cli-options.js b/tests/test-cli-options.js index d9fdb748..5ecf02ff 100644 --- a/tests/test-cli-options.js +++ b/tests/test-cli-options.js @@ -1,8 +1,10 @@ +/* @flow */ + const t = require('tap') const options = require('../lib/cli-options') -t.plan(4) +t.plan(5) // matches encoding option t.same(options(['node', '-e', "'console.log(testing)'", 'dotenv_config_encoding=utf8']), { @@ -14,6 +16,11 @@ t.same(options(['node', '-e', "'console.log(testing)'", 'dotenv_config_path=/cus path: '/custom/path/to/your/env/vars' }) +// matches debug option +t.same(options(['node', '-e', "'console.log(testing)'", 'dotenv_config_debug=true']), { + debug: 'true' +}) + // ignores empty values t.same(options(['node', '-e', "'console.log(testing)'", 'dotenv_config_path=']), {}) diff --git a/tests/test-config-cli.js b/tests/test-config-cli.js index 548bef26..c5281165 100644 --- a/tests/test-config-cli.js +++ b/tests/test-config-cli.js @@ -1,3 +1,5 @@ +/* @flow */ + const cp = require('child_process') const path = require('path') @@ -25,5 +27,5 @@ test('config preload loads .env', t => { } ) - t.equal(stdout.trim(), 'basic') + t.equal(stdout, 'basic\n') }) diff --git a/tests/test-config.js b/tests/test-config.js index 68c4fd83..8f883c6b 100644 --- a/tests/test-config.js +++ b/tests/test-config.js @@ -1,22 +1,25 @@ +/* @flow */ + const fs = require('fs') -const t = require('tap') const sinon = require('sinon') +const t = require('tap') const dotenv = require('../lib/main') const mockParseResponse = { test: 'foo' } let readFileSyncStub +let parseStub t.beforeEach(done => { readFileSyncStub = sinon.stub(fs, 'readFileSync').returns('test=foo') - sinon.stub(dotenv, 'parse').returns(mockParseResponse) + parseStub = sinon.stub(dotenv, 'parse').returns(mockParseResponse) done() }) t.afterEach(done => { readFileSyncStub.restore() - dotenv.parse.restore() + parseStub.restore() done() }) @@ -38,12 +41,22 @@ t.test('takes option for encoding', ct => { ct.equal(readFileSyncStub.args[0][1].encoding, testEncoding) }) +t.test('takes option for debug', ct => { + ct.plan(1) + + const logStub = sinon.stub(console, 'log') + dotenv.config({ debug: 'true' }) + + ct.ok(logStub.called) + logStub.restore() +}) + t.test('reads path with encoding, parsing output to process.env', ct => { ct.plan(2) const res = dotenv.config() - ct.same(res.parsed, mockParseResponse) + ct.same(res.parsed, mockParseResponse) ct.equal(readFileSyncStub.callCount, 1) }) @@ -51,6 +64,7 @@ t.test('makes load a synonym of config', ct => { ct.plan(2) const env = dotenv.load() + ct.same(env.parsed, mockParseResponse) ct.equal(readFileSyncStub.callCount, 1) }) @@ -63,7 +77,7 @@ t.test('does not write over keys already in process.env', ct => { // 'foo' returned as value in `beforeEach`. should keep this 'bar' const env = dotenv.config() - ct.equal(env.parsed.test, mockParseResponse.test) + ct.equal(env.parsed && env.parsed.test, mockParseResponse.test) ct.equal(process.env.test, existing) }) @@ -75,7 +89,7 @@ t.test('does not write over keys already in process.env if the key has a falsy v // 'foo' returned as value in `beforeEach`. should keep this '' const env = dotenv.config() - ct.equal(env.parsed.test, mockParseResponse.test) + ct.equal(env.parsed && env.parsed.test, mockParseResponse.test) // NB: process.env.test becomes undefined on Windows ct.notOk(process.env.test) }) diff --git a/tests/test-parse.js b/tests/test-parse.js index 4210933c..cd517b6f 100644 --- a/tests/test-parse.js +++ b/tests/test-parse.js @@ -1,5 +1,8 @@ +/* @flow */ + const fs = require('fs') +const sinon = require('sinon') const t = require('tap') const dotenv = require('../lib/main') @@ -7,7 +10,7 @@ const dotenv = require('../lib/main') process.env.TEST = 'test' const parsed = dotenv.parse(fs.readFileSync('tests/.env', { encoding: 'utf8' })) -t.plan(16) +t.plan(17) t.type(parsed, Object, 'should return an object') @@ -41,3 +44,9 @@ t.equal(parsed['USERNAME'], 'therealnerdybeast@example.tld', 'parses email addre const payload = dotenv.parse(Buffer.from('BASIC=basic')) t.equal(payload.BASIC, 'basic', 'should parse a buffer from a file into an object') + +// test debug path +const logStub = sinon.stub(console, 'log') +dotenv.parse(Buffer.from('what is this'), { debug: true }) +t.ok(logStub.called) +logStub.restore()