Skip to content

Commit 4733b52

Browse files
committed
feat(linter/no-extraneous-class): add conditional fixer (#10798)
## What This PR Does Adds a `suggestion`-level auto-fixer to remove empty classes. Empty classes with decorators are not removed.
1 parent 2b890ab commit 4733b52

File tree

2 files changed

+40
-10
lines changed

2 files changed

+40
-10
lines changed

crates/oxc_linter/src/rules/typescript/no_extraneous_class.rs

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,18 +69,17 @@ declare_oxc_lint!(
6969
/// ```
7070
NoExtraneousClass,
7171
typescript,
72-
suspicious
72+
suspicious,
73+
dangerous_suggestion
7374
);
7475

7576
fn empty_class_diagnostic(span: Span, has_decorators: bool) -> OxcDiagnostic {
76-
let diagnostic = OxcDiagnostic::warn("Unexpected empty class.").with_label(span);
77-
if has_decorators {
78-
diagnostic.with_help(
79-
r#"Set "allowWithDecorator": true in your config to allow empty decorated classes"#,
80-
)
77+
let help = if has_decorators {
78+
r#"Set "allowWithDecorator": true in your config to allow empty decorated classes"#
8179
} else {
82-
diagnostic
83-
}
80+
"Delete this class"
81+
};
82+
OxcDiagnostic::warn("Unexpected empty class.").with_label(span).with_help(help)
8483
}
8584

8685
fn only_static_no_extraneous_class_diagnostic(span: Span) -> OxcDiagnostic {
@@ -147,7 +146,22 @@ impl Rule for NoExtraneousClass {
147146
unsafe { std::hint::assert_unchecked(start <= u32::MAX as usize) };
148147
span = span.shrink_left(start as u32);
149148
}
150-
ctx.diagnostic(empty_class_diagnostic(span, !class.decorators.is_empty()));
149+
let has_decorators = !class.decorators.is_empty();
150+
ctx.diagnostic_with_suggestion(
151+
empty_class_diagnostic(span, has_decorators),
152+
|fixer| {
153+
if has_decorators {
154+
return fixer.noop();
155+
}
156+
if let Some(AstKind::ExportNamedDeclaration(decl)) =
157+
ctx.nodes().parent_kind(node.id())
158+
{
159+
fixer.delete(decl)
160+
} else {
161+
fixer.delete(class)
162+
}
163+
},
164+
);
151165
}
152166
}
153167
[ClassElement::MethodDefinition(constructor)] if constructor.kind.is_constructor() => {
@@ -308,5 +322,18 @@ fn test() {
308322
("abstract class Foo { constructor() {} }", None),
309323
];
310324

311-
Tester::new(NoExtraneousClass::NAME, NoExtraneousClass::PLUGIN, pass, fail).test_and_snapshot();
325+
let fix = vec![
326+
("class Foo {}", "", None, FixKind::DangerousSuggestion),
327+
("export class Foo {}", "", None, FixKind::DangerousSuggestion),
328+
(
329+
"@foo class Foo {}",
330+
"@foo class Foo {}",
331+
Some(json!([{ "allowWithDecorator": false }])),
332+
FixKind::DangerousSuggestion,
333+
),
334+
];
335+
336+
Tester::new(NoExtraneousClass::NAME, NoExtraneousClass::PLUGIN, pass, fail)
337+
.expect_fix(fix)
338+
.test_and_snapshot();
312339
}

crates/oxc_linter/src/snapshots/typescript_no_extraneous_class.snap

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ source: crates/oxc_linter/src/tester.rs
66
1 │ class Foo {}
77
· ────────────
88
╰────
9+
help: Delete this class
910

1011
typescript-eslint(no-extraneous-class): Unexpected class with only static properties.
1112
╭─[no_extraneous_class.tsx:5:14]
@@ -39,6 +40,7 @@ source: crates/oxc_linter/src/tester.rs
3940
· ────────────────────
4041
9 │ }
4142
╰────
43+
help: Delete this class
4244

4345
typescript-eslint(no-extraneous-class): Unexpected class with only static properties.
4446
╭─[no_extraneous_class.tsx:1:16]
@@ -79,6 +81,7 @@ source: crates/oxc_linter/src/tester.rs
7981
1 │ abstract class Foo {}
8082
· ─────────────────────
8183
╰────
84+
help: Delete this class
8285

8386
typescript-eslint(no-extraneous-class): Unexpected class with only static properties.
8487
╭─[no_extraneous_class.tsx:1:16]

0 commit comments

Comments
 (0)