@dotenvx/dotenvx 1.17.0 → 1.18.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/CHANGELOG.md CHANGED
@@ -2,7 +2,46 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
- ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.17.0...main)
5
+ ## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.18.1...main)
6
+
7
+ ## 1.18.1
8
+
9
+ ### Added
10
+
11
+ * escape user inputted regex groupings like `$1` or `$2`. ([#396](https://github.com/dotenvx/dotenvx/pull/396))
12
+
13
+ ## 1.18.0
14
+
15
+ ### Added
16
+
17
+ * `set` and `encrypt` preserve leading spaces ([#395](https://github.com/dotenvx/dotenvx/pull/395))
18
+
19
+ ```sh
20
+ HELLO=world
21
+ ```
22
+
23
+ ### Changed
24
+
25
+ * improve escape and quote handling for `set`, `encrypt`, and `decrypt` ([#395](https://github.com/dotenvx/dotenvx/pull/395))
26
+ * 🐞 fix `encrypt`, then `decrypt`, then `encrypt` on a json value ([#377](https://github.com/dotenvx/dotenvx/issues/377))
27
+
28
+ Note: the underlying `replace` engine to support these changes now wraps your values in single quotes. the prior `replace` engine wrapped in double quotes.
29
+
30
+ So where your `.env` used to look like this with double quotes:
31
+
32
+ ```sh
33
+ HELLO="encrypted:1234"
34
+ API_KEY="encrypted:5678"
35
+ ```
36
+
37
+ It will now begin looking like this with single quotes:
38
+
39
+ ```sh
40
+ HELLO='encrypted:1234'
41
+ API_KEY='encrypted:5678'
42
+ ```
43
+
44
+ It's an aesthetic side effect only. Your values will continue to be decrypted and encrypted correctly.
6
45
 
7
46
  ## 1.17.0
8
47
 
package/README.md CHANGED
@@ -260,6 +260,18 @@ More examples
260
260
  Hello World
261
261
  ```
262
262
 
263
+ </details>
264
+ * <details><summary>Kotlin 📐</summary><br>
265
+
266
+ ```sh
267
+ $ echo "HELLO=World" > .env
268
+ $ echo 'fun main() { val hello = System.getenv("HELLO") ?: ""; println("Hello $hello") }' > index.kt
269
+ $ kotlinc index.kt -include-runtime -d index.jar
270
+
271
+ $ dotenvx run -- java -jar index.jar
272
+ Hello World
273
+ ```
274
+
263
275
  </details>
264
276
  * <details><summary>.NET 🔵</summary><br>
265
277
 
@@ -1089,7 +1101,7 @@ More examples
1089
1101
 
1090
1102
  This can be useful for more complex .env values (spaces, escaped characters, quotes, etc) combined with `eval` on the command line.
1091
1103
 
1092
- ```
1104
+ ```sh
1093
1105
  $ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js
1094
1106
  $ eval $(dotenvx get --format=eval) node index.js
1095
1107
  Hello value World
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.17.0",
2
+ "version": "1.18.1",
3
3
  "name": "@dotenvx/dotenvx",
4
4
  "description": "a better dotenv–from the creator of `dotenv`",
5
5
  "author": "@motdotla",
@@ -0,0 +1,5 @@
1
+ function escapeDollarSigns (str) {
2
+ return str.replace(/\$/g, '$$$$')
3
+ }
4
+
5
+ module.exports = escapeDollarSigns
@@ -0,0 +1,5 @@
1
+ function escapeForRegex (str) {
2
+ return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&').replace(/-/g, '\\x2d')
3
+ }
4
+
5
+ module.exports = escapeForRegex
@@ -1,38 +1,59 @@
1
+ const util = require('util')
1
2
  const dotenv = require('dotenv')
2
3
 
3
- function replace (src, key, value) {
4
+ const escapeForRegex = require('./escapeForRegex')
5
+ const escapeDollarSigns = require('./escapeDollarSigns')
6
+
7
+ function replace (src, key, replaceValue) {
4
8
  let output
5
- let formatted = `${key}="${value}"`
9
+ let escapedValue = util.inspect(replaceValue, { showHidden: false, depth: null, colors: false })
10
+
11
+ if (replaceValue.includes('\n')) {
12
+ escapedValue = JSON.stringify(replaceValue) // use JSON stringify if string contains newlines
13
+ escapedValue = escapedValue.replace(/\\n/g, '\n') // fix up newlines
14
+ escapedValue = escapedValue.replace(/\\r/g, '\r')
15
+ }
16
+ let newPart = `${key}=${escapedValue}`
6
17
 
7
18
  const parsed = dotenv.parse(src)
8
19
  if (Object.prototype.hasOwnProperty.call(parsed, key)) {
9
- const regex = new RegExp(
10
- // Match the key at the start of a line, following a newline, or prefaced by export
11
- `(^|\\n)\\s*(export\\s+)?${key}\\s*=\\s*` +
12
- // `(^|\\n)${key}\\s*=\\s*` +
13
- // Non-capturing group to handle different types of quotations and unquoted values
14
- '(?:' +
15
- '(["\'`])' + // Match an opening quote
16
- '.*?' + // Non-greedy match for any characters within quotes
17
- // '\\2' + // Match the corresponding closing quote
18
- '\\3' + // Match the corresponding closing quote
19
- '|' +
20
- // Match unquoted values; account for escaped newlines
21
- '(?:[^#\\n\\\\]|\\\\.)*' + // Use non-capturing group for any character except #, newline, or backslash, or any escaped character
22
- ')',
23
- 'gs' // Global and dotAll mode to treat string as single line
20
+ const originalValue = parsed[key]
21
+ const escapedOriginalValue = escapeForRegex(originalValue)
22
+
23
+ // conditionally enforce end of line
24
+ let enforceEndOfLine = ''
25
+ if (escapedOriginalValue === '') {
26
+ enforceEndOfLine = '$' // EMPTY scenario
27
+ }
28
+
29
+ const currentPart = new RegExp(
30
+ '^' + // start of line
31
+ '(\\s*)?' + // spaces
32
+ '(export\\s+)?' + // export
33
+ key + // KEY
34
+ '\\s*=\\s*' + // spaces (KEY = value)
35
+ '["\'`]?' + // open quote
36
+ escapedOriginalValue + // escaped value
37
+ '["\'`]?' + // close quote
38
+ enforceEndOfLine
39
+ ,
40
+ 'gm' // (g)lobal (m)ultiline
24
41
  )
25
42
 
26
- output = src.replace(regex, `$1$2${formatted}`)
43
+ const saferInput = escapeDollarSigns(newPart) // cleanse user inputted capture groups ($1, $2 etc)
44
+
45
+ // $1 preserves spaces
46
+ // $2 preserves export
47
+ output = src.replace(currentPart, `$1$2${saferInput}`)
27
48
  } else {
28
49
  // append
29
50
  if (src.endsWith('\n')) {
30
- formatted = formatted + '\n'
51
+ newPart = newPart + '\n'
31
52
  } else {
32
- formatted = '\n' + formatted
53
+ newPart = '\n' + newPart
33
54
  }
34
55
 
35
- output = src + formatted
56
+ output = src + newPart
36
57
  }
37
58
 
38
59
  return output
@@ -83,7 +83,7 @@ class Genexample {
83
83
  if (key in parsed) {
84
84
  preExisted[key] = parsed[key]
85
85
  } else {
86
- exampleSrc += `${key}=""\n`
86
+ exampleSrc += `${key}=''\n`
87
87
 
88
88
  addedKeys.add(key)
89
89