/** * The MIT License (MIT) * * Copyright (c) 2018, Nick Gavrilov * * 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. * * From https://github.com/ilearnio/module-alias */ '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 module.exports.setMain = function(main){ require.main = main }