mirror of
https://github.com/danbulant/oxc
synced 2026-05-24 12:21:58 +00:00
feat(linter) eslint plugin unicorn: prefer optional catch binding (#1188)
This commit is contained in:
parent
49b6be607e
commit
e5d281e8e7
3 changed files with 181 additions and 0 deletions
|
|
@ -163,6 +163,7 @@ mod unicorn {
|
|||
pub mod prefer_code_point;
|
||||
pub mod prefer_date_now;
|
||||
pub mod prefer_logical_operator_over_ternary;
|
||||
pub mod prefer_optional_catch_binding;
|
||||
pub mod prefer_query_selector;
|
||||
pub mod prefer_regexp_test;
|
||||
pub mod prefer_string_trim_start_end;
|
||||
|
|
@ -301,6 +302,7 @@ oxc_macros::declare_all_lint_rules! {
|
|||
unicorn::prefer_code_point,
|
||||
unicorn::prefer_date_now,
|
||||
unicorn::prefer_logical_operator_over_ternary,
|
||||
unicorn::prefer_optional_catch_binding,
|
||||
unicorn::prefer_query_selector,
|
||||
unicorn::prefer_regexp_test,
|
||||
unicorn::prefer_string_trim_start_end,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
use oxc_ast::{
|
||||
ast::{BindingPattern, BindingPatternKind},
|
||||
AstKind,
|
||||
};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
use oxc_span::{GetSpan, Span};
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused")]
|
||||
#[diagnostic(severity(warning))]
|
||||
struct PreferOptionalCatchBindingDiagnostic(#[label] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct PreferOptionalCatchBinding;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
///
|
||||
/// Prefers omitting the catch binding parameter if it is unused
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
///
|
||||
/// It is unnecessary to bind the error to a variable if it is not used.
|
||||
///
|
||||
/// ### Example
|
||||
/// ```javascript
|
||||
/// // Bad
|
||||
/// try {
|
||||
/// // ...
|
||||
/// } catch (e) { }
|
||||
///
|
||||
/// // Good
|
||||
/// try {
|
||||
/// // ...
|
||||
/// } catch { }
|
||||
/// ```
|
||||
PreferOptionalCatchBinding,
|
||||
style
|
||||
);
|
||||
|
||||
impl Rule for PreferOptionalCatchBinding {
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let AstKind::CatchClause(catch_clause) = node.kind() else { return };
|
||||
|
||||
let Some(catch_param) = &catch_clause.param else { return };
|
||||
|
||||
let references_count = get_param_references_count(catch_param, ctx);
|
||||
|
||||
if references_count != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.diagnostic(PreferOptionalCatchBindingDiagnostic(catch_param.span()));
|
||||
}
|
||||
}
|
||||
|
||||
fn get_param_references_count(binding_pat: &BindingPattern, ctx: &LintContext) -> usize {
|
||||
match &binding_pat.kind {
|
||||
BindingPatternKind::BindingIdentifier(binding_ident) => {
|
||||
ctx.semantic().symbol_references(binding_ident.symbol_id.get().unwrap()).count()
|
||||
}
|
||||
BindingPatternKind::ObjectPattern(object_pat) => {
|
||||
let mut count = 0;
|
||||
|
||||
for prop in &object_pat.properties {
|
||||
count += get_param_references_count(&prop.value, ctx);
|
||||
}
|
||||
|
||||
if let Some(rest) = &object_pat.rest {
|
||||
count += get_param_references_count(&rest.argument, ctx);
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
BindingPatternKind::AssignmentPattern(_) => 1,
|
||||
BindingPatternKind::ArrayPattern(array_pat) => {
|
||||
let mut count = 0;
|
||||
|
||||
for element in (&array_pat.elements).into_iter().flatten() {
|
||||
count += get_param_references_count(element, ctx);
|
||||
}
|
||||
|
||||
count
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
r#"try {} catch {}"#,
|
||||
r#"try {} catch ({message}) {alert(message)}"#,
|
||||
r#"try {} catch ({cause: {message}}) {alert(message)}"#,
|
||||
r#"try {} catch({nonExistsProperty = thisWillExecute()}) {}"#,
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
r#"try {} catch (_) {}"#,
|
||||
r#"try {} catch (theRealErrorName) {}"#,
|
||||
r#"try { } catch (e)
|
||||
{ }"#,
|
||||
r#"try {} catch(e) {}"#,
|
||||
r#"try {} catch (e){}"#,
|
||||
r#"try {} catch ({}) {}"#,
|
||||
r#"try {} catch ({message}) {}"#,
|
||||
r#"try {} catch ({message: notUsedMessage}) {}"#,
|
||||
r#"try {} catch ({cause: {message}}) {}"#,
|
||||
];
|
||||
|
||||
Tester::new_without_config(PreferOptionalCatchBinding::NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: prefer_optional_catch_binding
|
||||
---
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch (_) {}
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch (theRealErrorName) {}
|
||||
· ────────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try { } catch (e)
|
||||
· ─
|
||||
2 │ { }
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch(e) {}
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch (e){}
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch ({}) {}
|
||||
· ──
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch ({message}) {}
|
||||
· ─────────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch ({message: notUsedMessage}) {}
|
||||
· ─────────────────────────
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-unicorn(prefer-optional-catch-binding): Prefer omitting the catch binding parameter if it is unused
|
||||
╭─[prefer_optional_catch_binding.tsx:1:1]
|
||||
1 │ try {} catch ({cause: {message}}) {}
|
||||
· ──────────────────
|
||||
╰────
|
||||
|
||||
|
||||
Loading…
Reference in a new issue