All files / lib/internal/process esm_loader.js

95.57% Statements 108/113
92.59% Branches 25/27
100% Functions 5/5
95.57% Lines 108/113

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 114143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 184x 184x 184x 184x 183x 183x 184x 143x 143x 143x 430x 430x 430x 430x 430x 429x 429x 429x 430x 1x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 325x 325x 322x 322x 322x 322x 322x 320x 320x 320x 320x 320x 320x 325x 14x 14x 320x 320x 325x 143x 336x 336x 62x 62x 62x 62x 336x     62x 62x 62x 62x 62x 62x 62x 62x 62x 62x 62x 62x 62x 336x 143x 143x 325x 325x 323x 325x 68x       68x 68x 68x 68x 68x 143x  
'use strict';
 
const {
  ArrayIsArray,
  ObjectCreate,
} = primordials;
 
const {
  ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING,
} = require('internal/errors').codes;
const { ESMLoader } = require('internal/modules/esm/loader');
const {
  hasUncaughtExceptionCaptureCallback,
} = require('internal/process/execution');
const { pathToFileURL } = require('internal/url');
const {
  getModuleFromWrap,
} = require('internal/vm/module');
 
exports.initializeImportMetaObject = function(wrap, meta) {
  const { callbackMap } = internalBinding('module_wrap');
  if (callbackMap.has(wrap)) {
    const { initializeImportMeta } = callbackMap.get(wrap);
    if (initializeImportMeta !== undefined) {
      initializeImportMeta(meta, getModuleFromWrap(wrap) || wrap);
    }
  }
};
 
exports.importModuleDynamicallyCallback =
async function importModuleDynamicallyCallback(wrap, specifier, assertions) {
  const { callbackMap } = internalBinding('module_wrap');
  if (callbackMap.has(wrap)) {
    const { importModuleDynamically } = callbackMap.get(wrap);
    if (importModuleDynamically !== undefined) {
      return importModuleDynamically(
        specifier, getModuleFromWrap(wrap) || wrap, assertions);
    }
  }
  throw new ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING();
};
 
const esmLoader = new ESMLoader();
exports.esmLoader = esmLoader;
 
// Module.runMain() causes loadESM() to re-run (which it should do); however, this should NOT cause
// ESM to be re-initialised; doing so causes duplicate custom loaders to be added to the public
// esmLoader.
let isESMInitialized = false;
 
/**
 * Causes side-effects: user-defined loader hooks are added to esmLoader.
 * @returns {void}
 */
async function initializeLoader() {
  if (isESMInitialized) { return; }
 
  const { getOptionValue } = require('internal/options');
  const customLoaders = getOptionValue('--experimental-loader');
  const preloadModules = getOptionValue('--import');
  const loaders = await loadModulesInIsolation(customLoaders);
 
  // Hooks must then be added to external/public loader
  // (so they're triggered in userland)
  esmLoader.addCustomLoaders(loaders);
 
  // Preload after loaders are added so they can be used
  if (preloadModules?.length) {
    await loadModulesInIsolation(preloadModules, loaders);
  }
 
  isESMInitialized = true;
}
 
function loadModulesInIsolation(specifiers, loaders = []) {
  if (!ArrayIsArray(specifiers) || specifiers.length === 0) { return; }
 
  let cwd;
  try {
    cwd = process.cwd() + '/';
  } catch {
    cwd = 'file:///';
  }
 
  // A separate loader instance is necessary to avoid cross-contamination
  // between internal Node.js and userland. For example, a module with internal
  // state (such as a counter) should be independent.
  const internalEsmLoader = new ESMLoader();
  internalEsmLoader.addCustomLoaders(loaders);
 
  // Importation must be handled by internal loader to avoid poluting userland
  return internalEsmLoader.import(
    specifiers,
    pathToFileURL(cwd).href,
    ObjectCreate(null),
  );
}
 
exports.loadESM = async function loadESM(callback) {
  try {
    await initializeLoader();
    await callback(esmLoader);
  } catch (err) {
    if (hasUncaughtExceptionCaptureCallback()) {
      process._fatalException(err);
      return;
    }
    internalBinding('errors').triggerUncaughtException(
      err,
      true /* fromPromise */
    );
  }
};