@dotenvx/dotenvx 0.42.0 → 0.43.1
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/README.md
CHANGED
|
@@ -32,7 +32,7 @@ brew install dotenvx/brew/dotenvx
|
|
|
32
32
|
```
|
|
33
33
|
> * [other global ways to install](https://dotenvx.com/docs/install)
|
|
34
34
|
>
|
|
35
|
-
>
|
|
35
|
+
> Install globally as a cli to unlock dotenv for ANY language, framework, or platform. 💥
|
|
36
36
|
>
|
|
37
37
|
> I am using (and recommending) this approach going forward. – [motdotla](https://github.com/motdotla)
|
|
38
38
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const resolveHome = require('./resolveHome')
|
|
2
|
+
|
|
3
|
+
function dotenvOptionPaths (options) {
|
|
4
|
+
let optionPaths = ['.env']
|
|
5
|
+
|
|
6
|
+
if (options && options.path) {
|
|
7
|
+
if (!Array.isArray(options.path)) {
|
|
8
|
+
optionPaths = [resolveHome(options.path)]
|
|
9
|
+
} else {
|
|
10
|
+
optionPaths = [] // reset default
|
|
11
|
+
|
|
12
|
+
for (const filepath of options.path) {
|
|
13
|
+
optionPaths.push(resolveHome(filepath))
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return optionPaths
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = dotenvOptionPaths
|
|
@@ -7,13 +7,10 @@ function parseDecryptEvalExpand (src, privateKey = null) {
|
|
|
7
7
|
// parse
|
|
8
8
|
const parsed = dotenv.parse(src)
|
|
9
9
|
|
|
10
|
-
// inline
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
|
|
14
|
-
// handle inline encrypted values
|
|
15
|
-
if (privateKey && privateKey.length > 0) {
|
|
16
|
-
// privateKey
|
|
10
|
+
// handle inline encrypted values
|
|
11
|
+
if (privateKey && privateKey.length > 0) {
|
|
12
|
+
for (const key in parsed) {
|
|
13
|
+
const value = parsed[key]
|
|
17
14
|
parsed[key] = decryptValue(value, privateKey)
|
|
18
15
|
}
|
|
19
16
|
}
|
|
@@ -6,8 +6,19 @@ function replace (src, key, value) {
|
|
|
6
6
|
|
|
7
7
|
const parsed = dotenv.parse(src)
|
|
8
8
|
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
const regex = new RegExp(
|
|
10
|
+
`^${key}=` + // start of line with key
|
|
11
|
+
'(?:' + // begin non-capturing group for handling both quoted and unquoted values
|
|
12
|
+
'(["\'`])' + // capture opening quote (' or " or `)
|
|
13
|
+
'[^\\1]*' + // match any character except the quote captured initially
|
|
14
|
+
'\\1' + // match the same closing quote as captured at the start
|
|
15
|
+
'|' + // OR
|
|
16
|
+
'[^#\\n]*' + // match any characters until a # (comment) or newline
|
|
17
|
+
')' + // end non-capturing group
|
|
18
|
+
'(\\n[^A-Z0-9_].*)*', // match subsequent lines that don't start with a letter, number, or underscore (continuation lines)
|
|
19
|
+
'm' // apply multiline mode, so ^ and $ match start and end of lines, not just the whole string
|
|
20
|
+
)
|
|
21
|
+
|
|
11
22
|
output = src.replace(regex, formatted)
|
|
12
23
|
} else {
|
|
13
24
|
// append
|
package/src/lib/main.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
const path = require('path')
|
|
1
2
|
const logger = require('./../shared/logger')
|
|
2
3
|
const dotenv = require('dotenv')
|
|
3
|
-
const dotenvExpand = require('dotenv-expand')
|
|
4
4
|
|
|
5
5
|
// services
|
|
6
6
|
const Ls = require('./services/ls')
|
|
7
7
|
const Get = require('./services/get')
|
|
8
|
+
const Run = require('./services/run')
|
|
8
9
|
const Sets = require('./services/sets')
|
|
9
10
|
const Status = require('./services/status')
|
|
10
11
|
const Encrypt = require('./services/encrypt')
|
|
@@ -13,25 +14,119 @@ const Settings = require('./services/settings')
|
|
|
13
14
|
const VaultEncrypt = require('./services/vaultEncrypt')
|
|
14
15
|
|
|
15
16
|
// helpers
|
|
16
|
-
const
|
|
17
|
+
const dotenvOptionPaths = require('./helpers/dotenvOptionPaths')
|
|
17
18
|
|
|
18
19
|
// proxies to dotenv
|
|
19
|
-
const config = function (options) {
|
|
20
|
-
|
|
20
|
+
const config = function (options = {}) {
|
|
21
|
+
// allow user to set processEnv to write to
|
|
22
|
+
let processEnv = process.env
|
|
23
|
+
if (options && options.processEnv != null) {
|
|
24
|
+
processEnv = options.processEnv
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// overload
|
|
28
|
+
const overload = options.overload || options.override
|
|
21
29
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
30
|
+
// DOTENV_KEY
|
|
31
|
+
let DOTENV_KEY = process.env.DOTENV_KEY
|
|
32
|
+
if (options && options.DOTENV_KEY) {
|
|
33
|
+
DOTENV_KEY = options.DOTENV_KEY
|
|
25
34
|
}
|
|
26
|
-
const expanded = dotenvExpand.expand(env)
|
|
27
35
|
|
|
28
|
-
//
|
|
29
|
-
if (options && options.
|
|
30
|
-
|
|
36
|
+
// debug -> log level
|
|
37
|
+
if (options && options.debug) {
|
|
38
|
+
logger.level = 'debug'
|
|
39
|
+
logger.debug('setting log level to debug')
|
|
31
40
|
}
|
|
32
|
-
const evaluated = dotenvEval.eval(expanded)
|
|
33
41
|
|
|
34
|
-
|
|
42
|
+
// build envs using user set option.path
|
|
43
|
+
const optionPaths = dotenvOptionPaths(options) // [ '.env' ]
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const envs = []
|
|
47
|
+
for (const optionPath of optionPaths) {
|
|
48
|
+
// if DOTENV_KEY is set then assume we are checking envVaultFile
|
|
49
|
+
if (DOTENV_KEY) {
|
|
50
|
+
envs.push({ type: 'envVaultFile', value: path.join(path.dirname(optionPath), '.env.vault') })
|
|
51
|
+
} else {
|
|
52
|
+
envs.push({ type: 'envFile', value: optionPath })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const {
|
|
57
|
+
processedEnvs,
|
|
58
|
+
readableFilepaths,
|
|
59
|
+
uniqueInjectedKeys
|
|
60
|
+
} = new Run(envs, overload, DOTENV_KEY, processEnv).run()
|
|
61
|
+
|
|
62
|
+
let lastError
|
|
63
|
+
const parsedAll = {}
|
|
64
|
+
|
|
65
|
+
for (const processedEnv of processedEnvs) {
|
|
66
|
+
if (processedEnv.type === 'envVaultFile') {
|
|
67
|
+
logger.verbose(`loading env from encrypted ${processedEnv.filepath} (${path.resolve(processedEnv.filepath)})`)
|
|
68
|
+
logger.debug(`decrypting encrypted env from ${processedEnv.filepath} (${path.resolve(processedEnv.filepath)})`)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (processedEnv.type === 'envFile') {
|
|
72
|
+
logger.verbose(`loading env from ${processedEnv.filepath} (${path.resolve(processedEnv.filepath)})`)
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (processedEnv.error) {
|
|
76
|
+
lastError = processedEnv.error
|
|
77
|
+
|
|
78
|
+
if (processedEnv.error.code === 'MISSING_ENV_FILE') {
|
|
79
|
+
// do not warn for conventions (too noisy)
|
|
80
|
+
if (!options.convention) {
|
|
81
|
+
logger.warnv(processedEnv.error)
|
|
82
|
+
logger.help(`? add one with [echo "HELLO=World" > ${processedEnv.filepath}] and re-run [dotenvx run -- yourcommand]`)
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
logger.warnv(processedEnv.error)
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
Object.assign(parsedAll, processedEnv.injected)
|
|
89
|
+
Object.assign(parsedAll, processedEnv.preExisted) // preExisted 'wins'
|
|
90
|
+
|
|
91
|
+
// debug parsed
|
|
92
|
+
const parsed = processedEnv.parsed
|
|
93
|
+
logger.debug(parsed)
|
|
94
|
+
|
|
95
|
+
// verbose/debug injected key/value
|
|
96
|
+
const injected = processedEnv.injected
|
|
97
|
+
for (const [key, value] of Object.entries(injected)) {
|
|
98
|
+
logger.verbose(`${key} set`)
|
|
99
|
+
logger.debug(`${key} set to ${value}`)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// verbose/debug preExisted key/value
|
|
103
|
+
const preExisted = processedEnv.preExisted
|
|
104
|
+
for (const [key, value] of Object.entries(preExisted)) {
|
|
105
|
+
logger.verbose(`${key} pre-exists (protip: use --overload to override)`)
|
|
106
|
+
logger.debug(`${key} pre-exists as ${value} (protip: use --overload to override)`)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
let msg = `injecting env (${uniqueInjectedKeys.length})`
|
|
112
|
+
if (readableFilepaths.length > 0) {
|
|
113
|
+
msg += ` from ${readableFilepaths.join(', ')}`
|
|
114
|
+
}
|
|
115
|
+
logger.successv(msg)
|
|
116
|
+
|
|
117
|
+
if (lastError) {
|
|
118
|
+
return { parsed: parsedAll, error: lastError }
|
|
119
|
+
} else {
|
|
120
|
+
return { parsed: parsedAll }
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
logger.error(error.message)
|
|
124
|
+
if (error.help) {
|
|
125
|
+
logger.help(error.help)
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { parsed: {}, error }
|
|
129
|
+
}
|
|
35
130
|
}
|
|
36
131
|
|
|
37
132
|
const configDotenv = function (options) {
|