diff options
Diffstat (limited to 'node_modules/shell-quote')
| -rw-r--r-- | node_modules/shell-quote/.eslintrc | 30 | ||||
| -rw-r--r-- | node_modules/shell-quote/.github/FUNDING.yml | 12 | ||||
| -rw-r--r-- | node_modules/shell-quote/.nycrc | 14 | ||||
| -rw-r--r-- | node_modules/shell-quote/LICENSE | 24 | ||||
| -rw-r--r-- | node_modules/shell-quote/README.md | 161 | ||||
| -rw-r--r-- | node_modules/shell-quote/index.js | 4 | ||||
| -rw-r--r-- | node_modules/shell-quote/package.json | 72 | ||||
| -rw-r--r-- | node_modules/shell-quote/parse.js | 226 | ||||
| -rwxr-xr-x | node_modules/shell-quote/print.py | 3 | ||||
| -rw-r--r-- | node_modules/shell-quote/quote.js | 19 | ||||
| -rw-r--r-- | node_modules/shell-quote/security.md | 11 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/comment.js | 16 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/env.js | 52 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/env_fn.js | 21 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/op.js | 102 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/parse.js | 44 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/quote.js | 60 | ||||
| -rw-r--r-- | node_modules/shell-quote/test/set.js | 31 |
18 files changed, 902 insertions, 0 deletions
diff --git a/node_modules/shell-quote/.eslintrc b/node_modules/shell-quote/.eslintrc new file mode 100644 index 0000000..9569d51 --- /dev/null +++ b/node_modules/shell-quote/.eslintrc @@ -0,0 +1,30 @@ +{ + "root": true, + + "extends": "@ljharb", + + "rules": { + "array-bracket-newline": 0, + "complexity": 0, + "eqeqeq": 1, + "func-style": [2, "declaration"], + "max-depth": 0, + "max-lines-per-function": 0, + "max-statements": 0, + "multiline-comment-style": 0, + "no-negated-condition": 1, + "no-param-reassign": 1, + "no-lonely-if": 1, + "no-shadow": 1, + "no-template-curly-in-string": 0, + }, + + "overrides": [ + { + "files": "example/**", + "rules": { + "no-console": 0, + }, + }, + ], +} diff --git a/node_modules/shell-quote/.github/FUNDING.yml b/node_modules/shell-quote/.github/FUNDING.yml new file mode 100644 index 0000000..0b6b6b4 --- /dev/null +++ b/node_modules/shell-quote/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: [ljharb] +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: npm/shell-quote +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] diff --git a/node_modules/shell-quote/.nycrc b/node_modules/shell-quote/.nycrc new file mode 100644 index 0000000..55c3d29 --- /dev/null +++ b/node_modules/shell-quote/.nycrc @@ -0,0 +1,14 @@ +{ + "all": true, + "check-coverage": false, + "reporter": ["text-summary", "text", "html", "json"], + "lines": 86, + "statements": 85.93, + "functions": 82.43, + "branches": 76.06, + "exclude": [ + "coverage", + "example", + "test" + ] +} diff --git a/node_modules/shell-quote/LICENSE b/node_modules/shell-quote/LICENSE new file mode 100644 index 0000000..3d59c73 --- /dev/null +++ b/node_modules/shell-quote/LICENSE @@ -0,0 +1,24 @@ +The MIT License + +Copyright (c) 2013 James Halliday (mail@substack.net) + +Permission is hereby granted, free of charge, +to any person obtaining a copy of this software and +associated documentation files (the "Software"), to +deal in the Software without restriction, including +without limitation the rights to use, copy, modify, +merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom +the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR +ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/node_modules/shell-quote/README.md b/node_modules/shell-quote/README.md new file mode 100644 index 0000000..6b545c5 --- /dev/null +++ b/node_modules/shell-quote/README.md @@ -0,0 +1,161 @@ +# shell-quote <sup>[![Version Badge][npm-version-svg]][package-url]</sup> + +[![github actions][actions-image]][actions-url] +[![coverage][codecov-image]][codecov-url] +[![License][license-image]][license-url] +[![Downloads][downloads-image]][downloads-url] + +[![npm badge][npm-badge-png]][package-url] + +Parse and quote shell commands. + +# example + +## quote + +``` js +var quote = require('shell-quote/quote'); +var s = quote([ 'a', 'b c d', '$f', '"g"' ]); +console.log(s); +``` + +output + +``` +a 'b c d' \$f '"g"' +``` + +## parse + +``` js +var parse = require('shell-quote/parse'); +var xs = parse('a "b c" \\$def \'it\\\'s great\''); +console.dir(xs); +``` + +output + +``` +[ 'a', 'b c', '\\$def', 'it\'s great' ] +``` + +## parse with an environment variable + +``` js +var parse = require('shell-quote/parse'); +var xs = parse('beep --boop="$PWD"', { PWD: '/home/robot' }); +console.dir(xs); +``` + +output + +``` +[ 'beep', '--boop=/home/robot' ] +``` + +## parse with custom escape character + +``` js +var parse = require('shell-quote/parse'); +var xs = parse('beep ^--boop="$PWD"', { PWD: '/home/robot' }, { escape: '^' }); +console.dir(xs); +``` + +output + +``` +[ 'beep --boop=/home/robot' ] +``` + +## parsing shell operators + +``` js +var parse = require('shell-quote/parse'); +var xs = parse('beep || boop > /byte'); +console.dir(xs); +``` + +output: + +``` +[ 'beep', { op: '||' }, 'boop', { op: '>' }, '/byte' ] +``` + +## parsing shell comment + +``` js +var parse = require('shell-quote/parse'); +var xs = parse('beep > boop # > kaboom'); +console.dir(xs); +``` + +output: + +``` +[ 'beep', { op: '>' }, 'boop', { comment: '> kaboom' } ] +``` + +# methods + +``` js +var quote = require('shell-quote/quote'); +var parse = require('shell-quote/parse'); +``` + +## quote(args) + +Return a quoted string for the array `args` suitable for using in shell +commands. + +## parse(cmd, env={}) + +Return an array of arguments from the quoted string `cmd`. + +Interpolate embedded bash-style `$VARNAME` and `${VARNAME}` variables with +the `env` object which like bash will replace undefined variables with `""`. + +`env` is usually an object but it can also be a function to perform lookups. +When `env(key)` returns a string, its result will be output just like `env[key]` +would. When `env(key)` returns an object, it will be inserted into the result +array like the operator objects. + +When a bash operator is encountered, the element in the array with be an object +with an `"op"` key set to the operator string. For example: + +``` +'beep || boop > /byte' +``` + +parses as: + +``` +[ 'beep', { op: '||' }, 'boop', { op: '>' }, '/byte' ] +``` + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install shell-quote +``` + +# license + +MIT + +[package-url]: https://npmjs.org/package/shell-quote +[npm-version-svg]: https://versionbadg.es/ljharb/shell-quote.svg +[deps-svg]: https://david-dm.org/ljharb/shell-quote.svg +[deps-url]: https://david-dm.org/ljharb/shell-quote +[dev-deps-svg]: https://david-dm.org/ljharb/shell-quote/dev-status.svg +[dev-deps-url]: https://david-dm.org/ljharb/shell-quote#info=devDependencies +[npm-badge-png]: https://nodei.co/npm/shell-quote.png?downloads=true&stars=true +[license-image]: https://img.shields.io/npm/l/shell-quote.svg +[license-url]: LICENSE +[downloads-image]: https://img.shields.io/npm/dm/shell-quote.svg +[downloads-url]: https://npm-stat.com/charts.html?package=shell-quote +[codecov-image]: https://codecov.io/gh/ljharb/shell-quote/branch/main/graphs/badge.svg +[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-url]: https://github.com/ljharb/shell-quote/actions diff --git a/node_modules/shell-quote/index.js b/node_modules/shell-quote/index.js new file mode 100644 index 0000000..28fb42d --- /dev/null +++ b/node_modules/shell-quote/index.js @@ -0,0 +1,4 @@ +'use strict'; + +exports.quote = require('./quote'); +exports.parse = require('./parse'); diff --git a/node_modules/shell-quote/package.json b/node_modules/shell-quote/package.json new file mode 100644 index 0000000..b9bafdc --- /dev/null +++ b/node_modules/shell-quote/package.json @@ -0,0 +1,72 @@ +{ + "name": "shell-quote", + "description": "quote and parse shell commands", + "version": "1.8.3", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + }, + "bugs": "https://github.com/ljharb/shell-quote/issues", + "devDependencies": { + "@ljharb/eslint-config": "^21.1.1", + "auto-changelog": "^2.5.0", + "encoding": "^0.1.13", + "eslint": "=8.8.0", + "evalmd": "^0.0.19", + "in-publish": "^2.0.1", + "jackspeak": "=2.1.1", + "npmignore": "^0.3.1", + "nyc": "^10.3.2", + "safe-publish-latest": "^2.0.0", + "tape": "^5.9.0" + }, + "homepage": "https://github.com/ljharb/shell-quote", + "keywords": [ + "command", + "parse", + "quote", + "shell" + ], + "license": "MIT", + "main": "index.js", + "repository": { + "type": "git", + "url": "http://github.com/ljharb/shell-quote.git" + }, + "scripts": { + "prepack": "npmignore --auto --commentLines=autogenerated", + "prepublish": "not-in-publish || npm run prepublishOnly", + "prepublishOnly": "safe-publish-latest", + "prelint": "evalmd README.md", + "lint": "eslint --ext=js,mjs .", + "pretest": "npm run lint", + "tests-only": "nyc tape 'test/**/*.js'", + "test": "npm run tests-only", + "posttest": "npx npm@'>=10.2' audit --production", + "version": "auto-changelog && git add CHANGELOG.md", + "postversion": "auto-changelog && git add CHANGELOG.md && git commit --no-edit --amend && git tag -f \"v$(node -e \"console.log(require('./package.json').version)\")\"" + }, + "auto-changelog": { + "output": "CHANGELOG.md", + "template": "keepachangelog", + "unreleased": false, + "commitLimit": false, + "backfillLimit": false, + "hideCredit": true, + "startingVersion": "1.7.4" + }, + "publishConfig": { + "ignore": [ + ".github/workflows", + "example", + "CHANGELOG.md" + ] + }, + "engines": { + "node": ">= 0.4" + } +} diff --git a/node_modules/shell-quote/parse.js b/node_modules/shell-quote/parse.js new file mode 100644 index 0000000..71d2eea --- /dev/null +++ b/node_modules/shell-quote/parse.js @@ -0,0 +1,226 @@ +'use strict'; + +// '<(' is process substitution operator and +// can be parsed the same as control operator +var CONTROL = '(?:' + [ + '\\|\\|', + '\\&\\&', + ';;', + '\\|\\&', + '\\<\\(', + '\\<\\<\\<', + '>>', + '>\\&', + '<\\&', + '[&;()|<>]' +].join('|') + ')'; +var controlRE = new RegExp('^' + CONTROL + '$'); +var META = '|&;()<> \\t'; +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 += (mult * Math.random()).toString(16); +} +var startsWithToken = new RegExp('^' + TOKEN); + +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 + ')+' + ].join('|'), 'g'); + + var matches = matchAll(string, chunker); + + if (matches.length === 0) { + return []; + } + if (!env) { + env = {}; + } + + var commented = false; + + return matches.map(function (match) { + var s = match[0]; + if (!s || commented) { + return void undefined; + } + if (controlRE.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 quote = false; + var esc = false; + var out = ''; + var isGlob = false; + var i; + + function parseEnvVar() { + i += 1; + var varend; + var varname; + var char = s.charAt(i); + + if (char === '{') { + i += 1; + if (s.charAt(i) === '}') { + throw new Error('Bad substitution: ' + s.slice(i - 2, i + 1)); + } + varend = s.indexOf('}', i); + if (varend < 0) { + throw new Error('Bad substitution: ' + s.slice(i)); + } + varname = s.slice(i, varend); + i = varend; + } else if ((/[*@#?$!_-]/).test(char)) { + varname = char; + i += 1; + } else { + var slicedFromI = s.slice(i); + varend = slicedFromI.match(/[^\w\d_]/); + if (!varend) { + varname = slicedFromI; + i = s.length; + } else { + varname = slicedFromI.slice(0, varend.index); + i += varend.index - 1; + } + } + return getVar(env, '', varname); + } + + for (i = 0; i < s.length; 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 (controlRE.test(c)) { + return { op: s }; + } else if (hash.test(c)) { + commented = true; + var commentObj = { comment: string.slice(match.index + i + 1) }; + if (out.length) { + return [out, commentObj]; + } + return [commentObj]; + } else if (c === BS) { + esc = true; + } else if (c === DS) { + out += parseEnvVar(); + } else { + out += c; + } + } + + if (isGlob) { + return { op: 'glob', pattern: out }; + } + + return out; + }).reduce(function (prev, arg) { // finalize parsed arguments + // TODO: replace this whole reduce with a concat + return typeof arg === 'undefined' ? prev : prev.concat(arg); + }, []); +} + +module.exports = function parse(s, env, opts) { + var mapped = parseInternal(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 (startsWithToken.test(x)) { + return JSON.parse(x.split(TOKEN)[1]); + } + return x; + })); + }, []); +}; diff --git a/node_modules/shell-quote/print.py b/node_modules/shell-quote/print.py new file mode 100755 index 0000000..dc8e868 --- /dev/null +++ b/node_modules/shell-quote/print.py @@ -0,0 +1,3 @@ +#!/usr/bin/env python3 +import sys +print(sys.argv[1]) diff --git a/node_modules/shell-quote/quote.js b/node_modules/shell-quote/quote.js new file mode 100644 index 0000000..5152aed --- /dev/null +++ b/node_modules/shell-quote/quote.js @@ -0,0 +1,19 @@ +'use strict'; + +module.exports = function quote(xs) { + return xs.map(function (s) { + if (s === '') { + return '\'\''; + } + if (s && typeof s === 'object') { + return s.op.replace(/(.)/g, '\\$1'); + } + if ((/["\s\\]/).test(s) && !(/'/).test(s)) { + return "'" + s.replace(/(['])/g, '\\$1') + "'"; + } + if ((/["'\s]/).test(s)) { + return '"' + s.replace(/(["\\$`!])/g, '\\$1') + '"'; + } + return String(s).replace(/([A-Za-z]:)?([#!"$&'()*,:;<=>?@[\\\]^`{|}])/g, '$1\\$2'); + }).join(' '); +}; diff --git a/node_modules/shell-quote/security.md b/node_modules/shell-quote/security.md new file mode 100644 index 0000000..dc86413 --- /dev/null +++ b/node_modules/shell-quote/security.md @@ -0,0 +1,11 @@ +# Security Policy + +## Supported Versions + +Only the latest major version is supported at any given time. + +## Reporting a Vulnerability + +To report a security vulnerability, please use the +[Tidelift security contact](https://tidelift.com/security). +Tidelift will coordinate the fix and disclosure. diff --git a/node_modules/shell-quote/test/comment.js b/node_modules/shell-quote/test/comment.js new file mode 100644 index 0000000..fb15d5c --- /dev/null +++ b/node_modules/shell-quote/test/comment.js @@ -0,0 +1,16 @@ +'use strict'; + +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(); +}); diff --git a/node_modules/shell-quote/test/env.js b/node_modules/shell-quote/test/env.js new file mode 100644 index 0000000..4cc0a51 --- /dev/null +++ b/node_modules/shell-quote/test/env.js @@ -0,0 +1,52 @@ +'use strict'; + +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.end(); +}); + +test('expand environment variables within here-strings', function (t) { + t.same(parse('a <<< $x', { x: 'Joe' }), ['a', { op: '<<<' }, 'Joe']); + t.same(parse('a <<< ${x}', { x: 'Joe' }), ['a', { op: '<<<' }, 'Joe']); + t.same(parse('a <<< "$x"', { x: 'Joe' }), ['a', { op: '<<<' }, 'Joe']); + t.same(parse('a <<< "${x}"', { x: 'Joe' }), ['a', { op: '<<<' }, 'Joe']); + + 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.end(); +}); + +test('special shell parameters', function (t) { + 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']); + }); +}); diff --git a/node_modules/shell-quote/test/env_fn.js b/node_modules/shell-quote/test/env_fn.js new file mode 100644 index 0000000..968e912 --- /dev/null +++ b/node_modules/shell-quote/test/env_fn.js @@ -0,0 +1,21 @@ +'use strict'; + +var test = require('tape'); +var parse = require('../').parse; + +function getEnv() { + return 'xxx'; +} + +function getEnvObj() { + return { op: '@@' }; +} + +test('functional env expansion', function (t) { + 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']); +}); diff --git a/node_modules/shell-quote/test/op.js b/node_modules/shell-quote/test/op.js new file mode 100644 index 0000000..38d3757 --- /dev/null +++ b/node_modules/shell-quote/test/op.js @@ -0,0 +1,102 @@ +'use strict'; + +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('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 2>boop'), ['beep', '2', { op: '>' }, 'boop']); + t.same(parse('beep<boop'), ['beep', { op: '<' }, 'boop']); + + t.end(); +}); + +test('double 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', { op: '||' }, 'boop']); + t.same(parse('beep|| boop'), ['beep', { op: '||' }, 'boop']); + t.same(parse('beep || boop'), ['beep', { op: '||' }, 'boop']); + + 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<(boop)'), + ['beep', { op: '<(' }, 'boop', { op: ')' }] + ); + t.same( + parse('beep<<(boop)'), + ['beep', { op: '<' }, { op: '<(' }, 'boop', { op: ')' }] + ); + + t.end(); +}); + +test('duplicating input file descriptors', function (t) { + // duplicating stdout to file descriptor 3 + t.same(parse('beep 3<&1'), ['beep', '3', { op: '<&' }, '1']); + + // duplicating stdout to file descriptor 0, i.e. stdin + t.same(parse('beep <&1'), ['beep', { op: '<&' }, '1']); + + // closes stdin + t.same(parse('beep <&-'), ['beep', { op: '<&' }, '-']); + + t.end(); +}); + +test('here strings', function (t) { + t.same(parse('cat <<< "hello world"'), ['cat', { op: '<<<' }, 'hello world']); + t.same(parse('cat <<< hello'), ['cat', { op: '<<<' }, 'hello']); + t.same(parse('cat<<<hello'), ['cat', { op: '<<<' }, 'hello']); + t.same(parse('cat<<<"hello world"'), ['cat', { op: '<<<' }, 'hello world']); + + 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', 'test/*.test.js']); + t.end(); +}); diff --git a/node_modules/shell-quote/test/parse.js b/node_modules/shell-quote/test/parse.js new file mode 100644 index 0000000..e6c36b1 --- /dev/null +++ b/node_modules/shell-quote/test/parse.js @@ -0,0 +1,44 @@ +'use strict'; + +var test = require('tape'); +var parse = require('../').parse; + +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']); + 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('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.deepEqual(parse('-x "" -y'), ['-x', '', '-y'], 'empty string is preserved'); + + t.end(); +}); diff --git a/node_modules/shell-quote/test/quote.js b/node_modules/shell-quote/test/quote.js new file mode 100644 index 0000000..814707f --- /dev/null +++ b/node_modules/shell-quote/test/quote.js @@ -0,0 +1,60 @@ +'use strict'; + +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.equal(quote(['a"b']), '\'a"b\''); + t.equal(quote(['"a"b"']), '\'"a"b"\''); + t.equal(quote(['a\\"b']), '\'a\\"b\''); + t.equal(quote(['a\\b']), '\'a\\b\''); + 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(); +}); + +test('quote windows paths', { skip: 'breaking change, disabled until 2.x' }, function (t) { + 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.end(); +}); + +test("chars for windows paths don't break out", function (t) { + var x = '`:\\a\\b'; + t.equal(quote([x]), "'`:\\a\\b'"); + t.end(); +}); + +test('empty strings', function (t) { + t.equal(quote(['-x', '', 'y']), '-x \'\' y'); + + t.end(); +}); diff --git a/node_modules/shell-quote/test/set.js b/node_modules/shell-quote/test/set.js new file mode 100644 index 0000000..9694538 --- /dev/null +++ b/node_modules/shell-quote/test/set.js @@ -0,0 +1,31 @@ +'use strict'; + +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.end(); +}); |
