From 259b7d013538d8a24473440579506174bab390fa Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sat, 28 Sep 2019 17:46:19 +0900 Subject: [PATCH 1/4] New: Changing the Default Value of --resolve-plugins-relative-to --- .../README.md | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 designs/2019-changing-default-of-resolve-plugins-relative-to/README.md diff --git a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md new file mode 100644 index 00000000..09f1486c --- /dev/null +++ b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md @@ -0,0 +1,123 @@ +- Start Date: 2019-09-28 +- RFC PR: (leave this empty, to be filled in later) +- Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) + +# Changing the Default Value of `--resolve-plugins-relative-to` + +## Summary + +This RFC changes the default value of `--resolve-plugins-relative-to` CLI option to work on more variety environments. + +## Motivation + +The current behavior is not useful for some environments. + +### When using a config file from outside of the project + +People can use the config file which is in a common directory by `--config` option. In that case, it's intuitive to load plugins from the directory that contains the config file. But currently, people have to use `--resolve-plugins-relative-to` option or install required plugins into the current working directory. + +``` +eslint . --config /home/me/.eslintrc.js --resolve-plugins-relative-to /home/me +``` + +``` +eslint projects/foo --config projects/shared/.eslintrc.js --resolve-plugins-relative-to projects/shared +``` + +### When developing multiple projects + +When the editor integrations run ESLint, it often uses the opened directory as the current working directory. However, it's problematic for monorepo development or something like. + +``` + +└ packages + ├ foo + ├ bar + ├ ... + └ zeta +``` + +Each package may have plugins, but ESLint cannot find such a plugin from the root directory. + +## Detailed Design + +This RFC changes the behavior when `--resolve-plugins-relative-to` CLI option was not presented. + +The logic to decide `--resolve-plugins-relative-to` value will be the following steps: + +1. If `--resolve-plugins-relative-to` CLI option is present, adopt it. +1. If `--config` CLI option is present, adopt the directory that contains the config file. +1. Otherwise, it's variable for each lint target file.
+ Adopt the directory which contains the closest config file from the lint target file.
+ This step is skipped if `--no-eslintrc` CLI option is present. +1. Adopt the current working directory if all of the above didn't match. + +For example: + +``` + +├ packages +│ ├ foo +│ │ ├ .eslintrc.yml # to use specific plugins +│ │ └ test.js +│ ├ bar +│ │ └ test.js +│ ├ ... +│ └ zeta +└ .eslintrc.yml +``` + +- With `eslint . --resolve-plugins-relative-to pckages/zeta`
+ It's `pckages/zeta` always. +- With `eslint . --config /home/me/my-config.js`
+ It's `/home/me` always. +- With `eslint .` + - When ESLint verifies `packages/foo/test.js`, it's `packages/foo` because the closest config file is `packages/foo/.eslintrc.yml`. + - When ESLint verifies `packages/bar/test.js`, it's `.` because the closest config file is `./.eslintrc.yml`. + +### About personal config file (`~/.eslintrc`) + +This RFC doesn't change the plugin base path for the personal config file (`~/.eslintrc`) because the functionality has been deprecated in [RFC 32](https://github.com/eslint/rfcs/pull/32). ESLint still loads plugins from the current working directory if there is no project config file, even if there is the personal config file. + +If people want to use the personal config file, use `--config` option (e.g., `eslint . --config ~/.eslintrc.json`). It should work intuitively. + +### Implementation + +The implementation appears in `CascadingConfigArrayFactory` class and `ConfigArrayFactory` class. + +**PoC:** [eslint/eslint#poc-improve-resolve-plugins-relative-to](https://github.com/eslint/eslint/compare/master...poc-improve-resolve-plugins-relative-to) + +- It adds the `pluginBasePath` option into the public methods of `ConfigArrayFactory`. Those methods load plugins from the location of the option. If the option is not present, load plugins from the location of constructor options. +- It updates the `CascadingConfigArrayFactory` behavior. The factory determines the plugin base path while finding config files. The factory traverses directories in the order from the leaf to the root. When the first config file was found, it determines the current traversing directory as the plugin base path.
+ There is the cache of the plugin base path for each directory and all cache keys of configs contain the plugin base path to avoid mix. + +## Documentation + +- It needs an entry in the migration guide because of a breaking change. +- It updates the "[Configuring Plugins](https://eslint.org/docs/user-guide/configuring#configuring-plugins)" section to describe where ESLint loads plugins from. + +## Drawbacks + +- The new logic is complex a bit. It increases maintenance cost. + +## Backwards Compatibility Analysis + +This RFC is a breaking change but has a small impact. + +If people use `--config` option with the path to outside of the current working directory and don't use `--resolve-plugins-relative-to` option, and the referred config depends on the plugins of the current working directory, then this RFC breaks the workflow. (I guess it's a rare case) + +Otherwise, this RFC moves the plugin base path to subdirectories, but Node.js can find packages from ancestor directories. + +Therefore, this RFC has a small impact. + +## Alternatives + +Nothing in particular. + +## Related Discussions + +- https://github.com/eslint/eslint/pull/11696 - New: add `--resolve-plugins-relative-to` flag +- https://github.com/eslint/eslint/issues/11914 - Personal config (`~/.eslintrc`) doesn't load global-installed configs/parsers/plugins +- https://github.com/eslint/eslint/issues/12019 - Allow to specify plugin resolution in config +- https://github.com/microsoft/vscode-eslint/issues/696 - ESLint fails to load plugins when using ESLint 6.x +- https://github.com/microsoft/vscode-eslint/issues/708 - Autodetect and propose working directories in mono repositories From dbb0c1ba8e30f32cd2f2a2f137d4a56621243872 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sat, 28 Sep 2019 17:52:58 +0900 Subject: [PATCH 2/4] add PR link --- .../README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md index 09f1486c..8396b2bf 100644 --- a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md +++ b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md @@ -1,5 +1,5 @@ - Start Date: 2019-09-28 -- RFC PR: (leave this empty, to be filled in later) +- RFC PR: https://github.com/eslint/rfcs/pull/39 - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) # Changing the Default Value of `--resolve-plugins-relative-to` From e9a2cd16b1a1347f62190e8fc0e491589d251148 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 25 Oct 2019 06:24:06 +0900 Subject: [PATCH 3/4] Update designs/2019-changing-default-of-resolve-plugins-relative-to/README.md Co-Authored-By: Kevin Partington --- .../README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md index 8396b2bf..da3a76cd 100644 --- a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md +++ b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md @@ -67,7 +67,7 @@ For example: └ .eslintrc.yml ``` -- With `eslint . --resolve-plugins-relative-to pckages/zeta`
+- With `eslint . --resolve-plugins-relative-to packages/zeta`
It's `pckages/zeta` always. - With `eslint . --config /home/me/my-config.js`
It's `/home/me` always. From f6420a0b368ff60cf7c5933f08cd501cc9df53c2 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Thu, 7 Nov 2019 19:26:59 +0900 Subject: [PATCH 4/4] separate this RFC # Conflicts: # designs/2019-changing-default-of-resolve-plugins-relative-to/README.md --- .../README.md | 89 +++++++------------ 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md index da3a76cd..da1d5695 100644 --- a/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md +++ b/designs/2019-changing-default-of-resolve-plugins-relative-to/README.md @@ -10,11 +10,7 @@ This RFC changes the default value of `--resolve-plugins-relative-to` CLI option ## Motivation -The current behavior is not useful for some environments. - -### When using a config file from outside of the project - -People can use the config file which is in a common directory by `--config` option. In that case, it's intuitive to load plugins from the directory that contains the config file. But currently, people have to use `--resolve-plugins-relative-to` option or install required plugins into the current working directory. +We can use the config file which is in a common directory by `--config` option. In that case, it's intuitive to load plugins from the directory that contains the config file. But currently, we have to use `--resolve-plugins-relative-to` option along with `--config` option, or have to install required plugins into the current working directory. For example: ``` eslint . --config /home/me/.eslintrc.js --resolve-plugins-relative-to /home/me @@ -24,56 +20,29 @@ eslint . --config /home/me/.eslintrc.js --resolve-plugins-relative-to /home/me eslint projects/foo --config projects/shared/.eslintrc.js --resolve-plugins-relative-to projects/shared ``` -### When developing multiple projects - -When the editor integrations run ESLint, it often uses the opened directory as the current working directory. However, it's problematic for monorepo development or something like. - -``` - -└ packages - ├ foo - ├ bar - ├ ... - └ zeta -``` - -Each package may have plugins, but ESLint cannot find such a plugin from the root directory. +This behavior is not convenient. ## Detailed Design -This RFC changes the behavior when `--resolve-plugins-relative-to` CLI option was not presented. +### `--resolve-plugins-relative-to` CLI option -The logic to decide `--resolve-plugins-relative-to` value will be the following steps: +This RFC changes the default value of `--resolve-plugins-relative-to` CLI option. 1. If `--resolve-plugins-relative-to` CLI option is present, adopt it. 1. If `--config` CLI option is present, adopt the directory that contains the config file. -1. Otherwise, it's variable for each lint target file.
- Adopt the directory which contains the closest config file from the lint target file.
- This step is skipped if `--no-eslintrc` CLI option is present. -1. Adopt the current working directory if all of the above didn't match. +1. Otherwise, adopt the current working directory. -For example: +This setting is used in the whole eslint process. Therefore, every rule ID is identified as unique, so the `rulesMeta` of formatters works fine. -``` - -├ packages -│ ├ foo -│ │ ├ .eslintrc.yml # to use specific plugins -│ │ └ test.js -│ ├ bar -│ │ └ test.js -│ ├ ... -│ └ zeta -└ .eslintrc.yml -``` +### `resolvePluginsRelativeTo` constructor option of CLIEngine + +This RFC changes the default value of `resolvePluginsRelativeTo` option. -- With `eslint . --resolve-plugins-relative-to packages/zeta`
- It's `pckages/zeta` always. -- With `eslint . --config /home/me/my-config.js`
- It's `/home/me` always. -- With `eslint .` - - When ESLint verifies `packages/foo/test.js`, it's `packages/foo` because the closest config file is `packages/foo/.eslintrc.yml`. - - When ESLint verifies `packages/bar/test.js`, it's `.` because the closest config file is `./.eslintrc.yml`. +1. If `resolvePluginsRelativeTo` constructor option is present, adopt it. +1. If `configFile` constructor option is present, adopt the directory that contains the config file. +1. Otherwise, adopt the current working directory. + +This setting is used in the whole `CLIEngine` instance. Therefore, every rule ID is identified as unique, so the `CLIEngine#getRules()` method works fine. ### About personal config file (`~/.eslintrc`) @@ -81,20 +50,29 @@ This RFC doesn't change the plugin base path for the personal config file (`~/.e If people want to use the personal config file, use `--config` option (e.g., `eslint . --config ~/.eslintrc.json`). It should work intuitively. -### Implementation +### Special handling of `~/` + +Bash replaces `~` by the user home directory, but this behavior is not compatible with other platforms. This is similar to that we cannot use glob patterns on every platform. -The implementation appears in `CascadingConfigArrayFactory` class and `ConfigArrayFactory` class. +Therefore, this RFC adds handling of `~`. In the following constructor options, if the path was exactly `~` or started with `~/` (and `~\` as well on Windows), the `CLIEngine` class replaces the `~` by `require("os").homedir()`. -**PoC:** [eslint/eslint#poc-improve-resolve-plugins-relative-to](https://github.com/eslint/eslint/compare/master...poc-improve-resolve-plugins-relative-to) +- `cacheLocation` +- `configFile` +- `cwd` +- `ignorePath` +- `resolvePluginsRelativeTo` -- It adds the `pluginBasePath` option into the public methods of `ConfigArrayFactory`. Those methods load plugins from the location of the option. If the option is not present, load plugins from the location of constructor options. -- It updates the `CascadingConfigArrayFactory` behavior. The factory determines the plugin base path while finding config files. The factory traverses directories in the order from the leaf to the root. When the first config file was found, it determines the current traversing directory as the plugin base path.
- There is the cache of the plugin base path for each directory and all cache keys of configs contain the plugin base path to avoid mix. +Notes: + +- It doesn't handle `~username/` notation because Node.js doesn't provide the way that gets the home directory of other users. +- It doesn't handle `~` in config files because this is a fallback of stuff that some shells do. ## Documentation - It needs an entry in the migration guide because of a breaking change. -- It updates the "[Configuring Plugins](https://eslint.org/docs/user-guide/configuring#configuring-plugins)" section to describe where ESLint loads plugins from. +- It updates the "[Command Line Interface](https://eslint.org/docs/user-guide/command-line-interface)" page to describe the `--config` option changes the default value of the `--resolve-plugins-relative-to` option. +- It updates the "[Command Line Interface](https://eslint.org/docs/user-guide/command-line-interface)" page to describe the `--config` option changes the default value of the `--resolve-plugins-relative-to` option. +- It updates the "[Node.js API](https://eslint.org/docs/developer-guide/nodejs-api)" page to describe the `configFile` constructor option changes the default value of the `resolvePluginsRelativeTo` constructor option on CLIEngine. ## Drawbacks @@ -106,10 +84,6 @@ This RFC is a breaking change but has a small impact. If people use `--config` option with the path to outside of the current working directory and don't use `--resolve-plugins-relative-to` option, and the referred config depends on the plugins of the current working directory, then this RFC breaks the workflow. (I guess it's a rare case) -Otherwise, this RFC moves the plugin base path to subdirectories, but Node.js can find packages from ancestor directories. - -Therefore, this RFC has a small impact. - ## Alternatives Nothing in particular. @@ -118,6 +92,3 @@ Nothing in particular. - https://github.com/eslint/eslint/pull/11696 - New: add `--resolve-plugins-relative-to` flag - https://github.com/eslint/eslint/issues/11914 - Personal config (`~/.eslintrc`) doesn't load global-installed configs/parsers/plugins -- https://github.com/eslint/eslint/issues/12019 - Allow to specify plugin resolution in config -- https://github.com/microsoft/vscode-eslint/issues/696 - ESLint fails to load plugins when using ESLint 6.x -- https://github.com/microsoft/vscode-eslint/issues/708 - Autodetect and propose working directories in mono repositories