feat(es/lints): Add this handling support to no-alert rule (#3515)

This commit is contained in:
Artur 2022-02-12 15:45:56 +03:00 committed by GitHub
parent b3a55dbb4e
commit af8200647b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 154 additions and 18 deletions

View File

@ -0,0 +1,7 @@
{
"jsc": {
"lints": {
"noAlert": ["error"]
}
}
}

View File

@ -0,0 +1,50 @@
this.alert();
class X {
constructor(x) {
this.alert(x);
}
alert() {}
m() {
const x = () => {
// shouldn't fail
this.alert();
}
}
m1() {
class Y {}
this.alert();
}
}
var o = {
a() {
this.alert();
},
b: function() {
this.alert()
},
c: () => {
// should fail
this.alert();
},
e: {
a() {
this.alert();
}
},
f() {
this.alert();
}
}
function f1() {
const x = () => {
// should fail
this.alert();
}
}

View File

@ -0,0 +1,18 @@
error: Unexpected alert
|
1 | this.alert();
| ^^^^^^^^^^^^
error: Unexpected alert
|
33 | this.alert();
| ^^^^^^^^^^^^
error: Unexpected alert
|
48 | this.alert();
| ^^^^^^^^^^^^

View File

@ -40,6 +40,9 @@ struct NoAlert {
top_level_declared_vars: AHashSet<Id>,
pass_call_on_global_this: bool,
inside_callee: bool,
classes_depth: usize,
objects_depth: usize,
arrow_fns_depth: usize,
obj: Option<JsWord>,
prop: Option<JsWord>,
}
@ -57,6 +60,9 @@ impl NoAlert {
top_level_declared_vars,
pass_call_on_global_this: es_version < EsVersion::Es2020,
inside_callee: false,
classes_depth: 0,
objects_depth: 0,
arrow_fns_depth: 0,
obj: None,
prop: None,
}
@ -76,6 +82,18 @@ impl NoAlert {
});
}
fn is_inside_class(&self) -> bool {
self.classes_depth > 0
}
fn is_inside_object(&self) -> bool {
self.objects_depth > 0
}
fn is_inside_arrow_fn(&self) -> bool {
self.arrow_fns_depth > 0
}
fn check(&self, call_span: Span, obj: &Option<JsWord>, prop: &JsWord) {
if let Some(obj) = obj {
let obj_name: &str = &*obj;
@ -108,6 +126,20 @@ impl NoAlert {
true
}
fn handle_member_prop(&mut self, prop: &MemberProp) {
match prop {
MemberProp::Ident(Ident { sym, .. }) => {
self.prop = Some(sym.clone());
}
MemberProp::Computed(comp) => {
if let Expr::Lit(Lit::Str(Str { value, .. })) = comp.expr.as_ref() {
self.prop = Some(value.clone());
}
}
_ => {}
}
}
fn handle_callee(&mut self, expr: &Expr) {
match expr {
Expr::Ident(ident) => {
@ -118,27 +150,32 @@ impl NoAlert {
Expr::Member(member_expr) => {
let MemberExpr { obj, prop, .. } = member_expr;
if let Expr::Ident(obj) = obj.as_ref() {
if !self.is_satisfying_indent(obj) {
return;
}
self.obj = Some(obj.sym.clone());
match prop {
MemberProp::Ident(Ident { sym, .. }) => {
self.prop = Some(sym.clone());
match obj.as_ref() {
Expr::Ident(obj) => {
if !self.is_satisfying_indent(obj) {
return;
}
MemberProp::Computed(comp) => {
if let Expr::Lit(Lit::Str(Str { value, .. })) = comp.expr.as_ref() {
self.prop = Some(value.clone());
}
}
_ => {}
self.obj = Some(obj.sym.clone());
self.handle_member_prop(prop);
}
Expr::This(_) => {
let inside_arrow_fn = self.is_inside_arrow_fn();
let inside_class = self.is_inside_class();
if inside_arrow_fn && inside_class {
return;
}
if !inside_arrow_fn && (inside_class || self.is_inside_object()) {
return;
}
self.handle_member_prop(prop);
}
_ => {}
}
// TODO: handle call alert on "this"
}
Expr::OptChain(opt_chain) => {
opt_chain.visit_children_with(self);
@ -182,4 +219,28 @@ impl Visit for NoAlert {
expr.visit_children_with(self);
}
}
fn visit_class(&mut self, class: &Class) {
self.classes_depth += 1;
class.visit_children_with(self);
self.classes_depth -= 1;
}
fn visit_object_lit(&mut self, lit_obj: &ObjectLit) {
self.objects_depth += 1;
lit_obj.visit_children_with(self);
self.objects_depth -= 1;
}
fn visit_arrow_expr(&mut self, arrow_fn: &ArrowExpr) {
self.arrow_fns_depth += 1;
arrow_fn.visit_children_with(self);
self.arrow_fns_depth -= 1;
}
}