pax_global_header00006660000000000000000000000064146137020520014512gustar00rootroot0000000000000052 comment=c0478902c641bebbb680017276f6e8427c252c01 import-meta-resolve-4.1.0/000077500000000000000000000000001461370205200154275ustar00rootroot00000000000000import-meta-resolve-4.1.0/.editorconfig000066400000000000000000000002231461370205200201010ustar00rootroot00000000000000root = true [*] indent_style = space indent_size = 2 end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true import-meta-resolve-4.1.0/.github/000077500000000000000000000000001461370205200167675ustar00rootroot00000000000000import-meta-resolve-4.1.0/.github/workflows/000077500000000000000000000000001461370205200210245ustar00rootroot00000000000000import-meta-resolve-4.1.0/.github/workflows/main.yml000066400000000000000000000011341461370205200224720ustar00rootroot00000000000000name: main on: - pull_request - push jobs: main: name: '${{matrix.node}} on ${{matrix.os}}' runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: ${{matrix.node}} - run: npm install - run: npm test - uses: codecov/codecov-action@v4 strategy: matrix: os: - ubuntu-latest # To do: Add back when supported again # - windows-latest node: - lts/gallium - node import-meta-resolve-4.1.0/.gitignore000066400000000000000000000001131461370205200174120ustar00rootroot00000000000000.DS_Store *.d.ts *.log coverage/ /node_modules test/baseline*.js yarn.lock import-meta-resolve-4.1.0/.npmrc000066400000000000000000000000231461370205200165420ustar00rootroot00000000000000package-lock=false import-meta-resolve-4.1.0/.prettierignore000066400000000000000000000000631461370205200204710ustar00rootroot00000000000000coverage/ *.md test/baseline.js test/node_modules/ import-meta-resolve-4.1.0/codecov.yml000066400000000000000000000000431461370205200175710ustar00rootroot00000000000000coverage: status: patch: off import-meta-resolve-4.1.0/funding.yml000066400000000000000000000000171461370205200176020ustar00rootroot00000000000000github: wooorm import-meta-resolve-4.1.0/index.js000066400000000000000000000025221461370205200170750ustar00rootroot00000000000000/** * @typedef {import('./lib/errors.js').ErrnoException} ErrnoException */ import {defaultResolve} from './lib/resolve.js' export {moduleResolve} from './lib/resolve.js' /** * Match `import.meta.resolve` except that `parent` is required (you can pass * `import.meta.url`). * * @param {string} specifier * The module specifier to resolve relative to parent * (`/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, * etc). * @param {string} parent * The absolute parent module URL to resolve from. * You must pass `import.meta.url` or something else. * @returns {string} * Returns a string to a full `file:`, `data:`, or `node:` URL * to the found thing. */ export function resolve(specifier, parent) { if (!parent) { throw new Error( 'Please pass `parent`: `import-meta-resolve` cannot ponyfill that' ) } try { return defaultResolve(specifier, {parentURL: parent}).url } catch (error) { // See: const exception = /** @type {ErrnoException} */ (error) if ( (exception.code === 'ERR_UNSUPPORTED_DIR_IMPORT' || exception.code === 'ERR_MODULE_NOT_FOUND') && typeof exception.url === 'string' ) { return exception.url } throw error } } import-meta-resolve-4.1.0/lib/000077500000000000000000000000001461370205200161755ustar00rootroot00000000000000import-meta-resolve-4.1.0/lib/errors.js000066400000000000000000000324511461370205200200540ustar00rootroot00000000000000/** * @typedef ErrnoExceptionFields * @property {number | undefined} [errnode] * @property {string | undefined} [code] * @property {string | undefined} [path] * @property {string | undefined} [syscall] * @property {string | undefined} [url] * * @typedef {Error & ErrnoExceptionFields} ErrnoException */ /** * @typedef {(...parameters: Array) => string} MessageFunction */ // Manually “tree shaken” from: // // Last checked on: Nov 2, 2023. import v8 from 'node:v8' import assert from 'node:assert' // Needed for types. // eslint-disable-next-line no-unused-vars import {URL} from 'node:url' import {format, inspect} from 'node:util' const own = {}.hasOwnProperty const classRegExp = /^([A-Z][a-z\d]*)+$/ // Sorted by a rough estimate on most frequently used entries. const kTypes = new Set([ 'string', 'function', 'number', 'object', // Accept 'Function' and 'Object' as alternative to the lower cased version. 'Function', 'Object', 'boolean', 'bigint', 'symbol' ]) export const codes = {} /** * Create a list string in the form like 'A and B' or 'A, B, ..., and Z'. * We cannot use Intl.ListFormat because it's not available in * --without-intl builds. * * @param {Array} array * An array of strings. * @param {string} [type] * The list type to be inserted before the last element. * @returns {string} */ function formatList(array, type = 'and') { return array.length < 3 ? array.join(` ${type} `) : `${array.slice(0, -1).join(', ')}, ${type} ${array[array.length - 1]}` } /** @type {Map} */ const messages = new Map() const nodeInternalPrefix = '__node_internal_' /** @type {number} */ let userStackTraceLimit codes.ERR_INVALID_ARG_TYPE = createError( 'ERR_INVALID_ARG_TYPE', /** * @param {string} name * @param {Array | string} expected * @param {unknown} actual */ (name, expected, actual) => { assert(typeof name === 'string', "'name' must be a string") if (!Array.isArray(expected)) { expected = [expected] } let message = 'The ' if (name.endsWith(' argument')) { // For cases like 'first argument' message += `${name} ` } else { const type = name.includes('.') ? 'property' : 'argument' message += `"${name}" ${type} ` } message += 'must be ' /** @type {Array} */ const types = [] /** @type {Array} */ const instances = [] /** @type {Array} */ const other = [] for (const value of expected) { assert( typeof value === 'string', 'All expected entries have to be of type string' ) if (kTypes.has(value)) { types.push(value.toLowerCase()) } else if (classRegExp.exec(value) === null) { assert( value !== 'object', 'The value "object" should be written as "Object"' ) other.push(value) } else { instances.push(value) } } // Special handle `object` in case other instances are allowed to outline // the differences between each other. if (instances.length > 0) { const pos = types.indexOf('object') if (pos !== -1) { types.slice(pos, 1) instances.push('Object') } } if (types.length > 0) { message += `${types.length > 1 ? 'one of type' : 'of type'} ${formatList( types, 'or' )}` if (instances.length > 0 || other.length > 0) message += ' or ' } if (instances.length > 0) { message += `an instance of ${formatList(instances, 'or')}` if (other.length > 0) message += ' or ' } if (other.length > 0) { if (other.length > 1) { message += `one of ${formatList(other, 'or')}` } else { if (other[0].toLowerCase() !== other[0]) message += 'an ' message += `${other[0]}` } } message += `. Received ${determineSpecificType(actual)}` return message }, TypeError ) codes.ERR_INVALID_MODULE_SPECIFIER = createError( 'ERR_INVALID_MODULE_SPECIFIER', /** * @param {string} request * @param {string} reason * @param {string} [base] */ (request, reason, base = undefined) => { return `Invalid module "${request}" ${reason}${ base ? ` imported from ${base}` : '' }` }, TypeError ) codes.ERR_INVALID_PACKAGE_CONFIG = createError( 'ERR_INVALID_PACKAGE_CONFIG', /** * @param {string} path * @param {string} [base] * @param {string} [message] */ (path, base, message) => { return `Invalid package config ${path}${ base ? ` while importing ${base}` : '' }${message ? `. ${message}` : ''}` }, Error ) codes.ERR_INVALID_PACKAGE_TARGET = createError( 'ERR_INVALID_PACKAGE_TARGET', /** * @param {string} packagePath * @param {string} key * @param {unknown} target * @param {boolean} [isImport=false] * @param {string} [base] */ (packagePath, key, target, isImport = false, base = undefined) => { const relatedError = typeof target === 'string' && !isImport && target.length > 0 && !target.startsWith('./') if (key === '.') { assert(isImport === false) return ( `Invalid "exports" main target ${JSON.stringify(target)} defined ` + `in the package config ${packagePath}package.json${ base ? ` imported from ${base}` : '' }${relatedError ? '; targets must start with "./"' : ''}` ) } return `Invalid "${ isImport ? 'imports' : 'exports' }" target ${JSON.stringify( target )} defined for '${key}' in the package config ${packagePath}package.json${ base ? ` imported from ${base}` : '' }${relatedError ? '; targets must start with "./"' : ''}` }, Error ) codes.ERR_MODULE_NOT_FOUND = createError( 'ERR_MODULE_NOT_FOUND', /** * @param {string} path * @param {string} base * @param {boolean} [exactUrl] */ (path, base, exactUrl = false) => { return `Cannot find ${ exactUrl ? 'module' : 'package' } '${path}' imported from ${base}` }, Error ) codes.ERR_NETWORK_IMPORT_DISALLOWED = createError( 'ERR_NETWORK_IMPORT_DISALLOWED', "import of '%s' by %s is not supported: %s", Error ) codes.ERR_PACKAGE_IMPORT_NOT_DEFINED = createError( 'ERR_PACKAGE_IMPORT_NOT_DEFINED', /** * @param {string} specifier * @param {string} packagePath * @param {string} base */ (specifier, packagePath, base) => { return `Package import specifier "${specifier}" is not defined${ packagePath ? ` in package ${packagePath}package.json` : '' } imported from ${base}` }, TypeError ) codes.ERR_PACKAGE_PATH_NOT_EXPORTED = createError( 'ERR_PACKAGE_PATH_NOT_EXPORTED', /** * @param {string} packagePath * @param {string} subpath * @param {string} [base] */ (packagePath, subpath, base = undefined) => { if (subpath === '.') return `No "exports" main defined in ${packagePath}package.json${ base ? ` imported from ${base}` : '' }` return `Package subpath '${subpath}' is not defined by "exports" in ${packagePath}package.json${ base ? ` imported from ${base}` : '' }` }, Error ) codes.ERR_UNSUPPORTED_DIR_IMPORT = createError( 'ERR_UNSUPPORTED_DIR_IMPORT', "Directory import '%s' is not supported " + 'resolving ES modules imported from %s', Error ) codes.ERR_UNSUPPORTED_RESOLVE_REQUEST = createError( 'ERR_UNSUPPORTED_RESOLVE_REQUEST', 'Failed to resolve module specifier "%s" from "%s": Invalid relative URL or base scheme is not hierarchical.', TypeError ) codes.ERR_UNKNOWN_FILE_EXTENSION = createError( 'ERR_UNKNOWN_FILE_EXTENSION', /** * @param {string} extension * @param {string} path */ (extension, path) => { return `Unknown file extension "${extension}" for ${path}` }, TypeError ) codes.ERR_INVALID_ARG_VALUE = createError( 'ERR_INVALID_ARG_VALUE', /** * @param {string} name * @param {unknown} value * @param {string} [reason='is invalid'] */ (name, value, reason = 'is invalid') => { let inspected = inspect(value) if (inspected.length > 128) { inspected = `${inspected.slice(0, 128)}...` } const type = name.includes('.') ? 'property' : 'argument' return `The ${type} '${name}' ${reason}. Received ${inspected}` }, TypeError // Note: extra classes have been shaken out. // , RangeError ) /** * Utility function for registering the error codes. Only used here. Exported * *only* to allow for testing. * @param {string} sym * @param {MessageFunction | string} value * @param {ErrorConstructor} constructor * @returns {new (...parameters: Array) => Error} */ function createError(sym, value, constructor) { // Special case for SystemError that formats the error message differently // The SystemErrors only have SystemError as their base classes. messages.set(sym, value) return makeNodeErrorWithCode(constructor, sym) } /** * @param {ErrorConstructor} Base * @param {string} key * @returns {ErrorConstructor} */ function makeNodeErrorWithCode(Base, key) { // @ts-expect-error It’s a Node error. return NodeError /** * @param {Array} parameters */ function NodeError(...parameters) { const limit = Error.stackTraceLimit if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = 0 const error = new Base() // Reset the limit and setting the name property. if (isErrorStackTraceLimitWritable()) Error.stackTraceLimit = limit const message = getMessage(key, parameters, error) Object.defineProperties(error, { // Note: no need to implement `kIsNodeError` symbol, would be hard, // probably. message: { value: message, enumerable: false, writable: true, configurable: true }, toString: { /** @this {Error} */ value() { return `${this.name} [${key}]: ${this.message}` }, enumerable: false, writable: true, configurable: true } }) captureLargerStackTrace(error) // @ts-expect-error It’s a Node error. error.code = key return error } } /** * @returns {boolean} */ function isErrorStackTraceLimitWritable() { // Do no touch Error.stackTraceLimit as V8 would attempt to install // it again during deserialization. try { if (v8.startupSnapshot.isBuildingSnapshot()) { return false } } catch {} const desc = Object.getOwnPropertyDescriptor(Error, 'stackTraceLimit') if (desc === undefined) { return Object.isExtensible(Error) } return own.call(desc, 'writable') && desc.writable !== undefined ? desc.writable : desc.set !== undefined } /** * This function removes unnecessary frames from Node.js core errors. * @template {(...parameters: unknown[]) => unknown} T * @param {T} wrappedFunction * @returns {T} */ function hideStackFrames(wrappedFunction) { // We rename the functions that will be hidden to cut off the stacktrace // at the outermost one const hidden = nodeInternalPrefix + wrappedFunction.name Object.defineProperty(wrappedFunction, 'name', {value: hidden}) return wrappedFunction } const captureLargerStackTrace = hideStackFrames( /** * @param {Error} error * @returns {Error} */ // @ts-expect-error: fine function (error) { const stackTraceLimitIsWritable = isErrorStackTraceLimitWritable() if (stackTraceLimitIsWritable) { userStackTraceLimit = Error.stackTraceLimit Error.stackTraceLimit = Number.POSITIVE_INFINITY } Error.captureStackTrace(error) // Reset the limit if (stackTraceLimitIsWritable) Error.stackTraceLimit = userStackTraceLimit return error } ) /** * @param {string} key * @param {Array} parameters * @param {Error} self * @returns {string} */ function getMessage(key, parameters, self) { const message = messages.get(key) assert(message !== undefined, 'expected `message` to be found') if (typeof message === 'function') { assert( message.length <= parameters.length, // Default options do not count. `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + `match the required ones (${message.length}).` ) return Reflect.apply(message, self, parameters) } const regex = /%[dfijoOs]/g let expectedLength = 0 while (regex.exec(message) !== null) expectedLength++ assert( expectedLength === parameters.length, `Code: ${key}; The provided arguments length (${parameters.length}) does not ` + `match the required ones (${expectedLength}).` ) if (parameters.length === 0) return message parameters.unshift(message) return Reflect.apply(format, null, parameters) } /** * Determine the specific type of a value for type-mismatch errors. * @param {unknown} value * @returns {string} */ function determineSpecificType(value) { if (value === null || value === undefined) { return String(value) } if (typeof value === 'function' && value.name) { return `function ${value.name}` } if (typeof value === 'object') { if (value.constructor && value.constructor.name) { return `an instance of ${value.constructor.name}` } return `${inspect(value, {depth: -1})}` } let inspected = inspect(value, {colors: false}) if (inspected.length > 28) { inspected = `${inspected.slice(0, 25)}...` } return `type ${typeof value} (${inspected})` } import-meta-resolve-4.1.0/lib/get-format.js000066400000000000000000000067011461370205200206040ustar00rootroot00000000000000// Manually “tree shaken” from: // // Last checked on: Apr 29, 2023. 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} */ 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 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 } import-meta-resolve-4.1.0/lib/package-json-reader.js000066400000000000000000000105461461370205200223430ustar00rootroot00000000000000// Manually “tree shaken” from: // // Last checked on: Apr 29, 2023. // Removed the native dependency. // Also: no need to cache, we do that in resolve already. /** * @typedef {import('./errors.js').ErrnoException} ErrnoException * * @typedef {'commonjs' | 'module' | 'none'} PackageType * * @typedef PackageConfig * @property {string} pjsonPath * @property {boolean} exists * @property {string | undefined} [main] * @property {string | undefined} [name] * @property {PackageType} type * @property {Record | undefined} [exports] * @property {Record | undefined} [imports] */ import fs from 'node:fs' import path from 'node:path' import {fileURLToPath} from 'node:url' import {codes} from './errors.js' const hasOwnProperty = {}.hasOwnProperty const {ERR_INVALID_PACKAGE_CONFIG} = codes /** @type {Map} */ const cache = new Map() /** * @param {string} jsonPath * @param {{specifier: URL | string, base?: URL}} options * @returns {PackageConfig} */ export function read(jsonPath, {base, specifier}) { const existing = cache.get(jsonPath) if (existing) { return existing } /** @type {string | undefined} */ let string try { string = fs.readFileSync(path.toNamespacedPath(jsonPath), 'utf8') } catch (error) { const exception = /** @type {ErrnoException} */ (error) if (exception.code !== 'ENOENT') { throw exception } } /** @type {PackageConfig} */ const result = { exists: false, pjsonPath: jsonPath, main: undefined, name: undefined, type: 'none', // Ignore unknown types for forwards compatibility exports: undefined, imports: undefined } if (string !== undefined) { /** @type {Record} */ let parsed try { parsed = JSON.parse(string) } catch (error_) { const cause = /** @type {ErrnoException} */ (error_) const error = new ERR_INVALID_PACKAGE_CONFIG( jsonPath, (base ? `"${specifier}" from ` : '') + fileURLToPath(base || specifier), cause.message ) error.cause = cause throw error } result.exists = true if ( hasOwnProperty.call(parsed, 'name') && typeof parsed.name === 'string' ) { result.name = parsed.name } if ( hasOwnProperty.call(parsed, 'main') && typeof parsed.main === 'string' ) { result.main = parsed.main } if (hasOwnProperty.call(parsed, 'exports')) { // @ts-expect-error: assume valid. result.exports = parsed.exports } if (hasOwnProperty.call(parsed, 'imports')) { // @ts-expect-error: assume valid. result.imports = parsed.imports } // Ignore unknown types for forwards compatibility if ( hasOwnProperty.call(parsed, 'type') && (parsed.type === 'commonjs' || parsed.type === 'module') ) { result.type = parsed.type } } cache.set(jsonPath, result) return result } /** * @param {URL | string} resolved * @returns {PackageConfig} */ export function getPackageScopeConfig(resolved) { // Note: in Node, this is now a native module. let packageJSONUrl = new URL('package.json', resolved) while (true) { const packageJSONPath = packageJSONUrl.pathname if (packageJSONPath.endsWith('node_modules/package.json')) { break } const packageConfig = read(fileURLToPath(packageJSONUrl), { specifier: resolved }) 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 packageJSONPath = fileURLToPath(packageJSONUrl) // ^^ Note: in Node, this is now a native module. return { pjsonPath: packageJSONPath, exists: false, type: 'none' } } /** * Returns the package type for a given URL. * @param {URL} url - The URL to get the package type for. * @returns {PackageType} */ export function getPackageType(url) { // To do @anonrig: Write a C++ function that returns only "type". return getPackageScopeConfig(url).type } import-meta-resolve-4.1.0/lib/resolve.js000066400000000000000000001036171461370205200202220ustar00rootroot00000000000000// Manually “tree shaken” from: // // Last checked on: Apr 29, 2023. /** * @typedef {import('node:fs').Stats} Stats * @typedef {import('./errors.js').ErrnoException} ErrnoException * @typedef {import('./package-json-reader.js').PackageConfig} PackageConfig */ import assert from 'node:assert' import {statSync, realpathSync} from 'node:fs' import process from 'node:process' import {URL, fileURLToPath, pathToFileURL} from 'node:url' import path from 'node:path' import {builtinModules} from 'node:module' import {defaultGetFormatWithoutErrors} from './get-format.js' import {codes} from './errors.js' import {getPackageScopeConfig, read} from './package-json-reader.js' import {getConditionsSet} from './utils.js' const RegExpPrototypeSymbolReplace = RegExp.prototype[Symbol.replace] const { ERR_NETWORK_IMPORT_DISALLOWED, ERR_INVALID_MODULE_SPECIFIER, ERR_INVALID_PACKAGE_CONFIG, ERR_INVALID_PACKAGE_TARGET, ERR_MODULE_NOT_FOUND, ERR_PACKAGE_IMPORT_NOT_DEFINED, ERR_PACKAGE_PATH_NOT_EXPORTED, ERR_UNSUPPORTED_DIR_IMPORT, ERR_UNSUPPORTED_RESOLVE_REQUEST } = codes const own = {}.hasOwnProperty const invalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))?(\\|\/|$)/i const deprecatedInvalidSegmentRegEx = /(^|\\|\/)((\.|%2e)(\.|%2e)?|(n|%6e|%4e)(o|%6f|%4f)(d|%64|%44)(e|%65|%45)(_|%5f)(m|%6d|%4d)(o|%6f|%4f)(d|%64|%44)(u|%75|%55)(l|%6c|%4c)(e|%65|%45)(s|%73|%53))(\\|\/|$)/i const invalidPackageNameRegEx = /^\.|%|\\/ const patternRegEx = /\*/g const encodedSeparatorRegEx = /%2f|%5c/i /** @type {Set} */ const emittedPackageWarnings = new Set() const doubleSlashRegEx = /[/\\]{2}/ /** * * @param {string} target * @param {string} request * @param {string} match * @param {URL} packageJsonUrl * @param {boolean} internal * @param {URL} base * @param {boolean} isTarget */ function emitInvalidSegmentDeprecation( target, request, match, packageJsonUrl, internal, base, isTarget ) { // @ts-expect-error: apparently it does exist, TS. if (process.noDeprecation) { return } const pjsonPath = fileURLToPath(packageJsonUrl) const double = doubleSlashRegEx.exec(isTarget ? target : request) !== null process.emitWarning( `Use of deprecated ${ double ? 'double slash' : 'leading or trailing slash matching' } resolving "${target}" for module ` + `request "${request}" ${ request === match ? '' : `matched to "${match}" ` }in the "${ internal ? 'imports' : 'exports' }" field module resolution of the package at ${pjsonPath}${ base ? ` imported from ${fileURLToPath(base)}` : '' }.`, 'DeprecationWarning', 'DEP0166' ) } /** * @param {URL} url * @param {URL} packageJsonUrl * @param {URL} base * @param {string} [main] * @returns {void} */ function emitLegacyIndexDeprecation(url, packageJsonUrl, base, main) { // @ts-expect-error: apparently it does exist, TS. if (process.noDeprecation) { return } const format = defaultGetFormatWithoutErrors(url, {parentURL: base.href}) if (format !== 'module') return const urlPath = fileURLToPath(url.href) const packagePath = fileURLToPath(new URL('.', packageJsonUrl)) const basePath = fileURLToPath(base) if (!main) { process.emitWarning( `No "main" or "exports" field defined in the package.json for ${packagePath} resolving the main entry point "${urlPath.slice( packagePath.length )}", imported from ${basePath}.\nDefault "index" lookups for the main are deprecated for ES modules.`, 'DeprecationWarning', 'DEP0151' ) } else if (path.resolve(packagePath, main) !== urlPath) { process.emitWarning( `Package ${packagePath} has a "main" field set to "${main}", ` + `excluding the full filename and extension to the resolved file at "${urlPath.slice( packagePath.length )}", imported from ${basePath}.\n Automatic extension resolution of the "main" field is ` + 'deprecated for ES modules.', 'DeprecationWarning', 'DEP0151' ) } } /** * @param {string} path * @returns {Stats | undefined} */ function tryStatSync(path) { // Note: from Node 15 onwards we can use `throwIfNoEntry: false` instead. try { return statSync(path) } catch { // Note: in Node code this returns `new Stats`, // but in Node 22 that’s marked as a deprecated internal API. // Which, well, we kinda are, but still to prevent that warning, // just yield `undefined`. } } /** * 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 * * @param {URL} url * @returns {boolean} */ function fileExists(url) { const stats = statSync(url, {throwIfNoEntry: false}) const isFile = stats ? stats.isFile() : undefined return isFile === null || isFile === undefined ? false : isFile } /** * @param {URL} packageJsonUrl * @param {PackageConfig} packageConfig * @param {URL} base * @returns {URL} */ function legacyMainResolve(packageJsonUrl, packageConfig, base) { /** @type {URL | undefined} */ let guess if (packageConfig.main !== undefined) { guess = new URL(packageConfig.main, packageJsonUrl) // Note: fs check redundances will be handled by Descriptor cache here. if (fileExists(guess)) return guess const tries = [ `./${packageConfig.main}.js`, `./${packageConfig.main}.json`, `./${packageConfig.main}.node`, `./${packageConfig.main}/index.js`, `./${packageConfig.main}/index.json`, `./${packageConfig.main}/index.node` ] let i = -1 while (++i < tries.length) { guess = new URL(tries[i], packageJsonUrl) if (fileExists(guess)) break guess = undefined } if (guess) { emitLegacyIndexDeprecation( guess, packageJsonUrl, base, packageConfig.main ) return guess } // Fallthrough. } const tries = ['./index.js', './index.json', './index.node'] let i = -1 while (++i < tries.length) { guess = new URL(tries[i], packageJsonUrl) if (fileExists(guess)) break guess = undefined } if (guess) { emitLegacyIndexDeprecation(guess, packageJsonUrl, base, packageConfig.main) return guess } // Not found. throw new ERR_MODULE_NOT_FOUND( fileURLToPath(new URL('.', packageJsonUrl)), fileURLToPath(base) ) } /** * @param {URL} resolved * @param {URL} base * @param {boolean} [preserveSymlinks] * @returns {URL} */ function finalizeResolution(resolved, base, preserveSymlinks) { if (encodedSeparatorRegEx.exec(resolved.pathname) !== null) { throw new ERR_INVALID_MODULE_SPECIFIER( resolved.pathname, 'must not include encoded "/" or "\\" characters', fileURLToPath(base) ) } /** @type {string} */ let filePath try { filePath = fileURLToPath(resolved) } catch (error) { const cause = /** @type {ErrnoException} */ (error) Object.defineProperty(cause, 'input', {value: String(resolved)}) Object.defineProperty(cause, 'module', {value: String(base)}) throw cause } const stats = tryStatSync( filePath.endsWith('/') ? filePath.slice(-1) : filePath ) if (stats && stats.isDirectory()) { const error = new ERR_UNSUPPORTED_DIR_IMPORT(filePath, fileURLToPath(base)) // @ts-expect-error Add this for `import.meta.resolve`. error.url = String(resolved) throw error } if (!stats || !stats.isFile()) { const error = new ERR_MODULE_NOT_FOUND( filePath || resolved.pathname, base && fileURLToPath(base), true ) // @ts-expect-error Add this for `import.meta.resolve`. error.url = String(resolved) throw error } if (!preserveSymlinks) { const real = realpathSync(filePath) const {search, hash} = resolved resolved = pathToFileURL(real + (filePath.endsWith(path.sep) ? '/' : '')) resolved.search = search resolved.hash = hash } return resolved } /** * @param {string} specifier * @param {URL | undefined} packageJsonUrl * @param {URL} base * @returns {Error} */ function importNotDefined(specifier, packageJsonUrl, base) { return new ERR_PACKAGE_IMPORT_NOT_DEFINED( specifier, packageJsonUrl && fileURLToPath(new URL('.', packageJsonUrl)), fileURLToPath(base) ) } /** * @param {string} subpath * @param {URL} packageJsonUrl * @param {URL} base * @returns {Error} */ function exportsNotFound(subpath, packageJsonUrl, base) { return new ERR_PACKAGE_PATH_NOT_EXPORTED( fileURLToPath(new URL('.', packageJsonUrl)), subpath, base && fileURLToPath(base) ) } /** * @param {string} request * @param {string} match * @param {URL} packageJsonUrl * @param {boolean} internal * @param {URL} [base] * @returns {never} */ function throwInvalidSubpath(request, match, packageJsonUrl, internal, base) { const reason = `request is not a valid match in pattern "${match}" for the "${ internal ? 'imports' : 'exports' }" resolution of ${fileURLToPath(packageJsonUrl)}` throw new ERR_INVALID_MODULE_SPECIFIER( request, reason, base && fileURLToPath(base) ) } /** * @param {string} subpath * @param {unknown} target * @param {URL} packageJsonUrl * @param {boolean} internal * @param {URL} [base] * @returns {Error} */ function invalidPackageTarget(subpath, target, packageJsonUrl, internal, base) { target = typeof target === 'object' && target !== null ? JSON.stringify(target, null, '') : `${target}` return new ERR_INVALID_PACKAGE_TARGET( fileURLToPath(new URL('.', packageJsonUrl)), subpath, target, internal, base && fileURLToPath(base) ) } /** * @param {string} target * @param {string} subpath * @param {string} match * @param {URL} packageJsonUrl * @param {URL} base * @param {boolean} pattern * @param {boolean} internal * @param {boolean} isPathMap * @param {Set | undefined} conditions * @returns {URL} */ function resolvePackageTargetString( target, subpath, match, packageJsonUrl, base, pattern, internal, isPathMap, conditions ) { if (subpath !== '' && !pattern && target[target.length - 1] !== '/') throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) if (!target.startsWith('./')) { if (internal && !target.startsWith('../') && !target.startsWith('/')) { let isURL = false try { new URL(target) isURL = true } catch { // Continue regardless of error. } if (!isURL) { const exportTarget = pattern ? RegExpPrototypeSymbolReplace.call( patternRegEx, target, () => subpath ) : target + subpath return packageResolve(exportTarget, packageJsonUrl, conditions) } } throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) } if (invalidSegmentRegEx.exec(target.slice(2)) !== null) { if (deprecatedInvalidSegmentRegEx.exec(target.slice(2)) === null) { if (!isPathMap) { const request = pattern ? match.replace('*', () => subpath) : match + subpath const resolvedTarget = pattern ? RegExpPrototypeSymbolReplace.call( patternRegEx, target, () => subpath ) : target emitInvalidSegmentDeprecation( resolvedTarget, request, match, packageJsonUrl, internal, base, true ) } } else { throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) } } const resolved = new URL(target, packageJsonUrl) const resolvedPath = resolved.pathname const packagePath = new URL('.', packageJsonUrl).pathname if (!resolvedPath.startsWith(packagePath)) throw invalidPackageTarget(match, target, packageJsonUrl, internal, base) if (subpath === '') return resolved if (invalidSegmentRegEx.exec(subpath) !== null) { const request = pattern ? match.replace('*', () => subpath) : match + subpath if (deprecatedInvalidSegmentRegEx.exec(subpath) === null) { if (!isPathMap) { const resolvedTarget = pattern ? RegExpPrototypeSymbolReplace.call( patternRegEx, target, () => subpath ) : target emitInvalidSegmentDeprecation( resolvedTarget, request, match, packageJsonUrl, internal, base, false ) } } else { throwInvalidSubpath(request, match, packageJsonUrl, internal, base) } } if (pattern) { return new URL( RegExpPrototypeSymbolReplace.call( patternRegEx, resolved.href, () => subpath ) ) } return new URL(subpath, resolved) } /** * @param {string} key * @returns {boolean} */ function isArrayIndex(key) { const keyNumber = Number(key) if (`${keyNumber}` !== key) return false return keyNumber >= 0 && keyNumber < 0xff_ff_ff_ff } /** * @param {URL} packageJsonUrl * @param {unknown} target * @param {string} subpath * @param {string} packageSubpath * @param {URL} base * @param {boolean} pattern * @param {boolean} internal * @param {boolean} isPathMap * @param {Set | undefined} conditions * @returns {URL | null} */ function resolvePackageTarget( packageJsonUrl, target, subpath, packageSubpath, base, pattern, internal, isPathMap, conditions ) { if (typeof target === 'string') { return resolvePackageTargetString( target, subpath, packageSubpath, packageJsonUrl, base, pattern, internal, isPathMap, conditions ) } if (Array.isArray(target)) { /** @type {Array} */ const targetList = target if (targetList.length === 0) return null /** @type {ErrnoException | null | undefined} */ let lastException let i = -1 while (++i < targetList.length) { const targetItem = targetList[i] /** @type {URL | null} */ let resolveResult try { resolveResult = resolvePackageTarget( packageJsonUrl, targetItem, subpath, packageSubpath, base, pattern, internal, isPathMap, conditions ) } catch (error) { const exception = /** @type {ErrnoException} */ (error) lastException = exception if (exception.code === 'ERR_INVALID_PACKAGE_TARGET') continue throw error } if (resolveResult === undefined) continue if (resolveResult === null) { lastException = null continue } return resolveResult } if (lastException === undefined || lastException === null) { return null } throw lastException } if (typeof target === 'object' && target !== null) { const keys = Object.getOwnPropertyNames(target) let i = -1 while (++i < keys.length) { const key = keys[i] if (isArrayIndex(key)) { throw new ERR_INVALID_PACKAGE_CONFIG( fileURLToPath(packageJsonUrl), base, '"exports" cannot contain numeric property keys.' ) } } i = -1 while (++i < keys.length) { const key = keys[i] if (key === 'default' || (conditions && conditions.has(key))) { // @ts-expect-error: indexable. const conditionalTarget = /** @type {unknown} */ (target[key]) const resolveResult = resolvePackageTarget( packageJsonUrl, conditionalTarget, subpath, packageSubpath, base, pattern, internal, isPathMap, conditions ) if (resolveResult === undefined) continue return resolveResult } } return null } if (target === null) { return null } throw invalidPackageTarget( packageSubpath, target, packageJsonUrl, internal, base ) } /** * @param {unknown} exports * @param {URL} packageJsonUrl * @param {URL} base * @returns {boolean} */ function isConditionalExportsMainSugar(exports, packageJsonUrl, base) { if (typeof exports === 'string' || Array.isArray(exports)) return true if (typeof exports !== 'object' || exports === null) return false const keys = Object.getOwnPropertyNames(exports) let isConditionalSugar = false let i = 0 let keyIndex = -1 while (++keyIndex < keys.length) { const key = keys[keyIndex] const currentIsConditionalSugar = key === '' || key[0] !== '.' if (i++ === 0) { isConditionalSugar = currentIsConditionalSugar } else if (isConditionalSugar !== currentIsConditionalSugar) { throw new ERR_INVALID_PACKAGE_CONFIG( fileURLToPath(packageJsonUrl), base, '"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 } /** * @param {string} match * @param {URL} pjsonUrl * @param {URL} base */ function emitTrailingSlashPatternDeprecation(match, pjsonUrl, base) { // @ts-expect-error: apparently it does exist, TS. if (process.noDeprecation) { return } const pjsonPath = fileURLToPath(pjsonUrl) if (emittedPackageWarnings.has(pjsonPath + '|' + match)) return emittedPackageWarnings.add(pjsonPath + '|' + match) process.emitWarning( `Use of deprecated trailing slash pattern mapping "${match}" in the ` + `"exports" field module resolution of the package at ${pjsonPath}${ base ? ` imported from ${fileURLToPath(base)}` : '' }. Mapping specifiers ending in "/" is no longer supported.`, 'DeprecationWarning', 'DEP0155' ) } /** * @param {URL} packageJsonUrl * @param {string} packageSubpath * @param {Record} packageConfig * @param {URL} base * @param {Set | undefined} conditions * @returns {URL} */ function packageExportsResolve( packageJsonUrl, packageSubpath, packageConfig, base, conditions ) { let exports = packageConfig.exports if (isConditionalExportsMainSugar(exports, packageJsonUrl, base)) { exports = {'.': exports} } if ( own.call(exports, packageSubpath) && !packageSubpath.includes('*') && !packageSubpath.endsWith('/') ) { // @ts-expect-error: indexable. const target = exports[packageSubpath] const resolveResult = resolvePackageTarget( packageJsonUrl, target, '', packageSubpath, base, false, false, false, conditions ) if (resolveResult === null || resolveResult === undefined) { throw exportsNotFound(packageSubpath, packageJsonUrl, base) } return resolveResult } let bestMatch = '' let bestMatchSubpath = '' const keys = Object.getOwnPropertyNames(exports) let i = -1 while (++i < keys.length) { const key = keys[i] const patternIndex = key.indexOf('*') if ( patternIndex !== -1 && packageSubpath.startsWith(key.slice(0, patternIndex)) ) { // When this reaches EOL, this can throw at the top of the whole function: // // if (StringPrototypeEndsWith(packageSubpath, '/')) // throwInvalidSubpath(packageSubpath) // // To match "imports" and the spec. if (packageSubpath.endsWith('/')) { emitTrailingSlashPatternDeprecation( packageSubpath, packageJsonUrl, base ) } const patternTrailer = key.slice(patternIndex + 1) if ( packageSubpath.length >= key.length && packageSubpath.endsWith(patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && key.lastIndexOf('*') === patternIndex ) { bestMatch = key bestMatchSubpath = packageSubpath.slice( patternIndex, packageSubpath.length - patternTrailer.length ) } } } if (bestMatch) { // @ts-expect-error: indexable. const target = /** @type {unknown} */ (exports[bestMatch]) const resolveResult = resolvePackageTarget( packageJsonUrl, target, bestMatchSubpath, bestMatch, base, true, false, packageSubpath.endsWith('/'), conditions ) if (resolveResult === null || resolveResult === undefined) { throw exportsNotFound(packageSubpath, packageJsonUrl, base) } return resolveResult } throw exportsNotFound(packageSubpath, packageJsonUrl, base) } /** * @param {string} a * @param {string} b */ function patternKeyCompare(a, b) { const aPatternIndex = a.indexOf('*') const bPatternIndex = b.indexOf('*') const baseLengthA = aPatternIndex === -1 ? a.length : aPatternIndex + 1 const baseLengthB = bPatternIndex === -1 ? b.length : bPatternIndex + 1 if (baseLengthA > baseLengthB) return -1 if (baseLengthB > baseLengthA) return 1 if (aPatternIndex === -1) return 1 if (bPatternIndex === -1) return -1 if (a.length > b.length) return -1 if (b.length > a.length) return 1 return 0 } /** * @param {string} name * @param {URL} base * @param {Set} [conditions] * @returns {URL} */ function packageImportsResolve(name, base, conditions) { if (name === '#' || name.startsWith('#/') || name.endsWith('/')) { const reason = 'is not a valid internal imports specifier name' throw new ERR_INVALID_MODULE_SPECIFIER(name, reason, fileURLToPath(base)) } /** @type {URL | undefined} */ let packageJsonUrl const packageConfig = getPackageScopeConfig(base) if (packageConfig.exists) { packageJsonUrl = pathToFileURL(packageConfig.pjsonPath) const imports = packageConfig.imports if (imports) { if (own.call(imports, name) && !name.includes('*')) { const resolveResult = resolvePackageTarget( packageJsonUrl, imports[name], '', name, base, false, true, false, conditions ) if (resolveResult !== null && resolveResult !== undefined) { return resolveResult } } else { let bestMatch = '' let bestMatchSubpath = '' const keys = Object.getOwnPropertyNames(imports) let i = -1 while (++i < keys.length) { const key = keys[i] const patternIndex = key.indexOf('*') if (patternIndex !== -1 && name.startsWith(key.slice(0, -1))) { const patternTrailer = key.slice(patternIndex + 1) if ( name.length >= key.length && name.endsWith(patternTrailer) && patternKeyCompare(bestMatch, key) === 1 && key.lastIndexOf('*') === patternIndex ) { bestMatch = key bestMatchSubpath = name.slice( patternIndex, name.length - patternTrailer.length ) } } } if (bestMatch) { const target = imports[bestMatch] const resolveResult = resolvePackageTarget( packageJsonUrl, target, bestMatchSubpath, bestMatch, base, true, true, false, conditions ) if (resolveResult !== null && resolveResult !== undefined) { return resolveResult } } } } } throw importNotDefined(name, packageJsonUrl, base) } /** * @param {string} specifier * @param {URL} base */ function parsePackageName(specifier, base) { let separatorIndex = specifier.indexOf('/') let validPackageName = true let isScoped = false if (specifier[0] === '@') { isScoped = true if (separatorIndex === -1 || specifier.length === 0) { validPackageName = false } else { separatorIndex = specifier.indexOf('/', separatorIndex + 1) } } const packageName = separatorIndex === -1 ? specifier : specifier.slice(0, separatorIndex) // Package name cannot have leading . and cannot have percent-encoding or // \\ separators. if (invalidPackageNameRegEx.exec(packageName) !== null) { validPackageName = false } if (!validPackageName) { throw new ERR_INVALID_MODULE_SPECIFIER( specifier, 'is not a valid package name', fileURLToPath(base) ) } const packageSubpath = '.' + (separatorIndex === -1 ? '' : specifier.slice(separatorIndex)) return {packageName, packageSubpath, isScoped} } /** * @param {string} specifier * @param {URL} base * @param {Set | undefined} conditions * @returns {URL} */ function packageResolve(specifier, base, conditions) { if (builtinModules.includes(specifier)) { return new URL('node:' + specifier) } const {packageName, packageSubpath, isScoped} = parsePackageName( specifier, base ) // ResolveSelf const packageConfig = getPackageScopeConfig(base) // Can’t test. /* c8 ignore next 16 */ if (packageConfig.exists) { const packageJsonUrl = pathToFileURL(packageConfig.pjsonPath) if ( packageConfig.name === packageName && packageConfig.exports !== undefined && packageConfig.exports !== null ) { return packageExportsResolve( packageJsonUrl, packageSubpath, packageConfig, base, conditions ) } } let packageJsonUrl = new URL( './node_modules/' + packageName + '/package.json', base ) let packageJsonPath = fileURLToPath(packageJsonUrl) /** @type {string} */ let lastPath do { const stat = tryStatSync(packageJsonPath.slice(0, -13)) if (!stat || !stat.isDirectory()) { lastPath = packageJsonPath packageJsonUrl = new URL( (isScoped ? '../../../../node_modules/' : '../../../node_modules/') + packageName + '/package.json', packageJsonUrl ) packageJsonPath = fileURLToPath(packageJsonUrl) continue } // Package match. const packageConfig = read(packageJsonPath, {base, specifier}) if (packageConfig.exports !== undefined && packageConfig.exports !== null) { return packageExportsResolve( packageJsonUrl, packageSubpath, packageConfig, base, conditions ) } if (packageSubpath === '.') { return legacyMainResolve(packageJsonUrl, packageConfig, base) } return new URL(packageSubpath, packageJsonUrl) // Cross-platform root check. } while (packageJsonPath.length !== lastPath.length) throw new ERR_MODULE_NOT_FOUND(packageName, fileURLToPath(base), false) } /** * @param {string} specifier * @returns {boolean} */ function isRelativeSpecifier(specifier) { if (specifier[0] === '.') { if (specifier.length === 1 || specifier[1] === '/') return true if ( specifier[1] === '.' && (specifier.length === 2 || specifier[2] === '/') ) { return true } } return false } /** * @param {string} specifier * @returns {boolean} */ function shouldBeTreatedAsRelativeOrAbsolutePath(specifier) { if (specifier === '') return false if (specifier[0] === '/') return true return isRelativeSpecifier(specifier) } /** * The “Resolver Algorithm Specification” as detailed in the Node docs (which is * sync and slightly lower-level than `resolve`). * * @param {string} specifier * `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc. * @param {URL} base * Full URL (to a file) that `specifier` is resolved relative from. * @param {Set} [conditions] * Conditions. * @param {boolean} [preserveSymlinks] * Keep symlinks instead of resolving them. * @returns {URL} * A URL object to the found thing. */ export function moduleResolve(specifier, base, conditions, preserveSymlinks) { // Note: The Node code supports `base` as a string (in this internal API) too, // we don’t. const protocol = base.protocol const isData = protocol === 'data:' const isRemote = isData || protocol === 'http:' || protocol === 'https:' // Order swapped from spec for minor perf gain. // Ok since relative URLs cannot parse as URLs. /** @type {URL | undefined} */ let resolved if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { try { resolved = new URL(specifier, base) } catch (error_) { const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base) error.cause = error_ throw error } } else if (protocol === 'file:' && specifier[0] === '#') { resolved = packageImportsResolve(specifier, base, conditions) } else { try { resolved = new URL(specifier) } catch (error_) { // Note: actual code uses `canBeRequiredWithoutScheme`. if (isRemote && !builtinModules.includes(specifier)) { const error = new ERR_UNSUPPORTED_RESOLVE_REQUEST(specifier, base) error.cause = error_ throw error } resolved = packageResolve(specifier, base, conditions) } } assert(resolved !== undefined, 'expected to be defined') if (resolved.protocol !== 'file:') { return resolved } return finalizeResolution(resolved, base, preserveSymlinks) } /** * @param {string} specifier * @param {URL | undefined} parsed * @param {URL | undefined} parsedParentURL */ function checkIfDisallowedImport(specifier, parsed, parsedParentURL) { if (parsedParentURL) { // Avoid accessing the `protocol` property due to the lazy getters. const parentProtocol = parsedParentURL.protocol if (parentProtocol === 'http:' || parentProtocol === 'https:') { if (shouldBeTreatedAsRelativeOrAbsolutePath(specifier)) { // Avoid accessing the `protocol` property due to the lazy getters. const parsedProtocol = parsed?.protocol // `data:` and `blob:` disallowed due to allowing file: access via // indirection if ( parsedProtocol && parsedProtocol !== 'https:' && parsedProtocol !== 'http:' ) { throw new ERR_NETWORK_IMPORT_DISALLOWED( specifier, parsedParentURL, 'remote imports cannot import from a local location.' ) } return {url: parsed?.href || ''} } if (builtinModules.includes(specifier)) { throw new ERR_NETWORK_IMPORT_DISALLOWED( specifier, parsedParentURL, 'remote imports cannot import from a local location.' ) } throw new ERR_NETWORK_IMPORT_DISALLOWED( specifier, parsedParentURL, 'only relative and absolute specifiers are supported.' ) } } } // Note: this is from: // /** * Checks if a value has the shape of a WHATWG URL object. * * Using a symbol or instanceof would not be able to recognize URL objects * coming from other implementations (e.g. in Electron), so instead we are * checking some well known properties for a lack of a better test. * * We use `href` and `protocol` as they are the only properties that are * easy to retrieve and calculate due to the lazy nature of the getters. * * @template {unknown} Value * @param {Value} self * @returns {Value is URL} */ function isURL(self) { return Boolean( self && typeof self === 'object' && 'href' in self && typeof self.href === 'string' && 'protocol' in self && typeof self.protocol === 'string' && self.href && self.protocol ) } /** * Validate user-input in `context` supplied by a custom loader. * * @param {unknown} parentURL * @returns {asserts parentURL is URL | string | undefined} */ function throwIfInvalidParentURL(parentURL) { if (parentURL === undefined) { return // Main entry point, so no parent } if (typeof parentURL !== 'string' && !isURL(parentURL)) { throw new codes.ERR_INVALID_ARG_TYPE( 'parentURL', ['string', 'URL'], parentURL ) } } /** * @param {string} specifier * @param {{parentURL?: string, conditions?: Array}} context * @returns {{url: string, format?: string | null}} */ export function defaultResolve(specifier, context = {}) { const {parentURL} = context assert(parentURL !== undefined, 'expected `parentURL` to be defined') throwIfInvalidParentURL(parentURL) /** @type {URL | undefined} */ let parsedParentURL if (parentURL) { try { parsedParentURL = new URL(parentURL) } catch { // Ignore exception } } /** @type {URL | undefined} */ let parsed /** @type {string | undefined} */ let protocol try { parsed = shouldBeTreatedAsRelativeOrAbsolutePath(specifier) ? new URL(specifier, parsedParentURL) : new URL(specifier) // Avoid accessing the `protocol` property due to the lazy getters. protocol = parsed.protocol if (protocol === 'data:') { return {url: parsed.href, format: null} } } catch { // Ignore exception } // There are multiple deep branches that can either throw or return; instead // of duplicating that deeply nested logic for the possible returns, DRY and // check for a return. This seems the least gnarly. const maybeReturn = checkIfDisallowedImport( specifier, parsed, parsedParentURL ) if (maybeReturn) return maybeReturn // This must come after checkIfDisallowedImport if (protocol === undefined && parsed) { protocol = parsed.protocol } if (protocol === 'node:') { return {url: specifier} } // This must come after checkIfDisallowedImport if (parsed && parsed.protocol === 'node:') return {url: specifier} const conditions = getConditionsSet(context.conditions) const url = moduleResolve(specifier, new URL(parentURL), conditions, false) return { // Do NOT cast `url` to a string: that will work even when there are real // problems, silencing them url: url.href, format: defaultGetFormatWithoutErrors(url, {parentURL}) } } import-meta-resolve-4.1.0/lib/utils.js000066400000000000000000000022441461370205200176750ustar00rootroot00000000000000// Manually “tree shaken” from: // // Last checked on: Apr 29, 2023. import {codes} from './errors.js' const {ERR_INVALID_ARG_VALUE} = codes // In Node itself these values are populated from CLI arguments, before any // user code runs. // Here we just define the defaults. const DEFAULT_CONDITIONS = Object.freeze(['node', 'import']) const DEFAULT_CONDITIONS_SET = new Set(DEFAULT_CONDITIONS) /** * Returns the default conditions for ES module loading. */ function getDefaultConditions() { return DEFAULT_CONDITIONS } /** * Returns the default conditions for ES module loading, as a Set. */ function getDefaultConditionsSet() { return DEFAULT_CONDITIONS_SET } /** * @param {Array} [conditions] * @returns {Set} */ export function getConditionsSet(conditions) { if (conditions !== undefined && conditions !== getDefaultConditions()) { if (!Array.isArray(conditions)) { throw new ERR_INVALID_ARG_VALUE( 'conditions', conditions, 'expected an array' ) } return new Set(conditions) } return getDefaultConditionsSet() } import-meta-resolve-4.1.0/license000066400000000000000000000066521461370205200170050ustar00rootroot00000000000000(The MIT License) Copyright (c) 2021 Titus Wormer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --- This is a derivative work based on: . Which is licensed: """ Copyright Node.js contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ This license applies to parts of Node.js originating from the https://github.com/joyent/node repository: """ Copyright Joyent, Inc. and other Node contributors. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ import-meta-resolve-4.1.0/package.json000066400000000000000000000050561461370205200177230ustar00rootroot00000000000000{ "name": "import-meta-resolve", "version": "4.1.0", "description": "Resolve things like Node.js — ponyfill for `import.meta.resolve`", "license": "MIT", "keywords": [ "resolve", "node", "esm", "module" ], "repository": "wooorm/import-meta-resolve", "bugs": "https://github.com/wooorm/import-meta-resolve/issues", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" }, "author": "Titus Wormer (https://wooorm.com)", "contributors": [ "Titus Wormer (https://wooorm.com)" ], "sideEffects": false, "type": "module", "main": "index.js", "types": "index.d.ts", "files": [ "lib/", "index.d.ts", "index.js" ], "devDependencies": { "@types/node": "^20.0.0", "@types/semver": "^7.0.0", "c8": "^9.0.0", "f-ck": "^2.0.0", "prettier": "^3.0.0", "remark-cli": "^12.0.0", "remark-preset-wooorm": "^10.0.0", "semver": "^7.0.0", "type-coverage": "^2.0.0", "typescript": "^5.0.0", "xo": "^0.58.0" }, "scripts": { "prepack": "npm run generate && npm run build && npm run format", "generate": "node --conditions development script.js", "build": "tsc --build --clean && tsc --build && type-coverage", "format": "remark . -qfo && prettier . -w --log-level warn && xo --fix", "test-api": "node --experimental-import-meta-resolve test/baseline.js && node --experimental-import-meta-resolve test/baseline-async.js && node test/index.js", "test-coverage": "c8 --check-coverage --branches 75 --functions 75 --lines 75 --statements 75 --reporter lcov npm run test-api", "test": "npm run generate && npm run build && npm run format && npm run test-coverage" }, "prettier": { "tabWidth": 2, "useTabs": false, "singleQuote": true, "bracketSpacing": false, "semi": false, "trailingComma": "none" }, "xo": { "prettier": true, "rules": { "complexity": "off", "max-depth": "off", "max-params": "off", "no-constant-condition": "off", "no-new": "off", "prefer-arrow-callback": "off", "unicorn/prefer-at": "off", "unicorn/prefer-string-replace-all": "off" }, "ignore": [ "test/node_modules/" ] }, "remarkConfig": { "plugins": [ "preset-wooorm", [ "remark-lint-maximum-heading-length", false ] ] }, "typeCoverage": { "atLeast": 100, "detail": true, "strict": true, "ignoreCatch": true, "ignoreFiles": [ "lib/errors.d.ts" ] } } import-meta-resolve-4.1.0/readme.md000066400000000000000000000170021461370205200172060ustar00rootroot00000000000000# import-meta-resolve [![Build][build-badge]][build] [![Coverage][coverage-badge]][coverage] [![Downloads][downloads-badge]][downloads] Resolve things like Node.js. ## Contents * [What is this?](#what-is-this) * [When to use this?](#when-to-use-this) * [Install](#install) * [Use](#use) * [API](#api) * [`resolve(specifier, parent)`](#resolvespecifier-parent) * [`moduleResolve(specifier, parent, conditions, preserveSymlinks)`](#moduleresolvespecifier-parent-conditions-preservesymlinks) * [`ErrnoException`](#errnoexception) * [Algorithm](#algorithm) * [Differences to Node](#differences-to-node) * [Types](#types) * [Compatibility](#compatibility) * [Contribute](#contribute) * [License](#license) ## What is this? This package is a ponyfill for [`import.meta.resolve`][native-resolve]. It supports everything you need to resolve files just like modern Node does: import maps, export maps, loading CJS and ESM projects, all of that! ## When to use this? As of Node.js 20.0, `import.meta.resolve` is still behind an experimental flag. This package can be used to do what it does in Node 16–20. ## Install This package is [ESM only][esm]. In Node.js (version 16+), install with [npm][]: ```sh npm install import-meta-resolve ``` ## Use ```js import {resolve} from 'import-meta-resolve' // A file: console.log(resolve('./index.js', import.meta.url)) //=> file:///Users/tilde/Projects/oss/import-meta-resolve/index.js // A CJS package: console.log(resolve('builtins', import.meta.url)) //=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/builtins/index.js // A scoped CJS package: console.log(resolve('@eslint/eslintrc', import.meta.url)) //=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/@eslint/eslintrc/lib/index.js // A package with an export map: console.log(resolve('micromark/lib/parse', import.meta.url)) //=> file:///Users/tilde/Projects/oss/import-meta-resolve/node_modules/micromark/lib/parse.js // A node builtin: console.log(resolve('fs', import.meta.url)) //=> node:fs ``` ## API This package exports the identifiers [`moduleResolve`][moduleresolve] and [`resolve`][resolve]. There is no default export. ### `resolve(specifier, parent)` Match `import.meta.resolve` except that `parent` is required (you can pass `import.meta.url`). ###### Parameters * `specifier` (`string`) — the module specifier to resolve relative to parent (`/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc) * `parent` (`string`, example: `import.meta.url`) — the absolute parent module URL to resolve from; you must pass `import.meta.url` or something else ###### Returns Full `file:`, `data:`, or `node:` URL (`string`) to the found thing ###### Throws Throws an [`ErrnoException`][errnoexception]. ### `moduleResolve(specifier, parent, conditions, preserveSymlinks)` The [“Resolver Algorithm Specification”][algo] as detailed in the Node docs (which is slightly lower-level than `resolve`). ###### Parameters * `specifier` (`string`) — `/example.js`, `./example.js`, `../example.js`, `some-package`, `fs`, etc * `parent` (`URL`, example: `import.meta.url`) — full URL (to a file) that `specifier` is resolved relative from * `conditions` (`Set`, default: `new Set(['node', 'import'])`) — conditions * `preserveSymlinks` (`boolean`, default: `false`) — keep symlinks instead of resolving them ###### Returns A URL object (`URL`) to the found thing. ###### Throws Throws an [`ErrnoException`][errnoexception]. ### `ErrnoException` One of many different errors that occur when resolving (TypeScript type). ###### Type ```ts type ErrnoExceptionFields = Error & { errnode?: number | undefined code?: string | undefined path?: string | undefined syscall?: string | undefined url?: string | undefined } ``` The `code` field on errors is one of the following strings: * `'ERR_INVALID_MODULE_SPECIFIER'` — when `specifier` is invalid (example: `'#'`) * `'ERR_INVALID_PACKAGE_CONFIG'` — when a `package.json` is invalid (example: invalid JSON) * `'ERR_INVALID_PACKAGE_TARGET'` — when a `package.json` `exports` or `imports` is invalid (example: when it does not start with `'./'`) * `'ERR_MODULE_NOT_FOUND'` — when `specifier` cannot be found in `parent` (example: `'some-missing-package'`) * `'ERR_NETWORK_IMPORT_DISALLOWED'` — thrown when trying to resolve a local file or builtin from a remote file (`node:fs` relative to `'https://example.com'`) * `'ERR_PACKAGE_IMPORT_NOT_DEFINED'` — when a local import is not defined in an import map (example: `'#local'` when not defined) * `'ERR_PACKAGE_PATH_NOT_EXPORTED'` — when an export is not defined in an export map (example: `'tape/index.js'`, which is not in its export map) * `'ERR_UNSUPPORTED_DIR_IMPORT'` — when attempting to import a directory (example: `'./lib/'`) * `'ERR_UNKNOWN_FILE_EXTENSION'` — when somehow reading a file that has an unexpected extensions (`'./readme.md'`) * `'ERR_INVALID_ARG_VALUE'` — when `conditions` is incorrect ## Algorithm The algorithm for `resolve` matches how Node handles `import.meta.resolve`, with a couple of differences. The algorithm for `moduleResolve` matches the [Resolver Algorithm Specification][algo] as detailed in the Node docs (which is sync and slightly lower-level than `resolve`). ## Differences to Node * `parent` defaulting to `import.meta.url` cannot be ponyfilled: you have to explicitly pass it * no support for loaders (that would mean implementing all of loaders) * no support for CLI flags: `--conditions`, `--experimental-default-type`, `--experimental-json-modules`, `--experimental-network-imports`, `--experimental-policy`, `--experimental-wasm-modules`, `--input-type`, `--no-addons`, `--preserve-symlinks`, nor `--preserve-symlinks-main` work * no support for `WATCH_REPORT_DEPENDENCIES` env variable * no attempt is made to add a suggestion based on how things used to work in CJS before to not-found errors * prototypal methods are not guarded: Node protects for example `String#slice` or so from being tampered with, whereas this doesn’t ## Types This package is fully typed with [TypeScript][]. It exports the additional type [`ErrnoException`][errnoexception]. ## Compatibility This package is at least compatible with all maintained versions of Node.js. As of now, that is Node.js 16 and later. ## Contribute Yes please! See [How to Contribute to Open Source][contribute]. ## License [MIT][license] © [Titus Wormer][author] and Node.js contributors [build-badge]: https://github.com/wooorm/import-meta-resolve/workflows/main/badge.svg [build]: https://github.com/wooorm/import-meta-resolve/actions [coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/import-meta-resolve.svg [coverage]: https://codecov.io/github/wooorm/import-meta-resolve [downloads-badge]: https://img.shields.io/npm/dm/import-meta-resolve.svg [downloads]: https://www.npmjs.com/package/import-meta-resolve [npm]: https://docs.npmjs.com/cli/install [license]: license [author]: https://wooorm.com [esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c [typescript]: https://www.typescriptlang.org [contribute]: https://opensource.guide/how-to-contribute/ [algo]: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html#esm_resolver_algorithm [native-resolve]: https://nodejs.org/api/esm.html#esm_import_meta_resolve_specifier_parent [resolve]: #resolvespecifier-parent [moduleresolve]: #moduleResolvespecifier-parent-conditions-preserveSymlinks [errnoexception]: #errnoexception import-meta-resolve-4.1.0/script.js000066400000000000000000000021041461370205200172660ustar00rootroot00000000000000import path from 'node:path' import fs from 'node:fs/promises' const base = await fs.readFile(path.join('test', 'core.js'), 'utf8') const asyncLines = base // Special baseline test for Node < 20, that doesn't support sync `import.meta.resolve` .replace(/\bresolve(?=\()/g, 'await import.meta.resolve') .replace(/\bresolve(?=,)/g, 'import.meta.resolve') .replace( /const run = .*$/g, 'const run = async (/** @type {() => Promise} */ f) => f()' ) .replace(/run\(/g, 'await run(async ') await fs.writeFile(path.join('test', 'baseline-async.js'), asyncLines) const syncLines = base // Node < 20 does not support sync import.meta.resolve, so skipping these tests if so .replace(/\bresolve(?=\()/g, 'import.meta.resolve') .replace(/\bresolve(?=,)/g, 'import.meta.resolve') .replace( '{skip: false}', "{skip: semver.lt(process.versions.node, '20.0.0')}" ) .replace( /const run = .*$/g, 'const run = (/** @type {() => void} */ f) => f()' ) .replace(/run\(/g, 'run(async ') await fs.writeFile(path.join('test', 'baseline.js'), syncLines) import-meta-resolve-4.1.0/test/000077500000000000000000000000001461370205200164065ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/core.js000066400000000000000000000450771461370205200177110ustar00rootroot00000000000000/** * @typedef {import('../index.js').ErrnoException} ErrnoException */ import assert from 'node:assert/strict' import {promises as fs, renameSync} from 'node:fs' import process from 'node:process' import {URL, pathToFileURL} from 'node:url' import test from 'node:test' import semver from 'semver' import {resolve} from '../index.js' const windows = process.platform === 'win32' const nodeBefore18 = semver.lt(process.versions.node, '18.0.0') const nodeBefore20 = semver.lt(process.versions.node, '20.0.0') const run = (/** @type {() => void} */ f) => f() process.on('exit', async () => { try { // Has to be sync. renameSync('package.json.bak', 'package.json') } catch (error) { const exception = /** @type {ErrnoException} */ (error) // ignore if not found, which will happen because baseline.js sometimes // skips the test. if (exception.code !== 'ENOENT') throw error } }) test( 'resolve(specifier, base?, conditions?)', // // Note: this is toggled by the `baseline*.js` tests (see `script.js` for details on why and how) {skip: false}, async function () { assert(resolve, 'expected `resolve` to exist (needed for TS in baseline)') await fs.rename('package.json', 'package.json.bak') try { resolve('', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal(exception.code, 'ERR_MODULE_NOT_FOUND', 'empty string') } try { resolve('abc', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'unfound bare specifier' ) } // Node before 20 throws for missing URLs. if (!nodeBefore20) { assert.equal( resolve('/abc', import.meta.url), new URL('/abc', import.meta.url).href, 'unfound absolute path' ) assert.equal( resolve('./abc', import.meta.url), new URL('abc', import.meta.url).href, 'unfound relative path' ) assert.equal( resolve('../abc', import.meta.url), new URL('../abc', import.meta.url).href, 'unfound relative parental path' ) } try { resolve('#', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_INVALID_MODULE_SPECIFIER', 'empty import specifier' ) } try { resolve('#/', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_INVALID_MODULE_SPECIFIER', 'empty absolute import specifier' ) } assert.equal( resolve('../tsconfig.json', import.meta.url), pathToFileURL('tsconfig.json').href, 'should resolve a json file' ) assert.equal( resolve('./index.js', import.meta.url), pathToFileURL('test/index.js').href, 'should resolve a js file' ) assert.equal( resolve('..', import.meta.url), pathToFileURL('./').href, 'should resolve a directory (1)' ) assert.equal( resolve('../lib', import.meta.url), pathToFileURL('./lib').href, 'should resolve a directory (2)' ) assert.equal( resolve('../lib/', import.meta.url), pathToFileURL('./lib/').href, 'should resolve a directory (3)' ) assert.equal( resolve('micromark', import.meta.url), new URL('../node_modules/micromark/index.js', import.meta.url).href, 'should resolve a bare specifier to a package' ) assert.equal( resolve('f-ck/index.js', import.meta.url), new URL('../node_modules/f-ck/index.js', import.meta.url).href, 'should resolve a bare specifier plus path' ) assert.equal( resolve('@bcoe/v8-coverage', import.meta.url), new URL( '../node_modules/@bcoe/v8-coverage/dist/lib/index.js', import.meta.url ).href, 'should resolve a bare specifier w/ scope to a package' ) try { resolve('xxx-missing', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'missing bare specifier' ) } try { resolve('@a/b', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'missing scoped bare specifier' ) } try { resolve('@scope-only', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_INVALID_MODULE_SPECIFIER', 'invalid scoped specifier' ) } try { resolve('%20', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_INVALID_MODULE_SPECIFIER', 'invalid package name as specifier' ) } try { resolve('micromark/index.js', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_PATH_NOT_EXPORTED', 'bare specifier w/ path that’s not exported' ) } assert.equal( resolve('micromark/stream', import.meta.url), new URL('../node_modules/micromark/stream.js', import.meta.url).href, 'should resolve a bare specifier + path which is exported' ) assert.equal( resolve('micromark', import.meta.url), new URL('../node_modules/micromark/index.js', import.meta.url).href, 'should cache results' ) assert.equal( resolve('fs', import.meta.url), 'node:fs', 'should support internal node modules' ) assert.equal( resolve('node:fs', import.meta.url), 'node:fs', 'should support `node:` protocols' ) assert.equal( resolve('data:1', import.meta.url), 'data:1', 'should support `data:` protocols' ) // Node before 18 fails on unknown protocols. if (!nodeBefore18) { assert.equal( resolve('xss:1', import.meta.url), 'xss:1', 'should support other protocols' ) } if (!nodeBefore18) { try { resolve('node:fs', 'https://example.com/file.html') assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_NETWORK_IMPORT_DISALLOWED', 'should not support loading builtins from http' ) } } assert.equal( resolve('./index.js?1', import.meta.url), new URL('index.js?1', import.meta.url).href, 'should support a `search` in specifiers' ) assert.equal( resolve('./index.js#1', import.meta.url), new URL('index.js#1', import.meta.url).href, 'should support a `hash` in specifiers' ) try { resolve('./example.js', 'data:1') assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) if (!nodeBefore18) { assert(exception.code) // To do: when pulling in new Node changes, the code is now // `ERR_UNSUPPORTED_RESOLVE_REQUEST` (from around Node 21.7). // Earlier was `ERR_INVALID_URL`. assert.ok( ['ERR_UNSUPPORTED_RESOLVE_REQUEST', 'ERR_INVALID_URL'].includes( exception.code ), 'should not be able to resolve relative to a `data:` parent url' ) } } assert.equal( resolve('./index.js', import.meta.url), new URL('index.js', import.meta.url).href, 'should be able to find files w/o `package.json`' ) assert.equal( resolve('micromark', import.meta.url), new URL('../node_modules/micromark/index.js', import.meta.url).href, 'should be able to find packages w/o `package.json`' ) try { resolve('xxx-missing', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'missing packages w/o `package.json`' ) } try { resolve('#local', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED', 'missing import map w/o `package.json`' ) } try { resolve('no-package-json', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'should not be able to import packages that themselves don’t have `package.json`s (1)' ) } try { resolve('package-no-main', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_MODULE_NOT_FOUND', 'should not be able to import packages w/o index files' ) } assert.equal( resolve('package-no-main-2', import.meta.url), new URL('node_modules/package-no-main-2/index.js', import.meta.url).href, 'should be able to import CJS packages w/o `main`' ) run(() => { assert(resolve, 'expected `resolve` to exist (needed for TS in baseline)') const oldEmitWarning = process.emitWarning /** @type {string | undefined} */ let deprecation // @ts-expect-error hush process.emitWarning = /** * @param {unknown} _1 * @param {unknown} _2 * @param {string} code */ (_1, _2, code) => { deprecation = code } assert.equal( resolve('package-no-main-3', import.meta.url), new URL('node_modules/package-no-main-3/index.js', import.meta.url) .href, 'should be able to import ESM packages w/o `main`, but warn (1)' ) if (nodeBefore18) { // Empty. } else { assert.equal( deprecation, 'DEP0151', 'should be able to import ESM packages w/o `main`, but warn (2)' ) } process.emitWarning = oldEmitWarning }) run(() => { assert(resolve, 'expected `resolve` to exist (needed for TS in baseline)') const oldEmitWarning = process.emitWarning /** @type {string | undefined} */ let deprecation // @ts-expect-error hush process.emitWarning = /** * @param {unknown} _1 * @param {unknown} _2 * @param {string} code */ (_1, _2, code) => { deprecation = code } assert.equal( resolve('package-no-main-4', import.meta.url), new URL('node_modules/package-no-main-4/index.js', import.meta.url) .href, 'should be able to import ESM packages w/ non-full `main`, but warn (1)' ) if (nodeBefore18) { // Empty. } else { assert.equal( deprecation, 'DEP0151', 'should be able to import ESM packages w/ non-full `main`, but warn (2)' ) } process.emitWarning = oldEmitWarning }) try { resolve('package-invalid-json', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_INVALID_PACKAGE_CONFIG', 'should not be able to import packages w/ broken `package.json`s' ) } assert.equal( resolve('package-export-map-1/a', import.meta.url), new URL('node_modules/package-export-map-1/b.js', import.meta.url).href, 'should be able to resolve to something from an export map (1)' ) assert.equal( resolve('package-export-map-1/lib/c', import.meta.url), new URL('node_modules/package-export-map-1/lib/c.js', import.meta.url) .href, 'should be able to resolve to something from an export map (2)' ) assert.equal( resolve('package-export-map-2', import.meta.url), new URL('node_modules/package-export-map-2/main.js', import.meta.url) .href, 'should be able to resolve to something from a main export map' ) try { resolve('package-export-map-2/missing', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_PATH_NOT_EXPORTED', 'should not be able to import things not in an export map' ) } try { resolve('package-export-map-4', import.meta.url) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_PATH_NOT_EXPORTED', 'should not be able to import things from an empty export map' ) } run(() => { assert(resolve, 'expected `resolve` to exist (needed for TS in baseline)') const oldEmitWarning = process.emitWarning /** @type {string} */ let deprecation // Windows doesn’t like `/` as a final path separator here. if (windows) return // @ts-expect-error hush process.emitWarning = /** * @param {unknown} _1 * @param {unknown} _2 * @param {string} code */ (_1, _2, code) => { if (deprecation) assert.fail() deprecation = code } assert.equal( resolve( './a/', new URL('node_modules/package-export-map-5/', import.meta.url).href ), new URL('node_modules/package-export-map-5/a/', import.meta.url).href ) try { // Twice for coverage: deprecation should fire only once. resolve( './a/b.js', new URL('node_modules/package-export-map-5/', import.meta.url).href ) assert.fail() } catch {} process.emitWarning = oldEmitWarning }) assert.equal( resolve( '#a', new URL('node_modules/package-import-map-1/', import.meta.url).href ), new URL('node_modules/package-import-map-1/index.js', import.meta.url) .href, 'should be able to resolve to something from a main export map w/ package name' ) try { resolve( '#b', new URL('node_modules/package-import-map-1/', import.meta.url).href ) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED', 'should not be able to import things not in an import map' ) } try { resolve( '#a', new URL('node_modules/package-import-map-2/', import.meta.url).href ) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) assert.equal( exception.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED', 'should not be able to import things not in an import map incorrectly defined w/o `#`' ) } assert.equal( resolve( '#a/b.js', new URL('node_modules/package-import-map-3/', import.meta.url).href ), new URL('node_modules/package-import-map-3/index.js', import.meta.url) .href, 'should be able to resolve to something to import map splats' ) try { resolve( '#a/b.js', new URL('node_modules/package-import-map-4/', import.meta.url).href ) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) if (!nodeBefore18) { assert.equal( exception.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED', 'should not be able to import an invalid import package target' ) } } run(() => { assert(resolve, 'expected `resolve` to exist (needed for TS in baseline)') const oldEmitWarning = process.emitWarning /** @type {string | undefined} */ let deprecation // @ts-expect-error hush process.emitWarning = /** * @param {unknown} _1 * @param {unknown} _2 * @param {string} code */ (_1, _2, code) => { if (deprecation) assert.fail() deprecation = code } try { resolve( '#a/b.js', new URL('node_modules/package-import-map-5/', import.meta.url).href ) assert.fail() } catch (error) { const exception = /** @type {ErrnoException} */ (error) if (!nodeBefore18) { assert.equal( exception.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED', 'should support legacy folders in import maps (1)' ) } } process.emitWarning = oldEmitWarning }) assert.equal( resolve( '#a', new URL('node_modules/package-import-map-6/', import.meta.url).href ), new URL('node:net').href, 'should be able to resolve to a built-in node module' ) assert.equal( resolve( 'package-self-import-1', new URL('node_modules/package-self-import-1/', import.meta.url).href ), new URL('node_modules/package-self-import-1/index.js', import.meta.url) .href, 'should be able to resolve a self-import' ) assert.equal( resolve( 'package-self-import-1', new URL( 'node_modules/package-self-import-1/test/index.js', import.meta.url ).href ), new URL('node_modules/package-self-import-1/index.js', import.meta.url) .href, 'should be able to resolve a self-import from a sub-file' ) assert.equal( resolve('package-custom-extensions', import.meta.url), new URL('node_modules/package-custom-extensions/b.ts', import.meta.url) .href, 'should be able to resolve a custom `.ts` extension' ) assert.equal( resolve('package-custom-extensions/c', import.meta.url), new URL('node_modules/package-custom-extensions/d.wasm', import.meta.url) .href, 'should be able to resolve a custom `.wasm` extension' ) } ) import-meta-resolve-4.1.0/test/index.js000066400000000000000000000002131461370205200200470ustar00rootroot00000000000000/* eslint-disable import/no-unassigned-import */ import './core.js' import './ponyfill.js' /* eslint-enable import/no-unassigned-import */ import-meta-resolve-4.1.0/test/node_modules/000077500000000000000000000000001461370205200210635ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/no-package-json/000077500000000000000000000000001461370205200240375ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/no-package-json/.gitkeep000066400000000000000000000000001461370205200254560ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/000077500000000000000000000000001461370205200261635ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/b.ts000066400000000000000000000000001461370205200267420ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/d.wasm000066400000000000000000000000001461370205200272650ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/lib/000077500000000000000000000000001461370205200267315ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/lib/c.ts000066400000000000000000000000001461370205200275110ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-custom-extensions/package.json000066400000000000000000000002041461370205200304450ustar00rootroot00000000000000{ "name": "package-custom-extensions", "exports": { ".": "./b.ts", "./c": "./d.wasm", "./lib/*": "./lib/*.ts" } } import-meta-resolve-4.1.0/test/node_modules/package-export-map-1/000077500000000000000000000000001461370205200247065ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-1/b.js000066400000000000000000000000001461370205200254530ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-1/lib/000077500000000000000000000000001461370205200254545ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-1/lib/c.js000066400000000000000000000000001461370205200262220ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-1/package.json000066400000000000000000000001101461370205200271640ustar00rootroot00000000000000{ "exports": { "./a": "./b.js", "./lib/*": "./lib/*.js" } } import-meta-resolve-4.1.0/test/node_modules/package-export-map-2/000077500000000000000000000000001461370205200247075ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-2/main.js000066400000000000000000000000001461370205200261570ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-2/package.json000066400000000000000000000000351461370205200271730ustar00rootroot00000000000000{ "exports": "./main.js" } import-meta-resolve-4.1.0/test/node_modules/package-export-map-3/000077500000000000000000000000001461370205200247105ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-3/main.js000066400000000000000000000000001461370205200261600ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-3/package.json000066400000000000000000000000761461370205200272010ustar00rootroot00000000000000{ "name": "import-meta-resolve", "exports": "./main.js" } import-meta-resolve-4.1.0/test/node_modules/package-export-map-4/000077500000000000000000000000001461370205200247115ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-4/package.json000066400000000000000000000000241461370205200271730ustar00rootroot00000000000000{ "exports": {} } import-meta-resolve-4.1.0/test/node_modules/package-export-map-5/000077500000000000000000000000001461370205200247125ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-5/lib/000077500000000000000000000000001461370205200254605ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-5/lib/index.js000066400000000000000000000000001461370205200271130ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-export-map-5/package.json000066400000000000000000000000751461370205200272020ustar00rootroot00000000000000{ "type": "module", "exports": { "a/": "./lib" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-1/000077500000000000000000000000001461370205200246775ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-1/index.js000066400000000000000000000000001461370205200263320ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-1/package.json000066400000000000000000000001021461370205200271560ustar00rootroot00000000000000{ "type": "module", "imports": { "#a": "./index.js" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-2/000077500000000000000000000000001461370205200247005ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-2/index.js000066400000000000000000000000001461370205200263330ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-2/package.json000066400000000000000000000001011461370205200271560ustar00rootroot00000000000000{ "type": "module", "imports": { "a": "./index.js" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-3/000077500000000000000000000000001461370205200247015ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-3/index.js000066400000000000000000000000001461370205200263340ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-3/package.json000066400000000000000000000001041461370205200271620ustar00rootroot00000000000000{ "type": "module", "imports": { "#a/*": "./index.js" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-4/000077500000000000000000000000001461370205200247025ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-4/index.js000066400000000000000000000000001461370205200263350ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-4/package.json000066400000000000000000000001031461370205200271620ustar00rootroot00000000000000{ "type": "module", "imports": { "#a/": "./index.js" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-5/000077500000000000000000000000001461370205200247035ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-5/index.js000066400000000000000000000000001461370205200263360ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-5/package.json000066400000000000000000000000731461370205200271710ustar00rootroot00000000000000{ "type": "module", "imports": { "#a/": "./" } } import-meta-resolve-4.1.0/test/node_modules/package-import-map-6/000077500000000000000000000000001461370205200247045ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-6/index.js000066400000000000000000000000001461370205200263370ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-import-map-6/package.json000066400000000000000000000000731461370205200271720ustar00rootroot00000000000000{ "type": "module", "imports": { "#a": "net" } } import-meta-resolve-4.1.0/test/node_modules/package-invalid-json/000077500000000000000000000000001461370205200250515ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-invalid-json/index.js000066400000000000000000000000001461370205200265040ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-invalid-json/package.json000066400000000000000000000000021461370205200273270ustar00rootroot00000000000000{ import-meta-resolve-4.1.0/test/node_modules/package-no-main-1/000077500000000000000000000000001461370205200241505ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-1/package.json000066400000000000000000000000031461370205200264270ustar00rootroot00000000000000{} import-meta-resolve-4.1.0/test/node_modules/package-no-main-2/000077500000000000000000000000001461370205200241515ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-2/index.js000066400000000000000000000000001461370205200256040ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-2/package.json000066400000000000000000000000031461370205200264300ustar00rootroot00000000000000{} import-meta-resolve-4.1.0/test/node_modules/package-no-main-3/000077500000000000000000000000001461370205200241525ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-3/index.js000066400000000000000000000000001461370205200256050ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-3/package.json000066400000000000000000000000271461370205200264370ustar00rootroot00000000000000{ "type": "module" } import-meta-resolve-4.1.0/test/node_modules/package-no-main-4/000077500000000000000000000000001461370205200241535ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-4/index.js000066400000000000000000000000001461370205200256060ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-no-main-4/package.json000066400000000000000000000000541461370205200264400ustar00rootroot00000000000000{ "type": "module", "main": "./index" } import-meta-resolve-4.1.0/test/node_modules/package-self-import-1/000077500000000000000000000000001461370205200250535ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-self-import-1/index.js000066400000000000000000000000001461370205200265060ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-self-import-1/package.json000066400000000000000000000001011461370205200273310ustar00rootroot00000000000000{ "name": "package-self-import-1", "exports": "./index.js" } import-meta-resolve-4.1.0/test/node_modules/package-self-import-1/test/000077500000000000000000000000001461370205200260325ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/node_modules/package-self-import-1/test/index.js000066400000000000000000000000001461370205200274650ustar00rootroot00000000000000import-meta-resolve-4.1.0/test/ponyfill.js000066400000000000000000000010501461370205200205740ustar00rootroot00000000000000import assert from 'node:assert/strict' import test from 'node:test' import {resolve} from '../index.js' test('ponyfill', async function () { assert.deepEqual( Object.keys(await import('import-meta-resolve')).sort(), ['moduleResolve', 'resolve'], 'should expose the public api' ) try { // @ts-expect-error resolve('x') assert.fail() } catch (error) { assert.equal( String(error), 'Error: Please pass `parent`: `import-meta-resolve` cannot ponyfill that', 'should throw w/o `parent`' ) } }) import-meta-resolve-4.1.0/tsconfig.json000066400000000000000000000005721461370205200201420ustar00rootroot00000000000000{ "include": ["**/*.js"], "exclude": ["coverage/", "node_modules/"], "compilerOptions": { "checkJs": true, "declaration": true, "emitDeclarationOnly": true, "exactOptionalPropertyTypes": true, "forceConsistentCasingInFileNames": true, "lib": ["es2022"], "module": "node16", "newLine": "lf", "strict": true, "target": "es2020" } }