From 44655cc4d426338a0130e4ba66801a851c0f687e Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sat, 24 Dec 2022 21:46:15 +0100 Subject: [PATCH 01/11] url: refactor to use more primordials --- lib/internal/freeze_intrinsics.js | 3 +- lib/internal/per_context/primordials.js | 2 + lib/internal/url.js | 53 ++++++++++--------------- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/lib/internal/freeze_intrinsics.js b/lib/internal/freeze_intrinsics.js index 508b071c7c0f88..1e2a732eb1dbe1 100644 --- a/lib/internal/freeze_intrinsics.js +++ b/lib/internal/freeze_intrinsics.js @@ -61,6 +61,7 @@ const { Int32ArrayPrototype, Int8Array, Int8ArrayPrototype, + IteratorPrototype, Map, MapPrototype, Number, @@ -211,7 +212,7 @@ module.exports = function() { // 27 Control Abstraction Objects // 27.1 Iteration - ObjectGetPrototypeOf(ArrayIteratorPrototype), // 27.1.2 IteratorPrototype + IteratorPrototype, // 27.1.2 IteratorPrototype // 27.1.3 AsyncIteratorPrototype ObjectGetPrototypeOf(ObjectGetPrototypeOf(ObjectGetPrototypeOf( (async function*() {})() diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 370f5953dc78e5..d7ca58d0469c07 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -260,6 +260,8 @@ function copyPrototype(src, dest, prefix) { copyPrototype(original.prototype, primordials, `${name}Prototype`); }); +primordials.IteratorPrototype = Reflect.getPrototypeOf(primordials.ArrayIteratorPrototype); + /* eslint-enable node-core/prefer-primordials */ const { diff --git a/lib/internal/url.js b/lib/internal/url.js index 40b25f6890b5db..9ecf527aa09b63 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -9,6 +9,7 @@ const { ArrayPrototypeSlice, FunctionPrototypeBind, Int8Array, + IteratorPrototype, Number, ObjectCreate, ObjectDefineProperties, @@ -20,9 +21,11 @@ const { ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, String, + StringPrototypeCharAt, StringPrototypeCharCodeAt, + StringPrototypeCodePointAt, StringPrototypeIncludes, - StringPrototypeReplace, + StringPrototypeIndexOf, StringPrototypeReplaceAll, StringPrototypeSlice, StringPrototypeSplit, @@ -139,11 +142,6 @@ function lazyCryptoRandom() { return cryptoRandom; } -// https://tc39.github.io/ecma262/#sec-%iteratorprototype%-object -const IteratorPrototype = ObjectGetPrototypeOf( - ObjectGetPrototypeOf([][SymbolIterator]()) -); - // Refs: https://html.spec.whatwg.org/multipage/browsers.html#concept-origin-opaque const kOpaqueOrigin = 'null'; @@ -1377,7 +1375,7 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParams Iterator', { }, [] ); - const breakLn = inspect(output, innerOpts).includes('\n'); + const breakLn = StringPrototypeIncludes(inspect(output, innerOpts), '\n'); const outputStrs = ArrayPrototypeMap(output, (p) => inspect(p, innerOpts)); let outputStr; if (breakLn) { @@ -1435,7 +1433,7 @@ function getPathFromURLWin32(url) { let pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { - const third = pathname.codePointAt(n + 2) | 0x20; + const third = StringPrototypeCodePointAt(pathname, n + 2) | 0x20; if ((pathname[n + 1] === '2' && third === 102) || // 2f 2F / (pathname[n + 1] === '5' && third === 99)) { // 5c 5C \ throw new ERR_INVALID_FILE_URL_PATH( @@ -1456,13 +1454,13 @@ function getPathFromURLWin32(url) { return `\\\\${domainToUnicode(hostname)}${pathname}`; } // Otherwise, it's a local path that requires a drive letter - const letter = pathname.codePointAt(1) | 0x20; - const sep = pathname[2]; + const letter = StringPrototypeCodePointAt(pathname, 1) | 0x20; + const sep = StringPrototypeCharAt(pathname, 2); if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z || // a..z A..Z (sep !== ':')) { throw new ERR_INVALID_FILE_URL_PATH('must be absolute'); } - return pathname.slice(1); + return StringPrototypeSlice(pathname, 1); } function getPathFromURLPosix(url) { @@ -1472,7 +1470,7 @@ function getPathFromURLPosix(url) { const pathname = url.pathname; for (let n = 0; n < pathname.length; n++) { if (pathname[n] === '%') { - const third = pathname.codePointAt(n + 2) | 0x20; + const third = StringPrototypeCodePointAt(pathname, n + 2) | 0x20; if (pathname[n + 1] === '2' && third === 102) { throw new ERR_INVALID_FILE_URL_PATH( 'must not include encoded / characters' @@ -1504,24 +1502,13 @@ 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; - function encodePathChars(filepath) { - if (StringPrototypeIncludes(filepath, '%')) - filepath = StringPrototypeReplace(filepath, percentRegEx, '%25'); + filepath = StringPrototypeReplaceAll(filepath, '%', '%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'); + if (!isWindows) filepath = StringPrototypeReplaceAll(filepath, '\\', '%5C'); + filepath = StringPrototypeReplaceAll(filepath, '\n', '%0A'); + filepath = StringPrototypeReplaceAll(filepath, '\r', '%0D'); + filepath = StringPrototypeReplaceAll(filepath, '\t', '%09'); return filepath; } @@ -1529,25 +1516,25 @@ function pathToFileURL(filepath) { const outURL = new URL('file://'); if (isWindows && StringPrototypeStartsWith(filepath, '\\\\')) { // UNC path format: \\server\share\resource - const paths = StringPrototypeSplit(filepath, '\\'); - if (paths.length <= 3) { + const hostnameEndIndex = StringPrototypeIndexOf('\\', 2); + if (hostnameEndIndex === -1) { throw new ERR_INVALID_ARG_VALUE( 'filepath', filepath, 'Missing UNC resource path' ); } - const hostname = paths[2]; - if (hostname.length === 0) { + if (hostnameEndIndex === 3) { throw new ERR_INVALID_ARG_VALUE( 'filepath', filepath, 'Empty UNC servername' ); } + const hostname = StringPrototypeSlice(filepath, 2, hostnameEndIndex); outURL.hostname = domainToASCII(hostname); outURL.pathname = encodePathChars( - ArrayPrototypeJoin(ArrayPrototypeSlice(paths, 3), '/')); + StringPrototypeReplaceAll(StringPrototypeSlice(filepath, hostnameEndIndex), '\\', '/')); } else { let resolved = path.resolve(filepath); // path.resolve strips trailing slashes so we must add them back From 80452de08ad947d67708ae810cbb7fc805d2b33f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 25 Dec 2022 02:16:26 +0100 Subject: [PATCH 02/11] Use `RegExpPrototypeSymbolReplace` over `StringPrototypeReplaceAll` --- lib/internal/url.js | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 9ecf527aa09b63..4e642ce07aeda9 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -20,13 +20,13 @@ const { ReflectApply, ReflectGetOwnPropertyDescriptor, ReflectOwnKeys, + RegExpPrototypeSymbolReplace, String, StringPrototypeCharAt, StringPrototypeCharCodeAt, StringPrototypeCodePointAt, StringPrototypeIncludes, StringPrototypeIndexOf, - StringPrototypeReplaceAll, StringPrototypeSlice, StringPrototypeSplit, StringPrototypeStartsWith, @@ -34,6 +34,7 @@ const { SymbolIterator, SymbolToStringTag, decodeURIComponent, + hardenRegExp, } = primordials; const { inspect } = require('internal/util/inspect'); @@ -116,6 +117,8 @@ const { revokeDataObject, } = internalBinding('blob'); +const FORWARD_SLASH = hardenRegExp(/\//g); + const context = Symbol('context'); const cannotBeBase = Symbol('cannot-be-base'); const cannotHaveUsernamePasswordPort = @@ -1442,7 +1445,7 @@ function getPathFromURLWin32(url) { } } } - pathname = StringPrototypeReplaceAll(pathname, '/', '\\'); + pathname = RegExpPrototypeSymbolReplace(FORWARD_SLASH, pathname, '\\'); pathname = decodeURIComponent(pathname); if (hostname !== '') { // If hostname is set, then we have a UNC path @@ -1502,13 +1505,19 @@ 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 = hardenRegExp(/%/g); +const backslashRegEx = hardenRegExp(/\\/g); +const newlineRegEx = hardenRegExp(/\n/g); +const carriageReturnRegEx = hardenRegExp(/\r/g); +const tabRegEx = hardenRegExp(/\t/g); + function encodePathChars(filepath) { - filepath = StringPrototypeReplaceAll(filepath, '%', '%25'); + filepath = RegExpPrototypeSymbolReplace(percentRegEx, filepath, '%25'); // In posix, backslash is a valid character in paths: - if (!isWindows) filepath = StringPrototypeReplaceAll(filepath, '\\', '%5C'); - filepath = StringPrototypeReplaceAll(filepath, '\n', '%0A'); - filepath = StringPrototypeReplaceAll(filepath, '\r', '%0D'); - filepath = StringPrototypeReplaceAll(filepath, '\t', '%09'); + if (!isWindows) filepath = RegExpPrototypeSymbolReplace(backslashRegEx, filepath, '%5C'); + filepath = RegExpPrototypeSymbolReplace(newlineRegEx, filepath, '%0A'); + filepath = RegExpPrototypeSymbolReplace(carriageReturnRegEx, filepath, '%0D'); + filepath = RegExpPrototypeSymbolReplace(tabRegEx, filepath, '%09'); return filepath; } @@ -1534,7 +1543,7 @@ function pathToFileURL(filepath) { const hostname = StringPrototypeSlice(filepath, 2, hostnameEndIndex); outURL.hostname = domainToASCII(hostname); outURL.pathname = encodePathChars( - StringPrototypeReplaceAll(StringPrototypeSlice(filepath, hostnameEndIndex), '\\', '/')); + RegExpPrototypeSymbolReplace(backslashRegEx, StringPrototypeSlice(filepath, hostnameEndIndex), '/')); } else { let resolved = path.resolve(filepath); // path.resolve strips trailing slashes so we must add them back From 2475de3f54eec75280b629d009e5d06838ddba32 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 25 Dec 2022 02:24:10 +0100 Subject: [PATCH 03/11] fixup! Use `RegExpPrototypeSymbolReplace` over `StringPrototypeReplaceAll` --- lib/internal/url.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 4e642ce07aeda9..571367a7e1ada6 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1512,12 +1512,17 @@ const carriageReturnRegEx = hardenRegExp(/\r/g); const tabRegEx = hardenRegExp(/\t/g); function encodePathChars(filepath) { - filepath = RegExpPrototypeSymbolReplace(percentRegEx, filepath, '%25'); + if (StringPrototypeIncludes(filepath, '%')) + filepath = RegExpPrototypeSymbolReplace(percentRegEx, filepath, '%25'); // In posix, backslash is a valid character in paths: - if (!isWindows) filepath = RegExpPrototypeSymbolReplace(backslashRegEx, filepath, '%5C'); - filepath = RegExpPrototypeSymbolReplace(newlineRegEx, filepath, '%0A'); - filepath = RegExpPrototypeSymbolReplace(carriageReturnRegEx, filepath, '%0D'); - filepath = RegExpPrototypeSymbolReplace(tabRegEx, filepath, '%09'); + if (!isWindows && StringPrototypeIncludes(filepath, '\\')) + filepath = RegExpPrototypeSymbolReplace(backslashRegEx, filepath, '%5C'); + if (StringPrototypeIncludes(filepath, '\n')) + filepath = RegExpPrototypeSymbolReplace(newlineRegEx, filepath, '%0A'); + if (StringPrototypeIncludes(filepath, '\r')) + filepath = RegExpPrototypeSymbolReplace(carriageReturnRegEx, filepath, '%0D'); + if (StringPrototypeIncludes(filepath, '\t')) + filepath = RegExpPrototypeSymbolReplace(tabRegEx, filepath, '%09'); return filepath; } From b2ab16ceabda2f5631c7b04c678d47cb1733a796 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 26 Dec 2022 01:36:42 +0100 Subject: [PATCH 04/11] do not harden in case that helps --- lib/internal/url.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 571367a7e1ada6..b959657f70ddef 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -34,7 +34,6 @@ const { SymbolIterator, SymbolToStringTag, decodeURIComponent, - hardenRegExp, } = primordials; const { inspect } = require('internal/util/inspect'); @@ -117,7 +116,7 @@ const { revokeDataObject, } = internalBinding('blob'); -const FORWARD_SLASH = hardenRegExp(/\//g); +const FORWARD_SLASH = /\//g; const context = Symbol('context'); const cannotBeBase = Symbol('cannot-be-base'); @@ -1505,11 +1504,11 @@ 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 = hardenRegExp(/%/g); -const backslashRegEx = hardenRegExp(/\\/g); -const newlineRegEx = hardenRegExp(/\n/g); -const carriageReturnRegEx = hardenRegExp(/\r/g); -const tabRegEx = hardenRegExp(/\t/g); +const percentRegEx = /%/g; +const backslashRegEx = /\\/g; +const newlineRegEx = /\n/g; +const carriageReturnRegEx = /\r/g; +const tabRegEx = /\t/g; function encodePathChars(filepath) { if (StringPrototypeIncludes(filepath, '%')) From b8d193f2c8d5d7b01bf00e21941cc744faf6ac18 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 29 Dec 2022 20:20:38 +0100 Subject: [PATCH 05/11] add benchmarks for url utils --- benchmark/url/whatwgurl-to-and-from-path.js | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 benchmark/url/whatwgurl-to-and-from-path.js diff --git a/benchmark/url/whatwgurl-to-and-from-path.js b/benchmark/url/whatwgurl-to-and-from-path.js new file mode 100644 index 00000000000000..3b87c0670a8fee --- /dev/null +++ b/benchmark/url/whatwgurl-to-and-from-path.js @@ -0,0 +1,30 @@ +'use strict'; +const common = require('../common.js'); +const { fileURLToPath, pathToFileURL } = require('node:url'); +const isWindows = process.platform === 'win32'; + +const bench = common.createBenchmark(main, { + input: isWindows ? [ + 'file:///c/', + ] : [ + 'file:///dev/null', + 'file:///dev/null?key=param&bool', + 'file:///dev/null?key=param&bool#hash', + ], + method: isWindows ? [ + 'fileURLToPath', + ] : [ + 'fileURLToPath', + 'pathToFileURL', + ], + n: [5e6], +}); + +function main({ n, input, method }) { + method = method === 'fileURLOrPath' ? fileURLToPath : pathToFileURL; + bench.start(); + for (let i = 0; i < n; i++) { + method(input); + } + bench.end(n); +} From 00cd18f8b35713491bab392d8df31139b7c759c6 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 19 Jan 2023 15:23:05 +0100 Subject: [PATCH 06/11] Update lib/internal/url.js --- lib/internal/url.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index b959657f70ddef..6042608fdfdbf2 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1529,7 +1529,7 @@ function pathToFileURL(filepath) { const outURL = new URL('file://'); if (isWindows && StringPrototypeStartsWith(filepath, '\\\\')) { // UNC path format: \\server\share\resource - const hostnameEndIndex = StringPrototypeIndexOf('\\', 2); + const hostnameEndIndex = StringPrototypeIndexOf(filepath, '\\', 2); if (hostnameEndIndex === -1) { throw new ERR_INVALID_ARG_VALUE( 'filepath', From 1fc0fb0dfde3c55364ff545cc3e649a2b16aee3f Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 19 Jan 2023 16:27:18 +0100 Subject: [PATCH 07/11] esm: skip file: URL conversion to path when possible --- lib/internal/modules/esm/get_format.js | 30 +++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js index 640d240acd4ca1..a381a264f6f3ac 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -4,9 +4,10 @@ const { ObjectPrototypeHasOwnProperty, PromisePrototypeThen, PromiseResolve, + StringPrototypeCharCodeAt, StringPrototypeSlice, } = primordials; -const { basename, extname, relative } = require('path'); +const { basename, relative } = require('path'); const { getOptionValue } = require('internal/options'); const { extensionFormatMap, @@ -41,6 +42,29 @@ function getDataProtocolModuleFormat(parsed) { return mimeToFormat(mime); } +const DOT_CODE = 46; +const SLASH_CODE = 47; + +/** + * Returns the file extension from a file: URL. Should give similar result than + * require('node:path').extname(require('node:url').fileURLToPath(url)). + * @param {URL} url A file: URL. + * @returns {string} + */ +function extname(url) { + const { pathname } = url; + for (let i = pathname.length - 1; i > 0; i--) { + switch (StringPrototypeCharCodeAt(pathname, i)) { + case SLASH_CODE: + return ''; + + case DOT_CODE: + return StringPrototypeSlice(pathname, i); + } + } + return ''; +} + /** * @param {URL} url * @param {{parentURL: string}} context @@ -48,8 +72,7 @@ function getDataProtocolModuleFormat(parsed) { * @returns {string} */ function getFileProtocolModuleFormat(url, context, ignoreErrors) { - const filepath = fileURLToPath(url); - const ext = extname(filepath); + const ext = extname(url); if (ext === '.js') { return getPackageType(url) === 'module' ? 'module' : 'commonjs'; } @@ -59,6 +82,7 @@ function getFileProtocolModuleFormat(url, context, ignoreErrors) { // Explicit undefined return indicates load hook should rerun format check if (ignoreErrors) { return undefined; } + const filepath = fileURLToPath(url); let suggestion = ''; if (getPackageType(url) === 'module' && ext === '') { const config = getPackageScopeConfig(url); From 3a61d80ed1aac3bdfb8322e5c796644db4547baf Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 22 Jan 2023 10:26:53 +0100 Subject: [PATCH 08/11] fix UNC validation --- lib/internal/url.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index 6042608fdfdbf2..cebd2d57ce6e91 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -1537,7 +1537,7 @@ function pathToFileURL(filepath) { 'Missing UNC resource path' ); } - if (hostnameEndIndex === 3) { + if (hostnameEndIndex === 2) { throw new ERR_INVALID_ARG_VALUE( 'filepath', filepath, From 1ceaa2c82a9f679b68d29c02739d02275aae28a4 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 22 Jan 2023 10:57:13 +0100 Subject: [PATCH 09/11] fixup! esm: skip file: URL conversion to path when possible --- lib/internal/modules/esm/translators.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index b21c3c18cf7383..5b69ef417692d5 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -35,8 +35,7 @@ const { Module: CJSModule, cjsParseCache } = require('internal/modules/cjs/loader'); -const internalURLModule = require('internal/url'); -const { fileURLToPath, URL } = require('url'); +const { fileURLToPath, URL } = require('internal/url'); let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); @@ -147,9 +146,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source, isMain) { debug(`Translating CJSModule ${url}`); - let filename = internalURLModule.fileURLToPath(new URL(url)); - if (isWindows) - filename = StringPrototypeReplaceAll(filename, '/', '\\'); + const filename = fileURLToPath(new URL(url)); if (!cjsParse) await initCJSParse(); const { module, exportNames } = cjsPreparseModuleExports(filename); From fc4fc3f0e47cb029ff2b80190b931abf44814156 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 22 Jan 2023 10:58:56 +0100 Subject: [PATCH 10/11] side effect free regex replacement --- lib/internal/url.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/internal/url.js b/lib/internal/url.js index cebd2d57ce6e91..ae133b02e20fa1 100644 --- a/lib/internal/url.js +++ b/lib/internal/url.js @@ -48,6 +48,7 @@ const { removeColors, toUSVString, kEnumerableProperty, + SideEffectFreeRegExpPrototypeSymbolReplace, } = require('internal/util'); const { @@ -1444,7 +1445,7 @@ function getPathFromURLWin32(url) { } } } - pathname = RegExpPrototypeSymbolReplace(FORWARD_SLASH, pathname, '\\'); + pathname = SideEffectFreeRegExpPrototypeSymbolReplace(FORWARD_SLASH, pathname, '\\'); pathname = decodeURIComponent(pathname); if (hostname !== '') { // If hostname is set, then we have a UNC path From 256e4bdbf352f605c95ce7d685f9f7711b37e503 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Sun, 22 Jan 2023 11:36:52 +0100 Subject: [PATCH 11/11] Revert "esm: skip file: URL conversion to path when possible" This reverts commit 1ceaa2c82a9f679b68d29c02739d02275aae28a4 and 1fc0fb0dfde3c55364ff545cc3e649a2b16aee3f. --- lib/internal/modules/esm/get_format.js | 30 +++---------------------- lib/internal/modules/esm/translators.js | 7 ++++-- 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js index a381a264f6f3ac..640d240acd4ca1 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -4,10 +4,9 @@ const { ObjectPrototypeHasOwnProperty, PromisePrototypeThen, PromiseResolve, - StringPrototypeCharCodeAt, StringPrototypeSlice, } = primordials; -const { basename, relative } = require('path'); +const { basename, extname, relative } = require('path'); const { getOptionValue } = require('internal/options'); const { extensionFormatMap, @@ -42,29 +41,6 @@ function getDataProtocolModuleFormat(parsed) { return mimeToFormat(mime); } -const DOT_CODE = 46; -const SLASH_CODE = 47; - -/** - * Returns the file extension from a file: URL. Should give similar result than - * require('node:path').extname(require('node:url').fileURLToPath(url)). - * @param {URL} url A file: URL. - * @returns {string} - */ -function extname(url) { - const { pathname } = url; - for (let i = pathname.length - 1; i > 0; i--) { - switch (StringPrototypeCharCodeAt(pathname, i)) { - case SLASH_CODE: - return ''; - - case DOT_CODE: - return StringPrototypeSlice(pathname, i); - } - } - return ''; -} - /** * @param {URL} url * @param {{parentURL: string}} context @@ -72,7 +48,8 @@ function extname(url) { * @returns {string} */ function getFileProtocolModuleFormat(url, context, ignoreErrors) { - const ext = extname(url); + const filepath = fileURLToPath(url); + const ext = extname(filepath); if (ext === '.js') { return getPackageType(url) === 'module' ? 'module' : 'commonjs'; } @@ -82,7 +59,6 @@ function getFileProtocolModuleFormat(url, context, ignoreErrors) { // Explicit undefined return indicates load hook should rerun format check if (ignoreErrors) { return undefined; } - const filepath = fileURLToPath(url); let suggestion = ''; if (getPackageType(url) === 'module' && ext === '') { const config = getPackageScopeConfig(url); diff --git a/lib/internal/modules/esm/translators.js b/lib/internal/modules/esm/translators.js index 5b69ef417692d5..b21c3c18cf7383 100644 --- a/lib/internal/modules/esm/translators.js +++ b/lib/internal/modules/esm/translators.js @@ -35,7 +35,8 @@ const { Module: CJSModule, cjsParseCache } = require('internal/modules/cjs/loader'); -const { fileURLToPath, URL } = require('internal/url'); +const internalURLModule = require('internal/url'); +const { fileURLToPath, URL } = require('url'); let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { debug = fn; }); @@ -146,7 +147,9 @@ translators.set('commonjs', async function commonjsStrategy(url, source, isMain) { debug(`Translating CJSModule ${url}`); - const filename = fileURLToPath(new URL(url)); + let filename = internalURLModule.fileURLToPath(new URL(url)); + if (isWindows) + filename = StringPrototypeReplaceAll(filename, '/', '\\'); if (!cjsParse) await initCJSParse(); const { module, exportNames } = cjsPreparseModuleExports(filename);