@dotenvx/dotenvx 1.75.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +39 -1
- package/README.md +4 -114
- package/package.json +8 -7
- package/src/cli/actions/decrypt.js +35 -17
- package/src/cli/actions/doctor.js +2 -2
- package/src/cli/actions/encrypt.js +64 -85
- package/src/cli/actions/ext/genexample.js +2 -2
- package/src/cli/actions/get.js +22 -7
- package/src/cli/actions/keypair.js +55 -42
- package/src/cli/actions/login.js +4 -3
- package/src/cli/actions/normalizeArmorAliases.js +9 -0
- package/src/cli/actions/run.js +65 -22
- package/src/cli/actions/set.js +87 -37
- package/src/cli/dotenvx.js +8 -23
- package/src/lib/api/{postKeypair.js → postArmorKeyring.js} +4 -14
- package/src/lib/{helpers/envResolution → conventions}/environment.js +1 -1
- package/src/lib/conventions/filepaths.js +9 -0
- package/src/lib/conventions/keynames.js +38 -0
- package/src/lib/helpers/catchAndLog.js +4 -1
- package/src/lib/helpers/cryptography/index.js +2 -9
- package/src/lib/helpers/cryptography/{isPublicKey.js → isDotenvPublicKey.js} +2 -2
- package/src/lib/helpers/cryptography/isPlainKey.js +7 -0
- package/src/lib/helpers/cryptography/mutateKeysSrc.js +5 -21
- package/src/lib/helpers/envResolution/index.js +1 -1
- package/src/lib/helpers/errors.js +26 -0
- package/src/lib/helpers/keypairMetadata.js +1 -1
- package/src/lib/helpers/prompts.js +46 -0
- package/src/lib/main.d.ts +2 -39
- package/src/lib/main.js +83 -46
- package/src/lib/providers/armor/index.js +29 -0
- package/src/lib/providers/index.js +46 -0
- package/src/lib/providers/worker.js +6 -0
- package/src/lib/resolvers/envs.js +302 -0
- package/src/lib/resolvers/get.js +69 -0
- package/src/lib/resolvers/keypair.js +81 -0
- package/src/lib/resolvers/ls.js +41 -0
- package/src/lib/services/armorDown.js +2 -2
- package/src/lib/services/{armorKeypair.js → armorKeyring.js} +14 -51
- package/src/lib/services/armorMove.js +2 -2
- package/src/lib/services/armorPull.js +2 -2
- package/src/lib/services/armorPush.js +2 -2
- package/src/lib/services/armorUp.js +2 -2
- package/src/lib/services/genexample.js +5 -6
- package/src/lib/services/login.js +25 -0
- package/src/lib/services/prebuild.js +9 -3
- package/src/lib/services/precommit.js +9 -3
- package/src/lib/transforms/decrypt.js +83 -0
- package/src/lib/transforms/encrypt.js +178 -0
- package/src/lib/transforms/set.js +179 -0
- package/src/shared/logger.js +5 -0
- package/src/cli/actions/normalizeArmorOptions.js +0 -10
- package/src/cli/actions/rotate.js +0 -87
- package/src/lib/helpers/append.js +0 -62
- package/src/lib/helpers/cryptography/armorKeypair.js +0 -42
- package/src/lib/helpers/cryptography/armorKeypairSync.js +0 -55
- package/src/lib/helpers/cryptography/encryptValue.js +0 -7
- package/src/lib/helpers/cryptography/localKeypair.js +0 -14
- package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +0 -38
- package/src/lib/helpers/cryptography/provision.js +0 -56
- package/src/lib/helpers/cryptography/provisionSync.js +0 -51
- package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +0 -26
- package/src/lib/helpers/escapeDollarSigns.js +0 -5
- package/src/lib/helpers/escapeForRegex.js +0 -5
- package/src/lib/helpers/evalKeyValue.js +0 -23
- package/src/lib/helpers/isIgnoringDotenvKeys.js +0 -19
- package/src/lib/helpers/keyResolution/index.js +0 -16
- package/src/lib/helpers/keyResolution/keyNamesForEnvFile.js +0 -24
- package/src/lib/helpers/keyResolution/keyValues.js +0 -99
- package/src/lib/helpers/keyResolution/keyValuesFromEnvSrc.js +0 -85
- package/src/lib/helpers/keyResolution/keyValuesSync.js +0 -103
- package/src/lib/helpers/keyResolution/readFileKey.js +0 -19
- package/src/lib/helpers/keyResolution/readFileKeySync.js +0 -17
- package/src/lib/helpers/keyResolution/readProcessKey.js +0 -7
- package/src/lib/helpers/localDisplayPath.js +0 -11
- package/src/lib/helpers/parse.js +0 -214
- package/src/lib/helpers/pluralize.js +0 -10
- package/src/lib/helpers/quotes.js +0 -36
- package/src/lib/helpers/replace.js +0 -82
- package/src/lib/helpers/resolveEscapeSequences.js +0 -5
- package/src/lib/services/decrypt.js +0 -156
- package/src/lib/services/encrypt.js +0 -213
- package/src/lib/services/get.js +0 -76
- package/src/lib/services/keypair.js +0 -60
- package/src/lib/services/loginPoll.js +0 -36
- package/src/lib/services/ls.js +0 -57
- package/src/lib/services/rotate.js +0 -197
- package/src/lib/services/run.js +0 -255
- package/src/lib/services/sets.js +0 -328
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
|
|
4
|
-
const readFileKeySync = require('./readFileKeySync')
|
|
5
|
-
const armorKeypairSync = require('../cryptography/armorKeypairSync')
|
|
6
|
-
|
|
7
|
-
const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
|
|
8
|
-
const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
|
|
9
|
-
|
|
10
|
-
function readProcessKey (processEnv, keyName) {
|
|
11
|
-
if (processEnv[keyName] && processEnv[keyName].length > 0) {
|
|
12
|
-
return processEnv[keyName]
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function publicKeyNameFromEnvSrc (envParsed) {
|
|
17
|
-
for (const keyName of Object.keys(envParsed)) {
|
|
18
|
-
if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
|
|
19
|
-
return keyName
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function finalValue (parsed, keyName) {
|
|
27
|
-
const values = parsed[keyName]
|
|
28
|
-
return values ? values[values.length - 1] : undefined
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function keyValuesFromEnvSrc (src, privateKeyName = null, opts = {}) {
|
|
32
|
-
let keysFilepath = opts.keysFilepath || null
|
|
33
|
-
const noArmor = opts.noArmor === true
|
|
34
|
-
const processEnv = opts.processEnv || process.env
|
|
35
|
-
const { parsed: envParsed } = scan(src)
|
|
36
|
-
|
|
37
|
-
const publicKeyName = publicKeyNameFromEnvSrc(envParsed)
|
|
38
|
-
const publicKeyValue = publicKeyName ? readProcessKey(processEnv, publicKeyName) || finalValue(envParsed, publicKeyName) || null : null
|
|
39
|
-
|
|
40
|
-
if (!privateKeyName && publicKeyName) {
|
|
41
|
-
privateKeyName = publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA)
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
let privateKeyValue = null
|
|
45
|
-
let privateKeySource = null
|
|
46
|
-
if (privateKeyName) {
|
|
47
|
-
privateKeyValue = readProcessKey(processEnv, privateKeyName)
|
|
48
|
-
|
|
49
|
-
if (!privateKeyValue) {
|
|
50
|
-
if (keysFilepath) {
|
|
51
|
-
keysFilepath = path.resolve(keysFilepath)
|
|
52
|
-
} else {
|
|
53
|
-
keysFilepath = path.resolve('.env.keys')
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
privateKeyValue = readFileKeySync(privateKeyName, keysFilepath)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!noArmor && !privateKeyValue && publicKeyValue && publicKeyValue.length > 0) {
|
|
61
|
-
const armorOptions = {}
|
|
62
|
-
if (opts.token) {
|
|
63
|
-
armorOptions.token = opts.token
|
|
64
|
-
}
|
|
65
|
-
if (opts.command) {
|
|
66
|
-
armorOptions.command = opts.command
|
|
67
|
-
}
|
|
68
|
-
const kp = armorKeypairSync(publicKeyValue, armorOptions)
|
|
69
|
-
privateKeyValue = kp.privateKey
|
|
70
|
-
privateKeySource = 'armor'
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const result = {
|
|
74
|
-
publicKeyValue: publicKeyValue || null,
|
|
75
|
-
privateKeyValue: privateKeyValue || null,
|
|
76
|
-
privateKeyName: privateKeyName || null
|
|
77
|
-
}
|
|
78
|
-
if (privateKeySource) {
|
|
79
|
-
result.privateKeySource = privateKeySource
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return result
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
module.exports = keyValuesFromEnvSrc
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
|
|
4
|
-
const fsx = require('./../fsx')
|
|
5
|
-
const keyNamesForEnvFile = require('./keyNamesForEnvFile')
|
|
6
|
-
const readProcessKey = require('./readProcessKey')
|
|
7
|
-
const readFileKeySync = require('./readFileKeySync')
|
|
8
|
-
const armorKeypairSync = require('../cryptography/armorKeypairSync')
|
|
9
|
-
|
|
10
|
-
function invertForPrivateKeyName (filepath) {
|
|
11
|
-
const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
|
|
12
|
-
const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
|
|
13
|
-
|
|
14
|
-
if (!fsx.existsSync(filepath)) {
|
|
15
|
-
return null
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const envSrc = fsx.readFileXSync(filepath)
|
|
19
|
-
const { parsed: envParsed } = scan(envSrc)
|
|
20
|
-
|
|
21
|
-
let publicKeyName
|
|
22
|
-
for (const keyName of Object.keys(envParsed)) {
|
|
23
|
-
if (keyName === PUBLIC_KEY_SCHEMA || keyName.startsWith(PUBLIC_KEY_SCHEMA)) {
|
|
24
|
-
publicKeyName = keyName // find DOTENV_PUBLIC_KEY* in filename
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
if (publicKeyName) {
|
|
29
|
-
return publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA) // return inverted (DOTENV_PUBLIC_KEY* -> DOTENV_PRIVATE_KEY*) if found
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return null
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function keyValuesSync (filepath, opts = {}) {
|
|
36
|
-
let keysFilepath = opts.keysFilepath || null
|
|
37
|
-
const noArmor = opts.noArmor === true
|
|
38
|
-
const names = keyNamesForEnvFile(filepath)
|
|
39
|
-
const publicKeyName = names.publicKeyName // DOTENV_PUBLIC_KEY_${ENVIRONMENT}
|
|
40
|
-
let privateKeyName = names.privateKeyName // DOTENV_PRIVATE_KEY_${ENVIRONMENT}
|
|
41
|
-
|
|
42
|
-
let publicKey = null
|
|
43
|
-
let privateKey = null
|
|
44
|
-
let privateKeySource = null
|
|
45
|
-
|
|
46
|
-
// public key: process.env first, then .env*
|
|
47
|
-
publicKey = readProcessKey(publicKeyName)
|
|
48
|
-
if (!publicKey) {
|
|
49
|
-
publicKey = readFileKeySync(publicKeyName, filepath) || null
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// private key: process.env first, then .env.keys, then invert public key
|
|
53
|
-
privateKey = readProcessKey(privateKeyName)
|
|
54
|
-
if (!privateKey) {
|
|
55
|
-
if (keysFilepath) { // user specified -fk flag
|
|
56
|
-
keysFilepath = path.resolve(keysFilepath)
|
|
57
|
-
} else {
|
|
58
|
-
keysFilepath = path.resolve(path.dirname(filepath), '.env.keys') // typical scenario
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
privateKey = readFileKeySync(privateKeyName, keysFilepath)
|
|
62
|
-
}
|
|
63
|
-
// invert
|
|
64
|
-
if (!privateKey) {
|
|
65
|
-
privateKeyName = invertForPrivateKeyName(filepath)
|
|
66
|
-
if (privateKeyName) {
|
|
67
|
-
privateKey = readProcessKey(privateKeyName)
|
|
68
|
-
if (!privateKey) {
|
|
69
|
-
privateKey = readFileKeySync(privateKeyName, keysFilepath)
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// armor
|
|
75
|
-
if (!noArmor && !privateKey && publicKey && publicKey.length > 0) {
|
|
76
|
-
const armorOptions = { envFilepath: filepath }
|
|
77
|
-
if (opts.token) {
|
|
78
|
-
armorOptions.token = opts.token
|
|
79
|
-
}
|
|
80
|
-
if (opts.command) {
|
|
81
|
-
armorOptions.command = opts.command
|
|
82
|
-
}
|
|
83
|
-
if (opts.noSpinner) {
|
|
84
|
-
armorOptions.noSpinner = true
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
const kp = armorKeypairSync(publicKey, armorOptions)
|
|
88
|
-
privateKey = kp.privateKey
|
|
89
|
-
privateKeySource = 'armor'
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const result = {
|
|
93
|
-
publicKeyValue: publicKey || null, // important to make sure name is rendered
|
|
94
|
-
privateKeyValue: privateKey || null // important to make sure name is rendered
|
|
95
|
-
}
|
|
96
|
-
if (privateKeySource) {
|
|
97
|
-
result.privateKeySource = privateKeySource
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return result
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
module.exports = keyValuesSync
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
const fsx = require('./../fsx')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
|
|
4
|
-
async function readFileKey (keyName, filepath) {
|
|
5
|
-
if (!(await fsx.exists(filepath))) {
|
|
6
|
-
return undefined
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const src = await fsx.readFileX(filepath)
|
|
10
|
-
const { parsed } = scan(src)
|
|
11
|
-
const values = parsed[keyName]
|
|
12
|
-
|
|
13
|
-
if (values && values.length > 0) {
|
|
14
|
-
const value = values[values.length - 1]
|
|
15
|
-
return value || undefined
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
module.exports = readFileKey
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
const fsx = require('./../fsx')
|
|
2
|
-
const { scan } = require('@dotenvx/primitives')
|
|
3
|
-
|
|
4
|
-
function readFileKeySync (keyName, filepath) {
|
|
5
|
-
if (fsx.existsSync(filepath)) {
|
|
6
|
-
const src = fsx.readFileXSync(filepath)
|
|
7
|
-
const { parsed } = scan(src)
|
|
8
|
-
const values = parsed[keyName]
|
|
9
|
-
|
|
10
|
-
if (values && values.length > 0) {
|
|
11
|
-
const value = values[values.length - 1]
|
|
12
|
-
return value || undefined
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
module.exports = readFileKeySync
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
|
-
function localDisplayPath (filepath) {
|
|
4
|
-
if (!filepath) return '.env.keys'
|
|
5
|
-
if (!path.isAbsolute(filepath)) return filepath
|
|
6
|
-
|
|
7
|
-
const relative = path.relative(process.cwd(), filepath)
|
|
8
|
-
return relative || path.basename(filepath)
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
module.exports = localDisplayPath
|
package/src/lib/helpers/parse.js
DELETED
|
@@ -1,214 +0,0 @@
|
|
|
1
|
-
const decryptKeyValue = require('./cryptography/decryptKeyValue')
|
|
2
|
-
const { encrypted } = require('@dotenvx/primitives')
|
|
3
|
-
const evalKeyValue = require('./evalKeyValue')
|
|
4
|
-
const resolveEscapeSequences = require('./resolveEscapeSequences')
|
|
5
|
-
|
|
6
|
-
class Parse {
|
|
7
|
-
static LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
|
8
|
-
|
|
9
|
-
constructor (src, privateKey = null, processEnv = process.env, overload = false, privateKeyName = null) {
|
|
10
|
-
this.src = src
|
|
11
|
-
this.privateKey = privateKey
|
|
12
|
-
this.privateKeyName = privateKeyName
|
|
13
|
-
this.processEnv = processEnv
|
|
14
|
-
this.overload = overload
|
|
15
|
-
|
|
16
|
-
this.parsed = {}
|
|
17
|
-
this.preExisted = {}
|
|
18
|
-
this.injected = {}
|
|
19
|
-
this.errors = []
|
|
20
|
-
|
|
21
|
-
// for use with progressive expansion
|
|
22
|
-
this.runningParsed = {}
|
|
23
|
-
// for use with stopping expansion for literals
|
|
24
|
-
this.literals = {}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
run () {
|
|
28
|
-
const lines = this.getLines()
|
|
29
|
-
|
|
30
|
-
let match
|
|
31
|
-
while ((match = Parse.LINE.exec(lines)) !== null) {
|
|
32
|
-
const key = match[1]
|
|
33
|
-
const value = match[2]
|
|
34
|
-
const quote = this.quote(value) // must be raw match
|
|
35
|
-
this.parsed[key] = this.clean(value, quote) // file value
|
|
36
|
-
|
|
37
|
-
if (!this.overload && this.inProcessEnv(key)) {
|
|
38
|
-
this.parsed[key] = this.processEnv[key] // use process.env pre-existing value
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// decrypt
|
|
42
|
-
try {
|
|
43
|
-
this.parsed[key] = this.decrypt(key, this.parsed[key])
|
|
44
|
-
} catch (e) {
|
|
45
|
-
this.errors.push(e)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const encryptedPrefixed = encrypted(this.parsed[key]) // do not eval encrypted prefix
|
|
49
|
-
|
|
50
|
-
// eval empty, double, or backticks
|
|
51
|
-
let evaled = false
|
|
52
|
-
if (!encryptedPrefixed && quote !== "'" && (!this.inProcessEnv(key) || this.processEnv[key] === this.parsed[key])) {
|
|
53
|
-
const priorEvaled = this.parsed[key]
|
|
54
|
-
// eval
|
|
55
|
-
try {
|
|
56
|
-
this.parsed[key] = this.eval(key, priorEvaled)
|
|
57
|
-
} catch (e) {
|
|
58
|
-
this.errors.push(e)
|
|
59
|
-
}
|
|
60
|
-
if (priorEvaled !== this.parsed[key]) {
|
|
61
|
-
evaled = true
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
// expand empty, double, or backticks
|
|
66
|
-
if (!encryptedPrefixed && !evaled && quote !== "'" && (!this.processEnv[key] || this.overload)) {
|
|
67
|
-
this.parsed[key] = resolveEscapeSequences(this.expand(this.parsed[key]))
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (quote === "'") {
|
|
71
|
-
this.literals[key] = this.parsed[key]
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// for use with progressive expansion
|
|
75
|
-
this.runningParsed[key] = this.parsed[key]
|
|
76
|
-
|
|
77
|
-
if (Object.prototype.hasOwnProperty.call(this.processEnv, key) && !this.overload) {
|
|
78
|
-
this.preExisted[key] = this.processEnv[key] // track preExisted
|
|
79
|
-
} else {
|
|
80
|
-
this.injected[key] = this.parsed[key] // track injected
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return {
|
|
85
|
-
parsed: this.parsed,
|
|
86
|
-
processEnv: this.processEnv,
|
|
87
|
-
injected: this.injected,
|
|
88
|
-
preExisted: this.preExisted,
|
|
89
|
-
errors: this.errors
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
trimmer (value) {
|
|
94
|
-
// Default undefined or null to empty string
|
|
95
|
-
return (value || '').trim()
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
quote (value) {
|
|
99
|
-
const v = this.trimmer(value)
|
|
100
|
-
const maybeQuote = v[0]
|
|
101
|
-
let q = ''
|
|
102
|
-
switch (maybeQuote) {
|
|
103
|
-
// single
|
|
104
|
-
case "'":
|
|
105
|
-
q = "'"
|
|
106
|
-
break
|
|
107
|
-
// double
|
|
108
|
-
case '"':
|
|
109
|
-
q = '"'
|
|
110
|
-
break
|
|
111
|
-
// backtick
|
|
112
|
-
case '`':
|
|
113
|
-
q = '`'
|
|
114
|
-
break
|
|
115
|
-
// empty
|
|
116
|
-
default:
|
|
117
|
-
q = ''
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return q
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
clean (value, _quote) {
|
|
124
|
-
let v = this.trimmer(value)
|
|
125
|
-
|
|
126
|
-
// Remove surrounding quotes
|
|
127
|
-
v = v.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
|
128
|
-
|
|
129
|
-
// Expand newlines if double quoted
|
|
130
|
-
if (_quote === '"') {
|
|
131
|
-
v = v.replace(/\\n/g, '\n') // newline
|
|
132
|
-
v = v.replace(/\\r/g, '\r') // carriage return
|
|
133
|
-
v = v.replace(/\\t/g, '\t') // tabs
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return v
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
decrypt (key, value) {
|
|
140
|
-
return decryptKeyValue(key, value, this.privateKeyName, this.privateKey)
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
eval (key, value) {
|
|
144
|
-
return evalKeyValue(key, value, this.processEnv, this.runningParsed)
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
expand (value) {
|
|
148
|
-
let env = { ...this.runningParsed, ...this.processEnv } // typically process.env wins
|
|
149
|
-
if (this.overload) {
|
|
150
|
-
env = { ...this.processEnv, ...this.runningParsed } // parsed wins
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
const regex = /(?<!\\)\${([^{}]+)}|(?<!\\)\$([A-Za-z_][A-Za-z0-9_]*)/g
|
|
154
|
-
|
|
155
|
-
let result = value
|
|
156
|
-
let match
|
|
157
|
-
|
|
158
|
-
while ((match = regex.exec(result)) !== null) {
|
|
159
|
-
const [template, bracedExpression, unbracedExpression] = match
|
|
160
|
-
const expression = bracedExpression || unbracedExpression
|
|
161
|
-
|
|
162
|
-
// match the operators `:+`, `+`, `:-`, and `-`
|
|
163
|
-
const opRegex = /(:\+|\+|:-|-)/
|
|
164
|
-
// find first match
|
|
165
|
-
const opMatch = expression.match(opRegex)
|
|
166
|
-
const splitter = opMatch ? opMatch[0] : null
|
|
167
|
-
|
|
168
|
-
const r = expression.split(splitter)
|
|
169
|
-
|
|
170
|
-
let defaultValue
|
|
171
|
-
let value
|
|
172
|
-
const key = r.shift()
|
|
173
|
-
|
|
174
|
-
if ([':+', '+'].includes(splitter)) {
|
|
175
|
-
defaultValue = env[key] ? r.join(splitter) : ''
|
|
176
|
-
value = null
|
|
177
|
-
} else {
|
|
178
|
-
defaultValue = r.join(splitter)
|
|
179
|
-
value = env[key]
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
if (value) {
|
|
183
|
-
result = result.replace(template, value)
|
|
184
|
-
} else {
|
|
185
|
-
result = result.replace(template, defaultValue)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// if the result equaled what was in env then stop expanding - handle self-referential check as well
|
|
189
|
-
if (result === env[key]) {
|
|
190
|
-
break
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// if the result came from what was a literal value then stop expanding
|
|
194
|
-
// BUT only if the literal value contains expansion patterns (${...} or $VAR)
|
|
195
|
-
if (this.literals[key] && /\$\{[^}]+\}|\$[A-Za-z_][A-Za-z0-9_]*/.test(this.literals[key])) {
|
|
196
|
-
break
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
regex.lastIndex = 0 // reset regex search position to re-evaluate after each replacement
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return result
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
inProcessEnv (key) {
|
|
206
|
-
return Object.prototype.hasOwnProperty.call(this.processEnv, key)
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
getLines () {
|
|
210
|
-
return (this.src || '').toString().replace(/\r\n?/mg, '\n') // Convert buffer to string and Convert line breaks to same format
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
module.exports = Parse
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const LINE = /(?:^|^)\s*(?:export\s+)?([\w.-]+)(?:\s*=\s*?|:\s+?)(\s*'(?:\\'|[^'])*'|\s*"(?:\\"|[^"])*"|\s*`(?:\\`|[^`])*`|[^#\r\n]+)?\s*(?:#.*)?(?:$|$)/mg
|
|
2
|
-
|
|
3
|
-
function quotes (src) {
|
|
4
|
-
const obj = {}
|
|
5
|
-
// Convert buffer to string
|
|
6
|
-
let lines = src.toString()
|
|
7
|
-
|
|
8
|
-
// Convert line breaks to same format
|
|
9
|
-
lines = lines.replace(/\r\n?/mg, '\n')
|
|
10
|
-
|
|
11
|
-
let match
|
|
12
|
-
while ((match = LINE.exec(lines)) != null) {
|
|
13
|
-
const key = match[1]
|
|
14
|
-
|
|
15
|
-
// Default undefined or null to empty string
|
|
16
|
-
let value = (match[2] || '')
|
|
17
|
-
|
|
18
|
-
// Remove whitespace
|
|
19
|
-
value = value.trim()
|
|
20
|
-
|
|
21
|
-
// Check if double quoted
|
|
22
|
-
const maybeQuote = value[0]
|
|
23
|
-
|
|
24
|
-
value = value.replace(/^(['"`])([\s\S]*)\1$/mg, '$2')
|
|
25
|
-
|
|
26
|
-
if (maybeQuote === value[0]) {
|
|
27
|
-
obj[key] = ''
|
|
28
|
-
} else {
|
|
29
|
-
obj[key] = maybeQuote
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return obj
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = quotes
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
const { scan } = require('@dotenvx/primitives')
|
|
2
|
-
const escapeForRegex = require('./escapeForRegex')
|
|
3
|
-
|
|
4
|
-
function replaceExistingValue (src, key, originalValue, replaceValue) {
|
|
5
|
-
const escapedKey = escapeForRegex(key)
|
|
6
|
-
const escapedOriginalValue = escapeForRegex(originalValue)
|
|
7
|
-
|
|
8
|
-
// conditionally enforce end of line
|
|
9
|
-
let enforceEndOfLine = ''
|
|
10
|
-
if (escapedOriginalValue === '') {
|
|
11
|
-
enforceEndOfLine = '$' // EMPTY scenario
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
const currentPart = new RegExp(
|
|
15
|
-
'^' + // start of line
|
|
16
|
-
'(\\s*)?' + // spaces
|
|
17
|
-
'(export\\s+)?' + // export
|
|
18
|
-
escapedKey + // KEY
|
|
19
|
-
'\\s*=\\s*' + // spaces (KEY = value)
|
|
20
|
-
'(["\'`]?)' + // open quote
|
|
21
|
-
escapedOriginalValue + // escaped value
|
|
22
|
-
'\\3' + // close quote
|
|
23
|
-
enforceEndOfLine
|
|
24
|
-
,
|
|
25
|
-
'gm' // (g)lobal (m)ultiline
|
|
26
|
-
)
|
|
27
|
-
|
|
28
|
-
return src.replace(currentPart, function (match, spaces = '', exportPart = '', quote = '') {
|
|
29
|
-
let newPart = `${key}=${quote}${replaceValue}${quote}`
|
|
30
|
-
|
|
31
|
-
// if empty quote and consecutive newlines
|
|
32
|
-
const newlineMatch = src.match(new RegExp(`${escapedKey}\\s*=\\s*\n\n`, 'm')) // match any consecutive newline scenario for a blank value
|
|
33
|
-
if (escapedOriginalValue === '' && quote === '' && newlineMatch) {
|
|
34
|
-
const newlineCount = (newlineMatch[0].match(/\n/g)).length - 1
|
|
35
|
-
for (let i = 0; i < newlineCount; i++) {
|
|
36
|
-
newPart += '\n' // re-append the extra newline to preserve user's format choice
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return `${spaces}${exportPart}${newPart}`
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function replace (src, key, replaceValue) {
|
|
45
|
-
let output
|
|
46
|
-
let newPart = ''
|
|
47
|
-
|
|
48
|
-
const { parsed } = scan(src, { expandDoubleQuotedNewlines: false, convertWindowsNewlines: false })
|
|
49
|
-
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
|
50
|
-
const allValues = parsed[key]
|
|
51
|
-
let duplicateOutput = src
|
|
52
|
-
const replacements = Array.isArray(replaceValue) ? replaceValue : allValues.map(() => replaceValue)
|
|
53
|
-
const replacementByValue = new Map()
|
|
54
|
-
|
|
55
|
-
allValues.forEach((value, index) => {
|
|
56
|
-
if (!replacementByValue.has(value)) {
|
|
57
|
-
replacementByValue.set(value, replacements[index])
|
|
58
|
-
}
|
|
59
|
-
})
|
|
60
|
-
|
|
61
|
-
for (const [value, replacement] of replacementByValue) {
|
|
62
|
-
duplicateOutput = replaceExistingValue(duplicateOutput, key, value, replacement)
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return duplicateOutput
|
|
66
|
-
} else {
|
|
67
|
-
newPart += `${key}="${replaceValue}"`
|
|
68
|
-
|
|
69
|
-
// append
|
|
70
|
-
if (src.endsWith('\n')) {
|
|
71
|
-
newPart = newPart + '\n'
|
|
72
|
-
} else {
|
|
73
|
-
newPart = '\n' + newPart
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
output = src + newPart
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
return output
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
module.exports = replace
|