Skip to content
This repository has been archived by the owner on Jan 6, 2021. It is now read-only.

Introduce dollar sign escaping #147

Merged
merged 3 commits into from
Oct 16, 2017
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,18 @@
"code",
"test"
]
},
{
"login": "sventschui",
"name": "Sven",
"avatar_url": "https://avatars3.githubusercontent.com/u/512692?v=4",
"profile": "https://github.com/sventschui",
"contributions": [
"code",
"doc",
"example",
"test"
]
}
]
}
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Run scripts that set and use environment variables across platforms
[![downloads][downloads-badge]][npm-stat]

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

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 tough.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tough

Should be "though"


Lastly, if you want to pass a JSON string (e.g., when using [ts-loader]), you can do as follows:

```json
Expand Down Expand Up @@ -142,9 +144,9 @@ much easier for Windows users.
Thanks goes to these people ([emoji key][emojis]):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
| [<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) |
| [<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") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<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) |
| [<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") |
<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the [all-contributors][all-contributors] specification. Contributions of any kind welcome!
Expand Down
20 changes: 20 additions & 0 deletions src/__tests__/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,23 @@ test(`resolves an env variable with a JSON string value on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
expect(varValueConvert('$JSON_VAR')).toBe(JSON_VALUE)
})

test(`does not resolve an env variable prefixed with \\ on Windows`, () => {
isWindowsMock.__mock.returnValue = true
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
})

test(`does not resolve an env variable prefixed with \\ on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
expect(varValueConvert('\\$VAR1')).toBe('$VAR1')
})

test(`resolves an env variable prefixed with \\\\ on Windows`, () => {
isWindowsMock.__mock.returnValue = true
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
})

test(`resolves an env variable prefixed with \\\\ on UNIX`, () => {
isWindowsMock.__mock.returnValue = false
expect(varValueConvert('\\\\$VAR1')).toBe('\\value1')
})
22 changes: 16 additions & 6 deletions src/variable.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ function replaceListDelimiters(varValue, varName = '') {
/**
* This will attempt to resolve the value of any env variables that are inside
* this string. For example, it will transform this:
* cross-env FOO=$NODE_ENV echo $FOO
* cross-env FOO=$NODE_ENV BAR=\\$NODE_ENV echo $FOO $BAR
* Into this:
* FOO=development echo $FOO
* FOO=development BAR=$NODE_ENV echo $FOO
* (Or whatever value the variable NODE_ENV has)
* Note that this function is only called with the right-side portion of the
* env var assignment, so in that example, this function would transform
Expand All @@ -40,10 +40,20 @@ function replaceListDelimiters(varValue, varName = '') {
* @returns {String} Converted value
*/
function resolveEnvVars(varValue) {
const envUnixRegex = /\$(\w+)|\${(\w+)}/g // $my_var or ${my_var}
return varValue.replace(envUnixRegex, (_, varName, altVarName) => {
return process.env[varName || altVarName] || ''
})
const envUnixRegex = /(\\*)(\$(\w+)|\${(\w+)})/g // $my_var or ${my_var} or \$my_var
return varValue.replace(
envUnixRegex,
(_, escapeChars, varNameWithDollarSign, varName, altVarName) => {
// do not replace things preceded by a odd number of \
if (escapeChars.length % 2 === 1) {
return varNameWithDollarSign
}
return (
escapeChars.substr(0, escapeChars.length / 2) +
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you walk me through why only half the back-slashes are required? I'm not sure I understand.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what happens in regular js string escaping too. \\ gets to be a \. This is needed to allow somebody to write a \ in front of a $VARIABLE and still replace the variable.

\$VAR -> $VAR
\\$VAR -> \value
\\\$VAR -> \\$VAR
\\\\$VAR -> \\value

and so on.

Hope this makes it clear

Copy link
Collaborator

@hgwood hgwood Oct 16, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Thank you. What about the other case? If the number of back-slashes is odd, isn't this code going to replace the expression by $VAR every time? Shouldn't some back-slashes be retained?

Also I'm not sure your examples are quite consistent. In \$VAR -> $VAR, the back-slash is escaping the dollar sign. In \\$VAR -> \value the first back-slash escapes the second and the dollar sign is not escaped. Sounds fine up to there. Then in \\\$VAR -> \\$VAR, the first black-slash escapes the second, then the third escapes the dollar sign. So the result should be \$VAR, shouldn't it? Maybe you made a typo? Fourth example looks right.

(process.env[varName || altVarName] || '')
)
},
)
}

/**
Expand Down