diff --git a/apps/website/content/docs/rules/overview.mdx b/apps/website/content/docs/rules/overview.mdx
index 54f1073c1..f2b535d9f 100644
--- a/apps/website/content/docs/rules/overview.mdx
+++ b/apps/website/content/docs/rules/overview.mdx
@@ -135,7 +135,7 @@ full: true
| [`component-name`](naming-convention-component-name) | 0️⃣ | `🔍` `⚙️` | Enforces naming conventions for components. |
| [`filename`](naming-convention-filename) | 0️⃣ | `🔍` `⚙️` | Enforces naming convention for JSX files. |
| [`filename-extension`](naming-convention-filename-extension) | 0️⃣ | `🔍` `⚙️` | Enforces consistent use of the JSX file extension. |
-| [`use-state`](naming-convention-use-state) | 0️⃣ | `🔍` | Enforces destructuring and symmetric naming of `useState` hook value and setter variables. |
+| [`use-state`](naming-convention-use-state) | 0️⃣ | `🔍` | Enforces destructuring and symmetric naming of `useState` hook value and setter. |
## Debug Rules
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.spec.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.spec.ts
index cedf902c5..1b166a67c 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.spec.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.spec.ts
@@ -5,21 +5,21 @@ ruleTester.run(RULE_NAME, rule, {
invalid: [
{
code: /* tsx */ ``,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "usePascalCase" }],
},
{
code: /* tsx */ ``,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "useConstantCase" }],
options: [{ rule: "CONSTANT_CASE" }],
},
{
code: /* tsx */ ``,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "useConstantCase" }],
options: ["CONSTANT_CASE"],
},
{
code: /* tsx */ ``,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "usePascalCase" }],
options: [{ allowAllCaps: false, rule: "PascalCase" }],
},
{
@@ -28,7 +28,7 @@ ruleTester.run(RULE_NAME, rule, {
return
foo
}
`,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "useConstantCase" }],
options: [{ rule: "CONSTANT_CASE" }],
},
{
@@ -39,7 +39,7 @@ ruleTester.run(RULE_NAME, rule, {
)
}
`,
- errors: [{ messageId: "componentName" }],
+ errors: [{ messageId: "useConstantCase" }],
options: [{ allowLeadingUnderscore: false, rule: "CONSTANT_CASE" }],
},
],
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.ts
index af1fd4127..c914b8cfe 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/component-name.ts
@@ -1,12 +1,10 @@
import * as AST from "@eslint-react/ast";
import { useComponentCollector, useComponentCollectorLegacy } from "@eslint-react/core";
-import type { _ } from "@eslint-react/eff";
-import { constFalse } from "@eslint-react/eff";
+import { _ } from "@eslint-react/eff";
import * as JSX from "@eslint-react/jsx";
import type { RuleFeature } from "@eslint-react/shared";
import { RE_CONSTANT_CASE, RE_PASCAL_CASE } from "@eslint-react/shared";
import type { JSONSchema4 } from "@typescript-eslint/utils/json-schema";
-import type { CamelCase } from "string-ts";
import { match } from "ts-pattern";
import { createRule } from "../utils";
@@ -18,7 +16,9 @@ export const RULE_FEATURES = [
"CFG",
] as const satisfies RuleFeature[];
-export type MessageID = CamelCase;
+export type MessageID =
+ | "usePascalCase"
+ | "useConstantCase";
type Case = "CONSTANT_CASE" | "PascalCase";
@@ -88,32 +88,43 @@ function normalizeOptions(options: Options) {
} as const;
}
-function validate(name: string | _, options: ReturnType) {
- if (name == null) return false;
- if (options.excepts.some((regex) => regex.test(name))) {
- return true;
+function getViolationMessage(name: string | _, options: ReturnType): MessageID | _ {
+ if (name == null) return _;
+ const {
+ allowAllCaps = false,
+ allowLeadingUnderscore = false,
+ allowNamespace = false,
+ excepts,
+ rule,
+ } = options;
+ if (excepts.some((regex) => regex.test(name))) {
+ return _;
}
let normalized = name
.normalize("NFKD")
.replace(/[\u0300-\u036F]/g, "");
normalized = normalized.split(".").at(-1) ?? normalized;
- const { allowLeadingUnderscore = false, allowNamespace = false } = options;
if (allowNamespace) {
normalized = normalized.replace(":", "");
}
if (allowLeadingUnderscore) {
normalized = normalized.replace(/^_/, "");
}
- return match(options.rule)
- .with("CONSTANT_CASE", () => RE_CONSTANT_CASE.test(normalized))
+ return match(rule)
+ .with("CONSTANT_CASE", () =>
+ RE_CONSTANT_CASE.test(normalized)
+ ? _
+ : "useConstantCase")
.with("PascalCase", () => {
// Allow all caps if the string is shorter than 4 characters. e.g. UI, CSS, SVG, etc.
if (normalized.length > 3 && /^[A-Z]+$/u.test(normalized)) {
- return options.allowAllCaps ?? false;
+ return allowAllCaps
+ ? _
+ : "usePascalCase";
}
- return RE_PASCAL_CASE.test(normalized);
+ return RE_PASCAL_CASE.test(normalized) ? _ : "usePascalCase";
})
- .otherwise(constFalse);
+ .otherwise(() => _);
}
export default createRule({
@@ -124,7 +135,8 @@ export default createRule({
description: "enforce component naming convention to 'PascalCase' or 'CONSTANT_CASE'",
},
messages: {
- componentName: "A component name must be in {{case}}.",
+ useConstantCase: "Component name '{{name}}' must be in CONSTANT_CASE.",
+ usePascalCase: "Component name '{{name}}' must be in PascalCase.",
},
schema,
},
@@ -143,14 +155,13 @@ export default createRule({
if (/^[a-z]/u.test(name)) {
return;
}
- if (validate(name, options)) {
- return;
- }
+ const violation = getViolationMessage(name, options);
+ if (violation == null) return;
context.report({
- messageId: "componentName",
+ messageId: violation,
node,
data: {
- case: options.rule,
+ name,
},
});
},
@@ -160,29 +171,30 @@ export default createRule({
for (const { node: component } of functionComponents.values()) {
const id = AST.getFunctionIdentifier(component);
if (id?.name == null) continue;
- if (validate(id.name, options)) {
- continue;
- }
+ const name = id.name;
+ const violation = getViolationMessage(name, options);
+ if (violation == null) continue;
context.report({
- messageId: "componentName",
+ messageId: violation,
node: id,
data: {
- case: options.rule,
+ name,
},
});
}
for (const { node: component } of classComponents.values()) {
const id = AST.getClassIdentifier(component);
if (id?.name == null) continue;
- if (!validate(id.name, options)) {
- context.report({
- messageId: "componentName",
- node: id,
- data: {
- case: options.rule,
- },
- });
- }
+ const name = id.name;
+ const violation = getViolationMessage(name, options);
+ if (violation == null) continue;
+ context.report({
+ messageId: violation,
+ node: id,
+ data: {
+ case: options.rule,
+ },
+ });
}
},
};
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.spec.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.spec.ts
index ea2411d86..b15a18c49 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.spec.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.spec.ts
@@ -11,7 +11,7 @@ ruleTester.run(RULE_NAME, rule, {
code: withoutJSX,
errors: [
{
- messageId: "filenameExtensionUnexpected",
+ messageId: "useJsxFileExtensionAsNeeded",
},
],
filename: "react.tsx",
@@ -21,7 +21,7 @@ ruleTester.run(RULE_NAME, rule, {
code: withoutJSX,
errors: [
{
- messageId: "filenameExtensionUnexpected",
+ messageId: "useJsxFileExtensionAsNeeded",
},
],
filename: "react.tsx",
@@ -31,7 +31,7 @@ ruleTester.run(RULE_NAME, rule, {
code: withJSXElement,
errors: [
{
- messageId: "filenameExtensionInvalid",
+ messageId: "useJsxFileExtension",
},
],
filename: "react.tsx",
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.ts
index 38c73637d..1a6eff735 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/filename-extension.ts
@@ -12,8 +12,8 @@ export const RULE_FEATURES = [
] as const satisfies RuleFeature[];
export type MessageID =
- | "filenameExtensionInvalid"
- | "filenameExtensionUnexpected";
+ | "useJsxFileExtension"
+ | "useJsxFileExtensionAsNeeded";
type Allow = "always" | "as-needed";
@@ -74,8 +74,8 @@ export default createRule({
description: "enforce naming convention for JSX file extensions",
},
messages: {
- filenameExtensionInvalid: "The JSX file extension is required.",
- filenameExtensionUnexpected: "Use JSX file extension as needed.",
+ useJsxFileExtension: "Use {{extensions}} file extension for JSX files.",
+ useJsxFileExtensionAsNeeded: "Do not use {{extensions}} file extension for files without JSX.",
},
schema,
},
@@ -86,6 +86,7 @@ export default createRule({
const extensions = isObject(options) && "extensions" in options
? options.extensions
: defaultOptions[0].extensions;
+ const extensionsString = extensions.map((ext) => `'${ext}'`).join(", ");
const filename = context.filename;
let hasJSXNode = false;
@@ -102,8 +103,11 @@ export default createRule({
const isJSXExt = extensions.includes(fileNameExt);
if (hasJSXNode && !isJSXExt) {
context.report({
- messageId: "filenameExtensionInvalid",
+ messageId: "useJsxFileExtension",
node,
+ data: {
+ extensions: extensionsString,
+ },
});
return;
}
@@ -119,8 +123,11 @@ export default createRule({
&& allow === "as-needed"
) {
context.report({
- messageId: "filenameExtensionUnexpected",
+ messageId: "useJsxFileExtensionAsNeeded",
node,
+ data: {
+ extensions: extensionsString,
+ },
});
}
},
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.md b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.md
index bc523fc6e..13377c730 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.md
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.md
@@ -20,7 +20,7 @@ react-naming-convention/use-state
## What it does
-Enforces destructuring and symmetric naming of `useState` hook value and setter variables
+Enforces destructuring and symmetric naming of `useState` hook value and setter
## Examples
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts
index f50f91b85..255b89443 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.spec.ts
@@ -12,7 +12,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
@@ -28,7 +28,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
@@ -51,7 +51,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
@@ -69,7 +69,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
@@ -87,7 +87,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
@@ -105,7 +105,7 @@ ruleTester.run(RULE_NAME, rule, {
}
`,
errors: [{
- messageId: "useState",
+ messageId: "unexpected",
data: {
setterName: "setState",
stateName: "state",
diff --git a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.ts b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.ts
index c92b080cd..4480a45fe 100644
--- a/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.ts
+++ b/packages/plugins/eslint-plugin-react-naming-convention/src/rules/use-state.ts
@@ -7,7 +7,6 @@ import {
import type { RuleFeature } from "@eslint-react/shared";
import { getSettingsFromContext } from "@eslint-react/shared";
import { AST_NODE_TYPES as T } from "@typescript-eslint/types";
-import type { CamelCase } from "string-ts";
import { capitalize } from "string-ts";
import { createRule } from "../utils";
@@ -18,7 +17,7 @@ export const RULE_FEATURES = [
"CHK",
] as const satisfies RuleFeature[];
-export type MessageID = CamelCase;
+export type MessageID = "unexpected";
function isSetterNameLoose(name: string) {
// eslint-disable-next-line @typescript-eslint/no-misused-spread
@@ -32,11 +31,11 @@ export default createRule<[], MessageID>({
meta: {
type: "problem",
docs: {
- description: "enforce destructuring and symmetric naming of 'useState' hook value and setter variables",
+ description: "enforce destructuring and symmetric naming of 'useState' hook value and setter",
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
- useState: "An useState call is not destructured into value + setter pair.",
+ unexpected: "An useState call is not destructured into value + setter pair.",
},
schema: [],
},
@@ -73,14 +72,14 @@ export default createRule<[], MessageID>({
const { id } = hookCall.parent;
switch (id.type) {
case T.Identifier: {
- context.report({ messageId: "useState", node: id });
+ context.report({ messageId: "unexpected", node: id });
break;
}
case T.ArrayPattern: {
const [state, setState] = id.elements;
if (state?.type === T.ObjectPattern && setState?.type === T.Identifier) {
if (!isSetterNameLoose(setState.name)) {
- context.report({ messageId: "useState", node: id });
+ context.report({ messageId: "unexpected", node: id });
}
break;
}
@@ -92,7 +91,7 @@ export default createRule<[], MessageID>({
if (setStateName === expectedSetterName) {
return;
}
- context.report({ messageId: "useState", node: id });
+ context.report({ messageId: "unexpected", node: id });
}
}
}
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.spec.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.spec.ts
index 94199189c..6b9083796 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.spec.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.spec.ts
@@ -13,7 +13,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInLifecycle",
+ messageId: "expectedRemoveEventListenerInUnmount",
},
],
},
@@ -27,7 +27,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -46,7 +46,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -63,15 +63,15 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
data: { effectMethodKind: "useEffect", eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "removeEventListener" },
},
],
@@ -89,15 +89,15 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
data: { effectMethodKind: "useEffect", eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "removeEventListener" },
},
],
@@ -113,7 +113,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -131,15 +131,15 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
data: { effectMethodKind: "useEffect", eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "addEventListener" },
},
{
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
data: { eventMethodKind: "removeEventListener" },
},
],
@@ -158,7 +158,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -176,7 +176,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -194,7 +194,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -212,7 +212,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -230,7 +230,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -248,7 +248,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -266,7 +266,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -284,7 +284,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -302,7 +302,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -321,7 +321,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -341,7 +341,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -360,7 +360,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -379,7 +379,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -399,10 +399,10 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -423,7 +423,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -453,7 +453,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -484,7 +484,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -515,7 +515,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -545,7 +545,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -576,7 +576,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -607,7 +607,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
@@ -638,7 +638,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
},
],
},
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.ts
index af001aac9..e17eaf101 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-event-listener.ts
@@ -21,9 +21,9 @@ export const RULE_FEATURES = [
] as const satisfies RuleFeature[];
export type MessageID =
- | "noLeakedEventListenerInEffect"
- | "noLeakedEventListenerInLifecycle"
- | "noLeakedEventListenerOfInlineFunction";
+ | "expectedRemoveEventListenerInCleanup"
+ | "expectedRemoveEventListenerInUnmount"
+ | "unexpectedInlineFunction";
// #endregion
@@ -153,11 +153,11 @@ export default createRule<[], MessageID>({
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
- noLeakedEventListenerInEffect:
+ expectedRemoveEventListenerInCleanup:
"An 'addEventListener' in '{{effectMethodKind}}' should have a corresponding 'removeEventListener' in its cleanup function.",
- noLeakedEventListenerInLifecycle:
+ expectedRemoveEventListenerInUnmount:
"An 'addEventListener' in 'componentDidMount' should have a corresponding 'removeEventListener' in 'componentWillUnmount' method.",
- noLeakedEventListenerOfInlineFunction: "A/an '{{eventMethodKind}}' should not have an inline listener function.",
+ unexpectedInlineFunction: "A/an '{{eventMethodKind}}' should not have an inline listener function.",
},
schema: [],
},
@@ -211,7 +211,7 @@ export default createRule<[], MessageID>({
return;
}
context.report({
- messageId: "noLeakedEventListenerOfInlineFunction",
+ messageId: "unexpectedInlineFunction",
node: listener,
data: { eventMethodKind: callKind },
});
@@ -291,7 +291,7 @@ export default createRule<[], MessageID>({
case "setup":
case "cleanup":
context.report({
- messageId: "noLeakedEventListenerInEffect",
+ messageId: "expectedRemoveEventListenerInCleanup",
node: aEntry.node,
data: {
effectMethodKind: "useEffect",
@@ -301,7 +301,7 @@ export default createRule<[], MessageID>({
case "mount":
case "unmount":
context.report({
- messageId: "noLeakedEventListenerInLifecycle",
+ messageId: "expectedRemoveEventListenerInUnmount",
node: aEntry.node,
});
continue;
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.spec.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.spec.ts
index d7cbbe06d..08d63e273 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.spec.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.spec.ts
@@ -13,7 +13,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedIntervalNoIntervalId",
+ messageId: "expectedIntervalId",
},
],
},
@@ -27,7 +27,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedIntervalNoIntervalId",
+ messageId: "expectedIntervalId",
},
],
},
@@ -41,7 +41,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedIntervalNoIntervalId",
+ messageId: "expectedIntervalId",
},
],
},
@@ -55,7 +55,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedIntervalInEffect",
+ messageId: "expectedClearIntervalInCleanup",
},
],
},
@@ -69,7 +69,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedIntervalInEffect",
+ messageId: "expectedClearIntervalInCleanup",
},
],
},
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.ts
index ea966217f..6619e1061 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-interval.ts
@@ -19,9 +19,9 @@ export const RULE_FEATURES = [
] as const satisfies RuleFeature[];
export type MessageID =
- | "noLeakedIntervalInEffect"
- | "noLeakedIntervalInLifecycle"
- | "noLeakedIntervalNoIntervalId";
+ | "expectedClearIntervalInCleanup"
+ | "expectedClearIntervalInUnmount"
+ | "expectedIntervalId";
// #endregion
@@ -64,11 +64,11 @@ export default createRule<[], MessageID>({
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
- noLeakedIntervalInEffect:
+ expectedClearIntervalInCleanup:
"A 'setInterval' created in '{{ kind }}' must be cleared with 'clearInterval' in the cleanup function.",
- noLeakedIntervalInLifecycle:
+ expectedClearIntervalInUnmount:
"A 'setInterval' created in '{{ kind }}' must be cleared with 'clearInterval' in the 'componentWillUnmount' method.",
- noLeakedIntervalNoIntervalId: "A 'setInterval' must be assigned to a variable for proper cleanup.",
+ expectedIntervalId: "A 'setInterval' must be assigned to a variable for proper cleanup.",
},
schema: [],
},
@@ -104,7 +104,7 @@ export default createRule<[], MessageID>({
const intervalIdNode = VAR.getVariableDeclaratorId(node);
if (intervalIdNode == null) {
context.report({
- messageId: "noLeakedIntervalNoIntervalId",
+ messageId: "expectedIntervalId",
node,
});
break;
@@ -150,7 +150,7 @@ export default createRule<[], MessageID>({
case "setup":
case "cleanup":
context.report({
- messageId: "noLeakedIntervalInEffect",
+ messageId: "expectedClearIntervalInCleanup",
node: sEntry.node,
data: {
kind: "useEffect",
@@ -160,7 +160,7 @@ export default createRule<[], MessageID>({
case "mount":
case "unmount":
context.report({
- messageId: "noLeakedIntervalInLifecycle",
+ messageId: "expectedClearIntervalInUnmount",
node: sEntry.node,
data: {
kind: "componentDidMount",
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.spec.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.spec.ts
index 551fc4ba3..b9e287196 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.spec.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.spec.ts
@@ -18,7 +18,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserver",
+ messageId: "expectedDisconnectOrUnobserveInCleanup",
},
],
},
@@ -40,7 +40,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserver",
+ messageId: "expectedDisconnectOrUnobserveInCleanup",
},
],
},
@@ -58,7 +58,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserverNoFloatingInstance",
+ messageId: "unexpectedFloatingInstance",
},
],
},
@@ -81,7 +81,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserver",
+ messageId: "expectedDisconnectOrUnobserveInCleanup",
},
],
},
@@ -107,7 +107,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserverInControlFlow",
+ messageId: "expectedDisconnectInControlFlow",
},
],
},
@@ -133,7 +133,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserverInControlFlow",
+ messageId: "expectedDisconnectInControlFlow",
},
],
},
@@ -153,7 +153,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedResizeObserverNoFloatingInstance",
+ messageId: "unexpectedFloatingInstance",
},
],
},
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.ts
index 16a3a45e7..712d7e3b5 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-resize-observer.ts
@@ -20,9 +20,9 @@ export const RULE_FEATURES = [
] as const satisfies RuleFeature[];
export type MessageID =
- | "noLeakedResizeObserver"
- | "noLeakedResizeObserverInControlFlow"
- | "noLeakedResizeObserverNoFloatingInstance";
+ | "expectedDisconnectInControlFlow"
+ | "expectedDisconnectOrUnobserveInCleanup"
+ | "unexpectedFloatingInstance";
// #endregion
@@ -92,11 +92,11 @@ export default createRule<[], MessageID>({
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
- noLeakedResizeObserver:
- "A 'ResizeObserver' instance created in 'useEffect' must be disconnected in the cleanup function.",
- noLeakedResizeObserverInControlFlow:
+ expectedDisconnectInControlFlow:
"Dynamically added 'ResizeObserver.observe' should be cleared all at once using 'ResizeObserver.disconnect' in the cleanup function.",
- noLeakedResizeObserverNoFloatingInstance:
+ expectedDisconnectOrUnobserveInCleanup:
+ "A 'ResizeObserver' instance created in 'useEffect' must be disconnected in the cleanup function.",
+ unexpectedFloatingInstance:
"A 'ResizeObserver' instance created in component or custom Hook must be assigned to a variable for proper cleanup.",
},
schema: [],
@@ -188,7 +188,7 @@ export default createRule<[], MessageID>({
const id = getInstanceID(node);
if (id == null) {
context.report({
- messageId: "noLeakedResizeObserverNoFloatingInstance",
+ messageId: "unexpectedFloatingInstance",
node,
});
return;
@@ -212,14 +212,14 @@ export default createRule<[], MessageID>({
const hasDynamicallyAdded = oentries
.some((e) => !isPhaseNode(AST.findParentNode(e.node, or(isDynamic, isPhaseNode))));
if (hasDynamicallyAdded) {
- context.report({ messageId: "noLeakedResizeObserverInControlFlow", node });
+ context.report({ messageId: "expectedDisconnectInControlFlow", node });
continue;
}
for (const oEntry of oentries) {
if (uentries.some((uEntry) => isInstanceIDEqual(uEntry.element, oEntry.element, context))) {
continue;
}
- context.report({ messageId: "noLeakedResizeObserver", node: oEntry.node });
+ context.report({ messageId: "expectedDisconnectOrUnobserveInCleanup", node: oEntry.node });
}
}
},
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.spec.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.spec.ts
index 2f03113be..e0b92ef98 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.spec.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.spec.ts
@@ -13,7 +13,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedTimeoutNoTimeoutId",
+ messageId: "expectedTimeoutId",
},
],
},
@@ -27,7 +27,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedTimeoutNoTimeoutId",
+ messageId: "expectedTimeoutId",
},
],
},
@@ -41,7 +41,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedTimeoutNoTimeoutId",
+ messageId: "expectedTimeoutId",
},
],
},
@@ -55,7 +55,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedTimeoutInEffect",
+ messageId: "expectedClearTimeoutInCleanup",
},
],
},
@@ -69,7 +69,7 @@ ruleTester.run(RULE_NAME, rule, {
`,
errors: [
{
- messageId: "noLeakedTimeoutInEffect",
+ messageId: "expectedClearTimeoutInCleanup",
},
],
},
diff --git a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.ts b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.ts
index 89df7c287..11967f58f 100644
--- a/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.ts
+++ b/packages/plugins/eslint-plugin-react-web-api/src/rules/no-leaked-timeout.ts
@@ -19,9 +19,9 @@ export const RULE_FEATURES = [
] as const satisfies RuleFeature[];
export type MessageID =
- | "noLeakedTimeoutInEffect"
- | "noLeakedTimeoutInLifecycle"
- | "noLeakedTimeoutNoTimeoutId";
+ | "expectedClearTimeoutInCleanup"
+ | "expectedClearTimeoutInUnmount"
+ | "expectedTimeoutId";
// #endregion
@@ -63,11 +63,11 @@ export default createRule<[], MessageID>({
[Symbol.for("rule_features")]: RULE_FEATURES,
},
messages: {
- noLeakedTimeoutInEffect:
+ expectedClearTimeoutInCleanup:
"A 'setTimeout' created in '{{ kind }}' must be cleared with 'clearTimeout' in the cleanup function.",
- noLeakedTimeoutInLifecycle:
+ expectedClearTimeoutInUnmount:
"A 'setTimeout' created in '{{ kind }}' must be cleared with 'clearTimeout' in the 'componentWillUnmount' method.",
- noLeakedTimeoutNoTimeoutId: "A 'setTimeout' must be assigned to a variable for proper cleanup.",
+ expectedTimeoutId: "A 'setTimeout' must be assigned to a variable for proper cleanup.",
},
schema: [],
},
@@ -100,7 +100,7 @@ export default createRule<[], MessageID>({
const timeoutIdNode = VAR.getVariableDeclaratorId(node);
if (timeoutIdNode == null) {
context.report({
- messageId: "noLeakedTimeoutNoTimeoutId",
+ messageId: "expectedTimeoutId",
node,
});
break;
@@ -139,7 +139,7 @@ export default createRule<[], MessageID>({
case "setup":
case "cleanup":
context.report({
- messageId: "noLeakedTimeoutInEffect",
+ messageId: "expectedClearTimeoutInCleanup",
node: sEntry.node,
data: {
kind: "useEffect",
@@ -149,7 +149,7 @@ export default createRule<[], MessageID>({
case "mount":
case "unmount":
context.report({
- messageId: "noLeakedTimeoutInLifecycle",
+ messageId: "expectedClearTimeoutInUnmount",
node: sEntry.node,
data: {
kind: "componentDidMount",