From c3d0091f68b3ce7e25e0965d11fc12edfe54ece8 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Fri, 27 Jan 2023 21:56:38 -0500 Subject: [PATCH 1/9] Properly handle quotes in commands at console --- packages/core/lib/console-child.js | 8 +++++++- packages/core/lib/console.js | 5 ++++- packages/core/package.json | 1 + yarn.lock | 2 +- 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index fa14fc008cf..386b94fefde 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -1,11 +1,17 @@ const TruffleError = require("@truffle/error"); const Config = require("@truffle/config"); const yargs = require("yargs"); +const shellQuote = require("shell-quote"); const { deriveConfigEnvironment } = require("./command-utils"); // we split off the part Truffle cares about and need to convert to an array const input = process.argv[2].split(" -- "); -const inputStrings = input[1].split(" "); +const inputStrings = shellQuote + .parse(input[1], process.env) + .map(stringOrOp => + typeof stringOrOp === "string" ? stringOrOp : stringOrOp.op + ); //we don't want bash operators treated specially, let's +//just replace them with the underlying string // we need to make sure this function exists so ensjs doesn't complain as it requires // getRandomValues for some functionalities - webpack strips out the crypto lib diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index f40d11db7e5..2e9ee65eb82 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -402,7 +402,10 @@ class Console extends EventEmitter { if ( this.allowedCommands.includes(processedInput.split(" ")[0]) && getCommand({ - inputStrings: processedInput.split(" "), + inputStrings: processedInput.split(" "), //note: splitting on spaces + //here isn't really correct (doesn't handle quotes), but I'm pretty + //sure it's good enough for the limited purposes of this line, so + //I'm leaving it alone options: {}, noAliases: this.options.noAliases }) !== null diff --git a/packages/core/package.json b/packages/core/package.json index 2fc74e3325e..e24ddb3cd72 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -78,6 +78,7 @@ "original-require": "^1.0.1", "sane": "^4.0.2", "semver": "7.3.7", + "shell-quote": "^1.7.4", "source-map-support": "^0.5.19", "spawn-args": "0.2.0", "tmp": "^0.2.1", diff --git a/yarn.lock b/yarn.lock index 68c48cd1b51..9ea8984cb96 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22955,7 +22955,7 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== -shell-quote@^1.7.3: +shell-quote@^1.7.3, shell-quote@^1.7.4: version "1.7.4" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== From 10a9ea38e3ddcc5561f4e70e15bf41e5f3f67123 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Mon, 30 Jan 2023 14:59:57 -0500 Subject: [PATCH 2/9] Change escape character to caret on Windows --- packages/core/lib/console-child.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 386b94fefde..d9669294f76 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -2,12 +2,15 @@ const TruffleError = require("@truffle/error"); const Config = require("@truffle/config"); const yargs = require("yargs"); const shellQuote = require("shell-quote"); +const path = require("path"); const { deriveConfigEnvironment } = require("./command-utils"); // we split off the part Truffle cares about and need to convert to an array const input = process.argv[2].split(" -- "); +const escapeCharacter = path.sep === "\\" ? "^" : "\\"; //set escape character +//based on current OS; backslash for Unix, caret for Windows const inputStrings = shellQuote - .parse(input[1], process.env) + .parse(input[1], process.env, { escape: escapeCharacter }) .map(stringOrOp => typeof stringOrOp === "string" ? stringOrOp : stringOrOp.op ); //we don't want bash operators treated specially, let's From eede3fe0453d0de850f8be83d43c9254706c5da0 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Mon, 30 Jan 2023 15:02:38 -0500 Subject: [PATCH 3/9] Handle case of shell comments --- packages/core/lib/console-child.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index d9669294f76..8035405c2b8 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -11,9 +11,7 @@ const escapeCharacter = path.sep === "\\" ? "^" : "\\"; //set escape character //based on current OS; backslash for Unix, caret for Windows const inputStrings = shellQuote .parse(input[1], process.env, { escape: escapeCharacter }) - .map(stringOrOp => - typeof stringOrOp === "string" ? stringOrOp : stringOrOp.op - ); //we don't want bash operators treated specially, let's + .map(stringOrObj => stringOrObj.op ?? stringOrObj.comment ?? stringOrObj); //we don't want bash operators or comments treated specially; let's //just replace them with the underlying string // we need to make sure this function exists so ensjs doesn't complain as it requires From 6b8a27b3fa6fc5153a1e1f785b0b7d55a2c90c09 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Wed, 1 Feb 2023 15:43:16 -0500 Subject: [PATCH 4/9] Update shell-quote version --- packages/core/package.json | 2 +- yarn.lock | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/core/package.json b/packages/core/package.json index e24ddb3cd72..2a9942077f5 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -78,7 +78,7 @@ "original-require": "^1.0.1", "sane": "^4.0.2", "semver": "7.3.7", - "shell-quote": "^1.7.4", + "shell-quote": "^1.8.0", "source-map-support": "^0.5.19", "spawn-args": "0.2.0", "tmp": "^0.2.1", diff --git a/yarn.lock b/yarn.lock index 9ea8984cb96..5c47ec689da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22955,11 +22955,16 @@ shell-quote@^1.6.1: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== -shell-quote@^1.7.3, shell-quote@^1.7.4: +shell-quote@^1.7.3: version "1.7.4" resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== +shell-quote@^1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" + integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== + shiki@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" From cf8d07d7a1e7d5b65ff4e16693d813c82c4e4d64 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Wed, 1 Feb 2023 15:44:03 -0500 Subject: [PATCH 5/9] Account for globs in shell-quote handling --- packages/core/lib/console-child.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 8035405c2b8..1735a1f1e5d 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -11,8 +11,15 @@ const escapeCharacter = path.sep === "\\" ? "^" : "\\"; //set escape character //based on current OS; backslash for Unix, caret for Windows const inputStrings = shellQuote .parse(input[1], process.env, { escape: escapeCharacter }) - .map(stringOrObj => stringOrObj.op ?? stringOrObj.comment ?? stringOrObj); //we don't want bash operators or comments treated specially; let's + .map( + stringOrObj => + stringOrObj.pattern ?? + stringOrObj.op ?? + stringOrObj.comment ?? + stringOrObj + ); //we don't want globs or bash operators or comments treated specially; let's //just replace them with the underlying string +//note that it's important that pattern comes before op here, as globs have both // we need to make sure this function exists so ensjs doesn't complain as it requires // getRandomValues for some functionalities - webpack strips out the crypto lib From cbd0b522c7637899d9f73d10a48df1526d6afc13 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Wed, 1 Feb 2023 23:58:45 -0500 Subject: [PATCH 6/9] Replace shell-quote library with hand-rolled parseQuotesAndEscapes --- packages/core/lib/command-utils.js | 85 ++++++++++++++++++++++++++++++ packages/core/lib/console-child.js | 22 +++----- packages/core/package.json | 1 - yarn.lock | 5 -- 4 files changed, 92 insertions(+), 21 deletions(-) diff --git a/packages/core/lib/command-utils.js b/packages/core/lib/command-utils.js index a27e24811e4..61b7b38f96c 100644 --- a/packages/core/lib/command-utils.js +++ b/packages/core/lib/command-utils.js @@ -13,6 +13,90 @@ const managedGanacheDefaultPort = 9545; const managedGanacheDefaultNetworkId = 5777; const managedDashboardDefaultPort = 24012; +//takes a string and splits it into arguments, shell-style, while +//taking account of quotes and escapes; the escape character can be +//customized (you can also pass in more than one valid escape character) +function parseQuotesAndEscapes(args, escapeCharacters = "\\") { + const quoteCharacters = "\"'"; //note we will handle the two quote types differently + let argArray = []; + let currentArg = ""; + let currentQuote = undefined; + let currentEscape = undefined; + let whitespace = true; //are we currently on whitespace? start this as true to allow whitespace at beginning + for (const char of args) { + if (currentEscape !== undefined) { + //escaped character + //note that inside quotes, we don't allow escaping everything; + //outside quotes, we allow escaping anything + if (currentQuote === '"') { + //inside a double-quote case + if (char === currentQuote) { + currentArg += char; //an escaped quote + } else { + //attempted to escape something not the current quote; + //don't treat it as an escape, include the escape char as well + currentArg += currentEscape + char; + } + } else { + //outside a quote case + //(note there's no single-quote case because we can't reach here + //in that case; currentEscape can't get set inside single quotes) + currentArg += char; //just the escaped character + } + currentEscape = undefined; + whitespace = false; //(this is not strictly necessary, but for clarity) + } else if (escapeCharacters.includes(char) && currentQuote !== "'") { + //(unescaped) escape character + //(again, inside single quotes, there is no escaping, so we just treat + //as ordinary character in that case) + currentEscape = char; + whitespace = false; + } else if (currentQuote !== undefined) { + //quoted character (excluding escape/escaped chars) + if (currentQuote === char) { + //closing quote + currentQuote = undefined; + } else { + //ordinary quoted character, including quote of non-matching type + currentArg += char; + } + whitespace = false; //again not necessary, included for clarity + } else if (quoteCharacters.includes(char)) { + //(unescaped) opening quote (closing quotes & quoted quotes handled above) + currentQuote = char; + whitespace = false; + } else if (char.match(/\s/)) { + //(unescaped) whitespace + if (!whitespace) { + //if we're already on whitespace, we don't need + //to do anything, this is just more whitespace. + //if however we're transitioning to whitespace, that means we need + //to split arguments here. + argArray.push(currentArg); + currentArg = ""; + whitespace = true; + } + } else { + //default case -- ordinary character + currentArg += char; + whitespace = false; + } + } + //having reached the end of the string, let's check for unterminated quotes & such + if (currentQuote !== undefined) { + throw new Error(`Error: quote with ${currentQuote} not terminated`); + } + if (currentEscape !== undefined) { + throw new Error(`Error: line ended with escape character ${currentEscape}`); + } + //now, we push our final argument, + //assuming of course that it's nonempty + if (currentArg !== "") { + argArray.push(currentArg); + } + return argArray; +} + // this function takes an object with an array of input strings, an options // object, and a boolean determining whether we allow inexact matches for // command names - it returns an object with the command name, the run method, @@ -312,6 +396,7 @@ const deriveConfigEnvironment = function (detectedConfig, network, url) { module.exports = { displayGeneralHelp, + parseQuotesAndEscapes, getCommand, prepareOptions, runCommand, diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index 1735a1f1e5d..ab69cd89c26 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -1,25 +1,17 @@ const TruffleError = require("@truffle/error"); const Config = require("@truffle/config"); const yargs = require("yargs"); -const shellQuote = require("shell-quote"); const path = require("path"); -const { deriveConfigEnvironment } = require("./command-utils"); +const { + deriveConfigEnvironment, + parseQuotesAndEscapes +} = require("./command-utils"); // we split off the part Truffle cares about and need to convert to an array const input = process.argv[2].split(" -- "); -const escapeCharacter = path.sep === "\\" ? "^" : "\\"; //set escape character -//based on current OS; backslash for Unix, caret for Windows -const inputStrings = shellQuote - .parse(input[1], process.env, { escape: escapeCharacter }) - .map( - stringOrObj => - stringOrObj.pattern ?? - stringOrObj.op ?? - stringOrObj.comment ?? - stringOrObj - ); //we don't want globs or bash operators or comments treated specially; let's -//just replace them with the underlying string -//note that it's important that pattern comes before op here, as globs have both +const escapeCharacters = path.sep === "\\" ? "^`" : "\\"; //set escape character +//based on current OS; backslash for Unix, caret or grave for Windows +const inputStrings = parseQuotesAndEscapes(input[1], escapeCharacters); // we need to make sure this function exists so ensjs doesn't complain as it requires // getRandomValues for some functionalities - webpack strips out the crypto lib diff --git a/packages/core/package.json b/packages/core/package.json index 2a9942077f5..2fc74e3325e 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -78,7 +78,6 @@ "original-require": "^1.0.1", "sane": "^4.0.2", "semver": "7.3.7", - "shell-quote": "^1.8.0", "source-map-support": "^0.5.19", "spawn-args": "0.2.0", "tmp": "^0.2.1", diff --git a/yarn.lock b/yarn.lock index 5c47ec689da..68c48cd1b51 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22960,11 +22960,6 @@ shell-quote@^1.7.3: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.4.tgz#33fe15dee71ab2a81fcbd3a52106c5cfb9fb75d8" integrity sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw== -shell-quote@^1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.0.tgz#20d078d0eaf71d54f43bd2ba14a1b5b9bfa5c8ba" - integrity sha512-QHsz8GgQIGKlRi24yFc6a6lN69Idnx634w49ay6+jA5yFh7a1UY+4Rp6HPx/L/1zcEDPEij8cIsiqR6bQsE5VQ== - shiki@^0.10.1: version "0.10.1" resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.10.1.tgz#6f9a16205a823b56c072d0f1a0bcd0f2646bef14" From 7317654e529893015697d70e98a517c32482d571 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Thu, 2 Feb 2023 20:30:38 -0500 Subject: [PATCH 7/9] Fix error handling with parseQuotesAndEscapes --- packages/core/lib/command-utils.js | 7 +++++-- packages/core/lib/console-child.js | 2 +- packages/core/lib/console.js | 12 ++++++------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/core/lib/command-utils.js b/packages/core/lib/command-utils.js index 61b7b38f96c..b0735d3156a 100644 --- a/packages/core/lib/command-utils.js +++ b/packages/core/lib/command-utils.js @@ -7,6 +7,7 @@ const debugModule = require("debug"); const debug = debugModule("core:command:run"); const commands = require("./commands/commands"); const Web3 = require("web3"); +const TruffleError = require("@truffle/error"); const defaultHost = "127.0.0.1"; const managedGanacheDefaultPort = 9545; @@ -84,10 +85,12 @@ function parseQuotesAndEscapes(args, escapeCharacters = "\\") { } //having reached the end of the string, let's check for unterminated quotes & such if (currentQuote !== undefined) { - throw new Error(`Error: quote with ${currentQuote} not terminated`); + throw new TruffleError(`Error: quote with ${currentQuote} not terminated`); } if (currentEscape !== undefined) { - throw new Error(`Error: line ended with escape character ${currentEscape}`); + throw new TruffleError( + `Error: line ended with escape character ${currentEscape}` + ); } //now, we push our final argument, //assuming of course that it's nonempty diff --git a/packages/core/lib/console-child.js b/packages/core/lib/console-child.js index ab69cd89c26..90df431d685 100644 --- a/packages/core/lib/console-child.js +++ b/packages/core/lib/console-child.js @@ -11,7 +11,7 @@ const { const input = process.argv[2].split(" -- "); const escapeCharacters = path.sep === "\\" ? "^`" : "\\"; //set escape character //based on current OS; backslash for Unix, caret or grave for Windows -const inputStrings = parseQuotesAndEscapes(input[1], escapeCharacters); +const inputStrings = parseQuotesAndEscapes(input[1], escapeCharacters); //note this shouldn't error since it's a recomputation // we need to make sure this function exists so ensjs doesn't complain as it requires // getRandomValues for some functionalities - webpack strips out the crypto lib diff --git a/packages/core/lib/console.js b/packages/core/lib/console.js index 2e9ee65eb82..18117a8f8aa 100644 --- a/packages/core/lib/console.js +++ b/packages/core/lib/console.js @@ -15,7 +15,7 @@ const EventEmitter = require("events"); const { spawn } = require("child_process"); const Require = require("@truffle/require"); const debug = require("debug")("console"); -const { getCommand } = require("./command-utils"); +const { getCommand, parseQuotesAndEscapes } = require("./command-utils"); const validTruffleCommands = require("./commands/commands"); // Create an expression that returns a string when evaluated @@ -400,17 +400,17 @@ class Console extends EventEmitter { async interpret(input, context, filename, callback) { const processedInput = processInput(input, this.allowedCommands); if ( - this.allowedCommands.includes(processedInput.split(" ")[0]) && + this.allowedCommands.includes(processedInput.split(/\s+/)[0]) && getCommand({ - inputStrings: processedInput.split(" "), //note: splitting on spaces - //here isn't really correct (doesn't handle quotes), but I'm pretty - //sure it's good enough for the limited purposes of this line, so - //I'm leaving it alone + inputStrings: processedInput.split(/\s+/), options: {}, noAliases: this.options.noAliases }) !== null ) { try { + parseQuotesAndEscapes(processedInput); //we're just doing this to see + //if it errors. unfortunately we need to throw out the result and recompute + //it afterward (but the input string is probably short so it's OK). await this.runSpawn(processedInput, this.options); } catch (error) { // Perform error handling ourselves. From 96c3f84e794e6a1b2e2e34f0454d48b53989db34 Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Thu, 2 Feb 2023 21:00:57 -0500 Subject: [PATCH 8/9] Add tests for parseQuotesAndEscapes --- packages/core/test/lib/command-utils.js | 59 ++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/packages/core/test/lib/command-utils.js b/packages/core/test/lib/command-utils.js index 289e21db1b9..b20081945b3 100644 --- a/packages/core/test/lib/command-utils.js +++ b/packages/core/test/lib/command-utils.js @@ -3,7 +3,10 @@ const fs = require("fs-extra"); const path = require("path"); const tmp = require("tmp"); const TruffleConfig = require("@truffle/config"); -const { deriveConfigEnvironment } = require("../../lib/command-utils"); +const { + deriveConfigEnvironment, + parseQuotesAndEscapes +} = require("../../lib/command-utils"); let config; @@ -96,4 +99,58 @@ describe("command-utils", function () { assert.equal(cfg.networks.develop.network_id, 5777); }); }); + + describe("parseQuotesAndEscapes", function () { + it("splits on whitespace", function () { + const parsed = parseQuotesAndEscapes(" abc def ghi "); + assert.deepEqual(parsed, ["abc", "def", "ghi"]); + }); + it("respects quotes and escapes", function () { + const parsed = parseQuotesAndEscapes("abc'd \"e'\"f 'g\"\\ hi"); + assert.deepEqual(parsed, ["abcd \"ef 'g hi"]); + }); + it("escapes correctly outside of a quote", function () { + const parsed = parseQuotesAndEscapes("ab\\c\\'\\\"\\\\ "); + assert.deepEqual(parsed, ["ab'\"\\"]); + }); + it("escapes correctly inside a double-quote", function () { + const parsed = parseQuotesAndEscapes('"ab\\"c\\d"'); + assert.deepEqual(parsed, ['ab"c\\d']); + }); + it("does not escape inside a single quote", function () { + const parsed = parseQuotesAndEscapes("'abc\\'"); + assert.deepEqual(parsed, ["abc\\"]); + }); + it("allows custom escapes", function () { + const parsed = parseQuotesAndEscapes("abc\\ de` f^ g `^^`", "^`"); + assert.deepEqual(parsed, ["abc\\", "de f g", "^`"]); + }); + it("errors on mismatched double quote", function () { + try { + parseQuotesAndEscapes('"abc\\"'); + } catch (error) { + if (error.message !== 'Error: quote with " not terminated') { + throw error; + } + } + }); + it("errors on mismatched single quote", function () { + try { + parseQuotesAndEscapes("'abc"); + } catch (error) { + if (error.message !== "Error: quote with ' not terminated") { + throw error; + } + } + }); + it("errors on escaped end-of-line", function () { + try { + parseQuotesAndEscapes("abc\\"); + } catch (error) { + if (error.message !== "Error: line ended with escape character \\") { + throw error; + } + } + }); + }); }); From 08b6477ce0edf99f61a95d41fa4301bb8e8db52d Mon Sep 17 00:00:00 2001 From: Harry Altman Date: Thu, 2 Feb 2023 21:32:13 -0500 Subject: [PATCH 9/9] Fix test, oops --- packages/core/test/lib/command-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/test/lib/command-utils.js b/packages/core/test/lib/command-utils.js index b20081945b3..eef5f2df859 100644 --- a/packages/core/test/lib/command-utils.js +++ b/packages/core/test/lib/command-utils.js @@ -111,7 +111,7 @@ describe("command-utils", function () { }); it("escapes correctly outside of a quote", function () { const parsed = parseQuotesAndEscapes("ab\\c\\'\\\"\\\\ "); - assert.deepEqual(parsed, ["ab'\"\\"]); + assert.deepEqual(parsed, ["abc'\"\\"]); }); it("escapes correctly inside a double-quote", function () { const parsed = parseQuotesAndEscapes('"ab\\"c\\d"');