-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
Copy pathmain.js
98 lines (74 loc) · 2.53 KB
/
main.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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