diff --git a/packages/eslint-plugin/docs/rules/README.md b/packages/eslint-plugin/docs/rules/README.md index 75c5723d748a..1cb9c5435fa1 100644 --- a/packages/eslint-plugin/docs/rules/README.md +++ b/packages/eslint-plugin/docs/rules/README.md @@ -55,3 +55,16 @@ module.exports = { ``` [Search for `🧱 extension rule`s](?=extension#rules) in this page to see all extension rules. + +## Frozen Rules + +When rules are feature complete, they are marked as frozen (indicated with ❄️ in the documentation). This applies to standalone rules that are complete, as well as [extension rules](#extension-rules) whose underlying core ESLint rules are frozen. After that point, we expect users to use [disable comments](https://eslint.org/docs/latest/use/configure/rules#using-configuration-comments-1) when they find an edge case that isn’t covered. + +When a rule is frozen, it means: + +- **Bug fixes**: We will still fix confirmed bugs. +- **New ECMAScript features**: We will ensure compatibility with new ECMAScript features, meaning the rule will not break on new syntax. +- **TypeScript support**: We will ensure compatibility with TypeScript syntax, meaning the rule will not break on TypeScript syntax and violations are appropriate for TypeScript. +- **New options**: We will not add any new options unless an option is the only way to fix a bug or support a newly-added ECMAScript feature. + +If you find that a frozen rule would work better for you with a change, we recommend copying the rule source code and modifying it to fit your needs. diff --git a/packages/eslint-plugin/src/rules/default-param-last.ts b/packages/eslint-plugin/src/rules/default-param-last.ts index 1d120720d26c..edfa85842df8 100644 --- a/packages/eslint-plugin/src/rules/default-param-last.ts +++ b/packages/eslint-plugin/src/rules/default-param-last.ts @@ -11,6 +11,7 @@ export default createRule({ docs: { description: 'Enforce default parameters to be last', extendsBaseRule: true, + frozen: true, }, messages: { shouldBeLast: 'Default parameters should be last.', diff --git a/packages/eslint-plugin/src/rules/dot-notation.ts b/packages/eslint-plugin/src/rules/dot-notation.ts index 69d53170c70e..73363938f13a 100644 --- a/packages/eslint-plugin/src/rules/dot-notation.ts +++ b/packages/eslint-plugin/src/rules/dot-notation.ts @@ -35,6 +35,7 @@ export default createRule({ docs: { description: 'Enforce dot notation whenever possible', extendsBaseRule: true, + frozen: true, recommended: 'stylistic', requiresTypeChecking: true, }, diff --git a/packages/eslint-plugin/src/rules/init-declarations.ts b/packages/eslint-plugin/src/rules/init-declarations.ts index 16b3f87e713c..fafc9a404f12 100644 --- a/packages/eslint-plugin/src/rules/init-declarations.ts +++ b/packages/eslint-plugin/src/rules/init-declarations.ts @@ -24,6 +24,7 @@ export default createRule({ description: 'Require or disallow initialization in variable declarations', extendsBaseRule: true, + frozen: true, }, hasSuggestions: baseRule.meta.hasSuggestions, messages: baseRule.meta.messages, diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 7ae9ec7627cf..f930292bf3f2 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -728,6 +728,7 @@ export default createRule({ type: 'suggestion', docs: { description: 'Require a consistent member declaration order', + frozen: true, }, messages: { incorrectGroupOrder: diff --git a/packages/eslint-plugin/src/rules/naming-convention.ts b/packages/eslint-plugin/src/rules/naming-convention.ts index 03500d825163..facda6fcbc44 100644 --- a/packages/eslint-plugin/src/rules/naming-convention.ts +++ b/packages/eslint-plugin/src/rules/naming-convention.ts @@ -70,6 +70,7 @@ export default createRule({ description: 'Enforce naming conventions for everything across a codebase', // technically only requires type checking if the user uses "type" modifiers + frozen: true, requiresTypeChecking: true, }, messages: { diff --git a/packages/eslint-plugin/src/rules/no-magic-numbers.ts b/packages/eslint-plugin/src/rules/no-magic-numbers.ts index 6ecddefd0645..04b48b3a1daa 100644 --- a/packages/eslint-plugin/src/rules/no-magic-numbers.ts +++ b/packages/eslint-plugin/src/rules/no-magic-numbers.ts @@ -53,6 +53,7 @@ export default createRule({ docs: { description: 'Disallow magic numbers', extendsBaseRule: true, + frozen: true, }, messages: baseRule.meta.messages, schema: [schema], diff --git a/packages/eslint-plugin/src/rules/prefer-destructuring.ts b/packages/eslint-plugin/src/rules/prefer-destructuring.ts index a3afb125a301..40c0de88ba40 100644 --- a/packages/eslint-plugin/src/rules/prefer-destructuring.ts +++ b/packages/eslint-plugin/src/rules/prefer-destructuring.ts @@ -76,6 +76,7 @@ export default createRule({ docs: { description: 'Require destructuring from arrays and/or objects', extendsBaseRule: true, + frozen: true, requiresTypeChecking: true, }, fixable: baseRule.meta.fixable, diff --git a/packages/utils/src/ts-eslint/Rule.ts b/packages/utils/src/ts-eslint/Rule.ts index 3b40254b0a6e..fb7b062fb0db 100644 --- a/packages/utils/src/ts-eslint/Rule.ts +++ b/packages/utils/src/ts-eslint/Rule.ts @@ -25,6 +25,11 @@ export interface RuleMetaDataDocs { * The URL of the rule's docs. */ url?: string; + + /** + * Mark this rule as frozen. + */ + frozen?: boolean; } export interface ExternalSpecifier { diff --git a/packages/website/src/components/RulesTable/index.tsx b/packages/website/src/components/RulesTable/index.tsx index 6f25e27e951d..68315eb926c9 100644 --- a/packages/website/src/components/RulesTable/index.tsx +++ b/packages/website/src/components/RulesTable/index.tsx @@ -55,9 +55,12 @@ function RuleRow({ return ( - - @typescript-eslint/{rule.name} - +
+ + @typescript-eslint/{rule.name} + + {rule.docs.frozen && ❄️} +

{interpolateCode(rule.docs.description)} diff --git a/packages/website/src/components/RulesTable/styles.module.css b/packages/website/src/components/RulesTable/styles.module.css index 3ffcec037609..7c6c7cfca093 100644 --- a/packages/website/src/components/RulesTable/styles.module.css +++ b/packages/website/src/components/RulesTable/styles.module.css @@ -145,3 +145,9 @@ text-align: center; cursor: default; } + +.ruleNameWrapper { + display: flex; + align-items: center; + gap: 0.5rem; +} diff --git a/packages/website/src/theme/MDXComponents/RuleAttributes.tsx b/packages/website/src/theme/MDXComponents/RuleAttributes.tsx index 0465e126aaad..ec1aa2d1d7d0 100644 --- a/packages/website/src/theme/MDXComponents/RuleAttributes.tsx +++ b/packages/website/src/theme/MDXComponents/RuleAttributes.tsx @@ -155,6 +155,18 @@ export function RuleAttributes({ name }: { name: string }): React.ReactNode { }); } + if (rule.docs.frozen) { + features.push({ + children: ( + <> + This rule is currently frozen{' '} + and is not accepting feature requests. + + ), + emoji: '❄️', + }); + } + return (
{features.map(feature => (