mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(linter/tree-shaking): support import statement (#3138)
This commit is contained in:
parent
d76507699d
commit
16a31e95b8
3 changed files with 104 additions and 23 deletions
|
|
@ -251,11 +251,21 @@ impl<'a> ListenerMap for AstNode<'a> {
|
|||
AstKind::Class(class) => {
|
||||
class.report_effects_when_called(options);
|
||||
}
|
||||
AstKind::ImportDefaultSpecifier(specifier) => {
|
||||
if !has_comment_about_side_effect_check(specifier.span, options.ctx) {
|
||||
options.ctx.diagnostic(NoSideEffectsDiagnostic::CallImport(specifier.span));
|
||||
}
|
||||
}
|
||||
AstKind::ImportSpecifier(specifier) => {
|
||||
let span = specifier.local.span;
|
||||
if !has_comment_about_side_effect_check(span, options.ctx) {
|
||||
options.ctx.diagnostic(NoSideEffectsDiagnostic::CallImport(span));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
fn report_effects_when_mutated(&self, options: &NodeListenerOptions) {
|
||||
#[allow(clippy::single_match)]
|
||||
match self.kind() {
|
||||
AstKind::VariableDeclarator(decl) => {
|
||||
if let Some(init) = &decl.init {
|
||||
|
|
@ -272,6 +282,15 @@ impl<'a> ListenerMap for AstNode<'a> {
|
|||
.ctx
|
||||
.diagnostic(NoSideEffectsDiagnostic::MutateParameter(Span::new(start, end)));
|
||||
}
|
||||
AstKind::ImportDefaultSpecifier(specifier) => {
|
||||
options.ctx.diagnostic(NoSideEffectsDiagnostic::MutateImport(specifier.span));
|
||||
}
|
||||
AstKind::ImportSpecifier(specifier) => {
|
||||
options.ctx.diagnostic(NoSideEffectsDiagnostic::MutateImport(specifier.local.span));
|
||||
}
|
||||
AstKind::ImportNamespaceSpecifier(specifier) => {
|
||||
options.ctx.diagnostic(NoSideEffectsDiagnostic::MutateImport(specifier.local.span));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -754,6 +773,11 @@ impl<'a> ListenerMap for IdentifierReference<'a> {
|
|||
}
|
||||
|
||||
fn report_effects_when_called(&self, options: &NodeListenerOptions) {
|
||||
// TODO: change to `isPureFunction`
|
||||
if has_pure_notation(self.span, options.ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
let ctx = options.ctx;
|
||||
if let Some(symbol_id) = get_symbol_id_of_variable(self, ctx) {
|
||||
let symbol_table = ctx.semantic().symbols();
|
||||
|
|
|
|||
|
|
@ -38,6 +38,10 @@ enum NoSideEffectsDiagnostic {
|
|||
#[diagnostic(severity(warning))]
|
||||
MutateOfThis(#[label] Span),
|
||||
|
||||
#[error("eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of mutating imported variable")]
|
||||
#[diagnostic(severity(warning))]
|
||||
MutateImport(#[label] Span),
|
||||
|
||||
#[error("eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling")]
|
||||
#[diagnostic(severity(warning))]
|
||||
Call(#[label] Span),
|
||||
|
|
@ -54,6 +58,10 @@ enum NoSideEffectsDiagnostic {
|
|||
#[diagnostic(severity(warning))]
|
||||
CallParameter(#[label] Span),
|
||||
|
||||
#[error("eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling imported function")]
|
||||
#[diagnostic(severity(warning))]
|
||||
CallImport(#[label] Span),
|
||||
|
||||
#[error("eslint-plugin-tree-shaking(no-side-effects-in-initialization): Debugger statements are side-effects")]
|
||||
#[diagnostic(severity(warning))]
|
||||
Debugger(#[label] Span),
|
||||
|
|
@ -234,23 +242,24 @@ fn test() {
|
|||
"const x = ext, y = ()=>{const x = ()=>{}; x()}; y()",
|
||||
// Identifier when mutated
|
||||
"const x = {}; x.y = ext",
|
||||
// // IfStatement
|
||||
// IfStatement
|
||||
"let y;if (ext > 0) {y = 1} else {y = 2}",
|
||||
"if (false) {ext()}",
|
||||
"if (true) {} else {ext()}",
|
||||
// // ImportDeclaration
|
||||
// r#"import "import""#,
|
||||
// r#"import x from "import-default""#,
|
||||
// r#"import {x} from "import""#,
|
||||
// r#"import {x as y} from "import""#,
|
||||
// r#"import * as x from "import""#,
|
||||
// r#"import /* tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#,
|
||||
// r#"import /* test */ /*tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#,
|
||||
// ImportDeclaration
|
||||
r#"import "import""#,
|
||||
r#"import x from "import-default""#,
|
||||
r#"import {x} from "import""#,
|
||||
r#"import {x as y} from "import""#,
|
||||
r#"import * as x from "import""#,
|
||||
r#"import /* tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#,
|
||||
r#"import /* test */ /*tree-shaking no-side-effects-when-called */ x from "import-default-no-effects"; x()"#,
|
||||
// TODO: Current only support the comment next to code.
|
||||
// r#"import /* tree-shaking no-side-effects-when-called*/ /* test */ x from "import-default-no-effects"; x()"#,
|
||||
// r#"import {/* tree-shaking no-side-effects-when-called */ x} from "import-no-effects"; x()"#,
|
||||
// r#"import {x as /* tree-shaking no-side-effects-when-called */ y} from "import-no-effects"; y()"#,
|
||||
// r#"import {x} from "import"; /*@__PURE__*/ x()"#,
|
||||
// r#"import {x} from "import"; /* @__PURE__ */ x()"#,
|
||||
r#"import {/* tree-shaking no-side-effects-when-called */ x} from "import-no-effects"; x()"#,
|
||||
r#"import {x as /* tree-shaking no-side-effects-when-called */ y} from "import-no-effects"; y()"#,
|
||||
r#"import {x} from "import"; /*@__PURE__*/ x()"#,
|
||||
r#"import {x} from "import"; /* @__PURE__ */ x()"#,
|
||||
// // JSXAttribute
|
||||
// r#"class X {}; const x = <X test="3"/>"#,
|
||||
// "class X {}; const x = <X test={3}/>",
|
||||
|
|
@ -532,15 +541,15 @@ fn test() {
|
|||
"if (1>0){ext()}",
|
||||
"if (1<0){} else {ext()}",
|
||||
"if (ext>0){ext()} else {ext()}",
|
||||
// // ImportDeclaration
|
||||
// r#"import x from "import-default"; x()"#,
|
||||
// r#"import x from "import-default"; x.z = 1"#,
|
||||
// r#"import {x} from "import"; x()"#,
|
||||
// r#"import {x} from "import"; x.z = 1"#,
|
||||
// r#"import {x as y} from "import"; y()"#,
|
||||
// r#"import {x as y} from "import"; y.a = 1"#,
|
||||
// r#"import * as y from "import"; y.x()"#,
|
||||
// r#"import * as y from "import"; y.x = 1"#,
|
||||
// ImportDeclaration
|
||||
r#"import x from "import-default"; x()"#,
|
||||
r#"import x from "import-default"; x.z = 1"#,
|
||||
r#"import {x} from "import"; x()"#,
|
||||
r#"import {x} from "import"; x.z = 1"#,
|
||||
r#"import {x as y} from "import"; y()"#,
|
||||
r#"import {x as y} from "import"; y.a = 1"#,
|
||||
r#"import * as y from "import"; y.x()"#,
|
||||
r#"import * as y from "import"; y.x = 1"#,
|
||||
// // JSXAttribute
|
||||
// "class X {}; const x = <X test={ext()}/>",
|
||||
// "class X {}; class Y {constructor(){ext()}}; const x = <X test=<Y/>/>",
|
||||
|
|
|
|||
|
|
@ -764,6 +764,54 @@ expression: no_side_effects_in_initialization
|
|||
· ───
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling imported function
|
||||
╭─[no_side_effects_in_initialization.tsx:1:8]
|
||||
1 │ import x from "import-default"; x()
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of mutating imported variable
|
||||
╭─[no_side_effects_in_initialization.tsx:1:8]
|
||||
1 │ import x from "import-default"; x.z = 1
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling imported function
|
||||
╭─[no_side_effects_in_initialization.tsx:1:9]
|
||||
1 │ import {x} from "import"; x()
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of mutating imported variable
|
||||
╭─[no_side_effects_in_initialization.tsx:1:9]
|
||||
1 │ import {x} from "import"; x.z = 1
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling imported function
|
||||
╭─[no_side_effects_in_initialization.tsx:1:14]
|
||||
1 │ import {x as y} from "import"; y()
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of mutating imported variable
|
||||
╭─[no_side_effects_in_initialization.tsx:1:14]
|
||||
1 │ import {x as y} from "import"; y.a = 1
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling
|
||||
╭─[no_side_effects_in_initialization.tsx:1:30]
|
||||
1 │ import * as y from "import"; y.x()
|
||||
· ───
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of mutating imported variable
|
||||
╭─[no_side_effects_in_initialization.tsx:1:13]
|
||||
1 │ import * as y from "import"; y.x = 1
|
||||
· ─
|
||||
╰────
|
||||
|
||||
⚠ eslint-plugin-tree-shaking(no-side-effects-in-initialization): Cannot determine side-effects of calling global function `ext`
|
||||
╭─[no_side_effects_in_initialization.tsx:1:15]
|
||||
1 │ const x = new ext()
|
||||
|
|
|
|||
Loading…
Reference in a new issue