diff --git a/.cspell.json b/.cspell.json index 080101b25f08..6133a8917ab4 100644 --- a/.cspell.json +++ b/.cspell.json @@ -72,6 +72,7 @@ "declarators", "destructure", "destructured", + "destructures", "discoverability", "dprint", "errored", @@ -121,6 +122,7 @@ "stringification", "stringifying", "stringly", + "subclassing", "superset", "thenables", "transpiled", @@ -137,7 +139,6 @@ "unfixable", "unoptimized", "unprefixed", - "upcasting", "upsert", "warnonunsupportedtypescriptversion", "Zacher" diff --git a/.lintstagedrc b/.lintstagedrc index c4eebcd2f404..62ea24d90961 100644 --- a/.lintstagedrc +++ b/.lintstagedrc @@ -1,3 +1,3 @@ { - "*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}": ["prettier --write"] + "*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,mdx,css}": ["prettier --write"] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0af262406419..8edd6ad69604 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + + +### Bug Fixes + +* **eslint-plugin:** [unbound-method] exempt all non-Promise built-in statics ([#8096](https://github.com/typescript-eslint/typescript-eslint/issues/8096)) ([3182959](https://github.com/typescript-eslint/typescript-eslint/commit/31829591e2c5cf6bdbdd5da23b12c5782f710fa5)) + + +### Features + +* **eslint-plugin:** deprecate formatting (meta.type: layout) rules ([#8073](https://github.com/typescript-eslint/typescript-eslint/issues/8073)) ([04dea84](https://github.com/typescript-eslint/typescript-eslint/commit/04dea84e8e934a415ec1381a90de3cde670d0dc3)) +* **eslint-plugin:** deprecate no-extra-semi in favor of ESLint Stylistic equivalent ([#8123](https://github.com/typescript-eslint/typescript-eslint/issues/8123)) ([9368bf3](https://github.com/typescript-eslint/typescript-eslint/commit/9368bf390afc58a19123782f8dff2bb5cdd3cccc)) +* **typescript-estree:** add allowDefaultProjectForFiles project service allowlist option ([#7752](https://github.com/typescript-eslint/typescript-eslint/issues/7752)) ([7ddadda](https://github.com/typescript-eslint/typescript-eslint/commit/7ddadda10845bc53967eeec83ba6b7cdc71a079f)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) diff --git a/docs/Maintenance.mdx b/docs/Maintenance.mdx index bc0db0d1e19a..0d599b38a376 100644 --- a/docs/Maintenance.mdx +++ b/docs/Maintenance.mdx @@ -12,3 +12,32 @@ We keep it in the open for visibility into our processes. If you're reading this as a new maintainer: welcome! We're happy to have you! ❤️‍🔥 ::: + +## Governance + +We follow a loose governance model that covers roles on the maintenance team and their associated responsibilities. +We see a few major benefits from doing so: + +- We want it to be clear how & why we do the things we do _(especially around compensation and expectations around roles)_ +- We want community input to make sure we're doing things the right way & focusing on truly useful improvements +- As we add to the processes over time, it'll be easier to make those changes clear & reviewable by everyone + +The following pages are a rough "v1.x" of our governance. +We do our best to roughly adhere to this model - though at times we may shortcut tasks if there is no downside in doing so. + +### Changes to Governance + +Any changes to this document will be posted for open discussion on the [typescript-eslint GitHub Discussions](https://github.com/typescript-eslint/typescript-eslint/discussions) and kept open for at least one month. +The discussion will be shared at the beginning, middle, and end of that month on Discord and all our social media accounts. + +## Providing Feedback + +We're always receptive to suggestions on how to improve our processes! +For general feedback, we'd suggest posting in the [`#development` channel on Discord](https://discord.com/channels/1026804805894672454/1088474511759917106). +We can help you turn that into a GitHub discussion. + +:::note +Please be kind: open source governance is an unsolved challenge. +We might not know what impractical or non-ideal things we're doing. +If there's anything sensitive you don't feel comfortable talking about in public, you can always DM or email one of the maintainers privately. +::: diff --git a/docs/linting/Troubleshooting.mdx b/docs/linting/Troubleshooting.mdx index ec964d14e843..526a79e03c63 100644 --- a/docs/linting/Troubleshooting.mdx +++ b/docs/linting/Troubleshooting.mdx @@ -153,6 +153,27 @@ module.exports = { }; ``` +## typescript-eslint thinks my variable is never nullish / is `any` / etc., but that is clearly not the case to me + +Our type-aware rules almost always trust the type information provided by the TypeScript compiler. Therefore, an easy way to check if our rule is behaving correctly is to inspect the type of the variable in question, such as by hovering over it in your IDE. + +If the IDE also shows that the type is never nullish / is `any`, you need to fix the type. A very common case is with the [`no-unnecessary-condition`](/rules/no-unnecessary-condition) rule. Take this code for example: + +```ts +let condition = false; + +const f = () => (condition = true); +f(); + +if (condition) { + //^^^^^^^^^ Unnecessary conditional, value is always falsy. +} +``` + +You can see that the type of `condition` is actually the literal type `false` by hovering over it in your IDE. In this case, typescript-eslint cannot possible know better than TypeScript itself, so you need to fix the report by fixing the type, such as through an assertion (`let condition = false as boolean`). + +If the IDE provides different type information from typescript-eslint's report, then make sure that the TypeScript setup used for your IDE, typescript-eslint, and `tsc` are the same: the same TypeScript version, the same type-checking compiler options, and the same files being included in the project. For example, if a type is declared in another file but that file is not included, the type will become `any`, and cause our `no-unsafe-*` rules to report. + ## I use a framework (like Vue) that requires custom file extensions, and I get errors like "You should add `parserOptions.extraFileExtensions` to your config" You can use `parserOptions.extraFileExtensions` to specify an array of non-TypeScript extensions to allow, for example: diff --git a/docs/maintenance/Contributor_Tiers.mdx b/docs/maintenance/Contributor_Tiers.mdx new file mode 100644 index 000000000000..aebf7ebe20d2 --- /dev/null +++ b/docs/maintenance/Contributor_Tiers.mdx @@ -0,0 +1,177 @@ +--- +id: contributor-tiers +title: Contributor Tiers +--- + +These tiers of contributors, committers, and maintainers roughly reflect how we've worked the past several years. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TierEntry RequirementsMonthly ExpectationsMonthly Reimbursement
Contributor1 point + (none) + + (none) +
Code Contributor1 point in pull requests + (none) + + (none) +
Committer + ~5 points in issues +
+ ~5 points in pull requests +
+ ~15 points total +
2 of 4 consecutive active months +
~10 points~1 share / active month
Maintainer + ~10 points in issues +
+ ~10 points in pull requests +
+ ~30 points total +
3 of 6 active months +
~20 points~2 shares / active month
+ +:::note +We treat everything here as approximate numbers. +We're a small enough team to informally discuss changes ad hoc and allow off-by-one-or-two months. +::: + +## Pointing + +Although it's impossible to accurately estimate software projects, we want to roughly establish expectations of effort+time spent on the tiers. +These are all rough estimations and should be taken as approximate starting guides to consider. + +We treat both the creation and review of issues and PRs along the rough scale of: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
SizeDescriptionPointsExamples
TrivialSmall typos or single-file bugfixes1 + + #6976 + + , #6992 +
Straightforward2-3 files at most, with minimal logical changes2 + + #6780 + + , #6910 +
LargeMulti-file logical changes that require real review+thought3 + + #6107 + + , #6907 +
UnusualDozen+ file logical changes that require deep investigation≥5* + + #6084 + + , #6777 +
+ +> \*Unusually large efforts may be >5 points at maintainer discretion depending on time spent. + +Any other activities (e.g. responding to Discord threads, working on upstream dependencies, …) should be treated as gaining points equal to their nearest equivalent point task in terms of complexity and effort. + +## Advancement + +Each tier corresponds to a role on Discord and GitHub. +When you first hit a tier, you can post in the [`#roles` channel on Discord](https://discord.com/channels/1026804805894672454/1184219870691328051). + +We will confirm privately that you've hit the intent of the contribution tiers. +We'll then grant you the role on Discord and GitHub and profusely thank you for everything you've done. ❤️ + +### Recognition + +Depending on the tier you reach, you can also provide information for an upcoming _Team_ page: + +- Contributor and Code Contributor: Preferred photo, name, social media handles +- Committer and Maintainer: ~2 paragraph bio of yourself + +See existing bios for examples of what to put. + +:::note +You can decline to opt into the Discord role or site recognition, and you can always opt out after the fact. +Nothing is mandatory. +We just like including recognition as thanks for working with us. 💕 +::: + +## Reimbursement + +Team members will be reimbursed the minimum of their activity level and their tier. +Each month: + +- Committers and maintainers who hit their expectation receive their full shares +- Committers and maintainers who hit roughly half their expectation receive half shares + +Reimbursements are generally handled through [our Open Collective page](https://opencollective.com/typescript-eslint). + +### Community Reimbursements + +Contributors who contribute nontrivial changes in a month (roughly ≥5 points and at least one _Large_ item) may be privately nominated at any time by a committer or maintainer to be reimbursed at the equivalent shares. + +Our intention is to always do this for contributors who submit _Large_ or greater contributions and don't need significant assistance in getting them merged. diff --git a/docs/maintenance/Governance.mdx b/docs/maintenance/Governance.mdx new file mode 100644 index 000000000000..2b37f5b29a00 --- /dev/null +++ b/docs/maintenance/Governance.mdx @@ -0,0 +1,4 @@ +--- +id: governance +title: Governance +--- diff --git a/docs/maintenance/Issues.mdx b/docs/maintenance/Issues.mdx index fbe1a45157fb..52794f3e7e70 100644 --- a/docs/maintenance/Issues.mdx +++ b/docs/maintenance/Issues.mdx @@ -5,7 +5,7 @@ title: Issues This document serves as a guide for how you might manage our [GitHub Issues](https://docs.github.com/issues), also known as issue triaging. -Use your best judgement when triaging issues, and most of all remember to be **kind, friendly, and encouraging** when responding to users. +Use your best judgement when triaging issues, and most of all remember to be **encouraging, friendly, and kind** when responding to users. Many users are new to open source and/or typed linting. It's imperative we give them a positive, uplifting experience. @@ -13,6 +13,17 @@ It's imperative we give them a positive, uplifting experience. If you're ever unsure on any part of issue management, don't hesitate to loop in a maintainer that has more context to help! ::: +## Governance + +Per the scales from [Contribution Tiers > Pointing](./Contributor_Tiers.mdx#pointing): + +- Straightforward: at reviewer discretion, may be marked as approved by any committer or maintainer. + This includes docs enhancements, bug fixes, and feature additions. +- Non-straightforward: may be marked as approved with either two committer approvals or one maintainer approval. + These include significant internal refactors and non-breaking public API changes. +- "Unusual"-categorized: require a public discussion followed by two maintainer approvals. + These include significant refactors with cross-project and public API ramifications. + ## Issue Flow :::note @@ -21,17 +32,17 @@ Don't treat these as exact responses you must use: they're just a starting copy+ Please do adopt your specific responses to your personal tone and to match the thread for non-straightforward issues. ::: -[Issues pending triage](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3Atriage) are searchable the `triage` label. +[Issues pending triage](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3Atriage) are searchable with the `triage` label. That label is added automatically when a new issue is created. Most issues go through the following review flow when created or updated: 1. A maintainer ensures the issue is valid: - If the poster didn't fill out an appropriate template with enough information: - - Add the `please fill out the template` and `awaiting response` labels + - Add the `please fill out the template` and `awaiting response` labels, and remove the `triage` label - Ask the poster for more information using a _Needs More Info_ response - If it's a duplicate of an issue that already exists: - - Add the `duplicate` label and remove the `bug` label - - If it's an obvious duplicate, post a _Clearly Duplicate Issue_ response + - Add the `duplicate` label and remove the `triage` label + - If it's an obvious duplicate, post a _Clearly Duplicate Issue_ response linking to the existing issue - If it's not an obvious duplicate, link to the existing issue and explain why - If the code is working as intended: - Add the `working as intended` label and remove the `bug` and `triage` labels @@ -135,6 +146,6 @@ Every so often, we like to [search for open issues `awaiting response`](https:// Our flow for issues that have been waiting for >=1 month is: 1. Ping the author with a message like the _Checking In_ template -2. Add the `stale` label to the issue -3. Wait 2 weeks -4. If they still haven't responded, close the issue with a message like the _Pruning Stale Issue_ template +1. Add the `stale` label to the issue +1. Wait 2 weeks +1. If they still haven't responded, close the issue with a message like the _Pruning Stale Issue_ template diff --git a/docs/maintenance/Pull_Requests.mdx b/docs/maintenance/Pull_Requests.mdx index 02f00ac952d0..4ed8fa9c513f 100644 --- a/docs/maintenance/Pull_Requests.mdx +++ b/docs/maintenance/Pull_Requests.mdx @@ -13,6 +13,17 @@ It's imperative we give them a positive, uplifting experience. If you're ever unsure on any part of PR reviews, don't hesitate to loop in a maintainer that has more context to help! ::: +## Governance + +Per the scales from [Contribution Tiers > Pointing](./Contributor_Tiers.mdx#pointing): + +- Straightforward: At reviewer discretion, may be merged with a single approval by any committer or maintainer. + This includes docs enhancements, bug fixes, and feature additions. +- Non-straightforward: may be merged with either two committer approvals or one maintainer approval. + These include multi-package internal refactors and non-breaking public API changes. +- "Unusual"-categorized: require two maintainer approvals. + These include significant refactors with cross-project and public API ramifications. + ## PR Flow :::note diff --git a/docs/maintenance/Major_Release_Steps.mdx b/docs/maintenance/Releases.mdx similarity index 65% rename from docs/maintenance/Major_Release_Steps.mdx rename to docs/maintenance/Releases.mdx index 42993b4480b2..95a5e20b0a92 100644 --- a/docs/maintenance/Major_Release_Steps.mdx +++ b/docs/maintenance/Releases.mdx @@ -1,9 +1,18 @@ --- -id: major-release-steps -title: Major Release Steps +id: releases +title: Releases --- -## 1. Pre-Release Preparation +[Users > Releases](../users/Releases.mdx) describes how our automatic releases are done. +There is generally no maintenance activity we need to take for the weekly releases. + +However, there are two kinds of releases we infrequently go through that each require manual effort. + +## Major Releases + +Per [Users > Releases > Major Releases](../users/Releases.mdx#major-releases), we infrequently release major versions with accumulated breaking changes. + +### 1. Pre-Release Preparation 1. Create a milestone by the name of the release [example: [Milestone 6.0.0](https://github.com/typescript-eslint/typescript-eslint/milestone/8)]. 1. If an issue for changes to recommended rule configs doesn't yet exist, create one [example: [Changes to the `recommended` sets for 5.0.0](https://github.com/typescript-eslint/typescript-eslint/issues/5900)]. @@ -18,7 +27,7 @@ title: Major Release Steps - Its publish command should be `npx lerna publish premajor --loglevel=verbose --canary --exact --force-publish --yes --dist-tag rc-v${major}`. - Merge this into `main` once reviewed and rebase the `v${major}` branch. -## 2. Merging Breaking Changes +### 2. Merging Breaking Changes 1. Send a PR from `v${major}` to `main` [example: [v6.0.0](https://github.com/typescript-eslint/typescript-eslint/pull/5886)]. 1. Change all [breaking change PRs](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aissue+is%3Aopen+label%3A%22breaking+change%22) to target the `v${major}` branch. @@ -34,11 +43,21 @@ _Non_-breaking changes can be merged to `main` or the major branch. They don't need any special treatment. ::: -## 3. Releasing the Version +### 3. Releasing the Version -1. Discuss with the maintainers to be ready for an [out-of-band](#out-of-band) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release. +1. Discuss with the maintainers to be ready for an [out-of-band](#out-of-band-releases) release. Doing this manually helps ensure someone is on-hand to action any issues that might arise from the major release. 1. Prepare the release notes. Lerna will automatically generate the release notes on GitHub, however this will be disorganized and unhelpful for users. We need to reorganize the release notes so that breaking changes are placed at the top to make them most visible. If any migrations are required, we must list the steps to make it easy for users. + - Example release notes: [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0), [`v4.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v4.0.0), [`v3.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v3.0.0) +1. Finally, tweet the release on the `@tseslint` twitter with a link to the GitHub release. Make sure you include additional information about the highlights of the release! -- Example release notes: [`v5.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v5.0.0), [`v4.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v4.0.0), [`v3.0.0`](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v3.0.0) +## Out-of-Band Releases -1. Finally, tweet the release on the `@tseslint` twitter with a link to the GitHub release. Make sure you include additional information about the highlights of the release! +Per [Users > Releases > Out-of-Band Releases](../users/Releases.mdx#out-of-band-releases), we may manually trigger a new release for a rare emergency such as a critical regression. +If that happens: + +1. Mention in any relevant issue(s) that you intend to release an out-of-band release +1. Post in a private maintenance Discord channel that you're working on it +1. Send a pull request resolving the issue(s) +1. Waiting up to a day (as reasonable) for approval before merging the PR +1. Trigger the private release workflow to cause a new release +1. Post back in those same issue(s) with a link to the newly released version(s) diff --git a/docs/maintenance/Dependency_Version_Upgrades.mdx b/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx similarity index 96% rename from docs/maintenance/Dependency_Version_Upgrades.mdx rename to docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx index ec0137f53b02..73d4e4fbed2d 100644 --- a/docs/maintenance/Dependency_Version_Upgrades.mdx +++ b/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx @@ -31,7 +31,7 @@ Whenever you discover any new areas of work that are blocked by dropping an old 1. Upgrade the root `package.json` `devDependency` to the latest ESLint 1. Add the new major version to the explicit `peerDependency` versions 1. Check [`eslint-visitor-keys`](https://www.npmjs.com/package/eslint-visitor-keys) for a new version to be upgraded to as well. -1. Update [Users > Dependency Versions > ESLint](../users/Dependency_Versions.mdx#eslint) +1. Update [Users > Dependency Versions > ESLint](../../users/Dependency_Versions.mdx#eslint) ### Removing Support for an Old ESLint Version @@ -42,7 +42,7 @@ Whenever you discover any new areas of work that are blocked by dropping an old - `/eslint.*5/i` - `/todo.*eslint.*5/i` - `/todo.*eslint/i` -1. Update [Users > Dependency Versions > ESLint](../users/Dependency_Versions.mdx#eslint) +1. Update [Users > Dependency Versions > ESLint](../../users/Dependency_Versions.mdx#eslint) See [chore: drop support for ESLint v6](https://github.com/typescript-eslint/typescript-eslint/pull/5972) for reference. @@ -115,7 +115,7 @@ A single PR can remove support for old TypeScript versions as a breaking change: 1. Update the root `package.json` `devDependency` 1. Update the `SUPPORTED_TYPESCRIPT_VERSIONS` constant in `warnAboutTSVersion.ts` 1. Update the `versions` constant in `version-check.ts` -1. Update [Users > Dependency Versions > TypeScript](../users/Dependency_Versions.mdx#typescript) +1. Update [Users > Dependency Versions > TypeScript](../../users/Dependency_Versions.mdx#typescript) 1. Search for source code comments (excluding `CHANGELOG.md` files) that mention a now-unsupported version of TypeScript. - For example, to remove support for v4.3, searches might include: - `4.3` diff --git a/docs/packages/TypeScript_ESTree.mdx b/docs/packages/TypeScript_ESTree.mdx index 610f641d384d..27122374bd18 100644 --- a/docs/packages/TypeScript_ESTree.mdx +++ b/docs/packages/TypeScript_ESTree.mdx @@ -167,7 +167,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * @see https://github.com/typescript-eslint/typescript-eslint/issues/6575 */ - EXPERIMENTAL_useProjectService?: boolean; + EXPERIMENTAL_useProjectService?: boolean | ProjectServiceOptions; /** * ***EXPERIMENTAL FLAG*** - Use this at your own risk. @@ -270,6 +270,16 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { }; } +/** + * Granular options to configure the project service. + */ +interface ProjectServiceOptions { + /** + * Globs of files to allow running with the default inferred project settings. + */ + allowDefaultProjectForFiles?: string[]; +} + interface ParserServices { program: ts.Program; esTreeNodeToTSNodeMap: WeakMap; diff --git a/docs/users/Dependency_Versions.mdx b/docs/users/Dependency_Versions.mdx index 7f2431bd9715..1954306a646a 100644 --- a/docs/users/Dependency_Versions.mdx +++ b/docs/users/Dependency_Versions.mdx @@ -55,4 +55,4 @@ See: [Packages > Parser > `warnOnUnsupportedTypeScriptVersion`](../packages/Pars ## Dependant Version Upgrades -See [Maintenance > Dependent Version Upgrades](../maintenance/Dependency_Version_Upgrades.mdx) for maintenance steps to update these versions. +See [Maintenance > Dependent Version Upgrades](../maintenance/pull-requests/Dependency_Version_Upgrades.mdx) for maintenance steps to update these versions. diff --git a/docs/users/Releases.mdx b/docs/users/Releases.mdx index 28b7099817c6..4ad0fdd9db70 100644 --- a/docs/users/Releases.mdx +++ b/docs/users/Releases.mdx @@ -73,9 +73,9 @@ We currently do not have a set schedule around when major releases shall be perf We keep a backlog of breaking issues as a milestone on GitHub that is named in the form `${major}.0.0`. When we do do a major release, we release a release candidate version to the `rc-v${major}` tag on npm for each commit to the major branch. -See [Maintenance > Major Release Steps](../maintenance/Major_Release_Steps.mdx) for steps to perform a major release. +See [Maintenance > Releases](../maintenance/Releases.mdx#major-releases) for steps to perform a major release. -## Out-of-Band +## Out-of-Band Releases We will do releases "out-of-band" (outside the [latest](#latest) schedule) for rare emergencies. We assess need on a case-by-case basis though generally an emergency is defined as a critical regression specifically introduced in the latest release. diff --git a/lerna.json b/lerna.json index 48712a67cbae..a24fd9776360 100644 --- a/lerna.json +++ b/lerna.json @@ -1,6 +1,6 @@ { "$schema": "node_modules/lerna/schemas/lerna-schema.json", - "version": "6.15.0", + "version": "6.16.0", "npmClient": "yarn", "stream": true, "command": { diff --git a/packages/ast-spec/CHANGELOG.md b/packages/ast-spec/CHANGELOG.md index 0a4e14e472a2..9480618c6f82 100644 --- a/packages/ast-spec/CHANGELOG.md +++ b/packages/ast-spec/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/ast-spec + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/ast-spec diff --git a/packages/ast-spec/package.json b/packages/ast-spec/package.json index c2ae4b692ee7..a0f16dd1682e 100644 --- a/packages/ast-spec/package.json +++ b/packages/ast-spec/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/ast-spec", - "version": "6.15.0", + "version": "6.16.0", "description": "Complete specification for the TypeScript-ESTree AST", "private": true, "keywords": [ diff --git a/packages/eslint-plugin-internal/CHANGELOG.md b/packages/eslint-plugin-internal/CHANGELOG.md index 4879e29a9df8..fba54ba3697f 100644 --- a/packages/eslint-plugin-internal/CHANGELOG.md +++ b/packages/eslint-plugin-internal/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-internal diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 58aa08bb7bb0..8a6e2c6f3ce5 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-internal", - "version": "6.15.0", + "version": "6.16.0", "private": true, "main": "dist/index.js", "scripts": { @@ -14,10 +14,10 @@ }, "dependencies": { "@prettier/sync": "*", - "@typescript-eslint/rule-tester": "6.15.0", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/type-utils": "6.15.0", - "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/rule-tester": "6.16.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/type-utils": "6.16.0", + "@typescript-eslint/utils": "6.16.0", "prettier": "^3.0.3" }, "devDependencies": { diff --git a/packages/eslint-plugin-tslint/CHANGELOG.md b/packages/eslint-plugin-tslint/CHANGELOG.md index 70a1babe5bd6..d1ecc13c0dc1 100644 --- a/packages/eslint-plugin-tslint/CHANGELOG.md +++ b/packages/eslint-plugin-tslint/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + + +### Features + +* **typescript-estree:** add allowDefaultProjectForFiles project service allowlist option ([#7752](https://github.com/typescript-eslint/typescript-eslint/issues/7752)) ([7ddadda](https://github.com/typescript-eslint/typescript-eslint/commit/7ddadda10845bc53967eeec83ba6b7cdc71a079f)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/eslint-plugin-tslint diff --git a/packages/eslint-plugin-tslint/package.json b/packages/eslint-plugin-tslint/package.json index 2101b9a8cf34..6ef15a53d070 100644 --- a/packages/eslint-plugin-tslint/package.json +++ b/packages/eslint-plugin-tslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin-tslint", - "version": "6.15.0", + "version": "6.16.0", "main": "dist/index.js", "typings": "src/index.ts", "description": "ESLint plugin that wraps a TSLint configuration and lints the whole source using TSLint", @@ -46,7 +46,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/utils": "6.15.0" + "@typescript-eslint/utils": "6.16.0" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0", @@ -55,7 +55,7 @@ }, "devDependencies": { "@types/lodash": "*", - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/parser": "6.16.0", "jest": "29.7.0", "prettier": "^3.0.3", "rimraf": "*" diff --git a/packages/eslint-plugin-tslint/tests/index.spec.ts b/packages/eslint-plugin-tslint/tests/index.spec.ts index 59f84be30770..bbe479c832b8 100644 --- a/packages/eslint-plugin-tslint/tests/index.spec.ts +++ b/packages/eslint-plugin-tslint/tests/index.spec.ts @@ -166,71 +166,73 @@ ruleTester.run('tslint/config', rule, { ], }); -describe('tslint/error', () => { - function testOutput(code: string, config: ClassicConfig.Config): void { - const linter = new TSESLint.Linter(); - linter.defineRule('tslint/config', rule); - linter.defineParser('@typescript-eslint/parser', parser); - - expect(() => linter.verify(code, config)).toThrow( - 'You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.', - ); - } - - it('should error on missing project', () => { - testOutput('foo;', { - rules: { - 'tslint/config': [2, tslintRulesConfig], - }, - parser: '@typescript-eslint/parser', +if (process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER !== 'true') { + describe('tslint/error', () => { + function testOutput(code: string, config: ClassicConfig.Config): void { + const linter = new TSESLint.Linter(); + linter.defineRule('tslint/config', rule); + linter.defineParser('@typescript-eslint/parser', parser); + + expect(() => linter.verify(code, config)).toThrow( + 'You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.', + ); + } + + it('should error on missing project', () => { + testOutput('foo;', { + rules: { + 'tslint/config': [2, tslintRulesConfig], + }, + parser: '@typescript-eslint/parser', + }); }); - }); - it('should error on default parser', () => { - testOutput('foo;', { - parserOptions: { - project: TEST_PROJECT_PATH, - }, - rules: { - 'tslint/config': [2, tslintRulesConfig], - }, + it('should error on default parser', () => { + testOutput('foo;', { + parserOptions: { + project: TEST_PROJECT_PATH, + }, + rules: { + 'tslint/config': [2, tslintRulesConfig], + }, + }); }); - }); - it('should not crash if there are no tslint rules specified', () => { - const linter = new TSESLint.Linter(); - jest.spyOn(console, 'warn').mockImplementation(); - linter.defineRule('tslint/config', rule); - linter.defineParser('@typescript-eslint/parser', parser); - - const filePath = path.resolve( - __dirname, - 'fixtures', - 'test-project', - 'extra.ts', - ); - - expect(() => - linter.verify( - 'foo;', - { - parserOptions: { - project: TEST_PROJECT_PATH, - }, - rules: { - 'tslint/config': [2, {}], + it('should not crash if there are no tslint rules specified', () => { + const linter = new TSESLint.Linter(); + jest.spyOn(console, 'warn').mockImplementation(); + linter.defineRule('tslint/config', rule); + linter.defineParser('@typescript-eslint/parser', parser); + + const filePath = path.resolve( + __dirname, + 'fixtures', + 'test-project', + 'extra.ts', + ); + + expect(() => + linter.verify( + 'foo;', + { + parserOptions: { + project: TEST_PROJECT_PATH, + }, + rules: { + 'tslint/config': [2, {}], + }, + parser: '@typescript-eslint/parser', }, - parser: '@typescript-eslint/parser', - }, - filePath, - ), - ).not.toThrow(); - - expect(console.warn).toHaveBeenCalledWith( - expect.stringContaining( - `Tried to lint ${filePath} but found no valid, enabled rules for this file type and file path in the resolved configuration.`, - ), - ); - jest.resetAllMocks(); + filePath, + ), + ).not.toThrow(); + + expect(console.warn).toHaveBeenCalledWith( + expect.stringContaining( + `Tried to lint ${filePath} but found no valid, enabled rules for this file type and file path in the resolved configuration.`, + ), + ); + jest.resetAllMocks(); + }); }); -}); +} diff --git a/packages/eslint-plugin/CHANGELOG.md b/packages/eslint-plugin/CHANGELOG.md index f339125f58a3..6f0f6f22246a 100644 --- a/packages/eslint-plugin/CHANGELOG.md +++ b/packages/eslint-plugin/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + + +### Bug Fixes + +* **eslint-plugin:** [unbound-method] exempt all non-Promise built-in statics ([#8096](https://github.com/typescript-eslint/typescript-eslint/issues/8096)) ([3182959](https://github.com/typescript-eslint/typescript-eslint/commit/31829591e2c5cf6bdbdd5da23b12c5782f710fa5)) + + +### Features + +* **eslint-plugin:** deprecate formatting (meta.type: layout) rules ([#8073](https://github.com/typescript-eslint/typescript-eslint/issues/8073)) ([04dea84](https://github.com/typescript-eslint/typescript-eslint/commit/04dea84e8e934a415ec1381a90de3cde670d0dc3)) +* **eslint-plugin:** deprecate no-extra-semi in favor of ESLint Stylistic equivalent ([#8123](https://github.com/typescript-eslint/typescript-eslint/issues/8123)) ([9368bf3](https://github.com/typescript-eslint/typescript-eslint/commit/9368bf390afc58a19123782f8dff2bb5cdd3cccc)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) diff --git a/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md b/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md index 83b183800d86..0e375c96937b 100644 --- a/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md +++ b/packages/eslint-plugin/docs/rules/explicit-member-accessibility.md @@ -164,7 +164,7 @@ class Animal { } ``` -### Overrides +### `overrides` There are three ways in which an override can be used. @@ -312,7 +312,7 @@ class Animal { } ``` -### Except specific methods +### `ignoredMethodNames` If you want to ignore some specific methods, you can do it by specifying method names. Note that this option does not care for the context, and will ignore every method with these names, which could lead to it missing some cases. You should use this sparingly. e.g. `[ { ignoredMethodNames: ['specificMethod', 'whateverMethod'] } ]` diff --git a/packages/eslint-plugin/docs/rules/no-empty-interface.md b/packages/eslint-plugin/docs/rules/no-empty-interface.md index 64bf24ffe1fa..f665acd4ae9a 100644 --- a/packages/eslint-plugin/docs/rules/no-empty-interface.md +++ b/packages/eslint-plugin/docs/rules/no-empty-interface.md @@ -50,20 +50,9 @@ interface Baz extends Foo, Bar {} ## Options -This rule accepts a single object option with the following default configuration: - -```json -{ - "@typescript-eslint/no-empty-interface": [ - "error", - { - "allowSingleExtends": false - } - ] -} -``` +### `allowSingleExtends` -- `allowSingleExtends: true` will silence warnings about extending a single interface without adding additional members +`allowSingleExtends: true` will silence warnings about extending a single interface without adding additional members ## When Not To Use It diff --git a/packages/eslint-plugin/docs/rules/no-explicit-any.md b/packages/eslint-plugin/docs/rules/no-explicit-any.md index 5e251fb7a03b..d81ea673b939 100644 --- a/packages/eslint-plugin/docs/rules/no-explicit-any.md +++ b/packages/eslint-plugin/docs/rules/no-explicit-any.md @@ -94,6 +94,13 @@ function greet(param: Array): Array {} ## Options +### `fixToUnknown` + +By default, this rule will not provide automatic ESLint _fixes_: only opt-in _suggestions_. +Switching types to `unknown` is safer but is likely to cause additional type errors. + +Enabling `{ "fixToUnknown": true }` gives the rule an auto-fixer to replace `: any` with `: unknown`. + ### `ignoreRestArgs` A boolean to specify if arrays from the rest operator are considered okay. `false` by default. diff --git a/packages/eslint-plugin/docs/rules/no-for-in-array.md b/packages/eslint-plugin/docs/rules/no-for-in-array.md index 2777c32a1e5d..4fb481cf469c 100644 --- a/packages/eslint-plugin/docs/rules/no-for-in-array.md +++ b/packages/eslint-plugin/docs/rules/no-for-in-array.md @@ -6,10 +6,14 @@ description: 'Disallow iterating over an array with a for-in loop.' > > See **https://typescript-eslint.io/rules/no-for-in-array** for documentation. -A for-in loop (`for (var i in o)`) iterates over the properties of an Object. -While it is legal to use for-in loops with array types, it is not common. -for-in will iterate over the indices of the array as strings, omitting any "holes" in -the array. +A for-in loop (`for (const i in o)`) iterates over the properties of an Object. +While it is legal to use for-in loops with array values, it is not common. There are several potential bugs with this: + +1. It iterates over all enumerable properties, including non-index ones and the entire prototype chain. For example, [`RegExp.prototype.exec`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec) returns an array with additional properties, and `for-in` will iterate over them. Some libraries or even your own code may add additional methods to `Array.prototype` (either as polyfill or as custom methods), and if not done properly, they may be iterated over as well. +2. It skips holes in the array. While sparse arrays are rare and advised against, they are still possible and your code should be able to handle them. +3. The "index" is returned as a string, not a number. This can be caught by TypeScript, but can still lead to subtle bugs. + +You may have confused for-in with for-of, which iterates over the elements of the array. If you actually need the index, use a regular `for` loop or the `forEach` method. ## Examples diff --git a/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md b/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md index 5c149ef653af..e57606d5ec9d 100644 --- a/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md +++ b/packages/eslint-plugin/docs/rules/no-meaningless-void-operator.md @@ -44,6 +44,8 @@ void bar(); // discarding a number ## Options +### `checkNever` + `checkNever: true` will suggest removing `void` when the argument has type `never`. ## When Not To Use It diff --git a/packages/eslint-plugin/docs/rules/no-misused-promises.md b/packages/eslint-plugin/docs/rules/no-misused-promises.md index 738b6f6f9afd..fc4ba7e460e3 100644 --- a/packages/eslint-plugin/docs/rules/no-misused-promises.md +++ b/packages/eslint-plugin/docs/rules/no-misused-promises.md @@ -17,7 +17,7 @@ See [`no-floating-promises`](./no-floating-promises.md) for detecting unhandled ## Options -### `"checksConditionals"` +### `checksConditionals` If you don't want to check conditionals, you can configure the rule with `"checksConditionals": false`: @@ -73,7 +73,7 @@ while (await promise) { -### `"checksVoidReturn"` +### `checksVoidReturn` Likewise, if you don't want to check functions that return promises where a void return is expected, your configuration will look like this: @@ -182,7 +182,7 @@ eventEmitter.on('some-event', () => { -### `"checksSpreads"` +### `checksSpreads` If you don't want to check object spreads, you can add this configuration: diff --git a/packages/eslint-plugin/docs/rules/no-parameter-properties.md b/packages/eslint-plugin/docs/rules/no-parameter-properties.md new file mode 100644 index 000000000000..65c94db1dc83 --- /dev/null +++ b/packages/eslint-plugin/docs/rules/no-parameter-properties.md @@ -0,0 +1,12 @@ +:::danger Deprecated + +This rule has been deprecated in favour of the [`parameter-properties`](https://typescript-eslint.io/rules/parameter-properties/) rule. + +::: + + diff --git a/packages/eslint-plugin/docs/rules/no-shadow.md b/packages/eslint-plugin/docs/rules/no-shadow.md index 5a9b52a818e1..d4eb49fa84ad 100644 --- a/packages/eslint-plugin/docs/rules/no-shadow.md +++ b/packages/eslint-plugin/docs/rules/no-shadow.md @@ -28,25 +28,31 @@ const defaultOptions: Options = { ### `ignoreTypeValueShadow` -When set to `true`, the rule will ignore the case when you name a type the same as a variable. - -TypeScript allows types and variables to shadow one-another. This is generally safe because you cannot use variables in type locations without a `typeof` operator, so there's little risk of confusion. +When set to `true`, the rule will ignore the case when you name a type the same as a variable. This is generally safe because you cannot use variables in type locations without a `typeof` operator, so there's little risk of confusion. Examples of **correct** code with `{ ignoreTypeValueShadow: true }`: ```ts option='{ "ignoreTypeValueShadow": true }' showPlaygroundButton type Foo = number; -const Foo = 1; - interface Bar { prop: number; } -const Bar = 'test'; + +function f() { + const Foo = 1; + const Bar = 'test'; +} ``` +:::note + +_Shadowing_ specifically refers to two identical identifiers that are in different, nested scopes. This is different from _redeclaration_, which is when two identical identifiers are in the same scope. Redeclaration is covered by the [`no-redeclare`](./no-redeclare.md) rule instead. + +::: + ### `ignoreFunctionTypeParameterNameValueShadow` -When set to `true`, the rule will ignore the case when you name a function type argument the same as a variable. +When set to `true`, the rule will ignore the case when you name a parameter in a function type the same as a variable. Each of a function type's arguments creates a value variable within the scope of the function type. This is done so that you can reference the type later using the `typeof` operator: diff --git a/packages/eslint-plugin/docs/rules/no-this-alias.md b/packages/eslint-plugin/docs/rules/no-this-alias.md index e9be8a524e6d..6014e56c3237 100644 --- a/packages/eslint-plugin/docs/rules/no-this-alias.md +++ b/packages/eslint-plugin/docs/rules/no-this-alias.md @@ -33,6 +33,75 @@ setTimeout(() => { ## Options +### `allowDestructuring` + +It can sometimes be useful to destructure properties from a class instance, such as retrieving multiple properties from the instance in one of its methods. +`allowDestructuring` allows those destructures and is `true` by default. +You can explicitly disallow them by setting `allowDestructuring` to `false`. + +Examples of code for the `{ "allowDestructuring": false }` option: + + + +#### ❌ Incorrect + +```ts option='{ "allowDestructuring": false }' +class ComponentLike { + props: unknown; + state: unknown; + + render() { + const { props, state } = this; + + console.log(props); + console.log(state); + } +} +``` + +#### ✅ Correct + +```ts option='{ "allowDestructuring": false }' +class ComponentLike { + props: unknown; + state: unknown; + + render() { + console.log(this.props); + console.log(this.state); + } +} +``` + +### `allowedNames` + +`no-this-alias` can alternately be used to allow only a specific list of names as `this` aliases. +We recommend against this except as a transitory step towards fixing all rule violations. + +Examples of code for the `{ "allowedNames": ["self"] }` option: + + + +#### ❌ Incorrect + +```ts option='{ "allowedNames": ["self"] }' +class Example { + method() { + const that = this; + } +} +``` + +#### ✅ Correct + +```ts option='{ "allowedNames": ["self"] }' +class Example { + method() { + const self = this; + } +} +``` + ## When Not To Use It If your project is structured in a way that it needs to assign `this` to variables, this rule is likely not for you. diff --git a/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md b/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md index 7afa80861999..59c9c126d2d8 100644 --- a/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md +++ b/packages/eslint-plugin/docs/rules/no-unnecessary-condition.md @@ -101,8 +101,7 @@ You might consider using [ESLint disable comments](https://eslint.org/docs/lates This rule has a known edge case of triggering on conditions that were modified within function calls (as side effects). It is due to limitations of TypeScript's type narrowing. See [#9998](https://github.com/microsoft/TypeScript/issues/9998) for details. - -We recommend upcasting the variable with a [type assertion](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions). +We recommend using a [type assertion](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions) in those cases. ```ts let condition = false as boolean; diff --git a/packages/eslint-plugin/docs/rules/parameter-properties.md b/packages/eslint-plugin/docs/rules/parameter-properties.md index 830e2a5250bb..87a467344a03 100644 --- a/packages/eslint-plugin/docs/rules/parameter-properties.md +++ b/packages/eslint-plugin/docs/rules/parameter-properties.md @@ -19,7 +19,7 @@ It may take an options object containing either or both of: - `"allow"`: allowing certain kinds of properties to be ignored - `"prefer"`: either `"class-property"` _(default)_ or `"parameter-property"` -### `"allow"` +### `allow` If you would like to ignore certain kinds of properties then you may pass an object containing `"allow"` as an array of any of the following options: @@ -45,7 +45,7 @@ For example, to ignore `public` properties: } ``` -### `"prefer"` +### `prefer` By default, the rule prefers class property (`"class-property"`). You can switch it to instead preferring parameter property with (`"parameter-property"`). diff --git a/packages/eslint-plugin/docs/rules/prefer-literal-enum-member.md b/packages/eslint-plugin/docs/rules/prefer-literal-enum-member.md index 3684b84d5446..de1ca2942b2e 100644 --- a/packages/eslint-plugin/docs/rules/prefer-literal-enum-member.md +++ b/packages/eslint-plugin/docs/rules/prefer-literal-enum-member.md @@ -61,7 +61,9 @@ enum Valid { ## Options -- `allowBitwiseExpressions` set to `true` will allow you to use bitwise expressions in enum initializer (Default: `false`). +### `allowBitwiseExpressions` + +When set to `true` will allow you to use bitwise expressions in enum initializer (default: `false`). Examples of code for the `{ "allowBitwiseExpressions": true }` option: diff --git a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md index 9377117fba44..0db387ab9a21 100644 --- a/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md +++ b/packages/eslint-plugin/docs/rules/prefer-nullish-coalescing.md @@ -167,6 +167,16 @@ foo ?? 'a string'; Also, if you would like to ignore all primitives types, you can set `ignorePrimitives: true`. It is equivalent to `ignorePrimitives: { string: true, number: true, bigint: true, boolean: true }`. +### `allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing` + +If this is set to `false`, then the rule will error on every file whose `tsconfig.json` does _not_ have the `strictNullChecks` compiler option (or `strict`) set to `true`. + +Without `strictNullChecks`, TypeScript essentially erases `undefined` and `null` from the types. This means when this rule inspects the types from a variable, **it will not be able to tell that the variable might be `null` or `undefined`**, which essentially makes this rule useless. + +You should be using `strictNullChecks` to ensure complete type-safety in your codebase. + +If for some reason you cannot turn on `strictNullChecks`, but still want to use this rule - you can use this option to allow it - but know that the behavior of this rule is _undefined_ with the compiler option turned off. We will not accept bug reports if you are using this option. + ## When Not To Use It If you are not using TypeScript 3.7 (or greater), then you will not be able to use this rule, as the operator is not supported. diff --git a/packages/eslint-plugin/docs/rules/promise-function-async.md b/packages/eslint-plugin/docs/rules/promise-function-async.md index a11dfdea3ce3..c85c00af40fc 100644 --- a/packages/eslint-plugin/docs/rules/promise-function-async.md +++ b/packages/eslint-plugin/docs/rules/promise-function-async.md @@ -58,6 +58,74 @@ async function functionReturnsUnionWithPromiseImplicitly(p: boolean) { } ``` +## Options + +### `allowAny` + +Whether to ignore functions that return `any` and `unknown`. +If you want additional safety, consider turning this option off, as it makes the rule less able to catch incorrect Promise behaviors. + +Examples of code with `{ "allowAny": false }`: + + + +#### ❌ Incorrect + +```ts option='{ "allowAny": false }' +const returnsAny = () => ({}) as any; +``` + +#### ✅ Correct + +```ts option='{ "allowAny": false }' +const returnsAny = async () => ({}) as any; +``` + +### `allowedPromiseNames` + +For projects that use constructs other than the global built-in `Promise` for asynchronous code. +This option allows specifying string names of classes or interfaces that cause a function to be checked as well. + +Examples of code with `{ "allowedPromiseNames": ["Bluebird"] }`: + + + +#### ❌ Incorrect + +```ts option='{ "allowedPromiseNames": ["Bluebird"] }' +import { Bluebird } from 'bluebird'; + +const returnsBluebird = () => new Bluebird(() => {}); +``` + +#### ✅ Correct + +```ts option='{ "allowedPromiseNames": ["Bluebird"] }' +import { Bluebird } from 'bluebird'; + +const returnsBluebird = async () => new Bluebird(() => {}); +``` + +### `checkArrowFunctions` + +Whether to check arrow functions. +`true` by default, but can be set to `false` to ignore them. + +### `checkFunctionDeclarations` + +Whether to check standalone function declarations. +`true` by default, but can be set to `false` to ignore them. + +### `checkFunctionExpressions` + +Whether to check inline function expressions. +`true` by default, but can be set to `false` to ignore them. + +### `checkMethodDeclarations` + +Whether to check methods on classes and object literals +`true` by default, but can be set to `false` to ignore them. + ## When Not To Use It This rule can be difficult to enable on projects that use APIs which require functions to always be `async`. diff --git a/packages/eslint-plugin/docs/rules/sort-type-constituents.md b/packages/eslint-plugin/docs/rules/sort-type-constituents.md index c767bff5edd5..10fe95e2bbe4 100644 --- a/packages/eslint-plugin/docs/rules/sort-type-constituents.md +++ b/packages/eslint-plugin/docs/rules/sort-type-constituents.md @@ -82,6 +82,46 @@ type T4 = ## Options +### `checkIntersections` + +Whether to check intersection types (`&`). + +Examples of code with `{ "checkIntersections": true }` (the default): + + + +#### ❌ Incorrect + +```ts option='{ "checkIntersections": true }' +type ExampleIntersection = B & A; +``` + +#### ✅ Correct + +```ts option='{ "checkIntersections": true }' +type ExampleIntersection = A & B; +``` + +### `checkUnions` + +Whether to check union types (`|`). + +Examples of code with `{ "checkUnions": true }` (the default): + + + +#### ❌ Incorrect + +```ts option='{ "checkUnions": true }' +type ExampleUnion = B | A; +``` + +#### ✅ Correct + +```ts option='{ "checkUnions": true }' +type ExampleUnion = A | B; +``` + ### `groupOrder` Each constituent of the type is placed into a group, and then the rule sorts alphabetically within each group. @@ -100,6 +140,22 @@ The ordering of groups is determined by this option. - `union` - Union types (`A | B`) - `nullish` - `null` and `undefined` +For example, configuring the rule with `{ "groupOrder": ["literal", "nullish" ]}`: + + + +#### ❌ Incorrect + +```ts option='{ "groupOrder": ["literal", "nullish" ]}' +type ExampleGroup = null | 123; +``` + +#### ✅ Correct + +```ts option='{ "groupOrder": ["literal", "nullish" ]}' +type ExampleGroup = 123 | null; +``` + ## When Not To Use It This rule is purely a stylistic rule for maintaining consistency in your project. diff --git a/packages/eslint-plugin/docs/rules/triple-slash-reference.md b/packages/eslint-plugin/docs/rules/triple-slash-reference.md index 40509d8fe235..364d4f6063fe 100644 --- a/packages/eslint-plugin/docs/rules/triple-slash-reference.md +++ b/packages/eslint-plugin/docs/rules/triple-slash-reference.md @@ -8,46 +8,94 @@ description: 'Disallow certain triple slash directives in favor of ES6-style imp TypeScript's `///` triple-slash references are a way to indicate that types from another module are available in a file. Use of triple-slash reference type directives is generally discouraged in favor of ECMAScript Module `import`s. -This rule reports on the use of `/// `, `/// `, or `/// ` directives. +This rule reports on the use of `/// `, `/// `, or `/// ` directives. ## Options -With `{ "path": "never", "types": "never", "lib": "never" }` options set, the following will all be **incorrect** usage: +Any number of the three kinds of references can be specified as an option. +Specifying `'always'` disables this lint rule for that kind of reference. -```ts option='{ "path": "never", "types": "never", "lib": "never" }' showPlaygroundButton -/// -/// -/// +### `lib` + +When set to `'never'`, bans `/// ` and enforces using an `import` instead: + + + +#### ❌ Incorrect + +```ts option='{ "lib": "never" }' +/// + +globalThis.value; +``` + +#### ✅ Correct + +```ts option='{ "lib": "never" }' +import { value } from 'code'; +``` + +### `path` + +When set to `'never'`, bans `/// ` and enforces using an `import` instead: + + + +#### ❌ Incorrect + +```ts option='{ "path": "never" }' +/// + +globalThis.value; ``` -Examples of **incorrect** code for the `{ "types": "prefer-import" }` option. Note that these are only errors when **both** styles are used for the **same** module: +#### ✅ Correct -```ts option='{ "types": "prefer-import" }' showPlaygroundButton -/// -import * as foo from 'foo'; +```ts option='{ "path": "never" }' +import { value } from 'code'; ``` -```ts option='{ "types": "prefer-import" }' showPlaygroundButton -/// -import foo = require('foo'); +### `types` + +When set to `'never'`, bans `/// ` and enforces using an `import` instead: + + + +#### ❌ Incorrect + +```ts option='{ "types": "never" }' +/// + +globalThis.value; ``` -With `{ "path": "always", "types": "always", "lib": "always" }` options set, the following will all be **correct** usage: +#### ✅ Correct -```ts option='{ "path": "always", "types": "always", "lib": "always" }' showPlaygroundButton -/// -/// -/// +```ts option='{ "types": "never" }' +import { value } from 'code'; ``` -Examples of **correct** code for the `{ "types": "prefer-import" }` option: + -```ts option='{ "types": "prefer-import" }' showPlaygroundButton -import * as foo from 'foo'; +The `types` option may alternately be given a `"prefer-import"` value. +Doing so indicates the rule should only report if there is already an `import` from the same location: + + + +#### ❌ Incorrect + +```ts option='{ "types": "prefer-import" }' +/// + +import { valueA } from 'code'; + +globalThis.valueB; ``` -```ts option='{ "types": "prefer-import" }' showPlaygroundButton -import foo = require('foo'); +#### ✅ Correct + +```ts option='{ "types": "prefer-import" }' +import { valueA, valueB } from 'code'; ``` ## When Not To Use It diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index df28fba6e392..76736528ac66 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/eslint-plugin", - "version": "6.15.0", + "version": "6.16.0", "description": "TypeScript plugin for ESLint", "files": [ "dist", @@ -57,10 +57,10 @@ }, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/type-utils": "6.15.0", - "@typescript-eslint/utils": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/type-utils": "6.16.0", + "@typescript-eslint/utils": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -73,8 +73,8 @@ "@types/debug": "*", "@types/marked": "*", "@types/natural-compare": "*", - "@typescript-eslint/rule-schema-to-typescript-types": "6.15.0", - "@typescript-eslint/rule-tester": "6.15.0", + "@typescript-eslint/rule-schema-to-typescript-types": "6.16.0", + "@typescript-eslint/rule-tester": "6.16.0", "ajv": "^6.12.6", "chalk": "^5.3.0", "cross-fetch": "*", diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts index f6e14dfe12a5..9881e3397de2 100644 --- a/packages/eslint-plugin/src/configs/all.ts +++ b/packages/eslint-plugin/src/configs/all.ts @@ -14,17 +14,9 @@ export = { '@typescript-eslint/ban-ts-comment': 'error', '@typescript-eslint/ban-tslint-comment': 'error', '@typescript-eslint/ban-types': 'error', - 'block-spacing': 'off', - '@typescript-eslint/block-spacing': 'error', - 'brace-style': 'off', - '@typescript-eslint/brace-style': 'error', '@typescript-eslint/class-literal-property-style': 'error', 'class-methods-use-this': 'off', '@typescript-eslint/class-methods-use-this': 'error', - 'comma-dangle': 'off', - '@typescript-eslint/comma-dangle': 'error', - 'comma-spacing': 'off', - '@typescript-eslint/comma-spacing': 'error', '@typescript-eslint/consistent-generic-constructors': 'error', '@typescript-eslint/consistent-indexed-object-style': 'error', '@typescript-eslint/consistent-type-assertions': 'error', @@ -38,23 +30,10 @@ export = { '@typescript-eslint/explicit-function-return-type': 'error', '@typescript-eslint/explicit-member-accessibility': 'error', '@typescript-eslint/explicit-module-boundary-types': 'error', - 'func-call-spacing': 'off', - '@typescript-eslint/func-call-spacing': 'error', - indent: 'off', - '@typescript-eslint/indent': 'error', 'init-declarations': 'off', '@typescript-eslint/init-declarations': 'error', - 'key-spacing': 'off', - '@typescript-eslint/key-spacing': 'error', - 'keyword-spacing': 'off', - '@typescript-eslint/keyword-spacing': 'error', - 'lines-around-comment': 'off', - '@typescript-eslint/lines-around-comment': 'error', - 'lines-between-class-members': 'off', - '@typescript-eslint/lines-between-class-members': 'error', 'max-params': 'off', '@typescript-eslint/max-params': 'error', - '@typescript-eslint/member-delimiter-style': 'error', '@typescript-eslint/member-ordering': 'error', '@typescript-eslint/method-signature-style': 'error', '@typescript-eslint/naming-convention': 'error', @@ -73,10 +52,6 @@ export = { '@typescript-eslint/no-empty-interface': 'error', '@typescript-eslint/no-explicit-any': 'error', '@typescript-eslint/no-extra-non-null-assertion': 'error', - 'no-extra-parens': 'off', - '@typescript-eslint/no-extra-parens': 'error', - 'no-extra-semi': 'off', - '@typescript-eslint/no-extra-semi': 'error', '@typescript-eslint/no-extraneous-class': 'error', '@typescript-eslint/no-floating-promises': 'error', '@typescript-eslint/no-for-in-array': 'error', @@ -138,10 +113,6 @@ export = { '@typescript-eslint/no-useless-template-literals': 'error', '@typescript-eslint/no-var-requires': 'error', '@typescript-eslint/non-nullable-type-assertion-style': 'error', - 'object-curly-spacing': 'off', - '@typescript-eslint/object-curly-spacing': 'error', - 'padding-line-between-statements': 'off', - '@typescript-eslint/padding-line-between-statements': 'error', '@typescript-eslint/parameter-properties': 'error', '@typescript-eslint/prefer-as-const': 'error', 'prefer-destructuring': 'off', @@ -162,8 +133,6 @@ export = { '@typescript-eslint/prefer-string-starts-ends-with': 'error', '@typescript-eslint/prefer-ts-expect-error': 'error', '@typescript-eslint/promise-function-async': 'error', - quotes: 'off', - '@typescript-eslint/quotes': 'error', '@typescript-eslint/require-array-sort-compare': 'error', 'require-await': 'off', '@typescript-eslint/require-await': 'error', @@ -171,19 +140,10 @@ export = { '@typescript-eslint/restrict-template-expressions': 'error', 'no-return-await': 'off', '@typescript-eslint/return-await': 'error', - semi: 'off', - '@typescript-eslint/semi': 'error', '@typescript-eslint/sort-type-constituents': 'error', - 'space-before-blocks': 'off', - '@typescript-eslint/space-before-blocks': 'error', - 'space-before-function-paren': 'off', - '@typescript-eslint/space-before-function-paren': 'error', - 'space-infix-ops': 'off', - '@typescript-eslint/space-infix-ops': 'error', '@typescript-eslint/strict-boolean-expressions': 'error', '@typescript-eslint/switch-exhaustiveness-check': 'error', '@typescript-eslint/triple-slash-reference': 'error', - '@typescript-eslint/type-annotation-spacing': 'error', '@typescript-eslint/typedef': 'error', '@typescript-eslint/unbound-method': 'error', '@typescript-eslint/unified-signatures': 'error', diff --git a/packages/eslint-plugin/src/rules/block-spacing.ts b/packages/eslint-plugin/src/rules/block-spacing.ts index 8a4ed0a00da5..ac71dbb1d2b7 100644 --- a/packages/eslint-plugin/src/rules/block-spacing.ts +++ b/packages/eslint-plugin/src/rules/block-spacing.ts @@ -17,6 +17,8 @@ export type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'block-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/block-spacing'], type: 'layout', docs: { description: diff --git a/packages/eslint-plugin/src/rules/brace-style.ts b/packages/eslint-plugin/src/rules/brace-style.ts index 412065b91ff5..6ab52b48ab29 100644 --- a/packages/eslint-plugin/src/rules/brace-style.ts +++ b/packages/eslint-plugin/src/rules/brace-style.ts @@ -16,6 +16,8 @@ export type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'brace-style', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/brace-style'], type: 'layout', docs: { description: 'Enforce consistent brace style for blocks', diff --git a/packages/eslint-plugin/src/rules/comma-dangle.ts b/packages/eslint-plugin/src/rules/comma-dangle.ts index 8ceb2a8c0efa..45d94c4a491c 100644 --- a/packages/eslint-plugin/src/rules/comma-dangle.ts +++ b/packages/eslint-plugin/src/rules/comma-dangle.ts @@ -46,6 +46,8 @@ function normalizeOptions(options: Option): NormalizedOptions { export default createRule({ name: 'comma-dangle', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/comma-dangle'], type: 'layout', docs: { description: 'Require or disallow trailing commas', diff --git a/packages/eslint-plugin/src/rules/comma-spacing.ts b/packages/eslint-plugin/src/rules/comma-spacing.ts index 851d6fcc19b0..09abc747b5a2 100644 --- a/packages/eslint-plugin/src/rules/comma-spacing.ts +++ b/packages/eslint-plugin/src/rules/comma-spacing.ts @@ -22,6 +22,8 @@ type MessageIds = 'missing' | 'unexpected'; export default createRule({ name: 'comma-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/comma-spacing'], type: 'layout', docs: { description: 'Enforce consistent spacing before and after commas', diff --git a/packages/eslint-plugin/src/rules/func-call-spacing.ts b/packages/eslint-plugin/src/rules/func-call-spacing.ts index a0645e640409..03e8a3683859 100644 --- a/packages/eslint-plugin/src/rules/func-call-spacing.ts +++ b/packages/eslint-plugin/src/rules/func-call-spacing.ts @@ -23,6 +23,8 @@ export type MessageIds = export default createRule({ name: 'func-call-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/func-call-spacing'], type: 'layout', docs: { description: diff --git a/packages/eslint-plugin/src/rules/indent.ts b/packages/eslint-plugin/src/rules/indent.ts index b50d6b71814a..c2d61583405a 100644 --- a/packages/eslint-plugin/src/rules/indent.ts +++ b/packages/eslint-plugin/src/rules/indent.ts @@ -92,6 +92,8 @@ const KNOWN_NODES = new Set([ export default createRule({ name: 'indent', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/indent'], type: 'layout', docs: { description: 'Enforce consistent indentation', diff --git a/packages/eslint-plugin/src/rules/key-spacing.ts b/packages/eslint-plugin/src/rules/key-spacing.ts index cfec69fdcbb5..bb882d1e8b48 100644 --- a/packages/eslint-plugin/src/rules/key-spacing.ts +++ b/packages/eslint-plugin/src/rules/key-spacing.ts @@ -27,6 +27,8 @@ const baseSchema = Array.isArray(baseRule.meta.schema) export default createRule({ name: 'key-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/key-spacing'], type: 'layout', docs: { description: diff --git a/packages/eslint-plugin/src/rules/keyword-spacing.ts b/packages/eslint-plugin/src/rules/keyword-spacing.ts index 0e4e26b4fa49..b36900062988 100644 --- a/packages/eslint-plugin/src/rules/keyword-spacing.ts +++ b/packages/eslint-plugin/src/rules/keyword-spacing.ts @@ -37,6 +37,8 @@ const schema = deepMerge( export default createRule({ name: 'keyword-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/keyword-spacing'], type: 'layout', docs: { description: 'Enforce consistent spacing before and after keywords', diff --git a/packages/eslint-plugin/src/rules/lines-around-comment.ts b/packages/eslint-plugin/src/rules/lines-around-comment.ts index 548c39768b3c..9c25d24351a6 100644 --- a/packages/eslint-plugin/src/rules/lines-around-comment.ts +++ b/packages/eslint-plugin/src/rules/lines-around-comment.ts @@ -50,6 +50,8 @@ function getCommentLineNums(comments: TSESTree.Comment[]): number[] { export default createRule({ name: 'lines-around-comment', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/lines-around-comment'], type: 'layout', docs: { description: 'Require empty lines around comments', diff --git a/packages/eslint-plugin/src/rules/lines-between-class-members.ts b/packages/eslint-plugin/src/rules/lines-between-class-members.ts index 2383142387a7..60da9308757a 100644 --- a/packages/eslint-plugin/src/rules/lines-between-class-members.ts +++ b/packages/eslint-plugin/src/rules/lines-between-class-members.ts @@ -33,6 +33,8 @@ const schema = Object.values( export default createRule({ name: 'lines-between-class-members', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/lines-between-class-members'], type: 'layout', docs: { description: 'Require or disallow an empty line between class members', diff --git a/packages/eslint-plugin/src/rules/member-delimiter-style.ts b/packages/eslint-plugin/src/rules/member-delimiter-style.ts index 02ee716a1b2b..1068387b6b13 100644 --- a/packages/eslint-plugin/src/rules/member-delimiter-style.ts +++ b/packages/eslint-plugin/src/rules/member-delimiter-style.ts @@ -136,6 +136,8 @@ const BASE_SCHEMA: JSONSchema4 = { export default createRule({ name: 'member-delimiter-style', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/member-delimiter-style'], type: 'layout', docs: { description: diff --git a/packages/eslint-plugin/src/rules/no-extra-parens.ts b/packages/eslint-plugin/src/rules/no-extra-parens.ts index 279ea3840473..8360df8e3ee4 100644 --- a/packages/eslint-plugin/src/rules/no-extra-parens.ts +++ b/packages/eslint-plugin/src/rules/no-extra-parens.ts @@ -20,6 +20,8 @@ type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'no-extra-parens', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/no-extra-parens'], type: 'layout', docs: { description: 'Disallow unnecessary parentheses', diff --git a/packages/eslint-plugin/src/rules/no-extra-semi.ts b/packages/eslint-plugin/src/rules/no-extra-semi.ts index 84903111bb71..f52e623cb9f0 100644 --- a/packages/eslint-plugin/src/rules/no-extra-semi.ts +++ b/packages/eslint-plugin/src/rules/no-extra-semi.ts @@ -13,6 +13,8 @@ type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'no-extra-semi', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/no-extra-semi'], type: 'suggestion', docs: { description: 'Disallow unnecessary semicolons', diff --git a/packages/eslint-plugin/src/rules/no-for-in-array.ts b/packages/eslint-plugin/src/rules/no-for-in-array.ts index 75a04de8b9c0..ad70180f3570 100644 --- a/packages/eslint-plugin/src/rules/no-for-in-array.ts +++ b/packages/eslint-plugin/src/rules/no-for-in-array.ts @@ -17,7 +17,7 @@ export default createRule({ }, messages: { forInViolation: - 'For-in loops over arrays are forbidden. Use for-of or array.forEach instead.', + 'For-in loops over arrays skips holes, returns indices as strings, and may visit the prototype chain or other enumerable properties. Use a more robust iteration method such as for-of or array.forEach instead.', }, schema: [], type: 'problem', diff --git a/packages/eslint-plugin/src/rules/object-curly-spacing.ts b/packages/eslint-plugin/src/rules/object-curly-spacing.ts index 66792ba75018..0f89ef5b98b2 100644 --- a/packages/eslint-plugin/src/rules/object-curly-spacing.ts +++ b/packages/eslint-plugin/src/rules/object-curly-spacing.ts @@ -24,10 +24,12 @@ export default createRule({ // eslint-disable-next-line eslint-plugin/prefer-message-ids,eslint-plugin/require-meta-type,eslint-plugin/require-meta-schema,eslint-plugin/require-meta-fixable -- all in base rule - https://github.com/not-an-aardvark/eslint-plugin-eslint-plugin/issues/274 meta: { ...baseRule.meta, + deprecated: true, docs: { description: 'Enforce consistent spacing inside braces', extendsBaseRule: true, }, + replacedBy: ['@stylistic/ts/object-curly-spacing'], }, defaultOptions: ['never'], create(context) { diff --git a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts index 442c8135e072..9c6555eb9075 100644 --- a/packages/eslint-plugin/src/rules/padding-line-between-statements.ts +++ b/packages/eslint-plugin/src/rules/padding-line-between-statements.ts @@ -590,6 +590,8 @@ const StatementTypes: Record = { export default createRule({ name: 'padding-line-between-statements', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/padding-line-between-statements'], type: 'layout', docs: { description: 'Require or disallow padding lines between statements', diff --git a/packages/eslint-plugin/src/rules/quotes.ts b/packages/eslint-plugin/src/rules/quotes.ts index 89100ef01ac7..2e1f3d6cd901 100644 --- a/packages/eslint-plugin/src/rules/quotes.ts +++ b/packages/eslint-plugin/src/rules/quotes.ts @@ -16,6 +16,8 @@ export type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'quotes', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/quotes'], type: 'layout', docs: { description: diff --git a/packages/eslint-plugin/src/rules/semi.ts b/packages/eslint-plugin/src/rules/semi.ts index 2129c27f9fb7..674ea99e3a96 100644 --- a/packages/eslint-plugin/src/rules/semi.ts +++ b/packages/eslint-plugin/src/rules/semi.ts @@ -16,6 +16,8 @@ export type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'semi', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/semi'], type: 'layout', docs: { description: 'Require or disallow semicolons instead of ASI', diff --git a/packages/eslint-plugin/src/rules/space-before-blocks.ts b/packages/eslint-plugin/src/rules/space-before-blocks.ts index f0e45ae7e329..5a668cc20f89 100644 --- a/packages/eslint-plugin/src/rules/space-before-blocks.ts +++ b/packages/eslint-plugin/src/rules/space-before-blocks.ts @@ -16,6 +16,8 @@ export type MessageIds = InferMessageIdsTypeFromRule; export default createRule({ name: 'space-before-blocks', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/space-before-blocks'], type: 'layout', docs: { description: 'Enforce consistent spacing before blocks', diff --git a/packages/eslint-plugin/src/rules/space-before-function-paren.ts b/packages/eslint-plugin/src/rules/space-before-function-paren.ts index 19836a9081f4..9e3366f3a9b1 100644 --- a/packages/eslint-plugin/src/rules/space-before-function-paren.ts +++ b/packages/eslint-plugin/src/rules/space-before-function-paren.ts @@ -20,6 +20,8 @@ export type MessageIds = 'missing' | 'unexpected'; export default createRule({ name: 'space-before-function-paren', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/space-before-function-paren'], type: 'layout', docs: { description: 'Enforce consistent spacing before function parenthesis', diff --git a/packages/eslint-plugin/src/rules/space-infix-ops.ts b/packages/eslint-plugin/src/rules/space-infix-ops.ts index 2bf643b08736..561d6b27e2c2 100644 --- a/packages/eslint-plugin/src/rules/space-infix-ops.ts +++ b/packages/eslint-plugin/src/rules/space-infix-ops.ts @@ -18,6 +18,8 @@ const UNIONS = ['|', '&']; export default createRule({ name: 'space-infix-ops', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/space-infix-ops'], type: 'layout', docs: { description: 'Require spacing around infix operators', diff --git a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts index 442dd71162a2..bfc31993a501 100644 --- a/packages/eslint-plugin/src/rules/type-annotation-spacing.ts +++ b/packages/eslint-plugin/src/rules/type-annotation-spacing.ts @@ -102,6 +102,8 @@ function getRules( export default createRule({ name: 'type-annotation-spacing', meta: { + deprecated: true, + replacedBy: ['@stylistic/ts/type-annotation-spacing'], type: 'layout', docs: { description: 'Require consistent spacing around type annotations', diff --git a/packages/eslint-plugin/src/rules/unbound-method.ts b/packages/eslint-plugin/src/rules/unbound-method.ts index f0ace192655c..de08e970d491 100644 --- a/packages/eslint-plugin/src/rules/unbound-method.ts +++ b/packages/eslint-plugin/src/rules/unbound-method.ts @@ -24,51 +24,16 @@ export type Options = [Config]; export type MessageIds = 'unbound' | 'unboundWithoutThisAnnotation'; /** - * The following is a list of exceptions to the rule - * Generated via the following script. - * This is statically defined to save making purposely invalid calls every lint run - * ``` -SUPPORTED_GLOBALS.flatMap(namespace => { - const object = window[namespace]; - return Object.getOwnPropertyNames(object) - .filter( - name => - !name.startsWith('_') && - typeof object[name] === 'function', - ) - .map(name => { - try { - const x = object[name]; - x(); - } catch (e) { - if (e.message.includes("called on non-object")) { - return `${namespace}.${name}`; - } - } - }); -}).filter(Boolean); - * ``` + * Static methods on these globals are either not `this`-aware or supported being + * called without `this`. + * + * - `Promise` is not in the list because it supports subclassing by using `this` + * - `Array` is in the list because although it supports subclassing, the `this` + * value defaults to `Array` when unbound + * + * This is now a language-design invariant: static methods are never `this`-aware + * because TC39 wants to make `array.map(Class.method)` work! */ -const nativelyNotBoundMembers = new Set([ - 'Promise.all', - 'Promise.race', - 'Promise.resolve', - 'Promise.reject', - 'Promise.allSettled', - 'Object.defineProperties', - 'Object.defineProperty', - 'Reflect.defineProperty', - 'Reflect.deleteProperty', - 'Reflect.get', - 'Reflect.getOwnPropertyDescriptor', - 'Reflect.getPrototypeOf', - 'Reflect.has', - 'Reflect.isExtensible', - 'Reflect.ownKeys', - 'Reflect.preventExtensions', - 'Reflect.set', - 'Reflect.setPrototypeOf', -]); const SUPPORTED_GLOBALS = [ 'Number', 'Object', @@ -78,7 +43,6 @@ const SUPPORTED_GLOBALS = [ 'Array', 'Proxy', 'Date', - 'Infinity', 'Atomics', 'Reflect', 'console', @@ -86,23 +50,23 @@ const SUPPORTED_GLOBALS = [ 'JSON', 'Intl', ] as const; -const nativelyBoundMembers = SUPPORTED_GLOBALS.map(namespace => { - if (!(namespace in global)) { - // node.js might not have namespaces like Intl depending on compilation options - // https://nodejs.org/api/intl.html#intl_options_for_building_node_js - return []; - } - const object = global[namespace]; - return Object.getOwnPropertyNames(object) - .filter( - name => - !name.startsWith('_') && - typeof (object as Record)[name] === 'function', - ) - .map(name => `${namespace}.${name}`); -}) - .reduce((arr, names) => arr.concat(names), []) - .filter(name => !nativelyNotBoundMembers.has(name)); +const nativelyBoundMembers = new Set( + SUPPORTED_GLOBALS.flatMap(namespace => { + if (!(namespace in global)) { + // node.js might not have namespaces like Intl depending on compilation options + // https://nodejs.org/api/intl.html#intl_options_for_building_node_js + return []; + } + const object = global[namespace]; + return Object.getOwnPropertyNames(object) + .filter( + name => + !name.startsWith('_') && + typeof (object as Record)[name] === 'function', + ) + .map(name => `${namespace}.${name}`); + }), +); const isNotImported = ( symbol: ts.Symbol, @@ -201,7 +165,7 @@ export default createRule({ if ( objectSymbol && - nativelyBoundMembers.includes(getMemberFullName(node)) && + nativelyBoundMembers.has(getMemberFullName(node)) && isNotImported(objectSymbol, currentSourceFile) ) { return; @@ -232,7 +196,7 @@ export default createRule({ if ( notImported && isIdentifier(initNode) && - nativelyBoundMembers.includes( + nativelyBoundMembers.has( `${initNode.name}.${property.key.name}`, ) ) { diff --git a/packages/eslint-plugin/tests/areOptionsValid.test.ts b/packages/eslint-plugin/tests/areOptionsValid.test.ts index ab234f2fe3a8..1908acf1460f 100644 --- a/packages/eslint-plugin/tests/areOptionsValid.test.ts +++ b/packages/eslint-plugin/tests/areOptionsValid.test.ts @@ -4,7 +4,7 @@ import { areOptionsValid } from './areOptionsValid'; const exampleRule = createRule<['value-a' | 'value-b'], never>({ name: 'my-example-rule', meta: { - type: 'layout', + type: 'suggestion', docs: { description: 'Detects something or other', }, diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts index a811396013cd..b10ce6d78242 100644 --- a/packages/eslint-plugin/tests/docs.test.ts +++ b/packages/eslint-plugin/tests/docs.test.ts @@ -53,7 +53,11 @@ describe('Validating rule docs', () => { // comments in the files for more information. 'camelcase.md', 'no-duplicate-imports.md', + 'no-parameter-properties.md', ]); + + const rulesWithComplexOptions = new Set(['array-type', 'member-ordering']); + it('All rules must have a corresponding rule doc', () => { const files = fs .readdirSync(docsRoot) @@ -107,17 +111,19 @@ describe('Validating rule docs', () => { ); }); + const headings = tokens.filter(tokenIsHeading); + const requiredHeadings = ['When Not To Use It']; + const importantHeadings = new Set([ ...requiredHeadings, 'How to Use', 'Options', 'Related To', + 'When Not To Use It', ]); test('important headings must be h2s', () => { - const headings = tokens.filter(tokenIsHeading); - for (const heading of headings) { if (importantHeadings.has(heading.raw.replace(/#/g, '').trim())) { expect(heading.depth).toBe(2); @@ -145,6 +151,35 @@ describe('Validating rule docs', () => { } }); } + + const { schema } = rule.meta; + if ( + !rulesWithComplexOptions.has(ruleName) && + Array.isArray(schema) && + !rule.meta.docs?.extendsBaseRule && + rule.meta.type !== 'layout' + ) { + test('each rule option should be mentioned in a heading', () => { + const headingTextAfterOptions = headings + .slice(headings.findIndex(header => header.text === 'Options')) + .map(header => header.text) + .join('\n'); + + for (const schemaItem of schema) { + if (schemaItem.type === 'object') { + for (const property of Object.keys( + schemaItem.properties as object, + )) { + if (!headingTextAfterOptions.includes(`\`${property}\``)) { + throw new Error( + `At least one header should include \`${property}\`.`, + ); + } + } + } + } + }); + } }); } }); diff --git a/packages/eslint-plugin/tests/rules/unbound-method.test.ts b/packages/eslint-plugin/tests/rules/unbound-method.test.ts index 9eb2b73b22c2..9221dc2ebfe1 100644 --- a/packages/eslint-plugin/tests/rules/unbound-method.test.ts +++ b/packages/eslint-plugin/tests/rules/unbound-method.test.ts @@ -57,6 +57,7 @@ ruleTester.run('unbound-method', rule, { "['1', '2', '3'].map(Number.parseInt);", '[5.2, 7.1, 3.6].map(Math.floor);', 'const x = console.log;', + 'const x = Object.defineProperty;', ...[ 'instance.bound();', 'instance.unbound();', diff --git a/packages/integration-tests/CHANGELOG.md b/packages/integration-tests/CHANGELOG.md index 3c383de71881..9c16bcbac10d 100644 --- a/packages/integration-tests/CHANGELOG.md +++ b/packages/integration-tests/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/integration-tests + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/integration-tests diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index e2fc58ec9706..d83b7b4ec82e 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/integration-tests", - "version": "6.15.0", + "version": "6.16.0", "private": true, "scripts": { "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", diff --git a/packages/parser/CHANGELOG.md b/packages/parser/CHANGELOG.md index 9118a1de5940..af2fd6d22433 100644 --- a/packages/parser/CHANGELOG.md +++ b/packages/parser/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/parser + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/parser diff --git a/packages/parser/package.json b/packages/parser/package.json index 6ea956fd4c29..051b0cf3cb88 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/parser", - "version": "6.15.0", + "version": "6.16.0", "description": "An ESLint custom parser which leverages TypeScript ESTree", "files": [ "dist", @@ -51,10 +51,10 @@ "eslint": "^7.0.0 || ^8.0.0" }, "dependencies": { - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", "debug": "^4.3.4" }, "devDependencies": { diff --git a/packages/repo-tools/CHANGELOG.md b/packages/repo-tools/CHANGELOG.md index 4708ec7f23f4..ac3afffa5d55 100644 --- a/packages/repo-tools/CHANGELOG.md +++ b/packages/repo-tools/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/repo-tools + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/repo-tools diff --git a/packages/repo-tools/package.json b/packages/repo-tools/package.json index 7e057d847a5d..a38da67822ce 100644 --- a/packages/repo-tools/package.json +++ b/packages/repo-tools/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/repo-tools", - "version": "6.15.0", + "version": "6.16.0", "private": true, "scripts": { "//": "NOTE: intentionally no build step in this package", diff --git a/packages/rule-schema-to-typescript-types/CHANGELOG.md b/packages/rule-schema-to-typescript-types/CHANGELOG.md index 6f3b6381f882..537180f63c35 100644 --- a/packages/rule-schema-to-typescript-types/CHANGELOG.md +++ b/packages/rule-schema-to-typescript-types/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/rule-schema-to-typescript-types + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/rule-schema-to-typescript-types diff --git a/packages/rule-schema-to-typescript-types/package.json b/packages/rule-schema-to-typescript-types/package.json index 2d86df160ec0..216208cfcf03 100644 --- a/packages/rule-schema-to-typescript-types/package.json +++ b/packages/rule-schema-to-typescript-types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-schema-to-typescript-types", - "version": "6.15.0", + "version": "6.16.0", "private": true, "type": "commonjs", "exports": { @@ -34,8 +34,8 @@ }, "dependencies": { "@prettier/sync": "*", - "@typescript-eslint/type-utils": "6.15.0", - "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/type-utils": "6.16.0", + "@typescript-eslint/utils": "6.16.0", "natural-compare": "^1.4.0", "prettier": "^3.0.3" }, diff --git a/packages/rule-tester/CHANGELOG.md b/packages/rule-tester/CHANGELOG.md index 5094fcdd7ce6..da6d8ee1e1b8 100644 --- a/packages/rule-tester/CHANGELOG.md +++ b/packages/rule-tester/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/rule-tester + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/rule-tester diff --git a/packages/rule-tester/package.json b/packages/rule-tester/package.json index a1e553b7edfe..6f73acebe9ba 100644 --- a/packages/rule-tester/package.json +++ b/packages/rule-tester/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/rule-tester", - "version": "6.15.0", + "version": "6.16.0", "description": "Tooling to test ESLint rules", "files": [ "dist", @@ -47,8 +47,8 @@ }, "//": "NOTE - AJV is out-of-date, but it's intentionally synced with ESLint - https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/package.json#L70", "dependencies": { - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/utils": "6.16.0", "ajv": "^6.10.0", "lodash.merge": "4.6.2", "semver": "^7.5.4" @@ -59,7 +59,7 @@ }, "devDependencies": { "@types/lodash.merge": "4.6.9", - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/parser": "6.16.0", "chai": "^4.3.7", "mocha": "^10.0.0", "sinon": "^16.0.0", diff --git a/packages/scope-manager/CHANGELOG.md b/packages/scope-manager/CHANGELOG.md index d36abf971564..9ee5cdc13c0a 100644 --- a/packages/scope-manager/CHANGELOG.md +++ b/packages/scope-manager/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/scope-manager + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/scope-manager diff --git a/packages/scope-manager/package.json b/packages/scope-manager/package.json index 6b1d5313f7bd..3d93b985807d 100644 --- a/packages/scope-manager/package.json +++ b/packages/scope-manager/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/scope-manager", - "version": "6.15.0", + "version": "6.16.0", "description": "TypeScript scope analyser for ESLint", "files": [ "dist", @@ -44,13 +44,13 @@ "typecheck": "npx nx typecheck" }, "dependencies": { - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0" + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0" }, "devDependencies": { "@prettier/sync": "*", "@types/glob": "*", - "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/typescript-estree": "6.16.0", "glob": "*", "jest-specific-snapshot": "*", "make-dir": "*", diff --git a/packages/type-utils/CHANGELOG.md b/packages/type-utils/CHANGELOG.md index 2949f912bb73..50c8a16235b0 100644 --- a/packages/type-utils/CHANGELOG.md +++ b/packages/type-utils/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/type-utils + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/type-utils diff --git a/packages/type-utils/package.json b/packages/type-utils/package.json index 56c59de14cc4..3c7f7e277e76 100644 --- a/packages/type-utils/package.json +++ b/packages/type-utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/type-utils", - "version": "6.15.0", + "version": "6.16.0", "description": "Type utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -45,13 +45,13 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/utils": "6.16.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, "devDependencies": { - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/parser": "6.16.0", "ajv": "^6.10.0", "downlevel-dts": "*", "jest": "29.7.0", diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md index aecb8fc70d47..fac93ffca4a3 100644 --- a/packages/types/CHANGELOG.md +++ b/packages/types/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/types + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/types diff --git a/packages/types/package.json b/packages/types/package.json index 0327d49caa14..2efea815928e 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/types", - "version": "6.15.0", + "version": "6.16.0", "description": "Types for the TypeScript-ESTree AST spec", "files": [ "dist", diff --git a/packages/typescript-estree/CHANGELOG.md b/packages/typescript-estree/CHANGELOG.md index f752f1b2de46..02bc54ff2548 100644 --- a/packages/typescript-estree/CHANGELOG.md +++ b/packages/typescript-estree/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + + +### Features + +* **typescript-estree:** add allowDefaultProjectForFiles project service allowlist option ([#7752](https://github.com/typescript-eslint/typescript-eslint/issues/7752)) ([7ddadda](https://github.com/typescript-eslint/typescript-eslint/commit/7ddadda10845bc53967eeec83ba6b7cdc71a079f)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/typescript-estree diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 52d2964594f0..7f6a1c9d1e9f 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/typescript-estree", - "version": "6.15.0", + "version": "6.16.0", "description": "A parser that converts TypeScript source code into an ESTree compatible form", "files": [ "dist", @@ -52,11 +52,12 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/typescript-estree/src/create-program/createProjectService.ts index 380dec18f4cc..1cf7f9d82992 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/typescript-estree/src/create-program/createProjectService.ts @@ -1,6 +1,8 @@ +/* eslint-disable @typescript-eslint/no-empty-function -- for TypeScript APIs*/ import type * as ts from 'typescript/lib/tsserverlibrary'; -// eslint-disable-next-line @typescript-eslint/no-empty-function +import type { ProjectServiceOptions } from '../parser-options'; + const doNothing = (): void => {}; const createStubFileWatcher = (): ts.FileWatcher => ({ @@ -9,9 +11,15 @@ const createStubFileWatcher = (): ts.FileWatcher => ({ export type TypeScriptProjectService = ts.server.ProjectService; +export interface ProjectServiceSettings { + allowDefaultProjectForFiles: string[] | undefined; + service: TypeScriptProjectService; +} + export function createProjectService( - jsDocParsingMode?: ts.JSDocParsingMode, -): TypeScriptProjectService { + options: boolean | ProjectServiceOptions | undefined, + jsDocParsingMode: ts.JSDocParsingMode | undefined, +): ProjectServiceSettings { // We import this lazily to avoid its cost for users who don't use the service // TODO: Once we drop support for TS<5.3 we can import from "typescript" directly const tsserver = require('typescript/lib/tsserverlibrary') as typeof ts; @@ -30,7 +38,7 @@ export function createProjectService( watchFile: createStubFileWatcher, }; - return new tsserver.server.ProjectService({ + const service = new tsserver.server.ProjectService({ host: system, cancellationToken: { isCancellationRequested: (): boolean => false }, useSingleInferredProject: false, @@ -49,4 +57,12 @@ export function createProjectService( session: undefined, jsDocParsingMode, }); + + return { + allowDefaultProjectForFiles: + typeof options === 'object' + ? options.allowDefaultProjectForFiles + : undefined, + service, + }; } diff --git a/packages/typescript-estree/src/parseSettings/createParseSettings.ts b/packages/typescript-estree/src/parseSettings/createParseSettings.ts index 6b3429571014..a30942aa0d5b 100644 --- a/packages/typescript-estree/src/parseSettings/createParseSettings.ts +++ b/packages/typescript-estree/src/parseSettings/createParseSettings.ts @@ -1,7 +1,7 @@ import debug from 'debug'; import * as ts from 'typescript'; -import type { TypeScriptProjectService } from '../create-program/createProjectService'; +import type { ProjectServiceSettings } from '../create-program/createProjectService'; import { createProjectService } from '../create-program/createProjectService'; import { ensureAbsolutePath } from '../create-program/shared'; import type { TSESTreeOptions } from '../parser-options'; @@ -21,7 +21,7 @@ const log = debug( ); let TSCONFIG_MATCH_CACHE: ExpiringCache | null; -let TSSERVER_PROJECT_SERVICE: TypeScriptProjectService | null = null; +let TSSERVER_PROJECT_SERVICE: ProjectServiceSettings | null = null; // NOTE - we intentionally use "unnecessary" `?.` here because in TS<5.3 this enum doesn't exist // This object exists so we can centralize these for tracking and so we don't proliferate these across the file @@ -80,11 +80,14 @@ export function createParseSettings( errorOnTypeScriptSyntacticAndSemanticIssues: false, errorOnUnknownASTType: options.errorOnUnknownASTType === true, EXPERIMENTAL_projectService: - (options.EXPERIMENTAL_useProjectService === true && + (options.EXPERIMENTAL_useProjectService && process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER !== 'false') || (process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER === 'true' && options.EXPERIMENTAL_useProjectService !== false) - ? (TSSERVER_PROJECT_SERVICE ??= createProjectService(jsDocParsingMode)) + ? (TSSERVER_PROJECT_SERVICE ??= createProjectService( + options.EXPERIMENTAL_useProjectService, + jsDocParsingMode, + )) : undefined, EXPERIMENTAL_useSourceOfProjectReferenceRedirect: options.EXPERIMENTAL_useSourceOfProjectReferenceRedirect === true, diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/typescript-estree/src/parseSettings/index.ts index 352798be158f..6aca7a863aae 100644 --- a/packages/typescript-estree/src/parseSettings/index.ts +++ b/packages/typescript-estree/src/parseSettings/index.ts @@ -1,6 +1,6 @@ import type * as ts from 'typescript'; -import type * as tsserverlibrary from 'typescript/lib/tsserverlibrary'; +import type { ProjectServiceSettings } from '../create-program/createProjectService'; import type { CanonicalPath } from '../create-program/shared'; import type { TSESTree } from '../ts-estree'; import type { CacheLike } from './ExpiringCache'; @@ -67,9 +67,7 @@ export interface MutableParseSettings { /** * Experimental: TypeScript server to power program creation. */ - EXPERIMENTAL_projectService: - | tsserverlibrary.server.ProjectService - | undefined; + EXPERIMENTAL_projectService: ProjectServiceSettings | undefined; /** * Whether TS should use the source files for referenced projects instead of the compiled .d.ts files. diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index badd40ae8cfa..e86be6d50996 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -101,6 +101,16 @@ interface ParseOptions { suppressDeprecatedPropertyWarnings?: boolean; } +/** + * Granular options to configure the project service. + */ +export interface ProjectServiceOptions { + /** + * Globs of files to allow running with the default inferred project settings. + */ + allowDefaultProjectForFiles?: string[]; +} + interface ParseAndGenerateServicesOptions extends ParseOptions { /** * Causes the parser to error if the TypeScript compiler returns any unexpected syntax/semantic errors. @@ -114,7 +124,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * @see https://github.com/typescript-eslint/typescript-eslint/issues/6575 */ - EXPERIMENTAL_useProjectService?: boolean; + EXPERIMENTAL_useProjectService?: boolean | ProjectServiceOptions; /** * ***EXPERIMENTAL FLAG*** - Use this at your own risk. diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index aeef8d1e45ff..08c29892e220 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -53,6 +53,7 @@ function getProgramAndAST( const fromProjectService = useProgramFromProjectService( parseSettings.EXPERIMENTAL_projectService, parseSettings, + hasFullTypeInformation, ); if (fromProjectService) { return fromProjectService; diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index 59f6b0fe50ab..d49acd55e095 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -1,26 +1,44 @@ -import path from 'path'; -import type { server } from 'typescript/lib/tsserverlibrary'; +import { minimatch } from 'minimatch'; import { createProjectProgram } from './create-program/createProjectProgram'; -import { type ASTAndDefiniteProgram } from './create-program/shared'; +import type { ProjectServiceSettings } from './create-program/createProjectService'; +import { + type ASTAndDefiniteProgram, + ensureAbsolutePath, + getCanonicalFileName, +} from './create-program/shared'; import type { MutableParseSettings } from './parseSettings'; export function useProgramFromProjectService( - projectService: server.ProjectService, + { allowDefaultProjectForFiles, service }: ProjectServiceSettings, parseSettings: Readonly, + hasFullTypeInformation: boolean, ): ASTAndDefiniteProgram | undefined { - const opened = projectService.openClientFile( - absolutify(parseSettings.filePath), + const filePath = getCanonicalFileName(parseSettings.filePath); + + const opened = service.openClientFile( + ensureAbsolutePath(filePath, service.host.getCurrentDirectory()), parseSettings.codeFullText, /* scriptKind */ undefined, parseSettings.tsconfigRootDir, ); - if (!opened.configFileName) { - return undefined; + + if (hasFullTypeInformation) { + if (opened.configFileName) { + if (filePathMatchedBy(filePath, allowDefaultProjectForFiles)) { + throw new Error( + `${filePath} was included by allowDefaultProjectForFiles but also was found in the project service. Consider removing it from allowDefaultProjectForFiles.`, + ); + } + } else if (!filePathMatchedBy(filePath, allowDefaultProjectForFiles)) { + throw new Error( + `${filePath} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProjectForFiles.`, + ); + } } - const scriptInfo = projectService.getScriptInfo(parseSettings.filePath); - const program = projectService + const scriptInfo = service.getScriptInfo(filePath); + const program = service .getDefaultProjectForFile(scriptInfo!.fileName, true)! .getLanguageService(/*ensureSynchronized*/ true) .getProgram(); @@ -30,10 +48,13 @@ export function useProgramFromProjectService( } return createProjectProgram(parseSettings, [program]); +} - function absolutify(filePath: string): string { - return path.isAbsolute(filePath) - ? filePath - : path.join(projectService.host.getCurrentDirectory(), filePath); - } +function filePathMatchedBy( + filePath: string, + allowDefaultProjectForFiles: string[] | undefined, +): boolean { + return !!allowDefaultProjectForFiles?.some(pattern => + minimatch(filePath, pattern), + ); } diff --git a/packages/typescript-estree/tests/lib/createProjectService.test.ts b/packages/typescript-estree/tests/lib/createProjectService.test.ts index f6f6d117e3bc..9541dcd43942 100644 --- a/packages/typescript-estree/tests/lib/createProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/createProjectService.test.ts @@ -1,7 +1,21 @@ import { createProjectService } from '../../src/create-program/createProjectService'; describe('createProjectService', () => { - it('does not crash', () => { - createProjectService(); + it('sets allowDefaultProjectForFiles when options.allowDefaultProjectForFiles is defined', () => { + const allowDefaultProjectForFiles = ['./*.js']; + const settings = createProjectService( + { allowDefaultProjectForFiles }, + undefined, + ); + + expect(settings.allowDefaultProjectForFiles).toBe( + allowDefaultProjectForFiles, + ); + }); + + it('does not set allowDefaultProjectForFiles when options.allowDefaultProjectForFiles is not defined', () => { + const settings = createProjectService(undefined, undefined); + + expect(settings.allowDefaultProjectForFiles).toBeUndefined(); }); }); diff --git a/packages/typescript-estree/tests/lib/semanticInfo.test.ts b/packages/typescript-estree/tests/lib/semanticInfo.test.ts index 8502e70180c4..d580249079ab 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.test.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.test.ts @@ -337,7 +337,24 @@ describe('semanticInfo', () => { }); } - it('file not in provided program instance(s)', () => { + it('file not in single provided program instance should throw', () => { + const filename = 'non-existent-file.ts'; + const program = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json')); + const options = createOptions(filename); + const optionsWithSingleProgram = { + ...options, + programs: [program], + }; + expect(() => + parseAndGenerateServices('const foo = 5;', optionsWithSingleProgram), + ).toThrow( + process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER === 'true' + ? `${filename} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProjectForFiles.` + : `The file was not found in any of the provided program instance(s): ${filename}`, + ); + }); + + it('file not in multiple provided program instances should throw a program instance error', () => { const filename = 'non-existent-file.ts'; const program1 = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json')); const options = createOptions(filename); @@ -348,7 +365,9 @@ describe('semanticInfo', () => { expect(() => parseAndGenerateServices('const foo = 5;', optionsWithSingleProgram), ).toThrow( - `The file was not found in any of the provided program instance(s): ${filename}`, + process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER === 'true' + ? `${filename} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProjectForFiles.` + : `The file was not found in any of the provided program instance(s): ${filename}`, ); const program2 = createProgram(path.join(FIXTURES_DIR, 'tsconfig.json')); @@ -359,7 +378,9 @@ describe('semanticInfo', () => { expect(() => parseAndGenerateServices('const foo = 5;', optionsWithMultiplePrograms), ).toThrow( - `The file was not found in any of the provided program instance(s): ${filename}`, + process.env.TYPESCRIPT_ESLINT_EXPERIMENTAL_TSSERVER === 'true' + ? `${filename} was not found by the project service. Consider either including it in the tsconfig.json or including it in allowDefaultProjectForFiles.` + : `The file was not found in any of the provided program instance(s): ${filename}`, ); }); diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md index 5d8d3c74818e..6b56fd026f3e 100644 --- a/packages/utils/CHANGELOG.md +++ b/packages/utils/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/utils + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/utils diff --git a/packages/utils/package.json b/packages/utils/package.json index fe16a2af4aa3..3c1a45b81782 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/utils", - "version": "6.15.0", + "version": "6.16.0", "description": "Utilities for working with TypeScript + ESLint together", "files": [ "dist", @@ -68,16 +68,16 @@ "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", "semver": "^7.5.4" }, "peerDependencies": { "eslint": "^7.0.0 || ^8.0.0" }, "devDependencies": { - "@typescript-eslint/parser": "6.15.0", + "@typescript-eslint/parser": "6.16.0", "downlevel-dts": "*", "jest": "29.7.0", "prettier": "^3.0.3", diff --git a/packages/visitor-keys/CHANGELOG.md b/packages/visitor-keys/CHANGELOG.md index c22ed8645a08..7e81135bed4e 100644 --- a/packages/visitor-keys/CHANGELOG.md +++ b/packages/visitor-keys/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/visitor-keys + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/visitor-keys diff --git a/packages/visitor-keys/package.json b/packages/visitor-keys/package.json index 8ccfdb445a2e..0607e5cc02f2 100644 --- a/packages/visitor-keys/package.json +++ b/packages/visitor-keys/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/visitor-keys", - "version": "6.15.0", + "version": "6.16.0", "description": "Visitor keys used to help traverse the TypeScript-ESTree AST", "files": [ "dist", @@ -45,7 +45,7 @@ "typecheck": "tsc -p tsconfig.json --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/types": "6.16.0", "eslint-visitor-keys": "^3.4.1" }, "devDependencies": { diff --git a/packages/website-eslint/CHANGELOG.md b/packages/website-eslint/CHANGELOG.md index 2fbe0f4d768b..05e75d9d0357 100644 --- a/packages/website-eslint/CHANGELOG.md +++ b/packages/website-eslint/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + +**Note:** Version bump only for package @typescript-eslint/website-eslint + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package @typescript-eslint/website-eslint diff --git a/packages/website-eslint/package.json b/packages/website-eslint/package.json index 14d75a58ca12..beaa4c1c915a 100644 --- a/packages/website-eslint/package.json +++ b/packages/website-eslint/package.json @@ -1,6 +1,6 @@ { "name": "@typescript-eslint/website-eslint", - "version": "6.15.0", + "version": "6.16.0", "private": true, "description": "ESLint which works in browsers.", "files": [ @@ -23,16 +23,16 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/utils": "6.15.0" + "@typescript-eslint/types": "6.16.0", + "@typescript-eslint/utils": "6.16.0" }, "devDependencies": { - "@eslint/js": "8.53.0", - "@typescript-eslint/eslint-plugin": "6.15.0", - "@typescript-eslint/parser": "6.15.0", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@eslint/js": "8.56.0", + "@typescript-eslint/eslint-plugin": "6.16.0", + "@typescript-eslint/parser": "6.16.0", + "@typescript-eslint/scope-manager": "6.16.0", + "@typescript-eslint/typescript-estree": "6.16.0", + "@typescript-eslint/visitor-keys": "6.16.0", "esbuild": "~0.19.0", "eslint": "*", "esquery": "*", diff --git a/packages/website/CHANGELOG.md b/packages/website/CHANGELOG.md index 86708296acc5..7643ddd57b90 100644 --- a/packages/website/CHANGELOG.md +++ b/packages/website/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [6.16.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.15.0...v6.16.0) (2023-12-25) + + +### Features + +* **eslint-plugin:** deprecate formatting (meta.type: layout) rules ([#8073](https://github.com/typescript-eslint/typescript-eslint/issues/8073)) ([04dea84](https://github.com/typescript-eslint/typescript-eslint/commit/04dea84e8e934a415ec1381a90de3cde670d0dc3)) + +You can read about our [versioning strategy](https://main--typescript-eslint.netlify.app/users/versioning) and [releases](https://main--typescript-eslint.netlify.app/users/releases) on our website. + + + + + # [6.15.0](https://github.com/typescript-eslint/typescript-eslint/compare/v6.14.0...v6.15.0) (2023-12-18) **Note:** Version bump only for package website diff --git a/packages/website/blog/2023-07-09-announcing-typescript-eslint-v6.md b/packages/website/blog/2023-07-09-announcing-typescript-eslint-v6.md index a52e575a11a2..f1db265643da 100644 --- a/packages/website/blog/2023-07-09-announcing-typescript-eslint-v6.md +++ b/packages/website/blog/2023-07-09-announcing-typescript-eslint-v6.md @@ -481,10 +481,10 @@ console.log( Several rules were changed in significant enough ways to be considered breaking changes: - Previously deprecated rules are deleted ([chore(eslint-plugin): remove deprecated rules for v6](https://github.com/typescript-eslint/typescript-eslint/pull/6112)): - - `@typescript-eslint/no-duplicate-imports` - - `@typescript-eslint/no-implicit-any-catch` - - `@typescript-eslint/no-parameter-properties` - - `@typescript-eslint/sort-type-union-intersection-members` + - `@typescript-eslint/no-duplicate-imports`, replaced by `imports/no-duplicates` + - `@typescript-eslint/no-implicit-any-catch`, replaced by the TSConfig option [`useUnknownInCatchVariables`](https://www.typescriptlang.org/tsconfig#useUnknownInCatchVariables) + - `@typescript-eslint/no-parameter-properties`, replaced by `@typescript-eslint/parameter-properties` + - `@typescript-eslint/sort-type-union-intersection-members`, replaced by `@typescript-eslint/sort-type-constituents` - [feat(eslint-plugin): [prefer-nullish-coalescing]: add support for assignment expressions](https://github.com/typescript-eslint/typescript-eslint/pull/5234): Enhances the [`@typescript-eslint/prefer-nullish-coalescing`](https://typescript-eslint.io/prefer-nullish-coalescing) rule to also check `||=` expressions. - [feat(eslint-plugin): [prefer-optional-chain] use type checking for strict falsiness](https://github.com/typescript-eslint/typescript-eslint/pull/6240): Fixes edge case bugs in the [`@typescript-eslint/prefer-optional-chain`](https://typescript-eslint.io/prefer-optional-chain) rule around false positives, at the cost of making it require type information. - ✨ [feat(eslint-plugin): [restrict-plus-operands] change checkCompoundAssignments to skipCompoundAssignments](https://github.com/typescript-eslint/typescript-eslint/pull/7027): inverses the logical value of the option and renames it diff --git a/packages/website/blog/2023-12-25-deprecating-formatting-rules.md b/packages/website/blog/2023-12-25-deprecating-formatting-rules.md new file mode 100644 index 000000000000..439a8b4be14d --- /dev/null +++ b/packages/website/blog/2023-12-25-deprecating-formatting-rules.md @@ -0,0 +1,70 @@ +--- +authors: + - image_url: https://www.joshuakgoldberg.com/img/josh.jpg + name: Josh Goldberg + title: typescript-eslint Maintainer + url: https://github.com/JoshuaKGoldberg +description: We're following ESLint's lead in moving our formatting lint rules to the ESLint Stylistic project. +slug: deprecating-formatting-rules +tags: [formatter, formatting, prettier, style, stylistic] +title: Deprecating Formatting Rules +--- + +[ESLint recently announced their plan to deprecate their core formatting rules](https://eslint.org/blog/2023/10/deprecating-formatting-rules). +The [ESLint Stylistic](https://eslint.style) project has taken over maintenance of formatting rules. + +As a result, we in typescript-eslint are now able to deprecate our formatting rules as well. +We'll keep these deprecated rules available until our next major version. + + + +## Context: Formatting Rules + +The ESLint blog post thoroughly explains the history and tradeoffs of formatting rules. +See also [ESLint's 2020 Changes to Rule Policies blog post](https://eslint.org/blog/2020/05/changes-to-rules-policies/#what-are-the-changes) and our _[What About Formatting?](/linting/troubleshooting/formatting)_ docs. +The performance downsides of formatting rules are heightened when [linting with type information](/linting/typed-linting). + +## Timelines + +[v6.16.0](https://github.com/typescript-eslint/typescript-eslint/releases/tag/v6.16.0), released December 25th, 2023, marks the rules as deprecated. +Deprecation is only a documentation change. +Per semantic versioning, formatting-related rules will remain available for all releases of typescript-eslint in the current major version, v6. + +**Our next major version, v7, will remove all deprecated rules.** + +## Upgrading to ESLint Stylistic + +Although you can continue to use formatting rules in typescript-eslint for now, we don't plan on adding any new features or fixes to the rules. +You'll want to switch to using their equivalents from [ESLint Stylistic](https://eslint.style). + +See the [ESLint Stylistic > Getting Started](https://eslint.style/guide/getting-started) guide for how to switch formatting rules to that project. +The equivalent stylistic rules for deprecated typescript-eslint rules are summarized in this table: + +| typescript-eslint Rule | ESLint Stylistic Rule | +| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- | +| [`@typescript-eslint/block-spacing`](/rules/block-spacing) | [`@stylistic/block-spacing`](https://eslint.style/rules/ts/block-spacing) | +| [`@typescript-eslint/brace-style`](/rules/brace-style) | [`@stylistic/brace-style`](https://eslint.style/rules/ts/brace-style) | +| [`@typescript-eslint/comma-dangle`](/rules/comma-dangle) | [`@stylistic/comma-dangle`](https://eslint.style/rules/ts/comma-dangle) | +| [`@typescript-eslint/comma-spacing`](/rules/comma-spacing) | [`@stylistic/comma-spacing`](https://eslint.style/rules/ts/comma-spacing) | +| [`@typescript-eslint/func-call-spacing`](/rules/func-call-spacing) | [`@stylistic/func-call-spacing`](https://eslint.style/rules/ts/func-call-spacing) | +| [`@typescript-eslint/indent`](/rules/indent) | [`@stylistic/indent`](https://eslint.style/rules/ts/indent) | +| [`@typescript-eslint/key-spacing`](/rules/key-spacing) | [`@stylistic/key-spacing`](https://eslint.style/rules/ts/key-spacing) | +| [`@typescript-eslint/keyword-spacing`](/rules/keyword-spacing) | [`@stylistic/keyword-spacing`](https://eslint.style/rules/ts/keyword-spacing) | +| [`@typescript-eslint/lines-around-comment`](/rules/lines-around-comment) | [`@stylistic/lines-around-comment`](https://eslint.style/rules/ts/lines-around-comment) | +| [`@typescript-eslint/lines-between-class-members`](/rules/lines-between-class-members) | [`@stylistic/lines-between-class-members`](https://eslint.style/rules/ts/lines-between-class-members) | +| [`@typescript-eslint/member-delimiter-style`](/rules/member-delimiter-style) | [`@stylistic/member-delimiter-style`](https://eslint.style/rules/ts/member-delimiter-style) | +| [`@typescript-eslint/no-extra-parens`](/rules/no-extra-parens) | [`@stylistic/no-extra-parens`](https://eslint.style/rules/ts/no-extra-parens) | +| [`@typescript-eslint/no-extra-semi`](/rules/no-extra-semi) | [`@stylistic/no-extra-semi`](https://eslint.style/rules/ts/no-extra-semi) | +| [`@typescript-eslint/padding-line-between-statements`](/rules/padding-line-between-statements) | [`@stylistic/padding-line-between-statements`](https://eslint.style/rules/ts/padding-line-between-statements) | +| [`@typescript-eslint/quotes`](/rules/quotes) | [`@stylistic/quotes`](https://eslint.style/rules/ts/quotes) | +| [`@typescript-eslint/semi`](/rules/semi) | [`@stylistic/semi`](https://eslint.style/rules/ts/semi) | +| [`@typescript-eslint/space-before-blocks`](/rules/space-before-blocks) | [`@stylistic/space-before-blocks`](https://eslint.style/rules/ts/space-before-blocks) | +| [`@typescript-eslint/space-before-function-paren`](/rules/space-before-function-paren) | [`@stylistic/space-before-function-paren`](https://eslint.style/rules/ts/space-before-function-paren) | +| [`@typescript-eslint/space-infix-ops`](/rules/space-infix-ops) | [`@stylistic/space-infix-ops`](https://eslint.style/rules/ts/space-infix-ops) | +| [`@typescript-eslint/type-annotation-spacing`](/rules/type-annotation-spacing) | [`@stylistic/type-annotation-spacing`](https://eslint.style/rules/ts/type-annotation-spacing) | + +## Supporting typescript-eslint + +If you enjoyed this blog post and/or use typescript-eslint, please consider [supporting us on Open Collective](https://opencollective.com/typescript-eslint). +We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. +Thanks! 💖 diff --git a/packages/website/data/sponsors.json b/packages/website/data/sponsors.json index 2b2604e9524d..03aab330eae1 100644 --- a/packages/website/data/sponsors.json +++ b/packages/website/data/sponsors.json @@ -125,6 +125,13 @@ "totalDonations": 50000, "website": "https://skunk.team" }, + { + "id": "JetBrains", + "image": "https://images.opencollective.com/jetbrains/eb04ddc/logo.png", + "name": "JetBrains", + "totalDonations": 50000, + "website": "https://www.jetbrains.com/" + }, { "id": "Joe Alden", "image": "https://images.opencollective.com/joealden/44a6738/avatar.png", diff --git a/packages/website/package.json b/packages/website/package.json index b4087b600e4d..f3da86e3e98f 100644 --- a/packages/website/package.json +++ b/packages/website/package.json @@ -1,6 +1,6 @@ { "name": "website", - "version": "6.15.0", + "version": "6.16.0", "private": true, "scripts": { "build": "docusaurus build", @@ -24,8 +24,8 @@ "@docusaurus/theme-common": "~2.4.1", "@mdx-js/react": "1.6.22", "@prettier/sync": "*", - "@typescript-eslint/parser": "6.15.0", - "@typescript-eslint/website-eslint": "6.15.0", + "@typescript-eslint/parser": "6.16.0", + "@typescript-eslint/website-eslint": "6.16.0", "clsx": "^2.0.0", "eslint": "*", "json-schema": "^0.4.0", @@ -50,9 +50,9 @@ "@types/react": "*", "@types/react-helmet": "^6.1.6", "@types/react-router-dom": "^5.3.3", - "@typescript-eslint/eslint-plugin": "6.15.0", - "@typescript-eslint/rule-schema-to-typescript-types": "6.15.0", - "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/eslint-plugin": "6.16.0", + "@typescript-eslint/rule-schema-to-typescript-types": "6.16.0", + "@typescript-eslint/types": "6.16.0", "copy-webpack-plugin": "^11.0.0", "cross-fetch": "*", "globby": "^11.1.0", diff --git a/packages/website/plugins/generated-rule-docs.ts b/packages/website/plugins/generated-rule-docs.ts deleted file mode 100644 index 816df1635a4f..000000000000 --- a/packages/website/plugins/generated-rule-docs.ts +++ /dev/null @@ -1,505 +0,0 @@ -import prettier from '@prettier/sync'; -import pluginRules from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules'; -import { compile } from '@typescript-eslint/rule-schema-to-typescript-types'; -import * as fs from 'fs'; -import * as lz from 'lz-string'; -import type * as mdast from 'mdast'; -import { EOL } from 'os'; -import * as path from 'path'; -import type { Plugin } from 'unified'; -import type * as unist from 'unist'; - -/** - * Rules whose options schema generate annoyingly complex schemas. - * - * @remarks These need to be typed in manually in their .md docs file. - * @todo Get these schemas printing nicely in their .md docs files! - */ -const COMPLICATED_RULE_OPTIONS = new Set([ - 'member-ordering', - 'naming-convention', -]); -/** - * Rules that do funky things with their defaults and require special code - * rather than just JSON.stringify-ing their defaults blob - */ -const SPECIAL_CASE_DEFAULTS = new Map([ - // - ['ban-types', '[{ /* See below for default options */ }]'], -]); - -const prettierConfig = { - ...(prettier.resolveConfig(__filename) ?? {}), - filepath: path.join(__dirname, 'defaults.ts'), -}; - -const sourceUrlPrefix = - 'https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/'; - -const eslintPluginDirectory = path.resolve( - path.join(__dirname, '../../eslint-plugin'), -); - -const optionRegex = /option='(?