Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: better rules table (filter rules by extension, etc.) #7666

Merged
merged 21 commits into from
Oct 18, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 18 additions & 9 deletions packages/eslint-plugin/docs/rules/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,27 @@ pagination_prev: null
slug: /
---

`@typescript-eslint/eslint-plugin` includes over 100 rules that detect best practice violations, bugs, and/or stylistic issues specifically for TypeScript code.
See [Configs](/linting/configs) for how to enable recommended rules using configs.
## Introduction
Zamiell marked this conversation as resolved.
Show resolved Hide resolved

## Supported Rules
`@typescript-eslint/eslint-plugin` includes over 100 rules that detect best practice violations, bugs, and/or stylistic issues specifically for TypeScript code. All of our rules are listed below.

import RulesTable from "@site/src/components/RulesTable";
Instead of enabling rules one by one, we recommend using one of [our pre-defined configs](/linting/configs) to easily enable a large set of
recommended rules.
Zamiell marked this conversation as resolved.
Show resolved Hide resolved

## Rules

<RulesTable ruleset="supported-rules" />
The rules are listed in alphabetical order. You can optionally sort them based on these categories:

import RulesTable from "@site/src/components/RulesTable";

## Extension Rules
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just realized https://typescript-eslint.io/rules/#extension-rules is probably the only canonical link to an explanation of extension rules out there. So we probably don't want to get rid of the heading. But I've pestered you so much on this PR 😅 I'll just add it in, and if you @Josh-Cena / @Zamiell disagree we can always revert before the release on Monday.

Copy link
Contributor Author

@Zamiell Zamiell Oct 18, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we really need a separate heading though? it is fairly self-explanatory what an extension rule is.
like, for example, consider class-methods-use-this.
if you go to the page for it, it says:

This rule extends the base eslint/class-methods-use-this rule. It adds support for ignoring override methods or methods on classes that implement an interface.

After reading this, i am not left wondering, "I have more questions about what an extension rule is, I wonder if there is a more formal definition out there in a dedicated section?"

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think folks need somewhere to hard-link to. It's similar to ESLint's issue for fixers vs suggestions: even if they're fairly straightforward for many, some folks coming in fresh have a hard time with them. I personally had a hard time both with fixers-vs-suggestions and what extension rules are.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh and - pretty soon I think we'll be able to trim down the metadata list down to one sentence per item!

...which just leaves the deeper explanation on extension rules.

<RulesTable />

In some cases, ESLint provides a rule itself, but it doesn't support TypeScript syntax; either it crashes, or it ignores the syntax, or it falsely reports against it.
In these cases, we create what we call an extension rule; a rule within our plugin that has the same functionality, but also supports TypeScript.
## Sorting
Zamiell marked this conversation as resolved.
Show resolved Hide resolved

<RulesTable ruleset="extension-rules" />
- "Config Group" refers to the configuration preset. We offer [three different config groups](/linting/configs) that allow users to enable a large set of recommended rules all at once.
- `🔧 fixable` refers to whether the rule contains an ESLint auto-fixer. If the rule has an auto-fixer, then some rule violations can be fixed by running `eslint` with the `--fix` flag. This will automatically change the code, which can save a lot of time! (It is a common pattern for developers to configure their IDE to automatically run `eslint --fix` when saving a TypeScript file.)
- `💡 has suggestions` refers to whether the rule will offer a suggestion of how to fix the code. Sometimes, it is not safe to automatically fix the code with an auto-fixer. But in these cases, we often have a good guess of what the correct fix should be, and we can provide it as a suggestion to the developer.
Zamiell marked this conversation as resolved.
Show resolved Hide resolved
- `💭 requires type information` refers to whether the rule needs to leverage the power of the TypeScript compiler in order to work properly. Rules that require type information are usually much slower than rules that don't. Thus, if linting performance becomes an issue in a gigantic codebase, a good first step might be make rules that require type information run only in CI.
- `🧱 extension rule` means that the rule was originally a [core ESLint rule](https://eslint.org/docs/latest/rules/). Some core ESLint rules do not support TypeScript syntax: either they crash, ignore the syntax, or falsely report against it. In these cases, we create an "extension rule": a rule within our plugin that has the same functionality, but also supports TypeScript.
Zamiell marked this conversation as resolved.
Show resolved Hide resolved
- `📐 formatting rule` means that the rule has to do with formatting. Formatting rules are mostly here for legacy purposes, because we [strongly recommend against using ESLint for formatting](/linting/troubleshooting/formatting).
- `💀 deprecated rule` means that the rule should no longer be used and will be removed from the plugin in a future version.
Zamiell marked this conversation as resolved.
Show resolved Hide resolved
Zamiell marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 5 additions & 2 deletions packages/eslint-plugin/docs/rules/camelcase.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ This rule has been deprecated in favour of the [`naming-convention`](./naming-co
:::

<!--
This doc file has been left on purpose because `camelcase` is a core ESLint rule.
This exists to help direct people to the replacement rule.
This doc file has been left on purpose because `camelcase` is a core ESLint
rule. This exists to help direct people to the replacement rule.

Note that there is no actual way to get to this page in the normal navigation,
so end-users will only be able to get to this page from the search bar.
-->
7 changes: 5 additions & 2 deletions packages/eslint-plugin/docs/rules/no-duplicate-imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ This rule has been deprecated in favour of the [`import/no-duplicates`](https://
:::

<!--
This doc file has been left on purpose because `import/no-duplicates` is commonly requested.
This exists to help direct people to the replacement rule.
This doc file has been left on purpose because `import/no-duplicates` is
commonly requested. This exists to help direct people to the replacement rule.

Note that there is no actual way to get to this page in the normal navigation,
so end-users will only be able to get to this page from the search bar.
-->
3 changes: 2 additions & 1 deletion packages/eslint-plugin/tests/docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ describe('Validating rule docs', () => {
const ignoredFiles = new Set([
'README.md',
'TEMPLATE.md',
// these rule docs were left behind on purpose for legacy reasons
// These rule docs were left behind on purpose for legacy reasons. See the
// comments in the files for more information.
'camelcase.md',
'no-duplicate-imports.md',
]);
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-plugin/tools/generate-breaking-changes.mts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ async function main(): Promise<void> {
recommended === 'recommended' ? '🟩' : '',
recommended === 'strict' ? '🔵' : '',
recommended === 'stylistic' ? '🔸' : '',
meta.type === 'layout' ? 'layout 💩' : '(todo)',
meta.type === 'layout' ? 'layout 📐' : '(todo)',
];
}),
]),
Expand Down
51 changes: 1 addition & 50 deletions packages/website/sidebars/sidebar.rules.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
const globby = require('globby');
const path = require('path');

const plugin = require('@typescript-eslint/eslint-plugin');

const rules = Object.entries(plugin.rules).map(([name, rule]) => {
Expand All @@ -10,43 +7,6 @@ const rules = Object.entries(plugin.rules).map(([name, rule]) => {
};
});

const deprecatedRules = new Set(rules.filter(rule => rule.meta.deprecated));

const formattingRules = new Set(
rules.filter(rule => !rule.meta.deprecated && rule.meta.type === 'layout'),
);

const extensionRules = new Set(
rules.filter(
rule => rule.meta.docs?.extendsBaseRule && !formattingRules.has(rule),
),
);

const typescriptRules = rules.filter(
rule =>
!rule.meta.deprecated &&
!extensionRules.has(rule) &&
!deprecatedRules.has(rule) &&
!formattingRules.has(rule),
);

const paths = globby
.sync('*.md', {
cwd: path.join(__dirname, '../../eslint-plugin/docs/rules'),
})
.map(item => {
return {
name: path.basename(item, '.md'),
};
})
.filter(item => {
return (
item.name !== 'README' &&
item.name !== 'TEMPLATE' &&
!rules.some(a => a.name === item.name)
);
});

function createCategory(label, rules, additionalItems = []) {
return {
items: [
Expand All @@ -68,17 +28,8 @@ module.exports = {
someSidebar: [
'README',
{
...createCategory('TypeScript Rules', Array.from(typescriptRules)),
collapsed: false,
},
{
...createCategory('Extension Rules', Array.from(extensionRules)),
...createCategory('Rules', rules),
collapsed: false,
},
createCategory('Formatting Rules', Array.from(formattingRules)),
createCategory('Deprecated Rules', [
...Array.from(deprecatedRules),
...paths,
]),
],
Zamiell marked this conversation as resolved.
Show resolved Hide resolved
};