From 12504fdf4331c414b77e9c9c1333d832201a910c Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Sat, 27 Jan 2018 17:27:09 +0100 Subject: [PATCH 1/4] Add failing test with exclamation mark --- test/pattern.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/test/pattern.js b/test/pattern.js index bbe8580..8625e41 100644 --- a/test/pattern.js +++ b/test/pattern.js @@ -143,4 +143,49 @@ describe("[pattern] it should run matched tasks if glob like patterns are given. } }) }) + + describe("\"!test-task:**\" should not match to anything", () => { + it("Node API", async () => { + try { + await nodeApi("!test-task:**") + assert(false, "should not match") + } + catch (err) { + assert((/not found/i).test(err.message)) + } + }) + + it("npm-run-all command", async () => { + const stderr = new BufferStream() + try { + await runAll(["!test-task:**"], null, stderr) + assert(false, "should not match") + } + catch (_err) { + assert((/not found/i).test(stderr.value)) + } + }) + + it("run-s command", async () => { + const stderr = new BufferStream() + try { + await runSeq(["!test-task:**"], null, stderr) + assert(false, "should not match") + } + catch (_err) { + assert((/not found/i).test(stderr.value)) + } + }) + + it("run-p command", async () => { + const stderr = new BufferStream() + try { + await runPar(["!test-task:**"], null, stderr) + assert(false, "should not match") + } + catch (_err) { + assert((/not found/i).test(stderr.value)) + } + }) + }) }) From 4d14a06e0c5852df850dc562aa9df1f384f50d7f Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Sat, 27 Jan 2018 17:31:07 +0100 Subject: [PATCH 2/4] Pass `{ nonegate: true }` option to minimatch --- lib/match-tasks.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/match-tasks.js b/lib/match-tasks.js index 63a0de3..e3adb95 100644 --- a/lib/match-tasks.js +++ b/lib/match-tasks.js @@ -43,7 +43,7 @@ function createFilter(pattern) { const spacePos = trimmed.indexOf(" ") const task = spacePos < 0 ? trimmed : trimmed.slice(0, spacePos) const args = spacePos < 0 ? "" : trimmed.slice(spacePos) - const matcher = new Minimatch(swapColonAndSlash(task)) + const matcher = new Minimatch(swapColonAndSlash(task), { nonegate: true }) const match = matcher.match.bind(matcher) return { match, task, args } From 4b04f72d6bade32e67c3d7a811d8623a2dcbb152 Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Sun, 28 Jan 2018 13:34:11 +0100 Subject: [PATCH 3/4] Add failing test with question mark --- test-workspace/package.json | 4 +++- test/pattern.js | 22 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/test-workspace/package.json b/test-workspace/package.json index 91fc09a..9ef916e 100644 --- a/test-workspace/package.json +++ b/test-workspace/package.json @@ -38,7 +38,9 @@ "test-task:nest-append:run-s": "node ../bin/run-s/index.js test-task:append", "test-task:nest-append:run-p": "node ../bin/run-p/index.js test-task:append", "test-task:delayed": "node tasks/output-with-delay.js", - "test-task:yarn": "node ../bin/npm-run-all/index.js test-task:append:{a,b} --npm-path yarn" + "test-task:yarn": "node ../bin/npm-run-all/index.js test-task:append:{a,b} --npm-path yarn", + "!test": "node tasks/append1.js X", + "?test": "node tasks/append1.js Q" }, "repository": { "type": "git", diff --git a/test/pattern.js b/test/pattern.js index 8625e41..9074c55 100644 --- a/test/pattern.js +++ b/test/pattern.js @@ -188,4 +188,26 @@ describe("[pattern] it should run matched tasks if glob like patterns are given. } }) }) + + describe("\"!test\" \"?test\" to \"!test\", \"?test\"", () => { + it("Node API", async () => { + await nodeApi(["!test", "?test"]) + assert(result().trim() === "XQ") + }) + + it("npm-run-all command", async () => { + await runAll(["!test", "?test"]) + assert(result().trim() === "XQ") + }) + + it("run-s command", async () => { + await runSeq(["!test", "?test"]) + assert(result().trim() === "XQ") + }) + + it("run-p command", async () => { + await runPar(["!test", "?test"]) + assert(result().trim() === "XQ" || result().trim() === "QX") + }) + }) }) From 4972be916212fac30c74065c9589203a4c899f20 Mon Sep 17 00:00:00 2001 From: Erik Kemperman Date: Mon, 29 Jan 2018 14:15:37 +0100 Subject: [PATCH 4/4] Ensure output of shell-quote's `parse()` is valid input for npm-cli --- lib/run-task.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/run-task.js b/lib/run-task.js index ee70000..8cabc03 100644 --- a/lib/run-task.js +++ b/lib/run-task.js @@ -82,6 +82,22 @@ function detectStreamKind(stream, std) { ) } +/** + * Ensure the output of shell-quote's `parse()` is acceptable input to npm-cli. + * + * The `parse()` method of shell-quote sometimes returns special objects in its + * output array, e.g. if it thinks some elements should be globbed. But npm-cli + * only accepts strings and will throw an error otherwise. + * + * See https://github.com/substack/node-shell-quote#parsecmd-env + * + * @param {object|string} arg - Item in the output of shell-quote's `parse()`. + * @returns {string} A valid argument for npm-cli. + */ +function cleanTaskArg(arg) { + return arg.pattern || arg.op || arg +} + //------------------------------------------------------------------------------ // Interface //------------------------------------------------------------------------------ @@ -153,7 +169,7 @@ module.exports = function runTask(task, options) { else if (options.prefixOptions.indexOf("--silent") !== -1) { spawnArgs.push("--silent") } - Array.prototype.push.apply(spawnArgs, parseArgs(task)) + Array.prototype.push.apply(spawnArgs, parseArgs(task).map(cleanTaskArg)) cp = spawn(execPath, spawnArgs, spawnOptions)