| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 619f6bb commit d6a982b
14 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -177,6 +177,7 @@ const { | |||
| 177 | 177 | registerHooks, | |
| 178 | 178 | resolveHooks, | |
| 179 | 179 | resolveWithHooks, | |
| 180 | + validateLoadStrict, | ||
| 180 | 181 | } = require('internal/modules/customization_hooks'); | |
| 181 | 182 | const { stripTypeScriptModuleTypes } = require('internal/modules/typescript'); | |
| 182 | 183 | const packageJsonReader = require('internal/modules/package_json_reader'); | |
@@ -1176,7 +1177,7 @@ function loadBuiltinWithHooks(id, url, format) { | |||
| 1176 | 1177 | url ??= `node:${id}`; | |
| 1177 | 1178 | // TODO(joyeecheung): do we really want to invoke the load hook for the builtins? | |
| 1178 | 1179 | const loadResult = loadWithHooks(url, format || 'builtin', /* importAttributes */ undefined, | |
| 1179 | - getCjsConditionsArray(), getDefaultLoad(url, id)); | ||
| 1180 | + getCjsConditionsArray(), getDefaultLoad(url, id), validateLoadStrict); | ||
| 1180 | 1181 | if (loadResult.format && loadResult.format !== 'builtin') { | |
| 1181 | 1182 | return undefined; // Format has been overridden, return undefined for the caller to continue loading. | |
| 1182 | 1183 | } | |
@@ -1792,10 +1793,9 @@ function loadSource(mod, filename, formatFromNode) { | |||
| 1792 | 1793 | mod[kURL] = convertCJSFilenameToURL(filename); | |
| 1793 | 1794 | } | |
| 1794 | 1795 | ||
| 1796 | + const defaultLoad = getDefaultLoad(mod[kURL], filename); | ||
| 1795 | 1797 | const loadResult = loadWithHooks(mod[kURL], mod[kFormat], /* importAttributes */ undefined, | |
| 1796 | - getCjsConditionsArray(), | ||
| 1797 | - getDefaultLoad(mod[kURL], filename)); | ||
| 1798 | - | ||
| 1798 | + getCjsConditionsArray(), defaultLoad, validateLoadStrict); | ||
| 1799 | 1799 | // Reset the module properties with load hook results. | |
| 1800 | 1800 | if (loadResult.format !== undefined) { | |
| 1801 | 1801 | mod[kFormat] = loadResult.format; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -262,29 +262,56 @@ function validateResolve(specifier, context, result) { | |||
| 262 | 262 | */ | |
| 263 | 263 | ||
| 264 | 264 | /** | |
| 265 | - * Validate the result returned by a chain of resolve hook. | ||
| 265 | + * Validate the result returned by a chain of load hook. | ||
| 266 | 266 | * @param {string} url URL passed into the hooks. | |
| 267 | 267 | * @param {ModuleLoadContext} context Context passed into the hooks. | |
| 268 | 268 | * @param {ModuleLoadResult} result Result produced by load hooks. | |
| 269 | 269 | * @returns {ModuleLoadResult} | |
| 270 | 270 | */ | |
| 271 | - function validateLoad(url, context, result) { | ||
| 271 | + function validateLoadStrict(url, context, result) { | ||
| 272 | + validateSourceStrict(url, context, result); | ||
| 273 | + validateFormat(url, context, result); | ||
| 274 | + return result; | ||
| 275 | + } | ||
| 276 | + | ||
| 277 | + function validateLoadSloppy(url, context, result) { | ||
| 278 | + validateSourcePermissive(url, context, result); | ||
| 279 | + validateFormat(url, context, result); | ||
| 280 | + return result; | ||
| 281 | + } | ||
| 282 | + | ||
| 283 | + function validateSourceStrict(url, context, result) { | ||
| 272 | 284 | const { source, format } = result; | |
| 273 | 285 | // To align with module.register(), the load hooks are still invoked for | |
| 274 | 286 | // the builtins even though the default load step only provides null as source, | |
| 275 | 287 | // and any source content for builtins provided by the user hooks are ignored. | |
| 276 | 288 | if (!StringPrototypeStartsWith(url, 'node:') && | |
| 277 | 289 | typeof result.source !== 'string' && | |
| 278 | 290 | !isAnyArrayBuffer(source) && | |
| 279 | - !isArrayBufferView(source)) { | ||
| 291 | + !isArrayBufferView(source) && | ||
| 292 | + format !== 'addon') { | ||
| 280 | 293 | throw new ERR_INVALID_RETURN_PROPERTY_VALUE( | |
| 281 | 294 | 'a string, an ArrayBuffer, or a TypedArray', | |
| 282 | 295 | 'load', | |
| 283 | 296 | 'source', | |
| 284 | 297 | source, | |
| 285 | 298 | ); | |
| 286 | 299 | } | |
| 300 | + } | ||
| 287 | 301 | ||
| 302 | + function validateSourcePermissive(url, context, result) { | ||
| 303 | + const { source, format } = result; | ||
| 304 | + if (format === 'commonjs' && source == null) { | ||
| 305 | + // Accommodate the quirk in defaultLoad used by asynchronous loader hooks | ||
| 306 | + // which sets source to null for commonjs. | ||
| 307 | + // See: https://github.com/nodejs/node/issues/57327#issuecomment-2701382020 | ||
| 308 | + return; | ||
| 309 | + } | ||
| 310 | + validateSourceStrict(url, context, result); | ||
| 311 | + } | ||
| 312 | + | ||
| 313 | + function validateFormat(url, context, result) { | ||
| 314 | + const { format } = result; | ||
| 288 | 315 | if (typeof format !== 'string' && format !== undefined) { | |
| 289 | 316 | throw new ERR_INVALID_RETURN_PROPERTY_VALUE( | |
| 290 | 317 | 'a string', | |
@@ -293,12 +320,6 @@ function validateLoad(url, context, result) { | |||
| 293 | 320 | format, | |
| 294 | 321 | ); | |
| 295 | 322 | } | |
| 296 | - | ||
| 297 | - return { | ||
| 298 | - __proto__: null, | ||
| 299 | - format, | ||
| 300 | - source, | ||
| 301 | - }; | ||
| 302 | 323 | } | |
| 303 | 324 | ||
| 304 | 325 | class ModuleResolveContext { | |
@@ -338,9 +359,10 @@ let decoder; | |||
| 338 | 359 | * @param {ImportAttributes|undefined} importAttributes | |
| 339 | 360 | * @param {string[]} conditions | |
| 340 | 361 | * @param {(url: string, context: ModuleLoadContext) => ModuleLoadResult} defaultLoad | |
| 362 | + * @param {(url: string, context: ModuleLoadContext, result: ModuleLoadResult) => ModuleLoadResult} validateLoad | ||
| 341 | 363 | * @returns {ModuleLoadResult} | |
| 342 | 364 | */ | |
| 343 | - function loadWithHooks(url, originalFormat, importAttributes, conditions, defaultLoad) { | ||
| 365 | + function loadWithHooks(url, originalFormat, importAttributes, conditions, defaultLoad, validateLoad) { | ||
| 344 | 366 | debug('loadWithHooks', url, originalFormat); | |
| 345 | 367 | const context = new ModuleLoadContext(originalFormat, importAttributes, conditions); | |
| 346 | 368 | if (loadHooks.length === 0) { | |
@@ -403,4 +425,6 @@ module.exports = { | |||
| 403 | 425 | registerHooks, | |
| 404 | 426 | resolveHooks, | |
| 405 | 427 | resolveWithHooks, | |
| 428 | + validateLoadStrict, | ||
| 429 | + validateLoadSloppy, | ||
| 406 | 430 | }; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -61,7 +61,7 @@ const { | |||
| 61 | 61 | SHARED_MEMORY_BYTE_LENGTH, | |
| 62 | 62 | WORKER_TO_MAIN_THREAD_NOTIFICATION, | |
| 63 | 63 | } = require('internal/modules/esm/shared_constants'); | |
| 64 | - let debug = require('internal/util/debuglog').debuglog('esm', (fn) => { | ||
| 64 | + let debug = require('internal/util/debuglog').debuglog('async_loader_worker', (fn) => { | ||
| 65 | 65 | debug = fn; | |
| 66 | 66 | }); | |
| 67 | 67 | let importMetaInitializer; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -141,22 +141,34 @@ function defaultLoadSync(url, context = kEmptyObject) { | |||
| 141 | 141 | ||
| 142 | 142 | throwIfUnsupportedURLScheme(urlInstance, false); | |
| 143 | 143 | ||
| 144 | + let shouldBeReloadedByCJSLoader = false; | ||
| 144 | 145 | if (urlInstance.protocol === 'node:') { | |
| 145 | 146 | source = null; | |
| 146 | - } else if (source == null) { | ||
| 147 | - ({ responseURL, source } = getSourceSync(urlInstance, context)); | ||
| 148 | - context.source = source; | ||
| 149 | - } | ||
| 147 | + format ??= 'builtin'; | ||
| 148 | + } else if (format === 'addon') { | ||
| 149 | + // Skip loading addon file content. It must be loaded with dlopen from file system. | ||
| 150 | + source = null; | ||
| 151 | + } else { | ||
| 152 | + if (source == null) { | ||
| 153 | + ({ responseURL, source } = getSourceSync(urlInstance, context)); | ||
| 154 | + context = { __proto__: context, source }; | ||
| 155 | + } | ||
| 150 | 156 | ||
| 151 | - format ??= defaultGetFormat(urlInstance, context); | ||
| 157 | + // Now that we have the source for the module, run `defaultGetFormat` to detect its format. | ||
| 158 | + format ??= defaultGetFormat(urlInstance, context); | ||
| 152 | 159 | ||
| 160 | + // For backward compatibility reasons, we need to let go through Module._load | ||
| 161 | + // again. | ||
| 162 | + shouldBeReloadedByCJSLoader = (format === 'commonjs'); | ||
| 163 | + } | ||
| 153 | 164 | validateAttributes(url, format, importAttributes); | |
| 154 | 165 | ||
| 155 | 166 | return { | |
| 156 | 167 | __proto__: null, | |
| 157 | 168 | format, | |
| 158 | 169 | responseURL, | |
| 159 | 170 | source, | |
| 171 | + shouldBeReloadedByCJSLoader, | ||
| 160 | 172 | }; | |
| 161 | 173 | } | |
| 162 | 174 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -55,8 +55,9 @@ const { | |||
| 55 | 55 | resolveWithHooks, | |
| 56 | 56 | loadHooks, | |
| 57 | 57 | loadWithHooks, | |
| 58 | + validateLoadSloppy, | ||
| 58 | 59 | } = require('internal/modules/customization_hooks'); | |
| 59 | - let defaultResolve, defaultLoad, defaultLoadSync, importMetaInitializer; | ||
| 60 | + let defaultResolve, defaultLoadSync, importMetaInitializer; | ||
| 60 | 61 | ||
| 61 | 62 | const { tracingChannel } = require('diagnostics_channel'); | |
| 62 | 63 | const onImport = tracingChannel('module.import'); | |
@@ -146,6 +147,10 @@ let hooksProxy; | |||
| 146 | 147 | * @typedef {ArrayBuffer|TypedArray|string} ModuleSource | |
| 147 | 148 | */ | |
| 148 | 149 | ||
| 150 | + /** | ||
| 151 | + * @typedef {{ format: ModuleFormat, source: ModuleSource, translatorKey: string }} TranslateContext | ||
| 152 | + */ | ||
| 153 | + | ||
| 149 | 154 | /** | |
| 150 | 155 | * This class covers the base machinery of module loading. To add custom | |
| 151 | 156 | * behavior you can pass a customizations object and this object will be | |
@@ -503,18 +508,19 @@ class ModuleLoader { | |||
| 503 | 508 | ||
| 504 | 509 | const loadResult = this.#loadSync(url, { format, importAttributes }); | |
| 505 | 510 | ||
| 511 | + const formatFromLoad = loadResult.format; | ||
| 506 | 512 | // Use the synchronous commonjs translator which can deal with cycles. | |
| 507 | - const finalFormat = | ||
| 508 | - loadResult.format === 'commonjs' || | ||
| 509 | - loadResult.format === 'commonjs-typescript' ? 'commonjs-sync' : loadResult.format; | ||
| 513 | + const translatorKey = (formatFromLoad === 'commonjs' || formatFromLoad === 'commonjs-typescript') ? | ||
| 514 | + 'commonjs-sync' : formatFromLoad; | ||
| 510 | 515 | ||
| 511 | - if (finalFormat === 'wasm') { | ||
| 516 | + if (translatorKey === 'wasm') { | ||
| 512 | 517 | assert.fail('WASM is currently unsupported by require(esm)'); | |
| 513 | 518 | } | |
| 514 | 519 | ||
| 515 | 520 | const { source } = loadResult; | |
| 516 | 521 | const isMain = (parentURL === undefined); | |
| 517 | - const wrap = this.#translate(url, finalFormat, source, parentURL); | ||
| 522 | + const translateContext = { format: formatFromLoad, source, translatorKey, __proto__: null }; | ||
| 523 | + const wrap = this.#translate(url, translateContext, parentURL); | ||
| 518 | 524 | assert(wrap instanceof ModuleWrap, `Translator used for require(${url}) should not be async`); | |
| 519 | 525 | ||
| 520 | 526 | if (process.env.WATCH_REPORT_DEPENDENCIES && process.send) { | |
@@ -523,7 +529,7 @@ class ModuleLoader { | |||
| 523 | 529 | ||
| 524 | 530 | const cjsModule = wrap[imported_cjs_symbol]; | |
| 525 | 531 | if (cjsModule) { | |
| 526 | - assert(finalFormat === 'commonjs-sync'); | ||
| 532 | + assert(translatorKey === 'commonjs-sync'); | ||
| 527 | 533 | // Check if the ESM initiating import CJS is being required by the same CJS module. | |
| 528 | 534 | if (cjsModule?.[kIsExecuting]) { | |
| 529 | 535 | const parentFilename = urlToFilename(parentURL); | |
@@ -547,22 +553,22 @@ class ModuleLoader { | |||
| 547 | 553 | * Translate a loaded module source into a ModuleWrap. This is run synchronously, | |
| 548 | 554 | * but the translator may return the ModuleWrap in a Promise. | |
| 549 | 555 | * @param {string} url URL of the module to be translated. | |
| 550 | - * @param {string} format Format of the module to be translated. This is used to find | ||
| 551 | - * matching translators. | ||
| 552 | - * @param {ModuleSource} source Source of the module to be translated. | ||
| 553 | - * @param {string|undefined} parentURL URL of the parent module. Undefined if it's the entry point. | ||
| 556 | + * @param {TranslateContext} translateContext Context for the translator | ||
| 557 | + * @param {string|undefined} parentURL URL of the module initiating the module loading for the first time. | ||
| 558 | + * Undefined if it's the entry point. | ||
| 554 | 559 | * @returns {ModuleWrap} | |
| 555 | 560 | */ | |
| 556 | - #translate(url, format, source, parentURL) { | ||
| 561 | + #translate(url, translateContext, parentURL) { | ||
| 562 | + const { translatorKey, format } = translateContext; | ||
| 557 | 563 | this.validateLoadResult(url, format); | |
| 558 | - const translator = getTranslators().get(format); | ||
| 564 | + const translator = getTranslators().get(translatorKey); | ||
| 559 | 565 | ||
| 560 | 566 | if (!translator) { | |
| 561 | - throw new ERR_UNKNOWN_MODULE_FORMAT(format, url); | ||
| 567 | + throw new ERR_UNKNOWN_MODULE_FORMAT(translatorKey, url); | ||
| 562 | 568 | } | |
| 563 | 569 | ||
| 564 | - const result = FunctionPrototypeCall(translator, this, url, source, parentURL === undefined); | ||
| 565 | - assert(result instanceof ModuleWrap); | ||
| 570 | + const result = FunctionPrototypeCall(translator, this, url, translateContext, parentURL); | ||
| 571 | + assert(result instanceof ModuleWrap, `The ${format} module returned is not a ModuleWrap`); | ||
| 566 | 572 | return result; | |
| 567 | 573 | } | |
| 568 | 574 | ||
@@ -575,7 +581,8 @@ class ModuleLoader { | |||
| 575 | 581 | * @returns {ModuleWrap} | |
| 576 | 582 | */ | |
| 577 | 583 | loadAndTranslateForRequireInImportedCJS(url, loadContext, parentURL) { | |
| 578 | - const { format: formatFromLoad, source } = this.#loadSync(url, loadContext); | ||
| 584 | + const loadResult = this.#loadSync(url, loadContext); | ||
| 585 | + const formatFromLoad = loadResult.format; | ||
| 579 | 586 | ||
| 580 | 587 | if (formatFromLoad === 'wasm') { // require(wasm) is not supported. | |
| 581 | 588 | throw new ERR_UNKNOWN_MODULE_FORMAT(formatFromLoad, url); | |
@@ -587,15 +594,16 @@ class ModuleLoader { | |||
| 587 | 594 | } | |
| 588 | 595 | } | |
| 589 | 596 | ||
| 590 | - let finalFormat = formatFromLoad; | ||
| 597 | + let translatorKey = formatFromLoad; | ||
| 591 | 598 | if (formatFromLoad === 'commonjs') { | |
| 592 | - finalFormat = 'require-commonjs'; | ||
| 599 | + translatorKey = 'require-commonjs'; | ||
| 593 | 600 | } | |
| 594 | 601 | if (formatFromLoad === 'commonjs-typescript') { | |
| 595 | - finalFormat = 'require-commonjs-typescript'; | ||
| 602 | + translatorKey = 'require-commonjs-typescript'; | ||
| 596 | 603 | } | |
| 597 | 604 | ||
| 598 | - const wrap = this.#translate(url, finalFormat, source, parentURL); | ||
| 605 | + const translateContext = { ...loadResult, translatorKey, __proto__: null }; | ||
| 606 | + const wrap = this.#translate(url, translateContext, parentURL); | ||
| 599 | 607 | assert(wrap instanceof ModuleWrap, `Translator used for require(${url}) should not be async`); | |
| 600 | 608 | return wrap; | |
| 601 | 609 | } | |
@@ -610,8 +618,9 @@ class ModuleLoader { | |||
| 610 | 618 | */ | |
| 611 | 619 | loadAndTranslate(url, loadContext, parentURL) { | |
| 612 | 620 | const maybePromise = this.load(url, loadContext); | |
| 613 | - const afterLoad = ({ format, source }) => { | ||
| 614 | - return this.#translate(url, format, source, parentURL); | ||
| 621 | + const afterLoad = (loadResult) => { | ||
| 622 | + const translateContext = { ...loadResult, translatorKey: loadResult.format, __proto__: null }; | ||
| 623 | + return this.#translate(url, translateContext, parentURL); | ||
| 615 | 624 | }; | |
| 616 | 625 | if (isPromise(maybePromise)) { | |
| 617 | 626 | return maybePromise.then(afterLoad); | |
@@ -837,8 +846,8 @@ class ModuleLoader { | |||
| 837 | 846 | return this.#customizations.load(url, context); | |
| 838 | 847 | } | |
| 839 | 848 | ||
| 840 | - defaultLoad ??= require('internal/modules/esm/load').defaultLoad; | ||
| 841 | - return defaultLoad(url, context); | ||
| 849 | + defaultLoadSync ??= require('internal/modules/esm/load').defaultLoadSync; | ||
| 850 | + return defaultLoadSync(url, context); | ||
| 842 | 851 | } | |
| 843 | 852 | ||
| 844 | 853 | /** | |
@@ -873,7 +882,7 @@ class ModuleLoader { | |||
| 873 | 882 | // TODO(joyeecheung): construct the ModuleLoadContext in the loaders directly instead | |
| 874 | 883 | // of converting them from plain objects in the hooks. | |
| 875 | 884 | return loadWithHooks(url, context.format, context.importAttributes, this.#defaultConditions, | |
| 876 | - this.#loadAndMaybeBlockOnLoaderThread.bind(this)); | ||
| 885 | + this.#loadAndMaybeBlockOnLoaderThread.bind(this), validateLoadSloppy); | ||
| 877 | 886 | } | |
| 878 | 887 | return this.#loadAndMaybeBlockOnLoaderThread(url, context); | |
| 879 | 888 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments