UNPKG

dotenv-expand

Version:

Expand environment variables using dotenv

99 lines (74 loc) 2.59 kB
'use strict' function _resolveEscapeSequences (value) { return value.replace(/\\\$/g, '$') } function expandValue (value, processEnv, runningParsed) { const env = { ...runningParsed, ...processEnv } // process.env wins const regex = /(?<!\\)\${([^{}]+)}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g let result = value let match const seen = new Set() // self-referential checker while ((match = regex.exec(result)) !== null) { seen.add(result) const [template, bracedExpression, unbracedExpression] = match const expression = bracedExpression || unbracedExpression // match the operators `:+`, `+`, `:-`, and `-` const opRegex = /(:\+|\+|:-|-)/ // find first match const opMatch = expression.match(opRegex) const splitter = opMatch ? opMatch[0] : null const r = expression.split(splitter) let defaultValue let value const key = r.shift() if ([':+', '+'].includes(splitter)) { defaultValue = env[key] ? r.join(splitter) : '' value = null } else { defaultValue = r.join(splitter) value = env[key] } if (value) { // self-referential check if (seen.has(value)) { result = result.replace(template, defaultValue) } else { result = result.replace(template, value) } } else { result = result.replace(template, defaultValue) } // if the result equaled what was in process.env and runningParsed then stop expanding if (result === runningParsed[key]) { break } regex.lastIndex = 0 // reset regex search position to re-evaluate after each replacement } return result } function expand (options) { // for use with progressive expansion const runningParsed = {} let processEnv = process.env if (options && options.processEnv != null) { processEnv = options.processEnv } // dotenv.config() ran before this so the assumption is process.env has already been set for (const key in options.parsed) { let value = options.parsed[key] // short-circuit scenario: process.env was already set prior to the file value if (processEnv[key] && processEnv[key] !== value) { value = processEnv[key] } else { value = expandValue(value, processEnv, runningParsed) } options.parsed[key] = _resolveEscapeSequences(value) // for use with progressive expansion runningParsed[key] = _resolveEscapeSequences(value) } for (const processKey in options.parsed) { processEnv[processKey] = options.parsed[processKey] } return options } module.exports.expand = expand