UNPKG

@antora/user-require-helper

Version:

A helper function to resolve a module name or path in relation to the specified context and require it.

89 lines (83 loc) 4.06 kB
'use strict' const expandPath = require('@antora/expand-path-helper') const [indexOfAnchorSep, isPath, { extname, sep }] = ((path) => [ path === path.posix ? (str) => str.indexOf(':') : (str) => (str.match(/:(?![/\\])/) ?? { index: -1 }).index, path === path.posix ? (str) => !Math.floor(str.indexOf('./') / 2) || str.charAt() === '/' : (str) => !(Math.floor(str.indexOf('./') / 2) && Math.floor(str.indexOf('.\\') / 2)) || path.isAbsolute(str), path, ])(require('node:path')) /** * Resolve the module name or path in relation to the specified context and require it. * * The purpose of this function is to require a JavaScript module (specified as a module name or * path request) from the user's environment. Building on the behavior of `require.resolve`, this * function honor prefixes recognized by the @antora/expand-path-helper module to anchor the * location of the requested module name or path to the resolved context specified in the request. * * This function inspects the request argument to differentiate between a module name and a path. If * the request argument has a file extension, it is resolved as a path. Additionally, if the request * argument begins with a dot or dot dot segment, and it does not contain a colon, it is resolved as * a path, even if it doesn't have a file extension. Otherwise, it's resolved as a module name. * * @param {String} request - The module or path to require. Must be a non-empty string. * @param {Object} [context={}] - Named parameters that control how the request is resolved. * @param {String} [context.base='~+'] - The base directory from which to resolve a relative module * name or path. * @param {String} [context.cwd=process.cwd()] - The absolute path to use as the working directory. * @param {String} [context.dot='.'] - The directory to use in place of a leading dot segment in the * module name or path. * @param {Array<String>} [context.path=[]] - The paths to pass to `require.resolve` when a bare * module name is specified. If this value is empty, no paths are passed to `require.resolve`. * @param {Array<String>} [context.resolve=require.resolve] - The resolve function to use to resolve * a module name or path request. * * @returns {Object} The exported module object of the module or script at the resolved path. */ const userRequire = (request, context) => { return require(userResolve(request, context)) } /** * Resolve the module name or path in relation to the specified context and return it. * * Refer to userRequire for the list of parameters. * * @returns {String} The absolute path resolved from the module name or path request. */ userRequire.resolve = (request, { base, cwd, dot, paths = [], resolve = require.resolve } = {}) => { if (typeof request !== 'string') { throw new TypeError(`The "request" argument must be of type string. Received type ${typeof request}`) } if (!request) return resolve(request) if (extname(request + '_')) return resolve(expandPath(request, { base, cwd, dot })) const anchorSepIdx = indexOfAnchorSep(request) if (!~anchorSepIdx && isPath(request)) return resolve(expandPath(request, { base, cwd, dot })) const lastChar = request.charAt(request.length - 1) if (lastChar === '/' || lastChar === sep) request = request.substr(0, request.length - 1) if (~anchorSepIdx && !request.startsWith('node:')) { const anchor = request.substr(0, anchorSepIdx) request = request.substr(anchorSepIdx + 1) switch (anchor) { case '': paths = [expandPath('', { base })] break case '.': paths = [expandPath('.', { dot })] break case '^': paths = [] break default: paths = [expandPath(anchor, { base, cwd, dot })] } } if (!paths.length) return resolve(request) try { return resolve(request, { paths }) } catch (err) { err.message = err.message.replace(/$/m, ` at path ${paths.join(' or ')}`) throw err } } const userResolve = userRequire.resolve module.exports = userRequire