1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use super::Context;
use super::LintRule;
use crate::swc_ecma_ast;
use crate::swc_ecma_ast::{ArrayPat, ObjectPat, ObjectPatProp};
use swc_ecma_visit::Node;
use swc_ecma_visit::Visit;
pub struct NoEmptyPattern;
impl LintRule for NoEmptyPattern {
fn new() -> Box<Self> {
Box::new(NoEmptyPattern)
}
fn code(&self) -> &'static str {
"no-empty-pattern"
}
fn lint_module(&self, context: Context, module: swc_ecma_ast::Module) {
let mut visitor = NoEmptyPatternVisitor::new(context);
visitor.visit_module(&module, &module);
}
}
struct NoEmptyPatternVisitor {
context: Context,
}
impl NoEmptyPatternVisitor {
pub fn new(context: Context) -> Self {
Self { context }
}
}
impl Visit for NoEmptyPatternVisitor {
fn visit_object_pat_prop(
&mut self,
obj_pat_prop: &ObjectPatProp,
_parent: &dyn Node,
) {
if let ObjectPatProp::KeyValue(kv_prop) = obj_pat_prop {
if let swc_ecma_ast::Pat::Object(obj_pat) = &*kv_prop.value {
self.visit_object_pat(obj_pat, _parent);
} else if let swc_ecma_ast::Pat::Array(arr_pat) = &*kv_prop.value {
self.visit_array_pat(arr_pat, _parent);
}
}
}
fn visit_object_pat(&mut self, obj_pat: &ObjectPat, _parent: &dyn Node) {
if obj_pat.props.is_empty() {
if obj_pat.type_ann.is_none() {
self.context.add_diagnostic(
obj_pat.span,
"no-empty-pattern",
"empty patterns are not allowed",
)
}
} else {
for prop in &obj_pat.props {
self.visit_object_pat_prop(prop, _parent)
}
}
}
fn visit_array_pat(&mut self, arr_pat: &ArrayPat, _parent: &dyn Node) {
if arr_pat.elems.is_empty() {
self.context.add_diagnostic(
arr_pat.span,
"no-empty-pattern",
"empty patterns are not allowed",
)
} else {
for elem in &arr_pat.elems {
if let Some(element) = elem {
if let swc_ecma_ast::Pat::Object(obj_pat) = element {
self.visit_object_pat(&obj_pat, _parent);
} else if let swc_ecma_ast::Pat::Array(arr_pat) = element {
self.visit_array_pat(&arr_pat, _parent);
}
}
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::*;
#[test]
fn no_empty_pattern_valid() {
assert_lint_ok_n::<NoEmptyPattern>(vec![
"const {a = {}} = foo;",
"const {a, b = {}} = foo;",
"const {a = []} = foo;",
"function foo({a = {}}) {}",
"function foo({a = []}) {}",
"var [a] = foo",
"async function startFileServerAsLibrary({}: FileServerCfg = {}): Promise<void>",
]);
}
#[test]
fn no_empty_pattern_invalid() {
assert_lint_err::<NoEmptyPattern>("const {} = foo", 6);
assert_lint_err::<NoEmptyPattern>("const [] = foo", 6);
assert_lint_err::<NoEmptyPattern>("const {a: {}} = foo", 10);
assert_lint_err::<NoEmptyPattern>("const {a, b: {}} = foo", 13);
assert_lint_err::<NoEmptyPattern>("const {a: []} = foo", 10);
assert_lint_err::<NoEmptyPattern>("function foo({}) {}", 13);
assert_lint_err::<NoEmptyPattern>("function foo([]) {}", 13);
assert_lint_err::<NoEmptyPattern>("function foo({a: {}}) {}", 17);
assert_lint_err::<NoEmptyPattern>("function foo({a: []}) {}", 17);
}
}