From 8030eb5c2447d1d63652d81c6effeacc57a63e50 Mon Sep 17 00:00:00 2001 From: Denys Otrishko Date: Sun, 16 Aug 2020 12:28:54 +0300 Subject: [PATCH] esm: improve error message of ERR_UNSUPPORTED_ESM_URL_SCHEME Refs: https://github.com/nodejs/node/issues/34765 PR-URL: https://github.com/nodejs/node/pull/34795 Reviewed-By: Matteo Collina Reviewed-By: Ruben Bridgewater Reviewed-By: Jan Krems Reviewed-By: Guy Bedford Reviewed-By: Bradley Farias Reviewed-By: Anna Henningsen Reviewed-By: Rich Trott --- lib/internal/errors.js | 13 +++++++++++-- lib/internal/modules/esm/resolve.js | 2 +- test/es-module/test-esm-dynamic-import.js | 23 ++++++++++++++--------- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 8cb6179dff4110..f2c49ec0e545ea 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -27,6 +27,8 @@ const { WeakMap, } = primordials; +const isWindows = process.platform === 'win32'; + const messages = new Map(); const codes = {}; @@ -1399,8 +1401,15 @@ E('ERR_UNKNOWN_MODULE_FORMAT', 'Unknown module format: %s', RangeError); E('ERR_UNKNOWN_SIGNAL', 'Unknown signal: %s', TypeError); E('ERR_UNSUPPORTED_DIR_IMPORT', "Directory import '%s' is not supported " + 'resolving ES modules imported from %s', Error); -E('ERR_UNSUPPORTED_ESM_URL_SCHEME', 'Only file and data URLs are supported ' + - 'by the default ESM loader', Error); +E('ERR_UNSUPPORTED_ESM_URL_SCHEME', (url) => { + let msg = 'Only file and data URLs are supported by the default ESM loader'; + if (isWindows && url.protocol.length === 2) { + msg += '. Absolute Windows paths without prefix are not valid URLs, ' + + "consider using 'file://' prefix"; + } + msg += `. Received protocol '${url.protocol}'`; + return msg; +}, Error); // This should probably be a `TypeError`. E('ERR_VALID_PERFORMANCE_ENTRY_TYPE', diff --git a/lib/internal/modules/esm/resolve.js b/lib/internal/modules/esm/resolve.js index f6879465451c83..a598d7c0abbc9e 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -722,7 +722,7 @@ function defaultResolve(specifier, context = {}, defaultResolveUnused) { if (parsed && parsed.protocol === 'nodejs:') return { url: specifier }; if (parsed && parsed.protocol !== 'file:' && parsed.protocol !== 'data:') - throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(); + throw new ERR_UNSUPPORTED_ESM_URL_SCHEME(parsed); if (NativeModule.canBeRequiredByUsers(specifier)) { return { url: 'nodejs:' + specifier diff --git a/test/es-module/test-esm-dynamic-import.js b/test/es-module/test-esm-dynamic-import.js index e01b86eed143ed..24d13d7fb8662d 100644 --- a/test/es-module/test-esm-dynamic-import.js +++ b/test/es-module/test-esm-dynamic-import.js @@ -8,15 +8,11 @@ const absolutePath = require.resolve('../fixtures/es-modules/test-esm-ok.mjs'); const targetURL = new URL('file:///'); targetURL.pathname = absolutePath; -function expectErrorProperty(result, propertyKey, value) { - Promise.resolve(result) - .catch(common.mustCall((error) => { - assert.strictEqual(error[propertyKey], value); - })); -} - -function expectModuleError(result, err) { - expectErrorProperty(result, 'code', err); +function expectModuleError(result, code, message) { + Promise.resolve(result).catch(common.mustCall((error) => { + assert.strictEqual(error.code, code); + if (message) assert.strictEqual(error.message, message); + })); } function expectOkNamespace(result) { @@ -63,4 +59,13 @@ function expectFsNamespace(result) { 'ERR_MODULE_NOT_FOUND'); expectModuleError(import('http://example.com/foo.js'), 'ERR_UNSUPPORTED_ESM_URL_SCHEME'); + if (common.isWindows) { + const msg = + 'Only file and data URLs are supported by the default ESM loader. ' + + 'Absolute Windows paths without prefix are not valid URLs, ' + + "consider using 'file://' prefix. Received protocol 'c:'"; + expectModuleError(import('C:\\example\\foo.mjs'), + 'ERR_UNSUPPORTED_ESM_URL_SCHEME', + msg); + } })();