├── .github ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── social-rfc-update.yml ├── README.md ├── designs ├── 2018-processors-improvements │ └── README.md ├── 2018-simplified-package-loading │ └── README.md ├── 2019-additional-lint-targets │ └── README.md ├── 2019-allow-all-directives-in-line-comments │ └── README.md ├── 2019-changing-base-path-in-config-files-that-cli-options-specify │ └── README.md ├── 2019-config-simplification │ └── README.md ├── 2019-config-tester │ └── README.md ├── 2019-core-options │ └── README.md ├── 2019-deprecating-personal-config │ └── README.md ├── 2019-description-in-directive-comments │ └── README.md ├── 2019-drop-node8 │ └── README.md ├── 2019-esm-compatibilty │ └── README.md ├── 2019-expose-rules-to-formatters │ └── readme.MD ├── 2019-move-to-async-api │ └── README.md ├── 2019-pass-cwd-from-cli-engine │ └── README.md ├── 2019-plugin-loading-improvement │ └── README.md ├── 2019-plugin-root-path-flag │ └── README.md ├── 2019-processor-shared-settings │ └── README.md ├── 2019-recoverable-error-handling │ └── README.md ├── 2019-rule-tester-improvements │ └── README.md ├── 2019-suggestions │ └── README.md ├── 2019-update-default-ignore-patterns │ └── README.md ├── 2019-variable-definition-information-of-config-files │ └── README.md ├── 2020-cache-contents-option │ └── README.md ├── 2020-cwd-in-formatters │ └── README.md ├── 2020-es-module-support │ └── README.md ├── 2020-generic-ast-support │ └── README.md ├── 2020-rule-tester-only │ └── README.md ├── 2020-timing-list-size │ └── README.md ├── 2021-break-on-parsing-errors │ └── README.md ├── 2021-fixable-disable-directives │ └── design.md ├── 2021-init-command-eslint-cli │ └── README.md ├── 2021-package-exports │ └── README.md ├── 2021-schema-object-rules │ └── README.md ├── 2021-stricter-rule-test-validation │ └── README.md ├── 2021-suppression-support │ ├── ESLint.png │ ├── README.md │ ├── design_diagram.png │ └── violation.png ├── 2022-community-eslint-org │ └── README.md ├── 2022-docs-information-architecture-update │ └── README.md ├── 2022-languages │ └── README.md ├── 2022-suggestion-parse-errors │ └── README.md ├── 2022-supress-ignored-file-warnings │ └── README.md ├── 2022-unused-disable-directive-flexible-config │ └── README.md ├── 2023-only-run-reporting-rules │ └── README.md ├── 2023-rule-options-defaults │ └── README.md ├── 2023-rule-performance-statistics │ └── README.md ├── 2023-test-rule-errors │ └── README.md ├── 2024-baseline-support │ └── README.md ├── 2024-config-extends │ └── README.md ├── 2024-config-lookup-from-file │ └── README.md ├── 2024-deprecated-rule-metadata │ └── README.md ├── 2024-hooks-for-test-cases │ └── README.md ├── 2024-multithread-linting │ └── README.md ├── 2024-repo-ecosystem-plugin-tests │ └── README.md ├── 2024-report-unused-inline-configs │ └── README.md ├── 2024-support-ts-config-files │ └── README.md └── 2025-base-path-in-config-objects │ └── README.md └── templates └── design.md /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Summary 2 | 3 | 4 | 5 | ## Related Issues 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.github/workflows/social-rfc-update.yml: -------------------------------------------------------------------------------- 1 | name: Post RFC Social 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/crosspost -t -b -m "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_API_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 18 | TWITTER_API_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 | MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} 22 | MASTODON_HOST: ${{ secrets.MASTODON_HOST }} 23 | BLUESKY_IDENTIFIER: ${{ vars.BLUESKY_IDENTIFIER }} 24 | BLUESKY_PASSWORD: ${{ secrets.BLUESKY_PASSWORD }} 25 | BLUESKY_HOST: ${{ vars.BLUESKY_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/crosspost -t -b -m "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_API_CONSUMER_KEY: ${{ secrets.TWITTER_CONSUMER_KEY }} 38 | TWITTER_API_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 | MASTODON_ACCESS_TOKEN: ${{ secrets.MASTODON_ACCESS_TOKEN }} 42 | MASTODON_HOST: ${{ secrets.MASTODON_HOST }} 43 | BLUESKY_IDENTIFIER: ${{ vars.BLUESKY_IDENTIFIER }} 44 | BLUESKY_PASSWORD: ${{ secrets.BLUESKY_PASSWORD }} 45 | BLUESKY_HOST: ${{ vars.BLUESKY_HOST }} 46 | -------------------------------------------------------------------------------- /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/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/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-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-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/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-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-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 | -------------------------------------------------------------------------------- /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-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-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-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 | -------------------------------------------------------------------------------- /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-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/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 `