diff --git a/CLAUDE.md b/CLAUDE.md index a66314ecc02e..f2022078578d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,3 +6,4 @@ 6. When instructed to fix tests, do not remove or modify existing tests. 7. Write documentation for your code. 8. Run `cargo fmt --all` before commiting files. +9. Place all import statements at the top of the file for consistency. Do not use inline `use` statements within functions or impl blocks. diff --git a/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.js b/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.js index bfdac51518e2..4b652f6e1e7b 100644 --- a/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.js +++ b/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.js @@ -1,7 +1,7 @@ -(void 0).setStatus({message:`${(void 0).message} ${(void 0).code?` +let e;(void 0).setStatus({message:`${e.message} ${e.code?` Mon go os e Error C od -e: ${(void 0).code}`:"1\n23"}`}); +e: ${e.code}`:"1\n23"}`}); diff --git a/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.map b/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.map index c57344de4dc3..846fe9fabae5 100644 --- a/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.map +++ b/crates/swc/tests/fixture/sourcemap/issue-9567/output/index.map @@ -1,10 +1,10 @@ { - "mappings": "AAAaA,CAAAA,KAAAA,CAAG,EACTC,SAAS,CAAC,CACXC,QAAS,CAAC,EAAEC,AAFCA,CAAAA,KAAAA,CAAI,EAECD,OAAO,CAAC,CAAC,EACvBC,AAHSA,CAAAA,KAAAA,CAAI,EAGPC,IAAI,CACJ;AAAG;AAAS;AAC5B;AAAS;AACT;AAAI,GAAG,EAAED,AANUA,CAAAA,KAAAA,CAAI,EAMRC,IAAI,CAAC,CAAC,CACL,QACT,CAAC,AACN", + "mappings": "IAAmBA,EACjBC,SAAKC,SAAS,CAAC,CACXC,QAAS,CAAC,EAAEH,EAAMG,OAAO,CAAC,CAAC,EACvBH,EAAMI,IAAI,CACJ;AAAG;AAAS;AAC5B;AAAS;AACT;AAAI,GAAG,EAAEJ,EAAMI,IAAI,CAAC,CAAC,CACL,QACT,CAAC,AACN", "names": [ + "error", "span", "setStatus", "message", - "error", "code" ], "sources": [ diff --git a/crates/swc/tests/tsc-references/typeFromPropertyAssignment36.2.minified.js b/crates/swc/tests/tsc-references/typeFromPropertyAssignment36.2.minified.js index 39f3e283ce2e..ee6fe9b3e717 100644 --- a/crates/swc/tests/tsc-references/typeFromPropertyAssignment36.2.minified.js +++ b/crates/swc/tests/tsc-references/typeFromPropertyAssignment36.2.minified.js @@ -1,8 +1,8 @@ //// [typeFromPropertyAssignment36.ts] function d() {} -(function(b) { +(function() { function d() {} - return d.e = 12, d.e, b && (d.q = !1), d.q, b ? d.q = !1 : d.q = !0, d.q, b ? d.r = 1 : d.r = 2, d.r, b && (d.s = 'hi'), d; + return d.e = 12, d.e, d.q = !1, d.q, d.q = !1, d.q, d.r = 1, d.r, d.s = 'hi', d; })(!0).s, d.e = 12, d.e, d.q, d.q = !0, d.q, d.r = 2, d.r; var g = function() {}; g.expando, g.both = 0, g.both; diff --git a/crates/swc/tests/vercel/full/firebase/dist/1/output/index.js b/crates/swc/tests/vercel/full/firebase/dist/1/output/index.js index 60a74d7871d0..2423ce91314f 100644 --- a/crates/swc/tests/vercel/full/firebase/dist/1/output/index.js +++ b/crates/swc/tests/vercel/full/firebase/dist/1/output/index.js @@ -1,4 +1,5 @@ -var e, t = require("@firebase/util"), n = require("tslib"), r = require("@firebase/component"), i = require("@firebase/app"), a = require("@firebase/logger"), o = function(e) { +let e; +var t, n = require("@firebase/util"), r = require("tslib"), i = require("@firebase/component"), a = require("@firebase/app"), o = require("@firebase/logger"), p = function(e) { if (e && e.__esModule) return e; var t = Object.create(null); return e && Object.keys(e).forEach(function(n) { @@ -12,10 +13,10 @@ var e, t = require("@firebase/util"), n = require("tslib"), r = require("@fireba }); } }), t.default = e, Object.freeze(t); -}(i), p = function() { +}(a), s = function() { function e(e, t) { var n = this; - this._delegate = e, this.firebase = t, i._addComponent(e, new r.Component("app-compat", function() { + this._delegate = e, this.firebase = t, a._addComponent(e, new i.Component("app-compat", function() { return n; }, "PUBLIC")), this.container = e.container; } @@ -45,20 +46,20 @@ var e, t = require("@firebase/util"), n = require("tslib"), r = require("@fireba return new Promise(function(t) { e._delegate.checkDestroyed(), t(); }).then(function() { - return e.firebase.INTERNAL.removeApp(e.name), i.deleteApp(e._delegate); + return e.firebase.INTERNAL.removeApp(e.name), a.deleteApp(e._delegate); }); }, e.prototype._getService = function(e, t) { - void 0 === t && (t = i._DEFAULT_ENTRY_NAME), this._delegate.checkDestroyed(); + void 0 === t && (t = a._DEFAULT_ENTRY_NAME), this._delegate.checkDestroyed(); var n, r = this._delegate.container.getProvider(e); return r.isInitialized() || (null == (n = r.getComponent()) ? void 0 : n.instantiationMode) !== "EXPLICIT" || r.initialize(), r.getImmediate({ identifier: t }); }, e.prototype._removeServiceInstance = function(e, t) { - void 0 === t && (t = i._DEFAULT_ENTRY_NAME), this._delegate.container.getProvider(e).clearInstance(t); + void 0 === t && (t = a._DEFAULT_ENTRY_NAME), this._delegate.container.getProvider(e).clearInstance(t); }, e.prototype._addComponent = function(e) { - i._addComponent(this._delegate, e); + a._addComponent(this._delegate, e); }, e.prototype._addOrOverwriteComponent = function(e) { - i._addOrOverwriteComponent(this._delegate, e); + a._addOrOverwriteComponent(this._delegate, e); }, e.prototype.toJSON = function() { return { name: this.name, @@ -66,76 +67,76 @@ var e, t = require("@firebase/util"), n = require("tslib"), r = require("@fireba options: this.options }; }, e; -}(), s = ((e = {})["no-app"] = "No Firebase App '{$appName}' has been created - call Firebase App.initializeApp()", e["invalid-app-argument"] = "firebase.{$appName}() takes either no argument or a Firebase App instance.", e), c = new t.ErrorFactory("app-compat", "Firebase", s), u = function e() { - var r = function(e) { - var n = {}, r = { +}(), c = ((t = {})["no-app"] = "No Firebase App '{$appName}' has been created - call Firebase App.initializeApp()", t["invalid-app-argument"] = "firebase.{$appName}() takes either no argument or a Firebase App instance.", t), u = new n.ErrorFactory("app-compat", "Firebase", c), l = function e() { + var t = function(e) { + var t = {}, r = { __esModule: !0, initializeApp: function(i, a) { void 0 === a && (a = {}); - var p = o.initializeApp(i, a); - if (t.contains(n, p.name)) return n[p.name]; - var s = new e(p, r); - return n[p.name] = s, s; + var o = p.initializeApp(i, a); + if (n.contains(t, o.name)) return t[o.name]; + var s = new e(o, r); + return t[o.name] = s, s; }, app: i, - registerVersion: o.registerVersion, - setLogLevel: o.setLogLevel, - onLog: o.onLog, + registerVersion: p.registerVersion, + setLogLevel: p.setLogLevel, + onLog: p.onLog, apps: null, - SDK_VERSION: o.SDK_VERSION, + SDK_VERSION: p.SDK_VERSION, INTERNAL: { - registerComponent: function(n) { - var a = n.name, p = a.replace("-compat", ""); - if (o._registerComponent(n) && "PUBLIC" === n.type) { + registerComponent: function(t) { + var a = t.name, o = a.replace("-compat", ""); + if (p._registerComponent(t) && "PUBLIC" === t.type) { var s = function(e) { - if (void 0 === e && (e = i()), "function" != typeof e[p]) throw c.create("invalid-app-argument", { + if (void 0 === e && (e = i()), "function" != typeof e[o]) throw u.create("invalid-app-argument", { appName: a }); - return e[p](); + return e[o](); }; - void 0 !== n.serviceProps && t.deepExtend(s, n.serviceProps), r[p] = s, e.prototype[p] = function() { - for(var e = [], t = 0; t < arguments.length; t++)e[t] = arguments[t]; - return this._getService.bind(this, a).apply(this, n.multipleInstances ? e : []); + void 0 !== t.serviceProps && n.deepExtend(s, t.serviceProps), r[o] = s, e.prototype[o] = function() { + for(var e = [], n = 0; n < arguments.length; n++)e[n] = arguments[n]; + return this._getService.bind(this, a).apply(this, t.multipleInstances ? e : []); }; } - return "PUBLIC" === n.type ? r[p] : null; + return "PUBLIC" === t.type ? r[o] : null; }, removeApp: function(e) { - delete n[e]; + delete t[e]; }, useAsService: function(e, t) { return "serverAuth" === t ? null : t; }, - modularAPIs: o + modularAPIs: p } }; function i(e) { - if (e = e || o._DEFAULT_ENTRY_NAME, !t.contains(n, e)) throw c.create("no-app", { + if (e = e || p._DEFAULT_ENTRY_NAME, !n.contains(t, e)) throw u.create("no-app", { appName: e }); - return n[e]; + return t[e]; } return r.default = r, Object.defineProperty(r, "apps", { get: function() { - return Object.keys(n).map(function(e) { - return n[e]; + return Object.keys(t).map(function(e) { + return t[e]; }); } }), i.App = e, r; - }(p); - return r.INTERNAL = n.__assign(n.__assign({}, r.INTERNAL), { + }(s); + return t.INTERNAL = r.__assign(r.__assign({}, t.INTERNAL), { createFirebaseNamespace: e, extendNamespace: function(e) { - t.deepExtend(r, e); + n.deepExtend(t, e); }, - createSubscribe: t.createSubscribe, - ErrorFactory: t.ErrorFactory, - deepExtend: t.deepExtend - }), r; -}(), l = new a.Logger("@firebase/app-compat"); -if (t.isBrowser() && void 0 !== self.firebase) { - l.warn("\n Warning: Firebase is already defined in the global scope. Please make sure\n Firebase library is only loaded once.\n "); - var d = self.firebase.SDK_VERSION; - d && d.indexOf("LITE") >= 0 && l.warn("\n Warning: You are trying to load Firebase while using Firebase Performance standalone script.\n You should load Firebase Performance with this instance of Firebase to avoid loading duplicate code.\n "); + createSubscribe: n.createSubscribe, + ErrorFactory: n.ErrorFactory, + deepExtend: n.deepExtend + }), t; +}(), d = new o.Logger("@firebase/app-compat"); +if (n.isBrowser() && void 0 !== self.firebase) { + d.warn("\n Warning: Firebase is already defined in the global scope. Please make sure\n Firebase library is only loaded once.\n "); + var f = self.firebase.SDK_VERSION; + f && f.indexOf("LITE") >= 0 && d.warn("\n Warning: You are trying to load Firebase while using Firebase Performance standalone script.\n You should load Firebase Performance with this instance of Firebase to avoid loading duplicate code.\n "); } -i.registerVersion("@firebase/app-compat", "0.1.5", void 0), module.exports = u; +a.registerVersion("@firebase/app-compat", "0.1.5", e), module.exports = l; diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index 87bd81052933..24379707c395 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -46,6 +46,7 @@ mod iife; mod inline; mod loops; mod ops; +mod params; mod props; mod rest_params; mod sequences; @@ -91,6 +92,7 @@ pub(super) fn optimizer<'a>( ctx, mode, functions: Default::default(), + inlined_params: Default::default(), } } @@ -240,6 +242,11 @@ struct Optimizer<'a> { mode: &'a dyn Mode, functions: Box>, + + /// Tracks which parameter indices have been inlined for each function. + /// Maps function ID to a sorted vector of parameter indices that were + /// removed. + inlined_params: Box>>, } #[derive(Default)] @@ -1683,6 +1690,9 @@ impl VisitMut for Optimizer<'_> { self.ignore_unused_args_of_iife(e); self.inline_args_of_iife(e); + + // Remove arguments for parameters that have been inlined + self.remove_inlined_call_args(e); } #[cfg_attr(feature = "debug", tracing::instrument(level = "debug", skip_all))] @@ -2094,6 +2104,9 @@ impl VisitMut for Optimizer<'_> { self.drop_unused_params(&mut f.function.params); + // Inline parameters that are consistently passed the same constant value + self.inline_function_parameters(&mut f.function, &f.ident.to_id()); + let ctx = self .ctx .clone() @@ -2110,6 +2123,9 @@ impl VisitMut for Optimizer<'_> { self.functions .entry(ident.to_id()) .or_insert_with(|| FnMetadata::from(&*e.function)); + + // Inline parameters for named function expressions + self.inline_function_parameters(&mut e.function, &ident.to_id()); } if !self.options.keep_fnames { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/params.rs b/crates/swc_ecma_minifier/src/compress/optimize/params.rs new file mode 100644 index 000000000000..6da5edaa4fa0 --- /dev/null +++ b/crates/swc_ecma_minifier/src/compress/optimize/params.rs @@ -0,0 +1,592 @@ +use swc_common::DUMMY_SP; +use swc_ecma_ast::*; + +use super::Optimizer; +use crate::program_data::{ScopeData, VarUsageInfoFlags}; + +/// Methods related to parameter inlining optimization. +impl Optimizer<'_> { + /// Inline function parameters that are consistently passed the same + /// constant value. + /// + /// This optimization identifies function parameters where all call sites + /// pass the same constant value (including implicit undefined), and + /// transforms the function to use a variable declaration instead. + /// + /// Example: + /// ```js + /// function complex(foo, fn) { + /// if (Math.random() > 0.5) throw new Error(); + /// return fn?.(foo); + /// } + /// complex("foo"); + /// complex("bar"); + /// complex("baz"); + /// ``` + /// => + /// ```js + /// function complex(foo) { + /// const fn = undefined; // const if not reassigned, let otherwise + /// if (Math.random() > 0.5) throw new Error(); + /// return fn?.(foo); + /// } + /// complex("foo"); + /// complex("bar"); + /// complex("baz"); + /// ``` + pub(super) fn inline_function_parameters(&mut self, f: &mut Function, fn_id: &Id) { + // Skip if optimization is disabled + if self.options.inline == 0 && !self.options.reduce_vars { + return; + } + + // Skip if function uses eval or with statement + if let Some(scope_data) = self.data.scopes.get(&f.ctxt) { + if scope_data.intersects(ScopeData::HAS_EVAL_CALL | ScopeData::HAS_WITH_STMT) { + return; + } + } + + // Skip if function uses arguments object + if let Some(scope_data) = self.data.scopes.get(&f.ctxt) { + if scope_data.contains(ScopeData::USED_ARGUMENTS) { + return; + } + } + + // Get usage info for the function + let usage = match self.data.vars.get(fn_id) { + Some(u) => u, + None => return, + }; + + // Skip if function is exported, reassigned, or inlining is prevented + if usage.flags.contains(VarUsageInfoFlags::EXPORTED) + || usage.flags.contains(VarUsageInfoFlags::INLINE_PREVENTED) + || usage.flags.contains(VarUsageInfoFlags::REASSIGNED) + { + return; + } + + // Skip if function is used as a reference/argument (not just called) + // Check if the function is used in ways other than being called directly + // USED_AS_ARG indicates the function is passed to another function, which means + // we don't have visibility into all call sites + if usage.flags.contains(VarUsageInfoFlags::USED_AS_ARG) { + return; + } + + // Get call site arguments + let call_sites = match &usage.call_site_args { + Some(sites) if !sites.is_empty() => sites, + _ => return, + }; + + // Check if all call sites are known (callee_count should match call_sites + // length) + if usage.callee_count as usize != call_sites.len() { + return; + } + + // Analyze each parameter + let mut params_to_inline: Vec<(usize, Box)> = Vec::new(); + + for (param_idx, param) in f.params.iter().enumerate() { + // Only handle simple identifier parameters + let param_id = match ¶m.pat { + Pat::Ident(ident) => ident.id.to_id(), + _ => continue, // Skip destructuring, rest params, etc. + }; + + // Check if this parameter is shadowed by a function declaration in the body + // Function declarations are hoisted and would conflict with the inlined + // `let` declaration + if self.is_param_shadowed_by_fn_decl(f, ¶m_id) { + continue; + } + + // Check if this parameter has the same name as the function itself + // This would cause shadowing issues when we create a `let` declaration + if param_id == *fn_id { + continue; + } + + // Collect argument values for this parameter across all call sites + // Use Option>> to track: + // - None = no common value yet established + // - Some(None) = all call sites have implicit undefined + // - Some(Some(expr)) = all call sites have the same explicit expression + let mut common_value: Option>> = None; + let mut inlinable = true; + + for call_site in call_sites { + // Get argument at this position, or None if implicit undefined + let arg_value: Option> = if param_idx < call_site.len() { + call_site[param_idx].clone() + } else { + None // Implicit undefined + }; + + // Check if this is a safe, constant value to inline + if let Some(ref expr) = arg_value { + if !self.is_safe_constant_for_param_inline(expr) { + inlinable = false; + break; + } + } + // Implicit undefined (None) is always safe to inline + + match &common_value { + None => { + // First call site, establish the common value + common_value = Some(arg_value); + } + Some(existing) => { + // Check if this call site has the same value + if !self.arg_eq(existing, &arg_value) { + inlinable = false; + break; + } + } + } + } + + // If all call sites pass the same constant value, mark for inlining + if inlinable { + if let Some(Some(value)) = &common_value { + // Inline the constant value + params_to_inline.push((param_idx, value.clone())); + } else if let Some(None) = common_value { + // All call sites have implicit undefined + let undefined_expr = Box::new(Expr::Ident(Ident::new( + "undefined".into(), + DUMMY_SP, + self.ctx.expr_ctx.unresolved_ctxt, + ))); + params_to_inline.push((param_idx, undefined_expr)); + } + } + } + + // Apply the parameter inlining transformation + // Only inline if we can inline a contiguous suffix of parameters to avoid + // creating parameter lists with "holes" that might confuse other optimizations + if !params_to_inline.is_empty() { + // Sort by parameter index to check for contiguity + let mut sorted_for_check = params_to_inline.clone(); + sorted_for_check.sort_by_key(|(idx, _)| *idx); + + // Check if the parameters form a contiguous suffix + let mut is_valid_suffix = true; + let total_params = f.params.len(); + let first_inline_idx = sorted_for_check[0].0; + + // Must start at some index and continue to the end + if first_inline_idx + sorted_for_check.len() != total_params { + is_valid_suffix = false; + } else { + // Check contiguity + for (i, (idx, _)) in sorted_for_check.iter().enumerate() { + if *idx != first_inline_idx + i { + is_valid_suffix = false; + break; + } + } + } + + if is_valid_suffix { + self.apply_param_inlining(f, ¶ms_to_inline, fn_id); + } + } + } + + /// Apply parameter inlining transformation to a function. + fn apply_param_inlining( + &mut self, + f: &mut Function, + params_to_inline: &[(usize, Box)], + fn_id: &Id, + ) { + // Sort in reverse order to remove from the end first + let mut sorted_params = params_to_inline.to_vec(); + sorted_params.sort_by(|a, b| b.0.cmp(&a.0)); + + // Collect variable declarations to add at the beginning of function body + let mut var_decls = Vec::new(); + + // Track which parameter indices are being inlined (will be sorted) + let mut inlined_indices = Vec::new(); + + for (param_idx, value) in &sorted_params { + inlined_indices.push(*param_idx); + + if let Some(param) = f.params.get(*param_idx) { + if let Pat::Ident(ident) = ¶m.pat { + // Create variable declaration: let paramName = value; + // Always use 'let' to preserve parameter semantics (reassignable) + var_decls.push(Stmt::Decl(Decl::Var(Box::new(VarDecl { + span: DUMMY_SP, + ctxt: Default::default(), + kind: VarDeclKind::Let, + declare: false, + decls: vec![VarDeclarator { + span: DUMMY_SP, + name: Pat::Ident(ident.clone()), + init: Some(value.clone()), + definite: false, + }], + })))); + } + } + } + + // Remove parameters (in reverse order) + for (param_idx, _) in &sorted_params { + f.params.remove(*param_idx); + } + + // Add variable declarations to function body + if let Some(body) = &mut f.body { + var_decls.reverse(); // Reverse to maintain original order + var_decls.append(&mut body.stmts); + body.stmts = var_decls; + } + + // Store the inlined parameter indices for later use when visiting call + // sites. Reverse sort to get descending order for efficient removal. + inlined_indices.sort_by(|a, b| b.cmp(a)); + self.inlined_params.insert(fn_id.clone(), inlined_indices); + + self.changed = true; + report_change!( + "params: Inlined {} parameter(s) for function '{}{:?}'", + params_to_inline.len(), + fn_id.0, + fn_id.1 + ); + } + + /// Check if an expression is a safe constant value for parameter inlining. + fn is_safe_constant_for_param_inline(&self, expr: &Expr) -> bool { + match expr { + // Literal values are always safe + Expr::Lit(Lit::Null(_)) + | Expr::Lit(Lit::Bool(_)) + | Expr::Lit(Lit::Num(_)) + | Expr::Lit(Lit::Str(_)) + | Expr::Lit(Lit::BigInt(_)) => true, + + // Only allow unresolved "undefined" identifier + // We DO NOT inline variable references because: + // 1. It doesn't save code (just moves a reference) + // 2. It can interfere with other optimizations + // 3. The goal is to inline actual constants, not variable names + Expr::Ident(id) => { + let is_unresolved = id.ctxt == self.ctx.expr_ctx.unresolved_ctxt; + // Only allow unresolved "undefined" + is_unresolved && id.sym == "undefined" + } + + // Negated or numeric-negated literals + Expr::Unary(UnaryExpr { + op: UnaryOp::Bang | UnaryOp::Minus, + arg, + .. + }) => self.is_safe_constant_for_param_inline(arg), + + // Parenthesized expressions + Expr::Paren(ParenExpr { expr, .. }) => self.is_safe_constant_for_param_inline(expr), + + _ => false, + } + } + + /// Compare two optional argument values for equality. + /// None represents implicit undefined. + fn arg_eq(&self, a: &Option>, b: &Option>) -> bool { + match (a, b) { + (None, None) => true, // Both implicit undefined + (Some(a_expr), Some(b_expr)) => self.expr_eq(a_expr, b_expr), + _ => false, // One is implicit undefined, the other is not + } + } + + /// Compare two expressions for equality (structural equality for simple + /// cases). + /// + /// We cannot use the derived `Eq` trait because: + /// 1. NaN handling: We treat NaN as equal to NaN for parameter inlining + /// purposes, whereas standard floating point comparison has NaN != NaN. + /// 2. Context-aware identifier comparison: We only consider unresolved + /// "undefined" identifiers as safe to inline, checking the syntax + /// context. + fn expr_eq(&self, a: &Expr, b: &Expr) -> bool { + match (a, b) { + (Expr::Lit(Lit::Null(_)), Expr::Lit(Lit::Null(_))) => true, + (Expr::Lit(Lit::Bool(a)), Expr::Lit(Lit::Bool(b))) => a.value == b.value, + (Expr::Lit(Lit::Num(a)), Expr::Lit(Lit::Num(b))) => { + // Handle NaN specially: treat NaN as equal to NaN for parameter inlining + if a.value.is_nan() && b.value.is_nan() { + true + } else { + a.value == b.value + } + } + (Expr::Lit(Lit::Str(a)), Expr::Lit(Lit::Str(b))) => a.value == b.value, + (Expr::Lit(Lit::BigInt(a)), Expr::Lit(Lit::BigInt(b))) => a.value == b.value, + // Compare identifiers: we can compare naively since is_safe_constant_for_param_inline + // already validated that only unresolved "undefined" identifiers reach here + (Expr::Ident(a), Expr::Ident(b)) => a.sym == b.sym && a.ctxt == b.ctxt, + ( + Expr::Unary(UnaryExpr { + op: op_a, + arg: arg_a, + .. + }), + Expr::Unary(UnaryExpr { + op: op_b, + arg: arg_b, + .. + }), + ) if op_a == op_b => self.expr_eq(arg_a, arg_b), + (Expr::Paren(ParenExpr { expr: a, .. }), b) => self.expr_eq(a, b), + (a, Expr::Paren(ParenExpr { expr: b, .. })) => self.expr_eq(a, b), + _ => false, + } + } + + /// Remove arguments from a call expression that correspond to inlined + /// parameters. + /// + /// This method should be called when visiting a call expression to ensure + /// that arguments are removed for parameters that have been inlined. + pub(super) fn remove_inlined_call_args(&mut self, call: &mut CallExpr) { + // Get the function identifier from the callee + let fn_id = match &call.callee { + Callee::Expr(expr) => match &**expr { + Expr::Ident(ident) => ident.to_id(), + _ => return, // Not a simple identifier call + }, + _ => return, + }; + + // Check if this function has inlined parameters + let inlined_indices = match self.inlined_params.get(&fn_id) { + Some(indices) if !indices.is_empty() => indices, + _ => return, + }; + + // Remove arguments at the inlined parameter indices + // The indices are already sorted in descending order from apply_param_inlining + for &idx in inlined_indices { + if idx < call.args.len() { + call.args.remove(idx); + self.changed = true; + } + } + + if !inlined_indices.is_empty() { + report_change!( + "params: Removed {} argument(s) from call to '{}{:?}'", + inlined_indices.len(), + fn_id.0, + fn_id.1 + ); + } + } + + /// Check if a parameter is shadowed by a function declaration in the + /// function body. + /// + /// This prevents inlining parameters that would conflict with hoisted + /// function declarations or var declarations. For example: + /// ```js + /// function f(a) { + /// function a() { ... } + /// } + /// function g(arg) { + /// if (condition) { + /// var arg = 2; // var is hoisted and shadows parameter + /// } + /// } + /// ``` + /// We cannot inline `a` or `arg` as `let a = value` because the + /// declarations are hoisted. + fn is_param_shadowed_by_fn_decl(&self, f: &Function, param_id: &Id) -> bool { + if let Some(body) = &f.body { + self.check_stmts_for_shadowing(&body.stmts, param_id) + } else { + false + } + } + + /// Recursively check statements for shadowing declarations. + fn check_stmts_for_shadowing(&self, stmts: &[Stmt], param_id: &Id) -> bool { + for stmt in stmts { + match stmt { + // Check for function declarations + Stmt::Decl(Decl::Fn(fn_decl)) => { + if fn_decl.ident.to_id() == *param_id { + return true; + } + } + // Check for var declarations (which are hoisted) + Stmt::Decl(Decl::Var(var_decl)) if var_decl.kind == VarDeclKind::Var => { + for decl in &var_decl.decls { + if self.check_pat_for_id(&decl.name, param_id) { + return true; + } + } + } + // Recursively check block statements + Stmt::Block(block) => { + if self.check_stmts_for_shadowing(&block.stmts, param_id) { + return true; + } + } + // Recursively check if statements + Stmt::If(if_stmt) => { + if self.check_stmt_for_shadowing(&if_stmt.cons, param_id) { + return true; + } + if let Some(alt) = &if_stmt.alt { + if self.check_stmt_for_shadowing(alt, param_id) { + return true; + } + } + } + // Recursively check loops + Stmt::While(while_stmt) => { + if self.check_stmt_for_shadowing(&while_stmt.body, param_id) { + return true; + } + } + Stmt::DoWhile(do_while) => { + if self.check_stmt_for_shadowing(&do_while.body, param_id) { + return true; + } + } + Stmt::For(for_stmt) => { + // Check init for var declarations + if let Some(init) = &for_stmt.init { + match init { + VarDeclOrExpr::VarDecl(var_decl) + if var_decl.kind == VarDeclKind::Var => + { + for decl in &var_decl.decls { + if self.check_pat_for_id(&decl.name, param_id) { + return true; + } + } + } + _ => {} + } + } + if self.check_stmt_for_shadowing(&for_stmt.body, param_id) { + return true; + } + } + Stmt::ForIn(for_in) => { + // Check left side for var declarations + match &for_in.left { + ForHead::VarDecl(var_decl) if var_decl.kind == VarDeclKind::Var => { + for decl in &var_decl.decls { + if self.check_pat_for_id(&decl.name, param_id) { + return true; + } + } + } + _ => {} + } + if self.check_stmt_for_shadowing(&for_in.body, param_id) { + return true; + } + } + Stmt::ForOf(for_of) => { + // Check left side for var declarations + match &for_of.left { + ForHead::VarDecl(var_decl) if var_decl.kind == VarDeclKind::Var => { + for decl in &var_decl.decls { + if self.check_pat_for_id(&decl.name, param_id) { + return true; + } + } + } + _ => {} + } + if self.check_stmt_for_shadowing(&for_of.body, param_id) { + return true; + } + } + // Recursively check try-catch-finally + Stmt::Try(try_stmt) => { + if self.check_stmts_for_shadowing(&try_stmt.block.stmts, param_id) { + return true; + } + if let Some(handler) = &try_stmt.handler { + if self.check_stmts_for_shadowing(&handler.body.stmts, param_id) { + return true; + } + } + if let Some(finalizer) = &try_stmt.finalizer { + if self.check_stmts_for_shadowing(&finalizer.stmts, param_id) { + return true; + } + } + } + // Recursively check switch statements + Stmt::Switch(switch) => { + for case in &switch.cases { + if self.check_stmts_for_shadowing(&case.cons, param_id) { + return true; + } + } + } + // Recursively check labeled statements + Stmt::Labeled(labeled) => { + if self.check_stmt_for_shadowing(&labeled.body, param_id) { + return true; + } + } + // Recursively check with statements + Stmt::With(with) => { + if self.check_stmt_for_shadowing(&with.body, param_id) { + return true; + } + } + _ => {} + } + } + false + } + + /// Helper to check a single statement for shadowing. + fn check_stmt_for_shadowing(&self, stmt: &Stmt, param_id: &Id) -> bool { + match stmt { + Stmt::Block(block) => self.check_stmts_for_shadowing(&block.stmts, param_id), + _ => { + // For non-block statements, wrap in a slice and check + self.check_stmts_for_shadowing(std::slice::from_ref(stmt), param_id) + } + } + } + + /// Check if a pattern contains a specific identifier. + fn check_pat_for_id(&self, pat: &Pat, param_id: &Id) -> bool { + match pat { + Pat::Ident(ident) => ident.id.to_id() == *param_id, + Pat::Array(array) => array.elems.iter().any(|elem| { + elem.as_ref() + .is_some_and(|e| self.check_pat_for_id(e, param_id)) + }), + Pat::Object(obj) => obj.props.iter().any(|prop| match prop { + ObjectPatProp::KeyValue(kv) => self.check_pat_for_id(&kv.value, param_id), + ObjectPatProp::Assign(assign) => assign.key.to_id() == *param_id, + ObjectPatProp::Rest(rest) => self.check_pat_for_id(&rest.arg, param_id), + }), + Pat::Rest(rest) => self.check_pat_for_id(&rest.arg, param_id), + Pat::Assign(assign) => self.check_pat_for_id(&assign.left, param_id), + _ => false, + } + } +} diff --git a/crates/swc_ecma_minifier/src/program_data.rs b/crates/swc_ecma_minifier/src/program_data.rs index 4f26bb85710e..b1c9d94bc0f2 100644 --- a/crates/swc_ecma_minifier/src/program_data.rs +++ b/crates/swc_ecma_minifier/src/program_data.rs @@ -50,6 +50,11 @@ pub(crate) struct ProgramData { bitflags::bitflags! { #[derive(Debug, Clone, Copy)] pub(crate) struct VarUsageInfoFlags: u32 { + /// `true` if the variable cannot be safely inlined. + /// This is set when the variable is used in contexts that prevent + /// inlining optimizations, such as being passed to unknown functions, + /// used in complex expressions, or accessed in ways that require + /// preserving the original variable binding. const INLINE_PREVENTED = 1 << 0; /// `false` if it's only used. const DECLARED = 1 << 1; @@ -128,6 +133,13 @@ pub(crate) struct VarUsageInfo { infects_to: Vec, /// Only **string** properties. pub(crate) accessed_props: FxHashMap, + + /// Tracks call sites for functions. Each inner Vec contains the arguments + /// passed at that call site. Used for parameter inlining optimization. + /// Arguments are represented as Option> where: + /// - Some(expr) = explicit argument passed + /// - None = implicit undefined (argument not provided) + pub(crate) call_site_args: Option>>>>, } impl Default for VarUsageInfo { @@ -146,6 +158,7 @@ impl Default for VarUsageInfo { callee_count: Default::default(), infects_to: Default::default(), accessed_props: Default::default(), + call_site_args: Default::default(), } } } @@ -554,6 +567,20 @@ impl Storage for ProgramData { fn get_var_data(&self, id: Id) -> Option<&Self::VarData> { self.vars.get(&id).map(|v| v.as_ref()) } + + fn record_call_site_args(&mut self, callee_id: Id, args: &[Option>]) { + let var = self.vars.entry(callee_id).or_default(); + + // Initialize the call_site_args if it doesn't exist + if var.call_site_args.is_none() { + var.call_site_args = Some(Vec::new()); + } + + // Add this call site's arguments (cloned from the slice) + if let Some(ref mut call_sites) = var.call_site_args { + call_sites.push(args.to_vec()); + } + } } impl ScopeDataLike for ScopeData { diff --git a/crates/swc_ecma_minifier/tests/benches-full/d3.js b/crates/swc_ecma_minifier/tests/benches-full/d3.js index 0fbc49a6a3b0..54eb10cd45e5 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/d3.js +++ b/crates/swc_ecma_minifier/tests/benches-full/d3.js @@ -2723,10 +2723,10 @@ function(global, factory) { emitter(this, arguments).end(event); }).tween("brush", function() { var that = this, state = that.__brush, emit = emitter(that, arguments), selection0 = state.selection, selection1 = dim.input("function" == typeof selection ? selection.apply(this, arguments) : selection, state.extent), i = interpolate(selection0, selection1); - function tween(t) { - state.selection = 1 === t && null === selection1 ? null : i(t), redraw.call(that), emit.brush(); + function tween() { + state.selection = null === selection1 ? null : i(1), redraw.call(that), emit.brush(); } - return null !== selection0 && null !== selection1 ? tween : tween(1); + return null !== selection0 && null !== selection1 ? tween : tween(); }) : group.each(function() { var args = arguments, state = this.__brush, selection1 = dim.input("function" == typeof selection ? selection.apply(this, args) : selection, state.extent), emit = emitter(this, args).beforestart(); interrupt(this), state.selection = null === selection1 ? null : selection1, redraw.call(this), emit.start().brush().end(); @@ -9746,7 +9746,8 @@ function(global, factory) { function step() { tick(), event.call("tick", simulation), alpha < alphaMin && (stepper.stop(), event.call("end", simulation)); } - function tick(iterations) { + function tick() { + let iterations; var i, node, n = nodes.length; void 0 === iterations && (iterations = 1); for(var k = 0; k < iterations; ++k)for(alpha += (alphaTarget - alpha) * alphaDecay, forces.forEach(function(force) { diff --git a/crates/swc_ecma_minifier/tests/benches-full/echarts.js b/crates/swc_ecma_minifier/tests/benches-full/echarts.js index 3f6bfe43f8bd..abd8027773f2 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/echarts.js +++ b/crates/swc_ecma_minifier/tests/benches-full/echarts.js @@ -15928,7 +15928,8 @@ */ function registerPostUpdate(postUpdateFunc) { 0 > indexOf(postUpdateFuncs, postUpdateFunc) && postUpdateFunc && postUpdateFuncs.push(postUpdateFunc); } - function registerAction(actionInfo, eventName, action) { + function registerAction(actionInfo, eventName) { + let action; 'function' == typeof eventName && (action = eventName, eventName = ''); var actionType = isObject$2(actionInfo) ? actionInfo.type : [ actionInfo, @@ -33078,7 +33079,7 @@ }); group.add(elN), setLargeStyle$1(1, elP, seriesModel), setLargeStyle$1(-1, elN, seriesModel), incremental && (elP.incremental = !0, elN.incremental = !0); } - function setLargeStyle$1(sign, el, seriesModel, data) { + function setLargeStyle$1(sign, el, seriesModel) { // TODO put in visual? var borderColor = seriesModel.get([ 'itemStyle', @@ -35529,7 +35530,8 @@ }); } return result; - }(_a[0], _a[1], 0, Math.PI), isIndividualMorphingPath(toPath) || (toPath.__oldBuildPath = toPath.buildPath, toPath.buildPath = morphingPathBuildPath), function(morphingPath, morphingData, morphT) { + }(_a[0], _a[1], 0, Math.PI), isIndividualMorphingPath(toPath) || (toPath.__oldBuildPath = toPath.buildPath, toPath.buildPath = morphingPathBuildPath), function(morphingPath, morphingData) { + let morphT = 0; morphingPath.__morphingData = morphingData, morphingPath.__morphT = morphT; }(toPath, morphingData, 0); var oldDone = animationOpts && animationOpts.done, oldAborted = animationOpts && animationOpts.aborted, oldDuring = animationOpts && animationOpts.during; @@ -36328,13 +36330,15 @@ txCfgOpt && (stateObj.textConfig = txCfgOpt), setDefaultStateProxy(elDisplayable); } } - function setLagecyTransformProp(elOption, targetProps, legacyName, fromTransformable // If provided, retrieve from the element. - ) { + function setLagecyTransformProp(elOption, targetProps, legacyName) { + let fromTransformable // If provided, retrieve from the element. + ; var legacyArr = elOption[legacyName], xyName = LEGACY_TRANSFORM_PROPS[legacyName]; legacyArr && (fromTransformable ? (targetProps[xyName[0]] = fromTransformable[xyName[0]], targetProps[xyName[1]] = fromTransformable[xyName[1]]) : (targetProps[xyName[0]] = legacyArr[0], targetProps[xyName[1]] = legacyArr[1])); } - function setTransformProp(elOption, allProps, name, fromTransformable // If provided, retrieve from the element. - ) { + function setTransformProp(elOption, allProps, name) { + let fromTransformable // If provided, retrieve from the element. + ; null != elOption[name] && (allProps[name] = fromTransformable ? fromTransformable[name] : elOption[name]); } function setTransformPropToTransitionFrom(transitionFrom, name, fromTransformable // If provided, retrieve from the element. diff --git a/crates/swc_ecma_minifier/tests/benches-full/lodash.js b/crates/swc_ecma_minifier/tests/benches-full/lodash.js index 8adbfc500bd5..2ee12dabea76 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/lodash.js +++ b/crates/swc_ecma_minifier/tests/benches-full/lodash.js @@ -6014,7 +6014,8 @@ * * _.words('fred, barney, & pebbles', /[^, ]+/g); * // => ['fred', 'barney', '&', 'pebbles'] - */ function words(string, pattern, guard) { + */ function words(string) { + let pattern, guard; if (string = toString(string), pattern = guard ? undefined : pattern, undefined === pattern) { var string1; return (string1 = string, reHasUnicodeWord.test(string1)) ? string.match(reUnicodeWord) || [] : string.match(reAsciiWord) || []; diff --git a/crates/swc_ecma_minifier/tests/benches-full/terser.js b/crates/swc_ecma_minifier/tests/benches-full/terser.js index 90ec0ed29931..1e1288b90008 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/terser.js +++ b/crates/swc_ecma_minifier/tests/benches-full/terser.js @@ -1047,7 +1047,8 @@ } unexpected(); }); - function simple_statement(tmp) { + function simple_statement() { + let tmp; return new AST_SimpleStatement({ body: (tmp = expression(!0), semicolon(), tmp) }); diff --git a/crates/swc_ecma_minifier/tests/benches-full/three.js b/crates/swc_ecma_minifier/tests/benches-full/three.js index d4566afd30f6..0e5ada6cb398 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/three.js +++ b/crates/swc_ecma_minifier/tests/benches-full/three.js @@ -6589,8 +6589,8 @@ function(global, factory) { function setFlipSided(flipSided) { currentFlipSided !== flipSided && (flipSided ? gl.frontFace(2304) : gl.frontFace(2305), currentFlipSided = flipSided); } - function setCullFace(cullFace) { - 0 !== cullFace ? (enable(2884), cullFace !== currentCullFace && (1 === cullFace ? gl.cullFace(1029) : 2 === cullFace ? gl.cullFace(1028) : gl.cullFace(1032))) : disable(2884), currentCullFace = cullFace; + function setCullFace() { + enable(2884), 1 !== currentCullFace && gl.cullFace(1029), currentCullFace = 1; } function setPolygonOffset(polygonOffset, factor, units) { polygonOffset ? (enable(32823), (currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units) && (gl.polygonOffset(factor, units), currentPolygonOffsetFactor = factor, currentPolygonOffsetUnits = units)) : disable(32823); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/10328/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/10328/output.js index 27816b6a1ed4..45211a8b6ab8 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/10328/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/10328/output.js @@ -1,4 +1,4 @@ -function g(x, v) { +function g(x) { if ("a" === x) { let h; h = i({ diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/10473/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/10473/output.js index 2fc970d2e611..5c9df8bb8a9a 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/10473/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/10473/output.js @@ -18,11 +18,11 @@ function _objectSpread(t) { e % 2 ? ownKeys(Object(o), !0).forEach(function(e) { !function(e, t, o) { var e1; - (e1 = function(e, t) { + (e1 = function(e) { if ("object" != _typeof(e) || !e) return e; var o = e[Symbol.toPrimitive]; - if (void 0 === o) return ("string" === t ? String : Number)(e); - if (o = o.call(e, t || "default"), "object" != _typeof(o)) return o; + if (void 0 === o) return String(e); + if (o = o.call(e, "string"), "object" != _typeof(o)) return o; throw TypeError("@@toPrimitive must return a primitive value."); }(e1 = t, "string"), (t = "symbol" == _typeof(e1) ? e1 : e1 + "") in e) ? Object.defineProperty(e, t, { value: o, diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/2044/full/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/2044/full/output.js index e18cbc495996..d94a7c316add 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/2044/full/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/2044/full/output.js @@ -21,7 +21,8 @@ createCommonjsModule(function(module, exports) { value: !0 }); }), createCommonjsModule(function(module, exports) { - function _interopRequireDefault(obj) { + function _interopRequireDefault() { + let obj; return obj && obj.__esModule ? obj : { default: obj }; diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-1/output.js index e3bd904d61f9..7f90a5187591 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-1/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-1/output.js @@ -19,7 +19,8 @@ createCommonjsModule(function(module, exports) { value: !0 }); }), createCommonjsModule(function(module, exports) { - function _interopRequireDefault(obj) { + function _interopRequireDefault() { + let obj; return obj && obj.__esModule ? obj : { default: obj }; diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-10/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-10/output.js index e3bd904d61f9..7f90a5187591 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-10/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/2044/pass-10/output.js @@ -19,7 +19,8 @@ createCommonjsModule(function(module, exports) { value: !0 }); }), createCommonjsModule(function(module, exports) { - function _interopRequireDefault(obj) { + function _interopRequireDefault() { + let obj; return obj && obj.__esModule ? obj : { default: obj }; diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/8813/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/8813/output.js index 618b0354a8c7..01288398b039 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/8813/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/8813/output.js @@ -1,4 +1,4 @@ -let x = 'asdf', y = "PASS 1"; +let NaN, x = 'asdf', y = "PASS 1"; switch(x){ case x: default: @@ -21,7 +21,7 @@ var c = "FAIL"; switch(0 / 0){ case 0 / 0: break; - case void (c = "PASS"): + case c = "PASS", NaN: c = "FAIL"; } console.log(c); diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/firebase/dist/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/firebase/dist/1/output.js index f8d2531807bd..ca9b2bd71a13 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/firebase/dist/1/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/firebase/dist/1/output.js @@ -1,4 +1,5 @@ "use strict"; +let variant; var _a, util = require("@firebase/util"), tslib = require("tslib"), component = require("@firebase/component"), modularAPIs = require("@firebase/app"), logger$1 = require("@firebase/logger"), modularAPIs__namespace = /*#__PURE__*/ function(e) { if (e && e.__esModule) return e; var n = Object.create(null); @@ -278,5 +279,5 @@ if (util.isBrowser() && void 0 !== self.firebase) { sdkVersion && sdkVersion.indexOf("LITE") >= 0 && logger.warn("\n Warning: You are trying to load Firebase while using Firebase Performance standalone script.\n You should load Firebase Performance with this instance of Firebase to avoid loading duplicate code.\n "); } // Register `app` package. -modularAPIs.registerVersion("@firebase/app-compat", "0.1.5", void 0), module.exports = firebase$1; +modularAPIs.registerVersion("@firebase/app-compat", "0.1.5", variant), module.exports = firebase$1; //# sourceMappingURL=index.cjs.js.map diff --git a/crates/swc_ecma_minifier/tests/fixture/issues/quagga2/1.4.2/1/output.js b/crates/swc_ecma_minifier/tests/fixture/issues/quagga2/1.4.2/1/output.js index fb2d94c1a06b..750c6172be86 100644 --- a/crates/swc_ecma_minifier/tests/fixture/issues/quagga2/1.4.2/1/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/issues/quagga2/1.4.2/1/output.js @@ -8659,10 +8659,10 @@ if (0xff !== dataView.getUint8(0) || 0xd8 !== dataView.getUint8(1)) return !1; for(; offset < length && 0xff === dataView.getUint8(offset);){ if (0xe1 === dataView.getUint8(offset + 1)) return function(file, start, exifTags) { - if ("Exif" !== function(buffer, start, length) { + if ("Exif" !== function(buffer, start) { for(var outstr = "", n = start; n < start + 4; n++)outstr += String.fromCharCode(buffer.getUint8(n)); return outstr; - }(file, start, 0)) return !1; + }(file, start, 4)) return !1; var bigEnd, tiffOffset = start + 6; if (0x4949 === file.getUint16(tiffOffset)) bigEnd = !1; else { diff --git a/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/d6e1aeb5-38a8d7ae57119c23/output.js b/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/d6e1aeb5-38a8d7ae57119c23/output.js index aeb74976e398..80f56034403e 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/d6e1aeb5-38a8d7ae57119c23/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/d6e1aeb5-38a8d7ae57119c23/output.js @@ -24320,9 +24320,10 @@ this.trigger("dispose"), this.pendingTimelineChanges_ = {}, this.lastTimelineChanges_ = {}, this.off(); }, TimelineChangeController; }(videojs.EventTarget), Decrypter = factory(transform(getWorkerString(function() { - function createCommonjsModule(fn, basedir, module) { + function createCommonjsModule(fn) { + let module; return fn(module = { - path: basedir, + path: void 0, exports: {}, require: function(path, base) { throw null == base && module.path, Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs"); diff --git a/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/pages/index-cb36c1bf7f830e3c/output.js b/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/pages/index-cb36c1bf7f830e3c/output.js index d6dc0a8d4302..f5fdec7d9d7b 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/pages/index-cb36c1bf7f830e3c/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/33265/static/chunks/pages/index-cb36c1bf7f830e3c/output.js @@ -1033,7 +1033,8 @@ * @returns {Readonly} * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze - */ function freeze(object, oc) { + */ function freeze(object) { + let oc; return void 0 === oc && (oc = Object), oc && "function" == typeof oc.freeze ? oc.freeze(object) : object; } /** diff --git a/crates/swc_ecma_minifier/tests/fixture/next/36127/2/2/output.js b/crates/swc_ecma_minifier/tests/fixture/next/36127/2/2/output.js index 111142aa0cbf..1f8dc4931b59 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/36127/2/2/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/36127/2/2/output.js @@ -3,14 +3,14 @@ * * @param {RegExp} regex * @returns {(code: Code) => code is number} - */ function regexCheck(regex) { + */ function regexCheck() { return(/** * Check whether a code matches the bound regex. * * @param {Code} code Character code * @returns {code is number} Whether the character code matches the bound regex */ function(code) { - return null !== code && regex.test(String.fromCharCode(code)); + return null !== code && "Foo".test(String.fromCharCode(code)); }); } -console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")), console.log(regexCheck("Foo")); +console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()), console.log(regexCheck()); diff --git a/crates/swc_ecma_minifier/tests/fixture/next/chakra/output.js b/crates/swc_ecma_minifier/tests/fixture/next/chakra/output.js index 6e7e09e57b0e..5f86c614ae60 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/chakra/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/chakra/output.js @@ -1548,7 +1548,8 @@ var value1, replaceValue, valueStr = (value1 = value.toString(), void 0 === replaceValue && (replaceValue = "-"), value1.replace(/\s+/g, replaceValue)); return valueStr.includes("\\.") || Number.isInteger(parseFloat(value.toString())) ? value : valueStr.replace(".", "\\."); } - function cssVar(name, options) { + function cssVar(name) { + let options; var fallback, prefix, prefix1, fallback1, cssVariable = (void 0 === (prefix = null == options ? void 0 : options.prefix) && (prefix = ""), "--" + (void 0 === (prefix1 = prefix) && (prefix1 = ""), [ prefix1, chakra_ui_theme_tools_esm_escape(name) diff --git a/crates/swc_ecma_minifier/tests/fixture/next/react-ace/chunks/8a28b14e.d8fbda268ed281a1/output.js b/crates/swc_ecma_minifier/tests/fixture/next/react-ace/chunks/8a28b14e.d8fbda268ed281a1/output.js index 4702ca507806..1a1ed8a812cf 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/react-ace/chunks/8a28b14e.d8fbda268ed281a1/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/react-ace/chunks/8a28b14e.d8fbda268ed281a1/output.js @@ -156,7 +156,8 @@ importCssString(item[0], item[1]); }); } - function importCssString(cssText, id, target) { + function importCssString(cssText, id) { + let target; if ("undefined" != typeof document) { if (cssCache) { if (target) insertPendingStyles(); @@ -1806,9 +1807,9 @@ var reportErrorIfPathIsNotConfigured = function() { options.basePath || options.workerPath || options.modePath || options.themePath || Object.keys(options.$moduleUrls).length || (console.error("Unable to infer path to ace from script src,", "use ace.config.set('basePath', 'path') to enable dynamic loading of modes and themes", "or with webpack use ace/webpack-resolver"), reportErrorIfPathIsNotConfigured = function() {}); }; - function init(packaged) { + function init() { if (global && global.document) { - options.packaged = packaged || require.packaged || module.packaged || global.define && __webpack_require__.amdD.packaged; + options.packaged = !0; for(var scriptOptions = {}, scriptUrl = "", currentScript = document.currentScript || document._currentScript, scripts = (currentScript && currentScript.ownerDocument || document).getElementsByTagName("script"), i = 0; i < scripts.length; i++){ var script = scripts[i], src = script.src || script.getAttribute("src"); if (src) { diff --git a/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js b/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js index 30e171b619b2..feaeb167379f 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/react-pdf-renderer/output.js @@ -21785,10 +21785,11 @@ function o(e) { var t = this; this.next = null, this.entry = null, this.finish = function() { - var r = t.entry; - for(t.entry = null; r;){ - var n = r.callback; - e.pendingcb--, n(void 0), r = r.next; + let r; + var n = t.entry; + for(t.entry = null; n;){ + var i = n.callback; + e.pendingcb--, i(r), n = n.next; } e.corkedRequestsFree.next = t; }; diff --git a/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js b/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js index a8d36837dd8f..3c908ce02b77 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js @@ -7773,7 +7773,8 @@ * @param {Element[] | NodeList} elements - The elements which are needed to add / remove classes. * @param {string} oldClass * - Css class names which are needed to remove. If old classes are need to remove, can give this optional parameter. - */ function setCssClass(cssClass, elements, oldClass) { + */ function setCssClass(cssClass, elements) { + let oldClass; (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .isNullOrUndefined */ .le)(oldClass) || '' === oldClass || (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .removeClass */ .IV)(elements, oldClass.split(' ')), (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .isNullOrUndefined */ .le)(cssClass) || '' === cssClass || (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .addClass */ .cn)(elements, cssClass.split(' ')); } /** @@ -7813,7 +7814,8 @@ * - Boolean value to specify whether to set read only. Setting "True" value enables read only. * @param {HTMLInputElement | HTMLTextAreaElement} element * - The element which is need to enable read only. - */ function setReadonly(isReadonly, element, floatLabelType) { + */ function setReadonly(isReadonly, element) { + let floatLabelType; isReadonly ? (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .attributes */ .Y4)(element, { readonly: '' }) : element.removeAttribute('readonly'), (0, _syncfusion_ej2_base__WEBPACK_IMPORTED_MODULE_0__ /* .isNullOrUndefined */ .le)(floatLabelType) || validateLabel(element, floatLabelType); diff --git a/crates/swc_ecma_minifier/tests/fixture/next/target-es2015/static/chunks/main-04b5934c26266542/output.js b/crates/swc_ecma_minifier/tests/fixture/next/target-es2015/static/chunks/main-04b5934c26266542/output.js index e3bc766d1c37..3cd68e58a2b3 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/target-es2015/static/chunks/main-04b5934c26266542/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/target-es2015/static/chunks/main-04b5934c26266542/output.js @@ -928,7 +928,8 @@ throw map.delete(key), err; }) : prom; } - let canPrefetch = function(link) { + let canPrefetch = function() { + let link; try { return link = document.createElement("link"), !!window.MSInputMethodContext && !!document.documentMode || link.relList.supports("prefetch"); } catch (e) { diff --git a/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js b/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js index 74c804daa064..c3a45084d147 100644 --- a/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/next/wrap-contracts/output.js @@ -19850,7 +19850,8 @@ function endWritable(e, t, r) { t.ending = !0, finishMaybe(e, t), r && (t.finished ? process.nextTick(r) : e.once("finish", r)), t.ended = !0, e.writable = !1; } - function onCorkedFinish(e, t, r) { + function onCorkedFinish(e, t) { + let r; var n = e.entry; for(e.entry = null; n;){ var i = n.callback; diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/config.json new file mode 100644 index 000000000000..ea4efc8d6d6b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/config.json @@ -0,0 +1,3 @@ +{ + "inline": 2 +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/input.js new file mode 100644 index 000000000000..e42612b0b0d5 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/input.js @@ -0,0 +1,11 @@ +// Arrow function with inlinable parameter +const process = (value, multiplier) => { + return value * multiplier; +}; + +// multiplier is always 2 +const result1 = process(10, 2); +const result2 = process(20, 2); +const result3 = process(30, 2); + +console.log(result1, result2, result3); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/output.js new file mode 100644 index 000000000000..5ed281a587fd --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/arrow_function/output.js @@ -0,0 +1,7 @@ +// Arrow function with inlinable parameter +const process = (value, multiplier)=>value * multiplier; +// multiplier is always 2 +const result1 = 20; +const result2 = 40; +const result3 = 60; +console.log(20, 40, 60); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/config.json new file mode 100644 index 000000000000..dc43e1ae5d1f --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/config.json @@ -0,0 +1,4 @@ +{ + "inline": 2, + "reduce_vars": true +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/input.js new file mode 100644 index 000000000000..7889be21e9f7 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/input.js @@ -0,0 +1,9 @@ +// Basic parameter inlining - undefined parameter +function complex(foo, fn) { + if (Math.random() > 0.5) throw new Error(); + return fn?.(foo); +} + +console.log(complex("foo")); +console.log(complex("bar")); +console.log(complex("baz")); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/output.js new file mode 100644 index 000000000000..8d3fa6f65387 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/basic/output.js @@ -0,0 +1,9 @@ +// Basic parameter inlining - undefined parameter +function complex(foo) { + let fn; + if (Math.random() > 0.5) throw Error(); + return fn?.(foo); +} +console.log(complex("foo")); +console.log(complex("bar")); +console.log(complex("baz")); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/config.json new file mode 100644 index 000000000000..ea4efc8d6d6b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/config.json @@ -0,0 +1,3 @@ +{ + "inline": 2 +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/input.js new file mode 100644 index 000000000000..d72a4eda6b21 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/input.js @@ -0,0 +1,8 @@ +// Should NOT inline - different values passed +function add(a, b) { + return a + b; +} + +console.log(add(1, 2)); +console.log(add(3, 4)); +console.log(add(5, 6)); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/output.js new file mode 100644 index 000000000000..54e25bd81b95 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/different_values/output.js @@ -0,0 +1,7 @@ +// Should NOT inline - different values passed +function add(a, b) { + return a + b; +} +console.log(add(1, 2)); +console.log(add(3, 4)); +console.log(add(5, 6)); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/config.json new file mode 100644 index 000000000000..ea4efc8d6d6b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/config.json @@ -0,0 +1,3 @@ +{ + "inline": 2 +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/input.js new file mode 100644 index 000000000000..e9b2f6e15713 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/input.js @@ -0,0 +1,9 @@ +// Various literal types that can be inlined +function literals(str, num, bool, nil) { + console.log(str, num, bool, nil); + return str + num; +} + +literals("hello", 42, true, null); +literals("hello", 42, true, null); +literals("hello", 42, true, null); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/output.js new file mode 100644 index 000000000000..dfd98a9e4e79 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/literal_values/output.js @@ -0,0 +1,9 @@ +// Various literal types that can be inlined +function literals() { + let str = "hello"; + console.log(str, 42, true, null); + return str + 42; +} +literals(); +literals(); +literals(); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/config.json new file mode 100644 index 000000000000..ea4efc8d6d6b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/config.json @@ -0,0 +1,3 @@ +{ + "inline": 2 +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/input.js new file mode 100644 index 000000000000..c87a0739900a --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/input.js @@ -0,0 +1,12 @@ +// Mixed parameters - some inlinable, some not +function mixed(foo, callback, debug) { + if (debug) { + console.log("Debug:", foo); + } + return callback(foo); +} + +// callback varies, debug is always undefined +mixed("a", x => x * 2); +mixed("b", x => x + 1); +mixed("c", x => x - 1); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/output.js new file mode 100644 index 000000000000..b2dc37a6580b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/mixed_params/output.js @@ -0,0 +1,10 @@ +// Mixed parameters - some inlinable, some not +function mixed(foo, callback) { + let debug; + if (debug) console.log("Debug:", foo); + return callback(foo); +} +// callback varies, debug is always undefined +mixed("a", (x)=>2 * x); +mixed("b", (x)=>x + 1); +mixed("c", (x)=>x - 1); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/config.json b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/config.json new file mode 100644 index 000000000000..ea4efc8d6d6b --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/config.json @@ -0,0 +1,3 @@ +{ + "inline": 2 +} diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/input.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/input.js new file mode 100644 index 000000000000..c7e22c131ab3 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/input.js @@ -0,0 +1,9 @@ +// Multiple parameters that can all be inlined +function calc(a, b, c) { + return a + b + c; +} + +// All parameters are consistently the same +calc(1, 2, 3); +calc(1, 2, 3); +calc(1, 2, 3); diff --git a/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/output.js b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/output.js new file mode 100644 index 000000000000..d1624865b693 --- /dev/null +++ b/crates/swc_ecma_minifier/tests/fixture/param_inline/multiple_params/output.js @@ -0,0 +1,8 @@ +// Multiple parameters that can all be inlined +function calc() { + return 6; +} +// All parameters are consistently the same +calc(); +calc(); +calc(); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/chunkfilename-b114cf1d23876beaa712/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/chunkfilename-b114cf1d23876beaa712/output.js index bd88212357bd..9f40e6633f21 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/chunkfilename-b114cf1d23876beaa712/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/chunkfilename-b114cf1d23876beaa712/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/function-7fe8439c89afccb77983/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/function-7fe8439c89afccb77983/output.js index 13c9f3d00838..4387aa2f0929 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/function-7fe8439c89afccb77983/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/function-7fe8439c89afccb77983/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/head-432fc3a9a66c90ce2ec2/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/head-432fc3a9a66c90ce2ec2/output.js index dea558eeb324..22eae434f1f7 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/head-432fc3a9a66c90ce2ec2/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/head-432fc3a9a66c90ce2ec2/output.js @@ -239,12 +239,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/multiple-modules-d02ebebcfa5282e50b34/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/multiple-modules-d02ebebcfa5282e50b34/output.js index 0f2aa788296a..e180e3f7b64f 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/multiple-modules-d02ebebcfa5282e50b34/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/multiple-modules-d02ebebcfa5282e50b34/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/nested-05a7ce04b1f7eb6da341/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/nested-05a7ce04b1f7eb6da341/output.js index 12b8a73bf19d..b2d51f0b9f29 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/nested-05a7ce04b1f7eb6da341/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/nested-05a7ce04b1f7eb6da341/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-chunk-e2d9573b8d7df68a6cde/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-chunk-e2d9573b8d7df68a6cde/output.js index 192d61118060..39949be8b45f 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-chunk-e2d9573b8d7df68a6cde/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-chunk-e2d9573b8d7df68a6cde/output.js @@ -321,12 +321,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-9ced90e71a0d75a11cdd/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-9ced90e71a0d75a11cdd/output.js index 8c3d1fd81382..b1f71fa2826b 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-9ced90e71a0d75a11cdd/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-9ced90e71a0d75a11cdd/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-custom-loading-7f61b2e27708ca1854e0/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-custom-loading-7f61b2e27708ca1854e0/output.js index a8d0fa08983e..3a4e1a4895d7 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-custom-loading-7f61b2e27708ca1854e0/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/no-ssr-custom-loading-7f61b2e27708ca1854e0/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-994266264fb6ff57d32c/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-994266264fb6ff57d32c/output.js index 5749de67698c..2173017613d2 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-994266264fb6ff57d32c/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-994266264fb6ff57d32c/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-true-6d4aa8fc503b9d073aef/output.js b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-true-6d4aa8fc503b9d073aef/output.js index def8deb09cd5..d2dcadfe9f93 100644 --- a/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-true-6d4aa8fc503b9d073aef/output.js +++ b/crates/swc_ecma_minifier/tests/fixture/projects/next/archive-3/pages/dynamic/ssr-true-6d4aa8fc503b9d073aef/output.js @@ -207,12 +207,13 @@ READY_INITIALIZERS.push(function(ids) { var _step, _iterator = function(o, allowArrayLike) { if ("undefined" == typeof Symbol || null == o[Symbol.iterator]) { - if (Array.isArray(o) || (it = function(o, minLen) { + if (Array.isArray(o) || (it = function(o) { + let minLen; if (o) { - if ("string" == typeof o) return _arrayLikeToArray(o, void 0); + if ("string" == typeof o) return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if ("Object" === n && o.constructor && (n = o.constructor.name), "Map" === n || "Set" === n) return Array.from(o); - if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, void 0); + if ("Arguments" === n || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } }(o))) { it && (o = it); diff --git a/crates/swc_ecma_minifier/tests/libs-size.snapshot.md b/crates/swc_ecma_minifier/tests/libs-size.snapshot.md index 561c402979ab..33def784d1a5 100644 --- a/crates/swc_ecma_minifier/tests/libs-size.snapshot.md +++ b/crates/swc_ecma_minifier/tests/libs-size.snapshot.md @@ -1,14 +1,14 @@ | File | Original Size | Compressed Size | Gzipped Size | | --- | --- | --- | --- | | antd.js | 6.38 MiB | 2.06 MiB | 445.40 KiB | -| d3.js | 542.74 KiB | 261.45 KiB | 85.34 KiB | -| echarts.js | 3.41 MiB | 977.31 KiB | 314.18 KiB | +| d3.js | 542.74 KiB | 261.44 KiB | 85.33 KiB | +| echarts.js | 3.41 MiB | 977.32 KiB | 314.19 KiB | | jquery.js | 280.89 KiB | 87.80 KiB | 30.21 KiB | | lodash.js | 531.35 KiB | 68.92 KiB | 24.60 KiB | | moment.js | 169.83 KiB | 57.39 KiB | 18.26 KiB | | react.js | 70.45 KiB | 22.44 KiB | 8.04 KiB | -| terser.js | 1.08 MiB | 446.65 KiB | 120.49 KiB | -| three.js | 1.19 MiB | 630.73 KiB | 154.79 KiB | -| typescript.js | 10.45 MiB | 3.17 MiB | 840.60 KiB | +| terser.js | 1.08 MiB | 446.66 KiB | 120.48 KiB | +| three.js | 1.19 MiB | 630.72 KiB | 154.79 KiB | +| typescript.js | 10.45 MiB | 3.17 MiB | 840.69 KiB | | victory.js | 2.30 MiB | 694.10 KiB | 154.19 KiB | | vue.js | 334.13 KiB | 113.70 KiB | 41.81 KiB | diff --git a/crates/swc_ecma_minifier/tests/pass-1/9/1/output.js b/crates/swc_ecma_minifier/tests/pass-1/9/1/output.js index 543a8daa637c..6d837d2a0610 100644 --- a/crates/swc_ecma_minifier/tests/pass-1/9/1/output.js +++ b/crates/swc_ecma_minifier/tests/pass-1/9/1/output.js @@ -1 +1,4 @@ -console.log("Greeting:", "Hello"); +let value; +console.log("Greeting:", (value = "Hello", function() { + return value; +})()); diff --git a/crates/swc_ecma_minifier/tests/projects-size.snapshot.md b/crates/swc_ecma_minifier/tests/projects-size.snapshot.md index 9a6f8ecf5eea..625b3dcfdf41 100644 --- a/crates/swc_ecma_minifier/tests/projects-size.snapshot.md +++ b/crates/swc_ecma_minifier/tests/projects-size.snapshot.md @@ -2,7 +2,7 @@ | --- | --- | --- | --- | | angular-1.2.5.js | 757.44 KiB | 101.91 KiB | 37.18 KiB | | backbone-1.1.0.js | 59.77 KiB | 18.33 KiB | 6.29 KiB | -| jquery-1.9.1.js | 309.61 KiB | 90.76 KiB | 32.09 KiB | +| jquery-1.9.1.js | 309.61 KiB | 90.78 KiB | 32.08 KiB | | jquery.mobile-1.4.2.js | 534.38 KiB | 191.23 KiB | 52.60 KiB | | mootools-1.4.5.js | 181.36 KiB | 88.54 KiB | 27.48 KiB | | react-17.0.1.js | 82.58 KiB | 22.44 KiB | 8.04 KiB | diff --git a/crates/swc_ecma_minifier/tests/projects/output/jquery-1.9.1.js b/crates/swc_ecma_minifier/tests/projects/output/jquery-1.9.1.js index 1cc607d293b4..cb0368895520 100644 --- a/crates/swc_ecma_minifier/tests/projects/output/jquery-1.9.1.js +++ b/crates/swc_ecma_minifier/tests/projects/output/jquery-1.9.1.js @@ -2734,7 +2734,7 @@ domManip: function(args, table, callback) { // Flatten any nested arrays args = core_concat.apply([], args); - var elem, tag, first, node, hasScripts, scripts, doc, fragment, i = 0, l = this.length, set = this, iNoClone = l - 1, value = args[0], isFunction = jQuery.isFunction(value); + var first, node, hasScripts, scripts, doc, fragment, i = 0, l = this.length, set = this, iNoClone = l - 1, value = args[0], isFunction = jQuery.isFunction(value); // We can't cloneNode fragments that contain checked, in WebKit if (isFunction || !(l <= 1 || "string" != typeof value || jQuery.support.checkClone || !rchecked.test(value))) return this.each(function(index) { var self = set.eq(index); @@ -2743,9 +2743,10 @@ if (l && (first = (fragment = jQuery.buildFragment(args, this[0].ownerDocument, !1, this)).firstChild, 1 === fragment.childNodes.length && (fragment = first), first)) { // Use the original fragment for the last item instead of the first because it can end up // being emptied incorrectly in certain situations (#8070). - for(table = table && jQuery.nodeName(first, "tr"), hasScripts = (scripts = jQuery.map(getAll(fragment, "script"), disableScript)).length; i < l; i++){ - node = fragment, i !== iNoClone && (node = jQuery.clone(node, !0, !0), hasScripts && jQuery.merge(scripts, getAll(node, "script"))), callback.call(table && jQuery.nodeName(this[i], "table") ? (elem = this[i], tag = "tbody", elem.getElementsByTagName(tag)[0] || elem.appendChild(elem.ownerDocument.createElement(tag))) : this[i], node, i); - } + for(table = table && jQuery.nodeName(first, "tr"), hasScripts = (scripts = jQuery.map(getAll(fragment, "script"), disableScript)).length; i < l; i++)node = fragment, i !== iNoClone && (node = jQuery.clone(node, !0, !0), hasScripts && jQuery.merge(scripts, getAll(node, "script"))), callback.call(table && jQuery.nodeName(this[i], "table") ? function(elem) { + let tag = "tbody"; + return elem.getElementsByTagName(tag)[0] || elem.appendChild(elem.ownerDocument.createElement(tag)); + }(this[i], "tbody") : this[i], node, i); if (hasScripts) // Evaluate executable scripts on first document insertion for(doc = scripts[scripts.length - 1].ownerDocument, // Reenable scripts jQuery.map(scripts, restoreScript), i = 0; i < hasScripts; i++)node = scripts[i], rscriptType.test(node.type || "") && !jQuery._data(node, "globalEval") && jQuery.contains(doc, node) && (node.src ? // Hope ajax is available... diff --git a/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js b/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js index 63e6271ebb28..2de27d204873 100644 --- a/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js +++ b/crates/swc_ecma_minifier/tests/projects/output/react-dom-17.0.2.js @@ -3377,9 +3377,9 @@ * @return {boolean} True if the event is supported. * @internal * @license Modernizr 3.0.0pre (Custom Build) | MIT - */ function(eventNameSuffix) { + */ function() { if (!canUseDOM) return !1; - var eventName = "on" + eventNameSuffix, isSupported = eventName in document; + var eventName = "oninput", isSupported = eventName in document; if (!isSupported) { var element = document.createElement("div"); element.setAttribute(eventName, "return;"), isSupported = "function" == typeof element[eventName]; diff --git a/crates/swc_ecma_minifier/tests/terser/compress/arrow/issue_2136_2/output.js b/crates/swc_ecma_minifier/tests/terser/compress/arrow/issue_2136_2/output.js index 3bae317193ce..d1b4668d2c46 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/arrow/issue_2136_2/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/arrow/issue_2136_2/output.js @@ -1,4 +1,4 @@ -function f(x) { - console.log(x); +function f() { + console.log(2); } -f(2); +f(); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/drop_unused/issue_2136_2/output.js b/crates/swc_ecma_minifier/tests/terser/compress/drop_unused/issue_2136_2/output.js index 3bae317193ce..d1b4668d2c46 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/drop_unused/issue_2136_2/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/drop_unused/issue_2136_2/output.js @@ -1,4 +1,4 @@ -function f(x) { - console.log(x); +function f() { + console.log(2); } -f(2); +f(); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2601_1/output.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2601_1/output.js index 9e44326bad4f..eca3efbf3b39 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2601_1/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2601_1/output.js @@ -1,2 +1,5 @@ var a = "FAIL"; -console.log(a = "PASS"); +(function() { + let b; + b && b(), a = "PASS"; +})(), console.log(a); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_2/output.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_2/output.js index 17d695e0edd6..a71a8976afba 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_2/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_2/output.js @@ -1,2 +1,4 @@ var c = "FAIL"; -(c = "PASS"), console.log(c); +(function() { + c = "PASS"; +})(), console.log(c); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.js b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.js index 8bcd28693e3e..78916c4f4f21 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/functions/issue_2620_4/output.js @@ -1,9 +1,10 @@ var c = "FAIL"; (function() { var a = 0 / 0; + let NaN; switch(a){ case a: - case void (c = "PASS"): + case c = "PASS", NaN: } })(); console.log(c); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_else/output.js b/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_else/output.js index 0e50dcd5829d..024738ae7c1b 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_else/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_else/output.js @@ -1,6 +1,6 @@ -function f(x) { +function f() { (function() { - x || console.log("PASS"); + console.log("PASS"); })(); } -f(0); +f(); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_label/output.js b/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_label/output.js index 719890b97acb..dfe4fd37b8e1 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_label/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/issue_1673/side_effects_label/output.js @@ -1,9 +1,9 @@ -function f(x) { - (function () { +function f() { + (function() { L: { console.log("PASS"); break L; } })(); } -f(0); +f(); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/issue_281/modified/output.js b/crates/swc_ecma_minifier/tests/terser/compress/issue_281/modified/output.js index b7d0ff08bd6d..9527981bd7c5 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/issue_281/modified/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/issue_281/modified/output.js @@ -1,5 +1,5 @@ -function f5(b) { - var a = b; - return b++ + a; +function f5() { + let b = 1; + return b++ + 1; } -console.log(f5(1)); +console.log(f5()); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_1/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_1/output.js index 79cb7c0da8a3..0ee186d161a3 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_1/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_1/output.js @@ -1,7 +1,7 @@ function f() { - return function(b) { + return function() { return 2; - }(0) + function h() { + }(2) + function h() { return h(); }(); } diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_2/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_2/output.js index 79cb7c0da8a3..0ee186d161a3 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_2/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/defun_inline_2/output.js @@ -1,7 +1,7 @@ function f() { - return function(b) { + return function() { return 2; - }(0) + function h() { + }(2) + function h() { return h(); }(); } diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/do_while/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/do_while/output.js index f0842895c1a9..ac2b9dd3d85d 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/do_while/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/do_while/output.js @@ -1,9 +1,10 @@ -function f(a) { +function f() { + let a = 1; do (function() { a && (c = "PASS"); })(); while (a = 0) } var c = "FAIL"; -f(1); +f(); console.log(c); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_conditional/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_conditional/output.js index 3fab22ec4f19..2e23eb40eee2 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_conditional/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_conditional/output.js @@ -1,9 +1,8 @@ -function baz(s) { - return s ? foo : bar; +function baz() { + return bar; } -function foo() {} function bar() {} -(function () { +(function() { var thing = baz(); if (thing !== (thing = baz())) console.log("FAIL"); else console.log("PASS"); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_local_conditional/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_local_conditional/output.js index adfbe1e64544..1270eecacde9 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_local_conditional/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_local_conditional/output.js @@ -1,7 +1,7 @@ -function baz(s) { - return s ? function () {} : function () {}; +function baz() { + return function() {}; } -(function () { +(function() { var thing = baz(); if (thing !== (thing = baz())) console.log("PASS"); else console.log("FAIL"); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_yield/output.js b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_yield/output.js index f11b4f033029..d8514ae2af02 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_yield/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/reduce_vars/escape_yield/output.js @@ -1,5 +1,5 @@ function foo() {} -var gen = function*(s) { +var gen = function*() { for(;;)yield foo; }(); (function() { diff --git a/crates/swc_ecma_minifier/tests/terser/compress/switch/if_else8/output.js b/crates/swc_ecma_minifier/tests/terser/compress/switch/if_else8/output.js index 4a0cfa4e3318..c238618bfd88 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/switch/if_else8/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/switch/if_else8/output.js @@ -1,4 +1,4 @@ -function test(foo) { - return "bar" === foo ? "PASS" : "FAIL"; +function test() { + return "PASS"; } -console.log(test("bar")); +console.log(test()); diff --git a/crates/swc_ecma_minifier/tests/terser/compress/typeof/duplicate_defun_arg_name/output.js b/crates/swc_ecma_minifier/tests/terser/compress/typeof/duplicate_defun_arg_name/output.js index 4fa10c33dd0b..db4e33ad9068 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/typeof/duplicate_defun_arg_name/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/typeof/duplicate_defun_arg_name/output.js @@ -1,4 +1,5 @@ -function long_name(long_name) { - return typeof long_name; +function long_name() { + let long_name; + return "undefined"; } console.log("function", long_name()); diff --git a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs index 4cee58545145..9df32f8e270a 100644 --- a/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs +++ b/crates/swc_ecma_usage_analyzer/src/analyzer/mod.rs @@ -435,6 +435,26 @@ where self.data.var_or_default(i.to_id()).mark_used_as_callee(); }); + // Record call site arguments for parameter inlining optimization + if let Expr::Ident(callee_ident) = &**callee { + // Collect arguments for this call site + let mut call_args = Vec::new(); + for arg in &n.args { + if arg.spread.is_some() { + // Spread arguments prevent parameter inlining + call_args.clear(); + break; + } + call_args.push(Some(arg.expr.clone())); + } + + // Only record if we have a valid argument list (no spread) + if !call_args.is_empty() || n.args.is_empty() { + self.data + .record_call_site_args(callee_ident.to_id(), &call_args); + } + } + match &**callee { Expr::Fn(callee) => { for (idx, p) in callee.function.params.iter().enumerate() { diff --git a/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs b/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs index df2e9ee5f2b1..b1b59920b422 100644 --- a/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs +++ b/crates/swc_ecma_usage_analyzer/src/analyzer/storage.rs @@ -42,6 +42,10 @@ pub trait Storage: Sized + Default { fn mark_property_mutation(&mut self, id: Id); fn get_var_data(&self, id: Id) -> Option<&Self::VarData>; + + /// Records arguments passed to a function at a call site. + /// Used for parameter inlining optimization. + fn record_call_site_args(&mut self, callee_id: Id, args: &[Option>]); } pub trait ScopeDataLike: Sized + Default + Clone {