@dotenvx/dotenvx 1.75.0 → 2.0.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.
Files changed (89) hide show
  1. package/CHANGELOG.md +34 -1
  2. package/README.md +4 -114
  3. package/package.json +8 -7
  4. package/src/cli/actions/decrypt.js +35 -17
  5. package/src/cli/actions/doctor.js +2 -2
  6. package/src/cli/actions/encrypt.js +64 -85
  7. package/src/cli/actions/ext/genexample.js +2 -2
  8. package/src/cli/actions/get.js +16 -7
  9. package/src/cli/actions/keypair.js +55 -42
  10. package/src/cli/actions/login.js +4 -3
  11. package/src/cli/actions/normalizeArmorAliases.js +9 -0
  12. package/src/cli/actions/run.js +65 -22
  13. package/src/cli/actions/set.js +51 -37
  14. package/src/cli/dotenvx.js +6 -21
  15. package/src/lib/api/{postKeypair.js → postArmorKeyring.js} +4 -14
  16. package/src/lib/{helpers/envResolution → conventions}/environment.js +1 -1
  17. package/src/lib/conventions/filepaths.js +9 -0
  18. package/src/lib/conventions/keynames.js +38 -0
  19. package/src/lib/helpers/catchAndLog.js +4 -1
  20. package/src/lib/helpers/cryptography/index.js +1 -12
  21. package/src/lib/helpers/cryptography/mutateKeysSrc.js +5 -21
  22. package/src/lib/helpers/envResolution/index.js +1 -1
  23. package/src/lib/helpers/errors.js +13 -0
  24. package/src/lib/helpers/executeDynamic.js +1 -3
  25. package/src/lib/helpers/keypairMetadata.js +3 -3
  26. package/src/lib/helpers/readEnvKey.js +4 -3
  27. package/src/lib/main.d.ts +2 -39
  28. package/src/lib/main.js +82 -45
  29. package/src/lib/providers/armor/index.js +29 -0
  30. package/src/lib/providers/index.js +46 -0
  31. package/src/lib/providers/worker.js +6 -0
  32. package/src/lib/resolvers/envs.js +302 -0
  33. package/src/lib/resolvers/get.js +69 -0
  34. package/src/lib/resolvers/keypair.js +81 -0
  35. package/src/lib/resolvers/ls.js +41 -0
  36. package/src/lib/services/armorDown.js +2 -2
  37. package/src/lib/services/{armorKeypair.js → armorKeyring.js} +14 -51
  38. package/src/lib/services/armorMove.js +2 -2
  39. package/src/lib/services/armorPull.js +2 -2
  40. package/src/lib/services/armorPush.js +2 -2
  41. package/src/lib/services/armorUp.js +2 -2
  42. package/src/lib/services/genexample.js +19 -8
  43. package/src/lib/services/login.js +25 -0
  44. package/src/lib/services/prebuild.js +11 -5
  45. package/src/lib/services/precommit.js +11 -5
  46. package/src/lib/transforms/decrypt.js +83 -0
  47. package/src/lib/transforms/encrypt.js +179 -0
  48. package/src/lib/transforms/set.js +179 -0
  49. package/src/shared/logger.js +5 -0
  50. package/src/cli/actions/normalizeArmorOptions.js +0 -10
  51. package/src/cli/actions/rotate.js +0 -87
  52. package/src/lib/helpers/append.js +0 -61
  53. package/src/lib/helpers/cryptography/armorKeypair.js +0 -42
  54. package/src/lib/helpers/cryptography/armorKeypairSync.js +0 -55
  55. package/src/lib/helpers/cryptography/encryptValue.js +0 -7
  56. package/src/lib/helpers/cryptography/localKeypair.js +0 -14
  57. package/src/lib/helpers/cryptography/mutateKeysSrcSync.js +0 -38
  58. package/src/lib/helpers/cryptography/provision.js +0 -56
  59. package/src/lib/helpers/cryptography/provisionSync.js +0 -51
  60. package/src/lib/helpers/cryptography/provisionWithPrivateKey.js +0 -26
  61. package/src/lib/helpers/dotenvParse.js +0 -55
  62. package/src/lib/helpers/escapeDollarSigns.js +0 -5
  63. package/src/lib/helpers/escapeForRegex.js +0 -5
  64. package/src/lib/helpers/evalKeyValue.js +0 -23
  65. package/src/lib/helpers/isFullyEncrypted.js +0 -27
  66. package/src/lib/helpers/isIgnoringDotenvKeys.js +0 -19
  67. package/src/lib/helpers/keyResolution/index.js +0 -16
  68. package/src/lib/helpers/keyResolution/keyNamesForEnvFile.js +0 -24
  69. package/src/lib/helpers/keyResolution/keyValues.js +0 -99
  70. package/src/lib/helpers/keyResolution/keyValuesFromEnvSrc.js +0 -80
  71. package/src/lib/helpers/keyResolution/keyValuesSync.js +0 -103
  72. package/src/lib/helpers/keyResolution/readFileKey.js +0 -17
  73. package/src/lib/helpers/keyResolution/readFileKeySync.js +0 -15
  74. package/src/lib/helpers/keyResolution/readProcessKey.js +0 -7
  75. package/src/lib/helpers/localDisplayPath.js +0 -11
  76. package/src/lib/helpers/parse.js +0 -214
  77. package/src/lib/helpers/pluralize.js +0 -10
  78. package/src/lib/helpers/quotes.js +0 -36
  79. package/src/lib/helpers/replace.js +0 -82
  80. package/src/lib/helpers/resolveEscapeSequences.js +0 -5
  81. package/src/lib/services/decrypt.js +0 -157
  82. package/src/lib/services/encrypt.js +0 -214
  83. package/src/lib/services/get.js +0 -76
  84. package/src/lib/services/keypair.js +0 -60
  85. package/src/lib/services/loginPoll.js +0 -36
  86. package/src/lib/services/ls.js +0 -57
  87. package/src/lib/services/rotate.js +0 -198
  88. package/src/lib/services/run.js +0 -255
  89. package/src/lib/services/sets.js +0 -326
@@ -1,99 +0,0 @@
1
- const path = require('path')
2
-
3
- const fsx = require('./../fsx')
4
- const dotenvParse = require('./../dotenvParse')
5
- const keyNamesForEnvFile = require('./keyNamesForEnvFile')
6
- const readProcessKey = require('./readProcessKey')
7
- const readFileKey = require('./readFileKey')
8
- const armorKeypair = require('../cryptography/armorKeypair')
9
-
10
- async function invertForPrivateKeyName (filepath) {
11
- const PUBLIC_KEY_SCHEMA = 'DOTENV_PUBLIC_KEY'
12
- const PRIVATE_KEY_SCHEMA = 'DOTENV_PRIVATE_KEY'
13
-
14
- if (!(await fsx.exists(filepath))) {
15
- return null
16
- }
17
-
18
- const envSrc = await fsx.readFileX(filepath)
19
- const envParsed = dotenvParse(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
- async function keyValues (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 = await readFileKey(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 = await readFileKey(privateKeyName, keysFilepath)
62
- }
63
- // invert
64
- if (!privateKey) {
65
- privateKeyName = await invertForPrivateKeyName(filepath)
66
- if (privateKeyName) {
67
- privateKey = readProcessKey(privateKeyName)
68
- if (!privateKey) {
69
- privateKey = await readFileKey(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
- const kp = await armorKeypair(publicKey, armorOptions)
84
- privateKey = kp.privateKey
85
- privateKeySource = 'armor'
86
- }
87
-
88
- const result = {
89
- publicKeyValue: publicKey || null, // important to make sure name is rendered
90
- privateKeyValue: privateKey || null // important to make sure name is rendered
91
- }
92
- if (privateKeySource) {
93
- result.privateKeySource = privateKeySource
94
- }
95
-
96
- return result
97
- }
98
-
99
- module.exports = keyValues
@@ -1,80 +0,0 @@
1
- const path = require('path')
2
-
3
- const dotenvParse = require('./../dotenvParse')
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 keyValuesFromEnvSrc (src, privateKeyName = null, opts = {}) {
27
- let keysFilepath = opts.keysFilepath || null
28
- const noArmor = opts.noArmor === true
29
- const processEnv = opts.processEnv || process.env
30
- const envParsed = dotenvParse(src)
31
-
32
- const publicKeyName = publicKeyNameFromEnvSrc(envParsed)
33
- const publicKeyValue = publicKeyName ? readProcessKey(processEnv, publicKeyName) || envParsed[publicKeyName] || null : null
34
-
35
- if (!privateKeyName && publicKeyName) {
36
- privateKeyName = publicKeyName.replace(PUBLIC_KEY_SCHEMA, PRIVATE_KEY_SCHEMA)
37
- }
38
-
39
- let privateKeyValue = null
40
- let privateKeySource = null
41
- if (privateKeyName) {
42
- privateKeyValue = readProcessKey(processEnv, privateKeyName)
43
-
44
- if (!privateKeyValue) {
45
- if (keysFilepath) {
46
- keysFilepath = path.resolve(keysFilepath)
47
- } else {
48
- keysFilepath = path.resolve('.env.keys')
49
- }
50
-
51
- privateKeyValue = readFileKeySync(privateKeyName, keysFilepath)
52
- }
53
- }
54
-
55
- if (!noArmor && !privateKeyValue && publicKeyValue && publicKeyValue.length > 0) {
56
- const armorOptions = {}
57
- if (opts.token) {
58
- armorOptions.token = opts.token
59
- }
60
- if (opts.command) {
61
- armorOptions.command = opts.command
62
- }
63
- const kp = armorKeypairSync(publicKeyValue, armorOptions)
64
- privateKeyValue = kp.privateKey
65
- privateKeySource = 'armor'
66
- }
67
-
68
- const result = {
69
- publicKeyValue: publicKeyValue || null,
70
- privateKeyValue: privateKeyValue || null,
71
- privateKeyName: privateKeyName || null
72
- }
73
- if (privateKeySource) {
74
- result.privateKeySource = privateKeySource
75
- }
76
-
77
- return result
78
- }
79
-
80
- module.exports = keyValuesFromEnvSrc
@@ -1,103 +0,0 @@
1
- const path = require('path')
2
-
3
- const fsx = require('./../fsx')
4
- const dotenvParse = require('./../dotenvParse')
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 envParsed = dotenvParse(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,17 +0,0 @@
1
- const fsx = require('./../fsx')
2
- const dotenvParse = require('./../dotenvParse')
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 = dotenvParse(src)
11
-
12
- if (parsed[keyName] && parsed[keyName].length > 0) {
13
- return parsed[keyName]
14
- }
15
- }
16
-
17
- module.exports = readFileKey
@@ -1,15 +0,0 @@
1
- const fsx = require('./../fsx')
2
- const dotenvParse = require('./../dotenvParse')
3
-
4
- function readFileKeySync (keyName, filepath) {
5
- if (fsx.existsSync(filepath)) {
6
- const src = fsx.readFileXSync(filepath)
7
- const parsed = dotenvParse(src)
8
-
9
- if (parsed[keyName] && parsed[keyName].length > 0) {
10
- return parsed[keyName]
11
- }
12
- }
13
- }
14
-
15
- module.exports = readFileKeySync
@@ -1,7 +0,0 @@
1
- function readProcessKey (keyName) {
2
- if (process.env[keyName] && process.env[keyName].length > 0) {
3
- return process.env[keyName]
4
- }
5
- }
6
-
7
- module.exports = readProcessKey
@@ -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
@@ -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,10 +0,0 @@
1
- function pluralize (word, count) {
2
- // simple pluralization: add 's' at the end
3
- if (count === 0 || count > 1) {
4
- return word + 's'
5
- } else {
6
- return word
7
- }
8
- }
9
-
10
- module.exports = pluralize
@@ -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 dotenvParse = require('./dotenvParse')
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 = dotenvParse(src, true, true, true) // skip expanding \n and skip converting \r\n
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
@@ -1,5 +0,0 @@
1
- function resolveEscapeSequences (value) {
2
- return value.replace(/\\\$/g, '$')
3
- }
4
-
5
- module.exports = resolveEscapeSequences