Skip to content

Commit

Permalink
feat(es/lints): Implement valid-typeof rule (#4095)
Browse files Browse the repository at this point in the history
  • Loading branch information
ArturAralin committed Mar 20, 2022
1 parent b31ead5 commit 9ceefa7
Show file tree
Hide file tree
Showing 9 changed files with 236 additions and 1 deletion.
9 changes: 9 additions & 0 deletions crates/swc/tests/errors/lints/valid-typeof/default/.swcrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"jsc": {
"lints": {
"valid-typeof": [
"error"
]
}
}
}
9 changes: 9 additions & 0 deletions crates/swc/tests/errors/lints/valid-typeof/default/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
typeof foo === "strnig";
typeof foo == "undefimed";
typeof bar != "nunber";
typeof bar !== "fucntion";
typeof bar !== foo();
typeof foo > "strnig";
typeof bar !== "function";
typeof x === typeof y;
a === b;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

x Invalid typeof comparison value
,----
1 | typeof foo === "strnig";
: ^^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
2 | typeof foo == "undefimed";
: ^^^^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
3 | typeof bar != "nunber";
: ^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
4 | typeof bar !== "fucntion";
: ^^^^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
5 | typeof bar !== foo();
: ^^^^^^^^^^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"jsc": {
"lints": {
"valid-typeof": [
"error",
{
"requireStringLiterals": false
}
]
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
typeof foo === "strnig"
typeof foo == "undefimed"
typeof bar != "nunber"
typeof bar !== "fucntion"

typeof bar !== foo()

typeof bar !== ident

// Just for test =)
typeof foo > "strnig"
typeof bar !== "function"
typeof x === typeof y
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

x Invalid typeof comparison value
,----
1 | typeof foo === "strnig"
: ^^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
2 | typeof foo == "undefimed"
: ^^^^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
3 | typeof bar != "nunber"
: ^^^^^^^^^^^^^^^^^^^^^^
`----

x Invalid typeof comparison value
,----
4 | typeof bar !== "fucntion"
: ^^^^^^^^^^^^^^^^^^^^^^^^^
`----
6 changes: 5 additions & 1 deletion crates/swc_ecma_lints/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::rules::non_critical_lints::{
no_console::NoConsoleConfig, no_empty_function::NoEmptyFunctionConfig,
no_restricted_syntax::NoRestrictedSyntaxConfig, no_use_before_define::NoUseBeforeDefineConfig,
prefer_regex_literals::PreferRegexLiteralsConfig, quotes::QuotesConfig, radix::RadixConfig,
yoda::YodaConfig,
valid_typeof::ValidTypeofConfig, yoda::YodaConfig,
};

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
Expand Down Expand Up @@ -142,4 +142,8 @@ pub struct LintConfig {
#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "noNewSymbol")]
pub no_new_symbol: RuleConfig<()>,

#[cfg(feature = "non_critical_lints")]
#[serde(default, alias = "validTypeof")]
pub valid_typeof: RuleConfig<ValidTypeofConfig>,
}
3 changes: 3 additions & 0 deletions crates/swc_ecma_lints/src/rules/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub(crate) mod non_critical_lints {
pub mod prefer_regex_literals;
pub mod quotes;
pub mod radix;
pub mod valid_typeof;
pub mod yoda;
}

Expand Down Expand Up @@ -137,6 +138,8 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
top_level_ctxt,
&lint_config.no_new_symbol,
));

rules.extend(valid_typeof::valid_typeof(&lint_config.valid_typeof));
}

rules
Expand Down
131 changes: 131 additions & 0 deletions crates/swc_ecma_lints/src/rules/valid_typeof.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
use serde::{Deserialize, Serialize};
use swc_common::{errors::HANDLER, Span};
use swc_ecma_ast::*;
use swc_ecma_visit::{Visit, VisitWith};

use crate::{
config::{LintRuleReaction, RuleConfig},
rule::{visitor_rule, Rule},
};

const MESSAGE: &str = "Invalid typeof comparison value";

const VALID_TYPES: &[&str] = &[
"undefined",
"object",
"boolean",
"number",
"string",
"function",
"symbol",
"bigint",
];

#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ValidTypeofConfig {
require_string_literals: Option<bool>,
}

pub fn valid_typeof(config: &RuleConfig<ValidTypeofConfig>) -> Option<Box<dyn Rule>> {
match config.get_rule_reaction() {
LintRuleReaction::Off => None,
_ => Some(visitor_rule(ValidTypeof::new(config))),
}
}

#[derive(Debug, Default)]
struct ValidTypeof {
expected_reaction: LintRuleReaction,
require_string_literals: bool,
}

impl ValidTypeof {
fn new(config: &RuleConfig<ValidTypeofConfig>) -> Self {
let rule_config = config.get_rule_config();

Self {
expected_reaction: config.get_rule_reaction(),
require_string_literals: rule_config.require_string_literals.unwrap_or(true),
}
}

fn emit_report(&self, span: Span) {
HANDLER.with(|handler| match self.expected_reaction {
LintRuleReaction::Error => {
handler.struct_span_err(span, MESSAGE).emit();
}
LintRuleReaction::Warning => {
handler.struct_span_warn(span, MESSAGE).emit();
}
_ => {}
});
}

fn check(&self, span: Span, str_operand: &str) {
if !VALID_TYPES.contains(&str_operand) {
self.emit_report(span);
}
}
}

impl Visit for ValidTypeof {
fn visit_bin_expr(&mut self, bin_expr: &BinExpr) {
if let op!("==") | op!("===") | op!("!=") | op!("!==") = bin_expr.op {
match (bin_expr.left.as_ref(), bin_expr.right.as_ref()) {
// case typeof x === "type"
(
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
Expr::Lit(Lit::Str(Str { value, .. })),
) => {
self.check(bin_expr.span, &*value);
}
// case "type" === typeof x
(
Expr::Lit(Lit::Str(Str { value, .. })),
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
) => {
self.check(bin_expr.span, &*value);
}
// case typeof x === typeof y
(
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
) => {}
// case typeof x === foo()
(
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
_,
) => {
if self.require_string_literals {
self.emit_report(bin_expr.span);
}
}
// case foo() === typeof x
(
_,
Expr::Unary(UnaryExpr {
op: op!("typeof"), ..
}),
) => {
if self.require_string_literals {
self.emit_report(bin_expr.span);
}
}
_ => {}
}
}

bin_expr.visit_children_with(self);
}
}

1 comment on commit 9ceefa7

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmark

Benchmark suite Current: 9ceefa7 Previous: 57802cf Ratio
base_tr_fixer 23074 ns/iter (± 406) 30073 ns/iter (± 2558) 0.77
base_tr_resolver_and_hygiene 92992 ns/iter (± 7549) 122298 ns/iter (± 34200) 0.76
codegen_es2015 31344 ns/iter (± 316) 36473 ns/iter (± 8515) 0.86
codegen_es2016 31272 ns/iter (± 150) 35910 ns/iter (± 6413) 0.87
codegen_es2017 31223 ns/iter (± 208) 38216 ns/iter (± 5787) 0.82
codegen_es2018 31398 ns/iter (± 168) 36777 ns/iter (± 5952) 0.85
codegen_es2019 31320 ns/iter (± 170) 35774 ns/iter (± 5112) 0.88
codegen_es2020 31390 ns/iter (± 159) 35345 ns/iter (± 5574) 0.89
codegen_es3 31431 ns/iter (± 131) 35835 ns/iter (± 5184) 0.88
codegen_es5 31437 ns/iter (± 159) 36089 ns/iter (± 3874) 0.87
full_es2015 138391125 ns/iter (± 13273576) 156253598 ns/iter (± 10659414) 0.89
full_es2016 137908949 ns/iter (± 3477138) 155090921 ns/iter (± 10699741) 0.89
full_es2017 137136771 ns/iter (± 3575407) 153614856 ns/iter (± 9986336) 0.89
full_es2018 137042229 ns/iter (± 2533075) 154695495 ns/iter (± 11980513) 0.89
full_es2019 136810023 ns/iter (± 8047948) 156494154 ns/iter (± 11795701) 0.87
full_es2020 118835584 ns/iter (± 2409664) 142855115 ns/iter (± 12005590) 0.83
full_es3 182931818 ns/iter (± 4111203) 200717826 ns/iter (± 13739640) 0.91
full_es5 173155347 ns/iter (± 3415339) 190185859 ns/iter (± 12404967) 0.91
parser 563562 ns/iter (± 12087) 685395 ns/iter (± 141397) 0.82
ser_ast_node 145 ns/iter (± 2) 164 ns/iter (± 43) 0.88
ser_serde 144 ns/iter (± 1) 149 ns/iter (± 23) 0.97
emit_colors 12145215 ns/iter (± 7411750) 9576515 ns/iter (± 6332516) 1.27
emit_large 71025515 ns/iter (± 93443200) 48512012 ns/iter (± 70646269) 1.46
base_clone 2600099 ns/iter (± 361766) 2473483 ns/iter (± 458642) 1.05
fold_span 3771277 ns/iter (± 38257) 4314678 ns/iter (± 1104126) 0.87
fold_span_panic 3970135 ns/iter (± 82855) 4383202 ns/iter (± 697569) 0.91
visit_mut_span 2720041 ns/iter (± 10886) 2904239 ns/iter (± 444601) 0.94
visit_mut_span_panic 2762541 ns/iter (± 10820) 2929332 ns/iter (± 429583) 0.94
usage_builtin_type 15857229 ns/iter (± 9874220) 17082852 ns/iter (± 11133799) 0.93
usage_property 397525 ns/iter (± 7123) 417274 ns/iter (± 65727) 0.95
boxing_boxed 134 ns/iter (± 10) 167 ns/iter (± 57) 0.80
boxing_boxed_clone 72 ns/iter (± 0) 69 ns/iter (± 13) 1.04
boxing_unboxed 128 ns/iter (± 1) 136 ns/iter (± 24) 0.94
boxing_unboxed_clone 63 ns/iter (± 0) 67 ns/iter (± 11) 0.94
time_10 344 ns/iter (± 29) 334 ns/iter (± 45) 1.03
time_15 706 ns/iter (± 18) 701 ns/iter (± 111) 1.01
time_20 1288 ns/iter (± 11) 1226 ns/iter (± 220) 1.05
time_40 7122 ns/iter (± 41) 4447 ns/iter (± 701) 1.60
time_5 101 ns/iter (± 1) 110 ns/iter (± 25) 0.92
time_60 16157 ns/iter (± 43) 10141 ns/iter (± 2543) 1.59
total 0 ns/iter (± 0) 0 ns/iter (± 0) NaN

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.