Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: dotenvx/dotenvx
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.43.0
Choose a base ref
...
head repository: dotenvx/dotenvx
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: v0.43.1
Choose a head ref
  • 9 commits
  • 6 files changed
  • 2 contributors

Commits on May 20, 2024

  1. Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    e4e4cc4 View commit details

Commits on May 21, 2024

  1. making replace smarter

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    91c681c View commit details
  2. README update

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    91ed49b View commit details
  3. Merge pull request #226 from returnkirbo/main

    fix spelling mistake in README
    motdotla authored May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    193c70f View commit details
  4. add test to cover regression of setting values middway through .env file

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    1095da7 View commit details
  5. changelog 🪵

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    1c85a1e View commit details
  6. standard formatting 🧼

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    41eff92 View commit details
  7. Merge pull request #227 from dotenvx/replace-tests

    making replace smarter
    motdotla authored May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    8fc7f45 View commit details
  8. 0.43.1

    motdotla committed May 21, 2024

    Verified

    This commit was signed with the committer’s verified signature.
    dtolnay David Tolnay
    Copy the full SHA
    53354cc View commit details
Showing with 196 additions and 7 deletions.
  1. +7 −1 CHANGELOG.md
  2. +1 −1 README.md
  3. +2 −2 package-lock.json
  4. +1 −1 package.json
  5. +13 −2 src/lib/helpers/replace.js
  6. +172 −0 tests/lib/helpers/replace.test.js
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -2,7 +2,13 @@

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.

## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v0.43.0...main)
## [Unreleased](https://github.com/dotenvx/dotenvx/compare/v0.43.1...main)

## 0.43.1

### Added

* Improved `replace` function regex - to handle more edge case scenarios with replacing KEY/values ([#227](https://github.com/dotenvx/dotenvx/pull/227))

## 0.43.0

2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ brew install dotenvx/brew/dotenvx
```
> * [other global ways to install](https://dotenvx.com/docs/install)
>
> Intall globally as a cli to unlock dotenv for ANY language, framework, or platform. 💥
> Install globally as a cli to unlock dotenv for ANY language, framework, or platform. 💥
>
> I am using (and recommending) this approach going forward. – [motdotla](https://github.com/motdotla)
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "0.43.0",
"version": "0.43.1",
"name": "@dotenvx/dotenvx",
"description": "a better dotenv–from the creator of `dotenv`",
"author": "@motdotla",
15 changes: 13 additions & 2 deletions src/lib/helpers/replace.js
Original file line number Diff line number Diff line change
@@ -6,8 +6,19 @@ function replace (src, key, value) {

const parsed = dotenv.parse(src)
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
// replace
const regex = new RegExp(`^${key}=(?:(["'\`])[^\\1]*\\1|[^\\n]*)(\\n[^A-Z0-9_].*)*`, 'm')
const regex = new RegExp(
`^${key}=` + // start of line with key
'(?:' + // begin non-capturing group for handling both quoted and unquoted values
'(["\'`])' + // capture opening quote (' or " or `)
'[^\\1]*' + // match any character except the quote captured initially
'\\1' + // match the same closing quote as captured at the start
'|' + // OR
'[^#\\n]*' + // match any characters until a # (comment) or newline
')' + // end non-capturing group
'(\\n[^A-Z0-9_].*)*', // match subsequent lines that don't start with a letter, number, or underscore (continuation lines)
'm' // apply multiline mode, so ^ and $ match start and end of lines, not just the whole string
)

output = src.replace(regex, formatted)
} else {
// append
172 changes: 172 additions & 0 deletions tests/lib/helpers/replace.test.js
Original file line number Diff line number Diff line change
@@ -94,3 +94,175 @@ t.test('#replace evals', ct => {

ct.end()
})

t.test('#replace empty', ct => {
const src = 'HELLO='

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace empty backticks', ct => {
const src = 'HELLO=``'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace spaced single quotes', ct => {
const src = 'HELLO=\' single quote \''

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace spaced double quotes', ct => {
const src = 'HELLO=" single quote "'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace double quotes inside single quotes', ct => {
const src = 'HELLO=\'double "quotes" inside single quotes'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace single quotes inside double quotes', ct => {
const src = 'HELLO="single \'quotes\' inside single quotes"'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace double quotes and single quotes inside backticks', ct => {
const src = 'HELLO=`double "quotes" and single \'quotes\' inside backticks`'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace newlines', ct => {
const src = 'HELLO="expand\nnew\nlines"'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace unquoted newlines', ct => {
const src = 'HELLO=dontexpand\nnewlines'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace inline comments', ct => {
const src = 'HELLO=inline comments # work #very #well'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"# work #very #well')

ct.end()
})

t.test('#replace inline comments', ct => {
const src = 'HELLO=inline comments # work #very #well'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"# work #very #well') // make a little smarter to handle the spaces

ct.end()
})

t.test('#replace hashtag in quotes', ct => {
const src = 'HELLO="hash #tag quoted"'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace equal signs', ct => {
const src = 'HELLO=equals=='

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace inner quotes', ct => {
const src = 'HELLO={"foo": "bar"}'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace inner quotes as string', ct => {
const src = 'HELLO=\'{"foo": "bar"}\''

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

t.test('#replace inner quotes as backticks', ct => {
const src = 'HELLO=`{"foo": "bar\'s"}`'

const newSrc = replace(src, 'HELLO', 'Universe')
ct.same(newSrc, 'HELLO="Universe"')

ct.end()
})

// TODO: handle leading space
// t.test('#replace spaced key', ct => {
// const src = ' HELLO=parsed'
//
// const newSrc = replace(src, 'HELLO', 'Universe')
// ct.same(newSrc, ' HELLO="Universe"')
//
// ct.end()
// })

t.test('#replace somewhere in the middle', ct => {
const src = `VAR_1=val_1
VAR_2=val_2
VAR_3=val_3
VAR_4=val_4`

const newSrc = replace(src, 'VAR_2', 'val_2b')

const expected = `VAR_1=val_1
VAR_2="val_2b"
VAR_3=val_3
VAR_4=val_4`

ct.same(newSrc, expected)

ct.end()
})