diff --git a/.github/ISSUE_TEMPLATE/06-bug-report-other.yaml b/.github/ISSUE_TEMPLATE/06-bug-report-other.yaml
index ee44e376f654..3eb5e066206b 100644
--- a/.github/ISSUE_TEMPLATE/06-bug-report-other.yaml
+++ b/.github/ISSUE_TEMPLATE/06-bug-report-other.yaml
@@ -20,7 +20,11 @@ body:
- label: I have [read the FAQ](https://typescript-eslint.io/linting/troubleshooting) and my problem is not listed.
required: true
- type: markdown
- id: complexity-note
+ attributes:
+ value: |
+ **All typescript-eslint bug reports need an isolated reproduction** we can clone locally and get running without other projects or existing knowledge of your project.
+ If you can't provide one, your report will likely be closed without action.
+ - type: markdown
attributes:
value: |
### Note For Complex Issues
diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml
index 202088e5b17a..ae557bfdd433 100644
--- a/.github/workflows/lock.yml
+++ b/.github/workflows/lock.yml
@@ -14,8 +14,9 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: dessant/lock-threads@v4
+ - uses: dessant/lock-threads@v5.0.1
with:
+ add-issue-labels: 'locked due to age'
github-token: ${{ github.token }}
issue-inactive-days: '7'
issue-lock-reason: 'resolved'
diff --git a/.github/workflows/pr-labels.yml b/.github/workflows/pr-labels.yml
new file mode 100644
index 000000000000..3ede15e78943
--- /dev/null
+++ b/.github/workflows/pr-labels.yml
@@ -0,0 +1,25 @@
+name: Pull Request Labels
+
+on:
+ pull_request:
+ types: [labeled, opened, synchronize, unlabeled]
+
+jobs:
+ label:
+ runs-on: ubuntu-latest
+ permissions:
+ issues: write
+ pull-requests: write
+ steps:
+ - id: changed-stable-configs
+ uses: tj-actions/changed-files@v44.5.2
+ with:
+ files: packages/{eslint-plugin,typescript-eslint}/src/configs/{recommended,stylistic}*
+ - if: steps.changed-stable-configs.outputs.any_changed == 'true'
+ uses: mheap/github-action-required-labels@v5.4.1
+ with:
+ add_comment: true
+ count: 1
+ labels: breaking change
+ message: '🤖 Beep boop! PRs that change our stable preset configs must be labeled with `breaking change`.'
+ mode: minimum
diff --git a/docs/Contributing.mdx b/docs/Contributing.mdx
index 67f28ca8c34c..062477b1fedc 100644
--- a/docs/Contributing.mdx
+++ b/docs/Contributing.mdx
@@ -16,6 +16,6 @@ If you're new to open source, you may also find the [How to Contribute to Open S
## Next Steps
-1. [Finding or opening an issue](./contributing/Issues.mdx): In the issue tab, find the pr currently tagged with `accepting prs` or create a new issue.
-2. [Setting up a local environment](./contributing/Local_Development.mdx): Let's learn how to set up the local environment to start development.
-3. [Making a PR](./contributing/Pull_Requests.mdx): you've got changes locally that address an issue, take a look at that topic.
+1. [Finding or opening an issue](./contributing/Issues.mdx): In the issue tab, finding or creating an issue to work on.
+2. [Setting up a local environment](./contributing/Local_Development.mdx): Learning how to set up the local environment to start development.
+3. [Making a PR](./contributing/Pull_Requests.mdx): Sending in your changes to resolve an accepted issue.
diff --git a/docs/contributing/Issues.mdx b/docs/contributing/Issues.mdx
index 879600ae5d81..6a2861dfbeb6 100644
--- a/docs/contributing/Issues.mdx
+++ b/docs/contributing/Issues.mdx
@@ -34,6 +34,13 @@ We've found in the past that they result in accidental ["licked cookie"](https:/
If an issue has been marked as `accepting prs` and an open PR does not exist, feel free to send a PR.
You don't need to ask for permission.
+## Finding Issues
+
+Consider searching through:
+
+1. [Unassigned user-facing marked as `accepting prs` and `good first issue`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22+label%3A%22accepting+prs%22+-label%3A%22repo+maintenance%22+no%3Aassignee): to find issues marked as good for a first-timer
+2. [Unassigned user-facing marked as `accepting prs` without `good first issue`](https://github.com/typescript-eslint/typescript-eslint/issues?q=is%3Aopen+is%3Aissue+label%3A%22accepting+prs%22+-label%3A%22good+first+issue%22+-label%3A%22repo+maintenance%22+no%3Aassignee): once you've finished a few issues, to find more intermediate-level issues
+
## Questions and Support Requests
The issue tracker is not an appropriate place for questions or support requests.
diff --git a/docs/contributing/Local_Development.mdx b/docs/contributing/Local_Development.mdx
index 725e9354b32e..ad9e201d22b6 100644
--- a/docs/contributing/Local_Development.mdx
+++ b/docs/contributing/Local_Development.mdx
@@ -61,23 +61,6 @@ You can run `yarn test` in any package to run its tests.
> [VS Code launch tasks](https://code.visualstudio.com/docs/editor/tasks) tasks are provided that allow [visual debugging](https://code.visualstudio.com/docs/editor/debugging) tests.
-#### Code Coverage
-
-We aim for 100% code coverage in all PRs when possible, except in the `website/` package.
-Coverage reports are generated locally whenever `yarn test` is run.
-
-The `codecov` bot should also comment on your PR with the percentage, as well as links to the line-by-line coverage of each file touched by your PR.
-
-#### Granular Unit Tests
-
-Most tests in most packages are set up as small, self-contained unit tests.
-We generally prefer that to keep tests and their failure reports granular.
-
-For rule tests we recommend, when reasonable:
-
-- Including both `valid` and `invalid` code changes in most PRs that affect rule behavior
-- Limiting to one error per `invalid` case
-
### Type Checking
All code should pass TypeScript type checking.
diff --git a/docs/contributing/Pull_Requests.mdx b/docs/contributing/Pull_Requests.mdx
index dd3a0e4f2d69..a0b9ad083b06 100644
--- a/docs/contributing/Pull_Requests.mdx
+++ b/docs/contributing/Pull_Requests.mdx
@@ -25,7 +25,26 @@ Please don't:
- Comment on a closed PR
- Reasoning: It is much easier for maintainers to not lose track of things if they are posted as issues. If you think there's a bug in typescript-eslint, the right way to ask is to [file a new issue](https://github.com/typescript-eslint/typescript-eslint/issues/new/choose). The issue templates include helpful & necessary practices such as making sure you're on the latest version of all our packages. You can provide the link to the relevant PR to add more context.
-### Raising a PR
+### Testing Changes
+
+#### Code Coverage
+
+We aim for 100% code coverage in all PRs when possible, except in the `website/` package.
+Coverage reports are generated locally whenever `yarn test` is run.
+
+The `codecov` bot also comments on each PR with its percentage, as well as links to the line-by-line coverage of each file touched by the PR.
+
+#### Granular Unit Tests
+
+Most tests in most packages are set up as small, self-contained unit tests.
+We generally prefer that to keep tests and their failure reports granular.
+
+For rule tests we recommend, when reasonable:
+
+- Including both `valid` and `invalid` code changes in most PRs that affect rule behavior
+- Limiting to one error per `invalid` case
+
+### Raising the PR
Once your changes are ready, you can raise a PR! 🙌
The title of your PR should match the following format:
@@ -84,6 +103,14 @@ Once you've addressed all our feedback by making code changes and/or started a f
Once the feedback is addressed, and the PR is approved, we'll ensure the branch is up to date with `main`, and merge it for you.
+#### Updating Over Time
+
+You generally don't need to keep merging commits from `main` into your PR branch.
+If you see merge conflicts or other intersections that worry you, then you can preemptively - but that's optional.
+
+If we think merge conflicts need to be resolved in order to merge and/or review a PR, we might do that for you as a courtesy _if_ we have time.
+If not, we may ask you to.
+
### Asking Questions
If you need help and/or have a question, posting a comment in the PR is a great way to do so.
diff --git a/docs/maintenance/Contributor_Tiers.mdx b/docs/maintenance/Contributor_Tiers.mdx
index fe554936d1cb..154ae4ee4fed 100644
--- a/docs/maintenance/Contributor_Tiers.mdx
+++ b/docs/maintenance/Contributor_Tiers.mdx
@@ -95,7 +95,10 @@ We treat both the creation and review of issues and PRs along the rough scale of
#6976
- , #6992
+ ,{' '}
+
+ #6992
+
@@ -106,7 +109,10 @@ We treat both the creation and review of issues and PRs along the rough scale of
#6780
- , #6910
+ ,{' '}
+
+ #6910
+
@@ -117,7 +123,10 @@ We treat both the creation and review of issues and PRs along the rough scale of
#6107
- , #6907
+ ,{' '}
+
+ #6907
+
@@ -128,7 +137,10 @@ We treat both the creation and review of issues and PRs along the rough scale of
#6084
- , #6777
+ ,{' '}
+
+ #6777
+
diff --git a/docs/maintenance/Releases.mdx b/docs/maintenance/Releases.mdx
index 59737a7683b2..12b9dd0bf82b 100644
--- a/docs/maintenance/Releases.mdx
+++ b/docs/maintenance/Releases.mdx
@@ -50,7 +50,7 @@ In parallel to the general PR flow of the major version:
In parallel to the shared config changes work, make sure to test out the beta version on popular community projects willing to try it out.
-1. Create a pinned issue offering to try out the new version's beta for consumers [example: [Try out v6 beta on various important community repos](https://github.com/typescript-eslint/typescript-eslint/issues/6760)]
+1. Create a pinned issue offering to try out the new version's beta for consumers [example: [Try out v8 beta on various influential community repos](https://github.com/typescript-eslint/typescript-eslint/issues/9141)]
- Ask each community project if they'd be interested in trying out the new version, such as in their Discord or on their issue tracker.
- Each community project that's indicated willingness to receive a PR should have one.
1. Once the proposed _Shared Config Changes_ are merged into the `v${major}` branch, send a draft PR to each project with the new beta version.
diff --git a/docs/maintenance/issues/Rule_Deprecations.mdx b/docs/maintenance/issues/Rule_Deprecations_And_Deletions.mdx
similarity index 59%
rename from docs/maintenance/issues/Rule_Deprecations.mdx
rename to docs/maintenance/issues/Rule_Deprecations_And_Deletions.mdx
index 1e89880390b6..34715e9e73c2 100644
--- a/docs/maintenance/issues/Rule_Deprecations.mdx
+++ b/docs/maintenance/issues/Rule_Deprecations_And_Deletions.mdx
@@ -1,6 +1,6 @@
---
-id: rule-deprecations
-title: Rule Deprecations
+id: rule-deprecations-and-deletions
+title: Rule Deprecations, Renames, And Deletions
---
Sometimes a rule that used to be 👍 does not age well and becomes 👎.
@@ -14,12 +14,12 @@ In these cases, we aim to remove the old rule with minimal user disruption.
## Filing the Issue
-Rule deprecations can be filed as a [new issue bypassing templates](https://github.com/typescript-eslint/typescript-eslint/issues/new).
+Rule deprecations and renames can be filed as a [new issue bypassing templates](https://github.com/typescript-eslint/typescript-eslint/issues/new).
Provide it an `## Overview` containing:
- The rule name & link to its documentation page
-- A clear explanation of why you believe it should be deprecated
+- A clear explanation of why you believe it should be deprecated and/or renamed
- Whether it exists in popular configs such as `eslint-config-airbnb-typescript` and `eslint-config-standard-with-typescript`
- Sourcegraph queries showing how often it appears in user configs
@@ -30,5 +30,8 @@ Provide it an `## Overview` containing:
1. In any minor/patch version, add [rule `meta` properties](https://eslint.org/docs/latest/developer-guide/working-with-rules#rule-basics):
- `deprecated: true`
- `replacedBy`, if applicable
-2. In the next major version, you may delete the rule
- - If the rule is relatively popular with users, consider leaving a documentation page as a tombstone pointing to the new relevant rule or docs (see [`camelcase`](/rules/camelcase/) as an example)
+2. Search through open issues and PRs, and update the name in them accordingly:
+ - Deletions: close them with a link to the issue and deprecation PR
+ - Renames: update their title and explicitly mention in a comment that the rule has been renamed
+3. In the next major version, you may delete the deprecated rule
+ - Leave a documentation page as a tombstone pointing to the new relevant rule or docs (see [`camelcase`](/rules/camelcase) as an example)
diff --git a/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx b/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx
index c184221d1e6f..15ae0340c358 100644
--- a/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx
+++ b/docs/maintenance/pull-requests/Dependency_Version_Upgrades.mdx
@@ -134,6 +134,7 @@ We generally start the process of supporting a new TypeScript version just after
- Whenever a PR is merged, change the respective heading's emoji from 🏗 to ✅
1. Create a PR with a title like `feat: update TypeScript to X.Y-rc` and the following changes:
- In the root `package.json`, add `|| X.Y.1-rc2` to the `devDependency` on `typescript`
+ - In the parser's `getLib`, update the `switch (target)` and its preceding comment as needed (see [#6782](https://github.com/typescript-eslint/typescript-eslint/pull/6782))
- Change the `SUPPORTED_TYPESCRIPT_VERSIONS` constant's `<` version to the next version of TypeScript
- Change the `SUPPORTED_PRERELEASE_RANGES` constant to equal `['X.Y.1-rc']`
- Rename and update `patches/typescript*` to the new TypeScript version
diff --git a/docs/packages/ESLint_Plugin.mdx b/docs/packages/ESLint_Plugin.mdx
index bf0777a005d3..263d7e4123a5 100644
--- a/docs/packages/ESLint_Plugin.mdx
+++ b/docs/packages/ESLint_Plugin.mdx
@@ -5,6 +5,8 @@ sidebar_label: eslint-plugin
# `@typescript-eslint/eslint-plugin`
+
+
> The TypeScript plugin for ESLint. ✨
:::info
diff --git a/docs/packages/ESLint_Plugin_TSLint.mdx b/docs/packages/ESLint_Plugin_TSLint.mdx
index f8f3d8dc8119..91cea06c45a0 100644
--- a/docs/packages/ESLint_Plugin_TSLint.mdx
+++ b/docs/packages/ESLint_Plugin_TSLint.mdx
@@ -5,6 +5,8 @@ sidebar_label: eslint-plugin-tslint
# `@typescript-eslint/eslint-plugin-tslint`
+
+
> ESLint plugin that allows running TSLint rules within ESLint to help you migrate from TSLint to ESLint. ✨
:::caution
diff --git a/docs/packages/Parser.mdx b/docs/packages/Parser.mdx
index 14ef7d19ff1d..c337e5655967 100644
--- a/docs/packages/Parser.mdx
+++ b/docs/packages/Parser.mdx
@@ -3,8 +3,13 @@ id: parser
sidebar_label: parser
---
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
# `@typescript-eslint/parser`
+
+
> An [ESLint parser](https://eslint.org/docs/user-guide/configuring/plugins#specifying-parser) used to parse TypeScript code into ESLint-compatible nodes, as well as provide backing TypeScript programs. ✨
This is necessary because TypeScript produces a different, incompatible AST format to the one that ESLint requires to work.
@@ -276,7 +281,25 @@ For an option that allows linting files outside of your TSConfig file(s), see [`
Specifies using TypeScript APIs to generate type information for rules.
It will automatically detect the TSConfig for each file (like `project: true`), and will also allow type information to be computed for JavaScript files without the `allowJs` compiler option (unlike `project: true`).
-```js
+
+
+
+```js title="eslint.config.js"
+export default [
+ {
+ languageOptions: {
+ parserOptions: {
+ projectService: true,
+ },
+ },
+ },
+];
+```
+
+
+
+
+```js title=".eslintrc.js"
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
@@ -285,6 +308,9 @@ module.exports = {
};
```
+
+
+
**This setting or [`project`](#project) are required to use [rules which require type information](../getting-started/Typed_Linting.mdx)**.
This option brings two main benefits over the older `project`:
@@ -383,6 +409,24 @@ declare function createProgram(
Example usage:
+
+
+
+```js title="eslint.config.js"
+import * as parser from '@typescript-eslint/parser';
+
+export default [
+ {
+ parserOptions: {
+ programs: [parser.createProgram('tsconfig.json')],
+ },
+ },
+];
+```
+
+
+
+
```js title=".eslintrc.js"
const parser = require('@typescript-eslint/parser');
@@ -392,3 +436,34 @@ module.exports = {
},
};
```
+
+
+
+
+### `withoutProjectParserOptions(parserOptions)`
+
+Removes options that prompt the parser to parse the project with type information.
+In other words, you can use this if you are invoking the parser directly, to ensure that one file will be parsed in isolation, which is much faster.
+
+This is useful in cases where you invoke the parser directly, such as in an ESLint plugin context.
+
+```ts
+declare function withoutProjectParserOptions(
+ options: TSESTreeOptions,
+): TSESTreeOptions;
+```
+
+Example usage:
+
+```js title="somePlugin.js"
+const parser = require('@typescript-eslint/parser');
+
+function parse(path, content, context) {
+ const contextParserOptions = context.languageOptions?.parserOptions ?? {};
+ const parserOptions =
+ parser.withoutProjectParserOptions(contextParserOptions);
+
+ // Do something with the cleaned-up options eventually, such as invoking the parser
+ parser.parseForESLint(content, parserOptions);
+}
+```
diff --git a/docs/packages/Rule_Tester.mdx b/docs/packages/Rule_Tester.mdx
index 25deac0e38b5..41b4c2cc3acd 100644
--- a/docs/packages/Rule_Tester.mdx
+++ b/docs/packages/Rule_Tester.mdx
@@ -7,6 +7,8 @@ import CodeBlock from '@theme/CodeBlock';
# `@typescript-eslint/rule-tester`
+
+
> A utility for testing ESLint rules
This is a fork of ESLint's built-in `RuleTester` to provide some better types and additional features for testing TypeScript rules.
diff --git a/docs/packages/Scope_Manager.mdx b/docs/packages/Scope_Manager.mdx
index cd33ac0fc751..0afbdd4690c7 100644
--- a/docs/packages/Scope_Manager.mdx
+++ b/docs/packages/Scope_Manager.mdx
@@ -5,6 +5,8 @@ sidebar_label: scope-manager
# `@typescript-eslint/scope-manager`
+
+
> A fork of [`eslint-scope`](https://github.com/eslint/eslint-scope), enhanced to support TypeScript functionality. ✨
A "scope analyser" traverses an AST and builds a model of how variables (and in our case, types) are defined and consumed by the source code.
diff --git a/docs/packages/TypeScript_ESLint.mdx b/docs/packages/TypeScript_ESLint.mdx
index 5e910850b80d..379c939c0be1 100644
--- a/docs/packages/TypeScript_ESLint.mdx
+++ b/docs/packages/TypeScript_ESLint.mdx
@@ -8,6 +8,8 @@ import TabItem from '@theme/TabItem';
# `typescript-eslint`
+
+
> Tooling which enables you to use TypeScript with ESLint
This package is the main entrypoint that you can use to consume our tooling with ESLint.
diff --git a/docs/packages/TypeScript_ESTree.mdx b/docs/packages/TypeScript_ESTree.mdx
index 7cf5d44c8eed..e8a27eb0f012 100644
--- a/docs/packages/TypeScript_ESTree.mdx
+++ b/docs/packages/TypeScript_ESTree.mdx
@@ -5,6 +5,8 @@ sidebar_label: typescript-estree
# `@typescript-eslint/typescript-estree`
+
+
> The underlying code used by [`@typescript-eslint/parser`](./Parser.mdx) that converts TypeScript source code into an ESTree-compatible form. ✨
This parser is designed to be generic and robust.
diff --git a/docs/packages/Utils.mdx b/docs/packages/Utils.mdx
index df05daa76909..ea7020466324 100644
--- a/docs/packages/Utils.mdx
+++ b/docs/packages/Utils.mdx
@@ -5,6 +5,8 @@ sidebar_label: utils
# `@typescript-eslint/utils`
+
+
> Utilities for working with TypeScript + ESLint together. ✨
This package contains public utilities for writing custom rules and plugins in TypeScript.
diff --git a/docs/troubleshooting/FAQ.mdx b/docs/troubleshooting/FAQ.mdx
index 578f359132e6..164ee17c32bc 100644
--- a/docs/troubleshooting/FAQ.mdx
+++ b/docs/troubleshooting/FAQ.mdx
@@ -115,9 +115,9 @@ These errors are caused by an ESLint config requesting type information be gener
- If you **do** want to lint the file with [type-aware linting](../getting-started/Typed_Linting.mdx):
- Check the `include` option of each of the TSConfigs that you provide to `parserOptions.project` - you must ensure that all files match an `include` glob, or else our tooling will not be able to find it.
- If the file is a `.cjs`, `.js`, or `.mjs` file, make sure [`allowJs`](https://www.typescriptlang.org/tsconfig#allowJs) is enabled.
- - If your file shouldn't be a part of one of your existing tsconfigs (for example, it is a script/tool local to the repo), then consider creating a new tsconfig (we advise calling it `tsconfig.eslint.json`) in your project root which lists this file in its `include`. For an example of this, you can check out the configuration we use in this repo:
- - [`tsconfig.eslint.json`](https://github.com/typescript-eslint/typescript-eslint/blob/main/tsconfig.eslint.json)
- - [`eslint.config.mjs`](https://github.com/typescript-eslint/typescript-eslint/blob/main/eslint.config.mjs)
+ - If your file shouldn't be a part of one of your existing tsconfigs (for example, it is a script/tool local to the repo), then consider creating a new tsconfig (we advise calling it `tsconfig.eslint.json`) in your project root which lists this file in its `include`. For an example of this, you can check out the configuration we previously used in this repo:
+ - [`tsconfig.eslint.json`](https://github.com/typescript-eslint/typescript-eslint/blob/958fecaef10a26792dc00e936e98cb19fd26d05f/tsconfig.eslint.json)
+ - [`eslint.config.mjs`](https://github.com/typescript-eslint/typescript-eslint/blob/958fecaef10a26792dc00e936e98cb19fd26d05f/.eslintrc.js)
diff --git a/docs/troubleshooting/Formatting.mdx b/docs/troubleshooting/Formatting.mdx
index c01fe4532dbd..814544d1daab 100644
--- a/docs/troubleshooting/Formatting.mdx
+++ b/docs/troubleshooting/Formatting.mdx
@@ -114,6 +114,11 @@ Per [ESLint's 2020 Changes to Rule Policies blog post](https://eslint.org/blog/2
We mirror the ESLint team's move away from _formatting_ and _stylistic_ rules.
With the exception of bug fixes, no new formatting- or stylistic-related pull requests will be accepted into typescript-eslint.
+:::note
+The [`stylistic` configurations](../users/Shared_Configurations.mdx#stylistic) are not deprecated or recommended-against.
+We'll continue to include those configs and their rules to help enforce TypeScript-related stylistic consistency for the foreseeable future.
+:::
+
## `eslint-stylistic`
The downside of using a comprehensive formatter for formatting is that it will strictly apply opinions to code.
diff --git a/docs/users/Shared_Configurations.mdx b/docs/users/Shared_Configurations.mdx
index 5b52521eea08..59c7e26cb66d 100644
--- a/docs/users/Shared_Configurations.mdx
+++ b/docs/users/Shared_Configurations.mdx
@@ -14,6 +14,9 @@ import TabItem from '@theme/TabItem';
## Getting Started
+See [Getting Started > Quickstart](../getting-started/Quickstart.mdx) first to set up your ESLint configuration file.
+[Packages > typescript-eslint](../packages/TypeScript_ESLint.mdx) includes more documentation on the `tseslint` helper.
+
### Projects Without Type Checking
If your project does not enable [typed linting](../getting-started/Typed_Linting.mdx), we suggest enabling the [`recommended`](#recommended) and [`stylistic`](#stylistic) configurations to start:
@@ -181,10 +184,15 @@ module.exports = {
Some rules also enabled in `recommended` default to more strict settings in this configuration.
See [`configs/strict.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict.ts) for the exact contents of this config.
-:::caution
+:::tip
We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict` only if a nontrivial percentage of its developers are highly proficient in TypeScript.
:::
+:::warning
+This configuration is not considered "stable" under Semantic Versioning (semver).
+Its enabled rules and/or their options may change outside of major version updates.
+:::
+
### `strict-type-checked`
Contains all of `recommended`, `recommended-type-checked`, and `strict`, along with additional strict rules that require type information.
@@ -212,10 +220,15 @@ module.exports = {
Some rules also enabled in `recommended-type-checked` default to more strict settings in this configuration.
See [`configs/strict-type-checked.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict-type-checked.ts) for the exact contents of this config.
-:::caution
+:::tip
We recommend a TypeScript project extend from `plugin:@typescript-eslint/strict-type-checked` only if a nontrivial percentage of its developers are highly proficient in TypeScript.
:::
+:::warning
+This configuration is not considered "stable" under Semantic Versioning (semver).
+Its enabled rules and/or their options may change outside of major version updates.
+:::
+
### `stylistic`
Rules considered to be best practice for modern TypeScript codebases, but that do not impact program logic.
@@ -290,6 +303,11 @@ We do not recommend TypeScript projects extend from `plugin:@typescript-eslint/a
Many rules conflict with each other and/or are intended to be configured per-project.
:::
+:::warning
+This configuration is not considered "stable" under Semantic Versioning (semver).
+Its enabled rules and/or their options may change outside of major version updates.
+:::
+
### `base`
A minimal ruleset that sets only the required parser and plugin options needed to run typescript-eslint.
@@ -363,6 +381,11 @@ module.exports = {
+:::warning
+This configuration is not considered "stable" under Semantic Versioning (semver).
+Its enabled rules and/or their options may change outside of major version updates.
+:::
+
### `eslint-recommended`
This ruleset is meant to be used after extending `eslint:recommended`.
@@ -424,6 +447,11 @@ module.exports = {
See [`configs/strict-type-checked-only.ts`](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/src/configs/strict-type-checked-only.ts) for the exact contents of this config.
+:::warning
+This configuration is not considered "stable" under Semantic Versioning (semver).
+Its enabled rules and/or their options may change outside of major version updates.
+:::
+
### `stylistic-type-checked-only`
A version of `stylistic` that _only_ contains type-checked rules and disables of any corresponding core ESLint rules.
diff --git a/eslint.config.mjs b/eslint.config.mjs
index b313a874d5de..487d8c4d6492 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -97,9 +97,8 @@ export default tseslint.config(
// make sure we're not leveraging any deprecated APIs
'deprecation/deprecation': 'error',
- // TODO(#7130): Investigate changing these in or removing these from presets
+ // TODO: https://github.com/typescript-eslint/typescript-eslint/issues/8538
'@typescript-eslint/no-confusing-void-expression': 'off',
- '@typescript-eslint/prefer-string-starts-ends-with': 'off',
//
// our plugin :D
@@ -136,6 +135,12 @@ export default tseslint.config(
allowBitwiseExpressions: true,
},
],
+ '@typescript-eslint/prefer-string-starts-ends-with': [
+ 'error',
+ {
+ allowSingleElementEquality: 'always',
+ },
+ ],
'@typescript-eslint/unbound-method': 'off',
'@typescript-eslint/restrict-template-expressions': [
'error',
diff --git a/package.json b/package.json
index 5a9a8ffdc559..5c0303b2ea20 100644
--- a/package.json
+++ b/package.json
@@ -112,7 +112,7 @@
"ncp": "^2.0.0",
"netlify": "^13.1.14",
"nx": "18.3.5",
- "prettier": "3.2.5",
+ "prettier": "3.3.0",
"pretty-format": "^29.7.0",
"rimraf": "^5.0.5",
"tmp": "^0.2.1",
diff --git a/packages/ast-spec/src/base/UnaryExpressionBase.ts b/packages/ast-spec/src/base/UnaryExpressionBase.ts
index feb681ccbc3c..6401c7e73fb2 100644
--- a/packages/ast-spec/src/base/UnaryExpressionBase.ts
+++ b/packages/ast-spec/src/base/UnaryExpressionBase.ts
@@ -1,10 +1,8 @@
-import type { UnaryExpression } from '../expression/UnaryExpression/spec';
-import type { LeftHandSideExpression } from '../unions/LeftHandSideExpression';
-import type { Literal } from '../unions/Literal';
+import type { Expression } from '../unions/Expression';
import type { BaseNode } from './BaseNode';
export interface UnaryExpressionBase extends BaseNode {
operator: string;
prefix: boolean;
- argument: LeftHandSideExpression | Literal | UnaryExpression;
+ argument: Expression;
}
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/1-TSESTree-Error.shot
index 79f1c74928b4..b2dfc1ae3ec8 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/1-TSESTree-Error.shot
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/1-TSESTree-Error.shot
@@ -1,3 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSDeclareFunction _error_ async TSESTree - Error 1`] = `"NO ERROR"`;
+exports[`AST Fixtures declaration TSDeclareFunction _error_ async TSESTree - Error 1`] = `
+"TSError
+> 1 | declare async function foo();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 'async' modifier cannot be used in an ambient context.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/3-Alignment-Error.shot
index 1f36cb0955fb..67e64f02351d 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/3-Alignment-Error.shot
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/async/snapshots/3-Alignment-Error.shot
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSDeclareFunction _error_ async Error Alignment 1`] = `"Babel errored but TSESTree didn't"`;
+exports[`AST Fixtures declaration TSDeclareFunction _error_ async Error Alignment 1`] = `"Both errored"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/1-TSESTree-Error.shot
index ca0dba2a0c34..c8a50d813ca8 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/1-TSESTree-Error.shot
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/1-TSESTree-Error.shot
@@ -1,3 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSDeclareFunction _error_ declare-with-body TSESTree - Error 1`] = `"NO ERROR"`;
+exports[`AST Fixtures declaration TSDeclareFunction _error_ declare-with-body TSESTree - Error 1`] = `
+"TSError
+> 1 | declare function foo(): void {};
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ An implementation cannot be declared in ambient contexts.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/3-Alignment-Error.shot
index 22b125b56439..5bb326776847 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/3-Alignment-Error.shot
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/snapshots/3-Alignment-Error.shot
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSDeclareFunction _error_ declare-with-body Error Alignment 1`] = `"Babel errored but TSESTree didn't"`;
+exports[`AST Fixtures declaration TSDeclareFunction _error_ declare-with-body Error Alignment 1`] = `"Both errored"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/fixture.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/fixture.ts
new file mode 100644
index 000000000000..3bc9eccf0977
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/fixture.ts
@@ -0,0 +1,3 @@
+declare module "x" {
+ function* foo(): any;
+}
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/1-TSESTree-Error.shot
new file mode 100644
index 000000000000..804b5bd1e90f
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/1-TSESTree-Error.shot
@@ -0,0 +1,10 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-ambient TSESTree - Error 1`] = `
+"TSError
+ 1 | declare module "x" {
+> 2 | function* foo(): any;
+ | ^^^^^^^^^^^^^^^^^^^^^ A function signature cannot be declared as a generator.
+ 3 | }
+ 4 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/2-Babel-Error.shot
new file mode 100644
index 000000000000..a91598605cdc
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/2-Babel-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-ambient Babel - Error 1`] = `"NO ERROR"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/3-Alignment-Error.shot
new file mode 100644
index 000000000000..9a14b2e1b4b2
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/snapshots/3-Alignment-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-ambient Error Alignment 1`] = `"TSESTree errored but Babel didn't"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/fixture.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/fixture.ts
new file mode 100644
index 000000000000..b3985fb6a6e5
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/fixture.ts
@@ -0,0 +1,2 @@
+function* foo(): any;
+function* foo(): any {}
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/1-TSESTree-Error.shot
new file mode 100644
index 000000000000..50e0462fd03e
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/1-TSESTree-Error.shot
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-overload TSESTree - Error 1`] = `
+"TSError
+> 1 | function* foo(): any;
+ | ^^^^^^^^^^^^^^^^^^^^^ A function signature cannot be declared as a generator.
+ 2 | function* foo(): any {}
+ 3 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/2-Babel-Error.shot
new file mode 100644
index 000000000000..bf3d8c4f43d0
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/2-Babel-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-overload Babel - Error 1`] = `"NO ERROR"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/3-Alignment-Error.shot
new file mode 100644
index 000000000000..6c2cab494caa
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator-overload/snapshots/3-Alignment-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator-overload Error Alignment 1`] = `"TSESTree errored but Babel didn't"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/fixture.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/fixture.ts
similarity index 100%
rename from packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/fixture.ts
rename to packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/fixture.ts
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/1-TSESTree-Error.shot
new file mode 100644
index 000000000000..f5f1b9e07530
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/1-TSESTree-Error.shot
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator TSESTree - Error 1`] = `
+"TSError
+> 1 | declare function* foo();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^ Generators are not allowed in an ambient context.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/2-Babel-Error.shot
new file mode 100644
index 000000000000..8cac9a65578f
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/2-Babel-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator Babel - Error 1`] = `"NO ERROR"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/3-Alignment-Error.shot
new file mode 100644
index 000000000000..c04e69e4e12f
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/_error_/generator/snapshots/3-Alignment-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction _error_ generator Error Alignment 1`] = `"TSESTree errored but Babel didn't"`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/fixture.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/fixture.ts
new file mode 100644
index 000000000000..b7a7f4a7cd32
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/fixture.ts
@@ -0,0 +1,3 @@
+declare module 'x' {
+ async function foo(): any;
+}
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/1-TSESTree-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/1-TSESTree-AST.shot
new file mode 100644
index 000000000000..7d2ab1f0cd84
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/1-TSESTree-AST.shot
@@ -0,0 +1,94 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient TSESTree - AST 1`] = `
+Program {
+ type: "Program",
+ body: [
+ TSModuleDeclaration {
+ type: "TSModuleDeclaration",
+ body: TSModuleBlock {
+ type: "TSModuleBlock",
+ body: [
+ TSDeclareFunction {
+ type: "TSDeclareFunction",
+ async: true,
+ declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ decorators: [],
+ name: "foo",
+ optional: false,
+
+ range: [38, 41],
+ loc: {
+ start: { column: 17, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [45, 48],
+ loc: {
+ start: { column: 24, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [43, 48],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [23, 49],
+ loc: {
+ start: { column: 2, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+
+ range: [19, 51],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ declare: true,
+ global: false,
+ id: Literal {
+ type: "Literal",
+ raw: "'x'",
+ value: "x",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ kind: "module",
+
+ range: [0, 51],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ ],
+ sourceType: "script",
+
+ range: [0, 52],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 4 },
+ },
+}
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/2-TSESTree-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/2-TSESTree-Tokens.shot
new file mode 100644
index 000000000000..6057be3fa444
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/2-TSESTree-Tokens.shot
@@ -0,0 +1,136 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient TSESTree - Tokens 1`] = `
+[
+ Identifier {
+ type: "Identifier",
+ value: "declare",
+
+ range: [0, 7],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 7, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "module",
+
+ range: [8, 14],
+ loc: {
+ start: { column: 8, line: 1 },
+ end: { column: 14, line: 1 },
+ },
+ },
+ String {
+ type: "String",
+ value: "'x'",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "{",
+
+ range: [19, 20],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 20, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [23, 28],
+ loc: {
+ start: { column: 2, line: 2 },
+ end: { column: 7, line: 2 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [29, 37],
+ loc: {
+ start: { column: 8, line: 2 },
+ end: { column: 16, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [38, 41],
+ loc: {
+ start: { column: 17, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [41, 42],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 21, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [42, 43],
+ loc: {
+ start: { column: 21, line: 2 },
+ end: { column: 22, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [43, 44],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 23, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [45, 48],
+ loc: {
+ start: { column: 24, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ";",
+
+ range: [48, 49],
+ loc: {
+ start: { column: 27, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "}",
+
+ range: [50, 51],
+ loc: {
+ start: { column: 0, line: 3 },
+ end: { column: 1, line: 3 },
+ },
+ },
+]
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/3-Babel-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/3-Babel-AST.shot
new file mode 100644
index 000000000000..c7ec3ee7ecc0
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/3-Babel-AST.shot
@@ -0,0 +1,89 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient Babel - AST 1`] = `
+Program {
+ type: "Program",
+ body: [
+ TSModuleDeclaration {
+ type: "TSModuleDeclaration",
+ body: TSModuleBlock {
+ type: "TSModuleBlock",
+ body: [
+ TSDeclareFunction {
+ type: "TSDeclareFunction",
+ async: true,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ name: "foo",
+
+ range: [38, 41],
+ loc: {
+ start: { column: 17, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [45, 48],
+ loc: {
+ start: { column: 24, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [43, 48],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [23, 49],
+ loc: {
+ start: { column: 2, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+
+ range: [19, 51],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ declare: true,
+ id: Literal {
+ type: "Literal",
+ raw: "'x'",
+ value: "x",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+
+ range: [0, 51],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ ],
+ sourceType: "script",
+
+ range: [0, 52],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 4 },
+ },
+}
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/4-Babel-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/4-Babel-Tokens.shot
new file mode 100644
index 000000000000..d78930b42a75
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/4-Babel-Tokens.shot
@@ -0,0 +1,136 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient Babel - Tokens 1`] = `
+[
+ Identifier {
+ type: "Identifier",
+ value: "declare",
+
+ range: [0, 7],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 7, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "module",
+
+ range: [8, 14],
+ loc: {
+ start: { column: 8, line: 1 },
+ end: { column: 14, line: 1 },
+ },
+ },
+ String {
+ type: "String",
+ value: "'x'",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "{",
+
+ range: [19, 20],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 20, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [23, 28],
+ loc: {
+ start: { column: 2, line: 2 },
+ end: { column: 7, line: 2 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [29, 37],
+ loc: {
+ start: { column: 8, line: 2 },
+ end: { column: 16, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [38, 41],
+ loc: {
+ start: { column: 17, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [41, 42],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 21, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [42, 43],
+ loc: {
+ start: { column: 21, line: 2 },
+ end: { column: 22, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [43, 44],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 23, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [45, 48],
+ loc: {
+ start: { column: 24, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ";",
+
+ range: [48, 49],
+ loc: {
+ start: { column: 27, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "}",
+
+ range: [50, 51],
+ loc: {
+ start: { column: 0, line: 3 },
+ end: { column: 1, line: 3 },
+ },
+ },
+]
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/5-AST-Alignment-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/5-AST-Alignment-AST.shot
new file mode 100644
index 000000000000..435ae1de0ade
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/5-AST-Alignment-AST.shot
@@ -0,0 +1,98 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient AST Alignment - AST 1`] = `
+"Snapshot Diff:
+- TSESTree
++ Babel
+
+ Program {
+ type: 'Program',
+ body: Array [
+ TSModuleDeclaration {
+ type: 'TSModuleDeclaration',
+ body: TSModuleBlock {
+ type: 'TSModuleBlock',
+ body: Array [
+ TSDeclareFunction {
+ type: 'TSDeclareFunction',
+ async: true,
+- declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: 'Identifier',
+- decorators: Array [],
+ name: 'foo',
+- optional: false,
+
+ range: [38, 41],
+ loc: {
+ start: { column: 17, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ params: Array [],
+ returnType: TSTypeAnnotation {
+ type: 'TSTypeAnnotation',
+ typeAnnotation: TSAnyKeyword {
+ type: 'TSAnyKeyword',
+
+ range: [45, 48],
+ loc: {
+ start: { column: 24, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [43, 48],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+
+ range: [23, 49],
+ loc: {
+ start: { column: 2, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+
+ range: [19, 51],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ declare: true,
+- global: false,
+ id: Literal {
+ type: 'Literal',
+ raw: '\\'x\\'',
+ value: 'x',
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+- kind: 'module',
+
+ range: [0, 51],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 1, line: 3 },
+ },
+ },
+ ],
+ sourceType: 'script',
+
+ range: [0, 52],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 4 },
+ },
+ }"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/6-AST-Alignment-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/6-AST-Alignment-Tokens.shot
similarity index 52%
rename from packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/6-AST-Alignment-Tokens.shot
rename to packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/6-AST-Alignment-Tokens.shot
index 0c5870a8a61e..7dbd5a907254 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/6-AST-Alignment-Tokens.shot
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-ambient/snapshots/6-AST-Alignment-Tokens.shot
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSDeclareFunction generator AST Alignment - Token 1`] = `
+exports[`AST Fixtures declaration TSDeclareFunction async-ambient AST Alignment - Token 1`] = `
"Snapshot Diff:
Compared values have no visual difference."
`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/fixture.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/fixture.ts
new file mode 100644
index 000000000000..31dd56160e4c
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/fixture.ts
@@ -0,0 +1,2 @@
+async function foo(): any;
+async function foo(): any {}
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/1-TSESTree-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/1-TSESTree-AST.shot
new file mode 100644
index 000000000000..325d2fb0435a
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/1-TSESTree-AST.shot
@@ -0,0 +1,114 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload TSESTree - AST 1`] = `
+Program {
+ type: "Program",
+ body: [
+ TSDeclareFunction {
+ type: "TSDeclareFunction",
+ async: true,
+ declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ decorators: [],
+ name: "foo",
+ optional: false,
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [22, 25],
+ loc: {
+ start: { column: 22, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [20, 25],
+ loc: {
+ start: { column: 20, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [0, 26],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 26, line: 1 },
+ },
+ },
+ FunctionDeclaration {
+ type: "FunctionDeclaration",
+ async: true,
+ body: BlockStatement {
+ type: "BlockStatement",
+ body: [],
+
+ range: [53, 55],
+ loc: {
+ start: { column: 26, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ decorators: [],
+ name: "foo",
+ optional: false,
+
+ range: [42, 45],
+ loc: {
+ start: { column: 15, line: 2 },
+ end: { column: 18, line: 2 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [49, 52],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [47, 52],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [27, 55],
+ loc: {
+ start: { column: 0, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+ sourceType: "script",
+
+ range: [0, 56],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 3 },
+ },
+}
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/2-TSESTree-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/2-TSESTree-Tokens.shot
new file mode 100644
index 000000000000..213de06b48f9
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/2-TSESTree-Tokens.shot
@@ -0,0 +1,176 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload TSESTree - Tokens 1`] = `
+[
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [0, 5],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 5, line: 1 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [6, 14],
+ loc: {
+ start: { column: 6, line: 1 },
+ end: { column: 14, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [18, 19],
+ loc: {
+ start: { column: 18, line: 1 },
+ end: { column: 19, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [19, 20],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 20, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [20, 21],
+ loc: {
+ start: { column: 20, line: 1 },
+ end: { column: 21, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [22, 25],
+ loc: {
+ start: { column: 22, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ";",
+
+ range: [25, 26],
+ loc: {
+ start: { column: 25, line: 1 },
+ end: { column: 26, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [27, 32],
+ loc: {
+ start: { column: 0, line: 2 },
+ end: { column: 5, line: 2 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [33, 41],
+ loc: {
+ start: { column: 6, line: 2 },
+ end: { column: 14, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [42, 45],
+ loc: {
+ start: { column: 15, line: 2 },
+ end: { column: 18, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [45, 46],
+ loc: {
+ start: { column: 18, line: 2 },
+ end: { column: 19, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [46, 47],
+ loc: {
+ start: { column: 19, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [47, 48],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 21, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [49, 52],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "{",
+
+ range: [53, 54],
+ loc: {
+ start: { column: 26, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "}",
+
+ range: [54, 55],
+ loc: {
+ start: { column: 27, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+]
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/3-Babel-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/3-Babel-AST.shot
new file mode 100644
index 000000000000..09174cb2b0e4
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/3-Babel-AST.shot
@@ -0,0 +1,108 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload Babel - AST 1`] = `
+Program {
+ type: "Program",
+ body: [
+ TSDeclareFunction {
+ type: "TSDeclareFunction",
+ async: true,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ name: "foo",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [22, 25],
+ loc: {
+ start: { column: 22, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [20, 25],
+ loc: {
+ start: { column: 20, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [0, 26],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 26, line: 1 },
+ },
+ },
+ FunctionDeclaration {
+ type: "FunctionDeclaration",
+ async: true,
+ body: BlockStatement {
+ type: "BlockStatement",
+ body: [],
+
+ range: [53, 55],
+ loc: {
+ start: { column: 26, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: "Identifier",
+ name: "foo",
+
+ range: [42, 45],
+ loc: {
+ start: { column: 15, line: 2 },
+ end: { column: 18, line: 2 },
+ },
+ },
+ params: [],
+ returnType: TSTypeAnnotation {
+ type: "TSTypeAnnotation",
+ typeAnnotation: TSAnyKeyword {
+ type: "TSAnyKeyword",
+
+ range: [49, 52],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [47, 52],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [27, 55],
+ loc: {
+ start: { column: 0, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+ sourceType: "script",
+
+ range: [0, 56],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 3 },
+ },
+}
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/4-Babel-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/4-Babel-Tokens.shot
new file mode 100644
index 000000000000..ca4d328c84d9
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/4-Babel-Tokens.shot
@@ -0,0 +1,176 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload Babel - Tokens 1`] = `
+[
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [0, 5],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 5, line: 1 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [6, 14],
+ loc: {
+ start: { column: 6, line: 1 },
+ end: { column: 14, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [18, 19],
+ loc: {
+ start: { column: 18, line: 1 },
+ end: { column: 19, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [19, 20],
+ loc: {
+ start: { column: 19, line: 1 },
+ end: { column: 20, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [20, 21],
+ loc: {
+ start: { column: 20, line: 1 },
+ end: { column: 21, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [22, 25],
+ loc: {
+ start: { column: 22, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ";",
+
+ range: [25, 26],
+ loc: {
+ start: { column: 25, line: 1 },
+ end: { column: 26, line: 1 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "async",
+
+ range: [27, 32],
+ loc: {
+ start: { column: 0, line: 2 },
+ end: { column: 5, line: 2 },
+ },
+ },
+ Keyword {
+ type: "Keyword",
+ value: "function",
+
+ range: [33, 41],
+ loc: {
+ start: { column: 6, line: 2 },
+ end: { column: 14, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "foo",
+
+ range: [42, 45],
+ loc: {
+ start: { column: 15, line: 2 },
+ end: { column: 18, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "(",
+
+ range: [45, 46],
+ loc: {
+ start: { column: 18, line: 2 },
+ end: { column: 19, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ")",
+
+ range: [46, 47],
+ loc: {
+ start: { column: 19, line: 2 },
+ end: { column: 20, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: ":",
+
+ range: [47, 48],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 21, line: 2 },
+ },
+ },
+ Identifier {
+ type: "Identifier",
+ value: "any",
+
+ range: [49, 52],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "{",
+
+ range: [53, 54],
+ loc: {
+ start: { column: 26, line: 2 },
+ end: { column: 27, line: 2 },
+ },
+ },
+ Punctuator {
+ type: "Punctuator",
+ value: "}",
+
+ range: [54, 55],
+ loc: {
+ start: { column: 27, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+]
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/5-AST-Alignment-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/5-AST-Alignment-AST.shot
new file mode 100644
index 000000000000..2515ee9a01e1
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/5-AST-Alignment-AST.shot
@@ -0,0 +1,118 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload AST Alignment - AST 1`] = `
+"Snapshot Diff:
+- TSESTree
++ Babel
+
+ Program {
+ type: 'Program',
+ body: Array [
+ TSDeclareFunction {
+ type: 'TSDeclareFunction',
+ async: true,
+- declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: 'Identifier',
+- decorators: Array [],
+ name: 'foo',
+- optional: false,
+
+ range: [15, 18],
+ loc: {
+ start: { column: 15, line: 1 },
+ end: { column: 18, line: 1 },
+ },
+ },
+ params: Array [],
+ returnType: TSTypeAnnotation {
+ type: 'TSTypeAnnotation',
+ typeAnnotation: TSAnyKeyword {
+ type: 'TSAnyKeyword',
+
+ range: [22, 25],
+ loc: {
+ start: { column: 22, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [20, 25],
+ loc: {
+ start: { column: 20, line: 1 },
+ end: { column: 25, line: 1 },
+ },
+ },
+
+ range: [0, 26],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 26, line: 1 },
+ },
+ },
+ FunctionDeclaration {
+ type: 'FunctionDeclaration',
+ async: true,
+ body: BlockStatement {
+ type: 'BlockStatement',
+ body: Array [],
+
+ range: [53, 55],
+ loc: {
+ start: { column: 26, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+- declare: false,
+ expression: false,
+ generator: false,
+ id: Identifier {
+ type: 'Identifier',
+- decorators: Array [],
+ name: 'foo',
+- optional: false,
+
+ range: [42, 45],
+ loc: {
+ start: { column: 15, line: 2 },
+ end: { column: 18, line: 2 },
+ },
+ },
+ params: Array [],
+ returnType: TSTypeAnnotation {
+ type: 'TSTypeAnnotation',
+ typeAnnotation: TSAnyKeyword {
+ type: 'TSAnyKeyword',
+
+ range: [49, 52],
+ loc: {
+ start: { column: 22, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [47, 52],
+ loc: {
+ start: { column: 20, line: 2 },
+ end: { column: 25, line: 2 },
+ },
+ },
+
+ range: [27, 55],
+ loc: {
+ start: { column: 0, line: 2 },
+ end: { column: 28, line: 2 },
+ },
+ },
+ ],
+ sourceType: 'script',
+
+ range: [0, 56],
+ loc: {
+ start: { column: 0, line: 1 },
+ end: { column: 0, line: 3 },
+ },
+ }"
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/6-AST-Alignment-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/6-AST-Alignment-Tokens.shot
new file mode 100644
index 000000000000..b6b9fa4d737e
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/async-overload/snapshots/6-AST-Alignment-Tokens.shot
@@ -0,0 +1,6 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSDeclareFunction async-overload AST Alignment - Token 1`] = `
+"Snapshot Diff:
+Compared values have no visual difference."
+`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/1-TSESTree-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/1-TSESTree-AST.shot
deleted file mode 100644
index b621f52027bf..000000000000
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/1-TSESTree-AST.shot
+++ /dev/null
@@ -1,42 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AST Fixtures declaration TSDeclareFunction generator TSESTree - AST 1`] = `
-Program {
- type: "Program",
- body: [
- TSDeclareFunction {
- type: "TSDeclareFunction",
- async: false,
- declare: true,
- expression: false,
- generator: true,
- id: Identifier {
- type: "Identifier",
- decorators: [],
- name: "foo",
- optional: false,
-
- range: [18, 21],
- loc: {
- start: { column: 18, line: 1 },
- end: { column: 21, line: 1 },
- },
- },
- params: [],
-
- range: [0, 24],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 24, line: 1 },
- },
- },
- ],
- sourceType: "script",
-
- range: [0, 25],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 0, line: 2 },
- },
-}
-`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/2-TSESTree-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/2-TSESTree-Tokens.shot
deleted file mode 100644
index 42e396c00992..000000000000
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/2-TSESTree-Tokens.shot
+++ /dev/null
@@ -1,76 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AST Fixtures declaration TSDeclareFunction generator TSESTree - Tokens 1`] = `
-[
- Identifier {
- type: "Identifier",
- value: "declare",
-
- range: [0, 7],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 7, line: 1 },
- },
- },
- Keyword {
- type: "Keyword",
- value: "function",
-
- range: [8, 16],
- loc: {
- start: { column: 8, line: 1 },
- end: { column: 16, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: "*",
-
- range: [16, 17],
- loc: {
- start: { column: 16, line: 1 },
- end: { column: 17, line: 1 },
- },
- },
- Identifier {
- type: "Identifier",
- value: "foo",
-
- range: [18, 21],
- loc: {
- start: { column: 18, line: 1 },
- end: { column: 21, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: "(",
-
- range: [21, 22],
- loc: {
- start: { column: 21, line: 1 },
- end: { column: 22, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: ")",
-
- range: [22, 23],
- loc: {
- start: { column: 22, line: 1 },
- end: { column: 23, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: ";",
-
- range: [23, 24],
- loc: {
- start: { column: 23, line: 1 },
- end: { column: 24, line: 1 },
- },
- },
-]
-`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/3-Babel-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/3-Babel-AST.shot
deleted file mode 100644
index 26ccbf892c14..000000000000
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/3-Babel-AST.shot
+++ /dev/null
@@ -1,40 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AST Fixtures declaration TSDeclareFunction generator Babel - AST 1`] = `
-Program {
- type: "Program",
- body: [
- TSDeclareFunction {
- type: "TSDeclareFunction",
- async: false,
- declare: true,
- expression: false,
- generator: true,
- id: Identifier {
- type: "Identifier",
- name: "foo",
-
- range: [18, 21],
- loc: {
- start: { column: 18, line: 1 },
- end: { column: 21, line: 1 },
- },
- },
- params: [],
-
- range: [0, 24],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 24, line: 1 },
- },
- },
- ],
- sourceType: "script",
-
- range: [0, 25],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 0, line: 2 },
- },
-}
-`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/4-Babel-Tokens.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/4-Babel-Tokens.shot
deleted file mode 100644
index 76c88da05a16..000000000000
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/4-Babel-Tokens.shot
+++ /dev/null
@@ -1,76 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AST Fixtures declaration TSDeclareFunction generator Babel - Tokens 1`] = `
-[
- Identifier {
- type: "Identifier",
- value: "declare",
-
- range: [0, 7],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 7, line: 1 },
- },
- },
- Keyword {
- type: "Keyword",
- value: "function",
-
- range: [8, 16],
- loc: {
- start: { column: 8, line: 1 },
- end: { column: 16, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: "*",
-
- range: [16, 17],
- loc: {
- start: { column: 16, line: 1 },
- end: { column: 17, line: 1 },
- },
- },
- Identifier {
- type: "Identifier",
- value: "foo",
-
- range: [18, 21],
- loc: {
- start: { column: 18, line: 1 },
- end: { column: 21, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: "(",
-
- range: [21, 22],
- loc: {
- start: { column: 21, line: 1 },
- end: { column: 22, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: ")",
-
- range: [22, 23],
- loc: {
- start: { column: 22, line: 1 },
- end: { column: 23, line: 1 },
- },
- },
- Punctuator {
- type: "Punctuator",
- value: ";",
-
- range: [23, 24],
- loc: {
- start: { column: 23, line: 1 },
- end: { column: 24, line: 1 },
- },
- },
-]
-`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/5-AST-Alignment-AST.shot b/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/5-AST-Alignment-AST.shot
deleted file mode 100644
index f2de95210fab..000000000000
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/fixtures/generator/snapshots/5-AST-Alignment-AST.shot
+++ /dev/null
@@ -1,46 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AST Fixtures declaration TSDeclareFunction generator AST Alignment - AST 1`] = `
-"Snapshot Diff:
-- TSESTree
-+ Babel
-
- Program {
- type: 'Program',
- body: Array [
- TSDeclareFunction {
- type: 'TSDeclareFunction',
- async: false,
- declare: true,
- expression: false,
- generator: true,
- id: Identifier {
- type: 'Identifier',
-- decorators: Array [],
- name: 'foo',
-- optional: false,
-
- range: [18, 21],
- loc: {
- start: { column: 18, line: 1 },
- end: { column: 21, line: 1 },
- },
- },
- params: Array [],
-
- range: [0, 24],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 24, line: 1 },
- },
- },
- ],
- sourceType: 'script',
-
- range: [0, 25],
- loc: {
- start: { column: 0, line: 1 },
- end: { column: 0, line: 2 },
- },
- }"
-`;
diff --git a/packages/ast-spec/src/declaration/TSDeclareFunction/spec.ts b/packages/ast-spec/src/declaration/TSDeclareFunction/spec.ts
index 50cc07ec4248..ab75a908aa87 100644
--- a/packages/ast-spec/src/declaration/TSDeclareFunction/spec.ts
+++ b/packages/ast-spec/src/declaration/TSDeclareFunction/spec.ts
@@ -1,11 +1,55 @@
import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { FunctionBase } from '../../base/FunctionBase';
-import type { BlockStatement } from '../../statement/BlockStatement/spec';
-// TODO(#1852) - async + declare are semantically invalid together
-export interface TSDeclareFunction extends FunctionBase {
+interface TSDeclareFunctionBase extends FunctionBase {
type: AST_NODE_TYPES.TSDeclareFunction;
- body: BlockStatement | undefined;
+ /**
+ * TS1183: An implementation cannot be declared in ambient contexts.
+ */
+ body: undefined;
+ /**
+ * Whether the declaration has `declare` modifier.
+ */
declare: boolean;
expression: false;
}
+
+/**
+ * Function declaration with the `declare` keyword:
+ * ```
+ * declare function foo(): void;
+ * ```
+ */
+export interface TSDeclareFunctionWithDeclare extends TSDeclareFunctionBase {
+ /**
+ * TS1040: 'async' modifier cannot be used in an ambient context.
+ */
+ async: false;
+ declare: true;
+ /**
+ * TS1221: Generators are not allowed in an ambient context.
+ */
+ generator: false;
+}
+
+/**
+ * Function declaration without the `declare` keyword:
+ * ```
+ * function foo(): void;
+ * ```
+ * This can either be an overload signature or a declaration in an ambient context
+ * (e.g. `declare module`)
+ */
+
+export interface TSDeclareFunctionNoDeclare extends TSDeclareFunctionBase {
+ declare: false;
+ /**
+ * - TS1221: Generators are not allowed in an ambient context.
+ * - TS1222: An overload signature cannot be declared as a generator.
+ */
+ generator: false;
+}
+
+export type TSDeclareFunction =
+ | TSDeclareFunctionNoDeclare
+ | TSDeclareFunctionWithDeclare;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/fixture.ts b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/fixture.ts
new file mode 100644
index 000000000000..af81e9506a3d
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/fixture.ts
@@ -0,0 +1 @@
+import F = require(1 + 1);
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/1-TSESTree-Error.shot
new file mode 100644
index 000000000000..d3ac7ccd164c
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/1-TSESTree-Error.shot
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-2 TSESTree - Error 1`] = `
+"TSError
+> 1 | import F = require(1 + 1);
+ | ^^^^^ String literal expected.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/2-Babel-Error.shot
new file mode 100644
index 000000000000..c665f97c9fc1
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/2-Babel-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-2 Babel - Error 1`] = `[SyntaxError: Unexpected token (1:19)]`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/3-Alignment-Error.shot
new file mode 100644
index 000000000000..67e53098fb9d
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-2/snapshots/3-Alignment-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-2 Error Alignment 1`] = `"Both errored"`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/fixture.ts b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/fixture.ts
new file mode 100644
index 000000000000..fc7471ff2608
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/fixture.ts
@@ -0,0 +1 @@
+import F = require(`1`);
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/1-TSESTree-Error.shot
new file mode 100644
index 000000000000..6bbae44b9c80
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/1-TSESTree-Error.shot
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-3 TSESTree - Error 1`] = `
+"TSError
+> 1 | import F = require(\`1\`);
+ | ^^^ String literal expected.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/2-Babel-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/2-Babel-Error.shot
new file mode 100644
index 000000000000..705e7473716b
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/2-Babel-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-3 Babel - Error 1`] = `[SyntaxError: Unexpected token (1:19)]`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/3-Alignment-Error.shot
new file mode 100644
index 000000000000..ec7c941e43f8
--- /dev/null
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string-3/snapshots/3-Alignment-Error.shot
@@ -0,0 +1,3 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string-3 Error Alignment 1`] = `"Both errored"`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/1-TSESTree-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/1-TSESTree-Error.shot
index 51aedf5fa316..9bb0b788a352 100644
--- a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/1-TSESTree-Error.shot
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/1-TSESTree-Error.shot
@@ -1,3 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string TSESTree - Error 1`] = `"NO ERROR"`;
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string TSESTree - Error 1`] = `
+"TSError
+> 1 | import F = require(1);
+ | ^ String literal expected.
+ 2 |"
+`;
diff --git a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/3-Alignment-Error.shot b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/3-Alignment-Error.shot
index cda96c9ac3d2..cefcf4608939 100644
--- a/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/3-Alignment-Error.shot
+++ b/packages/ast-spec/src/declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/snapshots/3-Alignment-Error.shot
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string Error Alignment 1`] = `"Babel errored but TSESTree didn't"`;
+exports[`AST Fixtures declaration TSImportEqualsDeclaration _error_ external-module-ref-non-string Error Alignment 1`] = `"Both errored"`;
diff --git a/packages/ast-spec/src/expression/CallExpression/spec.ts b/packages/ast-spec/src/expression/CallExpression/spec.ts
index 3480b0a1041a..f380de25bc9d 100644
--- a/packages/ast-spec/src/expression/CallExpression/spec.ts
+++ b/packages/ast-spec/src/expression/CallExpression/spec.ts
@@ -2,11 +2,11 @@ import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
import type { TSTypeParameterInstantiation } from '../../special/TSTypeParameterInstantiation/spec';
import type { CallExpressionArgument } from '../../unions/CallExpressionArgument';
-import type { LeftHandSideExpression } from '../../unions/LeftHandSideExpression';
+import type { Expression } from '../../unions/Expression';
export interface CallExpression extends BaseNode {
type: AST_NODE_TYPES.CallExpression;
- callee: LeftHandSideExpression;
+ callee: Expression;
arguments: CallExpressionArgument[];
typeArguments: TSTypeParameterInstantiation | undefined;
optional: boolean;
diff --git a/packages/ast-spec/src/expression/ClassExpression/spec.ts b/packages/ast-spec/src/expression/ClassExpression/spec.ts
index dbd4936f67ca..71a7be13140a 100644
--- a/packages/ast-spec/src/expression/ClassExpression/spec.ts
+++ b/packages/ast-spec/src/expression/ClassExpression/spec.ts
@@ -5,5 +5,4 @@ export interface ClassExpression extends ClassBase {
type: AST_NODE_TYPES.ClassExpression;
abstract: false;
declare: false;
- decorators: [];
}
diff --git a/packages/ast-spec/src/expression/NewExpression/spec.ts b/packages/ast-spec/src/expression/NewExpression/spec.ts
index af88c9a5d2b1..c4478bd476d8 100644
--- a/packages/ast-spec/src/expression/NewExpression/spec.ts
+++ b/packages/ast-spec/src/expression/NewExpression/spec.ts
@@ -2,11 +2,11 @@ import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
import type { TSTypeParameterInstantiation } from '../../special/TSTypeParameterInstantiation/spec';
import type { CallExpressionArgument } from '../../unions/CallExpressionArgument';
-import type { LeftHandSideExpression } from '../../unions/LeftHandSideExpression';
+import type { Expression } from '../../unions/Expression';
export interface NewExpression extends BaseNode {
type: AST_NODE_TYPES.NewExpression;
- callee: LeftHandSideExpression;
+ callee: Expression;
arguments: CallExpressionArgument[];
typeArguments: TSTypeParameterInstantiation | undefined;
}
diff --git a/packages/ast-spec/src/expression/TaggedTemplateExpression/spec.ts b/packages/ast-spec/src/expression/TaggedTemplateExpression/spec.ts
index a11bc58325eb..2f9c3fbb2882 100644
--- a/packages/ast-spec/src/expression/TaggedTemplateExpression/spec.ts
+++ b/packages/ast-spec/src/expression/TaggedTemplateExpression/spec.ts
@@ -1,12 +1,12 @@
import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
import type { TSTypeParameterInstantiation } from '../../special/TSTypeParameterInstantiation/spec';
-import type { LeftHandSideExpression } from '../../unions/LeftHandSideExpression';
+import type { Expression } from '../../unions/Expression';
import type { TemplateLiteral } from '../TemplateLiteral/spec';
export interface TaggedTemplateExpression extends BaseNode {
+ quasi: TemplateLiteral;
+ tag: Expression;
type: AST_NODE_TYPES.TaggedTemplateExpression;
typeArguments: TSTypeParameterInstantiation | undefined;
- tag: LeftHandSideExpression;
- quasi: TemplateLiteral;
}
diff --git a/packages/ast-spec/src/special/TSExternalModuleReference/spec.ts b/packages/ast-spec/src/special/TSExternalModuleReference/spec.ts
index 1efd283fd8cf..debc2daff41b 100644
--- a/packages/ast-spec/src/special/TSExternalModuleReference/spec.ts
+++ b/packages/ast-spec/src/special/TSExternalModuleReference/spec.ts
@@ -1,9 +1,8 @@
import type { AST_NODE_TYPES } from '../../ast-node-types';
import type { BaseNode } from '../../base/BaseNode';
-import type { Expression } from '../../unions/Expression';
+import type { StringLiteral } from '../../expression/literal/StringLiteral/spec';
export interface TSExternalModuleReference extends BaseNode {
type: AST_NODE_TYPES.TSExternalModuleReference;
- // TODO(#1852) - this must be a string
- expression: Expression;
+ expression: StringLiteral;
}
diff --git a/packages/ast-spec/tests/fixtures-with-differences-ast.shot b/packages/ast-spec/tests/fixtures-with-differences-ast.shot
index 409216445120..fe7cf666fec3 100644
--- a/packages/ast-spec/tests/fixtures-with-differences-ast.shot
+++ b/packages/ast-spec/tests/fixtures-with-differences-ast.shot
@@ -56,8 +56,9 @@ exports[`AST Fixtures List fixtures with AST differences 1`] = `
"declaration/ImportDeclaration/fixtures/named-none/fixture.ts",
"declaration/ImportDeclaration/fixtures/named-one/fixture.ts",
"declaration/ImportDeclaration/fixtures/side-effect/fixture.ts",
+ "declaration/TSDeclareFunction/fixtures/async-ambient/fixture.ts",
+ "declaration/TSDeclareFunction/fixtures/async-overload/fixture.ts",
"declaration/TSDeclareFunction/fixtures/empty/fixture.ts",
- "declaration/TSDeclareFunction/fixtures/generator/fixture.ts",
"declaration/TSDeclareFunction/fixtures/param-many/fixture.ts",
"declaration/TSDeclareFunction/fixtures/param-one/fixture.ts",
"declaration/TSDeclareFunction/fixtures/returnType/fixture.ts",
diff --git a/packages/ast-spec/tests/fixtures-with-differences-errors.shot b/packages/ast-spec/tests/fixtures-with-differences-errors.shot
index 3baa5a85efca..76663a6ec6c8 100644
--- a/packages/ast-spec/tests/fixtures-with-differences-errors.shot
+++ b/packages/ast-spec/tests/fixtures-with-differences-errors.shot
@@ -8,10 +8,7 @@ exports[`AST Fixtures List fixtures with Error differences 1`] = `
"declaration/ClassDeclaration/fixtures/_error_/missing-type-param/fixture.ts",
"declaration/ExportNamedDeclaration/fixtures/_error_/assertion/fixture.ts",
"declaration/FunctionDeclaration/fixtures/_error_/missing-type-param/fixture.ts",
- "declaration/TSDeclareFunction/fixtures/_error_/async/fixture.ts",
- "declaration/TSDeclareFunction/fixtures/_error_/declare-with-body/fixture.ts",
"declaration/TSDeclareFunction/fixtures/_error_/missing-type-param/fixture.ts",
- "declaration/TSImportEqualsDeclaration/fixtures/_error_/external-module-ref-non-string/fixture.ts",
"declaration/TSImportEqualsDeclaration/fixtures/_error_/import-kind/fixture.ts",
"declaration/TSInterfaceDeclaration/fixtures/_error_/missing-extends/fixture.ts",
"declaration/TSInterfaceDeclaration/fixtures/_error_/missing-type-param/fixture.ts",
@@ -49,6 +46,9 @@ exports[`AST Fixtures List fixtures with Error differences 1`] = `
"TSESTree errored but Babel didn't": [
"declaration/ExportAllDeclaration/fixtures/_error_/named-non-identifier/fixture.ts",
"declaration/ExportNamedDeclaration/fixtures/_error_/aliased-literal/fixture.ts",
+ "declaration/TSDeclareFunction/fixtures/_error_/generator-ambient/fixture.ts",
+ "declaration/TSDeclareFunction/fixtures/_error_/generator-overload/fixture.ts",
+ "declaration/TSDeclareFunction/fixtures/_error_/generator/fixture.ts",
"element/AccessorProperty/fixtures/_error_/modifier-abstract-accessor-with-value/fixture.ts",
"legacy-fixtures/basics/fixtures/_error_/abstract-class-with-abstract-constructor/fixture.ts",
"legacy-fixtures/expressions/fixtures/_error_/instantiation-expression/fixture.ts",
diff --git a/packages/eslint-plugin-internal/src/rules/no-typescript-default-import.ts b/packages/eslint-plugin-internal/src/rules/no-typescript-default-import.ts
index 0864b7bba553..594ac9f51c2f 100644
--- a/packages/eslint-plugin-internal/src/rules/no-typescript-default-import.ts
+++ b/packages/eslint-plugin-internal/src/rules/no-typescript-default-import.ts
@@ -1,5 +1,4 @@
import type { TSESTree } from '@typescript-eslint/utils';
-import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import { createRule } from '../util';
@@ -61,10 +60,7 @@ export default createRule({
node: TSESTree.TSExternalModuleReference,
): void {
const parent = node.parent as TSESTree.TSImportEqualsDeclaration;
- if (
- node.expression.type === AST_NODE_TYPES.Literal &&
- node.expression.value === 'typescript'
- ) {
+ if (node.expression.value === 'typescript') {
context.report({
node,
messageId: 'noTSDefaultImport',
diff --git a/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
index a9be456e947f..57a372367fca 100644
--- a/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
+++ b/packages/eslint-plugin-internal/src/rules/plugin-test-formatting.ts
@@ -425,9 +425,7 @@ export default createRule({
}
}
- function isNoFormatTemplateTag(
- tag: TSESTree.LeftHandSideExpression,
- ): boolean {
+ function isNoFormatTemplateTag(tag: TSESTree.Expression): boolean {
return tag.type === AST_NODE_TYPES.Identifier && tag.name === 'noFormat';
}
diff --git a/packages/eslint-plugin/docs/rules/no-base-to-string.mdx b/packages/eslint-plugin/docs/rules/no-base-to-string.mdx
index 5e6b531e4384..f959897d7e68 100644
--- a/packages/eslint-plugin/docs/rules/no-base-to-string.mdx
+++ b/packages/eslint-plugin/docs/rules/no-base-to-string.mdx
@@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem';
> See **https://typescript-eslint.io/rules/no-base-to-string** for documentation.
JavaScript will call `toString()` on an object when it is converted to a string, such as when `+` adding to a string or in `${}` template literals.
-The default Object `.toString()` returns `"[object Object]"`, which is often not what was intended.
+The default Object `.toString()` uses the format `"[object Object]"`, which is often not what was intended.
This rule reports on stringified values that aren't primitives and don't define a more useful `.toString()` method.
> Note that `Function` provides its own `.toString()` that returns the function's code.
diff --git a/packages/eslint-plugin/docs/rules/no-misused-promises.mdx b/packages/eslint-plugin/docs/rules/no-misused-promises.mdx
index ff044b712d12..3621829cb977 100644
--- a/packages/eslint-plugin/docs/rules/no-misused-promises.mdx
+++ b/packages/eslint-plugin/docs/rules/no-misused-promises.mdx
@@ -127,19 +127,18 @@ Examples of code for this rule with `checksVoidReturn: true`:
```ts option='{ "checksVoidReturn": true }'
[1, 2, 3].forEach(async value => {
- await doSomething(value);
+ await fetch(`/${value}`);
});
-new Promise(async (resolve, reject) => {
- await doSomething();
+new Promise(async (resolve, reject) => {
+ await fetch('/');
resolve();
});
-const eventEmitter = new EventEmitter();
-eventEmitter.on('some-event', async () => {
- synchronousCall();
- await doSomething();
- otherSynchronousCall();
+document.addEventListener('click', async () => {
+ console.log('synchronous call');
+ await fetch('/');
+ console.log('synchronous call');
});
```
@@ -169,8 +168,7 @@ new Promise((resolve, reject) => {
});
// Name the async wrapper to call it later
-const eventEmitter = new EventEmitter();
-eventEmitter.on('some-event', () => {
+document.addEventListener('click', () => {
const handler = async () => {
await doSomething();
otherSynchronousCall();
@@ -210,30 +208,30 @@ Examples of code for this rule with `checksSpreads: true`:
```ts option='{ "checksSpreads": true }'
-const getData = () => someAsyncOperation({ myArg: 'foo' });
+const getData = () => fetch('/');
-return { foo: 42, ...getData() };
+console.log({ foo: 42, ...getData() });
-const getData2 = async () => {
- await someAsyncOperation({ myArg: 'foo' });
+const awaitData = async () => {
+ await fetch('/');
};
-return { foo: 42, ...getData2() };
+console.log({ foo: 42, ...awaitData() });
```
```ts option='{ "checksSpreads": true }'
-const getData = () => someAsyncOperation({ myArg: 'foo' });
+const getData = () => fetch('/');
-return { foo: 42, ...(await getData()) };
+console.log({ foo: 42, ...(await getData()) });
-const getData2 = async () => {
- await someAsyncOperation({ myArg: 'foo' });
+const awaitData = async () => {
+ await fetch('/');
};
-return { foo: 42, ...(await getData2()) };
+console.log({ foo: 42, ...(await awaitData()) });
```
diff --git a/packages/eslint-plugin/docs/rules/no-unused-expressions.mdx b/packages/eslint-plugin/docs/rules/no-unused-expressions.mdx
index 2f0805ba8de6..8d185e92c082 100644
--- a/packages/eslint-plugin/docs/rules/no-unused-expressions.mdx
+++ b/packages/eslint-plugin/docs/rules/no-unused-expressions.mdx
@@ -10,4 +10,44 @@ import TabItem from '@theme/TabItem';
> See **https://typescript-eslint.io/rules/no-unused-expressions** for documentation.
This rule extends the base [`eslint/no-unused-expressions`](https://eslint.org/docs/rules/no-unused-expressions) rule.
-It adds support for optional call expressions `x?.()`, and directive in module declarations.
+It supports TypeScript-specific expressions:
+
+- Marks directives in modules declarations (`"use strict"`, etc.) as not unused
+- Marks the following expressions as unused if their wrapped value expressions are unused:
+ - Assertion expressions: `x as number;`, `x!;`, `x;`
+ - Instantiation expressions: `Set;`
+
+Although the type expressions never have runtime side effects (that is, `x!;` is the same as `x;`), they can be used to assert types for testing purposes.
+
+## Examples
+
+
+
+
+```ts
+Set;
+1 as number;
+window!;
+```
+
+
+
+
+```ts
+function getSet() {
+ return Set;
+}
+
+// Funtion calls are allowed, so type expressions that wrap function calls are allowed
+getSet();
+getSet() as Set;
+getSet()!;
+
+// Namespaces can have directives
+namespace A {
+ 'use strict';
+}
+```
+
+
+
diff --git a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.mdx b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.mdx
index e01ff6ffbf62..e2ddcef23048 100644
--- a/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.mdx
+++ b/packages/eslint-plugin/docs/rules/prefer-readonly-parameter-types.mdx
@@ -402,3 +402,8 @@ function foo(arg: MyType) {}
## When Not To Use It
If your project does not attempt to enforce strong immutability guarantees of parameters, you can avoid this rule.
+
+This rule is very strict on what it considers mutable.
+Many types that describe themselves as readonly are considered mutable because they have mutable properties such as arrays or tuples.
+To work around these limitations, you might need to use the rule's options.
+In particular, the [`allow` option](#allow) can explicitly mark a type as readonly.
diff --git a/packages/eslint-plugin/docs/rules/restrict-template-expressions.mdx b/packages/eslint-plugin/docs/rules/restrict-template-expressions.mdx
index 3cf40a6e805d..f99cb0ab8e60 100644
--- a/packages/eslint-plugin/docs/rules/restrict-template-expressions.mdx
+++ b/packages/eslint-plugin/docs/rules/restrict-template-expressions.mdx
@@ -10,7 +10,7 @@ import TabItem from '@theme/TabItem';
> See **https://typescript-eslint.io/rules/restrict-template-expressions** for documentation.
JavaScript automatically [converts an object to a string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#string_coercion) in a string context, such as when concatenating it with a string using `+` or embedding it in a template literal using `${}`.
-The default `toString()` method of objects returns `"[object Object]"`, which is often not what was intended.
+The default `toString()` method of objects uses the format `"[object Object]"`, which is often not what was intended.
This rule reports on values used in a template literal string that aren't strings, optionally allowing other data types that provide useful stringification results.
:::note
diff --git a/packages/eslint-plugin/docs/rules/sort-type-constituents.mdx b/packages/eslint-plugin/docs/rules/sort-type-constituents.mdx
index a4e29c2cdc43..188590aa38b1 100644
--- a/packages/eslint-plugin/docs/rules/sort-type-constituents.mdx
+++ b/packages/eslint-plugin/docs/rules/sort-type-constituents.mdx
@@ -9,6 +9,12 @@ import TabItem from '@theme/TabItem';
>
> See **https://typescript-eslint.io/rules/sort-type-constituents** for documentation.
+:::danger Deprecated
+This rule has been deprecated in favor of the [`perfectionist/sort-intersection-types`](https://eslint-plugin-perfectionist.azat.io/rules/sort-intersection-types) and [`perfectionist/sort-union-types`](https://eslint-plugin-perfectionist.azat.io/rules/sort-union-types) rules.
+
+See [Docs: Deprecate sort-type-constituents in favor of eslint-plugin-perfectionist](https://github.com/typescript-eslint/typescript-eslint/issues/8915) and [eslint-plugin: Feature freeze naming and sorting stylistic rules](https://github.com/typescript-eslint/typescript-eslint/issues/8792) for more information.
+:::
+
Sorting union (`|`) and intersection (`&`) types can help:
- keep your codebase standardized
@@ -19,15 +25,6 @@ This rule reports on any types that aren't sorted alphabetically.
> Types are sorted case-insensitively and treating numbers like a human would, falling back to character code sorting in case of ties.
-:::note
-This rule is _feature frozen_: it will no longer receive new features such as new options.
-It still will accept bug and documentation fixes for its existing area of features.
-
-Stylistic rules that enforce naming and/or sorting conventions tend to grow incomprehensibly complex as increasingly obscure features are requested.
-This rule has reached the limit of what is reasonable for the typescript-eslint project to maintain.
-See [eslint-plugin: Feature freeze naming and sorting stylistic rules](https://github.com/typescript-eslint/typescript-eslint/issues/8792) for more information.
-:::
-
## Examples
diff --git a/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.mdx b/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.mdx
new file mode 100644
index 000000000000..d8224c93c808
--- /dev/null
+++ b/packages/eslint-plugin/docs/rules/sort-type-union-intersection-members.mdx
@@ -0,0 +1,12 @@
+:::danger Deprecated
+
+This rule has been renamed to [`sort-type-constituents`](https://typescript-eslint.io/rules/sort-type-constituents).
+
+:::
+
+
diff --git a/packages/eslint-plugin/src/configs/all.ts b/packages/eslint-plugin/src/configs/all.ts
index 2beb655455f3..5c1e1d7725ac 100644
--- a/packages/eslint-plugin/src/configs/all.ts
+++ b/packages/eslint-plugin/src/configs/all.ts
@@ -144,7 +144,6 @@ export = {
'@typescript-eslint/restrict-template-expressions': 'error',
'no-return-await': 'off',
'@typescript-eslint/return-await': 'error',
- '@typescript-eslint/sort-type-constituents': 'error',
'@typescript-eslint/strict-boolean-expressions': 'error',
'@typescript-eslint/switch-exhaustiveness-check': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts
index fabbe73898a5..4debac89cb26 100644
--- a/packages/eslint-plugin/src/rules/init-declarations.ts
+++ b/packages/eslint-plugin/src/rules/init-declarations.ts
@@ -28,7 +28,51 @@ export default createRule({
},
defaultOptions: ['always'],
create(context, [mode]) {
- const rules = baseRule.create(context);
+ // Make a custom context to adjust the the loc of reports where the base
+ // rule's behavior is a bit too aggressive with TS-specific syntax (namely,
+ // type annotations).
+ function getBaseContextOverride(): typeof context {
+ const reportOverride: typeof context.report = descriptor => {
+ if ('node' in descriptor && descriptor.loc == null) {
+ const { node, ...rest } = descriptor;
+ // We only want to special case the report loc when reporting on
+ // variables declarations that are not initialized. Declarations that
+ // _are_ initialized get reported by the base rule due to a setting to
+ // prohibit initializing variables entirely, in which case underlining
+ // the whole node including the type annotation and initializer is
+ // appropriate.
+ if (
+ node.type === AST_NODE_TYPES.VariableDeclarator &&
+ node.init == null
+ ) {
+ context.report({
+ ...rest,
+ loc: getReportLoc(node),
+ });
+ return;
+ }
+ }
+
+ context.report(descriptor);
+ };
+
+ // `return { ...context, report: reportOverride }` isn't safe because the
+ // `context` object has some getters that need to be preserved.
+ //
+ // `return new Proxy(context, ...)` doesn't work because `context` has
+ // non-configurable properties that throw when constructing a Proxy.
+ //
+ // So, we'll just use Proxy on a dummy object and use the `get` trap to
+ // proxy `context`'s properties.
+ return new Proxy({} as typeof context, {
+ get: (target, prop, receiver): unknown =>
+ prop === 'report'
+ ? reportOverride
+ : Reflect.get(context, prop, receiver),
+ });
+ }
+
+ const rules = baseRule.create(getBaseContextOverride());
return {
'VariableDeclaration:exit'(node: TSESTree.VariableDeclaration): void {
@@ -65,3 +109,26 @@ export default createRule({
}
},
});
+
+/**
+ * When reporting an uninitialized variable declarator, get the loc excluding
+ * the type annotation.
+ */
+function getReportLoc(
+ node: TSESTree.VariableDeclarator,
+): TSESTree.SourceLocation {
+ const start: TSESTree.Position = structuredClone(node.loc.start);
+ const end: TSESTree.Position = {
+ line: node.loc.start.line,
+ // `if (id.type === AST_NODE_TYPES.Identifier)` is a condition for
+ // reporting in the base rule (as opposed to things like destructuring
+ // assignment), so the type assertion should always be valid.
+ column:
+ node.loc.start.column + (node.id as TSESTree.Identifier).name.length,
+ };
+
+ return {
+ start,
+ end,
+ };
+}
diff --git a/packages/eslint-plugin/src/rules/no-base-to-string.ts b/packages/eslint-plugin/src/rules/no-base-to-string.ts
index 131579e8457e..0369e66fe66f 100644
--- a/packages/eslint-plugin/src/rules/no-base-to-string.ts
+++ b/packages/eslint-plugin/src/rules/no-base-to-string.ts
@@ -28,7 +28,7 @@ export default createRule({
},
messages: {
baseToString:
- "'{{name}}' {{certainty}} evaluate to '[object Object]' when stringified.",
+ "'{{name}}' {{certainty}} use Object's default stringification format ('[object Object]') when stringified.",
},
schema: [
{
diff --git a/packages/eslint-plugin/src/rules/no-implied-eval.ts b/packages/eslint-plugin/src/rules/no-implied-eval.ts
index de2e0574929d..dee23d62d275 100644
--- a/packages/eslint-plugin/src/rules/no-implied-eval.ts
+++ b/packages/eslint-plugin/src/rules/no-implied-eval.ts
@@ -36,9 +36,7 @@ export default createRule({
const services = getParserServices(context);
const checker = services.program.getTypeChecker();
- function getCalleeName(
- node: TSESTree.LeftHandSideExpression,
- ): string | null {
+ function getCalleeName(node: TSESTree.Expression): string | null {
if (node.type === AST_NODE_TYPES.Identifier) {
return node.name;
}
diff --git a/packages/eslint-plugin/src/rules/no-restricted-imports.ts b/packages/eslint-plugin/src/rules/no-restricted-imports.ts
index 861bbad05cd9..abd0a891b05e 100644
--- a/packages/eslint-plugin/src/rules/no-restricted-imports.ts
+++ b/packages/eslint-plugin/src/rules/no-restricted-imports.ts
@@ -312,10 +312,7 @@ export default createRule({
node: TSESTree.TSImportEqualsDeclaration,
): void {
if (
- node.moduleReference.type ===
- AST_NODE_TYPES.TSExternalModuleReference &&
- node.moduleReference.expression.type === AST_NODE_TYPES.Literal &&
- typeof node.moduleReference.expression.value === 'string'
+ node.moduleReference.type === AST_NODE_TYPES.TSExternalModuleReference
) {
const synthesizedImport = {
...node,
diff --git a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
index d55d8f75b06e..08950fa8d732 100644
--- a/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
+++ b/packages/eslint-plugin/src/rules/no-unsafe-argument.ts
@@ -165,7 +165,7 @@ export default createRule<[], MessageIds>({
function checkUnsafeArguments(
args: TSESTree.Expression[] | TSESTree.CallExpressionArgument[],
- callee: TSESTree.LeftHandSideExpression,
+ callee: TSESTree.Expression,
node:
| TSESTree.CallExpression
| TSESTree.NewExpression
diff --git a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts
index fc1008773aab..883783dbd527 100644
--- a/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts
+++ b/packages/eslint-plugin/src/rules/no-unsafe-assignment.ts
@@ -37,17 +37,18 @@ export default createRule({
requiresTypeChecking: true,
},
messages: {
- anyAssignment: 'Unsafe assignment of an `any` value.',
+ anyAssignment: 'Unsafe assignment of an {{sender}} value.',
anyAssignmentThis: [
- 'Unsafe assignment of an `any` value. `this` is typed as `any`.',
+ 'Unsafe assignment of an {{sender}} value. `this` is typed as `any`.',
'You can try to fix this by turning on the `noImplicitThis` compiler option, or adding a `this` parameter to the function.',
].join('\n'),
- unsafeArrayPattern: 'Unsafe array destructuring of an `any` array value.',
+ unsafeArrayPattern:
+ 'Unsafe array destructuring of an {{sender}} array value.',
unsafeArrayPatternFromTuple:
- 'Unsafe array destructuring of a tuple element with an `any` value.',
+ 'Unsafe array destructuring of a tuple element with an {{sender}} value.',
unsafeAssignment:
'Unsafe assignment of type {{sender}} to a variable of type {{receiver}}.',
- unsafeArraySpread: 'Unsafe spread of an `any` value in an array.',
+ unsafeArraySpread: 'Unsafe spread of an {{sender}} value in an array.',
},
schema: [],
},
@@ -88,6 +89,7 @@ export default createRule({
context.report({
node: receiverNode,
messageId: 'unsafeArrayPattern',
+ data: createData(senderType),
});
return false;
}
@@ -126,6 +128,7 @@ export default createRule({
context.report({
node: receiverElement,
messageId: 'unsafeArrayPatternFromTuple',
+ data: createData(senderType),
});
// we want to report on every invalid element in the tuple
didReport = true;
@@ -212,6 +215,7 @@ export default createRule({
context.report({
node: receiverProperty.value,
messageId: 'unsafeArrayPatternFromTuple',
+ data: createData(senderType),
});
didReport = true;
} else if (
@@ -275,7 +279,9 @@ export default createRule({
context.report({
node: reportingNode,
messageId,
+ data: createData(senderType),
});
+
return true;
}
@@ -297,10 +303,7 @@ export default createRule({
context.report({
node: reportingNode,
messageId: 'unsafeAssignment',
- data: {
- sender: checker.typeToString(sender),
- receiver: checker.typeToString(receiver),
- },
+ data: createData(sender, receiver),
});
return true;
}
@@ -315,6 +318,23 @@ export default createRule({
ComparisonType.None;
}
+ function createData(
+ senderType: ts.Type,
+ receiverType?: ts.Type,
+ ): Readonly> | undefined {
+ if (receiverType) {
+ return {
+ sender: '`' + checker.typeToString(senderType) + '`',
+ receiver: '`' + checker.typeToString(receiverType) + '`',
+ };
+ }
+ return {
+ sender: tsutils.isIntrinsicErrorType(senderType)
+ ? 'error typed'
+ : '`any`',
+ };
+ }
+
return {
'VariableDeclarator[init != null]'(
node: TSESTree.VariableDeclarator,
@@ -383,6 +403,7 @@ export default createRule({
context.report({
node: node,
messageId: 'unsafeArraySpread',
+ data: createData(restType),
});
}
},
diff --git a/packages/eslint-plugin/src/rules/sort-type-constituents.ts b/packages/eslint-plugin/src/rules/sort-type-constituents.ts
index 2f1b8f5cbd34..de87dc2aa962 100644
--- a/packages/eslint-plugin/src/rules/sort-type-constituents.ts
+++ b/packages/eslint-plugin/src/rules/sort-type-constituents.ts
@@ -117,6 +117,11 @@ export type MessageIds = 'notSorted' | 'notSortedNamed' | 'suggestFix';
export default createRule({
name: 'sort-type-constituents',
meta: {
+ deprecated: true,
+ replacedBy: [
+ 'perfectionist/sort-intersection-types',
+ 'perfectionist/sort-union-types',
+ ],
type: 'suggestion',
docs: {
description:
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-base-to-string.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-base-to-string.shot
index 21750093fe9a..f5bc9c118ff1 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-base-to-string.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-base-to-string.shot
@@ -5,18 +5,18 @@ exports[`Validating rule docs no-base-to-string.mdx code examples ESLint output
// Passing an object or class instance to string concatenation:
'' + {};
- ~~ '{}' will evaluate to '[object Object]' when stringified.
+ ~~ '{}' will use Object's default stringification format ('[object Object]') when stringified.
class MyClass {}
const value = new MyClass();
value + '';
-~~~~~ 'value' will evaluate to '[object Object]' when stringified.
+~~~~~ 'value' will use Object's default stringification format ('[object Object]') when stringified.
// Interpolation and manual .toString() calls too:
\`Value: \${value}\`;
- ~~~~~ 'value' will evaluate to '[object Object]' when stringified.
+ ~~~~~ 'value' will use Object's default stringification format ('[object Object]') when stringified.
({}).toString();
- ~~ '{}' will evaluate to '[object Object]' when stringified.
+ ~~ '{}' will use Object's default stringification format ('[object Object]') when stringified.
"
`;
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-misused-promises.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-misused-promises.shot
index 3c1170e888c0..e42445e017bb 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-misused-promises.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-misused-promises.shot
@@ -46,25 +46,24 @@ Options: { "checksVoidReturn": true }
[1, 2, 3].forEach(async value => {
~~~~~~~~~~~~~~~~ Promise returned in function argument where a void return was expected.
- await doSomething(value);
+ await fetch(\`/\${value}\`);
~~~~~~~~~~~~~~~~~~~~~~~~~~~
});
~
-new Promise(async (resolve, reject) => {
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Promise returned in function argument where a void return was expected.
- await doSomething();
-~~~~~~~~~~~~~~~~~~~~~~
+new Promise(async (resolve, reject) => {
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Promise returned in function argument where a void return was expected.
+ await fetch('/');
+~~~~~~~~~~~~~~~~~~~
resolve();
~~~~~~~~~~~~
});
~
-const eventEmitter = new EventEmitter();
-eventEmitter.on('some-event', async () => {
- synchronousCall();
- await doSomething();
- otherSynchronousCall();
+document.addEventListener('click', async () => {
+ console.log('synchronous call');
+ await fetch('/');
+ console.log('synchronous call');
});
"
`;
@@ -95,8 +94,7 @@ new Promise((resolve, reject) => {
});
// Name the async wrapper to call it later
-const eventEmitter = new EventEmitter();
-eventEmitter.on('some-event', () => {
+document.addEventListener('click', () => {
const handler = async () => {
await doSomething();
otherSynchronousCall();
@@ -117,16 +115,17 @@ exports[`Validating rule docs no-misused-promises.mdx code examples ESLint outpu
"Incorrect
Options: { "checksSpreads": true }
-const getData = () => someAsyncOperation({ myArg: 'foo' });
+const getData = () => fetch('/');
-return { foo: 42, ...getData() };
+console.log({ foo: 42, ...getData() });
+ ~~~~~~~~~ Expected a non-Promise value to be spreaded in an object.
-const getData2 = async () => {
- await someAsyncOperation({ myArg: 'foo' });
+const awaitData = async () => {
+ await fetch('/');
};
-return { foo: 42, ...getData2() };
- ~~~~~~~~~~ Expected a non-Promise value to be spreaded in an object.
+console.log({ foo: 42, ...awaitData() });
+ ~~~~~~~~~~~ Expected a non-Promise value to be spreaded in an object.
"
`;
@@ -134,14 +133,14 @@ exports[`Validating rule docs no-misused-promises.mdx code examples ESLint outpu
"Correct
Options: { "checksSpreads": true }
-const getData = () => someAsyncOperation({ myArg: 'foo' });
+const getData = () => fetch('/');
-return { foo: 42, ...(await getData()) };
+console.log({ foo: 42, ...(await getData()) });
-const getData2 = async () => {
- await someAsyncOperation({ myArg: 'foo' });
+const awaitData = async () => {
+ await fetch('/');
};
-return { foo: 42, ...(await getData2()) };
+console.log({ foo: 42, ...(await awaitData()) });
"
`;
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-assignment.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-assignment.shot
index 2e1b94899b68..de10a87d5f42 100644
--- a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-assignment.shot
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unsafe-assignment.shot
@@ -29,13 +29,13 @@ class Foo {
// generic position examples
const x: Set = new Set();
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type Set to a variable of type Set.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type \`Set\` to a variable of type \`Set\`.
const x: Map = new Map();
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type Map to a variable of type Map.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type \`Map\` to a variable of type \`Map\`.
const x: Set = new Set();
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type Set to a variable of type Set.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type \`Set\` to a variable of type \`Set\`.
const x: Set>> = new Set>>();
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type Set>> to a variable of type Set>>.
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Unsafe assignment of type \`Set>>\` to a variable of type \`Set>>\`.
"
`;
diff --git a/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unused-expressions.shot b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unused-expressions.shot
new file mode 100644
index 000000000000..f0f2802b58a2
--- /dev/null
+++ b/packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-unused-expressions.shot
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Validating rule docs no-unused-expressions.mdx code examples ESLint output 1`] = `
+"Incorrect
+
+Set;
+~~~~~~~~~~~~ Expected an assignment or function call and instead saw an expression.
+1 as number;
+~~~~~~~~~~~~ Expected an assignment or function call and instead saw an expression.
+window!;
+~~~~~~~~ Expected an assignment or function call and instead saw an expression.
+"
+`;
+
+exports[`Validating rule docs no-unused-expressions.mdx code examples ESLint output 2`] = `
+"Correct
+
+function getSet() {
+ return Set;
+}
+
+// Funtion calls are allowed, so type expressions that wrap function calls are allowed
+getSet();
+getSet() as Set;
+getSet()!;
+
+// Namespaces can have directives
+namespace A {
+ 'use strict';
+}
+"
+`;
diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts
index 53d0838af93e..ebe19ec4d586 100644
--- a/packages/eslint-plugin/tests/docs.test.ts
+++ b/packages/eslint-plugin/tests/docs.test.ts
@@ -8,12 +8,16 @@ import { Linter } from '@typescript-eslint/utils/ts-eslint';
import fs from 'fs';
import { marked } from 'marked';
import type * as mdast from 'mdast';
-import type { fromMarkdown as FromMarkdown } from 'mdast-util-from-markdown' with { 'resolution-mode': 'import' };
-import type { mdxFromMarkdown as MdxFromMarkdown } from 'mdast-util-mdx' with { 'resolution-mode': 'import' };
-import type { mdxjs as Mdxjs } from 'micromark-extension-mdxjs' with { 'resolution-mode': 'import' };
+import type { fromMarkdown as FromMarkdown } from 'mdast-util-from-markdown' with { 'resolution-mode':
+ 'import' };
+import type { mdxFromMarkdown as MdxFromMarkdown } from 'mdast-util-mdx' with { 'resolution-mode':
+ 'import' };
+import type { mdxjs as Mdxjs } from 'micromark-extension-mdxjs' with { 'resolution-mode':
+ 'import' };
import path from 'path';
import { titleCase } from 'title-case';
-import type * as UnistUtilVisit from 'unist-util-visit' with { 'resolution-mode': 'import' };
+import type * as UnistUtilVisit from 'unist-util-visit' with { 'resolution-mode':
+ 'import' };
import rules from '../src/rules';
import { areOptionsValid } from './areOptionsValid';
@@ -158,11 +162,47 @@ describe('Validating rule docs', () => {
'no-duplicate-imports.mdx',
'no-parameter-properties.mdx',
'no-useless-template-literals.mdx',
+ 'sort-type-union-intersection-members.mdx',
...oldStylisticRules,
]);
const rulesWithComplexOptions = new Set(['array-type', 'member-ordering']);
+ // TODO: whittle this list down to as few as possible
+ const rulesWithComplexOptionHeadings = new Set([
+ 'ban-ts-comment',
+ 'ban-types',
+ 'consistent-type-exports',
+ 'consistent-type-imports',
+ 'explicit-function-return-type',
+ 'explicit-member-accessibility',
+ 'explicit-module-boundary-types',
+ 'no-base-to-string',
+ 'no-confusing-void-expression',
+ 'no-duplicate-type-constituents',
+ 'no-empty-interface',
+ 'no-empty-object-type',
+ 'no-explicit-any',
+ 'no-floating-promises',
+ 'no-inferrable-types',
+ 'no-invalid-void-type',
+ 'no-meaningless-void-operator',
+ 'no-misused-promises',
+ 'no-type-alias',
+ 'no-unnecessary-condition',
+ 'no-unnecessary-type-assertion',
+ 'parameter-properties',
+ 'prefer-nullish-coalescing',
+ 'prefer-optional-chain',
+ 'prefer-string-starts-ends-with',
+ 'promise-function-async',
+ 'restrict-template-expressions',
+ 'strict-boolean-expressions',
+ 'switch-exhaustiveness-check',
+ 'switch-exhaustiveness-check',
+ 'unbound-method',
+ ]);
+
it('All rules must have a corresponding rule doc', () => {
const files = fs
.readdirSync(docsRoot)
@@ -263,22 +303,55 @@ describe('Validating rule docs', () => {
Array.isArray(schema) &&
!rule.meta.docs?.extendsBaseRule
) {
- 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');
+ describe('rule options', () => {
+ const headingsAfterOptions = headings.slice(
+ headings.findIndex(header => header.text === 'Options'),
+ );
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}\`.`,
+ test(property, () => {
+ const correspondingHeadingIndex =
+ headingsAfterOptions.findIndex(heading =>
+ heading.text.includes(`\`${property}\``),
+ );
+
+ if (correspondingHeadingIndex === -1) {
+ throw new Error(
+ `At least one header should include \`${property}\`.`,
+ );
+ }
+
+ if (rulesWithComplexOptionHeadings.has(ruleName)) {
+ return;
+ }
+
+ const relevantChildren = tokens.slice(
+ tokens.indexOf(
+ headingsAfterOptions[correspondingHeadingIndex],
+ ),
+ tokens.indexOf(
+ headingsAfterOptions[correspondingHeadingIndex + 1],
+ ),
);
- }
+
+ for (const rawTab of [
+ ``,
+ ``,
+ ]) {
+ if (
+ !relevantChildren.some(
+ child =>
+ child.type === 'html' && child.raw.includes(rawTab),
+ )
+ ) {
+ throw new Error(`Missing option example tab: ${rawTab}`);
+ }
+ }
+ });
}
}
}
diff --git a/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts b/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
index 252b6fe2f32b..a6ce89cc8d24 100644
--- a/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
+++ b/packages/eslint-plugin/tests/eslint-rules/no-undef.test.ts
@@ -259,6 +259,11 @@ const obj = {
},
};
`,
+ `
+class Foo {
+ [x: string]: any;
+}
+ `,
],
invalid: [
{
@@ -396,5 +401,35 @@ function Foo() {}
},
],
},
+ {
+ code: `
+class Foo {
+ [x: Bar]: string;
+}
+ `,
+ errors: [
+ {
+ messageId: 'undef',
+ data: {
+ name: 'Bar',
+ },
+ },
+ ],
+ },
+ {
+ code: `
+class Foo {
+ [x: string]: Bar;
+}
+ `,
+ errors: [
+ {
+ messageId: 'undef',
+ data: {
+ name: 'Bar',
+ },
+ },
+ ],
+ },
],
});
diff --git a/packages/eslint-plugin/tests/rules/consistent-return.test.ts b/packages/eslint-plugin/tests/rules/consistent-return.test.ts
index 1489b835d8ba..cb74ca29b8c3 100644
--- a/packages/eslint-plugin/tests/rules/consistent-return.test.ts
+++ b/packages/eslint-plugin/tests/rules/consistent-return.test.ts
@@ -380,7 +380,7 @@ ruleTester.run('consistent-return', rule, {
},
{
code: `
- declare async function bar(): Promise;
+ declare function bar(): Promise;
function foo(flag?: boolean): Promise {
if (flag) {
return bar();
diff --git a/packages/eslint-plugin/tests/rules/init-declarations.test.ts b/packages/eslint-plugin/tests/rules/init-declarations.test.ts
index f284cd101853..2667377b2a7e 100644
--- a/packages/eslint-plugin/tests/rules/init-declarations.test.ts
+++ b/packages/eslint-plugin/tests/rules/init-declarations.test.ts
@@ -1,5 +1,4 @@
import { RuleTester } from '@typescript-eslint/rule-tester';
-import { AST_NODE_TYPES } from '@typescript-eslint/utils';
import rule from '../../src/rules/init-declarations';
@@ -381,7 +380,10 @@ declare namespace myLib1 {
{
messageId: 'initialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 8,
},
],
},
@@ -392,7 +394,10 @@ declare namespace myLib1 {
{
messageId: 'initialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 23,
+ endLine: 1,
+ endColumn: 26,
},
],
},
@@ -407,12 +412,18 @@ var foo,
{
messageId: 'initialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 2,
+ column: 5,
+ endLine: 2,
+ endColumn: 8,
},
{
messageId: 'initialized',
data: { idName: 'baz' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 3,
+ endLine: 4,
+ endColumn: 6,
},
],
},
@@ -428,7 +439,10 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'bar' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 7,
+ endLine: 4,
+ endColumn: 10,
},
],
},
@@ -444,7 +458,10 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 10,
},
],
},
@@ -455,7 +472,10 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'a' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 6,
},
],
},
@@ -475,7 +495,10 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'b' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 5,
+ endLine: 4,
+ endColumn: 6,
},
],
},
@@ -492,12 +515,18 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'a' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 8,
},
{
messageId: 'initialized',
data: { idName: 'c' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 5,
+ column: 7,
+ endLine: 5,
+ endColumn: 8,
},
],
},
@@ -508,7 +537,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 20,
},
],
},
@@ -519,7 +551,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 15,
},
],
},
@@ -534,12 +569,18 @@ var foo,
{
messageId: 'notInitialized',
data: { idName: 'bar' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 3,
+ endLine: 3,
+ endColumn: 10,
},
{
messageId: 'notInitialized',
data: { idName: 'baz' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 3,
+ endLine: 4,
+ endColumn: 10,
},
],
},
@@ -555,8 +596,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'bar' },
-
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 7,
+ endLine: 4,
+ endColumn: 16,
},
],
},
@@ -567,7 +610,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'a' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 10,
},
],
},
@@ -586,7 +632,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'a' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 16,
},
],
},
@@ -603,7 +652,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'c' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 5,
+ column: 7,
+ endLine: 5,
+ endColumn: 12,
},
],
},
@@ -614,7 +666,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'i' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 10,
+ endLine: 1,
+ endColumn: 15,
},
],
},
@@ -628,7 +683,10 @@ for (var foo in []) {
{
messageId: 'notInitialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 2,
+ column: 10,
+ endLine: 2,
+ endColumn: 13,
},
],
},
@@ -642,7 +700,10 @@ for (var foo of []) {
{
messageId: 'notInitialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 2,
+ column: 10,
+ endLine: 2,
+ endColumn: 13,
},
],
},
@@ -657,7 +718,10 @@ function foo() {
{
messageId: 'initialized',
data: { idName: 'bar' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 10,
},
],
},
@@ -670,7 +734,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'arr' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 34,
},
],
},
@@ -681,7 +748,10 @@ function foo() {
{
messageId: 'notInitialized',
data: { idName: 'arr' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 33,
},
],
},
@@ -698,7 +768,10 @@ const class1 = class NAME {
{
messageId: 'notInitialized',
data: { idName: 'name1' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 4,
+ column: 9,
+ endLine: 4,
+ endColumn: 32,
},
],
},
@@ -709,7 +782,10 @@ const class1 = class NAME {
{
messageId: 'initialized',
data: { idName: 'arr' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 5,
+ endLine: 1,
+ endColumn: 8,
},
],
},
@@ -720,7 +796,10 @@ const class1 = class NAME {
{
messageId: 'notInitialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 1,
+ column: 13,
+ endLine: 1,
+ endColumn: 32,
},
],
},
@@ -735,7 +814,10 @@ namespace myLib {
{
messageId: 'initialized',
data: { idName: 'numberOfGreetings' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 24,
},
],
},
@@ -750,7 +832,10 @@ namespace myLib {
{
messageId: 'notInitialized',
data: { idName: 'numberOfGreetings' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 7,
+ endLine: 3,
+ endColumn: 36,
},
],
},
@@ -771,17 +856,26 @@ namespace myLib1 {
{
messageId: 'initialized',
data: { idName: 'foo' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 3,
+ column: 9,
+ endLine: 3,
+ endColumn: 12,
},
{
messageId: 'initialized',
data: { idName: 'bar' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 5,
+ column: 9,
+ endLine: 5,
+ endColumn: 12,
},
{
messageId: 'initialized',
data: { idName: 'baz' },
- type: AST_NODE_TYPES.VariableDeclarator,
+ line: 7,
+ column: 11,
+ endLine: 7,
+ endColumn: 14,
},
],
},
diff --git a/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts b/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts
index 85fa8450ad21..0f956df18c07 100644
--- a/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts
+++ b/packages/eslint-plugin/tests/rules/naming-convention/naming-convention.test.ts
@@ -466,11 +466,11 @@ ruleTester.run('naming-convention', rule, {
{
const camelCaseVar = 1;
function camelCaseFunction() {}
- declare function camelCaseDeclaredFunction() {};
+ declare function camelCaseDeclaredFunction();
}
const PascalCaseVar = 1;
function PascalCaseFunction() {}
- declare function PascalCaseDeclaredFunction() {};
+ declare function PascalCaseDeclaredFunction();
`,
options: [
{ selector: 'default', format: ['camelCase'] },
@@ -1507,7 +1507,7 @@ ruleTester.run('naming-convention', rule, {
code: `
const PascalCaseVar = 1;
function PascalCaseFunction() {}
- declare function PascalCaseDeclaredFunction() {};
+ declare function PascalCaseDeclaredFunction();
`,
options: [
{ selector: 'default', format: ['snake_case'] },
diff --git a/packages/eslint-plugin/tests/rules/no-require-imports.test.ts b/packages/eslint-plugin/tests/rules/no-require-imports.test.ts
index 4fc743026e56..0a9e56fc8520 100644
--- a/packages/eslint-plugin/tests/rules/no-require-imports.test.ts
+++ b/packages/eslint-plugin/tests/rules/no-require-imports.test.ts
@@ -255,7 +255,7 @@ var lib5 = require?.('lib5'),
],
},
{
- code: 'import pkg = require(`./package.json`);',
+ code: "import pkg = require('./package.json');",
options: [{ allow: ['^some-package$'] }],
errors: [
{
diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts
index c910999fd27c..163286853e41 100644
--- a/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts
+++ b/packages/eslint-plugin/tests/rules/no-unsafe-assignment.test.ts
@@ -130,6 +130,7 @@ declare function Foo(props: Props): never;
},
},
},
+
{
code: `
declare function Foo(props: { a: string }): never;
@@ -195,7 +196,60 @@ class Foo {
`,
errors: [{ messageId: 'anyAssignment' }],
},
+ {
+ code: `
+const [x] = spooky;
+ `,
+ errors: [
+ {
+ messageId: 'anyAssignment',
+ data: { sender: 'error typed', receiver: 'error typed' },
+ },
+ ],
+ },
+ {
+ code: `
+const [[[x]]] = [spooky];
+ `,
+ errors: [
+ {
+ messageId: 'unsafeArrayPatternFromTuple',
+ data: { sender: 'error typed', receiver: 'error typed' },
+ },
+ ],
+ },
+ {
+ code: `
+const {
+ x: { y: z },
+} = { x: spooky };
+ `,
+ errors: [
+ {
+ messageId: 'unsafeArrayPatternFromTuple',
+ data: { sender: 'error typed', receiver: 'error typed' },
+ },
+ {
+ messageId: 'anyAssignment',
+ data: { sender: 'error typed', receiver: 'error typed' },
+ },
+ ],
+ },
+ {
+ code: `
+let value: number;
+value = spooky;
+ `,
+ errors: [
+ {
+ messageId: 'anyAssignment',
+ data: {
+ sender: 'error typed',
+ },
+ },
+ ],
+ },
{
code: `
const [x] = 1 as any;
@@ -215,8 +269,8 @@ const [x] = [] as any[];
{
messageId: 'unsafeAssignment',
data: {
- sender: 'Set',
- receiver: 'Set',
+ sender: '`Set`',
+ receiver: '`Set`',
},
},
],
@@ -227,8 +281,8 @@ const [x] = [] as any[];
{
messageId: 'unsafeAssignment',
data: {
- sender: 'Map',
- receiver: 'Map',
+ sender: '`Map`',
+ receiver: '`Map`',
},
},
],
@@ -239,8 +293,8 @@ const [x] = [] as any[];
{
messageId: 'unsafeAssignment',
data: {
- sender: 'Set',
- receiver: 'Set',
+ sender: '`Set`',
+ receiver: '`Set`',
},
},
],
@@ -251,8 +305,8 @@ const [x] = [] as any[];
{
messageId: 'unsafeAssignment',
data: {
- sender: 'Set>>',
- receiver: 'Set>>',
+ sender: '`Set>>`',
+ receiver: '`Set>>`',
},
},
],
@@ -327,8 +381,8 @@ const x = [...([] as any[])];
column: 43,
endColumn: 70,
data: {
- sender: 'Set>>',
- receiver: 'Set>>',
+ sender: '`Set>>`',
+ receiver: '`Set>>`',
},
},
],
diff --git a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts
index c9e0c762d74f..b4706224efac 100644
--- a/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts
+++ b/packages/eslint-plugin/tests/rules/no-unused-vars/no-unused-vars.test.ts
@@ -697,6 +697,18 @@ export type T = {
};
`,
`
+type Foo = string;
+export class Bar {
+ [x: Foo]: any;
+}
+ `,
+ `
+type Foo = string;
+export class Bar {
+ [x: Foo]: Foo;
+}
+ `,
+ `
namespace Foo {
export const Foo = 1;
}
diff --git a/packages/parser/src/index.ts b/packages/parser/src/index.ts
index 9ccf6b17ed8f..9799bc982d07 100644
--- a/packages/parser/src/index.ts
+++ b/packages/parser/src/index.ts
@@ -5,6 +5,7 @@ export {
ParserServicesWithoutTypeInformation,
clearCaches,
createProgram,
+ withoutProjectParserOptions,
} from '@typescript-eslint/typescript-estree';
// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
diff --git a/packages/scope-manager/src/referencer/ClassVisitor.ts b/packages/scope-manager/src/referencer/ClassVisitor.ts
index 94cb7ab59815..cf5d7022b258 100644
--- a/packages/scope-manager/src/referencer/ClassVisitor.ts
+++ b/packages/scope-manager/src/referencer/ClassVisitor.ts
@@ -320,6 +320,10 @@ class ClassVisitor extends Visitor {
// intentionally skip
}
+ protected TSIndexSignature(node: TSESTree.TSIndexSignature): void {
+ this.visitType(node);
+ }
+
protected StaticBlock(node: TSESTree.StaticBlock): void {
this.#referencer.scopeManager.nestClassStaticBlockScope(node);
diff --git a/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts b/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts
new file mode 100644
index 000000000000..64b3581b128e
--- /dev/null
+++ b/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts
@@ -0,0 +1,7 @@
+type Bar = number;
+
+class Foo {
+ [x: string]: any;
+ [y: Bar]: string;
+ [z: symbol]: Foo;
+}
diff --git a/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts.shot b/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts.shot
new file mode 100644
index 000000000000..52fa3c5480ec
--- /dev/null
+++ b/packages/scope-manager/tests/fixtures/class/declaration/index-signature.ts.shot
@@ -0,0 +1,98 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`class declaration index-signature 1`] = `
+ScopeManager {
+ variables: [
+ ImplicitGlobalConstTypeVariable,
+ Variable$2 {
+ defs: [
+ TypeDefinition$1 {
+ name: Identifier<"Bar">,
+ node: TSTypeAliasDeclaration$1,
+ },
+ ],
+ name: "Bar",
+ references: [
+ Reference$1 {
+ identifier: Identifier<"Bar">,
+ isRead: true,
+ isTypeReference: true,
+ isValueReference: false,
+ isWrite: false,
+ resolved: Variable$2,
+ },
+ ],
+ isValueVariable: false,
+ isTypeVariable: true,
+ },
+ Variable$3 {
+ defs: [
+ ClassNameDefinition$2 {
+ name: Identifier<"Foo">,
+ node: ClassDeclaration$2,
+ },
+ ],
+ name: "Foo",
+ references: [],
+ isValueVariable: true,
+ isTypeVariable: true,
+ },
+ Variable$4 {
+ defs: [
+ ClassNameDefinition$3 {
+ name: Identifier<"Foo">,
+ node: ClassDeclaration$2,
+ },
+ ],
+ name: "Foo",
+ references: [
+ Reference$2 {
+ identifier: Identifier<"Foo">,
+ isRead: true,
+ isTypeReference: true,
+ isValueReference: false,
+ isWrite: false,
+ resolved: Variable$4,
+ },
+ ],
+ isValueVariable: true,
+ isTypeVariable: true,
+ },
+ ],
+ scopes: [
+ GlobalScope$1 {
+ block: Program$3,
+ isStrict: false,
+ references: [],
+ set: Map {
+ "const" => ImplicitGlobalConstTypeVariable,
+ "Bar" => Variable$2,
+ "Foo" => Variable$3,
+ },
+ type: "global",
+ upper: null,
+ variables: [
+ ImplicitGlobalConstTypeVariable,
+ Variable$2,
+ Variable$3,
+ ],
+ },
+ ClassScope$2 {
+ block: ClassDeclaration$2,
+ isStrict: true,
+ references: [
+ Reference$1,
+ Reference$2,
+ ],
+ set: Map {
+ "Foo" => Variable$4,
+ },
+ type: "class",
+ upper: GlobalScope$1,
+ variables: [
+ Variable$4,
+ ],
+ },
+ ],
+}
+`;
diff --git a/packages/typescript-eslint/src/configs/all.ts b/packages/typescript-eslint/src/configs/all.ts
index 2cacebbfc7ca..f01ac17c8ddb 100644
--- a/packages/typescript-eslint/src/configs/all.ts
+++ b/packages/typescript-eslint/src/configs/all.ts
@@ -153,7 +153,6 @@ export default (
'@typescript-eslint/restrict-template-expressions': 'error',
'no-return-await': 'off',
'@typescript-eslint/return-await': 'error',
- '@typescript-eslint/sort-type-constituents': 'error',
'@typescript-eslint/strict-boolean-expressions': 'error',
'@typescript-eslint/switch-exhaustiveness-check': 'error',
'@typescript-eslint/triple-slash-reference': 'error',
diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts
index b58b0fff18c8..28c0b9848dc6 100644
--- a/packages/typescript-estree/src/convert.ts
+++ b/packages/typescript-estree/src/convert.ts
@@ -958,19 +958,46 @@ export class Converter {
case SyntaxKind.FunctionDeclaration: {
const isDeclare = hasModifier(SyntaxKind.DeclareKeyword, node);
+ const isAsync = hasModifier(SyntaxKind.AsyncKeyword, node);
+ const isGenerator = !!node.asteriskToken;
+ if (isDeclare) {
+ if (node.body) {
+ this.#throwError(
+ node,
+ 'An implementation cannot be declared in ambient contexts.',
+ );
+ } else if (isAsync) {
+ this.#throwError(
+ node,
+ "'async' modifier cannot be used in an ambient context.",
+ );
+ } else if (isGenerator) {
+ this.#throwError(
+ node,
+ 'Generators are not allowed in an ambient context.',
+ );
+ }
+ } else {
+ if (!node.body && isGenerator) {
+ this.#throwError(
+ node,
+ 'A function signature cannot be declared as a generator.',
+ );
+ }
+ }
const result = this.createNode<
TSESTree.FunctionDeclaration | TSESTree.TSDeclareFunction
>(node, {
- type:
- isDeclare || !node.body
- ? AST_NODE_TYPES.TSDeclareFunction
- : AST_NODE_TYPES.FunctionDeclaration,
- async: hasModifier(SyntaxKind.AsyncKeyword, node),
+ // declare implies no body due to the invariant above
+ type: !node.body
+ ? AST_NODE_TYPES.TSDeclareFunction
+ : AST_NODE_TYPES.FunctionDeclaration,
+ async: isAsync,
body: this.convertChild(node.body) || undefined,
declare: isDeclare,
expression: false,
- generator: !!node.asteriskToken,
+ generator: isGenerator,
id: this.convertChild(node.name),
params: this.convertParameters(node.parameters),
returnType: node.type && this.convertTypeAnnotation(node.type, node),
@@ -3053,6 +3080,9 @@ export class Converter {
);
}
case SyntaxKind.ExternalModuleReference: {
+ if (node.expression.kind !== SyntaxKind.StringLiteral) {
+ this.#throwError(node.expression, 'String literal expected.');
+ }
return this.createNode(node, {
type: AST_NODE_TYPES.TSExternalModuleReference,
expression: this.convertChild(node.expression),
diff --git a/packages/typescript-estree/src/index.ts b/packages/typescript-estree/src/index.ts
index c86262b7cd9d..5f6e8768d0c4 100644
--- a/packages/typescript-estree/src/index.ts
+++ b/packages/typescript-estree/src/index.ts
@@ -19,6 +19,7 @@ export { typescriptVersionIsAtLeast } from './version-check';
export * from './getModifiers';
export { TSError } from './node-utils';
export * from './clear-caches';
+export { withoutProjectParserOptions } from './withoutProjectParserOptions';
// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
diff --git a/packages/typescript-estree/src/withoutProjectParserOptions.ts b/packages/typescript-estree/src/withoutProjectParserOptions.ts
new file mode 100644
index 000000000000..e0298e0f5632
--- /dev/null
+++ b/packages/typescript-estree/src/withoutProjectParserOptions.ts
@@ -0,0 +1,21 @@
+import type { TSESTreeOptions } from './parser-options';
+
+/**
+ * Removes options that prompt the parser to parse the project with type
+ * information. In other words, you can use this if you are invoking the parser
+ * directly, to ensure that one file will be parsed in isolation, which is much,
+ * much faster.
+ *
+ * @see https://github.com/typescript-eslint/typescript-eslint/issues/8428
+ */
+export function withoutProjectParserOptions(
+ opts: TSESTreeOptions,
+): TSESTreeOptions {
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars -- The variables are meant to be omitted
+ const { EXPERIMENTAL_useProjectService, project, ...rest } = opts as Record<
+ string,
+ unknown
+ >;
+
+ return rest;
+}
diff --git a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts
new file mode 100644
index 000000000000..56a96ca2bd91
--- /dev/null
+++ b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts
@@ -0,0 +1,14 @@
+import { withoutProjectParserOptions } from '../../src';
+
+describe('withoutProjectParserOptions', () => {
+ it('removes only project parser options', () => {
+ const without = withoutProjectParserOptions({
+ comment: true,
+ EXPERIMENTAL_useProjectService: true,
+ project: true,
+ });
+ expect(without).toEqual({
+ comment: true,
+ });
+ });
+});
diff --git a/packages/website/blog/2022-09-18-automated-rule-docs-with-docusaurus-and-remark.md b/packages/website/blog/2022-09-18-automated-rule-docs-with-docusaurus-and-remark.md
index 7606e3e9f364..8009c1f0004f 100644
--- a/packages/website/blog/2022-09-18-automated-rule-docs-with-docusaurus-and-remark.md
+++ b/packages/website/blog/2022-09-18-automated-rule-docs-with-docusaurus-and-remark.md
@@ -220,9 +220,3 @@ I'm excited to focus in particular on [Docs: Proofread rule docs for clarity (#4
We'd like to extend thanks to [Joshua Chen](https://github.com/Josh-Cena), one of the Docusaurus maintainers who also has been helping us with Docusaurus — and helped proofread [this blog post's PR](https://github.com/typescript-eslint/typescript-eslint/pull/5593).
Without Joshua, this change would have taken us a great deal longer (if we'd have been able to tackle it at all).
Thanks Joshua! 🤗
-
-## 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/blog/2023-02-24-consistent-type-exports-and-imports-why-and-how.md b/packages/website/blog/2023-02-24-consistent-type-exports-and-imports-why-and-how.md
index cde68190cd45..37df608f1226 100644
--- a/packages/website/blog/2023-02-24-consistent-type-exports-and-imports-why-and-how.md
+++ b/packages/website/blog/2023-02-24-consistent-type-exports-and-imports-why-and-how.md
@@ -183,9 +183,3 @@ If it detects an import that only imports specifiers with inline `type` qualifie
You can read more about the rules' configuration options in their docs pages.
See [our Getting Started docs](/getting-started) for more information on linting your TypeScript code with typescript-eslint.
-
-## 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/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md b/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md
index 49d3bbf416e9..a69f5f71a840 100644
--- a/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md
+++ b/packages/website/blog/2023-03-13-announcing-typescript-eslint-v6-beta.md
@@ -374,9 +374,3 @@ We'd like to extend a sincere _thank you_ to everybody who pitched in to make ty
See the [v6.0.0 milestone](https://github.com/typescript-eslint/typescript-eslint/milestone/8) for the list of issues and associated merged pull requests.
-
-## 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/blog/2023-07-09-announcing-typescript-eslint-v6.md b/packages/website/blog/2023-07-09-announcing-typescript-eslint-v6.md
index 0920b0047905..26e7f674e07b 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
@@ -699,9 +699,3 @@ We'd like to extend a sincere _thank you_ to everybody who pitched in to make ty
- [TypeScript](https://github.com/microsoft/TypeScript/pull/54693)
See the [v6.0.0 milestone](https://github.com/typescript-eslint/typescript-eslint/milestone/8) for the list of issues and associated merged pull requests.
-
-## 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/blog/2023-09-18-parser-options-project-true.md b/packages/website/blog/2023-09-18-parser-options-project-true.md
index d279beae93b3..e2ffd4ef6d1f 100644
--- a/packages/website/blog/2023-09-18-parser-options-project-true.md
+++ b/packages/website/blog/2023-09-18-parser-options-project-true.md
@@ -144,9 +144,3 @@ We hope this option will eventually become the standard way to enable typed lint
However, because it's so new and untested, we're keeping it under the `EXPERIMENTAL_` prefix for at least all of the `6.X` versions.
See [Packages > Parser > `EXPERIMENTAL_useProjectService`](/packages/parser#experimental_useprojectservice) for more information.
-
-## 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/blog/2023-12-25-deprecating-formatting-rules.md b/packages/website/blog/2023-12-25-deprecating-formatting-rules.md
index 6767fedc9904..c25ddbf6a490 100644
--- a/packages/website/blog/2023-12-25-deprecating-formatting-rules.md
+++ b/packages/website/blog/2023-12-25-deprecating-formatting-rules.md
@@ -32,6 +32,11 @@ Per semantic versioning, formatting-related rules will remain available for all
**Our next major version, v7, will remove all deprecated rules.**
+:::note
+The [`stylistic` configurations](/users/configs#stylistic) are not deprecated or recommended-against.
+We'll continue to include those configs and their rules to help enforce TypeScript-related stylistic consistency for the foreseeable future.
+:::
+
## 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.
@@ -62,9 +67,3 @@ The equivalent stylistic rules for deprecated typescript-eslint rules are summar
| [`@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/blog/2024-05-27-announcing-typescript-eslint-v8-beta.mdx b/packages/website/blog/2024-05-27-announcing-typescript-eslint-v8-beta.mdx
index 1b3e75de2fbd..6bda8fcbf66e 100644
--- a/packages/website/blog/2024-05-27-announcing-typescript-eslint-v8-beta.mdx
+++ b/packages/website/blog/2024-05-27-announcing-typescript-eslint-v8-beta.mdx
@@ -239,6 +239,8 @@ If you author any ESLint rules that refer to the syntax mentioned by them, these
- If your code handles mapped types, change from `node.typeParameter.constraint` to `node.constraint` and from `node.typeParameter.name` to `node.key`
- [feat(ast-spec): remove deprecated type params](https://github.com/typescript-eslint/typescript-eslint/pull/8933)
- If you haven't already you must stop using those removed AST properties that were already marked as `@deprecated`
+- [fix(typescript-estree): add TSEnumBody node for TSEnumDeclaration body #8920](https://github.com/typescript-eslint/typescript-eslint/pull/8920)
+ - If your code handles enums, switch from `node.members` to `node.body.members`
### Custom Rule `meta.docs` Types
@@ -349,9 +351,3 @@ We'd like to extend a sincere _thank you_ to everybody who pitched in to make ty
See the [v8.0.0 milestone](https://github.com/typescript-eslint/typescript-eslint/milestone/9) for the list of issues and associated merged pull requests.
-
-## 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/docusaurus.config.mts b/packages/website/docusaurus.config.mts
index 9e23f2b65323..a728e223b119 100644
--- a/packages/website/docusaurus.config.mts
+++ b/packages/website/docusaurus.config.mts
@@ -9,6 +9,7 @@ import type { UserThemeConfig as AlgoliaThemeConfig } from '@docusaurus/theme-se
import type { Config } from '@docusaurus/types';
import { version } from './package.json';
+import { blogFooter } from './plugins/blog-footer';
import { generatedRuleDocs } from './plugins/generated-rule-docs';
import { rulesMeta } from './rulesMeta';
@@ -19,6 +20,8 @@ const githubUrl = 'https://github.com/typescript-eslint/typescript-eslint';
const presetClassicOptions: PresetClassicOptions = {
blog: {
blogSidebarCount: 'ALL',
+ // Allow Docusaurus TOC remark plugin to pick up the injected H2
+ beforeDefaultRemarkPlugins: [blogFooter],
remarkPlugins,
},
docs: {
@@ -287,6 +290,10 @@ const redirects: PluginRedirectOptions = {
from: '/linting/typed-linting/monorepos',
to: '/getting-started/typed-linting/monorepos',
},
+ {
+ from: '/maintenance/issues/rule-deprecations',
+ to: '/maintenance/issues/rule-deprecations-and-deletions',
+ },
],
};
diff --git a/packages/website/package.json b/packages/website/package.json
index 7222cad68a7a..a5c649efedf4 100644
--- a/packages/website/package.json
+++ b/packages/website/package.json
@@ -25,6 +25,7 @@
"@docusaurus/theme-common": "^3.2.1",
"@typescript-eslint/parser": "7.12.0",
"@typescript-eslint/website-eslint": "7.12.0",
+ "@uiw/react-shields": "2.0.1",
"clsx": "^2.1.0",
"eslint": "*",
"json5": "^2.2.3",
diff --git a/packages/website/plugins/blog-footer.ts b/packages/website/plugins/blog-footer.ts
new file mode 100644
index 000000000000..e943ea59328a
--- /dev/null
+++ b/packages/website/plugins/blog-footer.ts
@@ -0,0 +1,52 @@
+import type * as mdast from 'mdast';
+import type { Plugin } from 'unified';
+
+import { nodeIsParent } from './utils/nodes';
+
+export const blogFooter: Plugin = () => {
+ return (root, file) => {
+ if (
+ !nodeIsParent(root) ||
+ !(file.value as string).includes('')
+ ) {
+ return;
+ }
+
+ root.children.push(
+ {
+ children: [
+ {
+ type: 'text',
+ value: 'Supporting typescript-eslint',
+ },
+ ],
+ depth: 2,
+ type: 'heading',
+ } as mdast.Heading,
+ {
+ children: [
+ {
+ type: 'text',
+ value:
+ 'If you enjoyed this blog post and/or use typescript-eslint, please consider ',
+ },
+ {
+ children: [
+ {
+ type: 'text',
+ value: 'supporting us on Open Collective',
+ },
+ ],
+ url: 'https://opencollective.com/typescript-eslint',
+ type: 'link',
+ },
+ {
+ type: 'text',
+ value: `. We're a small volunteer team and could use your support to make the ESLint experience on TypeScript great. Thanks! 💖`,
+ },
+ ],
+ type: 'paragraph',
+ } as mdast.Paragraph,
+ );
+ };
+};
diff --git a/packages/website/plugins/generated-rule-docs/RuleDocsPage.ts b/packages/website/plugins/generated-rule-docs/RuleDocsPage.ts
index d5dc9c213fda..81b0fd368bed 100644
--- a/packages/website/plugins/generated-rule-docs/RuleDocsPage.ts
+++ b/packages/website/plugins/generated-rule-docs/RuleDocsPage.ts
@@ -1,8 +1,8 @@
import type { ESLintPluginRuleModule } from '@typescript-eslint/eslint-plugin/use-at-your-own-risk/rules';
import type * as unist from 'unist';
-import type { VFileWithStem } from './utils';
-import { findH2Index } from './utils';
+import type { VFileWithStem } from '../utils/rules';
+import { findH2Index } from '../utils/rules';
export interface RequiredHeadingIndices {
howToUse: number;
diff --git a/packages/website/plugins/generated-rule-docs/addESLintHashToCodeBlocksMeta.ts b/packages/website/plugins/generated-rule-docs/addESLintHashToCodeBlocksMeta.ts
index ac59bea53559..636a14aa30cf 100644
--- a/packages/website/plugins/generated-rule-docs/addESLintHashToCodeBlocksMeta.ts
+++ b/packages/website/plugins/generated-rule-docs/addESLintHashToCodeBlocksMeta.ts
@@ -1,8 +1,9 @@
import type { MdxJsxFlowElement } from 'mdast-util-mdx';
import type * as unist from 'unist';
+import { nodeIsCode } from '../utils/nodes';
+import { convertToPlaygroundHash } from '../utils/rules';
import type { RuleDocsPage } from './RuleDocsPage';
-import { convertToPlaygroundHash, nodeIsCode } from './utils';
const optionRegex = /option='(?