From 95236e9abe546c455222a775f9648e82543dfaed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Donny/=EA=B0=95=EB=8F=99=EC=9C=A4?= Date: Thu, 8 Feb 2024 00:01:58 +0900 Subject: [PATCH] fix(es/parser): Fix detection of `use strict` directive (#8617) **Description:** Directives should be at the start of the file, and this PR changes the parser to match only at the start of a file. **Related issue:** - Closes #8616. --- .../tests/fixture/issues-8xxx/8616/input/1.js | 18 +++++++++++++ .../fixture/issues-8xxx/8616/output/1.js | 19 ++++++++++++++ crates/swc_ecma_ast/src/stmt.rs | 25 ++++++++++++++++++- .../swc_ecma_compat_es2015/src/classes/mod.rs | 2 +- .../src/parser/class_and_fn.rs | 17 +++++++++---- crates/swc_ecma_parser/src/parser/stmt.rs | 10 +------- .../src/resolver/mod.rs | 2 +- crates/swc_ecma_utils/src/lib.rs | 18 ++----------- 8 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 crates/swc/tests/fixture/issues-8xxx/8616/input/1.js create mode 100644 crates/swc/tests/fixture/issues-8xxx/8616/output/1.js diff --git a/crates/swc/tests/fixture/issues-8xxx/8616/input/1.js b/crates/swc/tests/fixture/issues-8xxx/8616/input/1.js new file mode 100644 index 000000000000..f8cb7cb12af1 --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8616/input/1.js @@ -0,0 +1,18 @@ + +var Module = (() => { + var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== 'undefined') _scriptDir ||= __filename; + return ( + function (moduleArg = {}) { + var Module = moduleArg; + var readyPromiseResolve, readyPromiseReject; Module["ready"] = new Promise((resolve, reject) => { readyPromiseResolve = resolve; readyPromiseReject = reject }); "use strict"; + + + return moduleArg + } + ); +})()(); +if (typeof exports === 'object' && typeof module === 'object') + module.exports = Module; +else if (typeof define === 'function' && define['amd']) + define([], () => Module); \ No newline at end of file diff --git a/crates/swc/tests/fixture/issues-8xxx/8616/output/1.js b/crates/swc/tests/fixture/issues-8xxx/8616/output/1.js new file mode 100644 index 000000000000..40ac5c41be4f --- /dev/null +++ b/crates/swc/tests/fixture/issues-8xxx/8616/output/1.js @@ -0,0 +1,19 @@ +var Module = (function() { + var _scriptDir = typeof document !== "undefined" && document.currentScript ? document.currentScript.src : undefined; + if (typeof __filename !== "undefined") _scriptDir || (_scriptDir = __filename); + return function() { + var moduleArg = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}; + var Module = moduleArg; + var readyPromiseResolve, readyPromiseReject; + Module["ready"] = new Promise(function(resolve, reject) { + readyPromiseResolve = resolve; + readyPromiseReject = reject; + }); + "use strict"; + return moduleArg; + }; +})()(); +if (typeof exports === "object" && typeof module === "object") module.exports = Module; +else if (typeof define === "function" && define["amd"]) define([], function() { + return Module; +}); diff --git a/crates/swc_ecma_ast/src/stmt.rs b/crates/swc_ecma_ast/src/stmt.rs index fc68f1759e85..a93f265e174c 100644 --- a/crates/swc_ecma_ast/src/stmt.rs +++ b/crates/swc_ecma_ast/src/stmt.rs @@ -6,7 +6,7 @@ use crate::{ expr::Expr, ident::Ident, pat::Pat, - UsingDecl, + Lit, Str, UsingDecl, }; /// Use when only block statements are allowed. @@ -106,6 +106,29 @@ pub enum Stmt { Expr(ExprStmt), } +impl Stmt { + pub fn is_use_strict(&self) -> bool { + match self { + Stmt::Expr(expr) => match *expr.expr { + Expr::Lit(Lit::Str(Str { ref raw, .. })) => { + matches!(raw, Some(value) if value == "\"use strict\"" || value == "'use strict'") + } + _ => false, + }, + _ => false, + } + } + + /// Returns true if the statement does not prevent the directives below + /// `self` from being directives. + pub fn can_precede_directive(&self) -> bool { + match self { + Stmt::Expr(expr) => matches!(*expr.expr, Expr::Lit(Lit::Str(_))), + _ => false, + } + } +} + // Memory layout depedns on the version of rustc. // #[cfg(target_pointer_width = "64")] // assert_eq_size!(Stmt, [u8; 56]); diff --git a/crates/swc_ecma_compat_es2015/src/classes/mod.rs b/crates/swc_ecma_compat_es2015/src/classes/mod.rs index c8336f70967c..d3f6de1e8dda 100644 --- a/crates/swc_ecma_compat_es2015/src/classes/mod.rs +++ b/crates/swc_ecma_compat_es2015/src/classes/mod.rs @@ -12,7 +12,7 @@ use swc_ecma_transforms_macros::fast_path; use swc_ecma_utils::{ alias_if_required, contains_this_expr, default_constructor, is_valid_ident, is_valid_prop_ident, prepend_stmt, private_ident, prop_name_to_expr, quote_expr, quote_ident, - quote_str, replace_ident, ExprFactory, IdentExt, IsDirective, ModuleItemLike, StmtLike, + quote_str, replace_ident, ExprFactory, IdentExt, ModuleItemLike, StmtLike, }; use swc_ecma_visit::{ as_folder, noop_visit_mut_type, noop_visit_type, Fold, Visit, VisitMut, VisitMutWith, VisitWith, diff --git a/crates/swc_ecma_parser/src/parser/class_and_fn.rs b/crates/swc_ecma_parser/src/parser/class_and_fn.rs index 798ced9a6286..e0edb1ebc339 100644 --- a/crates/swc_ecma_parser/src/parser/class_and_fn.rs +++ b/crates/swc_ecma_parser/src/parser/class_and_fn.rs @@ -1,7 +1,7 @@ use swc_common::{Spanned, SyntaxContext}; use super::*; -use crate::{error::SyntaxError, lexer::TokenContext, parser::stmt::IsDirective, Tokens}; +use crate::{error::SyntaxError, lexer::TokenContext, Tokens}; /// Parser for function expression and function declaration. impl Parser { @@ -1615,10 +1615,17 @@ pub(super) trait FnBodyParser { fn parse_fn_body_inner(&mut self, is_simple_parameter_list: bool) -> PResult; } fn has_use_strict(block: &BlockStmt) -> Option { - match block.stmts.iter().find(|stmt| stmt.is_use_strict()) { - Some(Stmt::Expr(ExprStmt { span, expr: _ })) => Some(*span), - _ => None, - } + block + .stmts + .iter() + .take_while(|s| s.can_precede_directive()) + .find_map(|s| { + if s.is_use_strict() { + Some(s.span()) + } else { + None + } + }) } impl FnBodyParser> for Parser { fn parse_fn_body_inner( diff --git a/crates/swc_ecma_parser/src/parser/stmt.rs b/crates/swc_ecma_parser/src/parser/stmt.rs index 0e4c3246161d..0564527bf210 100644 --- a/crates/swc_ecma_parser/src/parser/stmt.rs +++ b/crates/swc_ecma_parser/src/parser/stmt.rs @@ -1394,15 +1394,7 @@ enum TempForHead { pub(super) trait IsDirective { fn as_ref(&self) -> Option<&Stmt>; fn is_use_strict(&self) -> bool { - match self.as_ref() { - Some(Stmt::Expr(expr)) => match *expr.expr { - Expr::Lit(Lit::Str(Str { ref raw, .. })) => { - matches!(raw, Some(value) if value == "\"use strict\"" || value == "'use strict'") - } - _ => false, - }, - _ => false, - } + self.as_ref().map_or(false, Stmt::is_use_strict) } } diff --git a/crates/swc_ecma_transforms_base/src/resolver/mod.rs b/crates/swc_ecma_transforms_base/src/resolver/mod.rs index c109096468a6..ee704fb36ae0 100644 --- a/crates/swc_ecma_transforms_base/src/resolver/mod.rs +++ b/crates/swc_ecma_transforms_base/src/resolver/mod.rs @@ -5,7 +5,7 @@ use swc_common::{ Mark, Span, SyntaxContext, }; use swc_ecma_ast::*; -use swc_ecma_utils::{find_pat_ids, IsDirective}; +use swc_ecma_utils::find_pat_ids; use swc_ecma_visit::{ as_folder, noop_visit_mut_type, visit_mut_obj_and_computed, Fold, VisitMut, VisitMutWith, }; diff --git a/crates/swc_ecma_utils/src/lib.rs b/crates/swc_ecma_utils/src/lib.rs index 8bde4f1edcaf..5c4b16423bcf 100644 --- a/crates/swc_ecma_utils/src/lib.rs +++ b/crates/swc_ecma_utils/src/lib.rs @@ -2306,24 +2306,10 @@ pub trait IsDirective { } } fn directive_continue(&self) -> bool { - match self.as_ref() { - Some(Stmt::Expr(expr)) => match &*expr.expr { - Expr::Lit(Lit::Str(..)) => true, - _ => false, - }, - _ => false, - } + self.as_ref().map_or(false, Stmt::can_precede_directive) } fn is_use_strict(&self) -> bool { - match self.as_ref() { - Some(Stmt::Expr(expr)) => match *expr.expr { - Expr::Lit(Lit::Str(Str { ref raw, .. })) => { - matches!(raw, Some(value) if value == "\"use strict\"" || value == "'use strict'") - } - _ => false, - }, - _ => false, - } + self.as_ref().map_or(false, Stmt::is_use_strict) } }