From 2dff6e9ea03f8b14f0d22c1ebb42eb42d3ebfd88 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Sat, 25 Jun 2022 12:32:57 +0200 Subject: [PATCH] url: faster encodePathChars function. This is roughly twice as fast as before. Signed-off-by: Ruben Bridgewater --- lib/internal/url.js | 50 ++++++++++++++++++++++++++++----------------- 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index b483b4440ebf23..99f2b66a677867 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -19,10 +19,9 @@ const { ReflectApply, ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, + RegExp, String, StringPrototypeCharCodeAt, - StringPrototypeIncludes, - StringPrototypeReplace, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -1500,25 +1499,38 @@ function fileURLToPath(path) { // - CR: The carriage return character is also stripped out by the `pathname` // setter. // - TAB: The tab character is also stripped out by the `pathname` setter. -const percentRegEx = /%/g; -const backslashRegEx = /\\/g; -const newlineRegEx = /\n/g; -const carriageReturnRegEx = /\r/g; -const tabRegEx = /\t/g; +const escapePathRegExp = new RegExp(`%|\\n|\\r|\\t${isWindows ? '' : '|\\\\'}`); +const escapedPathChars = { + '%': '%25', + '\n': '%0A', + '\r': '%0D', + '\t': '%09', + '\\': '%5C', +}; +// As of V8 10.2 the hand written replacer is faster than using replace with a +// replacer function. function encodePathChars(filepath) { - if (StringPrototypeIncludes(filepath, '%')) - filepath = StringPrototypeReplace(filepath, percentRegEx, '%25'); - // In posix, backslash is a valid character in paths: - if (!isWindows && StringPrototypeIncludes(filepath, '\\')) - filepath = StringPrototypeReplace(filepath, backslashRegEx, '%5C'); - if (StringPrototypeIncludes(filepath, '\n')) - filepath = StringPrototypeReplace(filepath, newlineRegEx, '%0A'); - if (StringPrototypeIncludes(filepath, '\r')) - filepath = StringPrototypeReplace(filepath, carriageReturnRegEx, '%0D'); - if (StringPrototypeIncludes(filepath, '\t')) - filepath = StringPrototypeReplace(filepath, tabRegEx, '%09'); - return filepath; + if (!escapePathRegExp.test(filepath)) { + return filepath; + } + let result = ''; + let last = 0; + for (let i = 0; i < filepath.length; i++) { + const point = filepath.charCodeAt(i); + if (point <= 13 || point === 37 || (!isWindows && point === 92)) { + const replacingChar = escapedPathChars[filepath[i]]; + if (replacingChar !== undefined) { + result += `${filepath.slice(last, i)}${replacingChar}`; + last = i + 1; + } + } + } + + if (last !== filepath.length) { + result += filepath.slice(last); + } + return result; } function pathToFileURL(filepath) {