mirror of
https://github.com/danbulant/oxc
synced 2026-05-23 06:08:47 +00:00
feat(linter): no-empty-pattern (#74)
* feat(linter): no-empty-pattern * chore(linter/no-empty-pattern): update docs and examples * chore: fix typo
This commit is contained in:
parent
92b232372f
commit
85de06eae7
3 changed files with 196 additions and 0 deletions
|
|
@ -1,10 +1,12 @@
|
|||
mod no_array_constructor;
|
||||
mod no_debugger;
|
||||
mod no_empty;
|
||||
mod no_empty_pattern;
|
||||
|
||||
pub use no_array_constructor::NoArrayConstructor;
|
||||
pub use no_debugger::NoDebugger;
|
||||
pub use no_empty::NoEmpty;
|
||||
pub use no_empty_pattern::NoEmptyPattern;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, rule::RuleMeta, AstNode};
|
||||
|
||||
|
|
@ -13,6 +15,7 @@ lazy_static::lazy_static! {
|
|||
RuleEnum::NoDebugger(NoDebugger::default()),
|
||||
RuleEnum::NoEmpty(NoEmpty::default()),
|
||||
RuleEnum::NoArrayConstructor(NoArrayConstructor::default()),
|
||||
RuleEnum::NoEmptyPattern(NoEmptyPattern::default()),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -22,6 +25,7 @@ pub enum RuleEnum {
|
|||
NoDebugger(NoDebugger),
|
||||
NoEmpty(NoEmpty),
|
||||
NoArrayConstructor(NoArrayConstructor),
|
||||
NoEmptyPattern(NoEmptyPattern),
|
||||
}
|
||||
|
||||
impl RuleEnum {
|
||||
|
|
@ -30,6 +34,7 @@ impl RuleEnum {
|
|||
Self::NoDebugger(_) => NoDebugger::NAME,
|
||||
Self::NoEmpty(_) => NoEmpty::NAME,
|
||||
Self::NoArrayConstructor(_) => NoArrayConstructor::NAME,
|
||||
Self::NoEmptyPattern(_) => NoEmptyPattern::NAME,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -44,6 +49,9 @@ impl RuleEnum {
|
|||
Self::NoArrayConstructor(_) => Self::NoArrayConstructor(
|
||||
maybe_value.map(NoArrayConstructor::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
Self::NoEmptyPattern(_) => Self::NoEmptyPattern(
|
||||
maybe_value.map(NoEmptyPattern::from_configuration).unwrap_or_default(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,6 +60,7 @@ impl RuleEnum {
|
|||
Self::NoDebugger(rule) => rule.run(node, ctx),
|
||||
Self::NoEmpty(rule) => rule.run(node, ctx),
|
||||
Self::NoArrayConstructor(rule) => rule.run(node, ctx),
|
||||
Self::NoEmptyPattern(rule) => rule.run(node, ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
119
crates/oxc_linter/src/rules/no_empty_pattern.rs
Normal file
119
crates/oxc_linter/src/rules/no_empty_pattern.rs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
use oxc_ast::{AstKind, Span};
|
||||
use oxc_diagnostics::{
|
||||
miette::{self, Diagnostic},
|
||||
thiserror::Error,
|
||||
};
|
||||
use oxc_macros::declare_oxc_lint;
|
||||
|
||||
use crate::{context::LintContext, rule::Rule, AstNode};
|
||||
|
||||
#[derive(Debug, Error, Diagnostic)]
|
||||
#[error("eslint(no-empty-pattern): Disallow empty destructuring patterns")]
|
||||
#[diagnostic()]
|
||||
struct NoEmptyPatternDiagnostic(&'static str, #[label("Empty {0} binding pattern")] pub Span);
|
||||
|
||||
#[derive(Debug, Default, Clone)]
|
||||
pub struct NoEmptyPattern;
|
||||
|
||||
declare_oxc_lint!(
|
||||
/// ### What it does
|
||||
/// Disallow empty destructuring patterns
|
||||
///
|
||||
/// ### Why is this bad?
|
||||
/// When using destructuring, it’s possible to create a pattern that has no effect.
|
||||
/// This happens when empty curly braces are used to the right of
|
||||
/// an embedded object destructuring pattern, such as:
|
||||
///
|
||||
/// ```JavaScript
|
||||
/// // doesn't create any variables
|
||||
/// var {a: {}} = foo;
|
||||
/// ```
|
||||
/// In this code, no new variables are created because a is just a location helper
|
||||
/// while the `{}` is expected to contain the variables to create, such as:
|
||||
///
|
||||
/// ```JavaScript
|
||||
/// // creates variable b
|
||||
/// var {a: { b }} = foo;
|
||||
/// ```
|
||||
///
|
||||
/// In many cases, the empty object pattern is a mistake
|
||||
/// where the author intended to use a default value instead, such as:
|
||||
///
|
||||
/// ```JavaScript
|
||||
/// // creates variable a
|
||||
/// var {a = {}} = foo;
|
||||
/// ```
|
||||
///
|
||||
/// The difference between these two patterns is subtle,
|
||||
/// especially because the problematic empty pattern looks just like an object literal.
|
||||
///
|
||||
/// ### Examples of incorrect code for this rule:
|
||||
///
|
||||
/// ```JavaScript
|
||||
/// var {} = foo;
|
||||
/// var [] = foo;
|
||||
/// var {a: {}} = foo;
|
||||
/// var {a: []} = foo;
|
||||
/// function foo({}) {}
|
||||
/// function foo([]) {}
|
||||
/// function foo({a: {}}) {}
|
||||
/// function foo({a: []}) {}
|
||||
/// ```
|
||||
///
|
||||
/// ### Examples of correct code for this rule:
|
||||
///
|
||||
/// ```JavaScript
|
||||
/// var {a = {}} = foo;
|
||||
/// var {a = []} = foo;
|
||||
/// function foo({a = {}}) {}
|
||||
/// function foo({a = []}) {}
|
||||
/// ```
|
||||
///
|
||||
NoEmptyPattern
|
||||
);
|
||||
|
||||
const RULE_NAME: &str = "no-empty-pattern";
|
||||
|
||||
impl Rule for NoEmptyPattern {
|
||||
const NAME: &'static str = RULE_NAME;
|
||||
|
||||
fn run<'a>(&self, node: &AstNode<'a>, ctx: &LintContext<'a>) {
|
||||
let (pattern_type, span) = match node.get().kind() {
|
||||
AstKind::ArrayPattern(array) if array.elements.is_empty() => ("array", array.span),
|
||||
AstKind::ObjectPattern(object) if object.properties.is_empty() => {
|
||||
("object", object.span)
|
||||
}
|
||||
_ => return,
|
||||
};
|
||||
|
||||
ctx.diagnostic(NoEmptyPatternDiagnostic(pattern_type, span));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
use crate::tester::Tester;
|
||||
|
||||
let pass = vec![
|
||||
("var {a = {}} = foo;", None),
|
||||
("var {a, b = {}} = foo;", None),
|
||||
("var {a = []} = foo;", None),
|
||||
("function foo({a = {}}) {}", None),
|
||||
("function foo({a = []}) {}", None),
|
||||
("var [a] = foo", None),
|
||||
];
|
||||
|
||||
let fail = vec![
|
||||
("var {} = foo", None),
|
||||
("var [] = foo", None),
|
||||
("var {a: {}} = foo", None),
|
||||
("var {a, b: {}} = foo", None),
|
||||
("var {a: []} = foo", None),
|
||||
("function foo({}) {}", None),
|
||||
("function foo([]) {}", None),
|
||||
("function foo({a: {}}) {}", None),
|
||||
("function foo({a: []}) {}", None),
|
||||
];
|
||||
|
||||
Tester::new(RULE_NAME, pass, fail).test_and_snapshot();
|
||||
}
|
||||
68
crates/oxc_linter/src/snapshots/no_empty_pattern.snap
Normal file
68
crates/oxc_linter/src/snapshots/no_empty_pattern.snap
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
source: crates/oxc_linter/src/tester.rs
|
||||
expression: no_empty_pattern
|
||||
---
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ var {} = foo
|
||||
· ─┬
|
||||
· ╰── Empty object binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ var [] = foo
|
||||
· ─┬
|
||||
· ╰── Empty array binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ var {a: {}} = foo
|
||||
· ─┬
|
||||
· ╰── Empty object binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ var {a, b: {}} = foo
|
||||
· ─┬
|
||||
· ╰── Empty object binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ var {a: []} = foo
|
||||
· ─┬
|
||||
· ╰── Empty array binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ function foo({}) {}
|
||||
· ─┬
|
||||
· ╰── Empty object binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ function foo([]) {}
|
||||
· ─┬
|
||||
· ╰── Empty array binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ function foo({a: {}}) {}
|
||||
· ─┬
|
||||
· ╰── Empty object binding pattern
|
||||
╰────
|
||||
|
||||
× eslint(no-empty-pattern): Disallow empty destructuring patterns
|
||||
╭─[no_empty_pattern.tsx:1:1]
|
||||
1 │ function foo({a: []}) {}
|
||||
· ─┬
|
||||
· ╰── Empty array binding pattern
|
||||
╰────
|
||||
|
||||
Loading…
Reference in a new issue