* This constructs (creates, instantiates and evaluates) a module graph that * is require()'d. * @param {CJSModule} mod CJS module wrapper of the ESM. * @param {string} filename Resolved filename of the module being require()'d * @param {string} source Source code. TODO(joyeecheung): pass
(mod, filename, source, isMain, parent)
| 263 | * @returns {{wrap: ModuleWrap, namespace: import('internal/modules/esm/utils').ModuleNamespaceObject}} |
| 264 | */ |
| 265 | importSyncForRequire(mod, filename, source, isMain, parent) { |
| 266 | const url = pathToFileURL(filename).href; |
| 267 | if (!getOptionValue('--require-module')) { |
| 268 | throw new ERR_REQUIRE_ESM(url, true); |
| 269 | } |
| 270 | |
| 271 | let job = this.loadCache.get(url, kImplicitTypeAttribute); |
| 272 | // This module job is already created: |
| 273 | // 1. If it was loaded by `require()` before, at this point the instantiation |
| 274 | // is already completed and we can check whether it is in a cycle |
| 275 | // (in that case the module status is kEvaluating), and whether the |
| 276 | // required graph is synchronous. |
| 277 | // 2. If it was loaded by `import` before, only allow it if it's already evaluated |
| 278 | // to forbid cycles. |
| 279 | // TODO(joyeecheung): ensure that imported synchronous graphs are evaluated |
| 280 | // synchronously so that any previously imported synchronous graph is already |
| 281 | // evaluated at this point. |
| 282 | // TODO(joyeecheung): add something similar to CJS loader's requireStack to help |
| 283 | // debugging the problematic links in the graph for import. |
| 284 | debug('importSyncForRequire', parent?.filename, '->', filename, job); |
| 285 | if (job !== undefined) { |
| 286 | mod[kRequiredModuleSymbol] = job.module; |
| 287 | const parentFilename = urlToFilename(parent?.filename); |
| 288 | // This race should only be possible on the loader hook thread. See https://github.com/nodejs/node/issues/59666 |
| 289 | if (!job.module) { |
| 290 | throw new ERR_REQUIRE_ESM_RACE_CONDITION(filename, parentFilename, this.isForAsyncLoaderHookWorker); |
| 291 | } |
| 292 | const status = job.module.getStatus(); |
| 293 | debug('Module status', job, status); |
| 294 | // hasAsyncGraph is available after module been instantiated. |
| 295 | if (status >= kInstantiated && job.module.hasAsyncGraph) { |
| 296 | throw new ERR_REQUIRE_ASYNC_MODULE(filename, parentFilename); |
| 297 | } |
| 298 | if (status === kEvaluated) { |
| 299 | return { wrap: job.module, namespace: job.module.getNamespace() }; |
| 300 | } else if (status === kInstantiated) { |
| 301 | // When it's an async job cached by another import request, |
| 302 | // which has finished linking but has not started its |
| 303 | // evaluation because the async run() task would be later |
| 304 | // in line. Then start the evaluation now with runSync(), which |
| 305 | // is guaranteed to finish by the time the other run() get to it, |
| 306 | // and the other task would just get the cached evaluation results, |
| 307 | // similar to what would happen when both are async. |
| 308 | mod[kRequiredModuleSymbol] = job.module; |
| 309 | const { namespace } = job.runSync(parent); |
| 310 | return { wrap: job.module, namespace: namespace || job.module.getNamespace() }; |
| 311 | } else if (status === kErrored) { |
| 312 | // If the module was previously imported and errored, throw the error. |
| 313 | throw job.module.getError(); |
| 314 | } |
| 315 | // When the cached async job have already encountered a linking |
| 316 | // error that gets wrapped into a rejection, but is still later |
| 317 | // in line to throw on it, just unwrap and throw the linking error |
| 318 | // from require(). |
| 319 | if (job.instantiated) { |
| 320 | throwIfPromiseRejected(job.instantiated); |
| 321 | } |
| 322 | if (status !== kEvaluating) { |
no test coverage detected