Skip to content

Commit d259b99

Browse files
fix(react-x): report no-class-component on class name, closes #1932
Highlight the class identifier instead of the whole class body. For a class expression, report on the variable name; for an anonymous class, report on the `class` keyword. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent dd66e7a commit d259b99

2 files changed

Lines changed: 68 additions & 1 deletion

File tree

plugins/eslint-plugin-react-x/src/rules/no-class-component/no-class-component.spec.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,69 @@ ruleTester.run(RULE_NAME, rule, {
278278
},
279279
],
280280
},
281+
{
282+
name: "class component reported on the class name only",
283+
code: tsx`
284+
class ParentComponent extends React.Component {
285+
render() {
286+
return <div />;
287+
}
288+
}
289+
`,
290+
errors: [
291+
{
292+
column: 7,
293+
data: {
294+
name: "ParentComponent",
295+
},
296+
endColumn: 22,
297+
endLine: 1,
298+
line: 1,
299+
messageId: "default",
300+
},
301+
],
302+
},
303+
{
304+
name: "class component assigned to a variable reported on the variable name",
305+
code: tsx`
306+
const ParentComponent = class extends React.Component {
307+
render() {
308+
return <div />;
309+
}
310+
};
311+
`,
312+
errors: [
313+
{
314+
column: 7,
315+
data: {
316+
name: "ParentComponent",
317+
},
318+
endColumn: 22,
319+
endLine: 1,
320+
line: 1,
321+
messageId: "default",
322+
},
323+
],
324+
},
325+
{
326+
name: "anonymous class component reported on the class keyword",
327+
code: tsx`
328+
export default class extends React.Component {
329+
render() {
330+
return <div />;
331+
}
332+
}
333+
`,
334+
errors: [
335+
{
336+
column: 16,
337+
endColumn: 21,
338+
endLine: 1,
339+
line: 1,
340+
messageId: "default",
341+
},
342+
],
343+
},
281344
{
282345
name: "error boundary with static componentDidCatch",
283346
code: tsx`

plugins/eslint-plugin-react-x/src/rules/no-class-component/no-class-component.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,18 @@ export function create(context: RuleContext<MessageID, []>): RuleListener {
3232
visitor,
3333
{
3434
"Program:exit"(program) {
35-
for (const { name = "anonymous", node: component } of api.getAllComponents(program)) {
35+
for (const { id, name = "anonymous", node: component } of api.getAllComponents(program)) {
3636
if (component.body.body.some((m) => core.isComponentDidCatch(m) || core.isGetDerivedStateFromError(m))) {
3737
continue;
3838
}
39+
const classToken = context.sourceCode.getFirstToken(component, {
40+
filter: (token) => token.value === "class",
41+
});
3942
context.report({
4043
data: {
4144
name,
4245
},
46+
loc: (id ?? classToken ?? component).loc,
4347
messageId: "default",
4448
node: component,
4549
});

0 commit comments

Comments
 (0)