| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- // Manually “tree shaken” from:
- // <https://github.com/nodejs/node/blob/7c3dce0/lib/internal/modules/esm/get_format.js>
- // Last checked on: Apr 29, 2024.
- import {fileURLToPath} from 'node:url'
- import {getPackageType} from './package-json-reader.js'
- import {codes} from './errors.js'
- const {ERR_UNKNOWN_FILE_EXTENSION} = codes
- const hasOwnProperty = {}.hasOwnProperty
- /** @type {Record<string, string>} */
- 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<string, ProtocolHandler>}
- */
- 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 value = extname(url)
- if (value === '.js') {
- const packageType = getPackageType(url)
- if (packageType !== 'none') {
- return packageType
- }
- return 'commonjs'
- }
- if (value === '') {
- 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[value]
- 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(value, 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
- }
|