fix(es/module): Handle directives (#8048)

**Related issue:**

 - Closes: #8047
This commit is contained in:
magic-akari 2023-10-02 11:44:05 -05:00 committed by GitHub
parent 0c8d8a3f4a
commit 4d8e1013bb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 135 additions and 39 deletions

View File

@ -20,8 +20,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter}, module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver}, path::{ImportResolver, Resolver},
util::{ util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src, define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
use_strict, ImportInterop, VecStmtLike,
}, },
}; };
@ -143,9 +143,19 @@ where
let mut stmts: Vec<Stmt> = Vec::with_capacity(n.body.len() + 4); 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"; // "use strict";
if self.config.strict_mode { if self.config.strict_mode && !stmts.has_use_strict() {
stmts.push(clone_first_use_directive(&n.body, true).unwrap_or_else(use_strict)); stmts.push(use_strict());
} }
let ModuleDeclStrip { let ModuleDeclStrip {
@ -170,7 +180,7 @@ where
); );
stmts.extend(n.body.take().into_iter().filter_map(|item| match item { 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, _ => None,
})); }));

View File

@ -16,8 +16,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter}, module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver}, path::{ImportResolver, Resolver},
util::{ util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src, define_es_module, emit_export_stmts, local_name_for_src, prop_name, use_strict,
prop_name, use_strict, ImportInterop, ObjPropKeyIdent, ImportInterop, ObjPropKeyIdent, VecStmtLike,
}, },
}; };
@ -113,15 +113,18 @@ where
let mut stmts: Vec<ModuleItem> = Vec::with_capacity(n.body.len() + 6); 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"; // "use strict";
if self.config.strict_mode { if self.config.strict_mode && !stmts.has_use_strict() {
stmts.push( stmts.push(use_strict().into());
clone_first_use_directive(&n.body, true)
.unwrap_or_else(use_strict)
.into(),
);
} }
let ModuleDeclStrip { let ModuleDeclStrip {
@ -156,7 +159,7 @@ where
); );
stmts.extend(n.body.take().into_iter().filter(|item| match item { stmts.extend(n.body.take().into_iter().filter(|item| match item {
ModuleItem::Stmt(stmt) => !stmt.is_directive(), ModuleItem::Stmt(stmt) => !stmt.is_empty(),
_ => false, _ => false,
})); }));

View File

@ -17,8 +17,8 @@ use crate::{
module_ref_rewriter::{ImportMap, ModuleRefRewriter}, module_ref_rewriter::{ImportMap, ModuleRefRewriter},
path::{ImportResolver, Resolver}, path::{ImportResolver, Resolver},
util::{ util::{
clone_first_use_directive, define_es_module, emit_export_stmts, local_name_for_src, define_es_module, emit_export_stmts, local_name_for_src, use_strict, ImportInterop,
use_strict, ImportInterop, VecStmtLike,
}, },
}; };
@ -116,9 +116,18 @@ where
let mut stmts: Vec<Stmt> = Vec::with_capacity(module_items.len() + 4); 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"; // "use strict";
if self.config.config.strict_mode { if self.config.config.strict_mode && !stmts.has_use_strict() {
stmts.push(clone_first_use_directive(module_items, true).unwrap_or_else(use_strict)); stmts.push(use_strict());
} }
let ModuleDeclStrip { let ModuleDeclStrip {
@ -143,7 +152,7 @@ where
); );
stmts.extend(module_items.take().into_iter().filter_map(|i| match i { 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, _ => None,
})); }));

View File

@ -194,26 +194,33 @@ pub(super) fn define_es_module(exports: Ident) -> Stmt {
.into_stmt() .into_stmt()
} }
pub(super) fn clone_first_use_directive( pub(super) trait VecStmtLike {
stmts: &[ModuleItem], type StmtLike: IsDirective;
want_use_strict: bool,
) -> Option<Stmt> { fn as_ref(&self) -> &[Self::StmtLike];
if stmts.is_empty() {
return None; 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 { impl VecStmtLike for [ModuleItem] {
ModuleItem::Stmt(stmt) => { type StmtLike = ModuleItem;
if (want_use_strict && stmt.is_use_strict())
|| (!want_use_strict && !stmt.is_use_strict() && stmt.is_directive()) fn as_ref(&self) -> &[Self::StmtLike] {
{ self
Some(stmt.clone())
} else {
None
} }
} }
_ => None,
}) impl VecStmtLike for [Stmt] {
type StmtLike = Stmt;
fn as_ref(&self) -> &[Self::StmtLike] {
self
}
} }
pub(super) fn use_strict() -> Stmt { pub(super) fn use_strict() -> Stmt {

View File

@ -3,6 +3,7 @@ define([
"require", "require",
"exports" "exports"
], function(require, exports) { ], function(require, exports) {
"use client";
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true

View File

@ -6,6 +6,7 @@
], factory); ], factory);
else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {}); else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {});
})(this, function(exports) { })(this, function(exports) {
"use client";
"use strict"; "use strict";
Object.defineProperty(exports, "__esModule", { Object.defineProperty(exports, "__esModule", {
value: true value: true

View File

@ -0,0 +1,12 @@
"use client";
"foo";
"use bar";
"use strict";
// All above are directives
function foo() { }
"use hello"; // This is not directive

View File

@ -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
});

View File

@ -0,0 +1,7 @@
"use client";
"foo";
"use bar";
"use strict";
// All above are directives
function foo() {}
"use hello"; // This is not directive

View File

@ -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
});

View File

@ -2262,6 +2262,7 @@ pub fn prepend_stmts<T: StmtLike>(
pub trait IsDirective { pub trait IsDirective {
fn as_ref(&self) -> Option<&Stmt>; fn as_ref(&self) -> Option<&Stmt>;
#[deprecated(note = "use directive_continue instead")]
fn is_directive(&self) -> bool { fn is_directive(&self) -> bool {
match self.as_ref() { match self.as_ref() {
Some(Stmt::Expr(expr)) => match &*expr.expr { Some(Stmt::Expr(expr)) => match &*expr.expr {
@ -2273,6 +2274,15 @@ pub trait IsDirective {
_ => false, _ => 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 { fn is_use_strict(&self) -> bool {
match self.as_ref() { match self.as_ref() {
Some(Stmt::Expr(expr)) => match *expr.expr { Some(Stmt::Expr(expr)) => match *expr.expr {
@ -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 { pub trait IdentExt {
fn prefix(&self, prefix: &str) -> Ident; fn prefix(&self, prefix: &str) -> Ident;