From 8f38c19c0860daa13563f4c9ab253cd9b5be49ab 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 54a05df736148f..191d51552f7d22 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -26,6 +26,8 @@ const { WeakMap, } = primordials; +const isWindows = process.platform === 'win32'; + const messages = new Map(); const codes = {}; @@ -1410,8 +1412,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 04a17c908ad91b..d58eac5f1c10cb 100644 --- a/lib/internal/modules/esm/resolve.js +++ b/lib/internal/modules/esm/resolve.js @@ -747,7 +747,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 e72922d31c0b18..30a5758ad9b0d4 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) { @@ -60,4 +56,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); + } })();