Skip to content

Commit 4d8e101

Browse files
authoredOct 2, 2023
fix(es/module): Handle directives (#8048)
**Related issue:** - Closes: #8047
1 parent 0c8d8a3 commit 4d8e101

File tree

11 files changed

+134
-38
lines changed

11 files changed

+134
-38
lines changed
 

‎crates/swc_ecma_transforms_module/src/amd.rs

+15-5
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ use crate::{
2020
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
2121
path::{ImportResolver, Resolver},
2222
util::{
23-
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
24-
use_strict, ImportInterop,
23+
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
24+
VecStmtLike,
2525
},
2626
};
2727

@@ -143,9 +143,19 @@ where
143143

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

146+
// Collect directives
147+
stmts.extend(
148+
&mut n
149+
.body
150+
.iter_mut()
151+
.take_while(|i| i.directive_continue())
152+
.map(|i| i.take())
153+
.map(ModuleItem::expect_stmt),
154+
);
155+
146156
// "use strict";
147-
if self.config.strict_mode {
148-
stmts.push(clone_first_use_directive(&n.body, true).unwrap_or_else(use_strict));
157+
if self.config.strict_mode && !stmts.has_use_strict() {
158+
stmts.push(use_strict());
149159
}
150160

151161
let ModuleDeclStrip {
@@ -170,7 +180,7 @@ where
170180
);
171181

172182
stmts.extend(n.body.take().into_iter().filter_map(|item| match item {
173-
ModuleItem::Stmt(stmt) if !stmt.is_directive() => Some(stmt),
183+
ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt),
174184
_ => None,
175185
}));
176186

‎crates/swc_ecma_transforms_module/src/common_js.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ use crate::{
1616
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
1717
path::{ImportResolver, Resolver},
1818
util::{
19-
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
20-
prop_name, use_strict, ImportInterop, ObjPropKeyIdent,
19+
define_es_module, emit_export_stmts, local_name_for_src, prop_name, use_strict,
20+
ImportInterop, ObjPropKeyIdent, VecStmtLike,
2121
},
2222
};
2323

@@ -113,15 +113,18 @@ where
113113

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

116-
stmts.extend(clone_first_use_directive(&n.body, false).map(From::from));
116+
// Collect directives
117+
stmts.extend(
118+
&mut n
119+
.body
120+
.iter_mut()
121+
.take_while(|i| i.directive_continue())
122+
.map(|i| i.take()),
123+
);
117124

118125
// "use strict";
119-
if self.config.strict_mode {
120-
stmts.push(
121-
clone_first_use_directive(&n.body, true)
122-
.unwrap_or_else(use_strict)
123-
.into(),
124-
);
126+
if self.config.strict_mode && !stmts.has_use_strict() {
127+
stmts.push(use_strict().into());
125128
}
126129

127130
let ModuleDeclStrip {
@@ -156,7 +159,7 @@ where
156159
);
157160

158161
stmts.extend(n.body.take().into_iter().filter(|item| match item {
159-
ModuleItem::Stmt(stmt) => !stmt.is_directive(),
162+
ModuleItem::Stmt(stmt) => !stmt.is_empty(),
160163
_ => false,
161164
}));
162165

‎crates/swc_ecma_transforms_module/src/umd.rs

+14-5
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ use crate::{
1717
module_ref_rewriter::{ImportMap, ModuleRefRewriter},
1818
path::{ImportResolver, Resolver},
1919
util::{
20-
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src,
21-
use_strict, ImportInterop,
20+
define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
21+
VecStmtLike,
2222
},
2323
};
2424

@@ -116,9 +116,18 @@ where
116116

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

119+
// Collect directives
120+
stmts.extend(
121+
module_items
122+
.iter_mut()
123+
.take_while(|i| i.directive_continue())
124+
.map(|i| i.take())
125+
.map(ModuleItem::expect_stmt),
126+
);
127+
119128
// "use strict";
120-
if self.config.config.strict_mode {
121-
stmts.push(clone_first_use_directive(module_items, true).unwrap_or_else(use_strict));
129+
if self.config.config.strict_mode && !stmts.has_use_strict() {
130+
stmts.push(use_strict());
122131
}
123132

124133
let ModuleDeclStrip {
@@ -143,7 +152,7 @@ where
143152
);
144153

145154
stmts.extend(module_items.take().into_iter().filter_map(|i| match i {
146-
ModuleItem::Stmt(stmt) if !stmt.is_directive() => Some(stmt),
155+
ModuleItem::Stmt(stmt) if !stmt.is_empty() => Some(stmt),
147156
_ => None,
148157
}));
149158

‎crates/swc_ecma_transforms_module/src/util.rs

+25-18
Original file line numberDiff line numberDiff line change
@@ -194,26 +194,33 @@ pub(super) fn define_es_module(exports: Ident) -> Stmt {
194194
.into_stmt()
195195
}
196196

197-
pub(super) fn clone_first_use_directive(
198-
stmts: &[ModuleItem],
199-
want_use_strict: bool,
200-
) -> Option<Stmt> {
201-
if stmts.is_empty() {
202-
return None;
197+
pub(super) trait VecStmtLike {
198+
type StmtLike: IsDirective;
199+
200+
fn as_ref(&self) -> &[Self::StmtLike];
201+
202+
fn has_use_strict(&self) -> bool {
203+
self.as_ref()
204+
.iter()
205+
.take_while(|s| s.directive_continue())
206+
.any(IsDirective::is_use_strict)
203207
}
208+
}
204209

205-
stmts.iter().find_map(|item| match item {
206-
ModuleItem::Stmt(stmt) => {
207-
if (want_use_strict && stmt.is_use_strict())
208-
|| (!want_use_strict && !stmt.is_use_strict() && stmt.is_directive())
209-
{
210-
Some(stmt.clone())
211-
} else {
212-
None
213-
}
214-
}
215-
_ => None,
216-
})
210+
impl VecStmtLike for [ModuleItem] {
211+
type StmtLike = ModuleItem;
212+
213+
fn as_ref(&self) -> &[Self::StmtLike] {
214+
self
215+
}
216+
}
217+
218+
impl VecStmtLike for [Stmt] {
219+
type StmtLike = Stmt;
220+
221+
fn as_ref(&self) -> &[Self::StmtLike] {
222+
self
223+
}
217224
}
218225

219226
pub(super) fn use_strict() -> Stmt {

‎crates/swc_ecma_transforms_module/tests/fixture/common/issue-7315/output.amd.js

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ define([
33
"require",
44
"exports"
55
], function(require, exports) {
6+
"use client";
67
"use strict";
78
Object.defineProperty(exports, "__esModule", {
89
value: true

‎crates/swc_ecma_transforms_module/tests/fixture/common/issue-7315/output.umd.js

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
], factory);
77
else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {});
88
})(this, function(exports) {
9+
"use client";
910
"use strict";
1011
Object.defineProperty(exports, "__esModule", {
1112
value: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
"use client";
2+
3+
"foo";
4+
5+
"use bar";
6+
7+
"use strict";
8+
// All above are directives
9+
10+
function foo() { }
11+
12+
"use hello"; // This is not directive
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
define([
2+
"require"
3+
], function(require) {
4+
"use client";
5+
"foo";
6+
"use bar";
7+
"use strict";
8+
// All above are directives
9+
function foo() {}
10+
"use hello"; // This is not directive
11+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"use client";
2+
"foo";
3+
"use bar";
4+
"use strict";
5+
// All above are directives
6+
function foo() {}
7+
"use hello"; // This is not directive
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
(function(global, factory) {
2+
if (typeof module === "object" && typeof module.exports === "object") factory();
3+
else if (typeof define === "function" && define.amd) define([], factory);
4+
else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory();
5+
})(this, function() {
6+
"use client";
7+
"foo";
8+
"use bar";
9+
"use strict";
10+
// All above are directives
11+
function foo() {}
12+
"use hello"; // This is not directive
13+
});

‎crates/swc_ecma_utils/src/lib.rs

+22
Original file line numberDiff line numberDiff line change
@@ -2262,6 +2262,7 @@ pub fn prepend_stmts<T: StmtLike>(
22622262

22632263
pub trait IsDirective {
22642264
fn as_ref(&self) -> Option<&Stmt>;
2265+
#[deprecated(note = "use directive_continue instead")]
22652266
fn is_directive(&self) -> bool {
22662267
match self.as_ref() {
22672268
Some(Stmt::Expr(expr)) => match &*expr.expr {
@@ -2273,6 +2274,15 @@ pub trait IsDirective {
22732274
_ => false,
22742275
}
22752276
}
2277+
fn directive_continue(&self) -> bool {
2278+
match self.as_ref() {
2279+
Some(Stmt::Expr(expr)) => match &*expr.expr {
2280+
Expr::Lit(Lit::Str(..)) => true,
2281+
_ => false,
2282+
},
2283+
_ => false,
2284+
}
2285+
}
22762286
fn is_use_strict(&self) -> bool {
22772287
match self.as_ref() {
22782288
Some(Stmt::Expr(expr)) => match *expr.expr {
@@ -2292,6 +2302,18 @@ impl IsDirective for Stmt {
22922302
}
22932303
}
22942304

2305+
impl IsDirective for ModuleItem {
2306+
fn as_ref(&self) -> Option<&Stmt> {
2307+
self.as_stmt()
2308+
}
2309+
}
2310+
2311+
impl IsDirective for &ModuleItem {
2312+
fn as_ref(&self) -> Option<&Stmt> {
2313+
self.as_stmt()
2314+
}
2315+
}
2316+
22952317
pub trait IdentExt {
22962318
fn prefix(&self, prefix: &str) -> Ident;
22972319

0 commit comments

Comments
 (0)
Failed to load comments.