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

99.23% Statements 129/130
89.65% Branches 26/29
100% Functions 6/6
99.23% Lines 129/130

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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 143x 43x 43x 43x 43x 43x 43x 43x 43x 143x 143x 143x 143x 143x 143x 143x 1042x 1042x 1042x 1042x 469x 469x 573x 573x 587x 17x 17x 17x 17x 7x 17x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 7x 7x   1042x 1042x 143x 143x 143x 143x 143x 143x 74x 74x 74x 74x 74x 60x 60x 74x 74x 74x 143x 143x 143x 143x 143x 143x 1354x 1354x 1354x 1354x 1354x 1354x 143x 143x 143x 143x 143x 143x 220x 220x 220x 220x 220x 220x 143x 143x 143x 143x 143x 143x  
'use strict';
const {
  RegExpPrototypeExec,
  ObjectAssign,
  ObjectCreate,
  ObjectPrototypeHasOwnProperty,
  PromisePrototypeThen,
  PromiseResolve,
  StringPrototypeSlice,
} = primordials;
const { basename, extname, relative } = require('path');
const { getOptionValue } = require('internal/options');
const { fetchModule } = require('internal/modules/esm/fetch_module');
const {
  extensionFormatMap,
  getLegacyExtensionFormat,
  mimeToFormat,
} = require('internal/modules/esm/formats');
 
const experimentalNetworkImports =
  getOptionValue('--experimental-network-imports');
const experimentalSpecifierResolution =
  getOptionValue('--experimental-specifier-resolution');
const { getPackageType, getPackageScopeConfig } = require('internal/modules/esm/resolve');
const { URL, fileURLToPath } = require('internal/url');
const { ERR_UNKNOWN_FILE_EXTENSION } = require('internal/errors').codes;
 
const protocolHandlers = ObjectAssign(ObjectCreate(null), {
  'data:': getDataProtocolModuleFormat,
  'file:': getFileProtocolModuleFormat,
  'http:': getHttpProtocolModuleFormat,
  'https:': getHttpProtocolModuleFormat,
  'node:'() { return 'builtin'; },
});
 
/**
 * @param {URL} parsed
 * @returns {string | null}
 */
function getDataProtocolModuleFormat(parsed) {
  const { 1: mime } = RegExpPrototypeExec(
    /^([^/]+\/[^;,]+)(?:[^,]*?)(;base64)?,/,
    parsed.pathname,
  ) || [ null, null, null ];
 
  return mimeToFormat(mime);
}
 
/**
 * @param {URL} url
 * @param {{parentURL: string}} context
 * @param {boolean} ignoreErrors
 * @returns {string}
 */
function getFileProtocolModuleFormat(url, context, ignoreErrors) {
  const filepath = fileURLToPath(url);
  const ext = extname(filepath);
  if (ext === '.js') {
    return getPackageType(url) === 'module' ? 'module' : 'commonjs';
  }
 
  const format = extensionFormatMap[ext];
  if (format) return format;
 
  if (experimentalSpecifierResolution !== 'node') {
    // Explicit undefined return indicates load hook should rerun format check
    if (ignoreErrors) return undefined;
    let suggestion = '';
    if (getPackageType(url) === 'module' && ext === '') {
      const config = getPackageScopeConfig(url);
      const fileBasename = basename(filepath);
      const relativePath = StringPrototypeSlice(relative(config.pjsonPath, filepath), 1);
      suggestion = 'Loading extensionless files is not supported inside of ' +
        '"type":"module" package.json contexts. The package.json file ' +
        `${config.pjsonPath} caused this "type":"module" context. Try ` +
        `changing ${filepath} to have a file extension. Note the "bin" ` +
        'field of package.json can point to a file with an extension, for example ' +
        `{"type":"module","bin":{"${fileBasename}":"${relativePath}.js"}}`;
    }
    throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath, suggestion);
  }

  return getLegacyExtensionFormat(ext) ?? null;
}
 
/**
 * @param {URL} url
 * @param {{parentURL: string}} context
 * @returns {Promise<string> | undefined} only works when enabled
 */
function getHttpProtocolModuleFormat(url, context) {
  if (experimentalNetworkImports) {
    return PromisePrototypeThen(
      PromiseResolve(fetchModule(url, context)),
      (entry) => {
        return mimeToFormat(entry.headers['content-type']);
      }
    );
  }
}
 
/**
 * @param {URL | URL['href']} url
 * @param {{parentURL: string}} context
 * @returns {Promise<string> | string | undefined} only works when enabled
 */
function defaultGetFormatWithoutErrors(url, context) {
  const parsed = new URL(url);
  if (!ObjectPrototypeHasOwnProperty(protocolHandlers, parsed.protocol))
    return null;
  return protocolHandlers[parsed.protocol](parsed, context, true);
}
 
/**
 * @param {URL | URL['href']} url
 * @param {{parentURL: string}} context
 * @returns {Promise<string> | string | undefined} only works when enabled
 */
function defaultGetFormat(url, context) {
  const parsed = new URL(url);
  return ObjectPrototypeHasOwnProperty(protocolHandlers, parsed.protocol) ?
    protocolHandlers[parsed.protocol](parsed, context, false) :
    null;
}
 
module.exports = {
  defaultGetFormat,
  defaultGetFormatWithoutErrors,
  extensionFormatMap,
};