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.
224 lines
5.8 KiB
224 lines
5.8 KiB
'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
|
|
|