This commit is contained in:
Simon Priet
2021-09-05 22:53:58 +02:00
commit 9e2991e668
17888 changed files with 1263126 additions and 0 deletions

27
node_modules/shell-quote/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,27 @@
language: node_js
os:
- linux
- osx
- windows
node_js:
- "0.8"
- "0.10"
- "0.12"
- "iojs"
- "4"
- "5"
- "6"
- "7"
- "8"
- "9"
- "10"
- "11"
- "12"
matrix:
exclude:
- os: windows
node_js: "0.8"
- os: windows
node_js: "iojs"
before_install:
- 'if [ $TRAVIS_NODE_VERSION == 0.8 ]; then nvm install-latest-npm; fi'

21
node_modules/shell-quote/CHANGELOG.md generated vendored Normal file
View File

@@ -0,0 +1,21 @@
# acorn-node change log
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 1.7.2
* Fix a regression introduced in 1.6.3. This reverts the Windows path quoting fix. ([144e1c2](https://github.com/substack/node-shell-quote/commit/144e1c20cd57549a414c827fb3032e60b7b8721c))
## 1.7.1
* Fix `$` being removed when not part of an environment variable name. ([@Adman](https://github.com/Admin) in [#32](https://github.com/substack/node-shell-quote/pull/32))
## 1.7.0
* Add support for parsing `>>` and `>&` redirection operators. ([@forivall](https://github.com/forivall) in [#16](https://github.com/substack/node-shell-quote/pull/16))
* Add support for parsing `<(` process substitution operator. ([@cuonglm](https://github.com/cuonglm) in [#15](https://github.com/substack/node-shell-quote/pull/15))
## 1.6.3
* Fix Windows path quoting problems. ([@dy](https://github.com/dy) in [#34](https://github.com/substack/node-shell-quote/pull/34))
## 1.6.2
* Remove dependencies in favour of native methods. ([@zertosh](https://github.com/zertosh) in [#21](https://github.com/substack/node-shell-quote/pull/21))

24
node_modules/shell-quote/LICENSE generated vendored Normal file
View File

@@ -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.

3
node_modules/shell-quote/example/env.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
var parse = require('../').parse;
var xs = parse('beep --boop="$PWD"', { PWD: '/home/robot' });
console.dir(xs);

3
node_modules/shell-quote/example/op.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
var parse = require('../').parse;
var xs = parse('beep || boop > /byte');
console.dir(xs);

3
node_modules/shell-quote/example/parse.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
var parse = require('../').parse;
var xs = parse('a "b c" \\$def \'it\\\'s great\'');
console.dir(xs);

3
node_modules/shell-quote/example/quote.js generated vendored Normal file
View File

@@ -0,0 +1,3 @@
var quote = require('../').quote;
var s = quote([ 'a', 'b c d', '$f', '"g"' ]);
console.log(s);

199
node_modules/shell-quote/index.js generated vendored Normal file
View File

@@ -0,0 +1,199 @@
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-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 + '])+';
var SINGLE_QUOTE = '"((\\\\"|[^"])*?)"';
var DOUBLE_QUOTE = '\'((\\\\\'|[^\'])*?)\'';
var TOKEN = '';
for (var i = 0; i < 4; i++) {
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;
}));
}, []);
};
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 };
}
// 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;
}
if (isGlob) return {op: 'glob', pattern: 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 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;
}
}

30
node_modules/shell-quote/package.json generated vendored Normal file
View File

@@ -0,0 +1,30 @@
{
"name": "shell-quote",
"description": "quote and parse shell commands",
"version": "1.7.2",
"author": {
"name": "James Halliday",
"email": "mail@substack.net",
"url": "http://substack.net"
},
"bugs": "https://github.com/substack/node-shell-quote/issues",
"devDependencies": {
"tape": "4"
},
"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": {
"test": "tape test/*.js"
}
}

138
node_modules/shell-quote/readme.markdown generated vendored Normal file
View File

@@ -0,0 +1,138 @@
# shell-quote
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 charcter
``` 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

14
node_modules/shell-quote/test/comment.js generated vendored Normal file
View File

@@ -0,0 +1,14 @@
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();
});

41
node_modules/shell-quote/test/env.js generated vendored Normal file
View File

@@ -0,0 +1,41 @@
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('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' ]);
});
});

19
node_modules/shell-quote/test/env_fn.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
var test = require('tape');
var parse = require('../').parse;
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' ]);
function getEnv (key) {
return 'xxx';
}
function getEnvObj (key) {
return { op: '@@' };
}
});

78
node_modules/shell-quote/test/op.js generated vendored Normal file
View File

@@ -0,0 +1,78 @@
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('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();
})

23
node_modules/shell-quote/test/parse.js generated vendored Normal file
View File

@@ -0,0 +1,23 @@
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.end();
});

42
node_modules/shell-quote/test/quote.js generated vendored Normal file
View File

@@ -0,0 +1,42 @@
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();
});
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()
})

29
node_modules/shell-quote/test/set.js generated vendored Normal file
View File

@@ -0,0 +1,29 @@
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 (key) {
t.fail('should not have matched any keys');
}),
[ 'X=7 8 9', { op: ';' }, 'printx' ]
);
t.end();
});