 false
});


// internalBindingAllowlist contains the name of internalBinding modules
// that are allowed for access via process.binding()... This is used
// to provide a transition path for modules that are being moved over to
// internalBinding.
const internalBindingAllowlist = new SafeSet([
  'async_wrap',
  'buffer',
  'cares_wrap',
  'config',
  'constants',
  'contextify',
  'crypto',
  'fs',
  'fs_event_wrap',
  'http_parser',
  'icu',
  'inspector',
  'js_stream',
  'natives',
  'os',
  'pipe_wrap',
  'process_wrap',
  'signal_wrap',
  'spawn_sync',
  'stream_wrap',
  'tcp_wrap',
  'tls_wrap',
  'tty_wrap',
  'udp_wrap',
  'url',
  'util',
  'uv',
  'v8',
  'zlib',
]);

const runtimeDeprecatedList = new SafeSet([
  'async_wrap',
  'crypto',
  'http_parser',
  'signal_wrap',
  'url',
  'v8',
]);

const legacyWrapperList = new SafeSet([
  'util',
]);

// Modules that can only be imported via the node: scheme.
const schemelessBlockList = new SafeSet([
  'test',
]);

// Set up process.binding() and process._linkedBinding().
{
  const bindingObj = ObjectCreate(null);

  process.binding = function binding(module) {
    module = String(module);
    // Deprecated specific process.binding() modules, but not all, allow
    // selective fallback to internalBinding for the deprecated ones.
    if (internalBindingAllowlist.has(module)) {
      if (runtimeDeprecatedList.has(module)) {
        runtimeDeprecatedList.delete(module);
        process.emitWarning(
          `Access to process.binding('${module}') is deprecated.`,
          'DeprecationWarning',
          'DEP0111');
      }
      if (legacyWrapperList.has(module)) {
        return nativeModuleRequire('internal/legacy/processbinding')[module]();
      }
      return internalBinding(module);
    }
    // eslint-disable-next-line no-restricted-syntax
    throw new Error(`No such module: ${module}`);
  };

  process._linkedBinding = function _linkedBinding(module) {
    module = String(module);
    let mod = bindingObj[module];
    if (typeof mod !== 'object')
      mod = bindingObj[module] = getLinkedBinding(module);
    return mod;
  };
}

// Set up internalBinding() in the closure.
/**
 * @type {InternalBinding}
 */
let internalBinding;
{
  const bindingObj = ObjectCreate(null);
  // eslint-disable-next-line no-global-assign
  internalBinding = function internalBinding(module) {
    let mod = bindingObj[module];
    if (typeof mod !== 'object') {
      mod = bindingObj[module] = getInternalBinding(module);
      ArrayPrototypePush(moduleLoadList, `Internal Binding ${module}`);
    }
    return mod;
  };
}

const loaderId = 'internal/bootstrap/loaders';
const {
  moduleIds,
  compileFunction
} = internalBinding('native_module');

const getOwn = (target, property, receiver) => {
  return ObjectPrototypeHasOwnProperty(target, property) ?
    ReflectGet(target, property, receiver) :
    undefined;
};

/**
 * An internal abstraction for the built-in JavaScript modules of Node.js.
 * Be careful not to expose this to user land unless --expose-internals is
 * used, in which case there is no compatibility guarantee about this class.
 */
class NativeModule {
  /**
   * A map from the module IDs to the module instances.
   * @type {Map<string, NativeModule>}
   */
  static map = new SafeMap(
    ArrayPrototypeMap(moduleIds, (id) => [id, new NativeModule(id)])
  );

  constructor(id) {
    this.filename = `${id}.js`;
    this.id = id;
    this.canBeRequiredByUsers = !StringPrototypeStartsWith(id, 'internal/');

    // The CJS exports object of the module.
    this.exports = {};
    // States used to work around circular dependencies.
    this.loaded = false;
    this.loading = false;

    // The following properties are used by the ESM implementation and only
    // initialized when the native module is loaded by users.
    /**
     * The C++ ModuleWrap binding used to interface with the ESM implementation.
     * @type {ModuleWrap|undefined}
     */
    this.module = undefined;
    /**
     * Exported names for the ESM imports.
     * @type {string[]|undefined}
     */
    this.exportKeys = undefined;
  }

  // To be called during pre-execution when --expose-internals is on.
  // Enables the user-land module loader to access internal modules.
  static exposeInternals() {
    for (const { 0: id, 1: mod } of NativeModule.map) {
      // Do not expose this to user land even with --expose-internals.
      if (id !== loaderId) {
        mod.canBeRequiredByUsers = true;
      }
    }
  }

  static exists(id) {
    return NativeModule.map.has(id);
  }

  static canBeRequiredByUsers(id) {
    const mod = NativeModule.map.get(id);
    return mod && mod.canBeRequiredByUsers;
  }

  // Determine if a core module can be loaded without the node: prefix. This
  // function does not validate if the module actually exists.
  static canBeRequiredWithoutScheme(id) {
    return !schemelessBlockList.has(id);
  }

  static getSchemeOnlyModuleNames() {
    return ArrayFrom(schemelessBlockList);
  }

  // Used by user-land module loaders to compile and load builtins.
  compileForPublicLoader() {
    if (!this.canBeRequiredByUsers) {
      // No code because this is an assertion against bugs
      // eslint-disable-next-line no-restricted-syntax
      throw new Error(`Should not compile ${this.id} for public use`);
    }
    this.compileForInternalLoader();
    if (!this.exportKeys) {
      // When using --expose-internals, we do not want to reflect the named
      // exports from core modules as this can trigger unnecessary getters.
      const internal = StringPrototypeStartsWith(this.id, 'internal/');
      this.exportKeys = internal ? [] : ObjectKeys(this.exports);
    }
    this.getESMFacade();
    this.syncExports();
    return this.exports;
  }

  getESMFacade() {
    if (this.module) return this.module;
    const { ModuleWrap } = internalBinding('module_wrap');
    const url = `node:${this.id}`;
    const nativeModule = this;
    const exportsKeys = ArrayPrototypeSlice(this.exportKeys);
    ArrayPrototypePush(exportsKeys, 'default');
    this.module = new ModuleWrap(
      url, undefined, exportsKeys,
      function() {
        nativeModule.syncExports();
        this.setExport('default', nativeModule.exports);
      });
    // Ensure immediate sync execution to capture exports now
    this.module.instantiate();
    this.module.evaluate(-1, false);
    return this.module;
  }

  // Provide named exports for all builtin libraries so that the libraries
  // may be imported in a nicer way for ESM users. The default export is left
  // as the entire namespace (module.exports) and updates when this function is
  // called so that APMs and other behavior are supported.
  syncExports() {
    const names = this.exportKeys;
    if (this.module) {
      for (let i = 0; i < names.length; i++) {
        const exportName = names[i];
        if (exportName === 'default') continue;
        this.module.setExport(exportName,
                              getOwn(this.exports, exportName, this.exports));
      }
    }
  }

  compileForInternalLoader() {
    if (this.loaded || this.loading) {
      return this.exports;
    }

    const id = this.id;
    this.loading = true;

    try {
      const requireFn = StringPrototypeStartsWith(this.id, 'internal/deps/') ?
        requireWithFallbackInDeps : nativeModuleRequire;

      const fn = compileFunction(id);
      fn(this.exports, requireFn, this, process, internalBinding, primordials);

      this.loaded = true;
    } finally {
      this.loading = false;
    }

    ArrayPrototypePush(moduleLoadList, `NativeModule ${id}`);
    return this.exports;
  }
}

// Think of this as module.exports in this file even though it is not
// written in CommonJS style.
const loaderExports = {
  internalBinding,
  NativeModule,
  require: nativeModuleRequire
};

function nativeModuleRequire(id) {
  if (id === loaderId) {
    return loaderExports;
  }

  const mod = NativeModule.map.get(id);
  // Can't load the internal errors module from here, have to use a raw error.
  // eslint-disable-next-line no-restricted-syntax
  if (!mod) throw new TypeError(`Missing internal module '${id}'`);
  return mod.compileForInternalLoader();
}

// Allow internal modules from dependencies to require
// other modules from dependencies by providing fallbacks.
function requireWithFallbackInDeps(request) {
  if (!NativeModule.map.has(request)) {
    request = `internal/deps/${request}`;
  }
  return nativeModuleRequire(request);
}

// Pass the exports back to C++ land for C++ internals to use.
return loaderExports;
