Initial code test
This commit is contained in:
commit
d4fae15f5c
1696 files changed
+271223
No files matched your search
+50
@@ -0,0 +1,50 @@
|
||||
// TypeScript Version: 3.0
|
||||
/// <reference types="node" />
|
||||
|
||||
export interface DotenvPopulateInput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
export interface DotenvParseInput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
export interface DotenvParseOutput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
export interface DotenvExpandOptions {
|
||||
error?: Error;
|
||||
|
||||
/**
|
||||
* Default: `process.env`
|
||||
*
|
||||
* Specify an object to write your secrets to. Defaults to process.env environment variables.
|
||||
*
|
||||
* example: `const processEnv = {}; require('dotenv').config({ processEnv: processEnv })`
|
||||
*/
|
||||
processEnv?: DotenvPopulateInput;
|
||||
|
||||
/**
|
||||
* Default: `object`
|
||||
*
|
||||
* Object coming from dotenv's parsed result.
|
||||
*/
|
||||
parsed?: DotenvParseInput;
|
||||
}
|
||||
|
||||
export interface DotenvExpandOutput {
|
||||
error?: Error;
|
||||
parsed?: DotenvParseOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds variable expansion on top of dotenv.
|
||||
*
|
||||
* See https://docs.dotenv.org
|
||||
*
|
||||
* @param options - additional options. example: `{ processEnv: {}, error: null, parsed: { { KEY: 'value' } }`
|
||||
* @returns an object with a `parsed` key if successful or `error` key if an error occurred. example: { parsed: { KEY: 'value' } }
|
||||
*
|
||||
*/
|
||||
export function expand(options?: DotenvExpandOptions): DotenvExpandOutput
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
'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
|
||||
Reference in new issue
Block a user