All files / lib/internal/modules/esm module_job.js

97.39% Statements 112/115
82.5% Branches 33/40
100% Functions 7/7
97.39% Lines 112/115

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 11690x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 90x 3x 90x 90x 90x 90x 90x 90x 90x 90x 90x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 343x 343x 343x 343x 174x 174x 174x 343x 343x 343x 343x 343x 343x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 347x 90x 90x 111x 102x 102x 9x 8x 111x 90x 90x 90x 90x 90x 102x 102x 102x 276x 14x 14x 262x 262x 259x 102x 102x 99x 102x 1x 1x 1x 101x 98x 98x 102x       100x 259x 259x 259x 259x 99x 102x 90x 90x 111x 107x 107x 107x 111x 90x 90x 90x  
'use strict';
 
const {
  Object,
  SafeSet,
  SafePromise
} = primordials;
 
const { ModuleWrap } = internalBinding('module_wrap');
 
const { decorateErrorStack } = require('internal/util');
const { getOptionValue } = require('internal/options');
const assert = require('internal/assert');
const resolvedPromise = SafePromise.resolve();
 
function noop() {}
 
let hasPausedEntry = false;
 
/* A ModuleJob tracks the loading of a single Module, and the ModuleJobs of
 * its dependencies, over time. */
class ModuleJob {
  // `loader` is the Loader instance used for loading dependencies.
  // `moduleProvider` is a function
  constructor(loader, url, moduleProvider, isMain) {
    this.loader = loader;
    this.isMain = isMain;
 
    // This is a Promise<{ module, reflect }>, whose fields will be copied
    // onto `this` by `link()` below once it has been resolved.
    this.modulePromise = moduleProvider.call(loader, url, isMain);
    this.module = undefined;
    this.reflect = undefined;
 
    // Wait for the ModuleWrap instance being linked with all dependencies.
    const link = async () => {
      ({ module: this.module,
         reflect: this.reflect } = await this.modulePromise);
      assert(this.module instanceof ModuleWrap);
 
      const dependencyJobs = [];
      const promises = this.module.link(async (specifier) => {
        const jobPromise = this.loader.getModuleJob(specifier, url);
        dependencyJobs.push(jobPromise);
        return (await (await jobPromise).modulePromise).module;
      });
 
      if (promises !== undefined)
        await SafePromise.all(promises);
 
      return SafePromise.all(dependencyJobs);
    };
    // Promise for the list of all dependencyJobs.
    this.linked = link();
    // This promise is awaited later anyway, so silence
    // 'unhandled rejection' warnings.
    this.linked.catch(noop);
 
    // instantiated == deep dependency jobs wrappers instantiated,
    // module wrapper instantiated
    this.instantiated = undefined;
  }
 
  async instantiate() {
    if (!this.instantiated) {
      return this.instantiated = this._instantiate();
    }
    await this.instantiated;
    return this.module;
  }
 
  // This method instantiates the module associated with this job and its
  // entire dependency graph, i.e. creates all the module namespaces and the
  // exported/imported variables.
  async _instantiate() {
    const jobsInGraph = new SafeSet();
 
    const addJobsToDependencyGraph = async (moduleJob) => {
      if (jobsInGraph.has(moduleJob)) {
        return;
      }
      jobsInGraph.add(moduleJob);
      const dependencyJobs = await moduleJob.linked;
      return Promise.all(dependencyJobs.map(addJobsToDependencyGraph));
    };
    await addJobsToDependencyGraph(this);
    try {
      if (!hasPausedEntry && this.isMain && getOptionValue('--inspect-brk')) {
        hasPausedEntry = true;
        const initWrapper = internalBinding('inspector').callAndPauseOnStart;
        initWrapper(this.module.instantiate, this.module);
      } else {
        this.module.instantiate();
      }
    } catch (e) {
      decorateErrorStack(e);
      throw e;
    }
    for (const dependencyJob of jobsInGraph) {
      // Calling `this.module.instantiate()` instantiates not only the
      // ModuleWrap in this module, but all modules in the graph.
      dependencyJob.instantiated = resolvedPromise;
    }
    return this.module;
  }
 
  async run() {
    const module = await this.instantiate();
    const timeout = -1;
    const breakOnSigint = false;
    return { module, result: module.evaluate(timeout, breakOnSigint) };
  }
}
Object.setPrototypeOf(ModuleJob.prototype, null);
module.exports = ModuleJob;