🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

shell-quote

Package Overview
Dependencies
Maintainers
4
Versions
32
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.3
to
1.8.4
+5
-6
package.json
{
"name": "shell-quote",
"description": "quote and parse shell commands",
"version": "1.8.3",
"version": "1.8.4",
"author": {

@@ -15,10 +15,9 @@ "name": "James Halliday",

"devDependencies": {
"@ljharb/eslint-config": "^21.1.1",
"auto-changelog": "^2.5.0",
"encoding": "^0.1.13",
"eslint": "=8.8.0",
"@ljharb/eslint-config": "^22.2.3",
"auto-changelog": "^2.5.1",
"eslint": "^8.57.1",
"evalmd": "^0.0.19",
"in-publish": "^2.0.1",
"jackspeak": "=2.1.1",
"npmignore": "^0.3.1",
"npmignore": "^0.3.5",
"nyc": "^10.3.2",

@@ -25,0 +24,0 @@ "safe-publish-latest": "^2.0.0",

'use strict';
var OPS = [
'||',
'&&',
';;',
'|&',
'<(',
'<<<',
'>>',
'>&',
'<&',
'&',
';',
'(',
')',
'|',
'<',
'>'
];
var LINE_TERMINATORS = /[\n\r\u2028\u2029]/;
var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g;
module.exports = function quote(xs) {

@@ -9,3 +30,24 @@ return xs.map(function (s) {

if (s && typeof s === 'object') {
return s.op.replace(/(.)/g, '\\$1');
if (s.op === 'glob') {
if (typeof s.pattern !== 'string') {
throw new TypeError('glob token requires a string `pattern`');
}
if (LINE_TERMINATORS.test(s.pattern)) {
throw new TypeError('glob `pattern` must not contain line terminators');
}
return s.pattern.replace(GLOB_SHELL_SPECIAL, '\\$&');
}
if (typeof s.op === 'string') {
if (OPS.indexOf(s.op) < 0) {
throw new TypeError('invalid `op` value: ' + JSON.stringify(s.op));
}
return s.op.replace(/[\s\S]/g, '\\$&');
}
if (typeof s.comment === 'string') {
if (LINE_TERMINATORS.test(s.comment)) {
throw new TypeError('`comment` must not contain line terminators');
}
return '#' + s.comment;
}
throw new TypeError('unrecognized object token shape');
}

@@ -12,0 +54,0 @@ if ((/["\s\\]/).test(s) && !(/'/).test(s)) {

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

Each entry of `args` may be a string, or one of the object shapes that
`parse` emits: `{ op }` (where `op` is one of the control operators
`||`, `&&`, `;;`, `|&`, `<(`, `<<<`, `>>`, `>&`, `<&`, `&`, `;`, `(`,
`)`, `|`, `<`, `>`), `{ op: 'glob', pattern }`, or `{ comment }`. Any
other object shape, an unrecognized `op`, or a `pattern`/`comment`
containing line terminators throws a `TypeError`.
## parse(cmd, env={})

@@ -161,3 +168,3 @@

[codecov-url]: https://app.codecov.io/gh/ljharb/shell-quote/
[actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/ljharb/shell-quote
[actions-image]: https://img.shields.io/github/check-runs/ljharb/shell-quote/main
[actions-url]: https://github.com/ljharb/shell-quote/actions

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

t.same(
parse('2;b', {}, { escape: 'd' }),
[{ op: '2;b' }],
'control char in unquoted context mid-token with regex-special escape returns op'
);
t.end();
});

@@ -61,1 +61,57 @@ 'use strict';

});
test('quote ops: allowlist', function (t) {
var ops = ['||', '&&', ';;', '|&', '<(', '<<<', '>>', '>&', '<&', '&', ';', '(', ')', '|', '<', '>'];
for (var i = 0; i < ops.length; i++) {
var op = ops[i];
var expected = '';
for (var j = 0; j < op.length; j++) { expected += '\\' + op.charAt(j); }
t.equal(quote([{ op: op }]), expected, 'op ' + op);
}
t.end();
});
test('quote ops: rejects line terminators (GHSA-w7jw-789q-3m8p)', function (t) {
t['throws'](function () { quote([{ op: ';\nid' }]); }, TypeError, 'newline in op');
t['throws'](function () { quote([{ op: ';\rid' }]); }, TypeError, 'carriage return in op');
t['throws'](function () { quote([{ op: ';\u2028id' }]); }, TypeError, 'U+2028 in op');
t['throws'](function () { quote([{ op: ';\u2029id' }]); }, TypeError, 'U+2029 in op');
t.end();
});
test('quote ops: rejects non-allowlisted values', function (t) {
t['throws'](function () { quote([{ op: '' }]); }, TypeError, 'empty op');
t['throws'](function () { quote([{ op: 'foo' }]); }, TypeError, 'arbitrary string');
t['throws'](function () { quote([{ op: '|||' }]); }, TypeError, 'near-miss');
t['throws'](function () { quote([{ op: 42 }]); }, TypeError, 'non-string op');
t.end();
});
test('quote glob pattern', function (t) {
t.equal(quote([{ op: 'glob', pattern: 'test/*.test.js' }]), 'test/*.test.js');
t.equal(quote([{ op: 'glob', pattern: '?ab' }]), '?ab');
t.equal(quote([{ op: 'glob', pattern: '[ab]c' }]), '[ab]c');
t.equal(quote([{ op: 'glob', pattern: '{a,b}' }]), '{a,b}');
t.equal(quote([{ op: 'glob', pattern: 'my dir/*.txt' }]), 'my\\ dir/*.txt');
t.equal(quote([{ op: 'glob', pattern: 'a$b' }]), 'a\\$b');
t['throws'](function () { quote([{ op: 'glob' }]); }, TypeError, 'missing pattern');
t['throws'](function () { quote([{ op: 'glob', pattern: 'a\nb' }]); }, TypeError, 'newline in pattern');
t['throws'](function () { quote([{ op: 'glob', pattern: 'a\u2028b' }]); }, TypeError, 'U+2028 in pattern');
t.end();
});
test('quote comment', function (t) {
t.equal(quote(['echo', 'hi', { comment: ' a comment' }]), 'echo hi # a comment');
t.equal(quote([{ comment: '' }]), '#');
t['throws'](function () { quote([{ comment: 'a\nb' }]); }, TypeError, 'newline in comment');
t['throws'](function () { quote([{ comment: 'a\rb' }]); }, TypeError, 'CR in comment');
t['throws'](function () { quote([{ comment: 'a\u2028b' }]); }, TypeError, 'U+2028 in comment');
t.end();
});
test('quote rejects unrecognized object shapes', function (t) {
t['throws'](function () { quote([{}]); }, TypeError, 'empty object');
t['throws'](function () { quote([{ foo: 'bar' }]); }, TypeError, 'unknown key');
t['throws'](function () { quote([{ op: null }]); }, TypeError, 'null op');
t.end();
});
#!/usr/bin/env python3
import sys
print(sys.argv[1])