@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
JavaScript
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