Skip to content
This repository was archived by the owner on Nov 19, 2025. It is now read-only.

Commit 36b009e

Browse files
SvenKent C. Dodds
authored andcommitted
feat: introduce dollar sign escaping (#147)
* Introduce dollar sign escaping * Fix typo in README.md
1 parent 7719fb2 commit 36b009e

4 files changed

Lines changed: 53 additions & 9 deletions

File tree

.all-contributorsrc

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@
142142
"code",
143143
"test"
144144
]
145+
},
146+
{
147+
"login": "sventschui",
148+
"name": "Sven",
149+
"avatar_url": "https://avatars3.githubusercontent.com/u/512692?v=4",
150+
"profile": "https://github.com/sventschui",
151+
"contributions": [
152+
"code",
153+
"doc",
154+
"example",
155+
"test"
156+
]
145157
}
146158
]
147159
}

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Run scripts that set and use environment variables across platforms
1616
[![downloads][downloads-badge]][npm-stat]
1717

1818
[![MIT License][license-badge]][LICENSE]
19-
[![All Contributors](https://img.shields.io/badge/all_contributors-13-orange.svg?style=flat-square)](#contributors)
19+
[![All Contributors](https://img.shields.io/badge/all_contributors-14-orange.svg?style=flat-square)](#contributors)
2020
[![PRs Welcome][prs-badge]][prs]
2121
[![Donate][donate-badge]][donate]
2222
[![Code of Conduct][coc-badge]][coc]
@@ -97,6 +97,8 @@ the parent. This is quite useful for launching the same command with different
9797
env variables or when the environment variables are too long to have everything
9898
in one line.
9999

100+
If you preceed a dollar sign with an odd number of backslashes the expression statement will not be replaced. Note that this means backslashes after the JSON string escaping took place. `"FOO=\\$BAR"` will not be replaced. `"FOO=\\\\$BAR"` will be replaced though.
101+
100102
Lastly, if you want to pass a JSON string (e.g., when using [ts-loader]), you can do as follows:
101103

102104
```json
@@ -151,9 +153,9 @@ much easier for Windows users.
151153
Thanks goes to these people ([emoji key][emojis]):
152154

153155
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
154-
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub>Kent C. Dodds</sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds) [📖](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds) 🚇 [⚠️](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds) | [<img src="https://avatars1.githubusercontent.com/u/499038?v=3" width="100px;"/><br /><sub>Ya Zhuang </sub>](https://zhuangya.me)<br />🔌 [📖](https://github.com/kentcdodds/cross-env/commits?author=zhuangya) | [<img src="https://avatars3.githubusercontent.com/u/3440094?v=3" width="100px;"/><br /><sub>James Harris</sub>](https://wopian.me)<br />[📖](https://github.com/kentcdodds/cross-env/commits?author=wopian) | [<img src="https://avatars1.githubusercontent.com/u/8941730?v=3" width="100px;"/><br /><sub>compumike08</sub>](https://github.com/compumike08)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Acompumike08) [📖](https://github.com/kentcdodds/cross-env/commits?author=compumike08) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=compumike08) | [<img src="https://avatars1.githubusercontent.com/u/2270425?v=3" width="100px;"/><br /><sub>Daniel Rodríguez Rivero</sub>](https://github.com/danielo515)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Adanielo515) [💻](https://github.com/kentcdodds/cross-env/commits?author=danielo515) [📖](https://github.com/kentcdodds/cross-env/commits?author=danielo515) | [<img src="https://avatars2.githubusercontent.com/u/1508477?v=3" width="100px;"/><br /><sub>Jonas Keinholz</sub>](https://github.com/inyono)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Ainyono) [💻](https://github.com/kentcdodds/cross-env/commits?author=inyono) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=inyono) | [<img src="https://avatars3.githubusercontent.com/u/1656170?v=3" width="100px;"/><br /><sub>Hugo Wood</sub>](https://github.com/hgwood)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Ahgwood) [💻](https://github.com/kentcdodds/cross-env/commits?author=hgwood) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=hgwood) |
156+
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub>Kent C. Dodds</sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds "Code") [📖](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=kentcdodds "Tests") | [<img src="https://avatars1.githubusercontent.com/u/499038?v=3" width="100px;"/><br /><sub>Ya Zhuang </sub>](https://zhuangya.me)<br />[🔌](#plugin-zhuangya "Plugin/utility libraries") [📖](https://github.com/kentcdodds/cross-env/commits?author=zhuangya "Documentation") | [<img src="https://avatars3.githubusercontent.com/u/3440094?v=3" width="100px;"/><br /><sub>James Harris</sub>](https://wopian.me)<br />[📖](https://github.com/kentcdodds/cross-env/commits?author=wopian "Documentation") | [<img src="https://avatars1.githubusercontent.com/u/8941730?v=3" width="100px;"/><br /><sub>compumike08</sub>](https://github.com/compumike08)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Acompumike08 "Bug reports") [📖](https://github.com/kentcdodds/cross-env/commits?author=compumike08 "Documentation") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=compumike08 "Tests") | [<img src="https://avatars1.githubusercontent.com/u/2270425?v=3" width="100px;"/><br /><sub>Daniel Rodríguez Rivero</sub>](https://github.com/danielo515)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Adanielo515 "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=danielo515 "Code") [📖](https://github.com/kentcdodds/cross-env/commits?author=danielo515 "Documentation") | [<img src="https://avatars2.githubusercontent.com/u/1508477?v=3" width="100px;"/><br /><sub>Jonas Keinholz</sub>](https://github.com/inyono)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Ainyono "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=inyono "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=inyono "Tests") | [<img src="https://avatars3.githubusercontent.com/u/1656170?v=3" width="100px;"/><br /><sub>Hugo Wood</sub>](https://github.com/hgwood)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Ahgwood "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=hgwood "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=hgwood "Tests") |
155157
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
156-
| [<img src="https://avatars0.githubusercontent.com/u/3715715?v=3" width="100px;"/><br /><sub>Thiebaud Thomas</sub>](https://github.com/thomasthiebaud)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Athomasthiebaud) [💻](https://github.com/kentcdodds/cross-env/commits?author=thomasthiebaud) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=thomasthiebaud) | [<img src="https://avatars1.githubusercontent.com/u/1715800?v=3" width="100px;"/><br /><sub>Daniel Rey López</sub>](https://daniel.blog)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=DanReyLop) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=DanReyLop) | [<img src="https://avatars2.githubusercontent.com/u/6374832?v=3" width="100px;"/><br /><sub>Amila Welihinda</sub>](http://amilajack.com)<br />🚇 | [<img src="https://avatars1.githubusercontent.com/u/1396?v=3" width="100px;"/><br /><sub>Paul Betts</sub>](https://twitter.com/paulcbetts)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Apaulcbetts) [💻](https://github.com/kentcdodds/cross-env/commits?author=paulcbetts) | [<img src="https://avatars1.githubusercontent.com/u/6371670?v=3" width="100px;"/><br /><sub>Turner Hayes</sub>](https://github.com/turnerhayes)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Aturnerhayes) [💻](https://github.com/kentcdodds/cross-env/commits?author=turnerhayes) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=turnerhayes) | [<img src="https://avatars2.githubusercontent.com/u/22251956?v=4" width="100px;"/><br /><sub>Suhas Karanth</sub>](https://github.com/sudo-suhas)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=sudo-suhas) [⚠️](https://github.com/kentcdodds/cross-env/commits?author=sudo-suhas) |
158+
| [<img src="https://avatars0.githubusercontent.com/u/3715715?v=3" width="100px;"/><br /><sub>Thiebaud Thomas</sub>](https://github.com/thomasthiebaud)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Athomasthiebaud "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=thomasthiebaud "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=thomasthiebaud "Tests") | [<img src="https://avatars1.githubusercontent.com/u/1715800?v=3" width="100px;"/><br /><sub>Daniel Rey López</sub>](https://daniel.blog)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=DanReyLop "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=DanReyLop "Tests") | [<img src="https://avatars2.githubusercontent.com/u/6374832?v=3" width="100px;"/><br /><sub>Amila Welihinda</sub>](http://amilajack.com)<br />[🚇](#infra-amilajack "Infrastructure (Hosting, Build-Tools, etc)") | [<img src="https://avatars1.githubusercontent.com/u/1396?v=3" width="100px;"/><br /><sub>Paul Betts</sub>](https://twitter.com/paulcbetts)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Apaulcbetts "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=paulcbetts "Code") | [<img src="https://avatars1.githubusercontent.com/u/6371670?v=3" width="100px;"/><br /><sub>Turner Hayes</sub>](https://github.com/turnerhayes)<br />[🐛](https://github.com/kentcdodds/cross-env/issues?q=author%3Aturnerhayes "Bug reports") [💻](https://github.com/kentcdodds/cross-env/commits?author=turnerhayes "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=turnerhayes "Tests") | [<img src="https://avatars2.githubusercontent.com/u/22251956?v=4" width="100px;"/><br /><sub>Suhas Karanth</sub>](https://github.com/sudo-suhas)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=sudo-suhas "Code") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=sudo-suhas "Tests") | [<img src="https://avatars3.githubusercontent.com/u/512692?v=4" width="100px;"/><br /><sub>Sven</sub>](https://github.com/sventschui)<br />[💻](https://github.com/kentcdodds/cross-env/commits?author=sventschui "Code") [📖](https://github.com/kentcdodds/cross-env/commits?author=sventschui "Documentation") [💡](#example-sventschui "Examples") [⚠️](https://github.com/kentcdodds/cross-env/commits?author=sventschui "Tests") |
157159
<!-- ALL-CONTRIBUTORS-LIST:END -->
158160

159161
This project follows the [all-contributors][all-contributors] specification. Contributions of any kind welcome!

src/__tests__/variable.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,23 @@ test(`resolves an env variable with a JSON string value on UNIX`, () => {
9797
isWindowsMock.__mock.returnValue = false
9898
expect(varValueConvert('$JSON_VAR')).toBe(JSON_VALUE)
9999
})
100+
101+
test(`does not resolve an env variable prefixed with \\ on Windows`, () => {
102+
isWindowsMock.__mock.returnValue = true
103+
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
104+
})
105+
106+
test(`does not resolve an env variable prefixed with \\ on UNIX`, () => {
107+
isWindowsMock.__mock.returnValue = false
108+
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
109+
})
110+
111+
test(`resolves an env variable prefixed with \\\\ on Windows`, () => {
112+
isWindowsMock.__mock.returnValue = true
113+
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
114+
})
115+
116+
test(`resolves an env variable prefixed with \\\\ on UNIX`, () => {
117+
isWindowsMock.__mock.returnValue = false
118+
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
119+
})

src/variable.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ function replaceListDelimiters(varValue, varName = '') {
2929
/**
3030
* This will attempt to resolve the value of any env variables that are inside
3131
* this string. For example, it will transform this:
32-
* cross-env FOO=$NODE_ENV echo $FOO
32+
* cross-env FOO=$NODE_ENV BAR=\\$NODE_ENV echo $FOO $BAR
3333
* Into this:
34-
* FOO=development echo $FOO
34+
* FOO=development BAR=$NODE_ENV echo $FOO
3535
* (Or whatever value the variable NODE_ENV has)
3636
* Note that this function is only called with the right-side portion of the
3737
* env var assignment, so in that example, this function would transform
@@ -40,10 +40,20 @@ function replaceListDelimiters(varValue, varName = '') {
4040
* @returns {String} Converted value
4141
*/
4242
function resolveEnvVars(varValue) {
43-
const envUnixRegex = /\$(\w+)|\${(\w+)}/g // $my_var or ${my_var}
44-
return varValue.replace(envUnixRegex, (_, varName, altVarName) => {
45-
return process.env[varName || altVarName] || ''
46-
})
43+
const envUnixRegex = /(\\*)(\$(\w+)|\${(\w+)})/g // $my_var or ${my_var} or \$my_var
44+
return varValue.replace(
45+
envUnixRegex,
46+
(_, escapeChars, varNameWithDollarSign, varName, altVarName) => {
47+
// do not replace things preceded by a odd number of \
48+
if (escapeChars.length % 2 === 1) {
49+
return varNameWithDollarSign
50+
}
51+
return (
52+
escapeChars.substr(0, escapeChars.length / 2) +
53+
(process.env[varName || altVarName] || '')
54+
)
55+
},
56+
)
4757
}
4858

4959
/**

0 commit comments

Comments
 (0)