Skip to content

Commit

Permalink
[Fix] make 'import/order' work in a monorepo setup with scoped modules
Browse files Browse the repository at this point in the history
Fixes #1597
  • Loading branch information
skozin committed Jan 12, 2020
1 parent 72ab8ef commit b59c495
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Expand Up @@ -5,6 +5,15 @@ This project adheres to [Semantic Versioning](http://semver.org/).
This change log adheres to standards from [Keep a CHANGELOG](http://keepachangelog.com).

## [Unreleased]
### Fixed
- [`import/external-module-folders` setting] now correctly works with directories containing
modules symlinked from `node_modules` ([#1605])

### Changed
- [`import/external-module-folders` setting] behavior is more strict now: it will only match
complete path segments. That is, `some/path` won't match `/my/awesome/path` but will still
match `/my/some/path` and `/my/some/path/index.js`. Also, if an item starts with a forward
slash, it will be treated as an absolute path prefix ([#1605])

## [2.20.0] - 2020-01-10
### Added
Expand Down Expand Up @@ -638,6 +647,7 @@ for info on changes for earlier releases.

[`memo-parser`]: ./memo-parser/README.md

[#1605]: https://github.com/benmosher/eslint-plugin-import/pull/1605
[#1589]: https://github.com/benmosher/eslint-plugin-import/issues/1589
[#1586]: https://github.com/benmosher/eslint-plugin-import/pull/1586
[#1572]: https://github.com/benmosher/eslint-plugin-import/pull/1572
Expand Down
21 changes: 20 additions & 1 deletion README.md
Expand Up @@ -339,7 +339,26 @@ Contribution of more such shared configs for other platforms are welcome!

#### `import/external-module-folders`

An array of folders. Resolved modules only from those folders will be considered as "external". By default - `["node_modules"]`. Makes sense if you have configured your path or webpack to handle your internal paths differently and want to considered modules from some folders, for example `bower_components` or `jspm_modules`, as "external".
An array of folders. Resolved modules only from those folders will be considered as "external". By default - `["node_modules"]`. Makes sense if you have configured your path or webpack to handle your internal paths differently and want to consider modules from some folders, for example `bower_components` or `jspm_modules`, as "external".

This option is also useful in a monorepo setup: list here all directories that contain monorepo's
packages and they will be treated as external ones no matter which resolver is used.

Each item in this array is either a folder's name, its subpath, or its absolute prefix path:

- `jspm_modules` will match any file or folder named `jspm_modules` or which has a direct or
non-direct parent named `jspm_modules`, e.g. `/home/me/project/jspm_modules` or
`/home/me/project/jspm_modules/some-pkg/index.js`.

- `packages/core` will match any path that contains these two segments, for example
`/home/me/project/packages/core/src/utils.js`.

- `/home/me/project/packages` will only match files and directories inside this directory,
and the directory itself.

Please note that incomplete names are not allowed here so `components` won't match
`bower_components` and `packages/ui` won't match `packages/ui-utils` (but will match
`packages/ui/utils`).

#### `import/parsers`

Expand Down
15 changes: 10 additions & 5 deletions src/core/importType.js
@@ -1,5 +1,4 @@
import coreModules from 'resolve/lib/core'
import { join } from 'path'

import resolve from 'eslint-module-utils/resolve'

Expand All @@ -13,7 +12,7 @@ function baseModule(name) {
}

export function isAbsolute(name) {
return name.indexOf('/') === 0
return name[0] === '/'
}

// path is defined only when a resolver resolves to a non-standard path
Expand All @@ -26,11 +25,17 @@ export function isBuiltIn(name, settings, path) {

function isExternalPath(path, name, settings) {
const folders = (settings && settings['import/external-module-folders']) || ['node_modules']
return !path || folders.some(folder => isSubpath(folder, path))
}

// extract the part before the first / (redux-saga/effects => redux-saga)
const packageName = name.match(/([^/]+)/)[0]
function isSubpath(subpath, path) {
const subpathRegExpSrc = escapeRegExp(subpath.replace(/[/]$/, ''))
const subpathRegExp = new RegExp(`${isAbsolute(subpath) ? '^' : '(?:^|/)'}${subpathRegExpSrc}(?:/|$)`)
return subpathRegExp.test(path)
}

return !path || folders.some(folder => -1 < path.indexOf(join(folder, packageName)))
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}

const externalModuleRegExp = /^\w/
Expand Down

0 comments on commit b59c495

Please sign in to comment.