├── .github └── workflows │ └── node.js.yml ├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package.json ├── register.js └── test ├── specs.js └── src ├── bar └── baz │ └── index.js ├── foo └── index.js ├── mocha ├── hello.js └── test.js ├── node_modules └── module-alias │ └── .keep ├── node_modules_custom └── some-module │ └── index.js └── package.json /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: test 5 | 6 | on: 7 | push: 8 | branches: [ dev ] 9 | pull_request: 10 | branches: [ dev ] 11 | workflow_dispatch: 12 | 13 | jobs: 14 | build: 15 | 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | matrix: 20 | node-version: [6.x, 8.x, 10.x, 12.x, 14.x, 16.x, 17.x] 21 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ 22 | fail-fast: false 23 | 24 | steps: 25 | - uses: actions/checkout@v2 26 | - name: Use Node.js ${{ matrix.node-version }} 27 | uses: actions/setup-node@v2 28 | with: 29 | node-version: ${{ matrix.node-version }} 30 | - run: node -v 31 | - run: npm -v 32 | - run: npm install 33 | - run: npm run testonly 34 | 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018, Nick Gavrilov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # module-alias 2 | [![NPM Version][npm-image]][npm-url] 3 | 4 | If everyone who reads this would donate just $1, I would be a millionaire in 1 week! 🙃 Thank you for reaching 1M+ weekly downloads! 5 | 6 | More donations means more motivation for me to make updates. Thank you so much! 7 | 8 | [DONATE $1 ❤️](https://tinyurl.com/donate-module-alias) 9 | 10 | --- 11 | 12 | Create aliases of directories and register custom module paths in NodeJS like a boss! 13 | 14 | No more shit-coding paths in Node like so: 15 | 16 | ```js 17 | require('../../../../some/very/deep/module') 18 | ``` 19 | Enough of this madness! 20 | 21 | Just create an alias and do it the right way: 22 | 23 | ```js 24 | var module = require('@deep/module') 25 | // Or ES6 26 | import module from '@deep/module' 27 | ``` 28 | 29 | It also allows you to register directories that will act just like `node_modules` but with your own private modules, so that you can access them directly: 30 | 31 | ```js 32 | require('my_private_module'); 33 | // Or ES6 34 | import module from 'my_private_module' 35 | ``` 36 | 37 | **WARNING:** If you are going to use this package within another NPM package, please read [Using within another NPM package](#using-within-another-npm-package) first to be aware of potential caveats. 38 | 39 | ## Install 40 | 41 | ``` 42 | npm i --save module-alias 43 | ``` 44 | 45 | ## Usage 46 | 47 | Add your custom configuration to your `package.json` (in your application's root) 48 | 49 | ```js 50 | // Aliases 51 | "_moduleAliases": { 52 | "@root" : ".", // Application's root 53 | "@deep" : "src/some/very/deep/directory/or/file", 54 | "@my_module" : "lib/some-file.js", 55 | "something" : "src/foo", // Or without @. Actually, it could be any string 56 | } 57 | 58 | // Custom module directories, just like `node_modules` but with your private modules (optional) 59 | "_moduleDirectories": ["node_modules_custom"], 60 | ``` 61 | 62 | Then add this line at the very main file of your app, before any code 63 | 64 | ```js 65 | require('module-alias/register') 66 | ``` 67 | 68 | **And you're all set!** Now you can do stuff like: 69 | 70 | ```js 71 | require('something') 72 | const module = require('@root/some-module') 73 | const veryDeepModule = require('@deep/my-module') 74 | const customModule = require('my_private_module') // module from `node_modules_custom` directory 75 | 76 | // Or ES6 77 | import 'something' 78 | import module from '@root/some-module' 79 | import veryDeepModule from '@deep/my-module' 80 | import customModule from 'my_private_module' // module from `node_modules_custom` directory 81 | ``` 82 | 83 | ## Advanced usage 84 | 85 | If you don't want to modify your `package.json` or you just prefer to set it all up programmatically, then the following methods are available for you: 86 | 87 | * `addAlias('alias', 'target_path')` - register a single alias 88 | * `addAliases({ 'alias': 'target_path', ... }) ` - register multiple aliases 89 | * `addPath(path)` - Register custom modules directory (like node_modules, but with your own modules) 90 | 91 | _Examples:_ 92 | ```js 93 | const moduleAlias = require('module-alias') 94 | 95 | // 96 | // Register alias 97 | // 98 | moduleAlias.addAlias('@client', __dirname + '/src/client') 99 | 100 | // Or multiple aliases 101 | moduleAlias.addAliases({ 102 | '@root' : __dirname, 103 | '@client': __dirname + '/src/client', 104 | ... 105 | }) 106 | 107 | // Custom handler function (starting from v2.1) 108 | moduleAlias.addAlias('@src', (fromPath, request, alias) => { 109 | // fromPath - Full path of the file from which `require` was called 110 | // request - The path (first argument) that was passed into `require` 111 | // alias - The same alias that was passed as first argument to `addAlias` (`@src` in this case) 112 | 113 | // Return any custom target path for the `@src` alias depending on arguments 114 | if (fromPath.startsWith(__dirname + '/others')) return __dirname + '/others' 115 | return __dirname + '/src' 116 | }) 117 | 118 | // 119 | // Register custom modules directory 120 | // 121 | moduleAlias.addPath(__dirname + '/node_modules_custom') 122 | moduleAlias.addPath(__dirname + '/src') 123 | 124 | // 125 | // Import settings from a specific package.json 126 | // 127 | moduleAlias(__dirname + '/package.json') 128 | 129 | // Or let module-alias to figure where your package.json is 130 | // located. By default it will look in the same directory 131 | // where you have your node_modules (application's root) 132 | moduleAlias() 133 | ``` 134 | 135 | ## Usage with WebPack 136 | 137 | Luckily, WebPack has a built in support for aliases and custom modules directories so it's easy to make it work on the client side as well! 138 | 139 | ```js 140 | // webpack.config.js 141 | const npm_package = require('./package.json') 142 | 143 | module.exports = { 144 | entry: { ... }, 145 | resolve: { 146 | root: __dirname, 147 | alias: npm_package._moduleAliases || {}, 148 | modules: npm_package._moduleDirectories || [] // eg: ["node_modules", "node_modules_custom", "src"] 149 | } 150 | } 151 | ``` 152 | 153 | More details on the [official documentation](https://webpack.js.org/configuration/resolve). 154 | 155 | ## Usage with Jest 156 | 157 | Unfortunately, `module-alias` itself would not work from Jest due to a custom behavior of Jest's `require`. But you can use it's own aliasing mechanism instead. The configuration can be defined either in `package.json` or `jest.config.js`. The example below is for `package.json`: 158 | 159 | ```js 160 | "jest": { 161 | "moduleNameMapper": { 162 | "@root/(.*)": "/$1", 163 | "@client/(.*)": "/src/client/$1" 164 | }, 165 | } 166 | ``` 167 | 168 | More details on the [official documentation](https://jestjs.io/docs/en/configuration#modulenamemapper-objectstring-string--arraystring). 169 | 170 | ## Using within another NPM package 171 | 172 | You can use `module-alias` within another NPM package, however there are a few things to take into consideration. 173 | 174 | 1. As the aliases are global, you should make sure your aliases are unique, to avoid conflicts with end-user code, or with other libraries using module-alias. For example, you could prefix your aliases with '@my-lib/', and then use require('@my-lib/deep'). 175 | 2. The internal "register" mechanism may not work, you should not rely on `require('module-alias/register')` for automatic detection of `package.json` location (where you defined your aliases), as it tries to find package.json in either the current working directory of your node process, or two levels down from node_modules/module-alias. It is extremely likely that this is end-user code. So, instead, your should either register aliases manually with `moduleAlias.addAlias`, or using something like `require('module-alias')(__dirname)`. 176 | 177 | Here is an [example project](https://github.com/Kehrlann/module-alias-library). 178 | 179 | 180 | ## Known incompatibilities 181 | 182 | This module does not play well with: 183 | 184 | - Front-end JavaScript code. Module-alias is designed for server side so do not expect it to work with front-end frameworks (React, Vue, ...) as they tend to use Webpack. Use Webpack's [resolve.alias](https://webpack.js.org/configuration/resolve/#resolvealias) mechanism instead. 185 | - [Jest](https://jestjs.io), which discards node's module system entirely to use it's own module system, bypassing module-alias. 186 | - The [NCC compiler](https://github.com/zeit/ncc), as it uses WebPack under the hood without exposing properties, such as resolve.alias. It is not [something they wish to do](https://github.com/zeit/ncc/pull/460). 187 | 188 | ## How it works? 189 | 190 | In order to register an alias it modifies the internal `Module._resolveFilename` method so that when you use `require` or `import` it first checks whether the given string starts with one of the registered aliases, if so, it replaces the alias in the string with the target path of the alias. 191 | 192 | In order to register a custom modules path (`addPath`) it modifies the internal `Module._nodeModulePaths` method so that the given directory then acts like it's the `node_modules` directory. 193 | 194 | ## Refactor your code (for already existing projects) 195 | 196 | If you are using this on an existing project, you can use [relative-to-alias](https://github.com/s-yadav/relative-to-alias) to refactor your code to start using aliases. 197 | 198 | ## Donate 199 | 200 | If everyone who downloads module-alias would donate just $1, I would be a millionaire in 1 week! 201 | 202 | I love contributing to open source, for free, but you know, sometimes, in the middle of the night, I may wan to eat. 203 | 204 | There are some improvements planned for module-alias and your donations will help a lot to make it happen faster. 205 | 206 | [DONATE $1 ❤️](https://tinyurl.com/donate-module-alias) and thank you so much! 207 | 208 | 209 | [npm-image]: https://img.shields.io/npm/v/module-alias.svg 210 | [npm-url]: https://npmjs.org/package/module-alias 211 | [travis-image]: https://img.shields.io/travis/ilearnio/module-alias/master.svg 212 | [travis-url]: https://travis-ci.org/ilearnio/module-alias 213 | 214 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | var BuiltinModule = require('module') 4 | 5 | // Guard against poorly mocked module constructors 6 | var Module = module.constructor.length > 1 7 | ? module.constructor 8 | : BuiltinModule 9 | 10 | var nodePath = require('path') 11 | 12 | var modulePaths = [] 13 | var moduleAliases = {} 14 | var moduleAliasNames = [] 15 | 16 | var oldNodeModulePaths = Module._nodeModulePaths 17 | Module._nodeModulePaths = function (from) { 18 | var paths = oldNodeModulePaths.call(this, from) 19 | 20 | // Only include the module path for top-level modules 21 | // that were not installed: 22 | if (from.indexOf('node_modules') === -1) { 23 | paths = modulePaths.concat(paths) 24 | } 25 | 26 | return paths 27 | } 28 | 29 | var oldResolveFilename = Module._resolveFilename 30 | Module._resolveFilename = function (request, parentModule, isMain, options) { 31 | for (var i = moduleAliasNames.length; i-- > 0;) { 32 | var alias = moduleAliasNames[i] 33 | if (isPathMatchesAlias(request, alias)) { 34 | var aliasTarget = moduleAliases[alias] 35 | // Custom function handler 36 | if (typeof moduleAliases[alias] === 'function') { 37 | var fromPath = parentModule.filename 38 | aliasTarget = moduleAliases[alias](fromPath, request, alias) 39 | if (!aliasTarget || typeof aliasTarget !== 'string') { 40 | throw new Error('[module-alias] Expecting custom handler function to return path.') 41 | } 42 | } 43 | request = nodePath.join(aliasTarget, request.substr(alias.length)) 44 | // Only use the first match 45 | break 46 | } 47 | } 48 | 49 | return oldResolveFilename.call(this, request, parentModule, isMain, options) 50 | } 51 | 52 | function isPathMatchesAlias (path, alias) { 53 | // Matching /^alias(\/|$)/ 54 | if (path.indexOf(alias) === 0) { 55 | if (path.length === alias.length) return true 56 | if (path[alias.length] === '/') return true 57 | } 58 | 59 | return false 60 | } 61 | 62 | function addPathHelper (path, targetArray) { 63 | path = nodePath.normalize(path) 64 | if (targetArray && targetArray.indexOf(path) === -1) { 65 | targetArray.unshift(path) 66 | } 67 | } 68 | 69 | function removePathHelper (path, targetArray) { 70 | if (targetArray) { 71 | var index = targetArray.indexOf(path) 72 | if (index !== -1) { 73 | targetArray.splice(index, 1) 74 | } 75 | } 76 | } 77 | 78 | function addPath (path) { 79 | var parent 80 | path = nodePath.normalize(path) 81 | 82 | if (modulePaths.indexOf(path) === -1) { 83 | modulePaths.push(path) 84 | // Enable the search path for the current top-level module 85 | var mainModule = getMainModule() 86 | if (mainModule) { 87 | addPathHelper(path, mainModule.paths) 88 | } 89 | parent = module.parent 90 | 91 | // Also modify the paths of the module that was used to load the 92 | // app-module-paths module and all of it's parents 93 | while (parent && parent !== mainModule) { 94 | addPathHelper(path, parent.paths) 95 | parent = parent.parent 96 | } 97 | } 98 | } 99 | 100 | function addAliases (aliases) { 101 | for (var alias in aliases) { 102 | addAlias(alias, aliases[alias]) 103 | } 104 | } 105 | 106 | function addAlias (alias, target) { 107 | moduleAliases[alias] = target 108 | // Cost of sorting is lower here than during resolution 109 | moduleAliasNames = Object.keys(moduleAliases) 110 | moduleAliasNames.sort() 111 | } 112 | 113 | /** 114 | * Reset any changes maded (resets all registered aliases 115 | * and custom module directories) 116 | * The function is undocumented and for testing purposes only 117 | */ 118 | function reset () { 119 | var mainModule = getMainModule() 120 | 121 | // Reset all changes in paths caused by addPath function 122 | modulePaths.forEach(function (path) { 123 | if (mainModule) { 124 | removePathHelper(path, mainModule.paths) 125 | } 126 | 127 | // Delete from require.cache if the module has been required before. 128 | // This is required for node >= 11 129 | Object.getOwnPropertyNames(require.cache).forEach(function (name) { 130 | if (name.indexOf(path) !== -1) { 131 | delete require.cache[name] 132 | } 133 | }) 134 | 135 | var parent = module.parent 136 | while (parent && parent !== mainModule) { 137 | removePathHelper(path, parent.paths) 138 | parent = parent.parent 139 | } 140 | }) 141 | 142 | modulePaths = [] 143 | moduleAliases = {} 144 | moduleAliasNames = [] 145 | } 146 | 147 | /** 148 | * Import aliases from package.json 149 | * @param {object} options 150 | */ 151 | function init (options) { 152 | if (typeof options === 'string') { 153 | options = { base: options } 154 | } 155 | 156 | options = options || {} 157 | 158 | var candidatePackagePaths 159 | if (options.base) { 160 | candidatePackagePaths = [nodePath.resolve(options.base.replace(/\/package\.json$/, ''))] 161 | } else { 162 | // There is probably 99% chance that the project root directory in located 163 | // above the node_modules directory, 164 | // Or that package.json is in the node process' current working directory (when 165 | // running a package manager script, e.g. `yarn start` / `npm run start`) 166 | candidatePackagePaths = [nodePath.join(__dirname, '../..'), process.cwd()] 167 | } 168 | 169 | var npmPackage 170 | var base 171 | for (var i in candidatePackagePaths) { 172 | try { 173 | base = candidatePackagePaths[i] 174 | 175 | npmPackage = require(nodePath.join(base, 'package.json')) 176 | break 177 | } catch (e) { 178 | // noop 179 | } 180 | } 181 | 182 | if (typeof npmPackage !== 'object') { 183 | var pathString = candidatePackagePaths.join(',\n') 184 | throw new Error('Unable to find package.json in any of:\n[' + pathString + ']') 185 | } 186 | 187 | // 188 | // Import aliases 189 | // 190 | 191 | var aliases = npmPackage._moduleAliases || {} 192 | 193 | for (var alias in aliases) { 194 | if (aliases[alias][0] !== '/') { 195 | aliases[alias] = nodePath.join(base, aliases[alias]) 196 | } 197 | } 198 | 199 | addAliases(aliases) 200 | 201 | // 202 | // Register custom module directories (like node_modules) 203 | // 204 | 205 | if (npmPackage._moduleDirectories instanceof Array) { 206 | npmPackage._moduleDirectories.forEach(function (dir) { 207 | if (dir === 'node_modules') return 208 | 209 | var modulePath = nodePath.join(base, dir) 210 | addPath(modulePath) 211 | }) 212 | } 213 | } 214 | 215 | function getMainModule () { 216 | return require.main._simulateRepl ? undefined : require.main 217 | } 218 | 219 | module.exports = init 220 | module.exports.addPath = addPath 221 | module.exports.addAlias = addAlias 222 | module.exports.addAliases = addAliases 223 | module.exports.isPathMatchesAlias = isPathMatchesAlias 224 | module.exports.reset = reset 225 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "module-alias", 3 | "description": "Create aliases of directories and register custom module paths", 4 | "version": "2.2.3", 5 | "author": { 6 | "name": "Nick Gavrilov", 7 | "email": "artnikpro@gmail.com" 8 | }, 9 | "scripts": { 10 | "test": "npm run lint && npm run testonly", 11 | "testonly": "NODE_ENV=test mocha test/specs.js", 12 | "testonly-watch": "NODE_ENV=test mocha -w test/specs.js", 13 | "lint": "standard" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/ilearnio/module-alias/issues" 17 | }, 18 | "homepage": "https://github.com/ilearnio/module-alias", 19 | "keywords": [ 20 | "extend", 21 | "modules", 22 | "node", 23 | "path", 24 | "resolve" 25 | ], 26 | "license": "MIT", 27 | "main": "index.js", 28 | "files": [ 29 | "index.js", 30 | "register.js", 31 | "README.md", 32 | "LICENSE" 33 | ], 34 | "repository": { 35 | "type": "git", 36 | "url": "git+https://github.com/ilearnio/module-alias.git" 37 | }, 38 | "devDependencies": { 39 | "chai": "^3.5.0", 40 | "hello-world-classic": "ilearnio/hello-world-classic", 41 | "husky": "^3.0.2", 42 | "mocha": "^2.4.5", 43 | "semver": "^6.1.1", 44 | "standard": "^12.0.1" 45 | }, 46 | "husky": { 47 | "hooks": { 48 | "pre-push": "npm run test" 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /register.js: -------------------------------------------------------------------------------- 1 | require('.')() 2 | -------------------------------------------------------------------------------- /test/specs.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | var expect = require('chai').expect 3 | var exec = require('child_process').exec 4 | var path = require('path') 5 | var fs = require('fs') 6 | var semver = require('semver') 7 | 8 | describe('module-alias', function () { 9 | var moduleAlias 10 | 11 | before(function () { moduleAlias = require('..') }) 12 | 13 | afterEach(function () { 14 | moduleAlias.reset() 15 | }) 16 | 17 | it('should register path (addPath)', function () { 18 | var value 19 | try { 20 | value = require('foo') 21 | } catch (e) {} 22 | expect(value).to.equal(undefined) 23 | 24 | moduleAlias.addPath(path.join(__dirname, 'src')) 25 | try { 26 | value = require('foo') 27 | } catch (e) {} 28 | expect(value).to.equal('Hello from foo') 29 | }) 30 | 31 | it('should register an alias (addAlias)', function () { 32 | moduleAlias.addAlias('@baz', path.join(__dirname, 'src/bar/baz')) 33 | 34 | var value 35 | try { 36 | value = require('@baz') 37 | } catch (e) {} 38 | 39 | expect(value).to.equal('Hello from baz') 40 | }) 41 | 42 | it('should reset any changes after previous test cases (reset)', function () { 43 | var foo = null 44 | var baz = null 45 | try { 46 | foo = require('foo') 47 | baz = require('@baz') 48 | } catch (e) {} 49 | 50 | expect(foo).to.equal(null) 51 | expect(baz).to.equal(null) 52 | }) 53 | 54 | it('should match aliases', function () { 55 | expect(moduleAlias.isPathMatchesAlias('@foo/bar', '@foo')).to.equal(true) 56 | expect(moduleAlias.isPathMatchesAlias('one/three', 'one')).to.equal(true) 57 | expect(moduleAlias.isPathMatchesAlias('/one/three', '/one')).to.equal(true) 58 | }) 59 | 60 | it('should not match aliases', function () { 61 | expect(moduleAlias.isPathMatchesAlias('one-two/three', 'one')).to.equal(false) 62 | expect(moduleAlias.isPathMatchesAlias('/one-two/three', '/one')).to.equal(false) 63 | }) 64 | 65 | it('should register multiple aliases (addAliases)', function () { 66 | moduleAlias.addAliases({ 67 | '@src': path.join(__dirname, 'src'), 68 | '@foo': path.join(__dirname, 'src/foo/index.js'), 69 | '@bar': path.join(__dirname, 'src/bar'), 70 | 'something/foo': path.join(__dirname, 'src/foo') 71 | }) 72 | 73 | var src, foo, baz, something 74 | try { 75 | src = require('@src/foo') 76 | foo = require('@foo') 77 | baz = require('@bar/baz') 78 | something = require('something/foo') 79 | } catch (e) {} 80 | 81 | expect(src).to.equal('Hello from foo') 82 | expect(foo).to.equal('Hello from foo') 83 | expect(baz).to.equal('Hello from baz') 84 | expect(something).to.equal('Hello from foo') 85 | }) 86 | 87 | describe('importing settings from package.json', function () { 88 | function expectAliasesToBeImported () { 89 | var src, foo, baz, some, someModule 90 | try { 91 | src = require('@src/foo') 92 | foo = require('@foo') 93 | baz = require('@bar/baz') 94 | some = require('some/foo') 95 | someModule = require('some-module') 96 | } catch (e) {} 97 | 98 | expect(src).to.equal('Hello from foo') 99 | expect(foo).to.equal('Hello from foo') 100 | expect(baz).to.equal('Hello from baz') 101 | expect(some).to.equal('Hello from foo') 102 | expect(someModule).to.equal('Hello from some-module') 103 | } 104 | 105 | it('should import settings from user-defined base path', function () { 106 | moduleAlias({ 107 | base: path.join(__dirname, 'src') 108 | }) 109 | 110 | expectAliasesToBeImported() 111 | }) 112 | 113 | context('when base working directory is process.cwd()', function () { 114 | var baseWorkingDirectory 115 | beforeEach(function () { 116 | baseWorkingDirectory = process.cwd() 117 | }) 118 | 119 | afterEach(function () { 120 | process.chdir(baseWorkingDirectory) 121 | }) 122 | 123 | it('should import default settings from process.cwd()/package.json', function () { 124 | process.chdir(path.join(__dirname, 'src')) 125 | moduleAlias() 126 | 127 | expectAliasesToBeImported() 128 | }) 129 | }) 130 | 131 | context('when module-alias package is nested (looking up __dirname/../../)', function () { 132 | var moduleAliasDir = path.resolve( 133 | '.', 134 | 'test', 135 | 'src', 136 | 'node_modules', 137 | 'module-alias' 138 | ) 139 | var moduleAliasLocation = path.resolve(moduleAliasDir, 'index.js') 140 | var linkedModuleAlias 141 | 142 | before(function () { 143 | var indexJs = fs.readFileSync(path.resolve('.', 'index.js')) 144 | fs.writeFileSync(moduleAliasLocation, indexJs) 145 | linkedModuleAlias = require(moduleAliasDir) 146 | }) 147 | 148 | after(function () { 149 | linkedModuleAlias.reset() 150 | fs.unlinkSync(moduleAliasLocation) 151 | }) 152 | 153 | it('should import default settings from ../../package.json', function () { 154 | linkedModuleAlias() 155 | 156 | expectAliasesToBeImported() 157 | }) 158 | }) 159 | }) 160 | 161 | context('when used from the REPL', function () { 162 | before(function () { 163 | require.main._simulateRepl = true 164 | }) 165 | 166 | after(function () { 167 | delete require.main._simulateRepl 168 | }) 169 | 170 | it('should addPath', function () { 171 | moduleAlias.addPath('some-path') 172 | }) 173 | 174 | it('should reset', function () { 175 | moduleAlias.reset() 176 | }) 177 | }) 178 | 179 | it('should support forked modules', function () { 180 | expect(typeof require('hello-world-classic')).to.equal('function') 181 | }) 182 | 183 | it('should handle mocha test', function (done) { 184 | exec('mocha ' + path.join(__dirname, '/src/mocha/test.js'), function (_, result) { 185 | expect(result.toString('utf8')).to.match(/1 passing/) 186 | done() 187 | }) 188 | }) 189 | 190 | it('should work with require.resolve', function () { 191 | var aliasedDir = path.join(__dirname, 'src', 'foo') 192 | moduleAlias.addAliases({ 193 | 'some-alias': aliasedDir 194 | }) 195 | 196 | var bar = require.resolve('some-alias') 197 | 198 | expect(bar).to.equal(path.join(aliasedDir, 'index.js')) 199 | }) 200 | 201 | it('should match longest alias first', function () { 202 | moduleAlias.addAliases({ 203 | 'react-dom': path.join(__dirname, 'src/bar/baz'), 204 | 'react-dom/server': path.join(__dirname, 'src/foo') 205 | }) 206 | 207 | var bar, src 208 | try { 209 | bar = require('react-dom') 210 | src = require('react-dom/server') 211 | } catch (e) {} 212 | 213 | expect(bar).to.equal('Hello from baz') 214 | expect(src).to.equal('Hello from foo') 215 | }) 216 | 217 | if (semver.gte(process.version, '8.9.0')) { 218 | it('should support the options argument', function () { 219 | const options = { 220 | paths: [path.join(process.cwd(), 'test', 'src', 'bar')] 221 | } 222 | const baz = require.resolve('./baz', options) 223 | 224 | expect(baz).to.have.string(path.join('bar', 'baz', 'index.js')) 225 | }) 226 | } 227 | 228 | describe('Custom handler function', function () { 229 | it('should addAlias', function () { 230 | moduleAlias.addAlias('@src', function (fromPath, request, alias) { 231 | expect(fromPath).to.equal(__filename) 232 | expect(request).to.equal('@src/baz') 233 | expect(alias).to.equal('@src') 234 | return path.join(__dirname, 'src/bar') 235 | }) 236 | expect(require('@src/baz')).to.equal('Hello from baz') 237 | }) 238 | 239 | it('should addAliases', function () { 240 | moduleAlias.addAliases({ 241 | '@src': function (fromPath, request, alias) { 242 | expect(fromPath).to.equal(__filename) 243 | expect(request).to.equal('@src/baz') 244 | expect(alias).to.equal('@src') 245 | return path.join(__dirname, 'src/bar') 246 | }, 247 | '@bar': function (fromPath, request, alias) { 248 | expect(fromPath).to.equal(__filename) 249 | expect(request).to.equal('@bar/index.js') 250 | expect(alias).to.equal('@bar') 251 | return path.join(__dirname, 'src/foo') 252 | } 253 | }) 254 | expect(require('@src/baz')).to.equal('Hello from baz') 255 | expect(require('@bar/index.js')).to.equal('Hello from foo') 256 | }) 257 | 258 | it('should return npm package', function () { 259 | moduleAlias.addAlias('@src', function (fromPath, request, alias) { 260 | expect(fromPath).to.equal(__filename) 261 | expect(request).to.equal('@src') 262 | expect(alias).to.equal('@src') 263 | return 'hello-world-classic' 264 | }) 265 | expect(typeof require('@src')).to.equal('function') 266 | }) 267 | 268 | it('should throw when no path returned', function () { 269 | expect(function () { 270 | moduleAlias.addAlias('@src', function () {}) 271 | require('@src') 272 | }) 273 | .to.throw('[module-alias] Expecting custom handler function to return path.') 274 | }) 275 | }) 276 | }) 277 | -------------------------------------------------------------------------------- /test/src/bar/baz/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello from baz' 2 | -------------------------------------------------------------------------------- /test/src/foo/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello from foo' 2 | -------------------------------------------------------------------------------- /test/src/mocha/hello.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello' 2 | -------------------------------------------------------------------------------- /test/src/mocha/test.js: -------------------------------------------------------------------------------- 1 | /* eslint-env mocha */ 2 | var path = require('path') 3 | var assert = require('assert') 4 | var moduleAlias = require('../../..') 5 | 6 | moduleAlias.addAlias('@hello', path.join(__dirname, '/hello.js')) 7 | 8 | it('should pass', function () { 9 | assert(require('@hello') === 'Hello') 10 | }) 11 | -------------------------------------------------------------------------------- /test/src/node_modules/module-alias/.keep: -------------------------------------------------------------------------------- 1 | # keep me for folder 2 | -------------------------------------------------------------------------------- /test/src/node_modules_custom/some-module/index.js: -------------------------------------------------------------------------------- 1 | module.exports = 'Hello from some-module' 2 | -------------------------------------------------------------------------------- /test/src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "test-app", 3 | "_moduleDirectories": ["node_modules_custom"], 4 | "_moduleAliases": { 5 | "@src": "", 6 | "@foo": "foo/index.js", 7 | "@bar": "bar", 8 | "some/foo": "foo" 9 | } 10 | } 11 | --------------------------------------------------------------------------------