From 9b3b7d6978bbda570b85bc6367f27d4fbc9bb664 Mon Sep 17 00:00:00 2001 From: Jacob Smith <3012099+JakobJingleheimer@users.noreply.github.com> Date: Mon, 19 Sep 2022 22:55:09 +0200 Subject: [PATCH] esm,loader: tidy ESMLoader internals PR-URL: https://github.com/nodejs/node/pull/44701 Reviewed-By: Geoffrey Booth Reviewed-By: Antoine du Hamel --- lib/internal/modules/esm/get_format.js | 7 +- lib/internal/modules/esm/loader.js | 137 +++++++++++------------ test/es-module/test-esm-loader-hooks.mjs | 8 +- 3 files changed, 75 insertions(+), 77 deletions(-) diff --git a/lib/internal/modules/esm/get_format.js b/lib/internal/modules/esm/get_format.js index 950a769227c03f..a7329d279bb075 100644 --- a/lib/internal/modules/esm/get_format.js +++ b/lib/internal/modules/esm/get_format.js @@ -1,8 +1,6 @@ 'use strict'; const { RegExpPrototypeExec, - ObjectAssign, - ObjectCreate, ObjectPrototypeHasOwnProperty, PromisePrototypeThen, PromiseResolve, @@ -25,13 +23,14 @@ const { getPackageType, getPackageScopeConfig } = require('internal/modules/esm/ const { URL, fileURLToPath } = require('internal/url'); const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes; -const protocolHandlers = ObjectAssign(ObjectCreate(null), { +const protocolHandlers = { + '__proto__': null, 'data:': getDataProtocolModuleFormat, 'file:': getFileProtocolModuleFormat, 'http:': getHttpProtocolModuleFormat, 'https:': getHttpProtocolModuleFormat, 'node:'() { return 'builtin'; }, -}); +}; /** * @param {URL} parsed diff --git a/lib/internal/modules/esm/loader.js b/lib/internal/modules/esm/loader.js index cc7f64a9980d86..8dad259a57c19a 100644 --- a/lib/internal/modules/esm/loader.js +++ b/lib/internal/modules/esm/loader.js @@ -179,39 +179,38 @@ function nextHookFactory(chain, meta, { validateArgs, validateOutput }) { * the main module and everything in its dependency graph. */ class ESMLoader { - /** - * Prior to ESM loading. These are called once before any modules are started. - * @private - * @property {KeyedHook[]} globalPreloaders Last-in-first-out - * list of preload hooks. - */ - #globalPreloaders = []; - - /** - * Phase 2 of 2 in ESM loading. - * @private - * @property {KeyedHook[]} loaders Last-in-first-out - * collection of loader hooks. - */ - #loaders = [ - { - fn: defaultLoad, - url: 'node:internal/modules/esm/load', - }, - ]; - - /** - * Phase 1 of 2 in ESM loading. - * @private - * @property {KeyedHook[]} resolvers Last-in-first-out - * collection of resolver hooks. - */ - #resolvers = [ - { - fn: defaultResolve, - url: 'node:internal/modules/esm/resolve', - }, - ]; + #hooks = { + /** + * Prior to ESM loading. These are called once before any modules are started. + * @private + * @property {KeyedHook[]} globalPreload Last-in-first-out list of preload hooks. + */ + globalPreload: [], + + /** + * Phase 2 of 2 in ESM loading (phase 1 is below). + * @private + * @property {KeyedHook[]} load Last-in-first-out collection of loader hooks. + */ + load: [ + { + fn: defaultLoad, + url: 'node:internal/modules/esm/load', + }, + ], + + /** + * Phase 1 of 2 in ESM loading. + * @private + * @property {KeyedHook[]} resolve Last-in-first-out collection of resolve hooks. + */ + resolve: [ + { + fn: defaultResolve, + url: 'node:internal/modules/esm/resolve', + }, + ], + }; #importMetaInitializer = initializeImportMeta; @@ -305,13 +304,13 @@ class ESMLoader { ); if (globalPreload) { - acceptedHooks.globalPreloader = globalPreload; + acceptedHooks.globalPreload = globalPreload; } if (resolve) { - acceptedHooks.resolver = resolve; + acceptedHooks.resolve = resolve; } if (load) { - acceptedHooks.loader = load; + acceptedHooks.load = load; } return acceptedHooks; @@ -333,34 +332,34 @@ class ESMLoader { url, } = customLoaders[i]; const { - globalPreloader, - resolver, - loader, + globalPreload, + resolve, + load, } = ESMLoader.pluckHooks(exports); - if (globalPreloader) { + if (globalPreload) { ArrayPrototypePush( - this.#globalPreloaders, + this.#hooks.globalPreload, { - fn: globalPreloader, + fn: globalPreload, url, }, ); } - if (resolver) { + if (resolve) { ArrayPrototypePush( - this.#resolvers, + this.#hooks.resolve, { - fn: resolver, + fn: resolve, url, }, ); } - if (loader) { + if (load) { ArrayPrototypePush( - this.#loaders, + this.#hooks.load, { - fn: loader, + fn: load, url, }, ); @@ -411,14 +410,14 @@ class ESMLoader { async getModuleJob(specifier, parentURL, importAssertions) { let importAssertionsForResolve; - // By default, `this.#loaders` contains just the Node default load hook - if (this.#loaders.length !== 1) { + // By default, `this.#hooks.load` contains just the Node default load hook + if (this.#hooks.load.length !== 1) { // We can skip cloning if there are no user-provided loaders because // the Node.js default resolve hook does not use import assertions. - importAssertionsForResolve = ObjectAssign( - ObjectCreate(null), - importAssertions, - ); + importAssertionsForResolve = { + __proto__: null, + ...importAssertions, + }; } const { format, url } = @@ -529,11 +528,11 @@ class ESMLoader { if (!wasArr) { return namespaces[0]; } // We can skip the pairing below for (let i = 0; i < count; i++) { - const namespace = ObjectCreate(null); - namespace.url = specifiers[i]; - namespace.exports = namespaces[i]; - - namespaces[i] = namespace; + namespaces[i] = { + __proto__: null, + url: specifiers[i], + exports: namespaces[i], + }; } return namespaces; @@ -551,7 +550,7 @@ class ESMLoader { * @returns {{ format: ModuleFormat, source: ModuleSource }} */ async load(url, context = {}) { - const chain = this.#loaders; + const chain = this.#hooks.load; const meta = { chainFinished: null, context, @@ -680,7 +679,7 @@ class ESMLoader { } preload() { - for (let i = this.#globalPreloaders.length - 1; i >= 0; i--) { + for (let i = this.#hooks.globalPreload.length - 1; i >= 0; i--) { const channel = new MessageChannel(); const { port1: insidePreload, @@ -691,19 +690,19 @@ class ESMLoader { insideLoader.unref(); const { - fn: preloader, + fn: preload, url: specifier, - } = this.#globalPreloaders[i]; + } = this.#hooks.globalPreload[i]; - const preload = preloader({ + const preloaded = preload({ port: insideLoader, }); - if (preload == null) { return; } + if (preloaded == null) { return; } const hookErrIdentifier = `${specifier} globalPreload`; - if (typeof preload !== 'string') { // [2] + if (typeof preloaded !== 'string') { // [2] throw new ERR_INVALID_RETURN_VALUE( 'a string', hookErrIdentifier, @@ -712,7 +711,7 @@ class ESMLoader { } const { compileFunction } = require('vm'); const preloadInit = compileFunction( - preload, + preloaded, ['getBuiltin', 'port', 'setImportMetaCallback'], { filename: '', @@ -785,7 +784,7 @@ class ESMLoader { async resolve( originalSpecifier, parentURL, - importAssertions = ObjectCreate(null) + importAssertions = ObjectCreate(null), ) { const isMain = parentURL === undefined; @@ -800,7 +799,7 @@ class ESMLoader { parentURL, ); } - const chain = this.#resolvers; + const chain = this.#hooks.resolve; const context = { conditions: DEFAULT_CONDITIONS, importAssertions, diff --git a/test/es-module/test-esm-loader-hooks.mjs b/test/es-module/test-esm-loader-hooks.mjs index d314a4d9aa0a5e..2704fe1a52ccce 100644 --- a/test/es-module/test-esm-loader-hooks.mjs +++ b/test/es-module/test-esm-loader-hooks.mjs @@ -12,10 +12,10 @@ const { ESMLoader } = esmLoaderModule; const esmLoader = new ESMLoader(); const originalSpecifier = 'foo/bar'; - const importAssertions = Object.assign( - Object.create(null), - { type: 'json' }, - ); + const importAssertions = { + __proto__: null, + type: 'json', + }; const parentURL = 'file:///entrypoint.js'; const resolvedURL = 'file:///foo/bar.js'; const suggestedFormat = 'test';