├── designs ├── 2021-suppression-support │ ├── ESLint.png │ ├── violation.png │ └── design_diagram.png ├── 2019-deprecating-personal-config │ └── README.md ├── 2019-pass-cwd-from-cli-engine │ └── README.md ├── 2020-cwd-in-formatters │ └── README.md ├── 2019-drop-node8 │ └── README.md ├── 2019-update-default-ignore-patterns │ └── README.md ├── 2019-description-in-directive-comments │ └── README.md ├── 2019-processor-shared-settings │ └── README.md ├── 2020-cache-contents-option │ └── README.md ├── 2019-variable-definition-information-of-config-files │ └── README.md ├── 2019-rule-tester-improvements │ └── README.md ├── 2019-plugin-root-path-flag │ └── README.md ├── 2019-changing-base-path-in-config-files-that-cli-options-specify │ └── README.md ├── 2019-suggestions │ └── README.md ├── 2020-generic-ast-support │ └── README.md ├── 2021-fixable-disable-directives │ └── design.md ├── 2019-additional-lint-targets │ └── README.md ├── 2021-init-command-eslint-cli │ └── README.md ├── 2019-allow-all-directives-in-line-comments │ └── README.md ├── 2019-config-tester │ └── README.md ├── 2022-suggestion-parse-errors │ └── README.md ├── 2023-only-run-reporting-rules │ └── README.md ├── 2021-break-on-parsing-errors │ └── README.md ├── 2020-es-module-support │ └── README.md ├── 2019-expose-rules-to-formatters │ └── readme.MD ├── 2019-esm-compatibilty │ └── README.md ├── 2019-core-options │ └── README.md ├── 2019-recoverable-error-handling │ └── README.md ├── 2020-rule-tester-only │ └── README.md ├── 2021-package-exports │ └── README.md ├── 2022-supress-ignored-file-warnings │ └── README.md ├── 2020-timing-list-size │ └── README.md └── 2018-simplified-package-loading │ └── README.md ├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── tweet-rfc-update.yml ├── templates └── design.md └── README.md /designs/2021-suppression-support/ESLint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-rfcs/main/designs/2021-suppression-support/ESLint.png -------------------------------------------------------------------------------- /designs/2021-suppression-support/violation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-rfcs/main/designs/2021-suppression-support/violation.png -------------------------------------------------------------------------------- /designs/2021-suppression-support/design_diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antfu/eslint-rfcs/main/designs/2021-suppression-support/design_diagram.png -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | 4 | 5 | ## Related Issues 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /designs/2019-deprecating-personal-config/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-16 2 | - RFC PR: https://github.com/eslint/rfcs/pull/32 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Deprecating Personal Config 6 | 7 | ## Summary 8 | 9 | This RFC deprecates the personal config that is `.eslintrc` files on home directory. 10 | 11 | ## Motivation 12 | 13 | Since 6.0.0, ESLint doesn't load plugins/configs/parsers from the global installation even if it's not a part of a project such as the personal config. This is inconvenient for the personal config. But, in #28 discussion, we confirm that we don't want to use the global installation. 14 | 15 | We don't recommend to use global-installed ESLint. But the personal config has encouraged to use it. 16 | 17 | ## Detailed Design 18 | 19 | Three steps: 20 | 21 | 1. **Soft deprecation**: Update our documentation to announce to deprecate the personal config on the next minor release. 22 | 2. **Hard deprecation**: Add the deprecation warning of the personal config on ESLint 7.0.0. 23 | - ESLint shows a warning when it loaded the personal config. 24 | - ESLint shows a warning when it ignored the personal config (Currently, it ignores `.eslintrc` files on home directory if a project directory is in home directory and the project has `.eslintrc` files.) 25 | 3. **Removal**: Remove the personal config functionality on ESLint 8.0.0. 26 | - ESLint no longer loads the personal config even if the project config was not found. 27 | - ESLint no longer ignores the config files on home directory even if the project config was found. 28 | 29 | ## Documentation 30 | 31 | - Remove the personal config from [Configuring ESLint](https://eslint.org/docs/user-guide/configuring) page. 32 | - Announce on the release notes. 33 | 34 | ## Drawbacks 35 | 36 | It will make people inconvenient to lint standalone files. 37 | 38 | ## Backwards Compatibility Analysis 39 | 40 | Yes, this is a breaking change. 41 | 42 | To lint standalone files, people have to have a dummy project directory such as `sandbox`. 43 | 44 | ## Alternatives 45 | 46 | - https://github.com/eslint/rfcs/pull/28 47 | 48 | ## Related Discussions 49 | 50 | - https://github.com/eslint/rfcs/pull/7 51 | - https://github.com/eslint/rfcs/pull/28 52 | - https://github.com/eslint/eslint/issues/11914 53 | -------------------------------------------------------------------------------- /designs/2019-pass-cwd-from-cli-engine/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-25 2 | - RFC PR: https://github.com/eslint/rfcs/pull/35 3 | - Authors: Eric Wang 4 | 5 | # Pass cwd from cli engine 6 | 7 | ## Summary 8 | Make the CLIEngine `cwd` option available to rules to avoid the misalignment between it and process.cwd() 9 | 10 | see: https://github.com/eslint/eslint/issues/11218 11 | 12 | ## Motivation 13 | To avoid the misalignment between it and `process.cwd()`. 14 | There is a situation where a rule need to get the relative path of the current file to the root folder of the project. 15 | But it's hard to guarantee that all developers will open the root folder in their IDE (VSCode with eslint plugin for example), especially when the project grows. 16 | 17 | Use case: 18 | Say, the project is supposed to be open in `web` folder. 19 | But as the project grows, people tends to open some subfolder under the `web` to minimize sidebar. 20 | `eslint` plugin in VSCode will then run the `eslint` from the subfolder which cause the `process.cwd` not to return the expected value (e.g. the `web` folder) 21 | 22 | Expected: 23 | It is expected that the rule has access to the `cwd` in the option of the CLI engine. 24 | 25 | ## Detailed Design 26 | ### Change in Linter 27 | Modify the `Linter` constructor to accept an object with a optional string parameter `cwd` with a default value. 28 | ``` 29 | const linter = new Linter({ 30 | cwd: '/path/to/cwd' 31 | }); 32 | ``` 33 | or `const linter = new Linter({})`. 34 | The default value will be `process.cwd()` if the `process` exists, or `undefined` if not. 35 | 36 | 37 | ### Change in Context 38 | This RFC adds `getCwd()` method to rule context. 39 | The `getCwd()` method returns the value of the `cwd` option that was given in `Linter` constructor. 40 | 41 | https://github.com/eslint/eslint/pull/12021 42 | 43 | ## Documentation 44 | Adding the `cwd` into the `context` Api. 45 | Adding the `cwd` into the `Linter` constructor Api. 46 | 47 | ## Drawbacks 48 | Can't think of any. 49 | 50 | ## Backwards Compatibility Analysis 51 | Those rules using `process.cwd` will have exact same behavior, so there is no compatibility issue. 52 | 53 | ## Alternatives 54 | N/A 55 | 56 | ## Open Questions 57 | N/A 58 | 59 | ## Help Needed 60 | N/A 61 | 62 | ## Frequently Asked Questions 63 | N/A 64 | 65 | ## Related Discussions 66 | N/A 67 | -------------------------------------------------------------------------------- /.github/workflows/tweet-rfc-update.yml: -------------------------------------------------------------------------------- 1 | name: Tweet RFC Update 2 | on: 3 | # Can't use pull_request because it won't have access to secrets 4 | pull_request_target: 5 | types: [labeled, closed] 6 | jobs: 7 | tweetStateChange: 8 | runs-on: ubuntu-latest 9 | if: github.event.action == 'labeled' && contains(github.event.label.name, 'Commenting') 10 | steps: 11 | - uses: actions/setup-node@v3 12 | with: 13 | node-version: '18.x' 14 | - run: npx @humanwhocodes/tweet "The RFC '$TITLE' is now in the ${{ github.event.label.name }} phase.\n\n${{ github.event.pull_request.html_url }}" 15 | env: 16 | TITLE: ${{ github.event.pull_request.title }} 17 | TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 18 | TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} 19 | TWITTER_ACCESS_TOKEN_KEY: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }} 20 | TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} 21 | - run: npx @humanwhocodes/toot "The RFC '$TITLE' is now in the ${{ github.event.label.name }} phase.\n\n${{ github.event.pull_request.html_url }}" 22 | env: 23 | TITLE: ${{ github.event.pull_request.title }} 24 | MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} 25 | MASTODON_HOST: ${{ secrets.MASTODON_HOST }} 26 | 27 | tweetMerge: 28 | runs-on: ubuntu-latest 29 | if: github.event.action == 'closed' && github.event.pull_request.merged && contains(github.event.pull_request.labels.*.name, 'Final Commenting') 30 | steps: 31 | - uses: actions/setup-node@v3 32 | with: 33 | node-version: '18.x' 34 | - run: npx @humanwhocodes/tweet "The RFC '$TITLE' has been approved and merged!\n\n${{ github.event.pull_request.html_url }}" 35 | env: 36 | TITLE: ${{ github.event.pull_request.title }} 37 | TWITTER_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 38 | TWITTER_CONSUMER_SECRET: ${{ secrets.TWITTER_CONSUMER_SECRET }} 39 | TWITTER_ACCESS_TOKEN_KEY: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }} 40 | TWITTER_ACCESS_TOKEN_SECRET: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }} 41 | - run: npx @humanwhocodes/toot "The RFC '$TITLE' has been approved and merged!\n\n${{ github.event.pull_request.html_url }}" 42 | env: 43 | TITLE: ${{ github.event.pull_request.title }} 44 | MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} 45 | MASTODON_HOST: ${{ secrets.MASTODON_HOST }} 46 | -------------------------------------------------------------------------------- /designs/2020-cwd-in-formatters/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2020-06-05 3 | - RFC PR: https://github.com/eslint/rfcs/pull/57 4 | - Authors: Toru Nagashima (https://github.com/mysticatea) 5 | 6 | # Accessing `cwd` from formatters 7 | 8 | ## Summary 9 | 10 | This RFC lets formatters can access `cwd` in order to make relative paths or do something like. 11 | 12 | ## Motivation 13 | 14 | Our Node.js API has the `cwd` option, and ESLint uses it while linting. But formatters cannot access the `cwd` option. It prevents formatters from making relative paths for readability. 15 | 16 | ## Detailed Design 17 | 18 | Pass `cwd` to the `cwd` property of the second argument, then formatters can use it. 19 | 20 | ```js 21 | module.exports = (results, context) => { 22 | console.log(context.cwd) // → the absolute path to the current working directory. 23 | console.log(context.rulesMeta) // → the metadata of the used rules (it exists currently). 24 | } 25 | ``` 26 | 27 | ### Implementation 28 | 29 | The adapter object that the `ESLint.prototype.loadFormatter` method makes gives the `cwd`. 30 | 31 | > ```diff 32 | > @@ -575,7 +575,7 @@ class ESLint { 33 | > throw new Error("'name' must be a string"); 34 | > } 35 | > 36 | > - const { cliEngine } = privateMembersMap.get(this); 37 | > + const { cliEngine, options } = privateMembersMap.get(this); 38 | > const formatter = cliEngine.getFormatter(name); 39 | > 40 | > if (typeof formatter !== "function") { 41 | > @@ -595,6 +595,9 @@ class ESLint { 42 | > results.sort(compareResultsByFilePath); 43 | > 44 | > return formatter(results, { 45 | > + get cwd() { 46 | > + return options.cwd; 47 | > + }, 48 | > get rulesMeta() { 49 | > if (!rulesMeta) { 50 | > rulesMeta = createRulesMeta(cliEngine.getRules()); 51 | > ``` 52 | > 53 | > https://github.com/eslint/eslint/commit/43a7e207ca8c0b816d4fba2b4b290f761c33adb4 54 | 55 | ## Documentation 56 | 57 | We should update the "[Working with Custom Formatters](https://eslint.org/docs/developer-guide/working-with-custom-formatters)" page to mention the `cwd`. 58 | 59 | ## Drawbacks 60 | 61 | Nothing in particular. 62 | 63 | ## Backwards Compatibility Analysis 64 | 65 | This addition is backward compatible. 66 | 67 | If custom formatters want to use the `cwd` property and continue to support old versions of ESLint, they must check if the `cwd` property exists or not. 68 | 69 | ## Alternatives 70 | 71 | ## Related Discussions 72 | 73 | - https://github.com/eslint/eslint/issues/13376 - Output relative paths rather than absolute paths 74 | -------------------------------------------------------------------------------- /designs/2019-drop-node8/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-10-13 2 | - RFC PR: https://github.com/eslint/rfcs/pull/44 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Drop supports for Node.js 8.x and 11.x 6 | 7 | ## Summary 8 | 9 | This RFC drops supports for Node.js 8.x and 11.x because of end-of-life. (See [nodejs/release](https://github.com/nodejs/release#readme) to check the release schedule of Node.js) 10 | 11 | ## Motivation 12 | 13 | We get the capability to use new features and syntaxes by dropping the support for end-of-life versions of Node.js. Especially, [RFC40](https://github.com/eslint/rfcs/pull/40) wants to use async iteration, but Node.js 8.x doesn't support that syntax. 14 | 15 | ## Detailed Design 16 | 17 | This proposal updates the `engines` field of our `package.json` (and updates our CI scripts). 18 | 19 | ```diff 20 | "engines": { 21 | - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" 22 | + "node": "^10.12.0 || >=12.0.0" 23 | } 24 | ``` 25 | 26 | ### Why is it `^10.12.0`? 27 | 28 | > **Resolution:** We will choose Node version support based on the lowest point release supporting our desired features. 29 | > 30 | > [2019-March-14 ESLint TSC Meeting Notes: Decide how to manage support for minor versions of Node](https://github.com/eslint/tsc-meetings/blob/137fbe2be55499cd75f28a008900803078d22dfd/notes/2019/2019-03-14.md#decide-how-to-manage-support-for-minor-versions-of-node) 31 | 32 | Therefore, we should check the added features in Node.js `10.x`. 33 | 34 | I found two features we want to use. 35 | 36 | - [10.10.0](https://nodejs.org/en/blog/release/v10.10.0/) ... the `withFileTypes` option of `fs.readdir`/`fs.readdirSync`. We can reduce the calls of `fs.statSync` in our `FileEnumerator` class with this option. It may improve performance (especially on Windows). 37 | - [10.12.0](https://nodejs.org/en/blog/release/v10.12.0/) ... `module.createRequireFromPath(filename)` function. We can remove [our polyfill](https://github.com/eslint/eslint/blob/24ca088fdc901feef8f10b050414fbde64b55c7d/lib/shared/relative-module-resolver.js#L20-L29) with this version. 38 | 39 | ## Documentation 40 | 41 | We need write an entry in the migration guide because this is a breaking change. 42 | 43 | ## Drawbacks 44 | 45 | Users lose the capability to run ESLint on old Node.js. They may have to update their CI scripts. 46 | 47 | ## Backwards Compatibility Analysis 48 | 49 | This is a breaking change clearly. 50 | 51 | Users lose the capability to run ESLint on old Node.js. They may have to update their CI scripts. 52 | 53 | ## Alternatives 54 | 55 | N/A. 56 | 57 | ## Related Discussions 58 | 59 | - https://github.com/eslint/eslint/issues/10981 - Allow use node version >8 60 | - https://github.com/eslint/eslint/issues/11022 - Decide how to manage support for minor versions of Node 61 | -------------------------------------------------------------------------------- /designs/2019-update-default-ignore-patterns/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-11-28 2 | - RFC PR: https://github.com/eslint/rfcs/pull/51 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Update Default Ignore Patterns 6 | 7 | ## Summary 8 | 9 | This proposal changes the default ignore patterns to include `node_modules` in subdirectories and to exclude `.eslintrc.js`. 10 | 11 | ## Motivation 12 | 13 | - In monorepo style development, there are `node_modules`s in subdirectories. But the current default ignore patterns don't include it, so we have to configure ESLint with `node_modules` to ignore it. 14 | - Because ESLint ignores dotfiles, it doesn't lint `.eslintrc.js` by default. We have to configure ESLint with `!.eslintrc.js` to lint it. 15 | 16 | ## Detailed Design 17 | 18 | This proposal changes the default ignore patterns: 19 | 20 | - (as-is) `.*` 21 | - (new) `!.eslintrc.js` 22 | - (change) `/node_modules/*` → `/**/node_modules/*` 23 | - (remove) ~~`/bower_components/*`~~ 24 | 25 | Therefore, ESLint ignores `node_modules` in subdirectories, and no longer ignores `.eslintrc.js` and `bower_components`. 26 | 27 | ### How about the config files of other tools? 28 | 29 | For example, Babel has `.babelrc.js` and VuePress has `.vuepress/config.js`. ESLint ignores such files as dotfiles by default. 30 | 31 | This proposal doesn't change this behavior because we don't want to have allowlist/denylist for all tools in the world. Instead, we can have unignoring patterns in the `ignorePatterns` property of shareable configs for your tools. 32 | 33 | ## Documentation 34 | 35 | - It needs an entry in the migration guide for 7.0.0 (or another major release) because of breaking changes. 36 | - It needs to update the "[.eslintignore](https://eslint.org/docs/user-guide/configuring#eslintignore)" section to explain the new default ignore patterns. 37 | 38 | ## Drawbacks 39 | 40 | This proposal doesn't increase maintenance cost because it just updates a pattern list. 41 | 42 | If somebody wants to lint `node_modules` in subdirectories, they have to configure ESLint to unignore those. But I guess that it's rarer than wanting to ignore `node_modules` in subdirectories. 43 | 44 | ## Backwards Compatibility Analysis 45 | 46 | This is a breaking change. 47 | 48 | - ESLint may report more warnings on `.eslintrc.js`. 49 | - ESLint may report more warnings in `bower_components`. 50 | - ESLint may stop with fatal errors (all files are ignored) in the `node_modules` of subdirectories. 51 | 52 | ## Alternatives 53 | 54 | We can use the `ignorePatterns` of shareable configs to configure and reuse this kind of matter. 55 | 56 | ## Related Discussions 57 | 58 | - https://github.com/eslint/eslint/issues/1163 - ignore node_modules folder by default 59 | - https://github.com/eslint/eslint/issues/10089 - .babelrc.js should not be ignored by default 60 | - https://github.com/eslint/eslint/issues/10341 - do not ignore files started with `.` by default 61 | - https://github.com/eslint/tsc-meetings/blob/master/notes/2019/2019-12-05.md#remove-bower_components-from-default-ignores 62 | -------------------------------------------------------------------------------- /designs/2019-description-in-directive-comments/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-20 2 | - RFC PR: https://github.com/eslint/rfcs/pull/33 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Description in directive comments 6 | 7 | ## Summary 8 | 9 | This RFC adds the description support into directive comments such as `/*eslint-disable*/`. For example, `/* eslint-disable no-new -- this class has a side-effect in the constructor and it's a library's. */`. 10 | 11 | ## Motivation 12 | 13 | Directive comments make exceptions for static analysis. The explanation of why you made the exception here helps to maintain the code. However, ESLint doesn't have a comfortable way to write such an explanation. 14 | 15 | ## Detailed Design 16 | 17 | ESLint ignores the part preceded by `\s-{2,}\s` in directive comments. 18 | 19 | ```js 20 | /* eslint eqeqeq: off -- this part is ignored. */ 21 | /* eslint-disable -- this part is ignored. */ 22 | /* eslint-enable -- this part is ignored. */ 23 | // eslint-disable-line -- this part is ignored. 24 | // eslint-disable-next-line -- this part is ignored. 25 | /* global foo -- this part is ignored. */ 26 | /* globals foo, bar -- this part is ignored. */ 27 | /* exported foo, bar -- this part is ignored. */ 28 | 29 | "Longer is OK." 30 | // eslint-disable-line -------- this part is ignored. 31 | 32 | "Multiline." 33 | /* eslint-disable 34 | a-rule, 35 | another-rule 36 | -------- 37 | this part is ignored. 38 | this part is ignored. */ 39 | 40 | "Not affect to '--' which is not surrounded by spaces." 41 | /* eslint spaced-comment: [error, { exceptions: ["--"] }] */ 42 | ``` 43 | 44 | ### Implementation 45 | 46 | ```js 47 | // Use only the part before the first `--`. 48 | const [value] = comment.value.split(/\s-{2,}\s/u) 49 | ``` 50 | 51 | ## Documentation 52 | 53 | - The "[Disabling Rules with Inline Comments](https://eslint.org/docs/user-guide/configuring#disabling-rules-with-inline-comments)" section should describe `--`. 54 | 55 | ## Drawbacks 56 | 57 | If a complex directive comment has `\s-{2,}\s` in the body, this feature breaks it. 58 | 59 | ## Backwards Compatibility Analysis 60 | 61 | This is a breaking change technically, but I believe the effect is very limited. 62 | 63 | ## Alternatives 64 | 65 | - Another comment around directive comments. 66 | ```js 67 | /* explanation */ 68 | /* eslint-disable */ 69 | f() 70 | ``` 71 | In some cases, it's challenging to write another comment near directive comments. For example, there is `//eslint-disable-line` comment on a long line. 72 | 73 | ### Prior Arts 74 | 75 | - [istanbul](https://github.com/istanbuljs/istanbuljs) 76 | > ``` 77 | > /* istanbul ignore [non-word] [optional-docs] */ 78 | > ``` 79 | > 80 | > https://github.com/gotwarlost/istanbul/blob/master/ignoring-code-for-coverage.md 81 | - [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) 82 | > ``` 83 | > // phpcs:disable PEAR,Squiz.Arrays -- this isn't our code 84 | > ``` 85 | > 86 | > https://github.com/squizlabs/PHP_CodeSniffer/wiki/Advanced-Usage#ignoring-parts-of-a-file 87 | - [TSLint](https://github.com/palantir/tslint) doesn't have this feature, but there is a discussion: https://github.com/palantir/tslint/issues/1484. 88 | 89 | ## Related Discussions 90 | 91 | - https://github.com/eslint/eslint/issues/11806 92 | -------------------------------------------------------------------------------- /templates/design.md: -------------------------------------------------------------------------------- 1 | - Repo: (the repo it will be implemented in, e.g. eslint/espree) 2 | - Start Date: (fill me in with today's date, YYYY-MM-DD) 3 | - RFC PR: (leave this empty, to be filled in later) 4 | - Authors: (the names of everyone contributing to this RFC) 5 | 6 | # (RFC title goes here) 7 | 8 | ## Summary 9 | 10 | 11 | 12 | ## Motivation 13 | 14 | 16 | 17 | ## Detailed Design 18 | 19 | 27 | 28 | ## Documentation 29 | 30 | 34 | 35 | ## Drawbacks 36 | 37 | 47 | 48 | ## Backwards Compatibility Analysis 49 | 50 | 55 | 56 | ## Alternatives 57 | 58 | 64 | 65 | ## Open Questions 66 | 67 | 77 | 78 | ## Help Needed 79 | 80 | 86 | 87 | ## Frequently Asked Questions 88 | 89 | 96 | 97 | ## Related Discussions 98 | 99 | 105 | -------------------------------------------------------------------------------- /designs/2019-processor-shared-settings/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-01 2 | - RFC PR: https://github.com/eslint/rfcs/pull/29 3 | - Authors: @Conduitry 4 | 5 | # Access to options in processors 6 | 7 | ## Summary 8 | 9 | This would add the ability to send options to processors, via a new `processorOptions` object in the `.eslintrc` configuration. 10 | 11 | ## Motivation 12 | 13 | There is currently no good way to provide any sort of configuration to processor plugins. There are instances where this is useful (`eslint-plugin-html` and `eslint-plugin-svelte3` are two examples I am familiar with). The concept of "shared settings" exists, but these are only provided to rule plugins. 14 | 15 | ## Detailed Design 16 | 17 | A new top-level key called `processorOptions` would be added. (Typically, this would be configured alongside `processor` inside an override). This options object would then be sent as a third argument to `preprocess` and `postprocess`. 18 | 19 | For example, this is how configuring linting to use [`eslint-plugin-svelte3`](https://github.com/sveltejs/eslint-plugin-svelte3) with options might look: 20 | 21 | ```js 22 | module.exports = { 23 | // ... 24 | plugins: ['svelte3'], 25 | overrides: [ 26 | { 27 | files: '*.svelte', 28 | processor: 'svelte3/svelte3', 29 | processorOptions: { 30 | ignoreStyles: () => true, 31 | // ... 32 | }, 33 | }, 34 | ], 35 | }; 36 | ``` 37 | 38 | ## Documentation 39 | 40 | We'd document how to send options to processors that support them in . 41 | 42 | We'd document how to receive them as a third argument in . 43 | 44 | ## Drawbacks 45 | 46 | Slight increased maintenance burden is all I can think of. The entire configuration object is readily available in `Linter.prototype._verifyWithProcessor` where we would be calling `preprocess` and `postprocess`. 47 | 48 | ## Backwards Compatibility Analysis 49 | 50 | Existing users and plugins will be unaffacted, as this will simply be a third argument passed to `preprocess` and `postprocess`. 51 | 52 | ## Alternatives 53 | 54 | There are currently no processor-specific options. The only real way to access the linting configuration from within a processor is to monkey-patch `Linter.prototype.verify` so that we can intercept the config values. This is [what's happening in `eslint-plugin-svelte3` (near the bottom of the file)](https://github.com/sveltejs/eslint-plugin-svelte3/blob/master/index.js). `eslint-plugin-html` is also doing something similar. It involves searching through `require.cache` for the appropriate file, and is brittle and ugly. 55 | 56 | ## Open Questions 57 | 58 | ~~Do we want to provide the entire configuration object to the pre- and postprocessors, or just the shared settings?~~ Now that we're going to have configuration that's explicitly intended for this processor, it probably makes sense to only send that object. 59 | 60 | ## Help Needed 61 | 62 | I can certainly give implementing this a shot, but I've only dug into the ESLint codebase to the extent necessary to work around that lack of this feature. I'd appreciate some help, particularly with writing tests. 63 | 64 | If there are other places in the code besides `Linter.prototype._verifyWithProcessor` where processors are run, I'd also like to hear about them. 65 | 66 | ## Frequently Asked Questions 67 | 68 | ## Related Discussions 69 | 70 | https://gitter.im/eslint/eslint?at=5d0e804ad4535e477a829360 71 | -------------------------------------------------------------------------------- /designs/2020-cache-contents-option/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2020-07-15 2 | - RFC PR: https://github.com/eslint/rfcs/pull/63 3 | - Authors: @c-home 4 | 5 | # Add option to allow use of file contents for cache 6 | 7 | ## Summary 8 | 9 | This RFC proposes improving cache for CI by providing an option to use a hash (instead of `mtime` and `fsize`) comparison to determine whether a file has changed. 10 | 11 | ## Motivation 12 | 13 | Motivation for this change is the same as [#11490](https://github.com/eslint/eslint/issues/11490), where details of files like `mtime` are not preserved in the CI environment. With a hash comparison, the cache can be used in CI and would significantly reduce the time ESLint takes to run. 14 | 15 | ESLint uses [`file-entry-create`](https://github.com/royriojas/file-entry-cache) as its cache provider. [fileEntryCache#create](https://github.com/royriojas/file-entry-cache#createcachename-directory-usechecksum) gives the option to use a md5 hash through the `useChecksum` argument, but ESLint currently does not utilize it. 16 | 17 | ## Detailed Design 18 | 19 | This RFC adds a `--cache-strategy` CLI [option](https://github.com/eslint/eslint/blob/e71e2980cd2e319afc70d8c859c7ffd59cf4157b/lib/options.js#L198). Users can specify the option to be: 20 | - `contents`, for the use of an md5 hash 21 | - `metadata`, for the use of `mtime` and `fsize` 22 | 23 | Modified time and size (`metadata`), does not need to be specified as it will remain the default. 24 | 25 | The implementation will be similar to [#11487](https://github.com/eslint/eslint/pull/11487), with differences in the naming of the options. The options were kept general so if the underlying implementation of the comparison method were to change, the usage and documentation can remain the same. 26 | 27 | The majority of changes will be made to [`LintResultCache`](https://github.com/eslint/eslint/blob/e71e2980cd2e319afc70d8c859c7ffd59cf4157b/lib/cli-engine/lint-result-cache.js#L47). The `cache-strategy` will be added to the constructor of `LintResultCache`. If `cache-strategy` is set as `contents`, an md5 hash will be used in [fileEntryCache#create](https://github.com/royriojas/file-entry-cache#createcachename-directory-usechecksum). 28 | 29 | ## Documentation 30 | 31 | Documentation for ESLint CLI will be updated with a description of the option. 32 | 33 | ## Drawbacks 34 | 35 | - Specifying the details of the cache behaviour through a public option can make it more difficult to change the design and implementation [without breaking its usage](https://github.com/eslint/eslint/issues/11490#issuecomment-471400143). 36 | - Comparing files based on their contents is slower than comparing files by their file metadata. However, a file contents comparison is not the default. 37 | - Like any new feature, this flag will slightly increase the complexity and maintenance costs of ESLint. 38 | 39 | ## Backwards Compatibility Analysis 40 | 41 | This change is backwards-compatible. It adds a new CLI option while keeping the behavior the same if the option is not specified. 42 | 43 | ## Alternatives 44 | 45 | Mentioned as an alternative in [#11487](https://github.com/eslint/eslint/pull/11487), and if `file-entry-cache` [#14](https://github.com/royriojas/file-entry-cache/pull/14) were to be merged, an environment variable could be passed through `eslint` to `file-entry-cache`. 46 | 47 | ## Open Questions 48 | 49 | None 50 | 51 | ## Frequently Asked Questions 52 | 53 | None yet 54 | 55 | ## Related Discussions 56 | 57 | - https://github.com/eslint/eslint/issues/11319 58 | - https://github.com/eslint/eslint/issues/11490 59 | - https://github.com/eslint/eslint/pull/11487 60 | - https://github.com/royriojas/file-entry-cache/pull/14 61 | -------------------------------------------------------------------------------- /designs/2019-variable-definition-information-of-config-files/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-03-04 2 | - RFC PR: https://github.com/eslint/rfcs/pull/17 3 | - Authors: Toru Nagashima ([@mysticatea]) 4 | 5 | # Variable Definition Information of Config Files 6 | 7 | ## Summary 8 | 9 | This proposal adds variable definition information of config files to `Variable` objects. 10 | 11 | ## Motivation 12 | 13 | To make rules being able to report matters about variable definitions related to config files. 14 | 15 | Especially, this proposal minds [no-redeclare] rule to report redeclaration by a mix of regular variable declarations, `/*globals*/` comments, and config files. ([eslint/eslint#11370]) 16 | 17 | ## Detailed Design 18 | 19 | Currently, `Variable` objects have the following properties to express `/*globals*/` definitions. 20 | 21 | - `variable.eslintExplicitGlobal` (`boolean`) ... `true` if this variable was defined by `/*globals*/` comment. 22 | - `variable.eslintExplicitGlobalComment` (`Comment` object) ... The `/*globals*/` comment that defines this variable. If two or more comments defined this variable, it adopts the last one. 23 | - `variable.writeable` (`boolean`) ... `true` if the final setting is `"writable"`. 24 | 25 | This proposal adds the following properties. 26 | 27 | - `variable.eslintExplicitGlobalComments` (an array of `Comment` objects) ... All `/*globals*/` comments that define this variable. 28 | - `variable.eslintImplicitGlobalSetting` (`"readonly"` | `"writable"` | `null`) ... The setting in config files. This is `null` if config files didn't define it. 29 | 30 | And this proposal removes existing `variable.eslintExplicitGlobalComment` property in favor of new `variable.eslintExplicitGlobalComments` property. 31 | 32 | Both `variable.eslintExplicitGlobalComments` and `variable.eslintImplicitGlobalSetting` are instantiated even if regular variable declarations (E.g. `let foo` syntax) exist. Therefore, [no-redeclare] rule can verify redeclaration by a mix of regular variable declarations, `/*globals*/` comments, and config files. 33 | 34 | This will be implemented into [`addDeclaredGlobals(globalScope, configGlobals, commentDirectives)`][lib/linter.js#L73-L131] function. 35 | 36 | ## Documentation 37 | 38 | This proposal is related to making rules. So [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) page should describe those properties, including undocumented existing properties. 39 | 40 | - `variable.writeable` 41 | - `variable.eslintExplicitGlobal` 42 | - `variable.eslintExplicitGlobalComments` 43 | - `variable.eslintImplicitGlobalSetting` 44 | 45 | And, we should make an item in the migration guide. One undocumented property is removed. 46 | 47 | - `variable.eslintExplicitGlobalComment` 48 | 49 | ## Drawbacks 50 | 51 | Rules get accessible to `globals` setting values. It might restrict us to change the system which declares global variables. 52 | 53 | ## Backwards Compatibility Analysis 54 | 55 | If a plugin rule used `variable.eslintExplicitGlobalComment` property, because this proposal removes it, the rule will be broken. But that property was undocumented and [GitHub search](https://github.com/search?p=1&q=eslintExplicitGlobalComment+language%3Ajavascript&type=Code) shows only copies of `no-unused-vars` rule or ESLint core, so this removal is no danger. (One point, `eslint-plugin-closure` package has [the type definition of escope](https://github.com/google/eslint-closure/blob/bf5c0d4d2a67ea3e8394c228717ae23d1a1ae4ba/packages/eslint-plugin-closure/lib/externs/escope.js#L163). That will need to be tweaked regardless of the removal.) 56 | 57 | If a plugin rule used `variable.eslintExplicitGlobalComments` property or `variable.eslintImplicitGlobalSetting` property for some reason, the rule will be broken. But it's a pretty little possibility. 58 | 59 | ## Alternatives 60 | 61 | - Adding `context.getImplicitGlobalSettings()` method to `RuleContext` object to retrieve normalized `globals` setting. In this case, rules can know settings in config files even if `/*globals foo:off*/` comment existed. On the other hand, rules have to search and parse `/*globals*/` comments manually although ESLint core has handled those once. 62 | 63 | ## Related Discussions 64 | 65 | - [eslint/eslint#11370] 66 | 67 | 68 | [@mysticatea]: https://github.com/mysticatea 69 | [eslint/eslint#11370]: https://github.com/eslint/eslint/issues/11370 70 | [lib/linter.js#L73-L131]: https://github.com/eslint/eslint/blob/b00a5e9d8dc6c5f77eb0e4e0c58dfaf12a771d7b/lib/linter.js#L73-L131 71 | [no-redeclare]: https://eslint.org/docs/rules/no-redeclare 72 | [eslint-plugin-eslint-comments]: https://github.com/mysticatea/eslint-plugin-eslint-comments 73 | -------------------------------------------------------------------------------- /designs/2019-rule-tester-improvements/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-06-07 2 | - RFC PR: https://github.com/eslint/rfcs/pull/25 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # `RuleTester` Improvements 6 | 7 | ## Summary 8 | 9 | This RFC improves `RuleTester` to check more mistakes. 10 | 11 | ## Motivation 12 | 13 | `RuleTester` overlooks some mistakes. 14 | 15 | - Using non-standard properties of AST ([typescript-eslint/typescript-eslint#405](https://github.com/typescript-eslint/typescript-eslint/issues/405)).
16 | Especially, `node.start` and `node.end` exist in AST `espree` made, but it's not standardized and some custom parsers don't make those properties. But `node.loc` has `start`/`end` properties, so it's hard to detect `node.start`/`node.end` with static analysis. Therefore, `RuleTester` should detect those. 17 | - Untested autofix.
18 | If people forgot to write `output` property in test cases, `RuleTester` doesn't test autofix silently. 19 | - `errors` property with a number (found in [eslint/eslint#11798](https://github.com/eslint/eslint/pull/11798)).
20 | `errors` property with a number ignores syntax errors in test code. We overlooked the mistake of [tests/lib/rules/complexity.js#L84](https://github.com/eslint/eslint/blob/cb1922bdc07e58de0e55c13fd992dd8faf3292a4/tests/lib/rules/complexity.js#L84) due to this. The number `errors` property cannot check the reported error was the expected error. 21 | - Typo property names in `errors` property with objects.
22 | [eslint/eslint#12096](https://github.com/eslint/eslint/pull/12096). 23 | 24 | ## Detailed Design 25 | 26 | 1. Disallowing `node.start` and `node.end` 27 | 1. Ensuring to test autofix 28 | 1. Changing the `errors` property of a number to fail on syntax errors 29 | 1. Changing the `errors` property of objects to fail on unknown properties 30 | 31 | ### 1. Disallowing `node.start` and `node.end` 32 | 33 | `RuleTester` fails test cases if a rule implementation used `node.start` or `node.end` in the test case. 34 | 35 | #### Implementation 36 | 37 | - In `RuleTester`, it registers an internal custom parser that wraps `espree` or the parser of `item.parser` to `Linter` object. 38 | - The internal custom parser fixes the AST that the original parser returned, as like [test-parser.js](https://github.com/eslint/eslint/blob/21f3131aa1636afa8e5c01053e0e870f968425b1/tools/internal-testers/test-parser.js). 39 | 40 | ### 2. Ensuring to test autofix 41 | 42 | `RuleTester` fails test cases if a rule implementation fixed code but `output` property was not defined in the test case. 43 | 44 | #### Implementation 45 | 46 | - If `output` property didn't exist but the rule fixed the code, `RuleTester` fails the test case as "The rule fixed the code. Please add 'output' property." It's implemented around [lib/rule-tester/rule-tester.js#L594](https://github.com/eslint/eslint/blob/21f3131aa1636afa8e5c01053e0e870f968425b1/lib/rule-tester/rule-tester.js#L594). 47 | 48 | ### 3. Changing the `errors` property of a number to fail on syntax errors 49 | 50 | `RuleTester` fails test cases always if the `code` has a syntax error. 51 | 52 | #### Implementation 53 | 54 | - Unwrap [lib/rule-tester/rule-tester.js#L414-L419](https://github.com/eslint/eslint/blob/02d7542cfd0c2e95c2222b1e9e38228f4c19df19/lib/rule-tester/rule-tester.js#L414-L419). 55 | 56 | ### 4. Changing the `errors` property of objects to fail on unknown properties 57 | 58 | `RuleTester` fails test cases if any item of `errors` has unknown properties. 59 | 60 | #### Implementation 61 | 62 | - [eslint/eslint#12096](https://github.com/eslint/eslint/pull/12096) 63 | 64 | ## Documentation 65 | 66 | [RuleTester](https://eslint.org/docs/developer-guide/nodejs-api#ruletester) should be updated. 67 | 68 | - `output` ("optional" → "required if the rule fixes code") 69 | 70 | ## Drawbacks 71 | 72 | This change may enforce plugin owners to fix their tests. 73 | 74 | ## Backwards Compatibility Analysis 75 | 76 | This is a breaking change that can break existing tests. 77 | 78 | But the breaking cases may indicate that the rule was not tested enough. 79 | 80 | ## Alternatives 81 | 82 | - About "Disallowing `node.start` and `node.end`", we can standardize those properties. But it's a breaking change for custom parser owners. On the other hand, using `node.start` and `node.end` breaks the rule if users used custom parsers, so the impact of this disallowing is limited. 83 | 84 | ## Related Discussions 85 | 86 | - https://github.com/eslint/eslint/issues/8956 87 | - https://github.com/eslint/eslint/pull/8984 88 | - https://github.com/eslint/eslint/pull/11798 89 | - https://github.com/eslint/eslint/pull/12096 90 | - https://github.com/typescript-eslint/typescript-eslint/issues/405 91 | -------------------------------------------------------------------------------- /designs/2019-plugin-root-path-flag/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-03-13 2 | - RFC PR: https://github.com/eslint/rfcs/pull/18 3 | - Authors: Teddy Katz 4 | 5 | # Add a flag to specify the folder where plugins are resolved from 6 | 7 | ## Summary 8 | 9 | With the [2018-simplified-package-loading RFC](https://github.com/eslint/rfcs/blob/8bc0b80e0b3e54d10991a4774c41f7375dfcbbfe/designs/2018-simplified-package-loading/README.md) implemented, ESLint always resolves plugins relative to the current working directory. The CWD works well for the most common use case, but is inconvenient for certain integrations. This RFC proposes adding a CLI flag to specify an alternative place where plugins should be resolved from. 10 | 11 | ## Motivation 12 | 13 | We require whoever invokes ESLint to also install any necessary plugins. Generally speaking, in order to ensure that plugins are resolved correctly, ESLint should resolve plugins relative to whichever project installed the plugins. As a result, ESLint would ideally resolve plugins relative to the package that invokes ESLint. 14 | 15 | However, we can't reliably tell who is invoking ESLint, so the [2018-simplified-package-loading RFC](https://github.com/eslint/rfcs/blob/8bc0b80e0b3e54d10991a4774c41f7375dfcbbfe/designs/2018-simplified-package-loading/README.md) always loads plugins relative to the CWD. This works well when the end user invokes ESLint, because the CWD is usually somewhere in the end user's project. Unfortunately, it causes problems for third-party integrations that invoke ESLint on behalf of the end user, such as `standard` and `create-react-app`. The plugins used in these integrations are transitive dependencies for the end user, so they might not be reachable from the CWD. 16 | 17 | It is possible for these integrations to work around the issue by changing the CWD (with the `cwd` option in `CLIEngine`), but changing the CWD has a number of inconvenient side-effects. For example, if the `cwd` is set to the directory of a third-party package, the end user's `node_modules` folder is not ignored by default, and relative paths might be resolved in an unexpected way. 18 | 19 | ## Detailed Design 20 | 21 | This RFC adds a `--resolve-plugins-relative-to` CLI flag, and a corresponding `resolvePluginsRelativeTo` option in `CLIEngine`. The option value, if provided, must be an absolute path to a directory. 22 | 23 | When provided, ESLint loads all plugins relative to the `resolvePluginsRelativeTo` directory, rather than the CWD. The expectation is that integrations like `standard` and `create-react-app`, which already use `CLIEngine`, would pass an option like `{ resolvePluginsRelativeTo: __dirname }` to indicate that the package's own plugins should be used regardless of the CWD. 24 | 25 | The implementation is expected to be fairly simple when building on top of [eslint/eslint#11388](https://github.com/eslint/eslint/pull/11388). That implementation already has an equivalent directory path that gets passed around to specify plugin loading, but that path currently is always the same as the CWD. 26 | 27 | (Note: In the [2018-simplified-package-loading RFC](https://github.com/eslint/rfcs/blob/8bc0b80e0b3e54d10991a4774c41f7375dfcbbfe/designs/2018-simplified-package-loading/README.md), the `resolvePluginsRelativeTo` was referred to as the "project root".) 28 | 29 | ## Documentation 30 | 31 | This feature might be useful to add as a footnote for the larger announcement of package-loading changes. It would be worth mentioning in the parts of the documentation that describe how plugins are loaded, and it would also be added to the Node.js API docs. However, most end users would not need to use this option or be aware of its existence. 32 | 33 | ## Drawbacks 34 | 35 | Like any new feature, this flag will slightly increase the complexity and maintenance costs of ESLint core. 36 | 37 | If we change how plugins are loaded in the future, this flag may become obsolete or turn into a no-op. 38 | 39 | ## Backwards Compatibility Analysis 40 | 41 | This change is backwards-compatible. It adds a new CLI flag while keeping the behavior the same if the flag is not specified. 42 | 43 | ## Alternatives 44 | 45 | As described in [#14](https://github.com/eslint/rfcs/pull/14), We could change how plugin-loading works to always resolve plugins from the config that imports them, eliminating the need to load things from the CWD. That change would eliminate the need for this command-line flag. However, that change presents complex compatibility and design challenges which are still under discussion. If we change how the `plugins` directive works, it seems like it won't happen before v7.0.0, and this flag would be important to have in the meantime. Given that a user can already somehwat customize this behavior by changing the CWD, the existence of this flag is unlikely to impose a substantial compatibility burden even if we do change how plugins are loaded later. 46 | 47 | ## Open Questions 48 | 49 | None 50 | 51 | 52 | ## Frequently Asked Questions 53 | 54 | None yet 55 | 56 | ## Related Discussions 57 | 58 | * [#7](https://github.com/eslint/rfcs/pull/7) 59 | * [#14](https://github.com/eslint/rfcs/pull/14) 60 | -------------------------------------------------------------------------------- /designs/2019-changing-base-path-in-config-files-that-cli-options-specify/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-09-18 2 | - RFC PR: https://github.com/eslint/rfcs/pull/37 3 | - Authors: Toru Nagashima 4 | 5 | # Changing Base Path of `overrides` and `ignorePatterns` that CLI Options Specify 6 | 7 | ## Summary 8 | 9 | This RFC changes the base path of `overrides`, `ignorePatterns`, and `.eslintignore` from the directory which contains the config file to the current working directory if the config file was specified by CLI options `--config` or `--ignore-path`. 10 | 11 | ## Motivation 12 | 13 | Currently, the base path of `overrides`, `ignorePatterns`, and `.eslintignore` is the directory which contains the config file even if the config file was specified by CLI options `--config` or `--ignore-path`. 14 | 15 | ```bash 16 | # the paths of 'overrides' and 'ignorePatterns' are relative to 'node_modules/my-config/' 17 | eslint lib --config node_modules/@me/my-config/.eslintrc.js 18 | # the paths in `.eslintignore` are relative to 'node_modules/my-config/' 19 | eslint lib --ignore-path node_modules/@me/my-config/.eslintignore 20 | ``` 21 | 22 | This is a barrier to use `--config`/`--ignore-path` option with shared files. If we change the base path to the current working directory, it will resolve this problem. 23 | 24 | ### .gitignore and core.excludesFile 25 | 26 | `.eslintignore` has been designed as similar stuff to `.gitignore`. Therefore, it's better if the feature around `.eslintignore` is similar to `.gitignore`. 27 | 28 | Git doesn't have `--ignore-path`-like CLI option, but has `core.excludesFile` setting to specify additional ignore file. 29 | 30 | ```bash 31 | # Use './config/ignore' file as '.gitignore'. 32 | git config core.excludesFile config/ignore 33 | ``` 34 | 35 | In this case, the base path of the paths in `config/ignore` is the repository root. For example, `/node_modules` in `config/ignore` is `./node_modules` rather than `./config/ignore/node_modules`. This behavior is different from our `--ignore-path` option. 36 | 37 | ## Detailed Design 38 | 39 | It changes the base path of the following patterns to the current working directory: 40 | 41 | - In the file which is specified by the `--config` option: 42 | - `overrides[i].files` 43 | - `overrides[i].excludedFiles` 44 | - `ignorePatterns` 45 | - In the file which is specified by the `--ignore-path` option: 46 | - file patterns. 47 | 48 | ```bash 49 | # the paths of 'overrides' and 'ignorePatterns' are relative to './' 50 | eslint lib --config node_modules/@me/my-config/.eslintrc.js 51 | # the paths in `.eslintignore` are relative to './' 52 | eslint lib --ignore-path node_modules/@me/my-config/.eslintignore 53 | ``` 54 | 55 | This RFC *doesn't* change the resolving logic of `extends`, `parser`, and `plugins`. 56 | 57 | ### Implementation 58 | 59 | It modifies [`createCLIConfigArray()` function](https://github.com/eslint/eslint/blob/869f96aa87c4f990f54e1eeccb0e3f7dbd66e6c2/lib/cli-engine/cascading-config-array-factory.js#L133-L165). In the function, it modifies the elements of the config arrays which are created from the `ignorePath` (corresponds to `--ignore-path`) and the `specificConfigPath` (corresponds to `--config`). It modifies `element.criteria.basePath` (corresponds to `overrides`) and `element.ignorePattern.basePath` (corresponds to `ignorePatterns` and `.eslintignore`) to `cwd`. 60 | 61 | ## Documentation 62 | 63 | This change needs the migration guide because of a breaking change. 64 | 65 | This change needs to update the following documents: 66 | 67 | - the "[Configuration Based on Glob Patterns » Relative glob patterns](https://github.com/eslint/eslint/blob/869f96aa87c4f990f54e1eeccb0e3f7dbd66e6c2/docs/user-guide/configuring.md#relative-glob-patterns)" section. 68 | - the "[Ignoring Files and Directories » `ignorePatterns` in config files](https://github.com/eslint/eslint/blob/869f96aa87c4f990f54e1eeccb0e3f7dbd66e6c2/docs/user-guide/configuring.md#ignorepatterns-in-config-files)" section. 69 | - the "[Ignoring Files and Directories » `.eslintignore`](https://github.com/eslint/eslint/blob/869f96aa87c4f990f54e1eeccb0e3f7dbd66e6c2/docs/user-guide/configuring.md#eslintignore)" section. 70 | - As a side note, this section is outdated a bit. It said "Paths are relative to `.eslintignore` location or the current working directory.", but it has been changed since ESLint 4.0.0. Currently, it's "Paths are relative to `.eslintignore` location." 71 | 72 | ## Drawbacks 73 | 74 | This is a breaking change. It can break the current workflow. 75 | 76 | For example, if a user runs ESLint on variety directories with the same config by `--config` and `--ignore-path`, the workflow will be broken. The user has to change the path to target files instead of the working directory. 77 | 78 | ## Backwards Compatibility Analysis 79 | 80 | This is a breaking change. 81 | 82 | The behavior of `--config` and `--ignore-path` options will be changed. 83 | 84 | ## Alternatives 85 | 86 | ### Prior Arts 87 | 88 | - [`.gitignore` and `core.excludesFile`](#gitignore-and-coreexcludesfile) is similar to this RFC's behavior. 89 | 90 | ## Related Discussions 91 | 92 | - https://github.com/eslint/eslint/issues/6759 93 | - https://github.com/eslint/eslint/issues/11558 94 | - https://github.com/eslint/eslint/issues/12278 95 | -------------------------------------------------------------------------------- /designs/2019-suggestions/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-04 2 | - RFC PR: https://github.com/eslint/rfcs/pull/30 3 | - Authors: Ilya Volodin ([@ilyavolodin](https://github.com/ilyavolodin)), Dan Abramov ([@gaearon](https://github.com/gaearon)) 4 | 5 | # Code Suggestions 6 | 7 | ## Summary 8 | 9 | This RTC proposes introducing a new mechanism for providing users with suggestions. It's very similar to fixes mechanism that already exists in ESLint, but will provide ability to create multiple suggestions per rule, suggestions will not be automatically applied by using `--fix` flag, and will require user interaction. This feature will only be exposed through the ESLint API, and will not be available on the CLI. 10 | 11 | ## Motivation 12 | 13 | This has been suggested multiple times before, but the main driving force behind this proposal is ability to provide user with options on how to automatically refactor/fix their code, without a possibility of "stealthily" breaking it. Examples of such suggestions include ability to suggest adding `import` statement if certain code is added to a file by the user, ability to provide refactoring suggestions like extracting repeated value into a variable, reformatting code to extract repeated statements into reusable function, etc. I do not envision ESLint team to initially create any rules that would provide suggestions, so this would be a feature that would enable plugin authors to do so, but it might be something that ESLint team will eventually do. This feature is geared towards code editor integrations, as such, it will only be available via NodeJS API. 14 | 15 | ## Detailed Design 16 | 17 | Suggestion will be applied as a stand-alone change, without triggering multipass fixes. Each suggestion should focus on a singular change in the code and should not try to confirm to user defined styles. For example, if suggestion is adding a new statement into the codebase, it should not try to match correct indentation, or confirm to user preferences on presence/absence of semicolumns. All of those things will be corrected by multipass autofix when the user triggers it. It should be suggested that if a user wants to use suggestions, he/she should also enable auto-fix on save in their editor of choice. 18 | 19 | * Modify `context.report` function parameter to include new property called `suggest` of type array of objects. Each object will contain a description of the suggestion and a function that will be able to modify the code of the file to implement suggestion. Syntax is going to be exactly the same as for `fix` functions. Example of new signature below: 20 | ```js 21 | context.report({ 22 | node, 23 | loc, 24 | messageId: 'messageId', 25 | fix(fixer) { }, 26 | suggest: [ 27 | { desc: 'Description of the suggestion', fix: (fixer) => { }}, 28 | { desc: 'Description of the suggestion', fix: (fixer) => { }} 29 | ] 30 | }); 31 | ``` 32 | * Change `_verifyWithoutProcessors` and `_verifyWithProcessor` functions in linter.js to modify output of those functions to include `suggestions` array returned by the rule. After modification the signature of the return object should look like this: 33 | ```js 34 | interface LintMessage { 35 | //...(existing props)... 36 | suggestions: Array<{ desc: string, fix: { range: [number, number] } }> 37 | } 38 | ``` 39 | * Modify output of `CLIEngine` `executeOnFiles` and `executeOnText` to include `suggestions` array returned by the rule. If `options.disableFixes` are passed into those functions, return result should not include any suggestions return by the rules. 40 | * Update `docs` section of rule metadata to include `suggestion: true|false` to make it easier to identify rules that can return suggestions. 41 | * Unlike fixes, suggestion will not expose a new API function on `CLIEngine` to output selected suggestion to a file. Instead, integration would be expected to apply suggestion in memory and let the user save the file on their own. 42 | 43 | ## Documentation 44 | 45 | This would need to be documented as part of the public API. 46 | * [Node.js API](https://eslint.org/docs/developer-guide/nodejs-api) page needs to be updated with corresponding changes to `linter` and `CLIEngine`. 47 | * [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) page needs to be updated to show examples of returning suggestions. It would also need to include changes to metadata to identify rules that return suggestions. 48 | * Update rule documentation template to clearly show rules that return suggestions. 49 | 50 | ## Drawbacks 51 | 52 | * This might potentially be a bit confusing, since we do not have many functions that we provide through API only and not through CLI. 53 | * Suggestions might lead to user created rules that try to do too much modifications to the user's code. For example suggesting large refactoring that might introduce a lot of breaking changes. To mitigate this, we should add documentation that would warn rule creators against doing that. 54 | 55 | ## Backwards Compatibility Analysis 56 | 57 | Since `suggestions` property in `context.report` object is optional, this should be fully backwards compatible. 58 | 59 | ## Alternatives 60 | 61 | This functionality is basically the same as existing `autofix` functionality already included in ESLint. The only difference is there might be multiple suggestions per error and they are not applied automatically by ESLint. 62 | 63 | ## Open Questions 64 | 65 | Should we consider instead providing new type of `rules` that would not report any issues, but only provide suggestions? 66 | 67 | ## Related Discussions 68 | 69 | https://github.com/eslint/eslint/issues/7873 70 | https://github.com/eslint/eslint/issues/6733#issuecomment-234656842 71 | -------------------------------------------------------------------------------- /designs/2020-generic-ast-support/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2020-06-04 3 | - RFC PR: https://github.com/eslint/rfcs/pull/56 4 | - Authors: Ilya Volodin 5 | 6 | # Generic AST support 7 | 8 | ## Summary 9 | 10 | Allow ESLint to traverse and lint generic (non estree compliant AST) and allow parsers to specify information about AST that would drive ESLint's traversal and features. 11 | 12 | ## Motivation 13 | 14 | ESLint has cemented itself as a go to tool for JavaScript/TypeScript ecosystem for style checking and linting. However, there are a lot of connected languages/technologies that are used every day by ESLint users that are either lacking linters, or require yet another tool to be setup and configured for the repository. Examples include HTML, CSS, SCSS, LESS, GraphQL, JSON, etc. 15 | With addition of config overrides users can now setup separate configuration per glob, so that would allow them to have a single instance of ESLint and a single configuration that would allow linting of the entire repository, including all non javascript/typescript files. 16 | 17 | ## Detailed Design 18 | 19 | ### Initial assumptions 20 | * This RFC does not expect or implies that existing core or plugin rules will work for any files that are parsed through non-estree compliant parsers. Every parser that chooses to output custom AST will have to provide new rules that will work for this AST in the form of plugins. 21 | * This RFC doesn't propose full feature parity for new parser with existing ESLint capabilities. For example, it doesn't propose a new way to provide custom Code Path Analyzer, or support inline directives for controlling ESLint's flow for custom ASTs. However, those functionalities can be added later with a separate RFC(s). 22 | 23 | Currently ESLint has a lot of hardcoded assumptions about AST. For example, it assumes that nodes are identified by the property called `type` and that property exists on every node. It assumes that top-most node is always `Program` and that AST supports code-path-analysis (which is very specific to JavaScript). This RFC proposes to modify expected output from the `parseForESLint` method of the custom parsers to include additional property called `parserSupportOptions` of type object with four new properties (for now): 24 | - nodeIdentifier: function | string | undefined - Specifies a function that can retrieve the name of the ASTNode property that identifies node. Alternatively, can be a string that just returned the name of the property that identifies all nodes. If the property is not provided, ESLint will default to `type` for backwards compatibility. 25 | - codePathAnalysis: "off" | "default" - Indicates AST's support for built-in CodePathAnalysis support. Defaults to `”default”` for backwards compatibility. 26 | - rootNode: string - Provides the name of the top level node in the AST. Defaults to `Program` for backwards compatibility. 27 | - metadata: { language: string } - Used for informational purposes only. Identifies name of the language that this parser supports. 28 | 29 | This RFC also proposes modifying existing returned property "scopeManager" that's already returned by `parseForESLint`. Currently, while documentation states, that this property is not required, ESLint will crash if returning `null`. Instead, it can be modified to return tri-state value of type `"off" | "default" | ScopeManager`. If "off" is returned, scope analysis will be completely disabled for files parsed by custom parser. "default" will specify to use ESLint's default scope manager (eslint-scope). Providing an object of type `ScopeManager` will require ESLint to use it instead of analyzing code through eslint-scope. 30 | 31 | This change would allow basic support of linting non-estree compliant ASTs. This will still not enable full feature parity with ESLint's abilities when linting JavaScript. In the future new properties might be added to support parsing comments to enable inline directives for controlling rules. Other enhancements might include ability to provide replacement for CodePathAnalysis and scopes creation. 32 | 33 | ## Documentation 34 | 35 | This will be documented as part of the page that describes [working with custom parsers](https://eslint.org/docs/developer-guide/working-with-custom-parsers). In addition, blog post would let other users know that they can start creating parsers and rules for new languages. Although, it might be a good idea to wait until there's an example in the wild that could be pointed to as a reference. 36 | 37 | ## Drawbacks 38 | 39 | The only drawback that I can think of, is that JavaScript specific rules will not work for other ASTs. Each language will most likely have to implement their own set of rules, and they will be incompatible across different parsers. While this might cause some confusion for users, I do believe this makes sense and there is no need to try to somehow generalize rules to support multiple ASTs. 40 | 41 | ## Backwards Compatibility Analysis 42 | 43 | This change will be fully backwards compatible. In the future, default nodeIdentifier described above could be removed and moved into espree instead. 44 | 45 | ## Alternatives 46 | 47 | None that I can think of, other then not to support any non-compliant estree ASTs. 48 | 49 | ## Open Questions 50 | 51 | * Is it OK to release incomplete support for other AST types? Inline directives being the biggest obstacle, from my perspective. 52 | * Should `nodeIdentifier` be passed into rules through `context` to allow creations of very generic rules that can support multiple languages/ASTs? 53 | * Is `parserSupportOptions` descriptive enough name? I wasn't able to come up with anything better. 54 | 55 | ## Help Needed 56 | 57 | I have a working branch with a large refactoring effort to remove hardcoded `type` nodeIdentifier. Everything is working and all tests are passing, except for one in code-path-analysis. Unfortunately, I wasn't able to figure out what is causing this problem. Code is available here: https://github.com/ilyavolodin/eslint/tree/ast 58 | Another problem, is that I wasn't able to find a way to pass `nodeIdentifier` into formatters, since they live higher in the stack then execution of the custom parser provided. I need suggestions on how to fix this. Not all parsers require this information, but some might. 59 | 60 | ## Related Discussions 61 | 62 | * https://github.com/eslint/eslint/pull/13305 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESLint RFCs 2 | 3 | Many changes, including bug fixes and documentation improvements, can be 4 | implemented and reviewed via the normal GitHub pull request workflow. 5 | 6 | However, some changes are "substantial", and we ask that these be put 7 | through a bit of a design process and produce a consensus among the ESLint Technical Steering Committee (TSC). 8 | 9 | The "RFC" (request for comments) process is intended to provide a 10 | consistent and controlled path for new features to enter the project. 11 | 12 | ## When you need to follow this process 13 | 14 | You need to follow this process if you intend to make "substantial" 15 | changes to any part of the ESLint project or its documentation. What constitutes a 16 | "substantial" change is evolving based on community norms, but may 17 | include the following. 18 | 19 | * A new ESLint command line option. 20 | * A new feature of ESLint core. 21 | * A refactoring of existing ESLint core functionality. 22 | * Any breaking change. 23 | 24 | In addition to these, the TSC may request an RFC for any other change that it deems "substantial" based on the size or scope of the request. 25 | 26 | If you submit a pull request to implement a new feature without going 27 | through the RFC process, it may be closed with a polite request to 28 | submit an RFC first. 29 | 30 | ## Gathering feedback before submitting 31 | 32 | Before submitting an RFC, open an issue in the repository where you'd like to make the change (for example, to make a change to ESLint, open an issue in the [eslint/eslint](https://github.com/eslint/eslint) repository). The purpose of opening the issue is to gather feedback from the community and the ESLint team to ensure that there is enough interest to put together an RFC. 33 | 34 | Once the ESLint team has indicated that there is enough interest, you'll be asked to create an RFC to describe the change you'd like to make in more detail. 35 | 36 | **Note:** Please do not submit a pull request with your prototype or proof-of-concept. Instead, include a link to your fork or branch when you submit your RFC (see next section). 37 | 38 | ## How to submit an RFC to this repo 39 | 40 | To submit a new RFC, follow these steps: 41 | 42 | 1. [Fork](https://github.com/eslint/rfcs/fork) the RFC repo. 43 | 1. Create a directory inside of the `designs` directory. The directory name should begin with the year and include a meaningful description, such as `designs/2018-typescript-support`. 44 | 1. Copy the appropriate template file from the `templates` directory into the appropriate `designs` subdirectory (such as `designs/2018-typescript-support/README.md`). Be sure to name your file `README.md` so it is easily viewable in the GitHub interface. 45 | 1. If you want to include images in your RFC, place them in the same directory as the `README.md`. 46 | 1. Fill in the RFC. Please fill in every section in the template with as much detail as possible. 47 | 1. Submit a pull request to this repo with all of your files. This begins the approval process (detailed below). 48 | 1. RFCs that are accepted will be merged directly into this repo; RFCs that are not accepted will have their pull requests closed without merging. 49 | 50 | ## The RFC Approval Process 51 | 52 | When an RFC is submitted, it goes through the following process: 53 | 54 | 1. **Initial commenting period (21-90 days)** - the community and ESLint team are invited to provide feedback on the proposal. During this period, you should expect to update your RFC based on the feedback provided. Very few RFCs are ready for approval without edits, so this period is important for fine-tuning ideas and building consensus. (A PR in the initial commenting period has the **Initial Commenting** label applied.) The initial commenting period must last at least 21 days and not more than 90 days to allow the team and community enough time to comment. The TSC may decide to reject the RFC without promoting it to the final commenting period. 55 | 1. **Final commenting period (7 days)** - when all feedback has been addressed, the pull request author requests a final commenting period where ESLint TSC members provide their final feedback and either approve of the pull request or state their disagreement. (A PR in the final commenting period has the **Final Commenting** label applied.) ESLint TSC members are notified through GitHub when an RFC has passed into the final commenting period. 56 | 1. **Approval and Merge** - if the TSC reaches consensus on approving the RFC, the pull request will be merged. If consensus is not reached on the pull request then the RFC will be discussed at the next TSC meeting to determine whether or not to move forward. Approving and merging an RFC signifies that the TSC believes the change is directionally correct and wants to see it implemented in ESLint. An RFC does not need to be a final specification because we can make tweaks and consider edge cases during the implementation phase. 57 | 58 | **Note:** If two or more RFCs attempt to address the same problem or need, the TSC will consider all of the competing RFCs together to determine which RFC to approve. Alternately, the TSC may request that competing RFCs be merged in order to create a hybrid solution. 59 | 60 | ## The RFC Lifecycle 61 | 62 | Once an RFC is merged into this repo, then the authors may implement it and submit a pull request to the appropriate ESLint repo without opening an issue. Note that the implementation still needs to be reviewed separate from the RFC, so you should expect more feedback and iteration. 63 | 64 | If the RFC authors choose not to implement the RFC, then the RFC may be implemented by anyone. There is no guarantee that RFCs not implemented by their author will be implemented by the ESLint team. 65 | 66 | Changes to the design during implementation should be reflected by updating the related RFC. The goal is to have RFCs to look back on to understand the motivation and design of shipped ESLint features. 67 | 68 | ## Implementing an RFC 69 | 70 | The author of an RFC is not obligated to implement it. Of course, the 71 | RFC author (like any other developer) is welcome to post an 72 | implementation for review after the RFC has been accepted. 73 | 74 | When a pull request has implemented an RFC, the RFC should be updated with a link 75 | to the PR implementing it. 76 | 77 | **Thanks to the [Ember RFC process](https://github.com/emberjs/rfcs) for the inspiration for ESLint's RFC process.** 78 | -------------------------------------------------------------------------------- /designs/2021-fixable-disable-directives/design.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2021-04-11 3 | - RFC PR: https://github.com/eslint/rfcs/pull/78 4 | - Authors: [Josh Goldberg](https://github.com/JoshuaKGoldberg) 5 | 6 | # Fixable Disable Directives 7 | 8 | ## Summary 9 | 10 | Inline disable directives such as `/* eslint-disable */` that do not suppress any violations may be detected with the `--report-unused-disable-directives` CLI option, but there is no way to automatically remove those comments. 11 | This RFC proposes adding removal of those directives to the `--fix` CLI option as a new [`--fix-type`](https://eslint.org/docs/user-guide/command-line-interface#-fix-type): _**`directive`**_. 12 | 13 | ## Motivation 14 | 15 | Manually deleting comments from `--report-unused-disable-directives` is cumbersome, especially in large repositories with many directives. 16 | Users would benefit from a quick way to fix these without having to manually map between CLI output lines and files. 17 | 18 | ## Detailed Design 19 | 20 | Recapping the existing flow of code: 21 | 22 | - When the `--fix-type` CLI option is specified, `options.fix` is patched to filter on the `rule.meta` of each fix's corresponding `ruleId` 23 | - Unused disable directives are calculated by an `applyDirectives` function within the `applyDisableDirectives` function called in the linter's `_verifyWithoutProcessors` 24 | - These problems have a `ruleId` of `null` 25 | - `_verifyWithoutProcessors` is called within the call stack of each of the 1-10 passes in the linter's `verifyAndFix` 26 | 27 | This RFC proposes making three changes: 28 | 29 | - In the patched `options.fix`, consider a problem's meta type to be `"directive"` if its `ruleId` is `null` 30 | - Pass the `SourceCode` being linted as a parameter to `applyDisableDirectives` 31 | - Add a `fix` method to the unused directive problems returned by `applyDirectives` that uses the `SourceCode` 32 | 33 | ### Fix Behavior 34 | 35 | Directives where at least one rule is still used will have only the unused rule names removed from their source text. 36 | 37 | Directives where all >=1 rules are unused will use the `SourceCode` to compute: 38 | 39 | - If they are the only non-whitespace on their line, delete that line 40 | - Otherwise, delete just the comment and any now-unnecessary surrounding whitespace 41 | 42 | #### Fix Behavior Examples 43 | 44 | ```diff 45 | - /* eslint-disable */ 46 | ``` 47 | 48 | ```diff 49 | - // eslint-disable-next-line -- related explanation 50 | ``` 51 | 52 | ```diff 53 | - // eslint-disable-next-line unused, used 54 | + // eslint-disable-next-line used 55 | ``` 56 | 57 | ```diff 58 | - before /* eslint-disable-next-line -- related explanation */ after 59 | + before after 60 | ``` 61 | 62 | ```diff 63 | - before // eslint-disable-next-line -- related explanation 64 | + before 65 | ``` 66 | 67 | ```diff 68 | // before 69 | - // eslint-disable-next-line 70 | // after 71 | ``` 72 | 73 | Multiline block comments are already not allowed to be disable directives. [eslint/eslint#10334](https://github.com/eslint/eslint/issues/10334) 74 | 75 | ## Documentation 76 | 77 | - [Command Line Interface > Fixing Problems](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems)'s `--fix` documentation should mention the added directives fixing and the new `--fix-type` 78 | - [Rules > Report Unused ESLint Disable Comments](https://eslint.org/docs/user-guide/configuring/rules#report-unused-eslint-disable-comments) should link to that documentation 79 | 80 | ## Drawbacks 81 | 82 | Like any new feature, this flag will slightly increase the complexity and maintenance costs of ESLint core. 83 | 84 | This RFC's implementation would lock in the name for a new `--fix-type` even though we only have one concrete use case for it. 85 | 86 | ## Backwards Compatibility Analysis 87 | 88 | It is unlikely but not impossible that some `--fix` dependant users would rely on unused disable directives remaining in code. 89 | 90 | Otherwise, this change is additive in behavior. 91 | 92 | ## Alternatives 93 | 94 | - Applying directive fixes after the `verifyAndFix` passes 95 | - Not ideal: deleting a comment could introduce new rule violations that would warrant running >=1 other pass 96 | - Writing an external tool to apply these options 97 | - Not ideal: the internal implementation is simple; external would have to deal with variant formatters, etc and suffer from the same introduced rule violations 98 | 99 | ## Open Questions 100 | 101 | - Is `"directive"` a good name for the fix type? 102 | - It feels like it could be too specific to be extended for other meta/configuration in the future. 103 | - This RFC originally proposed `"meta"` but that goes too far in being overly vague. 104 | 105 | ## Help Needed 106 | 107 | I'm looking forward to implementing this if approved! 🙌 108 | 109 | ## Frequently Asked Questions 110 | 111 | > Will these be autofixed by default? 112 | 113 | If `--fix` and `--report-unused-disable-directives` are both true, then yes. 114 | There is no additional configuration that would need to be provided. 115 | 116 | If `--fix` is true but `--report-unused-disable-directives` is not, there will be no behavior change from this RFC. 117 | Unused directives would not add to reported problems and thus no new fixers would be added to them. 118 | 119 | If `--fix` is not true but `--report-unused-disable-directives` is, there will be no observable change from this RFC for CLI clients. 120 | Problems for unused directives will have a `fix` property attached but it will not be used without `--fix`. 121 | 122 | > Can I opt out? 123 | 124 | Yes. 125 | If you are in the peculiar situation of needing to enable `--fix` and `--report-unused-disable-directives` _without_ fixing those directives _(why?)_, you can use `--fix-type` with all types except `directive`. 126 | 127 | > How do the generated fixes compare to fixes from rules? 128 | 129 | Problems reported by directive usage checking are joined with remaining rule violation problems in a single array. 130 | This should allow directive fixing to seamlessly act similarly to rule fixing. 131 | 132 | ## Related Discussions 133 | 134 | - [eslint/eslint#10334](https://github.com/eslint/eslint/issues/10334) - Report an error for eslint-disable-line comments that span multiple lines #1033) 135 | - [eslint/eslint#9249](https://github.com/eslint/eslint/issues/9249) - Add CLI option to report unused eslint-disable directives 136 | - [eslint/eslint#11815](https://github.com/eslint/eslint/issues/11815) - --report-unused-disable-directives should be autofixable 137 | -------------------------------------------------------------------------------- /designs/2019-additional-lint-targets/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-05-12 2 | - RFC PR: https://github.com/eslint/rfcs/pull/20 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Configuring Additional Lint Targets with `.eslintrc` 6 | 7 | ## Summary 8 | 9 | This proposal adds the ability to specify additional target files into configuration files. This enhancement will solve the pain that people have to use the `--ext` option with wanted file extensions even if they use plugins which support additional file types. 10 | 11 | ## Motivation 12 | 13 | People have to use the `--ext` option or glob patterns to check wanted files even if they use plugins which support additional file types. 14 | 15 | ```yml 16 | plugins: 17 | - markdown 18 | - html 19 | - "@typescript-eslint" 20 | - react 21 | - vue 22 | ``` 23 | 24 | ```bash 25 | # ESLint checks only `*.js`. 26 | eslint src docs 27 | 28 | # Needs `--ext` option 29 | eslint src docs --ext .js,.md,.html,.ts,.jsx,.tsx,.vue 30 | ``` 31 | 32 | However, using plugins which support additional file types is the intention that wants to check those files. The requirement of redundant CLI options is not reasonable. 33 | 34 | Per "[Related Discussions](#related-discussions)" section, this is very regularly requested; I want to configure additional target files with `.eslintrc`. 35 | 36 | ## Detailed Design 37 | 38 | This proposal enhances `overrides` property of the config file. 39 | 40 | - If a config file in a directory has `overrides` property, ESLint checks the files which are matched by any of override entries (i.e., `files`/`excludedFiles` criteria) additionally in the directory. 41 | - If any of `files` value of an override entry ended with `*`, this enhancement doesn't use the entry in order to avoid checking too many kinds of files. 42 | - This enhancement affects only the case where a directory path is provided on the CLI. If people provide glob patterns on the CLI, ESLint behaves the same as currently. 43 | - The `--ext` option precedences this enhancement. If the `--ext` option was given, this enhancement is disabled. So people can use the current behavior by `--ext .js`. 44 | - The ignoring configuration (`.eslintignore`) precedences this enhancement. If `.eslintignore` contains the additional target files, ESLint just ignores those as same as currently. 45 | 46 | The `overrides` property means that people intend to check those files. So this behavior is intuitive. 47 | 48 |
49 | 💡 Example: 50 |
 51 | overrides:
 52 |   - files: "*.ts"
 53 |     parser: "@typescript-eslint/parser"
 54 |   - files: "tests/**/*"
 55 |     env: { mocha: true }
 56 | 
57 | 58 | With the above config, `eslint .` command will check `*.ts` files additionally. But the command doesn't check all files inside `tests` directory. 59 |
60 | 61 | ### Code blocks 62 | 63 | If a code block that processors extracted has the virtual filename, ESLint filters the file extension of the virtual filename with `--ext` option. This enhancement affects to that check. ESLint lints the code block if the `overrides` matches the virtual filename. 64 | 65 | ### Legacy file extension processors 66 | 67 | This enhancement **doesn't** affect legacy file extension processors. This means that `plugins` property in config files never changes the kinds of target files. 68 | 69 | On the other hand, `extends` property in config files can change the kinds of target files by the `overrides` property in the shareable configs. 70 | 71 | ### Implementation 72 | 73 | - For files, we can add the check to [lib/cli-engine/file-enumerator.js#L410](https://github.com/eslint/eslint/blob/553795712892c8350b1780e947f65d3c019293a7/lib/cli-engine/file-enumerator.js#L410). 74 | - For code blocks, we can add the check to [lib/cli-engine/cli-engine.js#L248](https://github.com/eslint/eslint/blob/21f3131aa1636afa8e5c01053e0e870f968425b1/lib/cli-engine/cli-engine.js#L248). 75 | 76 | ## Documentation 77 | 78 | This enhancement needs migration guide because of a breaking change. 79 | 80 | - If your config contains `overrides` property, `eslint` command with directory paths lints the files which are matched automatically. This may increase errors of your command.
81 | If you don't want to add file types to check, please use glob patterns instead of directory paths or `--ext .js` option. 82 | 83 | This enhancement, so it needs to update some documents. 84 | 85 | - In the description of `--ext` CLI option, it should say that your config file may add file types automatically. 86 | - In the description of `overrides` property, it should say that the `overrides[].files` property adds target files automatically. 87 | 88 | ## Drawbacks 89 | 90 | - This is a breaking change. 91 | - Implicit behavior may be confusing people. 92 | 93 | ## Backwards Compatibility Analysis 94 | 95 | In the following situation, `eslint` command increases errors. 96 | 97 | - Their configuration has `overrides` property (with `files` property which doesn't end with `*`). 98 | - Their `eslint` command is using directory paths without `--ext` option. 99 | 100 | I guess that the impact is limited because people use `--ext` option or glob patterns if they use configuration which affects files other than `*.js`. 101 | 102 | ## Alternatives 103 | 104 | - To add `extensions` property that behaves as same as `--ext` option. Explicit reduces confusion. However, plugins and shareable configs cannot add the `extensions` property without the breaking change that drops old ESLint support. 105 | 106 | ## Open Questions 107 | 108 | - 109 | 110 | ## Frequently Asked Questions 111 | 112 | - 113 | 114 | ## Related Discussions 115 | 116 | - [eslint/eslint#801](https://github.com/eslint/eslint/issues/801) - Configurable Extension Filter 117 | - [eslint/eslint#1674](https://github.com/eslint/eslint/issues/1674) - Allow setting file extensions in .eslintrc 118 | - [eslint/eslint#2274](https://github.com/eslint/eslint/issues/2274) - Configure file extensions in .eslintrc 119 | - [eslint/eslint#2419](https://github.com/eslint/eslint/issues/2419) - Allow configuration of default JS file types 120 | - [eslint/eslint#7324](https://github.com/eslint/eslint/issues/7324) - File extensions in .eslintrc 121 | - [eslint/eslint#8399](https://github.com/eslint/eslint/issues/8399) - Add .jsx to the default --ext extensions list 122 | - [eslint/eslint#10828](https://github.com/eslint/eslint/issues/10828) - Support specifying extensions in the config 123 | - [eslint/eslint#11223](https://github.com/eslint/eslint/issues/11223) - Add --ext to `eslintrc` or other config files 124 | -------------------------------------------------------------------------------- /designs/2021-init-command-eslint-cli/README.md: -------------------------------------------------------------------------------- 1 | - Repo: [eslint/eslint](https://github.com/eslint/eslint) 2 | - Start Date: 2020-06-29 3 | - RFC PR: https://github.com/eslint/rfcs/pull/79 4 | - Authors: Aniketh Saha ([anikethsaha](https://github.com/anikethsaha)) aladdin-add(weiran.zsd@outlook.com) 5 | 6 | # Move --init flag into a separate utility 7 | 8 | ## Summary 9 | 10 | - Remove the auto-config. 11 | - Move the `init` command from main repo ([eslint](https://github.com/eslint/eslint)) to a new repo named `@eslint/create-config`. 12 | 13 | ## Motivation 14 | 15 | Currently the whole `init` command is being shipped with the cli in the main repo. Though its not that much of size (roughly ~0.6MB for the [eslint/lib/init](https://github.com/eslint/eslint/tree/master/lib/init)), this command is not a type of command that we need everyday or everytime running eslint. It is mainly used when creating a new project or adding eslint to a project for the first time. So if we move this to a separate package that is meant to use in the command line, 16 | We will make use of tools like `npm` to simply run `npm init @eslint/config` or using `npx` to run `npx @eslint/create-config` or using `yarn` to run `yarn create @eslint/config` single time for a project instead of having it in the core project. 17 | 18 | ## Detailed Design 19 | 20 | 28 | 29 | The implementation is mainly migrating the code from main repo to `@eslint/create-config`. 30 | 31 | The approach would be following these steps 32 | 33 | ### 1. Remove eslint auto-config 34 | 35 | - Remove auto-config(`eslint/lib/init/autoconfig.js`), and its tests(`eslint/tests/lib/init/autoconfig.js`). 36 | - Remove dependency `progress`, as it's no longer used in production. 37 | 38 | ### 2. Move `eslint --init` related files to a separate repo 39 | 40 | - Move the `eslint/lib/init/*` to the new repo's `lib/*` directory 41 | - Add the following `dependencies` in `package.json` 42 | 43 | - `enquirer` 44 | - `semver` 45 | - `json-stable-stringify-without-jsonify` 46 | - `cross-spawn` 47 | - `debug` 48 | - `@eslint/eslintrc` 49 | - `eslint` (to be removed) 50 | - `espree` (to be removed) 51 | 52 | - for all those modules coming inside `../**/*`, it would be replaced using `eslint/**/*` 53 | - For `tests`, move the `tests/lib/init` to new repo's `tests/lib/` 54 | - Add the following `devDependencies` in `package.json` 55 | 56 | - `chai` 57 | - `sinon` 58 | - `js-yaml` 59 | - `proxyquire` 60 | - `shelljs` 61 | 62 | It was almost done: [aladdin-add/eslint-create](https://github.com/aladdin-add/eslint-create). 63 | I will make a PR once the official repo is created later. 64 | 65 | ### 3. Remove the usage of eslint & espree 66 | 67 | eslint was used: 68 | https://github.com/aladdin-add/eslint-create/blob/c27509cbbaea7c846fd9d7a373feece5254ac8d8/lib/config-file.js#L86 69 | 70 | It can be removed by using the local installed eslint, and switch to the new `ESLint` api. 71 | 72 | espree was used: 73 | https://github.com/aladdin-add/eslint-create/blob/c27509cbbaea7c846fd9d7a373feece5254ac8d8/lib/config-initializer.js#L161 74 | 75 | It can be removed after https://github.com/eslint/espree/issues/495 get landed. 76 | 77 | ### 4. Release the new package 78 | 79 | ### 5. Update eslint repo 80 | 81 | - Remove `eslint --init` related files. 82 | - the following dependencies can be removed in eslint repo: 83 | - enquirer 84 | - semver 85 | - Whenever `--init` command is being used, show a warning(e.g. "You can also run this command directly using 'npm init @eslint/config'") and run `npm init @eslint/config` using `child_process` of the native node modules. 86 | 87 | ## Documentation 88 | 89 | 93 | - [get-started](https://eslint.org/docs/user-guide/getting-started). 94 | - Documentation for `@eslint/create-config` will be created with proper usage and each prompt's details. In the main documentation, a link to `@eslint/create-config` will be given [here](https://github.com/eslint/eslint/blob/master/docs/user-guide/command-line-interface.md#--init) and basic usage and the package details will be documented. 95 | Also in the cli command options, [here](https://github.com/eslint/eslint/blob/master/docs/user-guide/command-line-interface.md#options), for `--init` we need to change the description. 96 | - A formal announcement in not needed, as it is not a breaking change. 97 | 98 | ## Drawbacks 99 | 100 | 110 | 111 | - This might increase the maintenance burden as this will add one more repo in the organization. 112 | - We may need to face challenges like re-directing of issues from `@eslint/create-config` repo to `eslint` and vice-versa. 113 | 114 | ## Backwards Compatibility Analysis 115 | 116 | 121 | 122 | - Users can use `eslint --init`, which is as the same as current. 123 | - Users can no longer use auto-config. 124 | 125 | ## Alternatives 126 | 127 | 133 | 134 | The current implementation in `eslint` repo is the alternative. No changes needed. 135 | 136 | ## Open Questions 137 | 138 | 148 | 149 | - Do we want to implement this as monorepo under `eslint` repo or a separate repo `@eslint/create-config` but github will make it as `create-config` or similar ? 150 | 151 | We decided not to go in the monorepo direction for this. 152 | -------------------------------------------------------------------------------- /designs/2019-allow-all-directives-in-line-comments/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-07-22 2 | - RFC PR: (leave this empty, to be filled in later) 3 | - Authors: Jordan Eldredge 4 | 5 | # Allow All Directives in Line Comments 6 | 7 | ## Summary 8 | 9 | ESLint currently only allows the following types of directives to be used inside of block comments (`/* Block Comment */`): 10 | 11 | * `exported` 12 | * `global(s)` 13 | * `eslint-(en|dis)able` 14 | * `eslint` 15 | 16 | Currently if a user adds one of these directives in a line comment (`// Line Comment`) the directive will be silently ignored. Which can be very confusing. 17 | 18 | I propose that we allow all directives to work in either type of comment. 19 | 20 | ## Motivation 21 | 22 | As a user of ESLint I occasionally wish to disable a rule, declare a valid global or add some other file level config. In doing so I often forget that these directives are only valid inside block level comments and add them as inline comments by mistake. When the comment fails to have its desired effect I consult the documentation to see what I did wrong. Did I remember the directive syntax or name incorrectly? On more than one occasion the problem has been that I used the wrong kind of comment. 23 | 24 | It would be nice if I didn't have to think about the comment type that I'm using. 25 | 26 | ## Detailed Design 27 | 28 | The function `getDirectiveComments` in [`linter.js`](https://github.com/eslint/eslint/blob/1fb362093a65b99456a11029967d9ee0c31fd697/lib/linter/linter.js#L263) currently does an `if (comment.type === "Block")` check before it looks for some types of directives. 29 | 30 | I believe we could simply remove that check. 31 | 32 | For `/* eslint-env */` directives which, by necessity, are parsed out of the file before an AST is avaliable, the regular expression in [linter.js](https://github.com/eslint/eslint/blob/fb08b7c9d28bc68864eb940e26df274059228b6a/lib/linter/linter.js#L406) would need to be updated to allow it to match line comments. 33 | 34 | ## Documentation 35 | 36 | We would need to update the [configuration](https://eslint.org/docs/user-guide/configuring#using-configuration-comments) documentation to remove the places where it states that some types of directives must use block comments. We would replace each of those comments with a note that "Before version _x.x_ this directive only worked in block comments" so that users using an older version of ESLint could figure out why their line comments were ignored. 37 | 38 | ## Drawbacks 39 | 40 | I don't see any drawbacks to this change. 41 | 42 | ## Backwards Compatibility Analysis 43 | 44 | While this change is backwards compatible in that it does not change any existing API contract, there is a possiblity that user's code bases will contain [accidental directives](#accidental-directives) (see below) which could potentially mean that upgrading to a version that contained this change would result in lint errors when it did not before. 45 | 46 | Therefore, we will consider this change a _breaking change_. 47 | 48 | ### Latent Directives 49 | 50 | Users may have added directives to their code using line comments and then never noticed that they had no effect. With this change, they will now begin functioning again. In some cases this may be welcome, since the user's original intention would finally be respected. In other cases the code may have changed since the user added the latent directive. In that case this change may cause an unwanted directive to be enabled. 51 | 52 | Anecdotally, I did an audit of a large swath of our code base and discovered only two directives which were being ignored due to their comment type. In both cases, enabling would be the correct behavior. 53 | 54 | ### Accidental Directives 55 | 56 | Users may also have written inline comments which were not intended as a directive, but parse as directives. I found one example in ESLint's own codebase: 57 | 58 | > `lineNumTokenBefore = 0; // global return at beginning of script` 59 | 60 | -- [newline-before-return.js:173](https://github.com/eslint/eslint/blob/02d7542cfd0c2e95c2222b1e9e38228f4c19df19/lib/rules/newline-before-return.js#L137) 61 | 62 | This would result in the following, somewhat confusing, error after upgrading to a version that contained this change: 63 | 64 | ``` 65 | /Users/jeldredge/projects/eslint/lib/rules/newline-before-return.js 66 | 137:51 error 'return' is defined but never used no-unused-vars 67 | 137:58 error 'at' is defined but never used no-unused-vars 68 | 137:61 error 'beginning' is defined but never used no-unused-vars 69 | 137:71 error 'of' is defined but never used no-unused-vars 70 | 137:74 error 'script' is defined but never used no-unused-vars 71 | 72 | ✖ 5 problems (5 errors, 0 warnings) 73 | ``` 74 | 75 | ## Alternatives 76 | 77 | An earlier revision of this RFC suggested reporting an error/warning when a directive that is only supported in a block comment was found in a line comment. See the following section for a discussion of why this may be a worth doing in addition to the changes detailed above. 78 | 79 | ## Optional Short Term Improvements 80 | 81 | Since code bases may contain line comments which were not intended as directives, but would be parsed as such after this change, (see [Accidental Directives](#accidental-directives) above) this change will be a breaking change and thus will need to wait for a major release. If the next major release is far off we could employ a short term fix of making line comment directives warnings which could be shipped in a minor release. 82 | 83 | This would have two benefits: 84 | 85 | 1. In the time between when the minor release ships and when the next major release ships, user would get explicit feedback when they accidentally write a line comment directive when ESLint is expecting a block comment directive rather than having it silently fail. 86 | 2. Accidental directives would be surfaced as errors in the minor version which means that those who adopt the minor release before the next major release, and resolved all new warnings would have a smooth upgrade experience. 87 | 88 | ### Implementation of Warnings 89 | 90 | If we decide to do the additional work of adding warnings in a minor version, here is how it could be implemented: 91 | 92 | The function `getDirectiveComments` in [`linter.js`](https://github.com/eslint/eslint/blob/1fb362093a65b99456a11029967d9ee0c31fd697/lib/linter/linter.js#L263) already has some examples of reporting problems with directive comments via the `createLintingProblem` function. 93 | 94 | Currently `getDirectiveComments` works by first handling `eslint-disable-(next-)line` directives, which are comment type agnostic, and then only looking for the other types of directives if the comment type is `Block`. 95 | 96 | Instead, after handling the `eslint-disable-(next-)line` directives, we could check to see if we are in an inline comment. If we are, we could add a problem with something like: 97 | 98 | ```JavaScript 99 | problems.push(createLintingProblem({ 100 | ruleId: null, 101 | message: `The ${match[1]} directive is only allowed in block comments.`, 102 | loc: comment.loc 103 | })); 104 | ``` 105 | 106 | ## Open Questions 107 | 108 | As far as I am aware, there are no open questions. 109 | 110 | ## Help Needed 111 | 112 | I expect that I could make the pull request myself without help. 113 | 114 | ## Related Discussions 115 | 116 | * [Warn when ESLint directives which expect to be used in block level comments are used in inline comments #12014](https://github.com/eslint/eslint/issues/12014) -------------------------------------------------------------------------------- /designs/2019-config-tester/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-06-14 2 | - RFC PR: https://github.com/eslint/rfcs/pull/27 3 | - Authors: Toru Nagashima <https://github.com/mysticatea> 4 | 5 | # Config Tester 6 | 7 | ## Summary 8 | 9 | Providing `ConfigTester` API that tests shareable configs and plugin's preset configs. 10 | 11 | ## Motivation 12 | 13 | Currently, we don't provide stuff to test shareable configs. This means the community doesn't have an easy way to check if their config is good or not. 14 | 15 | - Is the config structure valid? 16 | - Does every rule exist? 17 | - Does every rule have valid options? 18 | - Aren't there any deprecated rules? 19 | - Are there plugin settings of configured rules? 20 | - Will this config work after publish? 21 | - Does `package.json` have parsers, plugins, and extended configs? 22 | 23 | ## Detailed Design 24 | 25 | This RFC adds `ConfigTester` API to check configs. 26 | 27 | ```js 28 | const { ConfigTester } = require("eslint") 29 | 30 | // Instantiate the tester. 31 | const tester = new ConfigTester() 32 | const options = { 33 | ignoreDeprecatedRules: false, 34 | ignoreDisabledUnknownRules: false, 35 | ignoreMissingDependencies: false, 36 | ignoreRulesMissingFromConfig: false, 37 | } 38 | 39 | // Verify a shareable config (a path to the target file). 40 | tester.runOnConfigFile("index.js", options) 41 | tester.runOnConfigFile("es5.js", options) 42 | tester.runOnConfigFile("es2015.js", options) 43 | 44 | // Or verify plugin's preset configs (a config name in the plugin). 45 | tester.runOnPluginConfig("base", options) 46 | tester.runOnPluginConfig("recommended", options) 47 | tester.runOnPluginConfig("opinionated", options) 48 | ``` 49 | 50 | ### § `ConfigTester(projectRoot)` constructor 51 | 52 | Instantiate a new `ConfigTester` instance. 53 | 54 | #### Parameters 55 | 56 | The constructor has an optional parameter. 57 | 58 | Name | Description 59 | :----|:----------- 60 | `projectRoot` | Default is `process.cwd()`. The path to the project root. The root should contain `package.json`. 61 | 62 | #### Behavior 63 | 64 | The tester reads `` `${projectRoot}/package.json` `` to use in `run()` method. 65 | 66 |
67 | 🔗PoC: lib/config-tester/config-tester.js#L60-L66 68 |
69 | 70 | ### § `tester.runOnConfigFile(filePath, options)` method / `tester.runOnPluginConfig(configName, options)` method 71 | 72 | Validates a config data. 73 | 74 | #### Parameters 75 | 76 | Name | Description 77 | :----|:----------- 78 | `filePath` | Required. This is a path to a file (relative from `projectRoot`). 79 | `configName` | Required. This is a config name of the plugin. If it cannot load the entry file (`main` field in `${projectRoot}/package.json` or `${projectRoot}/index.js`), it throws `MODULE_NOT_FOUND_ERROR`. 80 | `options.ignoreDeprecatedRules` | Default is `false`. If `true` then the tester ignores deprecated rules. 81 | `options.ignoreDisabledUnknownRules` | Default is `false`. If `true` then the tester ignores unknown rules if the rule was configured as `0` (`"off"`). 82 | `options.ignoreRulesMissingFromConfig` | Default is `false`. If `true` then the tester ignores missing rules. The missing rules mean the rules that ESLint or a plugin defined but not configured. 83 | `options.ignoreMissingDependencies` | Default is `false`. If `true` then the tester ignores wrong dependency definition (`dependencies`/`peerDependencies`). 84 | 85 | #### Behavior 86 | 87 | Similarly to `RuleTester`, `ConfigTester` defines tests by `describe` and `it` global variables. Then it does: 88 | 89 | 1. Validate the config object has the valid scheme with `validateConfigSchema()`. 90 |
91 | 🔗PoC: lib/config-tester/config-tester.js#L244-L248 92 |
93 | 1. Validate the config content with `validateConfigArray()`. 94 |
95 | 🔗PoC: lib/config-tester/config-tester.js#L250-L265 96 |
97 | 1. Report non-existence rules. 98 | - Because `validateConfigArray(configArray)` ignores non-existence rules. 99 | - Configured plugin's rules are in `configArray.pluginRules`. 100 | - If `ignoreDisabledUnknownRules` option was `true` and non-existence rule's severity was `"off"`, the tester ignores it. 101 |
102 | 🔗PoC: lib/config-tester/config-tester.js#L267-L299 103 |
104 | 1. Report deprecated rules. 105 | - If `ignoreDeprecatedRules` option was `true`, the tester skips this step. 106 | - If the rule severity was `"off"`, the tester ignores it. 107 | - Check `meta.deprecated` in both core rules and `configArray.pluginRules`. 108 |
109 | 🔗PoC: lib/config-tester/config-tester.js#L301-L338 110 |
111 | 1. Check whether the config configures all rules. 112 | - If `ignoreRulesMissingFromConfig` option was `true`, the tester skips this step. 113 | - This step lets people know about new rules. 114 |
115 | 🔗PoC: lib/config-tester/config-tester.js#L340-L363 116 |
117 | 1. Check whether `${options.projectRoot}/package.json` contains the configured parser, plugins, and shareable configs. 118 | - If `ignoreMissingDependencies` option was `true`, the tester skips this step. 119 | - If `parser` or `extends` were a file path except `node_modules/**`, the file should be published; check `.npmignore` and `package.json`'s `lib` field. 120 | - If `parser` or `extends` were a package or a file path to `node_modules/**`, the package should be in `dependencies` or `peerDependencies`. 121 | - `plugins` should be in `peerDependencies` or `name`. 122 |
123 | 🔗PoC: lib/config-tester/config-tester.js#L365-L420 124 |
125 | 126 | ## Documentation 127 | 128 | - [Node.js API](https://eslint.org/docs/developer-guide/nodejs-api) page should describe the new `ConfigTester` API. 129 | - [Creating a Shareable Config](https://eslint.org/docs/developer-guide/shareable-configs#creating-a-shareable-config) section should note the tester. 130 | - [Configs in Plugins](https://eslint.org/docs/developer-guide/working-with-plugins#configs-in-plugins) section should note the tester. 131 | 132 | ## Drawbacks 133 | 134 | - If people can write the config with no mistakes, this tester may not be needed. 135 | 136 | ## Backwards Compatibility Analysis 137 | 138 | - This is not a breaking change. It just adds a new API. 139 | 140 | ## Alternatives 141 | 142 | - https://www.npmjs.com/package/eslint-find-rules - we can check missing rules and deprecated rules with this package. 143 | 144 | ## Related Discussions 145 | 146 | - https://github.com/eslint/eslint/issues/10289 147 | -------------------------------------------------------------------------------- /designs/2022-suggestion-parse-errors/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2022-12-10 3 | - RFC PR: 4 | - Authors: [bmish](https://github.com/bmish) 5 | 6 | # Check for parsing errors in suggestion fixes 7 | 8 | ## Summary 9 | 10 | 11 | 12 | Check for parsing errors in [suggestion fixes](https://eslint.org/docs/latest/developer-guide/working-with-rules#providing-suggestions) when running rule tests, the same way we do with rule [autofix](https://eslint.org/docs/latest/developer-guide/working-with-rules#applying-fixes) output. 13 | 14 | ## Motivation 15 | 16 | 18 | 19 | Over time, `RuleTester` has become stricter about verifying the validity of test cases and rule behavior, including in the recent, related [RFC-84: Stricter validation of rule tests](../2021-stricter-rule-test-validation/README.md). 20 | 21 | One likely oversight and gap in our validation is that we don't currently check for parsing/syntax errors in suggestion fixes. This is a problem because a user applying an invalid suggestion will end up with broken code. This is confusing and a poor user experience. 22 | 23 | ## Detailed Design 24 | 25 | 33 | 34 | We should apply the same validation to suggestions as we do to autofixes, and throw an error if a suggestion produces invalid code. 35 | 36 | In the rule testers: 37 | 38 | - lib/rule-tester/flat-rule-tester.js 39 | - lib/rule-tester/rule-tester.js 40 | 41 | We will follow the same pattern that is used for validating autofix output. When encountering a test case that is testing suggestion output, after the existing call to `SourceCodeFixer.applyFixes()`, we need to call `linter.verify()` on the code with the applied suggestion, and then assert that there are no fatal errors. 42 | 43 | Note that as a result of [RFC-84: Stricter validation of rule tests](../2021-stricter-rule-test-validation/README.md), test cases are required to test all suggestions, so we know all suggestions will be covered by our new check. 44 | 45 | In the tests for the rule testers: 46 | 47 | - tests/lib/rule-tester/flat-rule-tester.js 48 | - tests/lib/rule-tester/rule-tester.js 49 | 50 | We need to add a test case with an invalid suggestion, and assert that it throws. 51 | 52 | Draft implementation: 53 | 54 | ## Documentation 55 | 56 | 60 | 61 | This doesn't need to be documented as its one of many checks in the rule tester for invalid rule conditions or test cases. Users should intuitively expect that parsing errors will cause failures. It can simply be called out in the migration guide for the major version it's implemented in. 62 | 63 | ## Drawbacks 64 | 65 | 75 | 76 | 1. There may be a slight performance overhead to checking for parsing errors when running tests. This is likely to be negligible and worthwhile to catch real bugs that will impact users. 77 | 2. It's theoretically possible that a rule author intended to provide a broken suggestion, and this RFC would prevent that. It is true that suggestions are not intended to be held to the same standards are autofixes. Suggestions can be used to provide incomplete or unsafe fixes that change code behavior, which is why a user must choose to apply a suggestion manually. However, I don't believe suggestions should be allowed to provide syntactically-invalid/unparsable fixes. Producing broken code puts an unnecessary burden on the user to figure out how to un-break their code, and prevents ESLint and other tools from running on the code in the meantime. It should be possible to turn any desired suggestion into valid code/syntax, even if it's still incomplete or not production ready. 78 | 79 | ## Backwards Compatibility Analysis 80 | 81 | 86 | 87 | Plugin authors whose rules produce invalid suggestions will experience a breaking change when running tests due to the new test failure. This is desirable so that the plugin author is forced to fix the issue and release a patch. 88 | 89 | ## Alternatives 90 | 91 | 97 | 98 | 1. Do nothing -- continue to allow invalid suggestions. But there are minimal [drawbacks](#drawbacks) to checking for invalid suggestions and real-world benefits to users. 99 | 100 | ## Open Questions 101 | 102 | 112 | 113 | 1. Should we check for parsing errors when applying suggestions in core too (not just in rule tester)? 114 | 115 | Pros: 116 | 117 | - Showing an exception to end-users about the parsing error could be more clear than simply allowing the suggestion to produce broken code for them, and could encourage the end-user to file a ticket to have the issue fixed with the plugin author. 118 | 119 | Cons: 120 | 121 | - However, this additional assertion may be of limited value, as the vast majority of invalid suggestions would have already been caught by rule tests (as long as the rule actually has tests). 122 | - Autofixes and suggestions should both be held to the same validation standards, i.e. we can validate them both in rule tester but not in core. 123 | - Validating suggestions could cause a performance hit for end-users. 124 | 125 | In discussion, we decided not to validate suggestions in core. 126 | 127 | ## Help Needed 128 | 129 | 135 | 136 | I am open to implementing this. 137 | 138 | ## Frequently Asked Questions 139 | 140 | 147 | 148 | ## Related Discussions 149 | 150 | 156 | 157 | - - the issue triggering this RFC 158 | - - original suggestions RFC 159 | -------------------------------------------------------------------------------- /designs/2023-only-run-reporting-rules/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2023-01-16 3 | - RFC PR: 4 | - Authors: Maddy Miller 5 | 6 | # Only run reporting lint rules 7 | 8 | ## Summary 9 | 10 | Currently, ESLint will run all rules that are not marked as `off` in the configuration. 11 | This RFC proposes adding a way to configure which rules are actually run, to reduce linting 12 | time and better match the reporting outcome. Currently, when a rule is marked as `warn`, 13 | ESLint will still run the rule but not report the results when run under `--quiet`. The 14 | intended outcome of this RFC is to allow users to not run these rules when unnecessary. 15 | 16 | ## Motivation 17 | 18 | A common use-case of the `warn` level is to report errors to the developer in their IDE, 19 | but to completely ignore it when running ESLint on the command line via the `--quiet` flag. 20 | When running with many rules set to the `warn` level, this can cause a significant amount 21 | of overhead on ESLint runtime. On an example large codebase with 154988 lines of TypeScript 22 | code, I found that by disabling all rules set to warn, I was able to reduce ESLint runtime 23 | from 4 minutes and 39 seconds to just 22 seconds. As the `warn` rules are entirely ignored 24 | in this situation, this is a substantial amount of wasted time and resources that could be 25 | avoided. 26 | 27 | ## Detailed Design 28 | 29 | The proposed implementation is to modify the `--quiet` flag so that ESLint will skip 30 | running any rules that are set to the `warn` level. 31 | 32 | From an API perspective, this would be implemented by a filter function that filters down to 33 | which rules should be run. The function would take `(ruleId, severity)` and return true to 34 | include a rule or false to exclude it. For simplicity, this function should not be 35 | given rules marked as `off`, as if this function handled existing behavior then users of the 36 | API would have to mimic that when attempting to extend it. 37 | 38 | In `cli.js`'s `translateOptions` function, the `ruleFilter` option should be assigned to 39 | a function that filters to rules with a `severity` of 2 (error) when the `--quiet` flag is applied, 40 | otherwise always returns true. In `eslint/flat-eslint.js`, the `ruleFilter` should be taken from 41 | the `eslintOptions` object, and passed down to the `linter.verifyAndFix` call. 42 | 43 | Within `linter.js`, the API should be added to `VerifyOptions`, and will be passed down into and 44 | utilized within the `runRules` function during the `configuredRules` loop, after the check 45 | for disabled rules and the rule existing. The `ruleId`, and `severity` should be passed into the 46 | predicate function as an object. `normalizeVerifyOptions` should verify that the `ruleFilter` 47 | option is a function, and replace it with an always-true function if not. `processOptions` in 48 | `eslint-helpers.js` should also perform a validation check that the `ruleFilter` option is a function. 49 | 50 | The new `ruleFilter` function when implemented would look like this, using the `--quiet` flag 51 | rules outlined in this RFC as an example: 52 | 53 | ```typescript 54 | linter.verifyAndFix(text, configs, { 55 | ruleFilter: ({ ruleId: string, severity: number }) => { 56 | return severity === 2; 57 | }, 58 | }); 59 | ``` 60 | 61 | The function acts as a filter on the rules to enable, where removal from the list disables a rule. 62 | This function would return true for all rules which have a severity of 2 (error), effectively filtering out 63 | all other rules. 64 | 65 | The check for unused `eslint-disable` directives (`--report-unused-disable-directives`) 66 | should continue to mark `warn` rules as used, even when running with `--quiet`. As the 67 | rules are not actually run, an assumption would have to be made that all directives 68 | on rules present only in the un-filtered list are used when in this mode. This is a reasonable 69 | assumption, as the user likely does not expect `warn` flags to be touched at all in this mode. 70 | This would also apply to blanket `eslint-disable` directives that disable all rules, which 71 | should always be assumed to be used when the filter function has not changed the length of the list. 72 | 73 | In cases of conflicting flags such as the `--max-warnings` flag, this altered `--quiet` flag 74 | behavior should be disabled while it is in use. This is to ensure that the `--max-warnings` 75 | flag continues to work as expected. The filter API should not be set, and existing 76 | behavior of filtering the output should be used. This altered behavior should be documented 77 | to clarify that it causes warnings to be run despite the `--quiet` flag. 78 | 79 | ## Documentation 80 | 81 | Both the behaviour modification of impacted flags and the API would make sense to document. 82 | As they are relatively simple additions, they would be documented inline with the rest 83 | of the CLI and API documentation. Due to the potentially major performance improvements for 84 | many setups, I feel mentioning it in the release blog post, alongside the potential benefits, 85 | would be a good idea to spread awareness. 86 | 87 | ## Drawbacks 88 | 89 | This change modifies a command line flag, as well as a new API method. This adds further 90 | maintenance burden. However, the implementation is relatively simple, and the benefits 91 | are significant. 92 | 93 | As this flag has many interactions with other systems such as `--max-warnings`, further 94 | maintenance overhead is introduced by having to ensure it behaves correctly between 95 | the different flags. This would require updating documentation across all flags and relevant 96 | settings. 97 | 98 | ## Backwards Compatibility Analysis 99 | 100 | This is a breaking change as it alters the behaviour of the `--quiet` flag. 101 | While the alterations to the quiet flag should not affect the actual outcome of the command, 102 | as cases where it would are covered by this RFC, it is still worth noting as the behaviour 103 | is changing. 104 | 105 | For the case of rules with side effects, such as the `react/jsx-uses-vars` rule, these side 106 | effects will no longer run in quiet mode when set to `warn`. Due to this, users will need to 107 | update their eslint configuration to ensure that any rules with side effects are set to `error`. 108 | 109 | ## Alternatives 110 | 111 | ### Implement this via a separate `--skip-warnings` flag 112 | 113 | This alternative would be to implement this via a separate `--skip-warnings` flag, rather 114 | than into the `--quiet` flag. The same API changes would still be required. The benefit of 115 | this alternative is that it doesn't break behavior of the `--quiet` flag, but it also can 116 | cause confusion with a new flag. 117 | 118 | ### Expose more power via the CLI flag 119 | 120 | Given the API takes a filter, another alternative would be to also expose this power 121 | to the CLI. This would allow users to specify their own filter function, which would 122 | allow for more complex filtering. The downside to this change is that it's vastly more 123 | complex for both the end user and to implement. As the API side of this would be done 124 | anyway, this could be implemented alongside the current proposal in the future if necessary. 125 | However, I feel the simple option as outlined in this proposal that covers the majority 126 | use-case is ideal to keep as a flag either way. 127 | 128 | ## Open Questions 129 | 130 | ### Are there any other considerations I've missed 131 | 132 | In the proposal I've outlined two checks that require warnings to run, however I'm not 133 | familiar with all internal and external features of ESLint, so might have missed some other 134 | checks that we need to ensure still function correctly with this flag. 135 | 136 | ## Help Needed 137 | 138 | I'm not entirely familiar with the ESLint internals, but would be willing to at least 139 | partially implement this if given guidance on the specific areas of code that would need 140 | to be changed. 141 | 142 | ## Frequently Asked Questions 143 | 144 | 151 | 152 | ## Related Discussions 153 | 154 | https://github.com/eslint/eslint/issues/16450 155 | -------------------------------------------------------------------------------- /designs/2021-break-on-parsing-errors/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/eslint 2 | - Start Date: 2021/1/12 3 | - RFC PR: https://github.com/eslint/rfcs/pull/75 4 | - Authors: [A-Katopodis](https://github.com/A-Katopodis) 5 | 6 | # (Break on parsing errors) 7 | 8 | ## Summary 9 | 10 | The suggested change is for ESLint tp support an argument that will make the CLI exit with code 2 if any fatal errors are reported. The option will be an opt-in boolean argument called `--exit-on-fatal-error`. 11 | 12 | ## Motivation 13 | 14 | We met with a couple of cases where we assumed a succesfull run of ESLint in CI enviroments. When ESLint wouldn't be able to read the tsconfig.json, or had a wrongly configured source type the error would be a `fatal` one but the exit code would be `1`. There was no distiction between a run with no fatal errors and with fatal errors. 15 | 16 | More specifically the tsconfig.json invalid read is a error from `@typescript-eslint parser`, the parser correctly indicates a fatal parsing failure like it should so it falls under the same category as the incorrectly configured `sourceType` as in both cases we can't actually run any rules in the file. 17 | 18 | According to the eslint docs about exit codes: 19 | 20 | - 0: Linting was successful and there are no linting errors. If the --max-warnings flag is set to n, the number of linting warnings is at most n. 21 | - 1: Linting was successful and there is at least one linting error, or there are more linting warnings than allowed by the --max-warnings option. 22 | - 2: Linting was unsuccessful due to a configuration problem or an internal error. 23 | 24 | Being able to exit with code `2` instead of `1` it will allow for some CI pipelines to better understand the results and react differently if ESLint reports any `fatal` errors. For example, an Azure DevOps build task that is responsible for running ESLint and output a SARIF would fail on exit code `2` but not 1 indicating there is a configuration and not all of the files where scanned properly for rules. 25 | 26 | ## Detailed Design 27 | 28 | Design Summary: 29 | 30 | 1. Add a `exit-on-fatal-error` option. 31 | 2. Gather and report the fatal messages from `cli-engine`. 32 | 3. Return exit code `2` in the case of any fatal errors on `cli` 33 | 34 | A command example: 35 | 36 | `eslint **.js ----exit-on-fatal-error` 37 | 38 | With this argument if there is at least one fatal error in the results ESLint produces it will exit with code 2. 39 | 40 | ## Add a `exit-on-fatal-error` option. 41 | We would require the option in regard to other ones as well. 42 | ``` 43 | // inside of eslint.js 44 | .. 45 | .. 46 | * @property {number} fatalErrorCount Number of fatal errors for the result. 47 | .. 48 | .. 49 | ``` 50 | ``` 51 | // inside of lib/option.js 52 | .. 53 | .. 54 | { 55 | option: "exit-on-fatal-error", 56 | type: "Boolean", 57 | default: "false", 58 | description: "Trigger exit code 2 on any fatal errors." 59 | } 60 | .. 61 | .. 62 | ``` 63 | ## Gather and report the fatal messages. 64 | 65 | In order for ESLint to be able to make a choice based on the fact that a `fatal` error has been found or not we must first retrieve this information. Altough we will not be needing the count of the fatal errors using count instead of a boolean and offer more flexibility than a Boolean parameter, keeps the codebase consistent. 66 | 67 | The changes for that are on `cli-engine.js`: 68 | ``` 69 | function calculateStatsPerFile(messages) { 70 | return messages.reduce((stat, message) => { 71 | if (message.fatal || message.severity === 2) { 72 | stat.errorCount++; 73 | if (message.fatal) { 74 | stat.fatalErrorCount++; 75 | } 76 | if (message.fix) { 77 | stat.fixableErrorCount++; 78 | } 79 | } else { 80 | stat.warningCount++; 81 | if (message.fix) { 82 | stat.fixableWarningCount++; 83 | } 84 | } 85 | return stat; 86 | }, { 87 | errorCount: 0, 88 | fatalErrorCount: 0, 89 | warningCount: 0, 90 | fixableErrorCount: 0, 91 | fixableWarningCount: 0 92 | }); 93 | } 94 | ``` 95 | ``` 96 | function calculateStatsPerRun(results) { 97 | return results.reduce((stat, result) => { 98 | stat.errorCount += result.errorCount; 99 | stat.fatalErrorCount += result.fatalErrorCount; 100 | stat.warningCount += result.warningCount; 101 | stat.fixableErrorCount += result.fixableErrorCount; 102 | stat.fixableWarningCount += result.fixableWarningCount; 103 | return stat; 104 | }, { 105 | errorCount: 0, 106 | fatalErrorCount: 0, 107 | warningCount: 0, 108 | fixableErrorCount: 0, 109 | fixableWarningCount: 0 110 | }); 111 | } 112 | ``` 113 | 114 | ## Return exit code `2` in the case of any fatal errors on `cli` 115 | 116 | Now we can retreve those fatal errors from `cli.js` and act accordingly: 117 | 118 | First change the function that retrieves those errors: 119 | ``` 120 | function countErrors(results) { 121 | let errorCount = 0; 122 | let fatalErrorCount = 0; 123 | let warningCount = 0; 124 | 125 | for (const result of results) { 126 | errorCount += result.errorCount; 127 | fatalErrorCount += result.fatalErrorCount; 128 | warningCount += result.warningCount; 129 | } 130 | 131 | return { errorCount, warningCount }; 132 | return { errorCount, fatalErrorCount, warningCount }; 133 | } 134 | ``` 135 | 136 | Now with the new information this method gives us we can use it: 137 | ``` 138 | // on the execute method 139 | if (await printResults(engine, results, options.format, options.outputFile)) { 140 | const { errorCount, warningCount } = countErrors(results); 141 | const { errorCount, fatalErrorCount, warningCount } = countErrors(results); 142 | const tooManyWarnings = 143 | options.maxWarnings >= 0 && warningCount > options.maxWarnings; 144 | const fatalErrorExists = 145 | options.fatalParseError && fatalErrorCount > 0; 146 | 147 | if (!errorCount && tooManyWarnings) { 148 | log.error( 149 | "ESLint found too many warnings (maximum: %s).", 150 | options.maxWarnings 151 | ); 152 | } 153 | 154 | if(fatalErrorExists){ 155 | return 2; 156 | } 157 | 158 | return (errorCount || tooManyWarnings) ? 1 : 0; 159 | } 160 | return 2; 161 | ``` 162 | 163 | ## Documentation 164 | The section of the documentation requiring the change is the Command Line Interface: 165 | 166 | [Command Line Interface](https://eslint.org/docs/user-guide/command-line-interface) 167 | 168 | 169 | ## Drawbacks 170 | Some users who may want to enable this new feature may find themselves needing to reconfigure their process. It can change some CI pipelines if used. But since its optional the impact is minimal and it may allow them to discover issues. 171 | 172 | 173 | ## Backwards Compatibility Analysis 174 | There are no expected backward compatibility issues. The parameter will be disabled by default and only users who will use this new parameter will experience any kind of change. 175 | 176 | 177 | ## Open Questions 178 | 179 | ### Question: 180 | Do we want to still report all errors or only failed linting errors when `break-on-lint-error` is passed? 181 | 182 | ### Answer: 183 | After discussions we will be reporting all errors. 184 | 185 | ---- 186 | ### Question: 187 | Assume that for some files ESLint successfully lints them and reports a rule but for some others it doesnt. 188 | If ESLint finds a single file that has a parsing error should it report just that file or every rule as 189 | well? 190 | ### Answer: 191 | The choice is that we will be returing all of the found linting errors as discussed in these [comments](https://github.com/eslint/rfcs/pull/76#discussion_r572924056) 192 | 193 | ## Alternatives 194 | There 2 alternatives which we may want to consider, they were already discussed on the related issue: 195 | 196 | ## Use a new exit code 3 197 | The proposal remains the same but with exit code `3` instead of `2` 198 | 199 | ## Max Fatal Errors 200 | Another tweak to the proposal would be for the argument to be an integer similar to `--max-warnings`. Instead of reporting a different exit code than `1` we would 201 | 202 | ## Related Discussions 203 | https://github.com/eslint/eslint/issues/13711 204 | -------------------------------------------------------------------------------- /designs/2020-es-module-support/README.md: -------------------------------------------------------------------------------- 1 | - Repo: eslint/espree 2 | - Start Date: 2020-12-13 3 | - RFC PR: https://github.com/eslint/rfcs/pull/72 4 | - Authors: Mike Reinstein (https://github.com/mreinstein) 5 | 6 | # Adding es module support 7 | 8 | ## Summary 9 | 10 | Provide an ecmascript module for espree. 11 | 12 | 13 | ## Motivation 14 | 15 | Historically there have been a number of competing module standards: commonjs, requireJs, iife wrapped script tags, etc. 16 | 17 | This has contributed to a very complicated tooling scenario for node/npm/javascript based projects in general: 18 | * every module has it's own unique build system, with no consistency across modules. 19 | * projects are packed with complex configurations, much of which is plumbing related to packaging/bundling. 20 | 21 | Over time, browsers have adopted the ecma module standard. Today, support is pretty good: 22 | https://caniuse.com/es6-module 23 | 24 | Node also added support in v12.17.1 and up, and has officially marked the API stable: 25 | https://nodejs.org/dist/latest-v15.x/docs/api/esm.html#esm_modules_ecmascript_modules 26 | 27 | 28 | By adopting this new standard, we can achieve a few things: 29 | 30 | * eventual simplification of espree's build process by eliminating the need for multiple module formats 31 | * make it easier to directly importing espree in browser environments, deno, etc. Skypack is a CDN that already enables this, but they have internal logic that looks at every package in npm and tries to build an es module. https://www.skypack.dev/ 32 | 33 | As more projects adopt this standardized module format, the hope is a lot of this "connective glue" will fall away, leaving us with leaner modules and less build tooling across our stack. 34 | 35 | 36 | ## Detailed Design 37 | 38 | ### Nomenclature 39 | 40 | * `ESM` ecmascript module. The standardized module format for javascript 41 | * `CJS` commonjs. Node's historical module format (i.e., `module.exports = ...`, `const a = require('foo')`) 42 | * `UMD` universal module definition. A legacy format for specifying javascript code as a module in a way that tries to guarantee compatibility with many loader formats including requireJS, commonjs, and global script tags. 43 | * `IIFE` immediately invoked function expressions. A legacy strategy for encapsulating javascript into a module that won't leak global variables into the execution environment. It is still the primary way of packaging global script tags for inclusion in a web page. `UMD` is usually wrapped in an `IIFE` 44 | * `CDN` content delivery network. can be thought of as a set of servers that host static content all around the globe to deliver assets quickly and at scale. 45 | 46 | 47 | ### build process 48 | 49 | Today, espree is written in commonjs (CJS) format, and a universal module definition (UMD) build is created too. 50 | 51 | 52 | today's build process: 53 | ``` 54 | ┌-------------------┐ ┌-----------------┐ 55 | │ │ │ │ package.json: 56 | │ espree.js | │ build/espree.js │ 57 | │ (CJS entry point) ├──BUILD_STEP──▶│ (UMD bundle) │ CJS ---▶ "main": "espree.js", 58 | │ │ │ │ 59 | └-------------------┘ └-----------------┘ 60 | ``` 61 | 62 | 63 | The strategy that probably makes the most sense in this initial work is to do what is known as a "dual package" solution, where 64 | espree provides an ESM, and a CJS module. 65 | 66 | Providing a dual package shouldn't affect any existing espree users, but provies an ESM option for users that want it. 67 | 68 | 69 | proposed build process in this RFC: 70 | ``` 71 | ┌-------------------┐ 72 | │ │ 73 | │ dist/espree.cjs │ 74 | │ (CJS entry point) │ package.json: 75 | ┌-------------------┐ │ │ 76 | │ │ └--▲----------------┘ CJS ---▶ "main": "dist/espree.cjs", 77 | │ espree.js │ │ "exports": { 78 | │ (ESM entry point) ├───BUILD_STEP───┘ ESM ---▶ "import": "espree.js", 79 | │ │ CJS ---▶ "require": "./dist/espree.cjs" 80 | └-------------------┘ }, 81 | "type": "module" 82 | ``` 83 | 84 | browserify is specifically oriented around commonjs as the input format, so I also propose replacing it with rollup, which understands and expects ESM as it's input format. 85 | 86 | `UMD` is not part of the formal package interface and will be dropped altogether. 87 | 88 | 89 | ## Documentation 90 | 91 | The changes should be described in the migration guide for whichever major version of espree this goes into (currently considering the upcoming 8.x line.) 92 | 93 | Adding an `exports` field to `package.json` will break the existing API, it makes sense to formally announce this via blog post. 94 | 95 | 96 | ## Drawbacks 97 | 98 | The javascript build/tooling ecosystem is already monstrously complex, and this change adds another output format, which further complicates things (compare the 2 graphs above to see this additional complexity visualized.) 99 | 100 | I do believe this is a temporary scenario; as time goes on, the UMD and CJS entry points could be dropped altogether, along with the build step. But that will take months, maybe even years depending on how comfortable the community is with this change and how widely adopted the ESM format becomes. 101 | 102 | 103 | ## Backwards Compatibility Analysis 104 | 105 | The dual package approach _should_ not break espree for anyone currently using espree. 106 | 107 | 108 | ## Alternatives 109 | 110 | Another option is to just drop CJS, UMD and the build system altogether, provide an ESM only implementation, 111 | and make this a part of a semver-major version bump. (e.g., espree@8 is ESM only.) 112 | 113 | This would essentially eliminate the build step and make things very simple, but it has a big downside: 114 | * users that don't support ESM only projects would be stuck on `espree <= 7.x` forever (or at least until they added the ability to use ESM in their own stuff.) 115 | 116 | 117 | ## Open Questions 118 | 119 | None yet. 120 | 121 | 122 | ## Help Needed 123 | 124 | None yet. 125 | 126 | 127 | ## Frequently Asked Questions 128 | 129 | > what is this "dual package" stuff? 130 | 131 | It's a proposal by the node community on how a module may go about adopting ESM without totally breaking CJS for their users. https://nodejs.org/api/packages.html#packages_writing_dual_packages_while_avoiding_or_minimizing_hazards 132 | 133 | 134 | > are any other well known modules using this approach? 135 | 136 | acorn is producing a dual module, and has been the inspiration for my own work around the forthcoming espree PR https://github.com/acornjs/acorn/blob/master/acorn/package.json#L5-L11 137 | 138 | 139 | > does this mean local development now requires a build step? 140 | 141 | no. Tests should be written to run against the ESM source in `lib/`. The pre-release tests should be run against the CJS bundle as part of the pre-publish step. 142 | 143 | 144 | > how would one import espree now that it's providing an esm interface? 145 | 146 | There will be named exports. i.e., 147 | 148 | ```javascript 149 | import { parse, tokenize /*, ... */ } from 'espree'; 150 | ``` 151 | 152 | 153 | > npm modules reference each other via commonjs, and the browser's loader expects URLs, so why are we concerned with making npm modules work in a browser? 154 | 155 | that's true, you can't simply do `import espree from 'https://github/eslint/espree.js'` naively because it's referencing other npm modules in it, such as `acorn`. 156 | 157 | However there are some CDNs which will transform npm modules to refer to URLs. For example, this works today: 158 | 159 | ```javascript 160 | import espree from 'https://cdn.skypack.dev/espree' 161 | ``` 162 | 163 | By making espree a standard ESM it reduces the amount of transforms that need to be run on it to make it usable. 164 | 165 | It's also possible that in the semi-near future, node may consider offering URL loaders. Deno is already doing this. 166 | 167 | 168 | ## Related Discussions 169 | 170 | - [1] The discussion genesis https://github.com/eslint/espree/issues/457 171 | -------------------------------------------------------------------------------- /designs/2019-expose-rules-to-formatters/readme.MD: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-01-16 2 | - RFC PR: https://github.com/eslint/rfcs/pull/10 3 | - Authors: Chris Meyer (@EasyRhinoMSFT) 4 | 5 | # Providing Rule Metadata to Formatters 6 | 7 | ## Summary 8 | 9 | This proposal describes a design enhancement that provides formatters with details about the rules that have been executed by ESLint. 10 | 11 | ## Motivation 12 | 13 | Currently, formatters only see the ID of each rule for which a violation was identified, plus an instance-specific description, as properties on each result object. Formatters are not able to access useful rule metadata, such as category, description, and help URL. Formatters are also not aware of the full set of rules that were run, information that may be useful in some cases. 14 | 15 | ## Detailed Design 16 | 17 | Design Summary 18 | 1. In `cli.js::printResults`, obtain the rules map from the `Engine` object. 19 | 2. Add a second argument to the formatter's exported interface function. The value should be an object with a `rulesMeta` property that is a map with the rule name as the key and the `rule.meta` object as the value. See the "Command Line Interface (cli.js) Changes" section below for implementation. 20 | 21 | We should use a container object as the argument, with a ruleId/rule.meta map as a property, in order to accommodate potential future expansions of the data we pass to formatters. This suggestion was previously made in the discussion of issue [#9841](https://github.com/eslint/eslint/issues/9841). 22 | 23 | ### Command Line Interface (cli.js) Changes 24 | The implementation of this feature is very simple and straightfoward. The code location that invokes the formatter's exported interface function already has access to the API it should use to obtain the list of all executed rules. The call to `Engine.getRules` must be made in the try block because `engine` may be null during unit testing. 25 | 26 | ```js 27 | function printResults(engine, results, format, outputFile) { 28 | let formatter; 29 | let rules; 30 | 31 | try { 32 | formatter = engine.getFormatter(format); 33 | rules = engine.getRules(); 34 | } catch (e) { 35 | log.error(e.message); 36 | return false; 37 | } 38 | 39 | const rulesMeta = {}; 40 | rules.forEach(function(rule, ruleId) { 41 | rulesMeta[ruleId] = rule.meta; 42 | }); 43 | const output = formatter(results, { rulesMeta: rulesMeta }); 44 | ... 45 | } 46 | ``` 47 | 48 | ### Formatter Changes 49 | 50 | Formatters that implement the exported interface function would no changes. Future versions can make use of the rules data by adding the new argument to the exported interface function definition. This argument cannot be added unless it is used, as this will trip the JavaScript validation rule 'no-unused-vars.' 51 | 52 | A formatter that assigns a function reference to the exported interface function could exhibit unexpected behavior depending on the signature of the referenced function. For example, since this change's second argument is a complex object, a referenced function that expects a Number as its second argument could cause an exception. 53 | 54 | Currently the `html` formatter creates incorrect links rooted at the eslint.org domain for rules from plugins. We should fix this issue by using the meta.docs.url property that will become available with this change. 55 | 56 | The `json` formatter also requires attention. It simply stringifies the `results` object, and would therefore provide incomplete data by ignoring the new `data` argument. To avoid a breaking change to the existing `json` formatter, we should a new built-in formatter, perhaps named `json-with-metadata`, which returns a stringified object containing both objects: 57 | 58 | ```js 59 | module.exports = function(results, data) { 60 | return JSON.stringify({ 61 | results: results, 62 | rulesMeta: data.rulesMeta 63 | }); 64 | }; 65 | ``` 66 | 67 | ## Documentation 68 | 69 | Since custom formatter authors may want to take advantage of the newly-available rule metadata, a formal announcement may be justified (I don't have sufficient context in this regard so I will defer this determination.) 70 | 71 | The [Working with Custom Formatters](https://eslint.org/docs/developer-guide/working-with-custom-formatters) article will have to be updated: 72 | * Code samples will need the new `data` argument added wherever the exported interface function is shown, *but only when it is used*. 73 | * The `data` argument should be called out and described, and should include a link to the [Working with Rules](https://eslint.org/docs/developer-guide/working-with-rules) article. The primary goal here is to familiarize formatter author with the structure of the `data` argument and rulesMeta property. 74 | * It should be noted that the rulesMeta dictionary will be empty in cases where no rules have been run. 75 | * It should be noted that rule metadata properties such as description, category, and help URL are not required and may not be defined, and that custom formatter code should take this into account. 76 | * We should show the use of rule metadata in one of the examples by either modifying an existing one (maybe the [Detailed formatter](https://eslint.org/docs/developer-guide/working-with-custom-formatters#detailed-formatter) example) or adding a new one. One idea would be to suffix the results output with a list of rules that were violated, using a helper function something like this: 77 | 78 | ```js 79 | var rulesViolated = {}; 80 | ... 81 | function printRules() { 82 | var lines = "*** RULES:\n"; 83 | rulesViolated.forEach(function (ruleMetadata, ruleId) { 84 | lines += ruleId; 85 | 86 | if (ruleMetadata.docs.description) { 87 | lines += ": " + ruleMetadata.docs.description; 88 | } 89 | 90 | lines += "\n"; 91 | 92 | if (ruleMetadata.docs.url) { 93 | lines += ruleMetadata.docs.url + "\n"; 94 | } 95 | }); 96 | return lines; 97 | } 98 | ``` 99 | 100 | ## Drawbacks 101 | 102 | This is a fairly innocuous change in that it is additive, non-breaking (mostly, see Backwards Compatibility), and does not change any of ESLint's core functionality. A downside is that we will be exposing the Rule data model to third-party developers, so future changes could break existing formatters. For example, removing or renaming an existing property, or changing the structure of the Rule.meta object. 103 | 104 | ## Backwards Compatibility Analysis 105 | 106 | Since this change is manifested as a new argument to the formatter's exported interface function, existing formatter code that implements the exported interface function will not be affected and will continue to function even without adding the new argument to their exported function. 107 | 108 | (The following paragraph also appears in the Formatters section.) 109 | A formatter that assigns a function reference to the exported interface function could exhibit unexpected behavior depending on the signature of the referenced function. For example, since this change's second argument is a complex object, a referenced function that expects a Number as its second argument could cause an exception. 110 | 111 | ## Alternatives 112 | 113 | 119 | * Including the rule metadata in the result object. This approach results in redundant data being returned, and includes external metadata properties that are not directly relevant. 120 | * Pass the rules map itself as a argument to the formatter's exported interface function. This approach makes it messier to add additional data in the future, since new arguments would be necessary. 121 | 122 | ## Help Needed 123 | 124 | No help needed, I have implemented the change. 125 | 126 | ## Frequently Asked Questions 127 | 128 | 135 | 136 | ## Related Discussions 137 | 138 | Issue for this change: 139 | https://github.com/eslint/eslint/issues/11273 140 | 141 | Earlier related issue: 142 | https://github.com/eslint/eslint/issues/9841 143 | 144 | Initial inquiry: 145 | https://groups.google.com/forum/#!topic/eslint/kpHrxkeilwE 146 | -------------------------------------------------------------------------------- /designs/2019-esm-compatibilty/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-10-05 2 | - RFC PR: [#43](https://github.com/eslint/rfcs/pull/43) 3 | - Authors: Evan Plaice ([@evanplaice](https://github.com/evanplaice)) 4 | 5 | # ES Module Compatibility 6 | 7 | ## Summary 8 | 9 | **This Issue** 10 | 11 | Node now supports ES modules. ESLint configurations that use the CommonJS format (i.e., `.eslintrc`, `.eslintrc.js`) are not compatible with ES module based packages. 12 | 13 | **The Impact** 14 | 15 | This applies to ES module based packages (i.e., packages using `"type": "module"`) using a CommonJS configuration (i.e., `.eslintrc`, `.eslintrc.js`). 16 | 17 | **The Fix** 18 | 19 | Node provides an 'escape hatch' via the `.cjs` extension. The extension explicitly signals to Node that the file should *always* evaluate as CommonJS. Support for the `.cjs` needs to be added to ESLint, and ESLint users building ES module based packages need to be notified. 20 | 21 | ## Motivation 22 | 23 | ES modules are here. ESLint is ubiquitous in the JS ecosystem. With some minor adjustments, ESLint can be made to be compatible with the new format. 24 | 25 | ## Detailed Design 26 | 27 | To understand the design outlined here requires some background info into the mechanics by which Node modules are loaded. 28 | 29 | ### Jargon 30 | 31 | - Package - A NPM package (i.e., contains `package.json`) 32 | - Module - A JS file 33 | - CJS - A CommonJS module 34 | - ESM - A standard ECMAScript module 35 | - Consumer - A package that uses/depends on this package 36 | - Dependent - Package(s) that this package needs to work 37 | - Boundary - The demarcation between package, consumer, dependent 38 | 39 | ### A Crash Course on Package Boundaries 40 | 41 | Historically, NPM packages have come in a variety of different package formats (e.g., IIFE, AMD, UMD, CJS). Prior to an actual spec, NPM settled on CJS as it's de-facto module format. CJS isn't going anywhere, the addition of ESM is additive. 42 | 43 | By default, all NPM packages are CJS-based. That means all `.js` files will be read as CJS modules. To include an ES module in a CJS package, it must have the `.mjs` extension. 44 | 45 | If, `package.json` contains `"type": "module"` then the package is ESM-based. Meaning, all `.js` files contained within will be treated as ESM. To include a CJS module in a ESM-based package, it must have the `.cjs` extension. 46 | 47 | This configuration option does *not* affect consumers or dependents. Whatever the configuration, it applies to all modules within the package boundary. Assuming packages only ever directly import within their package boundary, there should be no issues with interoperability between CJS/ESM. 48 | 49 | ### The Scenario 50 | 51 | A user is creating a new package. They prefer ESM for Browser <-> Node compatibility so they configure their package to be ESM-based. 52 | 53 | The user adds `eslint` as a devDependency and a typical NPM script to lint the package's contents. 54 | 55 | The user defines `.eslintrc.js` outlining the rule set they prefer to use within their package. 56 | 57 | ### The Issue 58 | 59 | When the user package is ESM-based, all `.js` files within are read as ESM. 60 | 61 | However, ESLint is CJS-based so, it loads all files within its package boundary as CJS. 62 | 63 | The configuration file is defined as a CJS module (i.e., `module.exports`), but has a `.js` extension syntax so requiring it throws an error. ESLint, by design reaches across the package boundary to load the user-defined configuration but the user has inadvertently signaled to Node to load it with the wrong module loader. 64 | 65 | ### The Fix 66 | 67 | Add support for the `.cjs` file extension 68 | 69 | *Note: In Node, `.cjs` will always load as a CommonJS module, irrespective of package configuration* 70 | 71 | ### Usage 72 | 73 | If a user: 74 | 75 | - is building a ESM-based package 76 | - is using a JS-based configuration 77 | 78 | They should give the configuration a `.cjs` extension. 79 | 80 | ### Priority 81 | 82 | With the addition of `.cjs`, the new priority for configuration files will be 83 | 84 | 1. .eslintrc.js 85 | 1. .eslintrc.cjs 86 | 1. .eslintrc.yaml 87 | 1. .eslintrc.yml 88 | 1. .eslintrc.json 89 | 1. .eslintrc 90 | 1. package.json 91 | 92 | ## Documentation 93 | 94 | The [Configuration File Formats](https://github.com/eslint/website/blob/master/docs/6.0.0/user-guide/configuring.md#configuration-file-formats) section will need to be updated. 95 | 96 | ``` 97 | ## Configuration File Formats 98 | 99 | ESLint supports configuration files in several formats: 100 | 101 | * **JavaScript** - use `.eslintrc.js` and export an object containing your configuration. 102 | * **JavaScript (ESM) - same as `.eslintrc.js but used with ES module packages <--- 103 | * **YAML** - use `.eslintrc.yaml` or `.eslintrc.yml` to define the configuration structure. 104 | * **JSON** - use `.eslintrc.json` to define the configuration structure. ESLint's JSON files also allow JavaScript-style comments. 105 | * **Deprecated** - use `.eslintrc`, which can be either JSON or YAML. 106 | * **package.json** - create an `eslintConfig` property in your `package.json` file and define your configuration there. 107 | 108 | If there are multiple configuration files in the same directory, ESLint will only use one. The priority order is: 109 | 110 | 1. `.eslintrc.js` 111 | 1. `.eslintrc.cjs` <--- 112 | 1. `.eslintrc.yaml` 113 | 1. `.eslintrc.yml` 114 | 1. `.eslintrc.json` 115 | 1. `.eslintrc` 116 | 1. `package.json` 117 | 118 | **Note:** JavaScript (ESM) is for use with JavaScript packages that specify `"type":"module"` in `package.json`. <--- 119 | 120 | ``` 121 | 122 | ## Drawbacks 123 | 124 | ### Technical 125 | 126 | None. The change has no negative functionality or performance impacts. 127 | 128 | ### People 129 | 130 | Some developers within the Node ecosystem are strongly opposed to supporting `"type": "module"` at all. 131 | 132 | ## Backwards Compatibility Analysis 133 | 134 | *tl;dr: Backward compatibility will be unaffected* 135 | 136 | ### Story 1 - ESLint Compatibility 137 | 138 | This change is additive. It associates `.cjs` files with JS configurations. 139 | 140 | The existing semantics of loading CommonJS configurations for CommonJS-based packages do not change. 141 | 142 | ### Story 2 - Node Compatibility 143 | 144 | In Node, ES module and `.cjs` support roll out together. 145 | 146 | This change *only* impacts users who define their package as an ES module. 147 | 148 | Existing packages that use the default (i.e., CommonJS module resolution) will be unaffected. 149 | 150 | ## Alternatives 151 | 152 | ### Alternative 1 - Suppress the error 153 | 154 | **[PR#12333](https://github.com/eslint/eslint/pull/12333)** 155 | 156 | The fencing exists to prevent users from creating dual-mode (i.e., both ESM/CJS) packages as interoperability between the two format can cause issues. In the case of ESLint, loading a simple config file from a user-defined package should not cause any issues or side-effects. 157 | 158 | Eating the exception is viable solution. 159 | 160 | ### Alternative 2 - Support dynamic `import()` 161 | 162 | Instead of using 'import-fresh' to require the config, import it in a cross-format-compatible way using dynamic `import()`. 163 | 164 | There has been and will continue to be a lot of talk about using this approach as the CJS/ESM interoperability story is fleshed out. 165 | 166 | For now it presents too many unknowns. 167 | 168 | ## Open Questions 169 | 170 | 180 | 181 | ## Help Needed 182 | 183 | 189 | 190 | ## Frequently Asked Questions 191 | 192 | > Why doesn't compatibility w/ ESM-based packages 'just work'? 193 | 194 | ESLint reaches across the package boundary to retrieve the user-defined configuration. If the consumer package is ESM-based, the `.js` config file will be seen as an ES module. When the ES module loader encounters `module.exports` (i.e., the CommonJS module specifier) it will throw an error. 195 | 196 | > What does this interoperability issue affect? 197 | 198 | Only ESM-based packages (i.e., packages with `"type": "module"` defined in package.json). 199 | 200 | > What about 3rd-party linting tools that provide their own built-in rule set for ESLint (ex [StandardJS](https://standardjs.com/))? 201 | 202 | They aren't impacted by this change. 3rd-party modules define both their code and the ESLint rule set used within the same package boundary. 203 | 204 | > What about support for ES module configurations 205 | 206 | The scope of this RFC is limited to only ES module compatibility concerns. If there is a desire to add support for ESM-based configurations, it will need to be addressed in another RFC. 207 | 208 | ## Related Discussions 209 | 210 | - [Issue #12319](https://github.com/eslint/eslint/issues/12319) 211 | - [PR #12321](https://github.com/eslint/eslint/pull/12321) 212 | - [Transition Path Problems for Tooling - node/modules](https://github.com/nodejs/modules/issues/388) 213 | -------------------------------------------------------------------------------- /designs/2019-core-options/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-05-12 2 | - RFC PR: https://github.com/eslint/rfcs/pull/22 3 | - Authors: Toru Nagashima ([@mysticatea](https://github.com/mysticatea)) 4 | 5 | # Configuring core options in Config Files 6 | 7 | ## Summary 8 | 9 | This RFC adds several properties into config files to configure core options. People can use config files (including shareable configs!) instead of CLI options in order to configure some linter behavior. 10 | 11 | ## Motivation 12 | 13 | We cannot configure some linter's behavior with config files, especially, shareable configs. It's convenient if we can configure those in shareable configs. 14 | 15 | ## Detailed Design 16 | 17 | This RFC adds four properties to config files. 18 | 19 | ```js 20 | // .eslintrc.js 21 | module.exports = { 22 | noInlineConfig: false, // Corresponds to --no-inline-config 23 | reportUnusedDisableDirectives: false, // Corresponds to --report-unused-disable-directives 24 | verifyOnRecoverableParsingErrors: false, // Corresponds to --verify-on-recoverable-parsing-errors 25 | ignorePatterns: [], // Corresponds to --ignore-pattern 26 | 27 | overrides: [ 28 | { 29 | files: ["*.ts"], 30 | noInlineConfig: false, 31 | reportUnusedDisableDirectives: false, 32 | verifyOnRecoverableParsingErrors: false, 33 | // ignorePatterns: [], // Forbid this to avoid confusion with 'excludedFiles' property. 34 | }, 35 | ], 36 | } 37 | ``` 38 | 39 | ### § noInlineConfig 40 | 41 | That value can be a boolean value. Default is `false`. 42 | 43 | If `true` then it disables inline directive comments such as `/*eslint-disable*/`. 44 | 45 | If `noInlineConfig` is `true`, `--no-inline-config` was not given, and there are one or more directive comments, then ESLint reports each directive comment as a warning message (`severify=1`). For example, `"'eslint-disable' comment was ignored because your config file has 'noInlineConfig' setting."`. Therefore, end-users can know why directive comments didn't work. 46 | 47 |
48 | 💠Implementation: 49 |

In Linter#_verifyWithoutProcessors method, the linter checks both providedConfig and filenameOrOptions to determine noInlineConfig option. The filenameOrOptions.allowInlineConfig precedences providedConfig.noInlineConfig.

50 |
51 | 52 | ### § reportUnusedDisableDirectives 53 | 54 | That value can be a boolean value. Default is `false`. 55 | 56 | If `true` then it reports directive comments like `//eslint-disable-line` when no errors would have been reported on that line anyway. 57 | 58 | This option is different a bit from `--report-unused-disable-directives` CLI option. The `--report-unused-disable-directives` CLI option fails the linting with non-zero exit code (i.e., it's the same behavior as `severity=2`), but this `reportUnusedDisableDirectives` setting doesn't fail the linting (i.e., it's the same behavior as `severity=1`). Therefore, we cannot configure ESLint with `reportUnusedDisableDirectives` as failed by patch releases. 59 | 60 |
61 | 💠Implementation: 62 |
    63 |
  1. Linter and CLIEngine have options.reportUnusedDisableDirectives. This RFC enhances these options to accept "off", "warn", and "error". Existing false is the same as "off" and existing true is the same as "error".
  2. 64 |
  3. In Linter#_verifyWithoutProcessors method, the linter checks both providedConfig and filenameOrOptions to determine reportUnusedDisableDirectives option. The filenameOrOptions.reportUnusedDisableDirectives precedences providedConfig.reportUnusedDisableDirectives.
  4. 65 |
66 |
67 | 68 | ### § verifyOnRecoverableParsingErrors 69 | 70 | That value can be a boolean value. Default is `false`. 71 | 72 | If `true` then it runs rules even if recoverable errors existed. Then it shows both results. 73 | 74 |
75 | 💠Implementation: 76 |

In Linter#_verifyWithoutProcessors method, the linter checks both providedConfig and filenameOrOptions to determine verifyOnRecoverableParsingErrors option. The filenameOrOptions.verifyOnRecoverableParsingErrors precedences providedConfig.verifyOnRecoverableParsingErrors.

77 |
78 | 79 | ### § ignorePatterns 80 | 81 | That value can be an array of strings. Default is an empty array. 82 | 83 | This is very similar to `.eslintignore` file. Each value is a file pattern as same as each line of `.eslintignore` file. ESLint compares the path to source code files and the file pattern then it ignores the file if it was matched. The path to source code files is addressed as relative to the entry config file, as same as `files`/`excludedFiles` properties. 84 | 85 | ESLint concatenates all ignore patterns from all of `.eslintignore`, `--ignore-path`, `--ignore-pattern`, and `ignorePatterns`. If there are multiple `ignorePatterns` in a `ConfigArray`, all of them are concatenated. The order is: 86 | 87 | 1. The default ignoring. (I.e. `.*`, `node_modules/*`, and `bower_components/*`) 88 | 1. `ignorePatterns` in the appearance order in the config array. 89 | 1. `--ignore-path` or `.eslintignore`. 90 | 1. `--ignore-pattern` 91 | 92 | Negative patterns mean unignoring. For example, `!.*.js` makes ESLint checking JavaScript files which start with `.`. Negative patterns are used to override parent settings. 93 | Also, negative patterns is worthful for shareable configs of some platforms. For example, the config of VuePress can provide the configuration that unignores `.vuepress` directory. 94 | 95 | It disallows `ignorePatterns` property in `overrides` entries in order to avoid confusion with `excludedFiles`. And if a `ignorePatterns` property came from shareable configs in `overrides` entries, ESLint ignores it. This is the same behavior as `root` property. 96 | 97 | The `--no-ignore` CLI option disables `ignorePatterns` as well. 98 | 99 |
100 | 💠Implementation: 101 | 105 |
106 | 107 | ### § Other options? 108 | 109 | - `extensions` - This RFC doesn't add `extensions` option that corresponds to `--ext` because [#20 "Configuring Additional Lint Targets with `.eslintrc`"](https://github.com/eslint/rfcs/pull/20) is the good successor of that. 110 | - `rulePaths` - This RFC doesn't add `rulePaths` option that corresponds to `--rulesdir` because [#14 (`localPlugins`)](https://github.com/eslint/rfcs/pull/20) is the good successor of that. Because the `rulePaths` doesn't have namespace, shareable configs should not be able to configure that. (Or but it may be useful for some plugins such as `@typescript-eslint/eslint-plugin` in order to replace core rules. I'd like to discuss the replacement way in another place.) 111 | - `format` - This RFC doesn't add `format` option that corresponds to `--format` because it doesn't fit cascading configs. It needs another mechanism. 112 | - `maxWarnings` - This RFC doesn't add `maxWarnings` option that corresponds to `--max-warnings` because it doesn't fit cascading configs. It needs another mechanism. 113 | 114 | ## Documentation 115 | 116 | - [Configuring ESLint](https://eslint.org/docs/user-guide/configuring) page should describe new top-level properties. 117 | - [`--no-ignore` document](https://eslint.org/docs/user-guide/command-line-interface#--no-ignore) should mention `ignorePatterns` setting. 118 | 119 | ## Drawbacks 120 | 121 | Nothing in particular. 122 | 123 | ## Backwards Compatibility Analysis 124 | 125 | No concerns. Currently, unknown top-level properties are a fatal error. 126 | 127 | ## Alternatives 128 | 129 | - 130 | 131 | ## Related Discussions 132 | 133 | - [eslint/eslint#3529](https://github.com/eslint/eslint/issues/3529) - Set ignore path in .eslintrc 134 | - [eslint/eslint#4261](https://github.com/eslint/eslint/issues/4261) - combine .eslintignore with .eslintrc? 135 | - [eslint/eslint#8824](https://github.com/eslint/eslint/issues/8824) - Allow config to ignore comments that disable rules inline 136 | - [eslint/eslint#9382](https://github.com/eslint/eslint/issues/9382) - Proposal: `reportUnusedDisableDirectives` in config files 137 | - [eslint/eslint#10341](https://github.com/eslint/eslint/issues/10341) - do not ignore files started with `.` by default 138 | - [eslint/eslint#10891](https://github.com/eslint/eslint/issues/10891) - Allow setting ignorePatterns in eslintrc 139 | - [eslint/eslint#11665](https://github.com/eslint/eslint/issues/11665) - Add top-level option for noInlineConfig or allowInlineConfig 140 | -------------------------------------------------------------------------------- /designs/2019-recoverable-error-handling/README.md: -------------------------------------------------------------------------------- 1 | - Start Date: 2019-03-29 2 | - RFC PR: https://github.com/eslint/rfcs/pull/19 3 | - Authors: Toru Nagashima <[@mysticatea](https://github.com/mysticatea)> 4 | 5 | # Recoverable Error Handling 6 | 7 | ## Summary 8 | 9 | ESLint cannot verify source code if the code has a syntax error. However, we can make valid AST even if several kinds of syntax errors existed. For example, conflict of variable names doesn't break AST. This RFC calls such a syntax error as "Recoverable Errors". 10 | 11 | This RFC adds handling of [Recoverable Errors] into ESLint. 12 | 13 | ## Motivation 14 | 15 | The goal of this RFC is that improve ESLint experience by reducing "fixing an error makes more errors." 16 | 17 | This feature intends to be used for the syntax errors which don't affect AST shape. For example, name conflicts, type errors, etc. This feature doesn't intend to support invalid AST. 18 | 19 | ## Detailed Design 20 | 21 | ### § Handling [Recoverable Errors] in ESLint 22 | 23 | - `Linter` class passes `parserOptions.recoverableErrors` option with `true` to `espree` or custom parsers. 24 | - If the object the parser returned has `recoverableErrors` property with an array, or if the error the parser thrown has `recoverableErrors` property with an array, `Linter` class converts the errors to messages. 25 | 26 | Each element of `recoverableErrors` array has the following form. 27 | 28 | ```jsonc 29 | { 30 | "message": "Identifier 'foo' has already been declared", 31 | "line": 1, // 1-based line number. 32 | "column": 10, // 0-based column number. 33 | "endLine": 1, // Optional. 1-based line number. 34 | "endColumn": 13 // Optional. 0-based column number. 35 | } 36 | ``` 37 | 38 | Then `Linter` class converts that to a message: 39 | 40 | ```jsonc 41 | { 42 | "fatal": true, 43 | "ruleId": null, 44 | "severity": 2, 45 | "message": "Identifier 'foo' has already been declared", 46 | "line": 1, // 1-based line number. 47 | "column": 11, // 1-based column number. 48 | "endLine": 1, // Optional. 1-based line number. 49 | "endColumn": 14 // Optional. 1-based column number. 50 | } 51 | ``` 52 | 53 | - Directive comments such as `/*eslint-disable*/` cannot hide the messages of recoverable errors. 54 | - ESLint doesn't run any rules if a recoverable error existed. 55 | 56 | Practically, this is the support for multiple syntax errors. 57 | 58 | #### `verifyOnRecoverableParsingErrors` option 59 | 60 | `verifyOnRecoverableParsingErrors` option is the following three: 61 | 62 | - `--verify-on-recoverable-parsing-errors` CLI option 63 | - `verifyOnRecoverableParsingErrors` in `CLIEngine` constructor option (`boolean`, default is `false`) 64 | - `verifyOnRecoverableParsingErrors` in `Linter#verify()` option (`boolean`, default is `false`) 65 | 66 |
67 | An aside:
68 | And #22 coreOptions.verifyOnRecoverableParsingErrors in config files if both RFCs accepted. 69 |
70 | 71 | If the `verifyOnRecoverableParsingErrors` option was given, ESLint runs configured rules even if the parser returned recoverable errors. In that case, ESLint additionally controls lint messages to avoid confusion. 72 | 73 | If the parser returned any recoverable errors: 74 | 75 | - the `Linter` disables autofix by making [`disableFixes` option](https://eslint.org/docs/6.0.0/developer-guide/nodejs-api#linterverify) `true` internally as autofix is considered not safe. 76 | - the `Linter` catches exceptions which were thrown from rules and reports the exceptions as regular messages rather than crash in order to provide linting messages as best effort basis. For example, 77 | 78 | ```jsonc 79 | { 80 | "fatal": true, 81 | "ruleId": "a-rule", 82 | "severity": 2, 83 | "message": "'a-rule' failed to lint the code because of parsing error(s).", 84 | "line": 1, 85 | "column": 1, 86 | "endLine": 1, 87 | "endColumn": 1 88 | } 89 | ``` 90 | 91 | If a rule has an exception and regular messages, the `Linter` drops the regular messages to avoid confusion of wrong messages. 92 | 93 | ### § Handling [Recoverable Errors] in Espree 94 | 95 | Acorn, the underlying of `espree`, has `raiseRecoverable(pos, message)` method to customize handling of recoverable errors. 96 | 97 | If `options.recoverableErrors` was `true` then `espree` collects recoverable errors and returns the errors along with AST. Otherwise, `espree` throws syntax errors on recoverable errors as is currently. 98 | 99 | In `acorn@6.1.1`, there are the following recoverable errors: 100 | 101 | - "Comma is not permitted after the rest element" 102 | - "Parenthesized pattern" 103 | - "Redefinition of `__proto__` property" 104 | - "Redefinition of property" 105 | - "Binding XXX in strict mode" 106 | - "Assigning to XXX in strict mode" 107 | - "Argument name clash" 108 | - "Export 'XXX' is not defined" 109 | - "Multiple default clauses" 110 | - "Identifier 'XXX' has already been declared" 111 | - "Escape sequence in keyword XXX" 112 | - "Invalid regular expression: /a regexp/: An error description" 113 | 114 | > https://github.com/acornjs/acorn/search?q=raiseRecoverable 115 | 116 |
117 | An aside:
118 | A crazy idea is that we can make the parsing errors which are caused by older ecmaVersion recoverable. The parser parses code with the latest ecmaVersion always, then reports newer syntaxes as recoverable errors with understandable messages such as "async functions are not supported in ES5. Please set '2017' to 'parserOptions.ecmaVersion'." 119 |
120 | 121 | ### § Handling [Recoverable Errors] in Other Parsers 122 | 123 | This RFC doesn't contain the update of custom parsers. But this section considers if some popular custom parsers can applicate this feature. 124 | 125 | - `babel-eslint`
126 | I don't have enough knowledge about `babel-eslint` and recoverable errors. 127 | - `@typescript-eslint/parser`
128 | TypeScript parser parses source code loosely, then provides syntax/semantic errors by API along with AST. So currently `@typescript-eslint/parser` manually throws syntax errors if the parse result has syntax/semantic errors. Therefore, it can provide recoverable errors. 129 | - `vue-eslint-parser`
130 | It reports [HTML parse errors](https://html.spec.whatwg.org/multipage/parsing.html#parse-errors) and JavaScript syntax errors in `