text: // Copied from https://github.com/nodejs/node/blob/v13.12.0/lib/internal/modules/esm/resolve.js
  
  'use strict';
  
  const {
    ArrayIsArray,
    JSONParse,
    JSONStringify,
    ObjectGetOwnPropertyNames,
    ObjectPrototypeHasOwnProperty,
    SafeMap,
    StringPrototypeEndsWith,
    StringPrototypeIncludes,
    StringPrototypeIndexOf,
    StringPrototypeSlice,
    StringPrototypeStartsWith,
    StringPrototypeSubstr,
  } = primordials;
  
  const internalFS = require('internal/fs/utils');
  const { NativeModule } = require('internal/bootstrap/loaders');
  const {
    closeSync,
    fstatSync,
    openSync,
    readFileSync,
    realpathSync,
    statSync,
    Stats,
  } = require('fs');
  const { getOptionValue } = require('internal/options');
  const { sep } = require('path');
  
  const preserveSymlinks = getOptionValue('--preserve-symlinks');
  const preserveSymlinksMain = getOptionValue('--preserve-symlinks-main');
  const typeFlag = getOptionValue('--input-type');
  const { URL, pathToFileURL, fileURLToPath } = require('internal/url');
  const {
    ERR_INPUT_TYPE_NOT_ALLOWED,
    ERR_INVALID_MODULE_SPECIFIER,
    ERR_INVALID_PACKAGE_CONFIG,
    ERR_INVALID_PACKAGE_TARGET,
    ERR_MODULE_NOT_FOUND,
    ERR_PACKAGE_PATH_NOT_EXPORTED,
    ERR_UNSUPPORTED_ESM_URL_SCHEME,
  } = require('internal/errors').codes;
  
  const realpathCache = new SafeMap();
  const packageJSONCache = new SafeMap();  /* string -> PackageConfig */
  
  function tryStatSync(path) {
    try {
      return statSync(path);
    } catch {
      return new Stats();
    }
  }
  
  function readIfFile(path) {
    let fd;
    try {
      fd = openSync(path, 'r');
    } catch {
      return undefined;
    }
    try {
      if (!fstatSync(fd).isFile()) return undefined;
      return readFileSync(fd, 'utf8');
    } finally {
      closeSync(fd);
    }
  }
  
  function getPackageConfig(path, base) {
    const existing = packageJSONCache.get(path);
    if (existing !== undefined) {
      if (!existing.isValid) {
        throw new ERR_INVALID_PACKAGE_CONFIG(path, fileURLToPath(base), false);
      }
      return existing;
    }
  
    const source = readIfFile(path);
    if (source === undefined) {
      const packageConfig = {
        exists: false,
        main: undefined,
        name: undefined,
        isValid: true,
        type: 'none',
        exports: undefined
      };
      packageJSONCache.set(path, packageConfig);
      return packageConfig;
    }
  
    let packageJSON;
    try {
      packageJSON = JSONParse(source);
    } catch {
      const packageConfig = {
        exists: true,
        main: undefined,
        name: undefined,
        isValid: false,
        type: 'none',
        exports: undefined
      };
      packageJSONCache.set(path, packageConfig);
      return packageConfig;
    }
  
    let { main, name, type } = packageJSON;
    const { exports } = packageJSON;
    if (typeof main !== 'string') main = undefined;
    if (typeof name !== 'string') name = undefined;
    // Ignore unknown types for forwards compatibility
    if (type !== 'module' && type !== 'commonjs') type = 'none';
  
    const packageConfig = {
      exists: true,
      main,
      name,
      isValid: true,
      type,
      exports
    };
    packageJSONCache.set(path, packageConfig);
    return packageConfig;
  }
  
  function getPackageScopeConfig(resolved, base) {
    let packageJSONUrl = new URL('./package.json', resolved);
    while (true) {
      const packageJSONPath = packageJSONUrl.pathname;
      if (StringPrototypeEndsWith(packageJSONPath, 'node_modules/package.json'))
        break;
      const packageConfig = getPackageConfig(fileURLToPath(packageJSONUrl), base);
      if (packageConfig.exists) return packageConfig;
  
      const lastPackageJSONUrl = packageJSONUrl;
      packageJSONUrl = new URL('../package.json', packageJSONUrl);
  
      // Terminates at root where ../package.json equals ../../package.json
      // (can't just check "/package.json" for Windows support).
      if (packageJSONUrl.pathname === lastPackageJSONUrl.pathname) break;
    }
    const packageConfig = {
      exists: false,
      main: undefined,
      name: undefined,
      isValid: true,
      type: 'none',
      exports: undefined
    };
    packageJSONCache.set(fileURLToPath(packageJSONUrl), packageConfig);
    return packageConfig;
  }
  
  /*
   * Legacy CommonJS main resolution:
   * 1. let M = pkg_url + (json main field)
   * 2. TRY(M, M.js, M.json, M.node)
   * 3. TRY(M/index.js, M/index.json, M/index.node)
   * 4. TRY(pkg_url/index.js, pkg_url/index.json, pkg_url/index.node)
   * 5. NOT_FOUND
   */
  function fileExists(url) {
    return tryStatSync(fileURLToPath(url)).isFile();
  }
  
  function legacyMainResolve(packageJSONUrl, packageConfig) {
    let guess;
    if (packageConfig.main !== undefined) {
      // Note: fs check redundances will be handled by Descriptor cache here.
      if (fileExists(guess = new URL(`./${packageConfig.main}`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}.js`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}.json`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}.node`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}/index.js`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}/index.json`,
                                     packageJSONUrl))) {
        return guess;
      }
      if (fileExists(guess = new URL(`./${packageConfig.main}/index.node`,
                                     packageJSONUrl))) {
        return guess;
      }
      // Fallthrough.
    }
    if (fileExists(guess = new URL('./index.js', packageJSONUrl))) {
      return guess;
    }
    // So fs.
    if (fileExists(guess = new URL('./index.json', packageJSONUrl))) {
      return guess;
    }
    if (fileExists(guess = new URL('./index.node', packageJSONUrl))) {
      return guess;
    }
    // Not found.
    return undefined;
  }
  
  function resolveExtensionsWithTryExactName(search) {
    if (fileExists(search)) return search;
    return resolveExtensions(search);
  }
  
  const extensions = ['.js', '.json', '.node', '.mjs'];
  function resolveExtensions(search) {
    for (let i = 0; i < extensions.length; i++) {
      const extension = extensions[i];
      const guess = new URL(`${search.pathname}${extension}`, search);
      if (fileExists(guess)) return guess;
    }
    return undefined;
  }
  
  function resolveIndex(search) {
    return resolveExtensions(new URL('index', search));
  }
  
  function finalizeResolution(resolved, base) {
    if (getOptionValue('--experimental-specifier-resolution') === 'node') {
      let file = resolveExtensionsWithTryExactName(resolved);
      if (file !== undefined) return file;
      if (!StringPrototypeEndsWith(resolved.pathname, '/')) {
        file = resolveIndex(new URL(`${resolved.pathname}/`, base));
      } else {
        file = resolveIndex(resolved);
      }
      if (file !== undefined) return file;
      throw new ERR_MODULE_NOT_FOUND(
        resolved.pathname, fileURLToPath(base), 'module');
    }
  
    if (StringPrototypeEndsWith(resolved.pathname, '/')) return resolved;
    const path = fileURLToPath(resolved);
  
    if (!tryStatSync(path).isFile()) {
      throw new ERR_MODULE_NOT_FOUND(
        path || resolved.pathname, fileURLToPath(base), 'module');
    }
  
    return resolved;
  }
  
  function throwExportsNotFound(subpath, packageJSONUrl, base) {
    throw new ERR_PACKAGE_PATH_NOT_EXPORTED(
      fileURLToPath(packageJSONUrl), subpath, fileURLToPath(base));
  }
  
  function throwSubpathInvalid(subpath, packageJSONUrl, base) {
    throw new ERR_INVALID_MODULE_SPECIFIER(
      fileURLToPath(packageJSONUrl), subpath, fileURLToPath(base));
  }
  
  function throwExportsInvalid(
    subpath, target, packageJSONUrl, base) {
    if (typeof target === 'object' && target !== null) {
      target = JSONStringify(target, null, '');
    } else if (ArrayIsArray(target)) {
      target = `[${target}]`;
    } else {
      target = `${target}`;
    }
    throw new ERR_INVALID_PACKAGE_TARGET(
      fileURLToPath(packageJSONUrl), null, subpath, target, fileURLToPath(base));
  }
  
  function resolveExportsTargetString(
    target, subpath, match, packageJSONUrl, base) {
    if (target[0] !== '.' || target[1] !== '/' ||
        (subpath !== '' && target[target.length - 1] !== '/')) {
      throwExportsInvalid(match, target, packageJSONUrl, base);
    }
  
    const resolved = new URL(target, packageJSONUrl);
    const resolvedPath = resolved.pathname;
    const packagePath = new URL('.', packageJSONUrl).pathname;
  
    if (!StringPrototypeStartsWith(resolvedPath, packagePath) ||
        StringPrototypeIncludes(
          resolvedPath, '/node_modules/', packagePath.length - 1)) {
      throwExportsInvalid(match, target, packageJSONUrl, base);
    }
  
    if (subpath === '') return resolved;
    const subpathResolved = new URL(subpath, resolved);
    const subpathResolvedPath = subpathResolved.pathname;
    if (!StringPrototypeStartsWith(subpathResolvedPath, resolvedPath) ||
        StringPrototypeIncludes(subpathResolvedPath,
                                '/node_modules/', packagePath.length - 1)) {
      throwSubpathInvalid(match + subpath, packageJSONUrl, base);
    }
    return subpathResolved;
  }
  
  function isArrayIndex(key /* string */) { /* -> boolean */
    const keyNum = +key;
    if (`${keyNum}` !== key) return false;
    return keyNum >= 0 && keyNum < 0xFFFF_FFFF;
  }
  
  function resolveExportsTarget(
    packageJSONUrl, target, subpath, packageSubpath, base) {
    if (typeof target === 'string') {
      const resolved = resolveExportsTargetString(
        target, subpath, packageSubpath, packageJSONUrl, base);
      return finalizeResolution(resolved, base);
    } else if (ArrayIsArray(target)) {
      if (target.length === 0)
        throwExportsInvalid(packageSubpath, target, packageJSONUrl, base);
  
      let lastException;
      for (let i = 0; i < target.length; i++) {
        const targetItem = target[i];
        let resolved;
        try {
          resolved = resolveExportsTarget(
            packageJSONUrl, targetItem, subpath, packageSubpath, base);
        } catch (e) {
          lastException = e;
          if (e.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED' ||
              e.code === 'ERR_INVALID_PACKAGE_TARGET') {
            continue;
          }
          throw e;
        }
  
        return finalizeResolution(resolved, base);
      }
      throw lastException;
    } else if (typeof target === 'object' && target !== null) {
      const keys = ObjectGetOwnPropertyNames(target);
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        if (isArrayIndex(key)) {
          throw new ERR_INVALID_PACKAGE_CONFIG(
            fileURLToPath(packageJSONUrl),
            '"exports" cannot contain numeric property keys');
        }
      }
      for (let i = 0; i < keys.length; i++) {
        const key = keys[i];
        if (key === 'node' || key === 'import' || key === 'default') {
          const conditionalTarget = target[key];
          try {
            return resolveExportsTarget(
              packageJSONUrl, conditionalTarget, subpath, packageSubpath, base);
          } catch (e) {
            if (e.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') continue;
            throw e;
          }
        }
      }
      throwExportsNotFound(packageSubpath, packageJSONUrl, base);
    }
    throwExportsInvalid(packageSubpath, target, packageJSONUrl, base);
  }
  
  function isConditionalExportsMainSugar(exports, packageJSONUrl, base) {
    if (typeof exports === 'string' || ArrayIsArray(exports)) return true;
    if (typeof exports !== 'object' || exports === null) return false;
  
    const keys = ObjectGetOwnPropertyNames(exports);
    let isConditionalSugar = false;
    let i = 0;
    for (let j = 0; j < keys.length; j++) {
      const key = keys[j];
      const curIsConditionalSugar = key === '' || key[0] !== '.';
      if (i++ === 0) {
        isConditionalSugar = curIsConditionalSugar;
      } else if (isConditionalSugar !== curIsConditionalSugar) {
        throw new ERR_INVALID_PACKAGE_CONFIG(
          fileURLToPath(packageJSONUrl),
          '"exports" cannot contain some keys starting with \'.\' and some not.' +
          ' The exports object must either be an object of package subpath keys' +
          ' or an object of main entry condition name keys only.');
      }
    }
    return isConditionalSugar;
  }
  
  
  function packageMainResolve(packageJSONUrl, packageConfig, base) {
    if (packageConfig.exists) {
      const exports = packageConfig.exports;
      if (exports !== undefined) {
        if (isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
          return resolveExportsTarget(packageJSONUrl, exports, '', '', base);
        } else if (typeof exports === 'object' && exports !== null) {
          const target = exports['.'];
          if (target !== undefined)
            return resolveExportsTarget(packageJSONUrl, target, '', '', base);
        }
  
        throw new ERR_PACKAGE_PATH_NOT_EXPORTED(packageJSONUrl, '.');
      }
      if (packageConfig.main !== undefined) {
        const resolved = new URL(packageConfig.main, packageJSONUrl);
        const path = fileURLToPath(resolved);
        if (tryStatSync(path).isFile()) return resolved;
      }
      if (getOptionValue('--experimental-specifier-resolution') === 'node') {
        if (packageConfig.main !== undefined) {
          return finalizeResolution(
            new URL(packageConfig.main, packageJSONUrl), base);
        } else {
          return finalizeResolution(
            new URL('index', packageJSONUrl), base);
        }
      }
      if (packageConfig.type !== 'module') {
        return legacyMainResolve(packageJSONUrl, packageConfig);
      }
    }
  
    throw new ERR_MODULE_NOT_FOUND(
      fileURLToPath(new URL('.', packageJSONUrl)), fileURLToPath(base));
  }
  
  
  function packageExportsResolve(
    packageJSONUrl, packageSubpath, packageConfig, base) /* -> URL */ {
    const exports = packageConfig.exports;
    if (exports === undefined ||
        isConditionalExportsMainSugar(exports, packageJSONUrl, base)) {
      throwExportsNotFound(packageSubpath, packageJSONUrl, base);
    }
  
  
    if (ObjectPrototypeHasOwnProperty(exports, packageSubpath)) {
      const target = exports[packageSubpath];
      const resolved = resolveExportsTarget(
        packageJSONUrl, target, '', packageSubpath, base);
      return finalizeResolution(resolved, base);
    }
  
    let bestMatch = '';
    const keys = ObjectGetOwnPropertyNames(exports);
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      if (key[key.length - 1] !== '/') continue;
      if (StringPrototypeStartsWith(packageSubpath, key) &&
          key.length > bestMatch.length) {
        bestMatch = key;
      }
    }
  
    if (bestMatch) {
      const target = exports[bestMatch];
      const subpath = StringPrototypeSubstr(packageSubpath, bestMatch.length);
      const resolved = resolveExportsTarget(
        packageJSONUrl, target, subpath, packageSubpath, base);
      return finalizeResolution(resolved, base);
    }
  
    throwExportsNotFound(packageSubpath, packageJSONUrl, base);
  }
  
  function getPackageType(url) {
    const packageConfig = getPackageScopeConfig(url, url);
    return packageConfig.type;
  }
  
  function packageResolve(specifier /* string */, base /* URL */) { /* -> URL */
    let separatorIndex = StringPrototypeIndexOf(specifier, '/');
    let validPackageName = true;
    let isScoped = false;
    if (specifier[0] === '@') {
      isScoped = true;
      if (separatorIndex === -1 || specifier.length === 0) {
        validPackageName = false;
      } else {
        separatorIndex = StringPrototypeIndexOf(
          specifier, '/', separatorIndex + 1);
      }
    }
  
    const packageName = separatorIndex === -1 ?
      specifier : StringPrototypeSlice(specifier, 0, separatorIndex);
  
    // Package name cannot have leading . and cannot have percent-encoding or
    // separators.
    for (let i = 0; i < packageName.length; i++) {
      if (packageName[i] === '%' || packageName[i] === '\\') {
        validPackageName = false;
        break;
      }
    }
  
    if (!validPackageName) {
      throw new ERR_INVALID_MODULE_SPECIFIER(
        specifier, undefined, fileURLToPath(base));
    }
  
    const packageSubpath = separatorIndex === -1 ?
      '' : '.' + StringPrototypeSlice(specifier, separatorIndex);
  
    // ResolveSelf
    const packageConfig = getPackageScopeConfig(base, base);
    if (packageConfig.exists) {
      // TODO(jkrems): Find a way to forward the pair/iterator already generated
      // while executing GetPackageScopeConfig
      let packageJSONUrl;
      for (const [ filename, packageConfigCandidate ] of packageJSONCache) {
        if (packageConfig === packageConfigCandidate) {
          packageJSONUrl = pathToFileURL(filename);
          break;
        }
      }
      if (packageJSONUrl !== undefined &&
          packageConfig.name === packageName &&
          packageConfig.exports !== undefined) {
        if (packageSubpath === './') {
          return new URL('./', packageJSONUrl);
        } else if (packageSubpath === '') {
          return packageMainResolve(packageJSONUrl, packageConfig, base);
        } else {
          return packageExportsResolve(
            packageJSONUrl, packageSubpath, packageConfig, base);
        }
      }
    }
  
    let packageJSONUrl =
      new URL('./node_modules/' + packageName + '/package.json', base);
    let packageJSONPath = fileURLToPath(packageJSONUrl);
    let lastPath;
    do {
      const stat = tryStatSync(
        StringPrototypeSlice(packageJSONPath, 0, packageJSONPath.length - 13));
      if (!stat.isDirectory()) {
        lastPath = packageJSONPath;
        packageJSONUrl = new URL((isScoped ?
          '../../../../node_modules/' : '../../../node_modules/') +
          packageName + '/package.json', packageJSONUrl);
        packageJSONPath = fileURLToPath(packageJSONUrl);
        continue;
      }
  
      // Package match.
      const packageConfig = getPackageConfig(packageJSONPath, base);
      if (packageSubpath === './') {
        return new URL('./', packageJSONUrl);
      } else if (packageSubpath === '') {
        return packageMainResolve(packageJSONUrl, packageConfig, base);
      } else if (packageConfig.exports !== undefined) {
        return packageExportsResolve(
          packageJSONUrl, packageSubpath, packageConfig, base);
      } else {
        return finalizeResolution(
          new URL(packageSubpath, packageJSONUrl), base);
      }
      // Cross-platform root check.
    } while (packageJSONPath.length !== lastPath.length);
  
    // eslint can't handle the above code.
    // eslint-disable-next-line no-unreachable
    throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base));
  }
  
  function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) {
    if (specifier === '') return false;
    if (specifier[0] === '/') return true;
    if (specifier[0] === '.') {
      if (specifier.length === 1 || specifier[1] === '/') return true;
      if (specifier[1] === '.') {
        if (specifier.length === 2 || specifier[2] === '/') return true;
      }
    }
    return false;
  }
  
  function moduleResolve(specifier /* string */, base /* URL */) { /* -> URL */
    // Order swapped from spec for minor perf gain.
    // Ok since relative URLs cannot parse as URLs.
    let resolved;
    if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) {
      resolved = new URL(specifier, base);
    } else {
      try {
        resolved = new URL(specifier);
      } catch {
        return packageResolve(specifier, base);
      }
    }
    return finalizeResolution(resolved, base);
  }
  
  function defaultResolve(specifier, { parentURL } = {}, defaultResolveUnused) {
    let parsed;
    try {
      parsed = new URL(specifier);
      if (parsed.protocol === 'data:') {
        return {
          url: specifier
        };
      }
    } catch {}
    if (parsed && parsed.protocol === 'nodejs:')
      return { url: specifier };
    if (parsed && parsed.protocol !== 'file:' && parsed.protocol !== 'data:')
      throw new ERR_UNSUPPORTED_ESM_URL_SCHEME();
    if (NativeModule.canBeRequiredByUsers(specifier)) {
      return {
        url: 'nodejs:' + specifier
      };
    }
    if (parentURL && StringPrototypeStartsWith(parentURL, 'data:')) {
      // This is gonna blow up, we want the error
      new URL(specifier, parentURL);
    }
  
    const isMain = parentURL === undefined;
    if (isMain) {
      parentURL = pathToFileURL(`${process.cwd()}/`).href;
  
      // This is the initial entry point to the program, and --input-type has
      // been passed as an option; but --input-type can only be used with
      // --eval, --print or STDIN string input. It is not allowed with file
      // input, to avoid user confusion over how expansive the effect of the
      // flag should be (i.e. entry point only, package scope surrounding the
      // entry point, etc.).
      if (typeFlag)
        throw new ERR_INPUT_TYPE_NOT_ALLOWED();
    }
  
    let url = moduleResolve(specifier, new URL(parentURL));
  
    if (isMain ? !preserveSymlinksMain : !preserveSymlinks) {
      const urlPath = fileURLToPath(url);
      const real = realpathSync(urlPath, {
        [internalFS.realpathCacheKey]: realpathCache
      });
      const old = url;
      url = pathToFileURL(real + (urlPath.endsWith(sep) ? '/' : ''));
      url.search = old.search;
      url.hash = old.hash;
    }
  
    return { url: `${url}` };
  }
  
  module.exports = {
    defaultResolve,
    getPackageType
  };
  