123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- /* @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')
- const os = require('os')
- function log (message /*: string */) {
- console.log(`[dotenv][DEBUG] ${message}`)
- }
- const NEWLINE = '\n'
- const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
- const RE_NEWLINES = /\\n/g
- const NEWLINES_MATCH = /\r\n|\n|\r/
- // 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(NEWLINES_MATCH).forEach(function (line, idx) {
- // matching "KEY' and 'VAL' in 'KEY=VAL'
- const keyValueArr = line.match(RE_INI_KEY_VAL)
- // matched?
- if (keyValueArr != null) {
- const key = keyValueArr[1]
- // default undefined or missing values to empty string
- let val = (keyValueArr[2] || '')
- const end = val.length - 1
- const isDoubleQuoted = val[0] === '"' && val[end] === '"'
- const isSingleQuoted = val[0] === "'" && val[end] === "'"
- // if single or double quoted, remove quotes
- if (isSingleQuoted || isDoubleQuoted) {
- val = val.substring(1, end)
- // if double quoted, expand newlines
- if (isDoubleQuoted) {
- val = val.replace(RE_NEWLINES, NEWLINE)
- }
- } else {
- // remove surrounding whitespace
- val = val.trim()
- }
- obj[key] = val
- } else if (debug) {
- log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
- }
- })
- return obj
- }
- function resolveHome (envPath) {
- return envPath[0] === '~' ? path.join(os.homedir(), envPath.slice(1)) : envPath
- }
- // Populates process.env from .env file
- function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ {
- let dotenvPath = path.resolve(process.cwd(), '.env')
- let encoding /*: string */ = 'utf8'
- let debug = false
- if (options) {
- if (options.path != null) {
- dotenvPath = resolveHome(options.path)
- }
- 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 }), { debug })
- Object.keys(parsed).forEach(function (key) {
- if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
- process.env[key] = parsed[key]
- } else if (debug) {
- log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
- }
- })
- return { parsed }
- } catch (e) {
- return { error: e }
- }
- }
- module.exports.config = config
- module.exports.parse = parse
|