diff --git a/.eslintrc b/.eslintrc index 68df73c..4c29af2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,50 +1,41 @@ { - "root": true, + "root": true, - "extends": "@ljharb", + "extends": "@ljharb", - "rules": { - "array-bracket-newline": 0, - "array-bracket-spacing": 1, - "array-callback-return": 1, - "brace-style": 1, - "comma-spacing": 1, - "complexity": 0, - "consistent-return": 1, - "curly": 1, - "eqeqeq": 1, - "func-style": 1, - "indent": [1, 4], - "max-depth": 0, - "max-lines-per-function": 1, - "max-statements": 0, - "multiline-comment-style": 0, - "no-else-return": 1, - "no-lonely-if": 1, - "no-negated-condition": 1, - "no-param-reassign": 1, - "no-shadow": 1, - "no-template-curly-in-string": 0, - "no-trailing-spaces": 1, - "no-use-before-define": 1, - "no-useless-escape": 1, - "nonblock-statement-body-position": 1, - "object-curly-spacing": 1, - "prefer-regex-literals": 1, - "quotes": 1, - "space-before-blocks": 1, - "space-before-function-paren": 1, - "space-infix-ops": 1, - "spaced-comment": 1, - "wrap-regex": 1, - }, + "rules": { + "array-bracket-newline": 0, + "array-callback-return": 1, + "brace-style": 1, + "complexity": 0, + "consistent-return": 1, + "curly": 1, + "eqeqeq": 1, + "func-style": 1, + "max-depth": 0, + "max-lines-per-function": 1, + "max-statements": 0, + "multiline-comment-style": 0, + "no-else-return": 1, + "no-lonely-if": 1, + "no-negated-condition": 1, + "no-param-reassign": 1, + "no-shadow": 1, + "no-template-curly-in-string": 0, + "no-use-before-define": 1, + "no-useless-escape": 1, + "nonblock-statement-body-position": 1, + "prefer-regex-literals": 1, + "quotes": 1, + "wrap-regex": 1, + }, - "overrides": [ - { - "files": "example/**", - "rules": { - "no-console": 0, - }, - }, - ], + "overrides": [ + { + "files": "example/**", + "rules": { + "no-console": 0, + }, + }, + ], } diff --git a/example/quote.js b/example/quote.js index 0be7ff2..91c3d20 100644 --- a/example/quote.js +++ b/example/quote.js @@ -1,5 +1,5 @@ 'use strict'; var quote = require('../').quote; -var s = quote([ 'a', 'b c d', '$f', '"g"' ]); +var s = quote(['a', 'b c d', '$f', '"g"']); console.log(s); diff --git a/index.js b/index.js index cc9f57e..ce534c0 100644 --- a/index.js +++ b/index.js @@ -1,26 +1,26 @@ 'use strict'; exports.quote = function (xs) { - return xs.map(function (s) { - if (s && typeof s === 'object') { - return s.op.replace(/(.)/g, '\\$1'); - } - else if (/["\s]/.test(s) && !/'/.test(s)) { - return "'" + s.replace(/(['\\])/g, '\\$1') + "'"; - } - else if (/["'\s]/.test(s)) { - return '"' + s.replace(/(["\\$`!])/g, '\\$1') + '"'; - } - else { - return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g, '$1\\$2'); - } - }).join(' '); + return xs.map(function (s) { + if (s && typeof s === 'object') { + return s.op.replace(/(.)/g, '\\$1'); + } + else if (/["\s]/.test(s) && !/'/.test(s)) { + return "'" + s.replace(/(['\\])/g, '\\$1') + "'"; + } + else if (/["'\s]/.test(s)) { + return '"' + s.replace(/(["\\$`!])/g, '\\$1') + '"'; + } + else { + return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@\[\\\]^`{|}])/g, '$1\\$2'); + } + }).join(' '); }; // '<(' is process substitution operator and // can be parsed the same as control operator var CONTROL = '(?:' + [ - '\\|\\|', '\\&\\&', ';;', '\\|\\&', '\\<\\(', '>>', '>\\&', '[&;()|<>]' + '\\|\\|', '\\&\\&', ';;', '\\|\\&', '\\<\\(', '>>', '>\\&', '[&;()|<>]' ].join('|') + ')'; var META = '|&;()<> \\t'; var BAREWORD = '(\\\\[\'"' + META + ']|[^\\s\'"' + META + '])+'; @@ -29,173 +29,173 @@ var DOUBLE_QUOTE = '\'((\\\\\'|[^\'])*?)\''; var TOKEN = ''; for (var i = 0; i < 4; i++) { - TOKEN += (Math.pow(16,8)*Math.random()).toString(16); + TOKEN += (Math.pow(16, 8) * Math.random()).toString(16); } exports.parse = function (s, env, opts) { - var mapped = parse(s, env, opts); - if (typeof env !== 'function') return mapped; - return mapped.reduce(function (acc, s) { - if (typeof s === 'object') return acc.concat(s); - var xs = s.split(RegExp('(' + TOKEN + '.*?' + TOKEN + ')', 'g')); - if (xs.length === 1) return acc.concat(xs[0]); - return acc.concat(xs.filter(Boolean).map(function (x) { - if (RegExp('^' + TOKEN).test(x)) { - return JSON.parse(x.split(TOKEN)[1]); - } - else return x; - })); - }, []); + var mapped = parse(s, env, opts); + if (typeof env !== 'function') return mapped; + return mapped.reduce(function (acc, s) { + if (typeof s === 'object') return acc.concat(s); + var xs = s.split(RegExp('(' + TOKEN + '.*?' + TOKEN + ')', 'g')); + if (xs.length === 1) return acc.concat(xs[0]); + return acc.concat(xs.filter(Boolean).map(function (x) { + if (RegExp('^' + TOKEN).test(x)) { + return JSON.parse(x.split(TOKEN)[1]); + } + else return x; + })); + }, []); }; -function parse (s, env, opts) { - var chunker = new RegExp([ - '(' + CONTROL + ')', // control chars - '(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')*' - ].join('|'), 'g'); - var match = s.match(chunker).filter(Boolean); - var commented = false; +function parse(s, env, opts) { + var chunker = new RegExp([ + '(' + CONTROL + ')', // control chars + '(' + BAREWORD + '|' + SINGLE_QUOTE + '|' + DOUBLE_QUOTE + ')*' + ].join('|'), 'g'); + var match = s.match(chunker).filter(Boolean); + var commented = false; - if (!match) return []; - if (!env) env = {}; - if (!opts) opts = {}; - return match.map(function (s, j) { - if (commented) { - return; - } - if (RegExp('^' + CONTROL + '$').test(s)) { - return { op: s }; - } + if (!match) return []; + if (!env) env = {}; + if (!opts) opts = {}; + return match.map(function (s, j) { + if (commented) { + return; + } + if (RegExp('^' + CONTROL + '$').test(s)) { + return { op: s }; + } - // Hand-written scanner/parser for Bash quoting rules: - // - // 1. inside single quotes, all characters are printed literally. - // 2. inside double quotes, all characters are printed literally - // except variables prefixed by '$' and backslashes followed by - // either a double quote or another backslash. - // 3. outside of any quotes, backslashes are treated as escape - // characters and not printed (unless they are themselves escaped) - // 4. quote context can switch mid-token if there is no whitespace - // between the two quote contexts (e.g. all'one'"token" parses as - // "allonetoken") - var SQ = "'"; - var DQ = '"'; - var DS = '$'; - var BS = opts.escape || '\\'; - var quote = false; - var esc = false; - var out = ''; - var isGlob = false; + // Hand-written scanner/parser for Bash quoting rules: + // + // 1. inside single quotes, all characters are printed literally. + // 2. inside double quotes, all characters are printed literally + // except variables prefixed by '$' and backslashes followed by + // either a double quote or another backslash. + // 3. outside of any quotes, backslashes are treated as escape + // characters and not printed (unless they are themselves escaped) + // 4. quote context can switch mid-token if there is no whitespace + // between the two quote contexts (e.g. all'one'"token" parses as + // "allonetoken") + var SQ = "'"; + var DQ = '"'; + var DS = '$'; + var BS = opts.escape || '\\'; + var quote = false; + var esc = false; + var out = ''; + var isGlob = false; - for (var i = 0, len = s.length; i < len; i++) { - var c = s.charAt(i); - isGlob = isGlob || (!quote && (c === '*' || c === '?')); - if (esc) { - out += c; - esc = false; - } - else if (quote) { - if (c === quote) { - quote = false; - } - else if (quote == SQ) { - out += c; - } - else { // Double quote - if (c === BS) { - i += 1; - c = s.charAt(i); - if (c === DQ || c === BS || c === DS) { - out += c; - } else { - out += BS + c; - } - } - else if (c === DS) { - out += parseEnvVar(); - } - else { - out += c; - } - } - } - else if (c === DQ || c === SQ) { - quote = c; - } - else if (RegExp('^' + CONTROL + '$').test(c)) { - return { op: s }; - } - else if (RegExp('^#$').test(c)) { - commented = true; - if (out.length){ - return [out, { comment: s.slice(i+1) + match.slice(j+1).join(' ') }]; - } - return [{ comment: s.slice(i+1) + match.slice(j+1).join(' ') }]; - } - else if (c === BS) { - esc = true; - } - else if (c === DS) { - out += parseEnvVar(); - } - else out += c; - } + for (var i = 0, len = s.length; i < len; i++) { + var c = s.charAt(i); + isGlob = isGlob || (!quote && (c === '*' || c === '?')); + if (esc) { + out += c; + esc = false; + } + else if (quote) { + if (c === quote) { + quote = false; + } + else if (quote == SQ) { + out += c; + } + else { // Double quote + if (c === BS) { + i += 1; + c = s.charAt(i); + if (c === DQ || c === BS || c === DS) { + out += c; + } else { + out += BS + c; + } + } + else if (c === DS) { + out += parseEnvVar(); + } + else { + out += c; + } + } + } + else if (c === DQ || c === SQ) { + quote = c; + } + else if (RegExp('^' + CONTROL + '$').test(c)) { + return { op: s }; + } + else if (RegExp('^#$').test(c)) { + commented = true; + if (out.length) { + return [out, { comment: s.slice(i + 1) + match.slice(j + 1).join(' ') }]; + } + return [{ comment: s.slice(i + 1) + match.slice(j + 1).join(' ') }]; + } + else if (c === BS) { + esc = true; + } + else if (c === DS) { + out += parseEnvVar(); + } + else out += c; + } - if (isGlob) return {op: 'glob', pattern: out}; + if (isGlob) return { op: 'glob', pattern: out }; - return out; + return out; - function parseEnvVar() { - i += 1; - var varend, varname; - //debugger - if (s.charAt(i) === '{') { - i += 1; - if (s.charAt(i) === '}') { - throw new Error("Bad substitution: " + s.substr(i - 2, 3)); - } - varend = s.indexOf('}', i); - if (varend < 0) { - throw new Error("Bad substitution: " + s.substr(i)); - } - varname = s.substr(i, varend - i); - i = varend; - } - else if (/[*@#?$!_\-]/.test(s.charAt(i))) { - varname = s.charAt(i); - i += 1; - } - else { - varend = s.substr(i).match(/[^\w\d_]/); - if (!varend) { - varname = s.substr(i); - i = s.length; - } else { - varname = s.substr(i, varend.index); - i += varend.index - 1; - } - } - return getVar(null, '', varname); - } - }) - // finalize parsed aruments - .reduce(function(prev, arg){ - if (arg === undefined){ - return prev; - } - return prev.concat(arg); - },[]); + function parseEnvVar() { + i += 1; + var varend, varname; + // debugger + if (s.charAt(i) === '{') { + i += 1; + if (s.charAt(i) === '}') { + throw new Error("Bad substitution: " + s.substr(i - 2, 3)); + } + varend = s.indexOf('}', i); + if (varend < 0) { + throw new Error("Bad substitution: " + s.substr(i)); + } + varname = s.substr(i, varend - i); + i = varend; + } + else if (/[*@#?$!_\-]/.test(s.charAt(i))) { + varname = s.charAt(i); + i += 1; + } + else { + varend = s.substr(i).match(/[^\w\d_]/); + if (!varend) { + varname = s.substr(i); + i = s.length; + } else { + varname = s.substr(i, varend.index); + i += varend.index - 1; + } + } + return getVar(null, '', varname); + } + }) + // finalize parsed aruments + .reduce(function (prev, arg) { + if (arg === undefined) { + return prev; + } + return prev.concat(arg); + }, []); - function getVar (_, pre, key) { - var r = typeof env === 'function' ? env(key) : env[key]; - if (r === undefined && key != '') - r = ''; - else if (r === undefined) - r = '$'; + 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; - } - else return pre + r; - } + if (typeof r === 'object') { + return pre + TOKEN + JSON.stringify(r) + TOKEN; + } + else return pre + r; + } } diff --git a/package.json b/package.json index 7892075..ce06e56 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,37 @@ { - "name": "shell-quote", - "description": "quote and parse shell commands", - "version": "1.7.3", - "author": { - "name": "James Halliday", - "email": "mail@substack.net", - "url": "http://substack.net" - }, - "bugs": "https://github.com/substack/node-shell-quote/issues", - "devDependencies": { - "@ljharb/eslint-config": "^21.0.0", - "aud": "^2.0.1", - "eslint": "=8.8.0", - "tape": "^5.6.1" - }, - "homepage": "https://github.com/substack/node-shell-quote", - "keywords": [ - "command", - "parse", - "quote", - "shell" - ], - "license": "MIT", - "main": "index.js", - "repository": { - "type": "git", - "url": "http://github.com/substack/node-shell-quote.git" - }, - "scripts": { - "lint": "eslint --ext=js,mjs .", - "pretest": "npm run lint", - "tests-only": "tape 'test/**/*.js'", - "test": "npm run tests-only", - "posttest": "aud --production" - } + "name": "shell-quote", + "description": "quote and parse shell commands", + "version": "1.7.3", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "bugs": "https://github.com/substack/node-shell-quote/issues", + "devDependencies": { + "@ljharb/eslint-config": "^21.0.0", + "aud": "^2.0.1", + "eslint": "=8.8.0", + "tape": "^5.6.1" + }, + "homepage": "https://github.com/substack/node-shell-quote", + "keywords": [ + "command", + "parse", + "quote", + "shell" + ], + "license": "MIT", + "main": "index.js", + "repository": { + "type": "git", + "url": "http://github.com/substack/node-shell-quote.git" + }, + "scripts": { + "lint": "eslint --ext=js,mjs .", + "pretest": "npm run lint", + "tests-only": "tape 'test/**/*.js'", + "test": "npm run tests-only", + "posttest": "aud --production" + } } diff --git a/test/comment.js b/test/comment.js index f81d753..076ee35 100644 --- a/test/comment.js +++ b/test/comment.js @@ -4,13 +4,13 @@ var test = require('tape'); var parse = require('../').parse; test('comment', function (t) { - 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.end(); + 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.end(); }); diff --git a/test/env.js b/test/env.js index b19b58e..7b48b88 100644 --- a/test/env.js +++ b/test/env.js @@ -4,40 +4,40 @@ var test = require('tape'); var parse = require('../').parse; test('expand environment variables', function (t) { - t.same(parse('a $XYZ c', { XYZ: 'b' }), [ 'a', 'b', 'c' ]); - t.same(parse('a${XYZ}c', { XYZ: 'b' }), [ 'abc' ]); - t.same(parse('a${XYZ}c $XYZ', { XYZ: 'b' }), [ 'abc', 'b' ]); - t.same(parse('"-$X-$Y-"', { X: 'a', Y: 'b' }), [ '-a-b-' ]); - t.same(parse("'-$X-$Y-'", { X: 'a', Y: 'b' }), [ '-$X-$Y-' ]); - t.same(parse('qrs"$zzz"wxy', { zzz: 'tuv' }), [ 'qrstuvwxy' ]); - t.same(parse("qrs'$zzz'wxy", { zzz: 'tuv' }), [ 'qrs$zzzwxy' ]); - t.same(parse("qrs${zzz}wxy"), [ 'qrswxy' ]); - t.same(parse("qrs$wxy $"), [ 'qrs', '$' ]); - t.same(parse('grep "xy$"'), [ 'grep', 'xy$' ]); - t.same(parse("ab$x", { x: 'c' }), [ 'abc' ]); - t.same(parse("ab\\$x", { x: 'c' }), [ 'ab$x' ]); - t.same(parse("ab${x}def", { x: 'c' }), [ 'abcdef' ]); - t.same(parse("ab\\${x}def", { x: 'c' }), [ 'ab${x}def' ]); - t.same(parse('"ab\\${x}def"', { x: 'c' }), [ 'ab${x}def' ]); + t.same(parse('a $XYZ c', { XYZ: 'b' }), ['a', 'b', 'c']); + t.same(parse('a${XYZ}c', { XYZ: 'b' }), ['abc']); + t.same(parse('a${XYZ}c $XYZ', { XYZ: 'b' }), ['abc', 'b']); + t.same(parse('"-$X-$Y-"', { X: 'a', Y: 'b' }), ['-a-b-']); + t.same(parse("'-$X-$Y-'", { X: 'a', Y: 'b' }), ['-$X-$Y-']); + t.same(parse('qrs"$zzz"wxy', { zzz: 'tuv' }), ['qrstuvwxy']); + t.same(parse("qrs'$zzz'wxy", { zzz: 'tuv' }), ['qrs$zzzwxy']); + t.same(parse("qrs${zzz}wxy"), ['qrswxy']); + t.same(parse("qrs$wxy $"), ['qrs', '$']); + t.same(parse('grep "xy$"'), ['grep', 'xy$']); + t.same(parse("ab$x", { x: 'c' }), ['abc']); + t.same(parse("ab\\$x", { x: 'c' }), ['ab$x']); + t.same(parse("ab${x}def", { x: 'c' }), ['abcdef']); + t.same(parse("ab\\${x}def", { x: 'c' }), ['ab${x}def']); + t.same(parse('"ab\\${x}def"', { x: 'c' }), ['ab${x}def']); - t.end(); + t.end(); }); test('environment variables with metacharacters', function (t) { - t.same(parse('a $XYZ c', { XYZ: '"b"' }), [ 'a', '"b"', 'c' ]); - t.same(parse('a $XYZ c', { XYZ: '$X', X: 5 }), [ 'a', '$X', 'c' ]); - t.same(parse('a"$XYZ"c', { XYZ: "'xyz'" }), [ "a'xyz'c" ]); + t.same(parse('a $XYZ c', { XYZ: '"b"' }), ['a', '"b"', 'c']); + t.same(parse('a $XYZ c', { XYZ: '$X', X: 5 }), ['a', '$X', 'c']); + t.same(parse('a"$XYZ"c', { XYZ: "'xyz'" }), ["a'xyz'c"]); - t.end(); + t.end(); }); test('special shell parameters', function (t) { - var chars = '*@#?-$!0_'.split(''); - t.plan(chars.length); + var chars = '*@#?-$!0_'.split(''); + t.plan(chars.length); - chars.forEach(function (c) { - var env = {}; - env[c] = 'xxx'; - t.same(parse('a $' + c + ' c', env), [ 'a', 'xxx', 'c' ]); - }); + chars.forEach(function (c) { + var env = {}; + env[c] = 'xxx'; + t.same(parse('a $' + c + ' c', env), ['a', 'xxx', 'c']); + }); }); diff --git a/test/env_fn.js b/test/env_fn.js index c83c653..dd46980 100644 --- a/test/env_fn.js +++ b/test/env_fn.js @@ -4,18 +4,18 @@ var test = require('tape'); var parse = require('../').parse; test('functional env expansion', function (t) { - t.plan(4); + t.plan(4); - t.same(parse('a $XYZ c', getEnv), [ 'a', 'xxx', 'c' ]); - t.same(parse('a $XYZ c', getEnvObj), [ 'a', { op: '@@' }, 'c' ]); - t.same(parse('a${XYZ}c', getEnvObj), [ 'a', { op: '@@' }, 'c' ]); - t.same(parse('"a $XYZ c"', getEnvObj), [ 'a ', { op: '@@' }, ' c' ]); + t.same(parse('a $XYZ c', getEnv), ['a', 'xxx', 'c']); + t.same(parse('a $XYZ c', getEnvObj), ['a', { op: '@@' }, 'c']); + t.same(parse('a${XYZ}c', getEnvObj), ['a', { op: '@@' }, 'c']); + t.same(parse('"a $XYZ c"', getEnvObj), ['a ', { op: '@@' }, ' c']); - function getEnv() { - return 'xxx'; - } + function getEnv() { + return 'xxx'; + } - function getEnvObj() { - return { op: '@@' }; - } + function getEnvObj() { + return { op: '@@' }; + } }); diff --git a/test/op.js b/test/op.js index 91263cc..5fdce9e 100644 --- a/test/op.js +++ b/test/op.js @@ -4,77 +4,77 @@ var test = require('tape'); var parse = require('../').parse; test('single operators', function (t) { - t.same(parse('beep | boop'), [ 'beep', { op: '|' }, 'boop' ]); - t.same(parse('beep|boop'), [ 'beep', { op: '|' }, 'boop' ]); - t.same(parse('beep \\| boop'), [ 'beep', '|', 'boop' ]); - t.same(parse('beep "|boop"'), [ 'beep', '|boop' ]); + t.same(parse('beep | boop'), ['beep', { op: '|' }, 'boop']); + t.same(parse('beep|boop'), ['beep', { op: '|' }, 'boop']); + t.same(parse('beep \\| boop'), ['beep', '|', 'boop']); + t.same(parse('beep "|boop"'), ['beep', '|boop']); - t.same(parse('echo zing &'), [ 'echo', 'zing', { op: '&' } ]); - t.same(parse('echo zing&'), [ 'echo', 'zing', { op: '&' } ]); - t.same(parse('echo zing\\&'), [ 'echo', 'zing&' ]); - t.same(parse('echo "zing\\&"'), [ 'echo', 'zing\\&' ]); + t.same(parse('echo zing &'), ['echo', 'zing', { op: '&' }]); + t.same(parse('echo zing&'), ['echo', 'zing', { op: '&' }]); + t.same(parse('echo zing\\&'), ['echo', 'zing&']); + t.same(parse('echo "zing\\&"'), ['echo', 'zing\\&']); - t.same(parse('beep;boop'), [ 'beep', { op: ';' }, 'boop' ]); - t.same(parse('(beep;boop)'), [ - { op: '(' }, 'beep', { op: ';' }, 'boop', { op: ')' } - ]); + t.same(parse('beep;boop'), ['beep', { op: ';' }, 'boop']); + t.same(parse('(beep;boop)'), [ + { op: '(' }, 'beep', { op: ';' }, 'boop', { op: ')' } + ]); - t.same(parse('beep>boop'), [ 'beep', { op: '>' }, 'boop' ]); - t.same(parse('beep 2>boop'), [ 'beep', '2', { op: '>' }, 'boop' ]); - t.same(parse('beepboop'), ['beep', { op: '>' }, 'boop']); + t.same(parse('beep 2>boop'), ['beep', '2', { op: '>' }, 'boop']); + t.same(parse('beep>blip'), - [ 'beep', { op: ';;' }, 'boop', { op: '|&' }, 'byte', { op: '>>' }, 'blip' ] - ); + t.same(parse('beep && boop'), ['beep', { op: '&&' }, 'boop']); + t.same( + parse('beep && boop || byte'), + ['beep', { op: '&&' }, 'boop', { op: '||' }, 'byte'] + ); + t.same( + parse('beep&&boop||byte'), + ['beep', { op: '&&' }, 'boop', { op: '||' }, 'byte'] + ); + t.same( + parse('beep\\&\\&boop||byte'), + ['beep&&boop', { op: '||' }, 'byte'] + ); + t.same( + parse('beep\\&&boop||byte'), + ['beep&', { op: '&' }, 'boop', { op: '||' }, 'byte'] + ); + t.same( + parse('beep;;boop|&byte>>blip'), + ['beep', { op: ';;' }, 'boop', { op: '|&' }, 'byte', { op: '>>' }, 'blip'] + ); - t.same(parse('beep 2>&1'), [ 'beep', '2', { op: '>&' }, '1' ]); + t.same(parse('beep 2>&1'), ['beep', '2', { op: '>&' }, '1']); - t.same( - parse('beep<(boop)'), - [ 'beep', { op: '<(' }, 'boop', { op: ')' } ] - ); - t.same( - parse('beep<<(boop)'), - [ 'beep', { op: '<' }, { op: '<(' }, 'boop', { op: ')' } ] - ); + t.same( + parse('beep<(boop)'), + ['beep', { op: '<(' }, 'boop', { op: ')' }] + ); + t.same( + parse('beep<<(boop)'), + ['beep', { op: '<' }, { op: '<(' }, 'boop', { op: ')' }] + ); - t.end(); + t.end(); }); test('glob patterns', function (t) { - t.same( - parse('tap test/*.test.js'), - [ 'tap', { op: 'glob', pattern: 'test/*.test.js' } ] - ); + t.same( + parse('tap test/*.test.js'), + ['tap', { op: 'glob', pattern: 'test/*.test.js' }] + ); - t.same(parse('tap "test/*.test.js"'), ['tap', 'test/*.test.js']); - t.end(); + t.same(parse('tap "test/*.test.js"'), ['tap', 'test/*.test.js']); + t.end(); }); diff --git a/test/parse.js b/test/parse.js index 27cf542..7373181 100644 --- a/test/parse.js +++ b/test/parse.js @@ -4,22 +4,22 @@ var test = require('tape'); var parse = require('../').parse; test('parse shell commands', function (t) { - t.same(parse('a \'b\' "c"'), [ 'a', 'b', 'c' ]); - t.same( - parse('beep "boop" \'foo bar baz\' "it\'s \\"so\\" groovy"'), - [ 'beep', 'boop', 'foo bar baz', 'it\'s "so" groovy' ] - ); - t.same(parse('a b\\ c d'), [ 'a', 'b c', 'd' ]); - t.same(parse('\\$beep bo\\`op'), [ '$beep', 'bo`op' ]); - t.same(parse('echo "foo = \\"foo\\""'), [ 'echo', 'foo = "foo"' ]); - t.same(parse(''), []); - t.same(parse(' '), []); - t.same(parse("\t"), []); - t.same(parse('a"b c d"e'), [ 'ab c de' ]); - t.same(parse('a\\ b"c d"\\ e f'), [ 'a bc d e', 'f' ]); - t.same(parse('a\\ b"c d"\\ e\'f g\' h'), [ 'a bc d ef g', 'h' ]); - t.same(parse("x \"bl'a\"'h'"), ['x', "bl'ah"]); - t.same(parse("x bl^'a^'h'", {}, { escape: '^'}), ['x', "bl'a'h"]); + t.same(parse('a \'b\' "c"'), ['a', 'b', 'c']); + t.same( + parse('beep "boop" \'foo bar baz\' "it\'s \\"so\\" groovy"'), + ['beep', 'boop', 'foo bar baz', 'it\'s "so" groovy'] + ); + t.same(parse('a b\\ c d'), ['a', 'b c', 'd']); + t.same(parse('\\$beep bo\\`op'), ['$beep', 'bo`op']); + t.same(parse('echo "foo = \\"foo\\""'), ['echo', 'foo = "foo"']); + t.same(parse(''), []); + t.same(parse(' '), []); + t.same(parse("\t"), []); + t.same(parse('a"b c d"e'), ['ab c de']); + t.same(parse('a\\ b"c d"\\ e f'), ['a bc d e', 'f']); + t.same(parse('a\\ b"c d"\\ e\'f g\' h'), ['a bc d ef g', 'h']); + t.same(parse("x \"bl'a\"'h'"), ['x', "bl'ah"]); + t.same(parse("x bl^'a^'h'", {}, { escape: '^' }), ['x', "bl'a'h"]); - t.end(); + t.end(); }); diff --git a/test/quote.js b/test/quote.js index d0e8151..d972077 100644 --- a/test/quote.js +++ b/test/quote.js @@ -4,47 +4,47 @@ var test = require('tape'); var quote = require('../').quote; test('quote', function (t) { - t.equal(quote([ 'a', 'b', 'c d' ]), 'a b \'c d\''); - t.equal( - quote([ 'a', 'b', "it's a \"neat thing\"" ]), - 'a b "it\'s a \\"neat thing\\""' - ); - t.equal( - quote([ '$', '`', '\'' ]), - '\\$ \\` "\'"' - ); - t.equal(quote([]), ''); - t.equal(quote(["a\nb"]), "'a\nb'"); - t.equal(quote([' #(){}*|][!']), "' #(){}*|][!'"); - t.equal(quote(["'#(){}*|][!"]), '"\'#(){}*|][\\!"'); - t.equal(quote(["X#(){}*|][!"]), "X\\#\\(\\)\\{\\}\\*\\|\\]\\[\\!"); - t.equal(quote(["a\n#\nb"]), "'a\n#\nb'"); - t.equal(quote(['><;{}']), '\\>\\<\\;\\{\\}'); - t.equal(quote([ 'a', 1, true, false ]), 'a 1 true false'); - t.equal(quote([ 'a', 1, null, undefined ]), 'a 1 null undefined'); - t.equal(quote([ 'a\\x' ]), 'a\\\\x'); - t.end(); + t.equal(quote(['a', 'b', 'c d']), 'a b \'c d\''); + t.equal( + quote(['a', 'b', "it's a \"neat thing\""]), + 'a b "it\'s a \\"neat thing\\""' + ); + t.equal( + quote(['$', '`', '\'']), + '\\$ \\` "\'"' + ); + t.equal(quote([]), ''); + t.equal(quote(["a\nb"]), "'a\nb'"); + t.equal(quote([' #(){}*|][!']), "' #(){}*|][!'"); + t.equal(quote(["'#(){}*|][!"]), '"\'#(){}*|][\\!"'); + t.equal(quote(["X#(){}*|][!"]), "X\\#\\(\\)\\{\\}\\*\\|\\]\\[\\!"); + t.equal(quote(["a\n#\nb"]), "'a\n#\nb'"); + t.equal(quote(['><;{}']), '\\>\\<\\;\\{\\}'); + t.equal(quote(['a', 1, true, false]), 'a 1 true false'); + t.equal(quote(['a', 1, null, undefined]), 'a 1 null undefined'); + t.equal(quote(['a\\x']), 'a\\\\x'); + t.end(); }); test('quote ops', function (t) { - t.equal(quote([ 'a', { op: '|' }, 'b' ]), 'a \\| b'); - t.equal( - quote([ 'a', { op: '&&' }, 'b', { op: ';' }, 'c' ]), - 'a \\&\\& b \\; c' - ); - t.end(); + t.equal(quote(['a', { op: '|' }, 'b']), 'a \\| b'); + t.equal( + quote(['a', { op: '&&' }, 'b', { op: ';' }, 'c']), + 'a \\&\\& b \\; c' + ); + t.end(); }); test('quote windows paths', { skip: 'breaking change, disabled until 2.x' }, function (t) { - var path = 'C:\\projects\\node-shell-quote\\index.js'; + var path = 'C:\\projects\\node-shell-quote\\index.js'; - t.equal(quote([path, 'b', 'c d']), 'C:\\projects\\node-shell-quote\\index.js b \'c d\''); + t.equal(quote([path, 'b', 'c d']), 'C:\\projects\\node-shell-quote\\index.js b \'c d\''); - t.end(); + t.end(); }); test("chars for windows paths don't break out", function (t) { - var x = '`:\\a\\b'; - t.equal(quote([x]), '\\`\\:\\\\a\\\\b'); - t.end(); + var x = '`:\\a\\b'; + t.equal(quote([x]), '\\`\\:\\\\a\\\\b'); + t.end(); }); diff --git a/test/set.js b/test/set.js index ad8d938..9694538 100644 --- a/test/set.js +++ b/test/set.js @@ -4,28 +4,28 @@ var test = require('tape'); var parse = require('../').parse; test('set env vars', function (t) { - t.same( - parse('ABC=444 x y z'), - [ 'ABC=444', 'x', 'y', 'z' ] - ); - t.same( - parse('ABC=3\\ 4\\ 5 x y z'), - [ 'ABC=3 4 5', 'x', 'y', 'z' ] - ); - t.same( - parse('X="7 8 9" printx'), - [ 'X=7 8 9', 'printx' ] - ); - t.same( - parse('X="7 8 9"; printx'), - [ 'X=7 8 9', { op: ';' }, 'printx' ] - ); - t.same( - parse('X="7 8 9"; printx', function () { - t.fail('should not have matched any keys'); - }), - [ 'X=7 8 9', { op: ';' }, 'printx' ] - ); + t.same( + parse('ABC=444 x y z'), + ['ABC=444', 'x', 'y', 'z'] + ); + t.same( + parse('ABC=3\\ 4\\ 5 x y z'), + ['ABC=3 4 5', 'x', 'y', 'z'] + ); + t.same( + parse('X="7 8 9" printx'), + ['X=7 8 9', 'printx'] + ); + t.same( + parse('X="7 8 9"; printx'), + ['X=7 8 9', { op: ';' }, 'printx'] + ); + t.same( + parse('X="7 8 9"; printx', function () { + t.fail('should not have matched any keys'); + }), + ['X=7 8 9', { op: ';' }, 'printx'] + ); - t.end(); + t.end(); });