// Manually “tree shaken” from: // // Last checked on: Apr 24, 2023. import {URL, fileURLToPath} from 'node:url' import {getPackageType} from './resolve-get-package-type.js' import {codes} from './errors.js' const {ERR_UNKNOWN_FILE_EXTENSION} = codes const hasOwnProperty = {}.hasOwnProperty /** @type {Record} */ const extensionFormatMap = { // @ts-expect-error: hush. __proto__: null, '.cjs': 'commonjs', '.js': 'module', '.json': 'json', '.mjs': 'module' } /** * @param {string | null} mime * @returns {string | null} */ function mimeToFormat(mime) { if ( mime && /\s*(text|application)\/javascript\s*(;\s*charset=utf-?8\s*)?/i.test(mime) ) return 'module' if (mime === 'application/json') return 'json' return null } /** * @callback ProtocolHandler * @param {URL} parsed * @param {{parentURL: string}} context * @param {boolean} ignoreErrors * @returns {string | null | void} */ /** * @type {Record} */ const protocolHandlers = { // @ts-expect-error: hush. __proto__: null, 'data:': getDataProtocolModuleFormat, 'file:': getFileProtocolModuleFormat, 'http:': getHttpProtocolModuleFormat, 'https:': getHttpProtocolModuleFormat, 'node:'() { return 'builtin' } } /** * @param {URL} parsed */ function getDataProtocolModuleFormat(parsed) { const {1: mime} = /^([^/]+\/[^;,]+)[^,]*?(;base64)?,/.exec( parsed.pathname ) || [null, null, null] return mimeToFormat(mime) } /** * Returns the file extension from a URL. * * Should give similar result to * `require('node:path').extname(require('node:url').fileURLToPath(url))` * when used with a `file:` URL. * * @param {URL} url * @returns {string} */ function extname(url) { const pathname = url.pathname let index = pathname.length while (index--) { const code = pathname.codePointAt(index) if (code === 47 /* `/` */) { return '' } if (code === 46 /* `.` */) { return pathname.codePointAt(index - 1) === 47 /* `/` */ ? '' : pathname.slice(index) } } return '' } /** * @type {ProtocolHandler} */ function getFileProtocolModuleFormat(url, _context, ignoreErrors) { const ext = extname(url) if (ext === '.js') { return getPackageType(url) === 'module' ? 'module' : 'commonjs' } const format = extensionFormatMap[ext] if (format) return format // Explicit undefined return indicates load hook should rerun format check if (ignoreErrors) { return undefined } const filepath = fileURLToPath(url) throw new ERR_UNKNOWN_FILE_EXTENSION(ext, filepath) } function getHttpProtocolModuleFormat() { // To do: HTTPS imports. } /** * @param {URL} url * @param {{parentURL: string}} context * @returns {string | null} */ export function defaultGetFormatWithoutErrors(url, context) { if (!hasOwnProperty.call(protocolHandlers, url.protocol)) { return null } return protocolHandlers[url.protocol](url, context, true) || null } /** * @param {string} url * @param {{parentURL: string}} context * @returns {null | string | void} */ export function defaultGetFormat(url, context) { const parsed = new URL(url) return hasOwnProperty.call(protocolHandlers, parsed.protocol) ? protocolHandlers[parsed.protocol](parsed, context, false) : null }