mirror of
https://github.com/swc-project/swc.git
synced 2024-11-27 13:38:33 +03:00
feat(es/lints): Implement valid-typeof
rule (#4095)
This commit is contained in:
parent
b31ead5cbe
commit
9ceefa734f
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"lints": {
|
||||||
|
"valid-typeof": [
|
||||||
|
"error"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
@ -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();
|
||||||
|
: ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
`----
|
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"lints": {
|
||||||
|
"valid-typeof": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"requireStringLiterals": false
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
@ -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"
|
||||||
|
: ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
`----
|
@ -8,7 +8,7 @@ use crate::rules::non_critical_lints::{
|
|||||||
no_console::NoConsoleConfig, no_empty_function::NoEmptyFunctionConfig,
|
no_console::NoConsoleConfig, no_empty_function::NoEmptyFunctionConfig,
|
||||||
no_restricted_syntax::NoRestrictedSyntaxConfig, no_use_before_define::NoUseBeforeDefineConfig,
|
no_restricted_syntax::NoRestrictedSyntaxConfig, no_use_before_define::NoUseBeforeDefineConfig,
|
||||||
prefer_regex_literals::PreferRegexLiteralsConfig, quotes::QuotesConfig, radix::RadixConfig,
|
prefer_regex_literals::PreferRegexLiteralsConfig, quotes::QuotesConfig, radix::RadixConfig,
|
||||||
yoda::YodaConfig,
|
valid_typeof::ValidTypeofConfig, yoda::YodaConfig,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
|
||||||
@ -142,4 +142,8 @@ pub struct LintConfig {
|
|||||||
#[cfg(feature = "non_critical_lints")]
|
#[cfg(feature = "non_critical_lints")]
|
||||||
#[serde(default, alias = "noNewSymbol")]
|
#[serde(default, alias = "noNewSymbol")]
|
||||||
pub no_new_symbol: RuleConfig<()>,
|
pub no_new_symbol: RuleConfig<()>,
|
||||||
|
|
||||||
|
#[cfg(feature = "non_critical_lints")]
|
||||||
|
#[serde(default, alias = "validTypeof")]
|
||||||
|
pub valid_typeof: RuleConfig<ValidTypeofConfig>,
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,7 @@ pub(crate) mod non_critical_lints {
|
|||||||
pub mod prefer_regex_literals;
|
pub mod prefer_regex_literals;
|
||||||
pub mod quotes;
|
pub mod quotes;
|
||||||
pub mod radix;
|
pub mod radix;
|
||||||
|
pub mod valid_typeof;
|
||||||
pub mod yoda;
|
pub mod yoda;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,6 +138,8 @@ pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
|
|||||||
top_level_ctxt,
|
top_level_ctxt,
|
||||||
&lint_config.no_new_symbol,
|
&lint_config.no_new_symbol,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
rules.extend(valid_typeof::valid_typeof(&lint_config.valid_typeof));
|
||||||
}
|
}
|
||||||
|
|
||||||
rules
|
rules
|
||||||
|
131
crates/swc_ecma_lints/src/rules/valid_typeof.rs
Normal file
131
crates/swc_ecma_lints/src/rules/valid_typeof.rs
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user