// Manually “tree shaken” from: // // Last checked on: Nov 2, 2023. import {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, source?: Buffer}} 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') { const packageType = getPackageType(url) if (packageType !== 'none') { return packageType } return 'commonjs' } if (ext === '') { const packageType = getPackageType(url) // Legacy behavior if (packageType === 'none' || packageType === 'commonjs') { return 'commonjs' } // Note: we don’t implement WASM, so we don’t need // `getFormatOfExtensionlessFile` from `formats`. return 'module' } 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) { const protocol = url.protocol if (!hasOwnProperty.call(protocolHandlers, protocol)) { return null } return protocolHandlers[protocol](url, context, true) || null }