mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 21:54:36 +03:00
feat(es/lints): Add no-alert
and a feature gate (#3394)
swc_ecma_lints: - Implement `no-alert` - Add a feature gate for non-critical rules.
This commit is contained in:
parent
b509341fea
commit
5cbe4fe512
@ -40,3 +40,4 @@ swc_node_base = {path = "../swc_node_base"}
|
|||||||
swc_node_bundler = {path = "../swc_node_bundler"}
|
swc_node_bundler = {path = "../swc_node_bundler"}
|
||||||
tracing = {version = "0.1.28", features = ["release_max_level_info"]}
|
tracing = {version = "0.1.28", features = ["release_max_level_info"]}
|
||||||
tracing-subscriber = {version = "0.3.4", features = ["env-filter"]}
|
tracing-subscriber = {version = "0.3.4", features = ["env-filter"]}
|
||||||
|
swc_ecma_lints = {version = "0.11.1", path = "../swc_ecma_lints", features = ["non_critical_lints"]}
|
||||||
|
@ -91,6 +91,7 @@ rayon = "1"
|
|||||||
swc_node_base = {version = "0.5.0", path = "../swc_node_base"}
|
swc_node_base = {version = "0.5.0", path = "../swc_node_base"}
|
||||||
testing = {version = "0.18.0", path = "../testing"}
|
testing = {version = "0.18.0", path = "../testing"}
|
||||||
walkdir = "2"
|
walkdir = "2"
|
||||||
|
swc_ecma_lints = {version = "0.11.1", path = "../swc_ecma_lints", features = ["non_critical_lints"]}
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "usage"
|
name = "usage"
|
||||||
|
@ -29,7 +29,10 @@ use swc_common::{
|
|||||||
};
|
};
|
||||||
use swc_ecma_ast::{EsVersion, Expr, Program};
|
use swc_ecma_ast::{EsVersion, Expr, Program};
|
||||||
use swc_ecma_ext_transforms::jest;
|
use swc_ecma_ext_transforms::jest;
|
||||||
use swc_ecma_lints::{config::LintConfig, rules::lint_to_fold};
|
use swc_ecma_lints::{
|
||||||
|
config::LintConfig,
|
||||||
|
rules::{lint_to_fold, LintParams},
|
||||||
|
};
|
||||||
use swc_ecma_loader::resolvers::{
|
use swc_ecma_loader::resolvers::{
|
||||||
lru::CachingResolver, node::NodeModulesResolver, tsc::TsConfigResolver,
|
lru::CachingResolver, node::NodeModulesResolver, tsc::TsConfigResolver,
|
||||||
};
|
};
|
||||||
@ -296,11 +299,11 @@ impl Options {
|
|||||||
.global_mark
|
.global_mark
|
||||||
.unwrap_or_else(|| Mark::fresh(Mark::root()));
|
.unwrap_or_else(|| Mark::fresh(Mark::root()));
|
||||||
|
|
||||||
let target = target.unwrap_or_default();
|
let es_version = target.unwrap_or_default();
|
||||||
|
|
||||||
let syntax = syntax.unwrap_or_default();
|
let syntax = syntax.unwrap_or_default();
|
||||||
|
|
||||||
let mut program = parse(syntax, target, is_module)?;
|
let mut program = parse(syntax, es_version, is_module)?;
|
||||||
|
|
||||||
// Do a resolver pass before everything.
|
// Do a resolver pass before everything.
|
||||||
//
|
//
|
||||||
@ -394,7 +397,7 @@ impl Options {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let pass = PassBuilder::new(cm, handler, loose, assumptions, top_level_mark, pass)
|
let pass = PassBuilder::new(cm, handler, loose, assumptions, top_level_mark, pass)
|
||||||
.target(target)
|
.target(es_version)
|
||||||
.skip_helper_injection(self.skip_helper_injection)
|
.skip_helper_injection(self.skip_helper_injection)
|
||||||
.minify(js_minify)
|
.minify(js_minify)
|
||||||
.hygiene(if self.disable_hygiene {
|
.hygiene(if self.disable_hygiene {
|
||||||
@ -439,7 +442,12 @@ impl Options {
|
|||||||
),
|
),
|
||||||
syntax.typescript()
|
syntax.typescript()
|
||||||
),
|
),
|
||||||
lint_to_fold(swc_ecma_lints::rules::all(&lints, top_level_ctxt)),
|
lint_to_fold(swc_ecma_lints::rules::all(LintParams {
|
||||||
|
program: &program,
|
||||||
|
lint_config: &lints,
|
||||||
|
top_level_ctxt,
|
||||||
|
es_version,
|
||||||
|
})),
|
||||||
crate::plugin::plugins(experimental),
|
crate::plugin::plugins(experimental),
|
||||||
custom_before_pass(&program),
|
custom_before_pass(&program),
|
||||||
// handle jsx
|
// handle jsx
|
||||||
@ -457,7 +465,7 @@ impl Options {
|
|||||||
pass,
|
pass,
|
||||||
external_helpers,
|
external_helpers,
|
||||||
syntax,
|
syntax,
|
||||||
target,
|
target: es_version,
|
||||||
is_module,
|
is_module,
|
||||||
source_maps: source_maps.unwrap_or(SourceMapsConfig::Bool(false)),
|
source_maps: source_maps.unwrap_or(SourceMapsConfig::Bool(false)),
|
||||||
inline_sources_content: config.inline_sources_content,
|
inline_sources_content: config.inline_sources_content,
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"lints": {
|
||||||
|
"noAlert": ["error"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
alert();
|
||||||
|
|
||||||
|
const alert = () => {};
|
||||||
|
|
||||||
|
window.alert();
|
@ -0,0 +1,6 @@
|
|||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
5 | window.alert();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"lints": {
|
||||||
|
"noAlert": ["error"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,4 @@
|
|||||||
|
// Test cases taken form https://github.com/eslint/eslint/blob/5769cc23eca7197bb5993a0201cc269a056d4dfd/tests/lib/rules/no-alert.js
|
||||||
|
|
||||||
|
function alert() {}
|
||||||
|
window.alert(foo);
|
@ -0,0 +1,6 @@
|
|||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
4 | window.alert(foo);
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
8
crates/swc/tests/errors/lints/no-alert/es-2020/.swcrc
Normal file
8
crates/swc/tests/errors/lints/no-alert/es-2020/.swcrc
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"target": "es2020",
|
||||||
|
"lints": {
|
||||||
|
"noAlert": ["error"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
crates/swc/tests/errors/lints/no-alert/es-2020/input.js
Normal file
10
crates/swc/tests/errors/lints/no-alert/es-2020/input.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
// Test cases taken form https://github.com/eslint/eslint/blob/5769cc23eca7197bb5993a0201cc269a056d4dfd/tests/lib/rules/no-alert.js
|
||||||
|
|
||||||
|
globalThis.alert();
|
||||||
|
function foo() {
|
||||||
|
var globalThis = bar;
|
||||||
|
globalThis.alert();
|
||||||
|
}
|
||||||
|
globalThis.alert();
|
||||||
|
window?.alert(foo);
|
||||||
|
(window?.alert)(foo);
|
@ -0,0 +1,24 @@
|
|||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
3 | globalThis.alert();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
8 | globalThis.alert();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
9 | window?.alert(foo);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
10 | (window?.alert)(foo);
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
7
crates/swc/tests/errors/lints/no-alert/simple/.swcrc
Normal file
7
crates/swc/tests/errors/lints/no-alert/simple/.swcrc
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"jsc": {
|
||||||
|
"lints": {
|
||||||
|
"noAlert": ["error"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
54
crates/swc/tests/errors/lints/no-alert/simple/input.js
Normal file
54
crates/swc/tests/errors/lints/no-alert/simple/input.js
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
// Test cases taken form https://github.com/eslint/eslint/blob/5769cc23eca7197bb5993a0201cc269a056d4dfd/tests/lib/rules/no-alert.js
|
||||||
|
|
||||||
|
alert();
|
||||||
|
window.alert();
|
||||||
|
window["alert"]();
|
||||||
|
confirm();
|
||||||
|
window.confirm();
|
||||||
|
window["confirm"]();
|
||||||
|
prompt();
|
||||||
|
window.prompt();
|
||||||
|
window["prompt"]();
|
||||||
|
function foo1(alert) {
|
||||||
|
window.alert();
|
||||||
|
}
|
||||||
|
function foo2() {
|
||||||
|
alert();
|
||||||
|
}
|
||||||
|
function foo3() {
|
||||||
|
var alert = function () {};
|
||||||
|
}
|
||||||
|
alert();
|
||||||
|
|
||||||
|
// currently unsupported
|
||||||
|
// this.alert(foo)
|
||||||
|
// this['alert'](foo)
|
||||||
|
|
||||||
|
function foo4() {
|
||||||
|
var window = bar;
|
||||||
|
window.alert();
|
||||||
|
}
|
||||||
|
window.alert();
|
||||||
|
|
||||||
|
function foo5() {
|
||||||
|
alert();
|
||||||
|
const alert = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
alert(() => alert("foo"));
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
const obj = {
|
||||||
|
alert,
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
alert = () => {};
|
||||||
|
})();
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
console.log(alert);
|
||||||
|
})();
|
||||||
|
|
||||||
|
fu(() => alert(""));
|
@ -0,0 +1,96 @@
|
|||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
3 | alert();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
4 | window.alert();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
5 | window["alert"]();
|
||||||
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected confirm
|
||||||
|
|
||||||
|
|
|
||||||
|
6 | confirm();
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected confirm
|
||||||
|
|
||||||
|
|
|
||||||
|
7 | window.confirm();
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected confirm
|
||||||
|
|
||||||
|
|
|
||||||
|
8 | window["confirm"]();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected prompt
|
||||||
|
|
||||||
|
|
|
||||||
|
9 | prompt();
|
||||||
|
| ^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected prompt
|
||||||
|
|
||||||
|
|
|
||||||
|
10 | window.prompt();
|
||||||
|
| ^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected prompt
|
||||||
|
|
||||||
|
|
|
||||||
|
11 | window["prompt"]();
|
||||||
|
| ^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
13 | window.alert();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
16 | alert();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
21 | alert();
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
31 | window.alert();
|
||||||
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
38 | alert(() => alert("foo"));
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
38 | alert(() => alert("foo"));
|
||||||
|
| ^^^^^^^^^^^^
|
||||||
|
|
||||||
|
error: Unexpected alert
|
||||||
|
|
||||||
|
|
|
||||||
|
54 | fu(() => alert(""));
|
||||||
|
| ^^^^^^^^^
|
||||||
|
|
@ -24,3 +24,6 @@ swc_ecma_codegen = {version = "0.89.0", path = "../swc_ecma_codegen"}
|
|||||||
swc_ecma_parser = {version = "0.87.0", path = "../swc_ecma_parser"}
|
swc_ecma_parser = {version = "0.87.0", path = "../swc_ecma_parser"}
|
||||||
swc_ecma_transforms_base = {version = "0.57.0", path = "../swc_ecma_transforms_base"}
|
swc_ecma_transforms_base = {version = "0.57.0", path = "../swc_ecma_transforms_base"}
|
||||||
testing = {version = "0.18.0", path = "../testing"}
|
testing = {version = "0.18.0", path = "../testing"}
|
||||||
|
|
||||||
|
[features]
|
||||||
|
non_critical_lints = []
|
@ -1,4 +1,5 @@
|
|||||||
use crate::rules::no_console::NoConsoleConfig;
|
#[cfg(feature = "non_critical_lints")]
|
||||||
|
use crate::rules::non_critical_lints::no_console::NoConsoleConfig;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
|
|
||||||
@ -36,9 +37,15 @@ impl<T: Debug + Clone + Serialize + Default> RuleConfig<T> {
|
|||||||
#[non_exhaustive]
|
#[non_exhaustive]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct LintConfig {
|
pub struct LintConfig {
|
||||||
|
#[cfg(feature = "non_critical_lints")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub no_console: RuleConfig<NoConsoleConfig>,
|
pub no_console: RuleConfig<NoConsoleConfig>,
|
||||||
|
|
||||||
|
#[cfg(feature = "non_critical_lints")]
|
||||||
|
#[serde(default)]
|
||||||
|
pub no_alert: RuleConfig<()>,
|
||||||
|
|
||||||
|
#[cfg(feature = "non_critical_lints")]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub no_debugger: RuleConfig<()>,
|
pub no_debugger: RuleConfig<()>,
|
||||||
}
|
}
|
||||||
|
@ -6,22 +6,55 @@ use swc_ecma_visit::{noop_fold_type, Fold};
|
|||||||
mod const_assign;
|
mod const_assign;
|
||||||
mod duplicate_bindings;
|
mod duplicate_bindings;
|
||||||
mod duplicate_exports;
|
mod duplicate_exports;
|
||||||
pub mod no_console;
|
|
||||||
mod no_debugger;
|
|
||||||
|
|
||||||
pub fn all(lint_config: &LintConfig, top_level_ctxt: SyntaxContext) -> Vec<Box<dyn Rule>> {
|
#[cfg(feature = "non_critical_lints")]
|
||||||
|
#[path = ""]
|
||||||
|
pub(crate) mod non_critical_lints {
|
||||||
|
pub mod no_alert;
|
||||||
|
pub mod no_console;
|
||||||
|
pub mod no_debugger;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "non_critical_lints")]
|
||||||
|
use non_critical_lints::*;
|
||||||
|
|
||||||
|
pub struct LintParams<'a> {
|
||||||
|
pub program: &'a Program,
|
||||||
|
pub lint_config: &'a LintConfig,
|
||||||
|
pub top_level_ctxt: SyntaxContext,
|
||||||
|
pub es_version: EsVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn all(lint_params: LintParams) -> Vec<Box<dyn Rule>> {
|
||||||
let mut rules = vec![
|
let mut rules = vec![
|
||||||
const_assign::const_assign(),
|
const_assign::const_assign(),
|
||||||
duplicate_bindings::duplicate_bindings(),
|
duplicate_bindings::duplicate_bindings(),
|
||||||
duplicate_exports::duplicate_exports(),
|
duplicate_exports::duplicate_exports(),
|
||||||
];
|
];
|
||||||
|
|
||||||
rules.extend(no_console::no_console(
|
#[cfg(feature = "non_critical_lints")]
|
||||||
&lint_config.no_console,
|
{
|
||||||
top_level_ctxt,
|
let LintParams {
|
||||||
));
|
program,
|
||||||
|
lint_config,
|
||||||
|
top_level_ctxt,
|
||||||
|
es_version,
|
||||||
|
} = lint_params;
|
||||||
|
|
||||||
rules.extend(no_debugger::no_debugger(&lint_config.no_debugger));
|
rules.extend(no_console::no_console(
|
||||||
|
&lint_config.no_console,
|
||||||
|
top_level_ctxt,
|
||||||
|
));
|
||||||
|
|
||||||
|
rules.extend(no_alert::no_alert(
|
||||||
|
program,
|
||||||
|
&lint_config.no_alert,
|
||||||
|
top_level_ctxt,
|
||||||
|
es_version,
|
||||||
|
));
|
||||||
|
|
||||||
|
rules.extend(no_debugger::no_debugger(&lint_config.no_debugger));
|
||||||
|
}
|
||||||
|
|
||||||
rules
|
rules
|
||||||
}
|
}
|
||||||
|
184
crates/swc_ecma_lints/src/rules/no_alert.rs
Normal file
184
crates/swc_ecma_lints/src/rules/no_alert.rs
Normal file
@ -0,0 +1,184 @@
|
|||||||
|
use crate::{
|
||||||
|
config::{LintRuleReaction, RuleConfig},
|
||||||
|
rule::{visitor_rule, Rule},
|
||||||
|
};
|
||||||
|
use swc_atoms::JsWord;
|
||||||
|
use swc_common::{collections::AHashSet, errors::HANDLER, Span, SyntaxContext};
|
||||||
|
use swc_ecma_ast::*;
|
||||||
|
use swc_ecma_utils::{collect_decls_with_ctxt, ident::IdentLike};
|
||||||
|
use swc_ecma_visit::{noop_visit_type, Visit, VisitWith};
|
||||||
|
|
||||||
|
const FN_NAMES: &[&str] = &["alert", "confirm", "prompt"];
|
||||||
|
const GLOBAL_THIS_PROP: &str = "globalThis";
|
||||||
|
const OBJ_NAMES: &[&str] = &["window", GLOBAL_THIS_PROP];
|
||||||
|
|
||||||
|
pub fn no_alert(
|
||||||
|
program: &Program,
|
||||||
|
config: &RuleConfig<()>,
|
||||||
|
top_level_ctxt: SyntaxContext,
|
||||||
|
es_version: EsVersion,
|
||||||
|
) -> Option<Box<dyn Rule>> {
|
||||||
|
let top_level_declared_vars: AHashSet<Id> = collect_decls_with_ctxt(program, top_level_ctxt);
|
||||||
|
let rule_reaction = config.get_rule_reaction();
|
||||||
|
|
||||||
|
match rule_reaction {
|
||||||
|
LintRuleReaction::Off => None,
|
||||||
|
_ => Some(visitor_rule(NoAlert::new(
|
||||||
|
*rule_reaction,
|
||||||
|
top_level_declared_vars,
|
||||||
|
top_level_ctxt,
|
||||||
|
es_version,
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
struct NoAlert {
|
||||||
|
expected_reaction: LintRuleReaction,
|
||||||
|
top_level_ctxt: SyntaxContext,
|
||||||
|
top_level_declared_vars: AHashSet<Id>,
|
||||||
|
pass_call_on_global_this: bool,
|
||||||
|
inside_callee: bool,
|
||||||
|
obj: Option<JsWord>,
|
||||||
|
prop: Option<JsWord>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NoAlert {
|
||||||
|
fn new(
|
||||||
|
expected_reaction: LintRuleReaction,
|
||||||
|
top_level_declared_vars: AHashSet<Id>,
|
||||||
|
top_level_ctxt: SyntaxContext,
|
||||||
|
es_version: EsVersion,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
expected_reaction,
|
||||||
|
top_level_ctxt,
|
||||||
|
top_level_declared_vars,
|
||||||
|
pass_call_on_global_this: es_version < EsVersion::Es2020,
|
||||||
|
inside_callee: false,
|
||||||
|
obj: None,
|
||||||
|
prop: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_report(&self, span: Span, fn_name: &str) {
|
||||||
|
let message = format!("Unexpected {}", fn_name);
|
||||||
|
|
||||||
|
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, call_span: Span, obj: &Option<JsWord>, prop: &JsWord) {
|
||||||
|
if let Some(obj) = obj {
|
||||||
|
let obj_name: &str = &*obj;
|
||||||
|
|
||||||
|
if self.pass_call_on_global_this && obj_name == GLOBAL_THIS_PROP {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !OBJ_NAMES.contains(&obj_name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let fn_name: &str = &*prop;
|
||||||
|
|
||||||
|
if FN_NAMES.contains(&fn_name) {
|
||||||
|
self.emit_report(call_span, fn_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_satisfying_indent(&self, ident: &Ident) -> bool {
|
||||||
|
if ident.span.ctxt != self.top_level_ctxt {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.top_level_declared_vars.contains(&ident.to_id()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_callee(&mut self, expr: &Expr) {
|
||||||
|
match expr {
|
||||||
|
Expr::Ident(ident) => {
|
||||||
|
if self.is_satisfying_indent(ident) {
|
||||||
|
self.prop = Some(ident.sym.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
MemberProp::Computed(comp) => {
|
||||||
|
if let Expr::Lit(Lit::Str(Str { value, .. })) = comp.expr.as_ref() {
|
||||||
|
self.prop = Some(value.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: handle call alert on "this"
|
||||||
|
}
|
||||||
|
Expr::OptChain(opt_chain) => {
|
||||||
|
opt_chain.visit_children_with(self);
|
||||||
|
}
|
||||||
|
Expr::Paren(paren) => {
|
||||||
|
paren.visit_children_with(self);
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_call(&mut self, call_expr: &CallExpr) {
|
||||||
|
if let Some(callee) = call_expr.callee.as_expr() {
|
||||||
|
self.inside_callee = true;
|
||||||
|
|
||||||
|
callee.visit_with(self);
|
||||||
|
|
||||||
|
self.inside_callee = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(prop) = &self.prop {
|
||||||
|
self.check(call_expr.span, &self.obj, prop);
|
||||||
|
|
||||||
|
self.obj = None;
|
||||||
|
self.prop = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Visit for NoAlert {
|
||||||
|
noop_visit_type!();
|
||||||
|
|
||||||
|
fn visit_expr(&mut self, expr: &Expr) {
|
||||||
|
if self.inside_callee {
|
||||||
|
self.handle_callee(expr);
|
||||||
|
} else {
|
||||||
|
if let Expr::Call(call_expr) = expr {
|
||||||
|
self.handle_call(call_expr);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr.visit_children_with(self);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,10 +23,7 @@ pub fn no_console(
|
|||||||
|
|
||||||
match rule_reaction {
|
match rule_reaction {
|
||||||
LintRuleReaction::Off => None,
|
LintRuleReaction::Off => None,
|
||||||
_ => Some(visitor_rule(NoConsole::new(
|
_ => Some(visitor_rule(NoConsole::new(*rule_reaction, top_level_ctxt))),
|
||||||
rule_reaction.clone(),
|
|
||||||
top_level_ctxt,
|
|
||||||
))),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,7 @@ use crate::{
|
|||||||
config::{LintRuleReaction, RuleConfig},
|
config::{LintRuleReaction, RuleConfig},
|
||||||
rule::{visitor_rule, Rule},
|
rule::{visitor_rule, Rule},
|
||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use swc_common::{errors::HANDLER, Span};
|
||||||
use swc_common::{collections::AHashSet, errors::HANDLER, Span, SyntaxContext};
|
|
||||||
use swc_ecma_ast::*;
|
use swc_ecma_ast::*;
|
||||||
use swc_ecma_visit::{noop_visit_type, Visit};
|
use swc_ecma_visit::{noop_visit_type, Visit};
|
||||||
|
|
||||||
|
@ -1,8 +1,11 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use swc_common::{input::SourceFileInput, Mark, SyntaxContext};
|
use swc_common::{input::SourceFileInput, Mark, SyntaxContext};
|
||||||
use swc_ecma_ast::EsVersion;
|
use swc_ecma_ast::{EsVersion, Program};
|
||||||
use swc_ecma_lints::{config::LintConfig, rules::all};
|
use swc_ecma_lints::{
|
||||||
|
config::LintConfig,
|
||||||
|
rules::{all, LintParams},
|
||||||
|
};
|
||||||
use swc_ecma_parser::{lexer::Lexer, Parser, Syntax};
|
use swc_ecma_parser::{lexer::Lexer, Parser, Syntax};
|
||||||
use swc_ecma_transforms_base::resolver::resolver_with_mark;
|
use swc_ecma_transforms_base::resolver::resolver_with_mark;
|
||||||
use swc_ecma_utils::HANDLER;
|
use swc_ecma_utils::HANDLER;
|
||||||
@ -13,6 +16,7 @@ use swc_ecma_visit::VisitMutWith;
|
|||||||
fn pass(input: PathBuf) {
|
fn pass(input: PathBuf) {
|
||||||
testing::run_test(false, |cm, handler| {
|
testing::run_test(false, |cm, handler| {
|
||||||
let fm = cm.load_file(&input).unwrap();
|
let fm = cm.load_file(&input).unwrap();
|
||||||
|
let es_version = EsVersion::latest();
|
||||||
|
|
||||||
let lexer = Lexer::new(
|
let lexer = Lexer::new(
|
||||||
if input.extension().unwrap() == "ts" {
|
if input.extension().unwrap() == "ts" {
|
||||||
@ -29,7 +33,7 @@ fn pass(input: PathBuf) {
|
|||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
EsVersion::latest(),
|
es_version,
|
||||||
SourceFileInput::from(&*fm),
|
SourceFileInput::from(&*fm),
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
@ -43,13 +47,22 @@ fn pass(input: PathBuf) {
|
|||||||
|
|
||||||
let top_level_ctxt = SyntaxContext::empty().apply_mark(top_level_mark);
|
let top_level_ctxt = SyntaxContext::empty().apply_mark(top_level_mark);
|
||||||
|
|
||||||
let mut config = LintConfig::default();
|
let config = LintConfig::default();
|
||||||
|
|
||||||
let rules = all(&config, top_level_ctxt);
|
let program = Program::Module(m);
|
||||||
|
|
||||||
|
let rules = all(LintParams {
|
||||||
|
program: &program,
|
||||||
|
lint_config: &config,
|
||||||
|
top_level_ctxt,
|
||||||
|
es_version,
|
||||||
|
});
|
||||||
|
|
||||||
HANDLER.set(handler, || {
|
HANDLER.set(handler, || {
|
||||||
for mut rule in rules {
|
if let Program::Module(m) = &program {
|
||||||
rule.lint_module(&m);
|
for mut rule in rules {
|
||||||
|
rule.lint_module(&m);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -29,3 +29,4 @@ swc_common = {path = "../swc_common"}
|
|||||||
swc_ecmascript = {path = "../swc_ecmascript"}
|
swc_ecmascript = {path = "../swc_ecmascript"}
|
||||||
tracing = {version = "0.1.28", features = ["release_max_level_off"]}
|
tracing = {version = "0.1.28", features = ["release_max_level_off"]}
|
||||||
wasm-bindgen = {version = "0.2", features = ["serde-serialize"]}
|
wasm-bindgen = {version = "0.2", features = ["serde-serialize"]}
|
||||||
|
swc_ecma_lints = {version = "0.11.1", path = "../swc_ecma_lints", features = ["non_critical_lints"]}
|
||||||
|
Loading…
Reference in New Issue
Block a user