From 4416072124e55d85980d89f30e3915186276f729 Mon Sep 17 00:00:00 2001 From: Sam Kozin Date: Sun, 12 Jan 2020 01:38:32 +0300 Subject: [PATCH] [Fix] make 'import/order' work in a monorepo setup with scoped modules Fixes #1597 --- CHANGELOG.md | 9 +++++++++ README.md | 19 ++++++++++++++++++- src/core/importType.js | 15 ++++++++++----- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e89efd1bee..1f79c2e61a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` ([#PR]) + +### 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 ([#PR]) ## [2.20.0] - 2020-01-10 ### Added diff --git a/README.md b/README.md index 814d5fc28d..60b5bb1f11 100644 --- a/README.md +++ b/README.md @@ -339,7 +339,24 @@ 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. +Examples: + +- `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` diff --git a/src/core/importType.js b/src/core/importType.js index 8ec01c29e8..bac8f133b0 100644 --- a/src/core/importType.js +++ b/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' @@ -13,7 +12,7 @@ function baseModule(name) { } export function isAbsolute(name) { - return name.indexOf('/') === 0 + return !name || name[0] === '/' } // path is defined only when a resolver resolves to a non-standard path @@ -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/