Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support alias require #5520

Merged
merged 1 commit into from
Jan 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use crate::utils::eval::{self, BasicEvaluatedExpression};
use crate::visitors::{expr_matcher, scanner_context_module, JavascriptParser};
use crate::visitors::{extract_require_call_info, is_require_call_start};

pub const COMMONJS_REQUIRE: &str = "require";

pub struct CommonJsImportsParserPlugin;

impl CommonJsImportsParserPlugin {
Expand Down Expand Up @@ -94,15 +96,17 @@ impl CommonJsImportsParserPlugin {
&self,
parser: &mut JavascriptParser,
call_expr: &CallExpr,
for_name: &str,
) -> Option<(Vec<CommonJsRequireDependency>, Vec<RequireHeaderDependency>)> {
if call_expr.args.len() != 1 {
return None;
}

let is_require_expr = call_expr.callee.as_expr().is_some_and(|expr| {
(expr_matcher::is_require(expr) && parser.is_unresolved_require(expr))
|| expr_matcher::is_module_require(expr)
});
let is_require_expr = for_name == COMMONJS_REQUIRE
|| call_expr
.callee
.as_expr()
.is_some_and(|expr| expr_matcher::is_module_require(expr));

if !is_require_expr {
return None;
Expand Down Expand Up @@ -159,20 +163,64 @@ impl CommonJsImportsParserPlugin {
}

impl JavascriptParserPlugin for CommonJsImportsParserPlugin {
fn can_rename(&self, parser: &mut JavascriptParser, str: &str) -> Option<bool> {
if str == COMMONJS_REQUIRE && parser.is_unresolved_ident(str) {
Some(true)
} else {
None
}
}

fn rename(&self, parser: &mut JavascriptParser, expr: &Expr, str: &str) -> Option<bool> {
if str == COMMONJS_REQUIRE && parser.is_unresolved_ident(str) {
parser
.presentational_dependencies
.push(Box::new(ConstDependency::new(
expr.span().real_lo(),
expr.span().real_hi(),
"undefined".into(),
None,
)));
Some(false)
} else {
None
}
}

fn evaluate_typeof(
&self,
parser: &mut JavascriptParser,
expression: &Ident,
start: u32,
end: u32,
) -> Option<BasicEvaluatedExpression> {
if expression.sym.as_str() == "require" && parser.is_unresolved_ident("require") {
if expression.sym.as_str() == COMMONJS_REQUIRE && parser.is_unresolved_ident(COMMONJS_REQUIRE) {
Some(eval::evaluate_to_string("function".to_string(), start, end))
} else {
None
}
}

fn evaluate_identifier(
&self,
parser: &mut JavascriptParser,
ident: &str,
start: u32,
end: u32,
) -> Option<BasicEvaluatedExpression> {
if ident == COMMONJS_REQUIRE && parser.is_unresolved_ident(COMMONJS_REQUIRE) {
Some(eval::evaluate_to_identifier(
COMMONJS_REQUIRE.to_string(),
COMMONJS_REQUIRE.to_string(),
Some(true),
start,
end,
))
} else {
None
}
}

fn expression_logical_operator(
&self,
parser: &mut JavascriptParser,
Expand Down Expand Up @@ -240,14 +288,14 @@ impl JavascriptParserPlugin for CommonJsImportsParserPlugin {
&self,
parser: &mut JavascriptParser,
call_expr: &CallExpr,
_for_name: &str,
for_name: &str,
) -> Option<bool> {
let Callee::Expr(expr) = &call_expr.callee else {
return Some(false);
};
let deps = self.require_handler(parser, call_expr);

if let Some((commonjs_require_deps, require_helper_deps)) = deps {
if let Some((commonjs_require_deps, require_helper_deps)) =
self.require_handler(parser, call_expr, for_name)
{
for dep in commonjs_require_deps {
parser.dependencies.push(Box::new(dep))
}
Expand Down
78 changes: 61 additions & 17 deletions crates/rspack_plugin_javascript/src/parser_plugin/drive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,23 +68,6 @@ impl JavascriptParserPlugin for JavaScriptParserPluginDrive {
None
}

fn evaluate_typeof(
&self,
parser: &mut JavascriptParser,
ident: &swc_core::ecma::ast::Ident,
start: u32,
end: u32,
) -> Option<BasicEvaluatedExpression> {
for plugin in &self.plugins {
let res = plugin.evaluate_typeof(parser, ident, start, end);
// `SyncBailHook`
if res.is_some() {
return res;
}
}
None
}

fn call(&self, parser: &mut JavascriptParser, expr: &CallExpr, name: &str) -> Option<bool> {
for plugin in &self.plugins {
let res = plugin.call(parser, expr, name);
Expand Down Expand Up @@ -274,4 +257,65 @@ impl JavascriptParserPlugin for JavaScriptParserPluginDrive {
}
None
}

fn evaluate_typeof(
&self,
parser: &mut JavascriptParser,
ident: &swc_core::ecma::ast::Ident,
start: u32,
end: u32,
) -> Option<BasicEvaluatedExpression> {
for plugin in &self.plugins {
let res = plugin.evaluate_typeof(parser, ident, start, end);
// `SyncBailHook`
if res.is_some() {
return res;
}
}
None
}

fn evaluate_identifier(
&self,
parser: &mut JavascriptParser,
ident: &str,
start: u32,
end: u32,
) -> Option<BasicEvaluatedExpression> {
for plugin in &self.plugins {
let res = plugin.evaluate_identifier(parser, ident, start, end);
// `SyncBailHook`
if res.is_some() {
return res;
}
}
None
}

fn can_rename(&self, parser: &mut JavascriptParser, str: &str) -> Option<bool> {
for plugin in &self.plugins {
let res = plugin.can_rename(parser, str);
// `SyncBailHook`
if res.is_some() {
return res;
}
}
None
}

fn rename(
&self,
parser: &mut JavascriptParser,
expr: &swc_core::ecma::ast::Expr,
str: &str,
) -> Option<bool> {
for plugin in &self.plugins {
let res = plugin.rename(parser, expr, str);
// `SyncBailHook`
if res.is_some() {
return res;
}
}
None
}
}
36 changes: 18 additions & 18 deletions crates/rspack_plugin_javascript/src/parser_plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,21 @@ mod webpack_included_plugin;
/// TODO: should move to rspack_plugin_javascript once we drop old treeshaking
mod worker_syntax_plugin;

pub use self::api_plugin::APIPlugin;
pub use self::check_var_decl::CheckVarDeclaratorIdent;
pub use self::common_js_exports_parse_plugin::CommonJsExportsParserPlugin;
pub use self::common_js_imports_parse_plugin::CommonJsImportsParserPlugin;
pub use self::common_js_plugin::CommonJsPlugin;
pub use self::compatibility_plugin::CompatibilityPlugin;
pub use self::drive::JavaScriptParserPluginDrive;
pub use self::exports_info_api_plugin::ExportsInfoApiPlugin;
pub use self::harmony_detection_parser_plugin::HarmonDetectionParserPlugin;
pub use self::harmony_top_level_this_plugin::HarmonyTopLevelThisParserPlugin;
pub use self::node_stuff_plugin::NodeStuffPlugin;
pub use self::provide::ProviderPlugin;
pub use self::r#const::{is_logic_op, ConstPlugin};
pub use self::r#trait::{BoxJavascriptParserPlugin, JavascriptParserPlugin};
pub use self::require_context_dependency_parser_plugin::RequireContextDependencyParserPlugin;
pub use self::url_plugin::URLPlugin;
pub use self::webpack_included_plugin::WebpackIsIncludedPlugin;
pub use self::worker_syntax_plugin::WorkerSyntaxScanner;
pub(crate) use self::api_plugin::APIPlugin;
pub(crate) use self::check_var_decl::CheckVarDeclaratorIdent;
pub(crate) use self::common_js_exports_parse_plugin::CommonJsExportsParserPlugin;
pub(crate) use self::common_js_imports_parse_plugin::CommonJsImportsParserPlugin;
pub(crate) use self::common_js_plugin::CommonJsPlugin;
pub(crate) use self::compatibility_plugin::CompatibilityPlugin;
pub(crate) use self::drive::JavaScriptParserPluginDrive;
pub(crate) use self::exports_info_api_plugin::ExportsInfoApiPlugin;
pub(crate) use self::harmony_detection_parser_plugin::HarmonDetectionParserPlugin;
pub(crate) use self::harmony_top_level_this_plugin::HarmonyTopLevelThisParserPlugin;
pub(crate) use self::node_stuff_plugin::NodeStuffPlugin;
pub(crate) use self::provide::ProviderPlugin;
pub(crate) use self::r#const::{is_logic_op, ConstPlugin};
pub(crate) use self::r#trait::{BoxJavascriptParserPlugin, JavascriptParserPlugin};
pub(crate) use self::require_context_dependency_parser_plugin::RequireContextDependencyParserPlugin;
pub(crate) use self::url_plugin::URLPlugin;
pub(crate) use self::webpack_included_plugin::WebpackIsIncludedPlugin;
pub(crate) use self::worker_syntax_plugin::WorkerSyntaxScanner;
20 changes: 19 additions & 1 deletion crates/rspack_plugin_javascript/src/parser_plugin/trait.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use swc_core::ecma::ast::{
AssignExpr, AwaitExpr, BinExpr, CallExpr, ForOfStmt, Ident, IfStmt, MemberExpr, ModuleDecl,
AssignExpr, AwaitExpr, BinExpr, CallExpr, Expr, ForOfStmt, Ident, IfStmt, MemberExpr, ModuleDecl,
};
use swc_core::ecma::ast::{NewExpr, Program, Stmt, ThisExpr, UnaryExpr, VarDecl, VarDeclarator};

Expand All @@ -23,6 +23,14 @@ pub trait JavascriptParserPlugin {
/// The return value will have no effect.
fn top_level_for_of_await_stmt(&self, _parser: &mut JavascriptParser, _stmt: &ForOfStmt) {}

fn can_rename(&self, _parser: &mut JavascriptParser, _str: &str) -> Option<bool> {
None
}

fn rename(&self, _parser: &mut JavascriptParser, _expr: &Expr, _str: &str) -> Option<bool> {
None
}

fn program(&self, _parser: &mut JavascriptParser, _ast: &Program) -> Option<bool> {
None
}
Expand All @@ -46,6 +54,16 @@ pub trait JavascriptParserPlugin {
None
}

fn evaluate_identifier(
&self,
_parser: &mut JavascriptParser,
_ident: &str,
_start: u32,
_end: u32,
) -> Option<BasicEvaluatedExpression> {
None
}

fn call(
&self,
_parser: &mut JavascriptParser,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,8 @@ fn is_webpack_is_included(ident: &Ident) -> bool {
pub struct WebpackIsIncludedPlugin;

impl JavascriptParserPlugin for WebpackIsIncludedPlugin {
fn call(&self, parser: &mut JavascriptParser<'_>, expr: &CallExpr, _name: &str) -> Option<bool> {
let is_webpack_is_included = expr
.callee
.as_expr()
.and_then(|expr| expr.as_ident())
.map(is_webpack_is_included)
.unwrap_or_default();
if !is_webpack_is_included || expr.args.len() != 1 || expr.args[0].spread.is_some() {
fn call(&self, parser: &mut JavascriptParser<'_>, expr: &CallExpr, name: &str) -> Option<bool> {
if name != WEBPACK_IS_INCLUDED || expr.args.len() != 1 || expr.args[0].spread.is_some() {
return None;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,17 +188,15 @@ fn handle_logical_and(
let mut res = BasicEvaluatedExpression::with_range(expr.span.real_lo(), expr.span.hi().0);

let left = scanner.evaluate_expression(&expr.left);

match left.as_bool() {
Some(true) => {
let right = scanner.evaluate_expression(&expr.right);
// true && unknown = unknown
right.as_bool().map(|b| {
// true && right = right
res.set_bool(b);
res.set_side_effects(left.could_have_side_effects() || right.could_have_side_effects());
res
})
let mut right = scanner.evaluate_expression(&expr.right);
if left.could_have_side_effects() {
right.set_side_effects(true)
}
right.set_range(expr.span.real_lo(), expr.span.hi.0);
Some(right)
}
Some(false) => {
// false && any = false
Expand Down
41 changes: 41 additions & 0 deletions crates/rspack_plugin_javascript/src/utils/eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,24 @@ impl BasicEvaluatedExpression {
self.side_effects = false
}

pub fn set_truthy(&mut self) {
self.falsy = false;
self.truthy = true;
self.nullish = Some(false);
}

pub fn set_falsy(&mut self) {
self.falsy = true;
self.truthy = false;
}

pub fn set_nullish(&mut self, nullish: bool) {
self.nullish = Some(nullish);
if nullish {
self.set_falsy()
}
}

pub fn set_items(&mut self, items: Vec<BasicEvaluatedExpression>) {
self.ty = Ty::Array;
self.side_effects = items.iter().any(|item| item.could_have_side_effects());
Expand Down Expand Up @@ -365,6 +383,29 @@ pub fn evaluate_to_string(value: String, start: u32, end: u32) -> BasicEvaluated
eval
}

pub fn evaluate_to_identifier(
identifier: String,
root_info: String,
truthy: Option<bool>,
start: u32,
end: u32,
) -> BasicEvaluatedExpression {
let mut eval = BasicEvaluatedExpression::with_range(start, end);
eval.set_identifier(identifier, ExportedVariableInfo::Name(root_info));
eval.set_side_effects(false);
match truthy {
Some(v) => {
if v {
eval.set_truthy();
} else {
eval.set_falsy();
}
}
None => eval.set_nullish(true),
};
eval
}

bitflags! {
struct RegExpFlag: u8 {
const FLAG_Y = 1 << 0;
Expand Down
Loading
Loading