Skip to content

Commit

Permalink
fix(es/module): Handle directives (#8048)
Browse files Browse the repository at this point in the history
**Related issue:**

 - Closes: #8047
  • Loading branch information
magic-akari committed Oct 2, 2023
1 parent 0c8d8a3 commit 4d8e101
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 38 deletions.
20 changes: 15 additions & 5 deletions crates/swc_ecma_transforms_module/src/amd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver},
util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
use_strict, ImportInterop,
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
VecStmtLike,
},
};

Expand Down Expand Up @@ -143,9 +143,19 @@ where

let mut stmts: Vec<Stmt> = Vec::with_capacity(n.body.len() + 4);

// Collect directives
stmts.extend(
&mut n
.body
.iter_mut()
.take_while(|i| i.directive_continue())
.map(|i| i.take())
.map(ModuleItem::expect_stmt),
);

// "use strict";
if self.config.strict_mode {
stmts.push(clone_first_use_directive(&n.body, true).unwrap_or_else(use_strict));
if self.config.strict_mode && !stmts.has_use_strict() {
stmts.push(use_strict());
}

let ModuleDeclStrip {
Expand All @@ -170,7 +180,7 @@ where
);

stmts.extend(n.body.take().into_iter().filter_map(|item| match item {
ModuleItem::Stmt(stmt) if !stmt.is_directive() => Some(stmt),
ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt),
_ => None,
}));

Expand Down
23 changes: 13 additions & 10 deletions crates/swc_ecma_transforms_module/src/common_js.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver},
util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
prop_name, use_strict, ImportInterop, ObjPropKeyIdent,
define_es_module, emit_export_stmts, local_name_for_src, prop_name, use_strict,
ImportInterop, ObjPropKeyIdent, VecStmtLike,
},
};

Expand Down Expand Up @@ -113,15 +113,18 @@ where

let mut stmts: Vec<ModuleItem> = Vec::with_capacity(n.body.len() + 6);

stmts.extend(clone_first_use_directive(&n.body, false).map(From::from));
// Collect directives
stmts.extend(
&mut n
.body
.iter_mut()
.take_while(|i| i.directive_continue())
.map(|i| i.take()),
);

// "use strict";
if self.config.strict_mode {
stmts.push(
clone_first_use_directive(&n.body, true)
.unwrap_or_else(use_strict)
.into(),
);
if self.config.strict_mode && !stmts.has_use_strict() {
stmts.push(use_strict().into());
}

let ModuleDeclStrip {
Expand Down Expand Up @@ -156,7 +159,7 @@ where
);

stmts.extend(n.body.take().into_iter().filter(|item| match item {
ModuleItem::Stmt(stmt) => !stmt.is_directive(),
ModuleItem::Stmt(stmt) => !stmt.is_empty(),
_ => false,
}));

Expand Down
19 changes: 14 additions & 5 deletions crates/swc_ecma_transforms_module/src/umd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver},
util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
use_strict, ImportInterop,
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
VecStmtLike,
},
};

Expand Down Expand Up @@ -116,9 +116,18 @@ where

let mut stmts: Vec<Stmt> = Vec::with_capacity(module_items.len() + 4);

// Collect directives
stmts.extend(
module_items
.iter_mut()
.take_while(|i| i.directive_continue())
.map(|i| i.take())
.map(ModuleItem::expect_stmt),
);

// "use strict";
if self.config.config.strict_mode {
stmts.push(clone_first_use_directive(module_items, true).unwrap_or_else(use_strict));
if self.config.config.strict_mode && !stmts.has_use_strict() {
stmts.push(use_strict());
}

let ModuleDeclStrip {
Expand All @@ -143,7 +152,7 @@ where
);

stmts.extend(module_items.take().into_iter().filter_map(|i| match i {
ModuleItem::Stmt(stmt) if !stmt.is_directive() => Some(stmt),
ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt),
_ => None,
}));

Expand Down
43 changes: 25 additions & 18 deletions crates/swc_ecma_transforms_module/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,26 +194,33 @@ pub(super) fn define_es_module(exports: Ident) -> Stmt {
.into_stmt()
}

pub(super) fn clone_first_use_directive(
stmts: &[ModuleItem],
want_use_strict: bool,
) -> Option<Stmt> {
if stmts.is_empty() {
return None;
pub(super) trait VecStmtLike {
type StmtLike: IsDirective;

fn as_ref(&self) -> &[Self::StmtLike];

fn has_use_strict(&self) -> bool {
self.as_ref()
.iter()
.take_while(|s| s.directive_continue())
.any(IsDirective::is_use_strict)
}
}

stmts.iter().find_map(|item| match item {
ModuleItem::Stmt(stmt) => {
if (want_use_strict && stmt.is_use_strict())
|| (!want_use_strict && !stmt.is_use_strict() && stmt.is_directive())
{
Some(stmt.clone())
} else {
None
}
}
_ => None,
})
impl VecStmtLike for [ModuleItem] {
type StmtLike = ModuleItem;

fn as_ref(&self) -> &[Self::StmtLike] {
self
}
}

impl VecStmtLike for [Stmt] {
type StmtLike = Stmt;

fn as_ref(&self) -> &[Self::StmtLike] {
self
}
}

pub(super) fn use_strict() -> Stmt {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ define([
"require",
"exports"
], function(require, exports) {
"use client";
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
], factory);
else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {});
})(this, function(exports) {
"use client";
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client";

"foo";

"use bar";

"use strict";
// All above are directives

function foo() { }

"use hello"; // This is not directive
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
define([
"require"
], function(require) {
"use client";
"foo";
"use bar";
"use strict";
// All above are directives
function foo() {}
"use hello"; // This is not directive
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
"use client";
"foo";
"use bar";
"use strict";
// All above are directives
function foo() {}
"use hello"; // This is not directive
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(function(global, factory) {
if (typeof module === "object" && typeof module.exports === "object") factory();
else if (typeof define === "function" && define.amd) define([], factory);
else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory();
})(this, function() {
"use client";
"foo";
"use bar";
"use strict";
// All above are directives
function foo() {}
"use hello"; // This is not directive
});
22 changes: 22 additions & 0 deletions crates/swc_ecma_utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2262,6 +2262,7 @@ pub fn prepend_stmts<T: StmtLike>(

pub trait IsDirective {
fn as_ref(&self) -> Option<&Stmt>;
#[deprecated(note = "use directive_continue instead")]
fn is_directive(&self) -> bool {
match self.as_ref() {
Some(Stmt::Expr(expr)) => match &*expr.expr {
Expand All @@ -2273,6 +2274,15 @@ pub trait IsDirective {
_ => false,
}
}
fn directive_continue(&self) -> bool {
match self.as_ref() {
Some(Stmt::Expr(expr)) => match &*expr.expr {
Expr::Lit(Lit::Str(..)) => true,
_ => false,
},
_ => false,
}
}
fn is_use_strict(&self) -> bool {
match self.as_ref() {
Some(Stmt::Expr(expr)) => match *expr.expr {
Expand All @@ -2292,6 +2302,18 @@ impl IsDirective for Stmt {
}
}

impl IsDirective for ModuleItem {
fn as_ref(&self) -> Option<&Stmt> {
self.as_stmt()
}
}

impl IsDirective for &ModuleItem {
fn as_ref(&self) -> Option<&Stmt> {
self.as_stmt()
}
}

pub trait IdentExt {
fn prefix(&self, prefix: &str) -> Ident;

Expand Down

1 comment on commit 4d8e101

@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: 4d8e101 Previous: f717cf2 Ratio
es/full/bugs-1 275528 ns/iter (± 1852) 277700 ns/iter (± 26995) 0.99
es/full/minify/libraries/antd 1313388202 ns/iter (± 13063122) 1296931646 ns/iter (± 8457837) 1.01
es/full/minify/libraries/d3 278470778 ns/iter (± 5361479) 275029976 ns/iter (± 7061922) 1.01
es/full/minify/libraries/echarts 1048540142 ns/iter (± 10779862) 1052617424 ns/iter (± 11323377) 1.00
es/full/minify/libraries/jquery 83973165 ns/iter (± 168650) 83813640 ns/iter (± 132058) 1.00
es/full/minify/libraries/lodash 97160484 ns/iter (± 359447) 96871030 ns/iter (± 273483) 1.00
es/full/minify/libraries/moment 49767035 ns/iter (± 112519) 49734858 ns/iter (± 179312) 1.00
es/full/minify/libraries/react 18078089 ns/iter (± 107091) 17918412 ns/iter (± 68088) 1.01
es/full/minify/libraries/terser 216864726 ns/iter (± 893834) 215583178 ns/iter (± 1707353) 1.01
es/full/minify/libraries/three 384437340 ns/iter (± 1525872) 384143758 ns/iter (± 5259211) 1.00
es/full/minify/libraries/typescript 2632573209 ns/iter (± 22876423) 2631939666 ns/iter (± 14979883) 1.00
es/full/minify/libraries/victory 563959199 ns/iter (± 3775218) 559882757 ns/iter (± 3650006) 1.01
es/full/minify/libraries/vue 119010406 ns/iter (± 325846) 119013314 ns/iter (± 150541) 1.00
es/full/codegen/es3 34700 ns/iter (± 52) 34181 ns/iter (± 53) 1.02
es/full/codegen/es5 34612 ns/iter (± 89) 34176 ns/iter (± 82) 1.01
es/full/codegen/es2015 34547 ns/iter (± 111) 34180 ns/iter (± 109) 1.01
es/full/codegen/es2016 34622 ns/iter (± 95) 34106 ns/iter (± 84) 1.02
es/full/codegen/es2017 34607 ns/iter (± 133) 34080 ns/iter (± 87) 1.02
es/full/codegen/es2018 34616 ns/iter (± 135) 34040 ns/iter (± 83) 1.02
es/full/codegen/es2019 34609 ns/iter (± 76) 34174 ns/iter (± 89) 1.01
es/full/codegen/es2020 34658 ns/iter (± 87) 34159 ns/iter (± 81) 1.01
es/full/all/es3 164374660 ns/iter (± 912152) 165479614 ns/iter (± 755581) 0.99
es/full/all/es5 157601005 ns/iter (± 1594985) 157931122 ns/iter (± 1037684) 1.00
es/full/all/es2015 116261825 ns/iter (± 768070) 117551894 ns/iter (± 3157855) 0.99
es/full/all/es2016 116286729 ns/iter (± 785445) 116296416 ns/iter (± 698565) 1.00
es/full/all/es2017 114617768 ns/iter (± 1081265) 116068245 ns/iter (± 514407) 0.99
es/full/all/es2018 113623986 ns/iter (± 875593) 114383554 ns/iter (± 1711770) 0.99
es/full/all/es2019 112463834 ns/iter (± 1185707) 113537218 ns/iter (± 824325) 0.99
es/full/all/es2020 107996064 ns/iter (± 963528) 109234215 ns/iter (± 705824) 0.99
es/full/parser 485766 ns/iter (± 6118) 499748 ns/iter (± 4928) 0.97
es/full/base/fixer 17943 ns/iter (± 111) 21043 ns/iter (± 314) 0.85
es/full/base/resolver_and_hygiene 80666 ns/iter (± 278) 81865 ns/iter (± 136) 0.99

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

Please sign in to comment.