You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
225 lines
5.8 KiB
225 lines
5.8 KiB
4 weeks ago
|
'use strict'
|
||
|
|
||
|
var BuiltinModule = require('module')
|
||
|
|
||
|
// Guard against poorly mocked module constructors
|
||
|
var Module = module.constructor.length > 1
|
||
|
? module.constructor
|
||
|
: BuiltinModule
|
||
|
|
||
|
var nodePath = require('path')
|
||
|
|
||
|
var modulePaths = []
|
||
|
var moduleAliases = {}
|
||
|
var moduleAliasNames = []
|
||
|
|
||
|
var oldNodeModulePaths = Module._nodeModulePaths
|
||
|
Module._nodeModulePaths = function (from) {
|
||
|
var paths = oldNodeModulePaths.call(this, from)
|
||
|
|
||
|
// Only include the module path for top-level modules
|
||
|
// that were not installed:
|
||
|
if (from.indexOf('node_modules') === -1) {
|
||
|
paths = modulePaths.concat(paths)
|
||
|
}
|
||
|
|
||
|
return paths
|
||
|
}
|
||
|
|
||
|
var oldResolveFilename = Module._resolveFilename
|
||
|
Module._resolveFilename = function (request, parentModule, isMain, options) {
|
||
|
for (var i = moduleAliasNames.length; i-- > 0;) {
|
||
|
var alias = moduleAliasNames[i]
|
||
|
if (isPathMatchesAlias(request, alias)) {
|
||
|
var aliasTarget = moduleAliases[alias]
|
||
|
// Custom function handler
|
||
|
if (typeof moduleAliases[alias] === 'function') {
|
||
|
var fromPath = parentModule.filename
|
||
|
aliasTarget = moduleAliases[alias](fromPath, request, alias)
|
||
|
if (!aliasTarget || typeof aliasTarget !== 'string') {
|
||
|
throw new Error('[module-alias] Expecting custom handler function to return path.')
|
||
|
}
|
||
|
}
|
||
|
request = nodePath.join(aliasTarget, request.substr(alias.length))
|
||
|
// Only use the first match
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return oldResolveFilename.call(this, request, parentModule, isMain, options)
|
||
|
}
|
||
|
|
||
|
function isPathMatchesAlias (path, alias) {
|
||
|
// Matching /^alias(\/|$)/
|
||
|
if (path.indexOf(alias) === 0) {
|
||
|
if (path.length === alias.length) return true
|
||
|
if (path[alias.length] === '/') return true
|
||
|
}
|
||
|
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
function addPathHelper (path, targetArray) {
|
||
|
path = nodePath.normalize(path)
|
||
|
if (targetArray && targetArray.indexOf(path) === -1) {
|
||
|
targetArray.unshift(path)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function removePathHelper (path, targetArray) {
|
||
|
if (targetArray) {
|
||
|
var index = targetArray.indexOf(path)
|
||
|
if (index !== -1) {
|
||
|
targetArray.splice(index, 1)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function addPath (path) {
|
||
|
var parent
|
||
|
path = nodePath.normalize(path)
|
||
|
|
||
|
if (modulePaths.indexOf(path) === -1) {
|
||
|
modulePaths.push(path)
|
||
|
// Enable the search path for the current top-level module
|
||
|
var mainModule = getMainModule()
|
||
|
if (mainModule) {
|
||
|
addPathHelper(path, mainModule.paths)
|
||
|
}
|
||
|
parent = module.parent
|
||
|
|
||
|
// Also modify the paths of the module that was used to load the
|
||
|
// app-module-paths module and all of it's parents
|
||
|
while (parent && parent !== mainModule) {
|
||
|
addPathHelper(path, parent.paths)
|
||
|
parent = parent.parent
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function addAliases (aliases) {
|
||
|
for (var alias in aliases) {
|
||
|
addAlias(alias, aliases[alias])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function addAlias (alias, target) {
|
||
|
moduleAliases[alias] = target
|
||
|
// Cost of sorting is lower here than during resolution
|
||
|
moduleAliasNames = Object.keys(moduleAliases)
|
||
|
moduleAliasNames.sort()
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Reset any changes maded (resets all registered aliases
|
||
|
* and custom module directories)
|
||
|
* The function is undocumented and for testing purposes only
|
||
|
*/
|
||
|
function reset () {
|
||
|
var mainModule = getMainModule()
|
||
|
|
||
|
// Reset all changes in paths caused by addPath function
|
||
|
modulePaths.forEach(function (path) {
|
||
|
if (mainModule) {
|
||
|
removePathHelper(path, mainModule.paths)
|
||
|
}
|
||
|
|
||
|
// Delete from require.cache if the module has been required before.
|
||
|
// This is required for node >= 11
|
||
|
Object.getOwnPropertyNames(require.cache).forEach(function (name) {
|
||
|
if (name.indexOf(path) !== -1) {
|
||
|
delete require.cache[name]
|
||
|
}
|
||
|
})
|
||
|
|
||
|
var parent = module.parent
|
||
|
while (parent && parent !== mainModule) {
|
||
|
removePathHelper(path, parent.paths)
|
||
|
parent = parent.parent
|
||
|
}
|
||
|
})
|
||
|
|
||
|
modulePaths = []
|
||
|
moduleAliases = {}
|
||
|
moduleAliasNames = []
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Import aliases from package.json
|
||
|
* @param {object} options
|
||
|
*/
|
||
|
function init (options) {
|
||
|
if (typeof options === 'string') {
|
||
|
options = { base: options }
|
||
|
}
|
||
|
|
||
|
options = options || {}
|
||
|
|
||
|
var candidatePackagePaths
|
||
|
if (options.base) {
|
||
|
candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, ''))]
|
||
|
} else {
|
||
|
// There is probably 99% chance that the project root directory in located
|
||
|
// above the node_modules directory,
|
||
|
// Or that package.json is in the node process' current working directory (when
|
||
|
// running a package manager script, e.g. `yarn start` / `npm run start`)
|
||
|
candidatePackagePaths = [nodePath.join(__dirname, '../..'), process.cwd()]
|
||
|
}
|
||
|
|
||
|
var npmPackage
|
||
|
var base
|
||
|
for (var i in candidatePackagePaths) {
|
||
|
try {
|
||
|
base = candidatePackagePaths[i]
|
||
|
|
||
|
npmPackage = require(nodePath.join(base, 'package.json'))
|
||
|
break
|
||
|
} catch (e) {
|
||
|
// noop
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (typeof npmPackage !== 'object') {
|
||
|
var pathString = candidatePackagePaths.join(',\n')
|
||
|
throw new Error('Unable to find package.json in any of:\n[' + pathString + ']')
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Import aliases
|
||
|
//
|
||
|
|
||
|
var aliases = npmPackage._moduleAliases || {}
|
||
|
|
||
|
for (var alias in aliases) {
|
||
|
if (aliases[alias][0] !== '/') {
|
||
|
aliases[alias] = nodePath.join(base, aliases[alias])
|
||
|
}
|
||
|
}
|
||
|
|
||
|
addAliases(aliases)
|
||
|
|
||
|
//
|
||
|
// Register custom module directories (like node_modules)
|
||
|
//
|
||
|
|
||
|
if (npmPackage._moduleDirectories instanceof Array) {
|
||
|
npmPackage._moduleDirectories.forEach(function (dir) {
|
||
|
if (dir === 'node_modules') return
|
||
|
|
||
|
var modulePath = nodePath.join(base, dir)
|
||
|
addPath(modulePath)
|
||
|
})
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getMainModule () {
|
||
|
return require.main._simulateRepl ? undefined : require.main
|
||
|
}
|
||
|
|
||
|
module.exports = init
|
||
|
module.exports.addPath = addPath
|
||
|
module.exports.addAlias = addAlias
|
||
|
module.exports.addAliases = addAliases
|
||
|
module.exports.isPathMatchesAlias = isPathMatchesAlias
|
||
|
module.exports.reset = reset
|