@dotenvx/dotenvx
Advanced tools
Comparing version 1.17.0 to 1.18.0
@@ -5,4 +5,37 @@ # Changelog | ||
## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.17.0...main) | ||
## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v1.18.0...main) | ||
## 1.18.0 | ||
### Added | ||
* `set` and `encrypt` preserve leading spaces ([#395](https://github.com/dotenvx/dotenvx/pull/395/)) | ||
```sh | ||
HELLO=world | ||
``` | ||
### Changed | ||
* improve escape and quote handling for `set`, `encrypt`, and `decrypt` ([#395](https://github.com/dotenvx/dotenvx/pull/395)) | ||
* 🐞 fix `encrypt`, then `decrypt`, then `encrypt` on a json value ([#377](https://github.com/dotenvx/dotenvx/issues/377)) | ||
Note: the underlying `replace` engine to support these changes now wraps your values in single quotes. the prior `replace` engine wrapped in double quotes. | ||
So where your `.env` used to look like this with double quotes: | ||
```sh | ||
HELLO="encrypted:1234" | ||
API_KEY="encrypted:5678" | ||
``` | ||
It will now begin looking like this with single quotes: | ||
```sh | ||
HELLO='encrypted:1234' | ||
API_KEY='encrypted:5678' | ||
``` | ||
It's an aesthetic side effect only. Your values will continue to be decrypted and encrypted correctly. | ||
## 1.17.0 | ||
@@ -9,0 +42,0 @@ |
{ | ||
"version": "1.17.0", | ||
"version": "1.18.0", | ||
"name": "@dotenvx/dotenvx", | ||
@@ -4,0 +4,0 @@ "description": "a better dotenv–from the creator of `dotenv`", |
@@ -264,2 +264,14 @@ [![dotenvx](https://dotenvx.com/better-banner.png)](https://dotenvx.com) | ||
</details> | ||
* <details><summary>Kotlin 📐</summary><br> | ||
```sh | ||
$ echo "HELLO=World" > .env | ||
$ echo 'fun main() { val hello = System.getenv("HELLO") ?: ""; println("Hello $hello") }' > index.kt | ||
$ kotlinc index.kt -include-runtime -d index.jar | ||
$ dotenvx run -- java -jar index.jar | ||
Hello World | ||
``` | ||
</details> | ||
* <details><summary>.NET 🔵</summary><br> | ||
@@ -1093,3 +1105,3 @@ | ||
``` | ||
```sh | ||
$ echo "console.log('Hello ' + process.env.KEY + ' ' + process.env.HELLO)" > index.js | ||
@@ -1096,0 +1108,0 @@ $ eval $(dotenvx get --format=eval) node index.js |
@@ -0,36 +1,53 @@ | ||
const util = require('util') | ||
const dotenv = require('dotenv') | ||
function replace (src, key, value) { | ||
const escapeForRegex = require('./escapeForRegex') | ||
function replace (src, key, replaceValue) { | ||
let output | ||
let formatted = `${key}="${value}"` | ||
let escapedValue = util.inspect(replaceValue, { showHidden: false, depth: null, colors: false }) | ||
if (replaceValue.includes('\n')) { | ||
escapedValue = JSON.stringify(replaceValue) // use JSON stringify if string contains newlines | ||
escapedValue = escapedValue.replace(/\\n/g, '\n') // fix up newlines | ||
escapedValue = escapedValue.replace(/\\r/g, '\r') | ||
} | ||
let newPart = `${key}=${escapedValue}` | ||
const parsed = dotenv.parse(src) | ||
if (Object.prototype.hasOwnProperty.call(parsed, key)) { | ||
const regex = new RegExp( | ||
// Match the key at the start of a line, following a newline, or prefaced by export | ||
`(^|\\n)\\s*(export\\s+)?${key}\\s*=\\s*` + | ||
// `(^|\\n)${key}\\s*=\\s*` + | ||
// Non-capturing group to handle different types of quotations and unquoted values | ||
'(?:' + | ||
'(["\'`])' + // Match an opening quote | ||
'.*?' + // Non-greedy match for any characters within quotes | ||
// '\\2' + // Match the corresponding closing quote | ||
'\\3' + // Match the corresponding closing quote | ||
'|' + | ||
// Match unquoted values; account for escaped newlines | ||
'(?:[^#\\n\\\\]|\\\\.)*' + // Use non-capturing group for any character except #, newline, or backslash, or any escaped character | ||
')', | ||
'gs' // Global and dotAll mode to treat string as single line | ||
const originalValue = parsed[key] | ||
const escapedOriginalValue = escapeForRegex(originalValue) | ||
// conditionally enforce end of line | ||
let enforceEndOfLine = '' | ||
if (escapedOriginalValue === '') { | ||
enforceEndOfLine = '$' // EMPTY scenario | ||
} | ||
const currentPart = new RegExp( | ||
'^' + // start of line | ||
'(\\s*)?' + // spaces | ||
'(export\\s+)?' + // export | ||
key + // KEY | ||
'\\s*=\\s*' + // spaces (KEY = value) | ||
'["\'`]?' + // open quote | ||
escapedOriginalValue + // escaped value | ||
'["\'`]?' + // close quote | ||
enforceEndOfLine | ||
, | ||
'gm' // (g)lobal (m)ultiline | ||
) | ||
output = src.replace(regex, `$1$2${formatted}`) | ||
// $1 preserves spaces | ||
// $2 preserves export | ||
output = src.replace(currentPart, `$1$2${newPart}`) | ||
} else { | ||
// append | ||
if (src.endsWith('\n')) { | ||
formatted = formatted + '\n' | ||
newPart = newPart + '\n' | ||
} else { | ||
formatted = '\n' + formatted | ||
newPart = '\n' + newPart | ||
} | ||
output = src + formatted | ||
output = src + newPart | ||
} | ||
@@ -37,0 +54,0 @@ |
@@ -86,3 +86,3 @@ const fs = require('fs') | ||
} else { | ||
exampleSrc += `${key}=""\n` | ||
exampleSrc += `${key}=''\n` | ||
@@ -89,0 +89,0 @@ addedKeys.add(key) |
204801
75
3500
1716