Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

shell-quote

Package Overview
Dependencies
Maintainers
4
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

shell-quote - npm Package Compare versions

Comparing version 1.8.0 to 1.8.1

17

CHANGELOG.md

@@ -8,2 +8,19 @@ # Changelog

## [v1.8.1](https://github.com/ljharb/shell-quote/compare/v1.8.0...v1.8.1) - 2023-04-07
### Fixed
- [Fix] `parse`: preserve whitespace in comments [`#6`](https://github.com/ljharb/shell-quote/issues/6)
- [Fix] properly support the `escape` option [`#5`](https://github.com/ljharb/shell-quote/issues/5)
### Commits
- [Refactor] `parse`: hoist `getVar` to module level [`b42ac73`](https://github.com/ljharb/shell-quote/commit/b42ac73e39e566cfc355a4addc4bd2df2652556c)
- [Refactor] hoist some vars to module level [`8f0c5c3`](https://github.com/ljharb/shell-quote/commit/8f0c5c3c9df3a10e32f1972636675af6fffef998)
- [Refactor] `parse`: use `slice` over `substr`, cache some values [`fcb2e1a`](https://github.com/ljharb/shell-quote/commit/fcb2e1acd5312a1a1a4e6c66ec688aab383023b5)
- [Refactor] `parse`: a bit of cleanup [`6780ec5`](https://github.com/ljharb/shell-quote/commit/6780ec5194e36e2a696bfbaaf85169682a333321)
- [Refactor] `parse`: tweak the regex to not match nothing [`227d474`](https://github.com/ljharb/shell-quote/commit/227d4742a006e81ec3fde1eee103731a6f7ea920)
- [Tests] increase coverage [`a66de94`](https://github.com/ljharb/shell-quote/commit/a66de943555e49fbb1b657cbe3c5b2c703ae507d)
- [Refactor] `parse`: avoid shadowing a function arg [`1d58679`](https://github.com/ljharb/shell-quote/commit/1d5867907ecbf553556fe6ad790b6d6658aedba3)
## [v1.8.0](https://github.com/ljharb/shell-quote/compare/v1.7.4...v1.8.0) - 2023-01-30

@@ -10,0 +27,0 @@

2

package.json
{
"name": "shell-quote",
"description": "quote and parse shell commands",
"version": "1.8.0",
"version": "1.8.1",
"author": {

@@ -6,0 +6,0 @@ "name": "James Halliday",

@@ -6,22 +6,77 @@ 'use strict';

var CONTROL = '(?:' + [
'\\|\\|', '\\&\\&', ';;', '\\|\\&', '\\<\\(', '\\<\\<\\<', '>>', '>\\&', '<\\&', '[&;()|<>]'
'\\|\\|',
'\\&\\&',
';;',
'\\|\\&',
'\\<\\(',
'\\<\\<\\<',
'>>',
'>\\&',
'<\\&',
'[&;()|<>]'
].join('|') + ')';
var controlRE = new RegExp('^' + CONTROL + '$');
var META = '|&;()<> \\t';
var BAREWORD = '(\\\\[\'"' + META + ']|[^\\s\'"' + META + '])+';
var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
var DOUBLE_QUOTE = '\'((\\\\\'|[^\'])*?)\'';
var hash = /^#$/;
var SQ = "'";
var DQ = '"';
var DS = '$';
var TOKEN = '';
var mult = 0x100000000; // Math.pow(16, 8);
for (var i = 0; i < 4; i++) {
TOKEN += (Math.pow(16, 8) * Math.random()).toString(16);
TOKEN += (mult * Math.random()).toString(16);
}
var startsWithToken = new RegExp('^' + TOKEN);
function parseInternal(s, env, opts) {
function matchAll(s, r) {
var origIndex = r.lastIndex;
var matches = [];
var matchObj;
while ((matchObj = r.exec(s))) {
matches.push(matchObj);
if (r.lastIndex === matchObj.index) {
r.lastIndex += 1;
}
}
r.lastIndex = origIndex;
return matches;
}
function getVar(env, pre, key) {
var r = typeof env === 'function' ? env(key) : env[key];
if (typeof r === 'undefined' && key != '') {
r = '';
} else if (typeof r === 'undefined') {
r = '$';
}
if (typeof r === 'object') {
return pre + TOKEN + JSON.stringify(r) + TOKEN;
}
return pre + r;
}
function parseInternal(string, env, opts) {
if (!opts) {
opts = {};
}
var BS = opts.escape || '\\';
var BAREWORD = '(\\' + BS + '[\'"' + META + ']|[^\\s\'"' + META + '])+';
var chunker = new RegExp([
'(' + CONTROL + ')', // control chars
'(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')*'
'(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')+'
].join('|'), 'g');
var match = s.match(chunker).filter(Boolean);
if (!match) {
var matches = matchAll(string, chunker);
if (matches.length === 0) {
return [];

@@ -32,27 +87,11 @@ }

}
if (!opts) {
opts = {};
}
var commented = false;
function getVar(_, pre, key) {
var r = typeof env === 'function' ? env(key) : env[key];
if (r === undefined && key != '') {
r = '';
} else if (r === undefined) {
r = '$';
}
if (typeof r === 'object') {
return pre + TOKEN + JSON.stringify(r) + TOKEN;
}
return pre + r;
}
return match.map(function (s, j) {
if (commented) {
return matches.map(function (match) {
var s = match[0];
if (!s || commented) {
return void undefined;
}
if (RegExp('^' + CONTROL + '$').test(s)) {
if (controlRE.test(s)) {
return { op: s };

@@ -72,6 +111,2 @@ }

// "allonetoken")
var SQ = "'";
var DQ = '"';
var DS = '$';
var BS = opts.escape || '\\';
var quote = false;

@@ -87,28 +122,30 @@ var esc = false;

var varname;
// debugger
if (s.charAt(i) === '{') {
var char = s.charAt(i);
if (char === '{') {
i += 1;
if (s.charAt(i) === '}') {
throw new Error('Bad substitution: ' + s.substr(i - 2, 3));
throw new Error('Bad substitution: ' + s.slice(i - 2, i + 1));
}
varend = s.indexOf('}', i);
if (varend < 0) {
throw new Error('Bad substitution: ' + s.substr(i));
throw new Error('Bad substitution: ' + s.slice(i));
}
varname = s.substr(i, varend - i);
varname = s.slice(i, varend);
i = varend;
} else if ((/[*@#?$!_-]/).test(s.charAt(i))) {
varname = s.charAt(i);
} else if ((/[*@#?$!_-]/).test(char)) {
varname = char;
i += 1;
} else {
varend = s.substr(i).match(/[^\w\d_]/);
var slicedFromI = s.slice(i);
varend = slicedFromI.match(/[^\w\d_]/);
if (!varend) {
varname = s.substr(i);
varname = slicedFromI;
i = s.length;
} else {
varname = s.substr(i, varend.index);
varname = slicedFromI.slice(0, varend.index);
i += varend.index - 1;
}
}
return getVar(null, '', varname);
return getVar(env, '', varname);
}

@@ -144,10 +181,11 @@

quote = c;
} else if (RegExp('^' + CONTROL + '$').test(c)) {
} else if (controlRE.test(c)) {
return { op: s };
} else if ((/^#$/).test(c)) {
} else if (hash.test(c)) {
commented = true;
var commentObj = { comment: string.slice(match.index + i + 1) };
if (out.length) {
return [out, { comment: s.slice(i + 1) + match.slice(j + 1).join(' ') }];
return [out, commentObj];
}
return [{ comment: s.slice(i + 1) + match.slice(j + 1).join(' ') }];
return [commentObj];
} else if (c === BS) {

@@ -167,7 +205,5 @@ esc = true;

return out;
}).reduce(function (prev, arg) { // finalize parsed aruments
if (arg === undefined) {
return prev;
}
return prev.concat(arg);
}).reduce(function (prev, arg) { // finalize parsed arguments
// TODO: replace this whole reduce with a concat
return typeof arg === 'undefined' ? prev : prev.concat(arg);
}, []);

@@ -190,3 +226,3 @@ }

return acc.concat(xs.filter(Boolean).map(function (x) {
if (RegExp('^' + TOKEN).test(x)) {
if (startsWithToken.test(x)) {
return JSON.parse(x.split(TOKEN)[1]);

@@ -193,0 +229,0 @@ }

@@ -60,3 +60,3 @@ # shell-quote <sup>[![Version Badge][npm-version-svg]][package-url]</sup>

var parse = require('shell-quote/parse');
var xs = parse('beep --boop="$PWD"', { PWD: '/home/robot' }, { escape: '^' });
var xs = parse('beep ^--boop="$PWD"', { PWD: '/home/robot' }, { escape: '^' });
console.dir(xs);

@@ -68,3 +68,3 @@ ```

```
[ 'beep', '--boop=/home/robot' ]
[ 'beep --boop=/home/robot' ]
```

@@ -71,0 +71,0 @@

@@ -9,9 +9,9 @@ 'use strict';

t.same(parse('beep #boop'), ['beep', { comment: 'boop' }]);
t.same(parse('beep # boop'), ['beep', { comment: 'boop' }]);
t.same(parse('beep # > boop'), ['beep', { comment: '> boop' }]);
t.same(parse('beep # "> boop"'), ['beep', { comment: '"> boop"' }]);
t.same(parse('beep # boop'), ['beep', { comment: ' boop' }]);
t.same(parse('beep # > boop'), ['beep', { comment: ' > boop' }]);
t.same(parse('beep # "> boop"'), ['beep', { comment: ' "> boop"' }]);
t.same(parse('beep "#"'), ['beep', '#']);
t.same(parse('beep #"#"#'), ['beep', { comment: '"#"#' }]);
t.same(parse('beep > boop # > foo'), ['beep', { op: '>' }, 'boop', { comment: '> foo' }]);
t.same(parse('beep > boop # > foo'), ['beep', { op: '>' }, 'boop', { comment: ' > foo' }]);
t.end();
});

@@ -7,2 +7,15 @@ 'use strict';

test('parse shell commands', function (t) {
t.same(parse(''), [], 'parses an empty string');
t['throws'](
function () { parse('${}'); },
Error,
'empty substitution throws'
);
t['throws'](
function () { parse('${'); },
Error,
'incomplete substitution throws'
);
t.same(parse('a \'b\' "c"'), ['a', 'b', 'c']);

@@ -24,4 +37,8 @@ t.same(

t.same(parse("x bl^'a^'h'", {}, { escape: '^' }), ['x', "bl'a'h"]);
t.same(parse('abcH def', {}, { escape: 'H' }), ['abc def']);
t.deepEqual(parse('# abc def ghi'), [{ comment: ' abc def ghi' }], 'start-of-line comment content is unparsed');
t.deepEqual(parse('xyz # abc def ghi'), ['xyz', { comment: ' abc def ghi' }], 'comment content is unparsed');
t.end();
});
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc