diff --git a/README.md b/README.md index 3754252..adece9f 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,8 @@ module.exports = { ['babel-polyfill', 'babel-polyfill/dist/polyfill.min.js'], ['helper', './utils/helper'], ['material-ui/DatePicker', '../custom/DatePicker'], - ['material-ui', 'material-ui-ie10'] + ['material-ui', 'material-ui-ie10'], + ['lib', ['app/lib', 'common/lib']] ], extensions: ['.ts', '.js', '.jsx', '.json'] } @@ -62,6 +63,7 @@ Note: - The item of `map` array is also array type which contains 2 string + The first string represents the alias of module name or path + The second string represents the actual module name or path + + The second string may also be an array that is evaluated in order, with the first found used as resolved - The `map` item `['helper', './utils/helper']` means that the modules which match `helper` or `helper/*` will be resolved to `./utils/helper` or `./utils/helper/*` which are located relative to the `process current working directory` (almost the project root directory). If you just want to resolve `helper` to `./utils/helper`, use `['^helper$', './utils/helper']` instead. See [issue #3](https://github.com/johvin/eslint-import-resolver-alias/issues/3) - The order of 'material-ui/DatePicker' and 'material-ui' cannot be reversed, otherwise the alias rule 'material-ui/DatePicker' does not work - The default value of `extensions` property is `['.js', '.json', '.node']` if it is assigned to an empty array or not specified diff --git a/index.js b/index.js index a9bcdb1..4653ed0 100644 --- a/index.js +++ b/index.js @@ -58,23 +58,39 @@ exports.resolve = (modulePath, sourceFile, config) => { const re = new RegExp(`^${map[i][0]}($|/)`); const match = modulePath.match(re); if (match) { - resolvePath = modulePath.replace(match[0], `${map[i][1]}${match[1]}`); + resolvePath = getResolvePath(modulePath, match, map[i][1], extensions, sourceDir); break; } } } - // there is a relative path mapping in alias.map, - // the relative path is relative to the project root directory - if (resolvePath[0] === '.') { - resolvePath = path.resolve(process.cwd(), resolvePath); - return findModulePath(resolvePath, null, extensions); - } - - const paths = resolveLookupPaths(sourceDir); - return findModulePath(resolvePath, paths, extensions); + return smartFindModulePath(resolvePath, extensions, sourceDir); }; +// Get the resolved path +function getResolvePath(alias, match, actual, extensions, sourceDir) { + if (Array.isArray(actual)) { + let resolvePath, found; + + // Iterate through all possible paths + for (let i = 0; i < actual.length; i++) { + resolvePath = alias.replace(match[0], `${actual[i]}${match[1]}`); + found = smartFindModulePath(resolvePath, extensions, sourceDir); + + // If path resolves, use it, don't check any more + if (found.found) { + return resolvePath; + } + } + + // If no paths resolve, still return final path, we want to know if no paths resolve + return resolvePath; + } + else { + return alias.replace(match[0], `${actual}${match[1]}`); + } +} + // get extension object like Module._extensions function getExtensions(extArray) { if (Array.isArray(extArray) && extArray.length > 0) { @@ -87,6 +103,19 @@ function getExtensions(extArray) { return null; } +// Find module path, taking into account relative paths +function smartFindModulePath(resolvePath, extensions, sourceDir) { + // there is a relative path mapping in alias.map, + // the relative path is relative to the project root directory + if (resolvePath[0] === '.') { + resolvePath = path.resolve(process.cwd(), resolvePath); + return findModulePath(resolvePath, null, extensions); + } + + const paths = resolveLookupPaths(sourceDir); + return findModulePath(resolvePath, paths, extensions); +} + // find module path according to support file extensions. function findModulePath(request, paths, extArray) { if (extArray) { diff --git a/test/setup.js b/test/setup.js index 707340d..22f53af 100644 --- a/test/setup.js +++ b/test/setup.js @@ -14,7 +14,9 @@ const files = [ `${moduleDir}/module2/smile.js`, `${moduleDir}/module2/nav.jsx`, `${moduleDir}/polyfill2/polyfill.min.js`, - `${moduleDir}/mod/a.js` + `${moduleDir}/has_abc/abc.js`, + `${moduleDir}/has_def/def.js`, + `${moduleDir}/mod/a.js`, ]; files.forEach(file => { diff --git a/test/test.js b/test/test.js index 615f2b0..74f03c3 100644 --- a/test/test.js +++ b/test/test.js @@ -14,7 +14,8 @@ describe('resolver-alias/index.js', () => { ['red', './nothing'], // should not impact the paths which contain red and not starts with red ['module3', 'module2'], ['srcCore', './core'], - ['relativeSetup', './test/setup'] + ['relativeSetup', './test/setup'], + ['arrayPaths', ['has_abc', 'has_none', 'has_def']], ], extensions: ['.js', '.ts', '.jsx', '.json'] }; @@ -43,6 +44,16 @@ describe('resolver-alias/index.js', () => { 'srcCore', 'relativeSetup' ]; + const aliasModuleArrayPathArr = [ + 'module3/heihei', + 'module3/styles/red', + 'module3/nav', + 'polyfill', + 'core/red', + 'core', + 'arrayPaths/abc', + 'arrayPaths/def', + ]; const noneExistModulePathArr = [ 'abc/ggg', 'module2/bye', @@ -132,6 +143,18 @@ describe('resolver-alias/index.js', () => { }); }); + it('resolve alias modules that have an array of actual modules or paths', () => { + aliasModuleArrayPathArr.forEach((p) => { + const resolveModule = resolver.resolve(p, sourceFile, alias); + assert(resolveModule.found, `alias modulePath ${p} isn't resolved`); + }); + }); + + it('unable to resolve array modules that do not exist', () => { + const resolveModule = resolver.resolve('arrayPaths/ghi', sourceFile, alias); + assert(!resolveModule.found, `alias modulePath arrayPaths/ghi is resolved`); + }); + it('unable to resolve the modules that do not exist', () => { noneExistModulePathArr.forEach((p) => { const resolveModule = resolver.resolve(p, sourceFile, alias); @@ -154,5 +177,4 @@ describe('resolver-alias/index.js', () => { const a = require('mod/a'); assert(a.abc.found && a.abc.path != null, 'exist module is not resolved'); }); - });