feat(rome_js_analyze): noEmptyPattern
MODIFY
crates/rome_js_analyze/src/analyzers.rs
crates/rome_js_analyze/src/analyzers.rs
@@ -8,6 +8,8 @@ mod no_delete;
pub(crate) use no_delete::NoDelete;
mod no_double_equals;
pub(crate) use no_double_equals::NoDoubleEquals;
+mod no_empty_pattern;
+pub(crate) use no_empty_pattern::NoEmptyPattern;
mod no_implicit_boolean;
pub(crate) use no_implicit_boolean::NoImplicitBoolean;
mod no_multiple_spaces_in_regular_expression_literals;

ADD
crates/rome_js_analyze/src/analyzers/no_empty_pattern.rs
+use rome_analyze::{context::RuleContext, declare_rule, Rule, RuleCategory, RuleDiagnostic};
+use rome_console::markup;
+use rome_js_syntax::{JsArrayBindingPattern, JsObjectBindingPattern};
+use rome_rowan::{declare_node_union, AstNode, AstSeparatedList};
+
+declare_rule! {
+ /// Disallows empty destructuring patterns.
+ /// ## Examples
+ ///
+ /// ### Valid
+ /// The following cases are valid because they create new bindings.
+ ///
+ /// ```js
+ /// var {a = {}} = foo;
+ /// var {a, b = {}} = foo;
+ /// var {a = []} = foo;
+ /// function foo({a = {}}) {}
+ /// function foo({a = []}) {}
+ /// var [a] = foo;
+ /// ```
+ ///
+ /// ### Invalid
+ ///
+ /// ```js,expect_diagnostic
+ /// var {} = foo;
+ /// ```
+ ///
+ /// ```js,expect_diagnostic
+ /// var {a: {}} = foo;
+ /// ```
+ ///
+ /// ```js,expect_diagnostic
+ /// function foo({}) {}
+ /// ```
+ ///
+ pub(crate) NoEmptyPattern = "noEmptyPattern"
+}
+
+impl Rule for NoEmptyPattern {
+ const CATEGORY: RuleCategory = RuleCategory::Lint;
+
+ type Query = JsAnyBindPatternLike;
+ type State = ();
+
+ fn run(ctx: &RuleContext<Self>) -> Option<Self::State> {
+ match ctx.query() {
+ JsAnyBindPatternLike::JsArrayBindingPattern(array) => {
+ if array.elements().len() == 0 {
+ Some(())
+ } else {
+ None
+ }
+ }
+ JsAnyBindPatternLike::JsObjectBindingPattern(object) => {
+ if object.properties().len() == 0 {
+ Some(())
+ } else {
+ None
+ }
+ }
+ }
+ }
+
+ fn diagnostic(ctx: &RuleContext<Self>, _: &Self::State) -> Option<RuleDiagnostic> {
+ let node = ctx.query();
+ let node_type = match node {
+ JsAnyBindPatternLike::JsArrayBindingPattern(_) => "array",
+ JsAnyBindPatternLike::JsObjectBindingPattern(_) => "object",
+ };
+
+ Some(RuleDiagnostic::warning(
+ node.range(),
+ markup! {
+ "Unexpected empty "{node_type}" pattern."
+ },
+ ))
+ }
+}
+
+declare_node_union! {
+ /// enum of `JsObjectBindingPattern` and `JsArrayBindingPattern`
+ pub(crate) JsAnyBindPatternLike = JsArrayBindingPattern | JsObjectBindingPattern
+}

MODIFY
crates/rome_js_analyze/src/registry.rs
crates/rome_js_analyze/src/registry.rs
@@ -17,6 +17,9 @@ pub(crate) fn build_registry(filter: &AnalysisFilter) -> RuleRegistry<JsLanguage
if filter.match_rule::<NoDoubleEquals>() {
rules.push::<NoDoubleEquals>();
}
+ if filter.match_rule::<NoEmptyPattern>() {
+ rules.push::<NoEmptyPattern>();
+ }
if filter.match_rule::<NoImplicitBoolean>() {
rules.push::<NoImplicitBoolean>();
}

ADD
crates/rome_js_analyze/tests/specs/noEmptyPattern.js
+// valid
+var {a = {}} = foo;
+var {a, b = {}} = foo;
+var {a = []} = foo;
+function foo({a = {}}) {}
+function foo({a = []}) {}
+var [a] = foo;
+// invalid
+var {} = foo;
+var [] = foo;
+var {a: {}} = foo;
+var {a, b: {}} = foo;
+var {a: []} = foo;
+function foo({}) {};
+function foo([]) {};
+function foo({a: {}}) {};
+function foo({a: []}) {};
\ No newline at end of file

MODIFY
website/src/docs/lint/rules/index.md
website/src/docs/lint/rules/index.md
@@ -42,6 +42,13 @@ Disallow the use of the <code>delete</code> operator
Require the use of <code>===</code> and <code>!==</code>
</div>
<div class="rule">
+<h3 data-toc-exclude id="noEmptyPattern">
+ <a href="/docs/lint/rules/noEmptyPattern">noEmptyPattern</a>
+ <a class="header-anchor" href="#noEmptyPattern"></a>
+</h3>
+Disallows empty destructuring patterns.
+</div>
+<div class="rule">
<h3 data-toc-exclude id="noImplicitBoolean">
<a href="/docs/lint/rules/noImplicitBoolean">noImplicitBoolean</a>
<a class="header-anchor" href="#noImplicitBoolean"></a>

feat(rome_js_analyze): noEmptyPattern (#2731)