diff --git a/crates/swc/tests/tsc.rs b/crates/swc/tests/tsc.rs index fc2369c0a65c..b661866d7a9b 100644 --- a/crates/swc/tests/tsc.rs +++ b/crates/swc/tests/tsc.rs @@ -413,6 +413,8 @@ fn matrix(input: &Path) -> Vec { } fn compile(output: &Path, test_unit_data: TestUnitData) { + let _testing = testing::init(); + let cm = test_unit_data.cm; let c = Compiler::new(cm.clone()); diff --git a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs index 2976e2eead51..96380db3225c 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/conditionals.rs @@ -3,6 +3,7 @@ use std::mem::swap; use swc_common::{util::take::Take, EqIgnoreSpan, Spanned, DUMMY_SP}; use swc_ecma_ast::*; use swc_ecma_transforms_base::ext::ExprRefExt; +use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_utils::{ExprExt, ExprFactory, StmtExt, StmtLike}; use super::Optimizer; @@ -282,7 +283,10 @@ where }; let new_expr = self.compress_similar_cons_alt(&mut stmt.test, cons, alt, true); + if let Some(v) = new_expr { + debug_assert_valid(&v); + self.changed = true; *s = Stmt::Expr(ExprStmt { span: stmt.span, @@ -346,6 +350,9 @@ where alt: &mut Expr, is_for_if_stmt: bool, ) -> Option { + debug_assert_valid(cons); + debug_assert_valid(alt); + if cons.eq_ignore_span(alt) && !matches!(&*cons, Expr::Yield(..) | Expr::Fn(..)) { report_change!("conditionals: cons is same as alt"); return Some(Expr::Seq(SeqExpr { @@ -578,10 +585,7 @@ where span: DUMMY_SP, left: test.take(), op: op!("||"), - right: Box::new(Expr::Seq(SeqExpr { - span: alt.span, - exprs: alt.exprs.take(), - })), + right: Expr::from_exprs(alt.exprs.take()), })); Some(Expr::Seq(SeqExpr { span: DUMMY_SP, @@ -601,10 +605,7 @@ where span: DUMMY_SP, left: test.take(), op: op!("&&"), - right: Box::new(Expr::Seq(SeqExpr { - span: cons.span, - exprs: cons.exprs.take(), - })), + right: Expr::from_exprs(cons.exprs.take()), })); Some(Expr::Seq(SeqExpr { span: DUMMY_SP, diff --git a/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs b/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs index 39af09e9f7b6..7d6439bd18da 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/if_return.rs @@ -1,5 +1,6 @@ use swc_common::{util::take::Take, Spanned, DUMMY_SP}; use swc_ecma_ast::*; +use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_utils::{undefined, StmtExt, StmtLike}; use swc_ecma_visit::{noop_visit_type, Visit, VisitWith}; @@ -55,6 +56,8 @@ where for stmt in stmts.iter_mut() { self.merge_nested_if_returns(stmt, terminates); + + debug_assert_valid(&*stmt); } if terminates || is_fn_body { @@ -69,12 +72,18 @@ where match s { Stmt::Block(s) => { self.merge_if_returns(&mut s.stmts, terminate, false); + + debug_assert_valid(&*s); } Stmt::If(s) => { self.merge_nested_if_returns(&mut s.cons, can_work); + debug_assert_valid(&s.cons); + if let Some(alt) = s.alt.as_deref_mut() { self.merge_nested_if_returns(alt, can_work); + + debug_assert_valid(&*alt); } } _ => {} @@ -366,6 +375,8 @@ where } if let Some(mut cur) = cur { + self.normalize_expr(&mut cur); + match &*cur { Expr::Seq(seq) if !should_preserve_last_return diff --git a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs index 477f65fbb39e..4d10a87eb217 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/iife.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/iife.rs @@ -450,7 +450,6 @@ where Callee::Super(_) | Callee::Import(_) => return, Callee::Expr(e) => &mut **e, }; - self.normalize_expr(callee); if self.ctx.dont_invoke_iife { log_abort!("iife: Inline is prevented"); @@ -582,10 +581,7 @@ where exprs.push(body.take()); report_change!("inline: Inlining a call to an arrow function"); - *e = Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - }); + *e = *Expr::from_exprs(exprs); e.visit_mut_with(self); } } @@ -986,7 +982,9 @@ where }; self.merge_sequences_in_seq_expr(&mut e); - return Some(Expr::Seq(e)); + let mut e = Expr::Seq(e); + self.normalize_expr(&mut e); + return Some(e); } _ => {} } @@ -1008,7 +1006,9 @@ where }; self.merge_sequences_in_seq_expr(&mut e); - Some(Expr::Seq(e)) + let mut e = Expr::Seq(e); + self.normalize_expr(&mut e); + Some(e) } fn can_be_inlined_for_iife(&self, arg: &Expr) -> bool { diff --git a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs index 1107fb0829fc..0bd268db57c2 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/mod.rs @@ -9,6 +9,7 @@ use swc_common::{ SyntaxContext, DUMMY_SP, }; use swc_ecma_ast::*; +use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_utils::{ prepend_stmts, undefined, ExprCtx, ExprExt, ExprFactory, IsEmpty, ModuleItemLike, StmtLike, Type, Value, @@ -1740,24 +1741,64 @@ where _ => {} } + if e.is_seq() { + debug_assert_valid(e); + } + self.remove_invalid(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.optimize_str_access_to_arguments(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.replace_props(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.drop_unused_assignments(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_lits(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_typeofs(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_logical_exprs_as_bang_bang(e, false); + if e.is_seq() { + debug_assert_valid(e); + } + self.inline(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.handle_property_access(e); + if e.is_seq() { + debug_assert_valid(e); + } + if let Expr::Bin(bin) = e { let expr = self.optimize_lit_cmp(bin); if let Some(expr) = expr { @@ -1767,20 +1808,48 @@ where } } + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_cond_expr_if_similar(e); + if e.is_seq() { + debug_assert_valid(e); + } + if self.options.negate_iife { self.negate_iife_in_cond(e); + + if e.is_seq() { + debug_assert_valid(e); + } } self.collapse_assignment_to_vars(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.evaluate(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.invoke_iife(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.optimize_bangbang(e); + if e.is_seq() { + debug_assert_valid(e); + } + match e { Expr::Seq(s) if s.exprs.is_empty() => { e.take(); @@ -1877,6 +1946,8 @@ where } } + self.normalize_expr(&mut n.expr); + #[cfg(debug_assertions)] { n.visit_with(&mut AssertValid); @@ -1974,6 +2045,8 @@ where fn visit_mut_for_stmt(&mut self, s: &mut ForStmt) { self.visit_with_prepend(&mut s.init); + debug_assert_valid(&s.init); + s.test.visit_mut_with(self); s.update.visit_mut_with(self); @@ -2023,11 +2096,27 @@ where } } + #[cfg(debug_assertions)] + { + n.visit_with(&mut AssertValid); + } + if let Some(body) = &mut n.body { self.merge_if_returns(&mut body.stmts, false, true); + + #[cfg(debug_assertions)] + { + body.visit_with(&mut AssertValid); + } + self.drop_else_token(&mut body.stmts); } + #[cfg(debug_assertions)] + { + n.visit_with(&mut AssertValid); + } + { let ctx = Ctx { ..self.ctx }; self.with_ctx(ctx).optimize_usage_of_arguments(n); @@ -2333,6 +2422,7 @@ where ..self.ctx }; s.visit_mut_children_with(&mut *self.with_ctx(ctx)); + if self.prepend_stmts.is_empty() && self.append_stmts.is_empty() { match s { // We use var decl with no declarator to indicate we dropped an decl. @@ -2364,21 +2454,46 @@ where }) = s { *s = *body.take(); + + debug_assert_valid(s); } self.remove_duplicate_var_decls(s); + match s { + Stmt::Decl(Decl::Var(v)) if v.decls.is_empty() => { + s.take(); + if self.prepend_stmts.is_empty() && self.append_stmts.is_empty() { + return; + } + } + _ => {} + } + + debug_assert_valid(s); + // visit_mut_children_with above may produce easily optimizable block // statements. self.try_removing_block(s, false, false); + debug_assert_valid(s); + // These methods may modify prepend_stmts or append_stmts. self.optimize_loops_if_cond_is_false(s); + + debug_assert_valid(s); + self.optimize_loops_with_break(s); + debug_assert_valid(s); + self.try_removing_block(s, false, false); + debug_assert_valid(s); + if !self.prepend_stmts.is_empty() || !self.append_stmts.is_empty() { + report_change!("Creating a fake block because of prepend or append"); + let span = s.span(); *s = Stmt::Block(BlockStmt { span: span.apply_mark(self.marks.fake_block), @@ -2405,7 +2520,8 @@ where self.prepend_stmts = old_prepend; self.append_stmts = old_append; - let len = self.prepend_stmts.len(); + let prepend_len = self.prepend_stmts.len(); + let append_len = self.append_stmts.len(); #[cfg(feature = "debug")] if self.debug_infinite_loop { @@ -2416,7 +2532,8 @@ where } } - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); if let Stmt::Expr(ExprStmt { expr, .. }) = s { if is_pure_undefined(&self.expr_ctx, expr) { @@ -2454,7 +2571,8 @@ where } } - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); match s { // We use var decl with no declarator to indicate we dropped an decl. @@ -2465,34 +2583,39 @@ where _ => {} } - debug_assert_eq!(self.prepend_stmts.len(), len); - - #[cfg(debug_assertions)] - { - s.visit_with(&mut AssertValid); - } - - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); self.compress_if_without_alt(s); - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); self.compress_if_stmt_as_cond(s); - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); self.compress_if_stmt_as_expr(s); - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); self.optimize_const_switches(s); - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); self.optimize_switches(s); - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); #[cfg(feature = "debug")] if self.debug_infinite_loop { @@ -2503,14 +2626,9 @@ where } } - debug_assert_eq!(self.prepend_stmts.len(), len); - - #[cfg(debug_assertions)] - { - s.visit_with(&mut AssertValid); - } - - debug_assert_eq!(self.prepend_stmts.len(), len); + debug_assert_eq!(self.prepend_stmts.len(), prepend_len); + debug_assert_eq!(self.append_stmts.len(), append_len); + debug_assert_valid(s); } fn visit_mut_stmts(&mut self, stmts: &mut Vec) { @@ -2703,8 +2821,12 @@ where var.init.visit_mut_with(self); + debug_assert_valid(&var.init); + self.remove_duplicate_name_of_function(var); + debug_assert_valid(&var.init); + if let VarDeclarator { name: Pat::Ident(id), init: Some(init), @@ -2723,6 +2845,8 @@ where }; self.store_var_for_prop_hoisting(var); + + debug_assert_valid(&var.init); } #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] @@ -2749,6 +2873,8 @@ where return false; } + debug_assert_valid(&*var); + true }); @@ -2846,6 +2972,7 @@ where if let Some(usage) = self.data.vars.get(&i.id.to_id()) { if usage.declared_as_catch_param { var.init = None; + debug_assert_valid(var); return true; } } @@ -2854,6 +2981,8 @@ where return false; } + debug_assert_valid(var); + true }); } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs index 0202dfcdbc3c..783ccb54aa76 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/sequences.rs @@ -272,6 +272,12 @@ where seq.exprs.extend(take(&mut exprs)); seq.exprs.extend(extra); + if seq.exprs.len() == 1 { + stmt.init = Some(VarDeclOrExpr::Expr( + seq.exprs.pop().unwrap(), + )); + } + new_stmts.push(T::from_stmt(Stmt::For(stmt))); continue; @@ -281,11 +287,13 @@ where e.prepend_exprs(take(&mut exprs)); } None => { - stmt.init = - Some(VarDeclOrExpr::Expr(Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs: take(&mut exprs), - })))) + if exprs.is_empty() { + stmt.init = None; + } else { + stmt.init = Some(VarDeclOrExpr::Expr(Expr::from_exprs( + take(&mut exprs), + ))) + } } _ => { unreachable!() @@ -326,10 +334,7 @@ where if !exprs.is_empty() { new_stmts.push(T::from_stmt(Stmt::Expr(ExprStmt { span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs: take(&mut exprs), - })), + expr: Expr::from_exprs(take(&mut exprs)), }))) } @@ -341,10 +346,7 @@ where if !exprs.is_empty() { new_stmts.push(T::from_stmt(Stmt::Expr(ExprStmt { span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs: take(&mut exprs), - })), + expr: Expr::from_exprs(take(&mut exprs)), }))) } @@ -356,10 +358,7 @@ where if !exprs.is_empty() { new_stmts.push(T::from_stmt(Stmt::Expr(ExprStmt { span: DUMMY_SP, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs: take(&mut exprs), - })), + expr: Expr::from_exprs(take(&mut exprs)), }))) } @@ -676,6 +675,10 @@ where if let Some(Stmt::Expr(es)) = stmt.as_stmt_mut() { if let Expr::Seq(e) = &mut *es.expr { e.exprs.retain(|e| !e.is_invalid()); + if e.exprs.len() == 1 { + es.expr = e.exprs.pop().unwrap(); + return true; + } } } diff --git a/crates/swc_ecma_minifier/src/compress/optimize/util.rs b/crates/swc_ecma_minifier/src/compress/optimize/util.rs index e80572d5bef0..f53469b4f70a 100644 --- a/crates/swc_ecma_minifier/src/compress/optimize/util.rs +++ b/crates/swc_ecma_minifier/src/compress/optimize/util.rs @@ -17,11 +17,45 @@ where M: Mode, { pub(super) fn normalize_expr(&mut self, e: &mut Expr) { - if let Expr::Seq(seq) = e { - self.normalize_sequences(seq); - if seq.exprs.len() == 1 { - *e = *seq.exprs.take().into_iter().next().unwrap(); + match e { + Expr::Seq(seq) => { + for e in &mut seq.exprs { + self.normalize_expr(e); + } + + if seq.exprs.len() == 1 { + *e = *seq.exprs.take().into_iter().next().unwrap(); + self.normalize_expr(e); + return; + } + + if seq.exprs.iter().any(|v| v.is_seq()) { + let mut new = vec![]; + + for e in seq.exprs.take() { + match *e { + Expr::Seq(s) => { + new.extend(s.exprs); + } + _ => new.push(e), + } + } + + seq.exprs = new; + } + } + + Expr::Cond(cond) => { + self.normalize_expr(&mut cond.test); + self.normalize_expr(&mut cond.cons); + self.normalize_expr(&mut cond.alt); } + + Expr::Assign(a) => { + self.normalize_expr(&mut a.right); + } + + _ => {} } } diff --git a/crates/swc_ecma_minifier/src/compress/pure/misc.rs b/crates/swc_ecma_minifier/src/compress/pure/misc.rs index ad7b01d2316a..fc686c5b3a83 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/misc.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/misc.rs @@ -3,6 +3,7 @@ use std::{fmt::Write, iter::once, num::FpCategory}; use swc_atoms::js_word; use swc_common::{iter::IdentifyLast, util::take::Take, Span, DUMMY_SP}; use swc_ecma_ast::*; +use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_utils::{ ExprExt, ExprFactory, IdentUsageFinder, Type, Value::{self, Known}, @@ -19,17 +20,31 @@ use crate::{ impl Pure<'_> { pub(super) fn remove_invalid(&mut self, e: &mut Expr) { - if let Expr::Bin(BinExpr { left, right, .. }) = e { - self.remove_invalid(left); - self.remove_invalid(right); - - if left.is_invalid() { - *e = *right.take(); - self.remove_invalid(e); - } else if right.is_invalid() { - *e = *left.take(); - self.remove_invalid(e); + match e { + Expr::Seq(seq) => { + for e in &mut seq.exprs { + self.remove_invalid(e); + } + + if seq.exprs.len() == 1 { + *e = *seq.exprs.pop().unwrap(); + } + } + + Expr::Bin(BinExpr { left, right, .. }) => { + self.remove_invalid(left); + self.remove_invalid(right); + + if left.is_invalid() { + *e = *right.take(); + self.remove_invalid(e); + } else if right.is_invalid() { + *e = *left.take(); + self.remove_invalid(e); + } } + + _ => {} } } @@ -697,6 +712,12 @@ impl Pure<'_> { } pub(super) fn ignore_return_value(&mut self, e: &mut Expr, opts: DropOpts) { + if e.is_invalid() { + return; + } + + debug_assert_valid(e); + self.optimize_expr_in_bool_ctx(e, true); match e { @@ -705,6 +726,9 @@ impl Pure<'_> { e.take(); return; } + if seq.exprs.len() == 1 { + *e = *seq.exprs.remove(0); + } } Expr::Call(CallExpr { span, args, .. }) if span.has_mark(self.marks.pure) => { @@ -855,10 +879,14 @@ impl Pure<'_> { if tpl.exprs.is_empty() { e.take(); } else { - *e = Expr::Seq(SeqExpr { - span: tpl.span, - exprs: tpl.exprs.take(), - }); + if tpl.exprs.len() == 1 { + *e = *tpl.exprs.remove(0); + } else { + *e = Expr::Seq(SeqExpr { + span: tpl.span, + exprs: tpl.exprs.take(), + }); + } } return; @@ -1013,19 +1041,23 @@ impl Pure<'_> { } } - Expr::Seq(e) => { - self.drop_useless_ident_ref_in_seq(e); + Expr::Seq(seq) => { + self.drop_useless_ident_ref_in_seq(seq); - if let Some(last) = e.exprs.last_mut() { + if let Some(last) = seq.exprs.last_mut() { // Non-last elements are already processed. self.ignore_return_value(last, opts); } - let len = e.exprs.len(); - e.exprs.retain(|e| !e.is_invalid()); - if e.exprs.len() != len { + let len = seq.exprs.len(); + seq.exprs.retain(|e| !e.is_invalid()); + if seq.exprs.len() != len { self.changed = true; } + + if seq.exprs.len() == 1 { + *e = *seq.exprs.remove(0); + } return; } diff --git a/crates/swc_ecma_minifier/src/compress/pure/mod.rs b/crates/swc_ecma_minifier/src/compress/pure/mod.rs index 55c191b968fb..06f9bd0c92c7 100644 --- a/crates/swc_ecma_minifier/src/compress/pure/mod.rs +++ b/crates/swc_ecma_minifier/src/compress/pure/mod.rs @@ -4,6 +4,7 @@ use rayon::prelude::*; use swc_common::{pass::Repeated, util::take::Take, SyntaxContext, DUMMY_SP, GLOBALS}; use swc_ecma_ast::*; +use swc_ecma_transforms_optimization::debug_assert_valid; use swc_ecma_utils::{undefined, ExprCtx}; use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith, VisitWith}; #[cfg(feature = "debug")] @@ -321,8 +322,18 @@ impl VisitMut for Pure<'_> { e.visit_mut_children_with(&mut *self.with_ctx(ctx)); } - if e.is_lit() { - return; + match e { + Expr::Seq(seq) => { + if seq.exprs.len() == 1 { + *e = *seq.exprs.pop().unwrap(); + } + } + Expr::Invalid(..) | Expr::Lit(..) => return, + _ => {} + } + + if e.is_seq() { + debug_assert_valid(e); } if self.options.unused { @@ -351,8 +362,16 @@ impl VisitMut for Pure<'_> { self.eval_nested_tpl(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_tpl_as_str(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_str_addition(e); self.remove_invalid(e); @@ -374,62 +393,172 @@ impl VisitMut for Pure<'_> { self.compress_array_join(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.unsafe_optimize_fn_as_arrow(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_opt_chain(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_number_call(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_arguments_member_access(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_number_method_call(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.swap_bin_operands(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.optimize_bools(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.drop_logical_operands(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.lift_minus(e); + if e.is_seq() { + debug_assert_valid(e); + } self.convert_tpl_to_str(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.drop_useless_addition_of_str(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_useless_deletes(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.remove_useless_logical_rhs(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.handle_negated_seq(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.concat_str(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_array_method_call(e); + if e.is_seq() { + debug_assert_valid(e); + } self.eval_fn_method_call(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.eval_str_method_call(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_conds_as_logical(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_cond_with_logical_as_logical(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.lift_seqs_of_bin(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.lift_seqs_of_cond_assign(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.optimize_nullish_coalescing(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_negated_bin_eq(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.compress_useless_cond_expr(e); + if e.is_seq() { + debug_assert_valid(e); + } + self.optimize_builtin_object(e); + + if e.is_seq() { + debug_assert_valid(e); + } } fn visit_mut_expr_stmt(&mut self, s: &mut ExprStmt) { s.visit_mut_children_with(self); + if s.expr.is_seq() { + debug_assert_valid(&s.expr); + } + self.ignore_return_value( &mut s.expr, DropOpts { @@ -438,6 +567,10 @@ impl VisitMut for Pure<'_> { drop_str_lit: false, }, ); + + if s.expr.is_seq() { + debug_assert_valid(&s.expr); + } } fn visit_mut_exprs(&mut self, nodes: &mut Vec>) { @@ -689,7 +822,7 @@ impl VisitMut for Pure<'_> { #[cfg(debug_assertions)] { - e.visit_with(&mut AssertValid); + e.exprs.visit_with(&mut AssertValid); } } @@ -718,6 +851,16 @@ impl VisitMut for Pure<'_> { s.visit_mut_children_with(&mut *self.with_ctx(ctx)); } + match s { + Stmt::Expr(ExprStmt { expr, .. }) if expr.is_invalid() => { + *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); + return; + } + _ => {} + } + + debug_assert_valid(s); + #[cfg(feature = "debug")] if self.config.debug_infinite_loop { let text = dump(&*s, false); @@ -738,12 +881,20 @@ impl VisitMut for Pure<'_> { self.loop_to_for_stmt(s); + debug_assert_valid(s); + self.drop_instant_break(s); + debug_assert_valid(s); + self.optimize_labeled_stmt(s); + debug_assert_valid(s); + self.drop_useless_continue(s); + debug_assert_valid(s); + if let Stmt::Expr(es) = s { if es.expr.is_invalid() { *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); @@ -760,10 +911,7 @@ impl VisitMut for Pure<'_> { } } - #[cfg(debug_assertions)] - { - s.visit_with(&mut AssertValid); - } + debug_assert_valid(s); } fn visit_mut_stmts(&mut self, items: &mut Vec) { diff --git a/crates/swc_ecma_minifier/src/debug.rs b/crates/swc_ecma_minifier/src/debug.rs index 2b93bbf7a4bb..0a702e75223b 100644 --- a/crates/swc_ecma_minifier/src/debug.rs +++ b/crates/swc_ecma_minifier/src/debug.rs @@ -1,9 +1,5 @@ -#![cfg_attr(not(debug_assertions), allow(unused))] - use std::{ - fmt::Debug, io::Write, - mem::forget, process::{Command, Stdio}, }; @@ -11,10 +7,9 @@ use swc_common::{sync::Lrc, SourceMap, SyntaxContext}; use swc_ecma_ast::*; use swc_ecma_codegen::{text_writer::JsWriter, Emitter}; use swc_ecma_transforms_base::{fixer::fixer, hygiene::hygiene}; +pub use swc_ecma_transforms_optimization::{debug_assert_valid, AssertValid}; use swc_ecma_utils::{drop_span, DropSpan}; -use swc_ecma_visit::{ - noop_visit_mut_type, noop_visit_type, FoldWith, Visit, VisitMut, VisitMutWith, VisitWith, -}; +use swc_ecma_visit::{noop_visit_mut_type, FoldWith, VisitMut, VisitMutWith}; use tracing::debug; pub(crate) struct Debugger {} @@ -72,10 +67,7 @@ where /// If the cargo feature `debug` is disabled or the environment variable /// `SWC_RUN` is not `1`, this function is noop. pub(crate) fn invoke(module: &Module) { - #[cfg(debug_assertions)] - { - module.visit_with(&mut AssertValid); - } + debug_assert_valid(module); let _noop_sub = tracing::subscriber::set_default(tracing::subscriber::NoSubscriber::default()); @@ -160,66 +152,3 @@ pub(crate) fn invoke(module: &Module) { ) } } - -#[cfg(debug_assertions)] -struct Ctx<'a> { - v: &'a dyn Debug, -} - -#[cfg(debug_assertions)] -impl Drop for Ctx<'_> { - fn drop(&mut self) { - eprintln!("Context: {:?}", self.v); - } -} - -pub(crate) struct AssertValid; - -impl Visit for AssertValid { - noop_visit_type!(); - - #[cfg(debug_assertions)] - fn visit_expr(&mut self, n: &Expr) { - let ctx = Ctx { v: n }; - n.visit_children_with(self); - forget(ctx); - } - - #[cfg(debug_assertions)] - fn visit_invalid(&mut self, _: &Invalid) { - panic!("Invalid node found"); - } - - #[cfg(debug_assertions)] - fn visit_number(&mut self, n: &Number) { - assert!(!n.value.is_nan(), "NaN should be an identifier"); - } - - #[cfg(debug_assertions)] - fn visit_setter_prop(&mut self, p: &SetterProp) { - p.body.visit_with(self); - } - - #[cfg(debug_assertions)] - fn visit_stmt(&mut self, n: &Stmt) { - let ctx = Ctx { v: n }; - n.visit_children_with(self); - forget(ctx); - } - - #[cfg(debug_assertions)] - fn visit_tpl(&mut self, l: &Tpl) { - l.visit_children_with(self); - - assert_eq!(l.exprs.len() + 1, l.quasis.len()); - } - - #[cfg(debug_assertions)] - fn visit_var_declarators(&mut self, v: &[VarDeclarator]) { - v.visit_children_with(self); - - if v.is_empty() { - panic!("Found empty var declarators"); - } - } -} diff --git a/crates/swc_ecma_minifier/src/lib.rs b/crates/swc_ecma_minifier/src/lib.rs index fde4f07998d3..999b22e9db4a 100644 --- a/crates/swc_ecma_minifier/src/lib.rs +++ b/crates/swc_ecma_minifier/src/lib.rs @@ -104,6 +104,8 @@ pub fn optimize( let mut marks = Marks::new(); marks.unresolved_mark = extra.unresolved_mark; + debug_assert_valid(&m); + if let Some(defs) = options.compress.as_ref().map(|c| &c.global_defs) { let _timer = timer!("inline global defs"); // Apply global defs. @@ -166,6 +168,7 @@ pub fn optimize( let _timer = timer!("precompress"); m.visit_mut_with(&mut precompress_optimizer()); + debug_assert_valid(&m); } if options.compress.is_some() { @@ -175,6 +178,7 @@ pub fn optimize( marks, extra.unresolved_mark, )); + debug_assert_valid(&m); } m.visit_mut_with(&mut unique_scope()); @@ -192,7 +196,8 @@ pub fn optimize( } if let Some(options) = &options.compress { if options.unused { - perform_dce(&mut m, options, extra) + perform_dce(&mut m, options, extra); + debug_assert_valid(&m); } } diff --git a/crates/swc_ecma_minifier/tests/benches-full/echarts.js b/crates/swc_ecma_minifier/tests/benches-full/echarts.js index 4197ac8154a3..d194403fd5b8 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/echarts.js +++ b/crates/swc_ecma_minifier/tests/benches-full/echarts.js @@ -14602,8 +14602,8 @@ }, keyedColumns: getDimValueSimply, original: function(dataItem, dimName, dataIndex, dimIndex) { - var value = dataItem && (null == dataItem.value ? dataItem : dataItem.value); - return !(!this._rawData.pure && isObject(dataItem)) || dataItem instanceof Array || (this.hasItemOption = !0), parseDataValue(value instanceof Array ? value[dimIndex] : value, this._dimensionInfos[dimName]); + var dataItem1, value = dataItem && (null == dataItem.value ? dataItem : dataItem.value); + return !(!this._rawData.pure && isObject(dataItem1 = dataItem)) || dataItem1 instanceof Array || (this.hasItemOption = !0), parseDataValue(value instanceof Array ? value[dimIndex] : value, this._dimensionInfos[dimName]); }, typedArray: function(dataItem, dimName, dataIndex, dimIndex) { return dataItem[dimIndex]; @@ -31120,8 +31120,8 @@ }(api, el, dataIndex, elOption, seriesModel, morphPreparation), toBeReplacedIdx >= 0 ? group.replaceAt(el, toBeReplacedIdx) : group.add(el), el; } function doesElNeedRecreate(el, elOption) { - var elInner = inner$9(el), elOptionType = elOption.type, elOptionShape = elOption.shape, elOptionStyle = elOption.style; - return null != elOptionType && elOptionType !== elInner.customGraphicType || 'path' === elOptionType && elOptionShape && (hasOwn(elOptionShape, 'pathData') || hasOwn(elOptionShape, 'd')) && getPathData(elOptionShape) !== elInner.customPathData || 'image' === elOptionType && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== elInner.customImagePath; + var shape, elInner = inner$9(el), elOptionType = elOption.type, elOptionShape = elOption.shape, elOptionStyle = elOption.style; + return null != elOptionType && elOptionType !== elInner.customGraphicType || 'path' === elOptionType && (shape = elOptionShape) && (hasOwn(shape, 'pathData') || hasOwn(shape, 'd')) && getPathData(elOptionShape) !== elInner.customPathData || 'image' === elOptionType && hasOwn(elOptionStyle, 'image') && elOptionStyle.image !== elInner.customImagePath; } function processTxInfo(elOption, state, attachedTxInfo) { var stateOpt = state ? retrieveStateOption(elOption, state) : elOption, styleOpt = state ? retrieveStyleOptionOnState(elOption, stateOpt, EMPHASIS) : elOption.style, elType = elOption.type, txCfg = stateOpt ? stateOpt.textConfig : null, txConOptNormal = elOption.textContent, txConOpt = txConOptNormal ? state ? retrieveStateOption(txConOptNormal, state) : txConOptNormal : null; @@ -31208,7 +31208,7 @@ this._processResultIndividuals(combineResult, toIdx, null); } } else { - var morphFrom = morphDuration && from && (from !== to || isIndividualMorphingPath(from) || isCombiningPath(from)) ? from : null, transFromProps = {}; + var path, morphFrom = morphDuration && from && (from !== to || isIndividualMorphingPath(path = from) || isCombiningPath(path)) ? from : null, transFromProps = {}; prepareShapeOrExtraTransitionFrom('shape', to, morphFrom, toElOption, transFromProps, !1), prepareShapeOrExtraTransitionFrom('extra', to, morphFrom, toElOption, transFromProps, !1), prepareTransformTransitionFrom(to, morphFrom, toElOption, transFromProps, !1), prepareStyleTransitionFrom(to, morphFrom, toElOption, toElOption.style, transFromProps, !1), applyPropsFinal(to, allPropsFinal, toElOption.style), morphFrom && morphPath(morphFrom, to, elAnimationConfig), applyTransitionFrom(to, toDataIndex, toElOption, this._seriesModel, transFromProps, !1); } }, MorphPreparation.prototype._manyToOneForSingleTo = function(toIdx, fromIdxStart, fromCount) { diff --git a/crates/swc_ecma_minifier/tests/benches-full/lodash.js b/crates/swc_ecma_minifier/tests/benches-full/lodash.js index 52833ed011b3..e98ba878192a 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/lodash.js +++ b/crates/swc_ecma_minifier/tests/benches-full/lodash.js @@ -1013,7 +1013,8 @@ }; } function baseMatchesProperty(path, srcValue) { - return isKey(path) && srcValue == srcValue && !isObject(srcValue) ? matchesStrictComparable(toKey(path), srcValue) : function(object) { + var value; + return isKey(path) && (value = srcValue) == value && !isObject(value) ? matchesStrictComparable(toKey(path), srcValue) : function(object) { var objValue = get(object, path); return undefined === objValue && objValue === srcValue ? hasIn(object, path) : baseIsEqual(srcValue, objValue, 3); }; diff --git a/crates/swc_ecma_minifier/tests/benches-full/three.js b/crates/swc_ecma_minifier/tests/benches-full/three.js index 2e641758f8aa..05ddff80fb9c 100644 --- a/crates/swc_ecma_minifier/tests/benches-full/three.js +++ b/crates/swc_ecma_minifier/tests/benches-full/three.js @@ -6661,12 +6661,18 @@ depthNear: cameraVR.near, depthFar: cameraVR.far }), _currentDepthNear = cameraVR.near, _currentDepthFar = cameraVR.far); - var ipd, projL, projR, near, far, topFov, bottomFov, leftFov, rightFov, zOffset, xOffset, near2, far2, parent = camera.parent, cameras = cameraVR.cameras; + var parent = camera.parent, cameras = cameraVR.cameras; updateCamera(cameraVR, parent); for(var i = 0; i < cameras.length; i++)updateCamera(cameras[i], parent); camera.matrixWorld.copy(cameraVR.matrixWorld); for(var children = camera.children, _i3 = 0, l = children.length; _i3 < l; _i3++)children[_i3].updateMatrixWorld(!0); - return 2 === cameras.length ? (cameraLPos.setFromMatrixPosition(cameraL.matrixWorld), cameraRPos.setFromMatrixPosition(cameraR.matrixWorld), ipd = cameraLPos.distanceTo(cameraRPos), projL = cameraL.projectionMatrix.elements, projR = cameraR.projectionMatrix.elements, near = projL[14] / (projL[10] - 1), far = projL[14] / (projL[10] + 1), topFov = (projL[9] + 1) / projL[5], bottomFov = (projL[9] - 1) / projL[5], xOffset = -((zOffset = ipd / (-(leftFov = (projL[8] - 1) / projL[0]) + (rightFov = (projR[8] + 1) / projR[0]))) * leftFov), cameraL.matrixWorld.decompose(cameraVR.position, cameraVR.quaternion, cameraVR.scale), cameraVR.translateX(xOffset), cameraVR.translateZ(zOffset), cameraVR.matrixWorld.compose(cameraVR.position, cameraVR.quaternion, cameraVR.scale), cameraVR.matrixWorldInverse.copy(cameraVR.matrixWorld).invert(), near2 = near + zOffset, far2 = far + zOffset, cameraVR.projectionMatrix.makePerspective(near * leftFov - xOffset, near * rightFov + (ipd - xOffset), topFov * far / far2 * near2, bottomFov * far / far2 * near2, near2, far2)) : cameraVR.projectionMatrix.copy(cameraL.projectionMatrix), cameraVR; + return 2 === cameras.length ? function(camera, cameraL, cameraR) { + cameraLPos.setFromMatrixPosition(cameraL.matrixWorld), cameraRPos.setFromMatrixPosition(cameraR.matrixWorld); + var ipd = cameraLPos.distanceTo(cameraRPos), projL = cameraL.projectionMatrix.elements, projR = cameraR.projectionMatrix.elements, near = projL[14] / (projL[10] - 1), far = projL[14] / (projL[10] + 1), topFov = (projL[9] + 1) / projL[5], bottomFov = (projL[9] - 1) / projL[5], leftFov = (projL[8] - 1) / projL[0], rightFov = (projR[8] + 1) / projR[0], zOffset = ipd / (-leftFov + rightFov), xOffset = -(zOffset * leftFov); + cameraL.matrixWorld.decompose(camera.position, camera.quaternion, camera.scale), camera.translateX(xOffset), camera.translateZ(zOffset), camera.matrixWorld.compose(camera.position, camera.quaternion, camera.scale), camera.matrixWorldInverse.copy(camera.matrixWorld).invert(); + var near2 = near + zOffset, far2 = far + zOffset; + camera.projectionMatrix.makePerspective(near * leftFov - xOffset, near * rightFov + (ipd - xOffset), topFov * far / far2 * near2, bottomFov * far / far2 * near2, near2, far2); + }(cameraVR, cameraL, cameraR) : cameraVR.projectionMatrix.copy(cameraL.projectionMatrix), cameraVR; }; var onAnimationFrameCallback = null, animation = new WebGLAnimation(); animation.setAnimationLoop(function(time, frame) { diff --git a/crates/swc_ecma_minifier/tests/projects/output/jquery.mobile-1.4.2.js b/crates/swc_ecma_minifier/tests/projects/output/jquery.mobile-1.4.2.js index 74a7c1718139..b7a61a2146b8 100644 --- a/crates/swc_ecma_minifier/tests/projects/output/jquery.mobile-1.4.2.js +++ b/crates/swc_ecma_minifier/tests/projects/output/jquery.mobile-1.4.2.js @@ -5,7 +5,7 @@ return factory($, root, doc), $.mobile; }) : factory(root.jQuery, root, doc); }(this, document, function(jQuery, window, document1, undefined) { - var $, nsNormalizeDict, oldFind, rbrace, jqmDataRE, $1, window1, compensateToolbars, $2, undefined1, uuid, slice, _cleanData, $3, rcapitals, replaceFunction, $4, bool, docElem, refNode, fakeBody, div, $5, support, $6, self, $win, dummyFnToInitNavigate, undefined2, path, $base, dialogHashKey, undefined3, $7, path1, initialHref, $8, loc, $9, undefined4, props, testElement, vendorPrefixes, heldCall, curr, diff, handler, lastCall, $10, baseElement, base, $11, undefined5, originalWidget, keepNativeFactoryDefault, orig, $12, undefined6, pageTransitionQueue, isPageTransitioning, $13, window2, $14, defaultGetMaxScrollForTransition, $15, $16, $17, undefined7, rInitialLetter, iconposClass, $18, meta, initialContent, disabledZoom, enabledZoom, disabledInitially, $19, undefined8, rDividerListItem, origDefaultFilterCallback; + var $, nsNormalizeDict, oldFind, rbrace, jqmDataRE, $1, window1, compensateToolbars, $2, undefined1, uuid, slice, _cleanData, $3, rcapitals, replaceFunction, $4, bool, docElem, refNode, fakeBody, div, $5, support, $6, self, $win, dummyFnToInitNavigate, undefined2, path, $base, dialogHashKey, undefined3, $7, path1, initialHref, $8, undefined4, props, testElement, vendorPrefixes, heldCall, curr, diff, handler, lastCall, $9, baseElement, base, $10, undefined5, originalWidget, keepNativeFactoryDefault, orig, $11, undefined6, pageTransitionQueue, isPageTransitioning, $12, window2, $13, defaultGetMaxScrollForTransition, $14, $15, $16, undefined7, rInitialLetter, iconposClass, $17, meta, initialContent, disabledZoom, enabledZoom, disabledInitially, $18, undefined8, rDividerListItem, origDefaultFilterCallback; jQuery.mobile = {}, function($, window, undefined) { $.extend($.mobile, { version: "1.4.2", @@ -913,11 +913,15 @@ }); } } - }), ($8 = jQuery).mobile.navigate = function(url, data, noEvents) { - $8.mobile.navigate.navigator.go(url, data, noEvents); - }, $8.mobile.navigate.history = new $8.mobile.History(), $8.mobile.navigate.navigator = new $8.mobile.Navigator($8.mobile.navigate.history), loc = $8.mobile.path.parseLocation(), $8.mobile.navigate.history.add(loc.href, { - hash: loc.hash - }), $9 = jQuery, props = { + }), function($, undefined) { + $.mobile.navigate = function(url, data, noEvents) { + $.mobile.navigate.navigator.go(url, data, noEvents); + }, $.mobile.navigate.history = new $.mobile.History(), $.mobile.navigate.navigator = new $.mobile.Navigator($.mobile.navigate.history); + var loc = $.mobile.path.parseLocation(); + $.mobile.navigate.history.add(loc.href, { + hash: loc.hash + }); + }(jQuery), $8 = jQuery, props = { animation: {}, transition: {} }, testElement = document1.createElement("a"), vendorPrefixes = [ @@ -925,22 +929,22 @@ "webkit-", "moz-", "o-" - ], $9.each([ + ], $8.each([ "animation", "transition" ], function(i, test) { var testName = 0 === i ? test + "-name" : test; - $9.each(vendorPrefixes, function(j, prefix) { - if (undefined4 !== testElement.style[$9.camelCase(prefix + testName)]) return props[test].prefix = prefix, !1; - }), props[test].duration = $9.camelCase(props[test].prefix + test + "-duration"), props[test].event = $9.camelCase(props[test].prefix + test + "-end"), "" === props[test].prefix && (props[test].event = props[test].event.toLowerCase()); - }), $9.support.cssTransitions = undefined4 !== props.transition.prefix, $9.support.cssAnimations = undefined4 !== props.animation.prefix, $9(testElement).remove(), $9.fn.animationComplete = function(callback, type, fallbackTime) { + $8.each(vendorPrefixes, function(j, prefix) { + if (undefined4 !== testElement.style[$8.camelCase(prefix + testName)]) return props[test].prefix = prefix, !1; + }), props[test].duration = $8.camelCase(props[test].prefix + test + "-duration"), props[test].event = $8.camelCase(props[test].prefix + test + "-end"), "" === props[test].prefix && (props[test].event = props[test].event.toLowerCase()); + }), $8.support.cssTransitions = undefined4 !== props.transition.prefix, $8.support.cssAnimations = undefined4 !== props.animation.prefix, $8(testElement).remove(), $8.fn.animationComplete = function(callback, type, fallbackTime) { var timer, duration, that = this, animationType = type && "animation" !== type ? "transition" : "animation"; - return $9.support.cssTransitions && "transition" === animationType || $9.support.cssAnimations && "animation" === animationType ? (undefined4 === fallbackTime && ($9(this).context !== document1 && (duration = 3000 * parseFloat($9(this).css(props[animationType].duration))), (0 === duration || undefined4 === duration || isNaN(duration)) && (duration = $9.fn.animationComplete.defaultDuration)), timer = setTimeout(function() { - $9(that).off(props[animationType].event), callback.apply(that); - }, duration), $9(this).one(props[animationType].event, function() { + return $8.support.cssTransitions && "transition" === animationType || $8.support.cssAnimations && "animation" === animationType ? (undefined4 === fallbackTime && ($8(this).context !== document1 && (duration = 3000 * parseFloat($8(this).css(props[animationType].duration))), (0 === duration || undefined4 === duration || isNaN(duration)) && (duration = $8.fn.animationComplete.defaultDuration)), timer = setTimeout(function() { + $8(that).off(props[animationType].event), callback.apply(that); + }, duration), $8(this).one(props[animationType].event, function() { clearTimeout(timer), callback.call(this, arguments); - })) : (setTimeout($9.proxy(callback, this), 0), $9(this)); - }, $9.fn.animationComplete.defaultDuration = 1000, function($, window, document1, undefined) { + })) : (setTimeout($8.proxy(callback, this), 0), $8(this)); + }, $8.fn.animationComplete.defaultDuration = 1000, function($, window, document1, undefined) { var threshold, i, dataPropertyName = "virtualMouseBindings", touchTargetPropertyName = "virtualTouchID", virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split(" "), touchEventProps = "clientX clientY pageX pageY screenX screenY".split(" "), mouseHookProps = $.event.mouseHooks ? $.event.mouseHooks.props : [], mouseEventProps = $.event.props.concat(mouseHookProps), activeDocHandlers = {}, resetTimerID = 0, startX = 0, startY = 0, didScroll = !1, clickBlockList = [], blockMouseTriggers = !1, blockTouchTriggers = !1, eventCaptureSupported = "addEventListener" in document1, $document = $(document1), nextTouchID = 1, lastTouchID = 0; function getNativeEvent(event1) { for(; event1 && void 0 !== event1.originalEvent;)event1 = event1.originalEvent; @@ -1220,50 +1224,50 @@ return fn ? this.bind(event_name, fn) : this.trigger(event_name); }, $.attrFn && ($.attrFn[event_name] = !0); }(jQuery, this), base = { - element: (baseElement = ($10 = jQuery)("head").children("base")).length ? baseElement : $10("", { - href: $10.mobile.path.documentBase.hrefNoHash - }).prependTo($10("head")), + element: (baseElement = ($9 = jQuery)("head").children("base")).length ? baseElement : $9("", { + href: $9.mobile.path.documentBase.hrefNoHash + }).prependTo($9("head")), linkSelector: "[src], link[href], a[rel='external'], :jqmData(ajax='false'), a[target]", set: function(href) { - $10.mobile.dynamicBaseEnabled && $10.support.dynamicBaseTag && base.element.attr("href", $10.mobile.path.makeUrlAbsolute(href, $10.mobile.path.documentBase)); + $9.mobile.dynamicBaseEnabled && $9.support.dynamicBaseTag && base.element.attr("href", $9.mobile.path.makeUrlAbsolute(href, $9.mobile.path.documentBase)); }, rewrite: function(href, page) { - var newPath = $10.mobile.path.get(href); + var newPath = $9.mobile.path.get(href); page.find(base.linkSelector).each(function(i, link) { - var thisAttr = $10(link).is("[href]") ? "href" : $10(link).is("[src]") ? "src" : "action", thisUrl = $10(link).attr(thisAttr); - thisUrl = thisUrl.replace(location.protocol + "//" + location.host + location.pathname, ""), /^(\w+:|#|\/)/.test(thisUrl) || $10(link).attr(thisAttr, newPath + thisUrl); + var thisAttr = $9(link).is("[href]") ? "href" : $9(link).is("[src]") ? "src" : "action", thisUrl = $9(link).attr(thisAttr); + thisUrl = thisUrl.replace(location.protocol + "//" + location.host + location.pathname, ""), /^(\w+:|#|\/)/.test(thisUrl) || $9(link).attr(thisAttr, newPath + thisUrl); }); }, reset: function() { - base.element.attr("href", $10.mobile.path.documentBase.hrefNoSearch); + base.element.attr("href", $9.mobile.path.documentBase.hrefNoSearch); } - }, $10.mobile.base = base, ($11 = jQuery).mobile.widgets = {}, originalWidget = $11.widget, keepNativeFactoryDefault = $11.mobile.keepNative, $11.widget = (orig = $11.widget, function() { + }, $9.mobile.base = base, ($10 = jQuery).mobile.widgets = {}, originalWidget = $10.widget, keepNativeFactoryDefault = $10.mobile.keepNative, $10.widget = (orig = $10.widget, function() { var constructor = orig.apply(this, arguments), name = constructor.prototype.widgetName; - return constructor.initSelector = undefined5 !== constructor.prototype.initSelector ? constructor.prototype.initSelector : ":jqmData(role='" + name + "')", $11.mobile.widgets[name] = constructor, constructor; - }), $11.extend($11.widget, originalWidget), $11.mobile.document.on("create", function(event1) { - $11(event1.target).enhanceWithin(); - }), $11.widget("mobile.page", { + return constructor.initSelector = undefined5 !== constructor.prototype.initSelector ? constructor.prototype.initSelector : ":jqmData(role='" + name + "')", $10.mobile.widgets[name] = constructor, constructor; + }), $10.extend($10.widget, originalWidget), $10.mobile.document.on("create", function(event1) { + $10(event1.target).enhanceWithin(); + }), $10.widget("mobile.page", { options: { theme: "a", domCache: !1, - keepNativeDefault: $11.mobile.keepNative, + keepNativeDefault: $10.mobile.keepNative, contentTheme: null, enhanced: !1 }, _createWidget: function() { - $11.Widget.prototype._createWidget.apply(this, arguments), this._trigger("init"); + $10.Widget.prototype._createWidget.apply(this, arguments), this._trigger("init"); }, _create: function() { if (!1 === this._trigger("beforecreate")) return !1; this.options.enhanced || this._enhance(), this._on(this.element, { pagebeforehide: "removeContainerBackground", pagebeforeshow: "_handlePageBeforeShow" - }), this.element.enhanceWithin(), "dialog" === $11.mobile.getAttribute(this.element[0], "role") && $11.mobile.dialog && this.element.dialog(); + }), this.element.enhanceWithin(), "dialog" === $10.mobile.getAttribute(this.element[0], "role") && $10.mobile.dialog && this.element.dialog(); }, _enhance: function() { - var attrPrefix = "data-" + $11.mobile.ns, self = this; - this.options.role && this.element.attr("data-" + $11.mobile.ns + "role", this.options.role), this.element.attr("tabindex", "0").addClass("ui-page ui-page-theme-" + this.options.theme), this.element.find("[" + attrPrefix + "role='content']").each(function() { - var $this = $11(this), theme = this.getAttribute(attrPrefix + "theme") || undefined5; + var attrPrefix = "data-" + $10.mobile.ns, self = this; + this.options.role && this.element.attr("data-" + $10.mobile.ns + "role", this.options.role), this.element.attr("tabindex", "0").addClass("ui-page ui-page-theme-" + this.options.theme), this.element.find("[" + attrPrefix + "role='content']").each(function() { + var $this = $10(this), theme = this.getAttribute(attrPrefix + "theme") || undefined5; self.options.contentTheme = theme || self.options.contentTheme || self.options.dialog && self.options.theme || "dialog" === self.element.jqmData("role") && self.options.theme, $this.addClass("ui-content"), self.options.contentTheme && $this.addClass("ui-body-" + self.options.contentTheme), $this.attr("role", "main").addClass("ui-content"); }); }, @@ -1271,13 +1275,13 @@ var page = this.element; !page.data("mobile-page").options.domCache && page.is(":jqmData(external-page='true')") && page.bind("pagehide.remove", callback || function(e, data) { if (!data.samePage) { - var $this = $11(this), prEvent = new $11.Event("pageremove"); + var $this = $10(this), prEvent = new $10.Event("pageremove"); $this.trigger(prEvent), prEvent.isDefaultPrevented() || $this.removeWithDependents(); } }); }, _setOptions: function(o) { - undefined5 !== o.theme && this.element.removeClass("ui-page-theme-" + this.options.theme).addClass("ui-page-theme-" + o.theme), undefined5 !== o.contentTheme && this.element.find("[data-" + $11.mobile.ns + "='content']").removeClass("ui-body-" + this.options.contentTheme).addClass("ui-body-" + o.contentTheme); + undefined5 !== o.theme && this.element.removeClass("ui-page-theme-" + this.options.theme).addClass("ui-page-theme-" + o.theme), undefined5 !== o.contentTheme && this.element.find("[data-" + $10.mobile.ns + "='content']").removeClass("ui-body-" + this.options.contentTheme).addClass("ui-body-" + o.contentTheme); }, _handlePageBeforeShow: function() { this.setContainerBackground(); @@ -1293,7 +1297,7 @@ }); }, keepNativeSelector: function() { - var options = this.options, keepNative = $11.trim(options.keepNative || ""), globalValue = $11.trim($11.mobile.keepNative), optionValue = $11.trim(options.keepNativeDefault), newDefault = keepNativeFactoryDefault === globalValue ? "" : globalValue, oldDefault = "" === newDefault ? optionValue : ""; + var options = this.options, keepNative = $10.trim(options.keepNative || ""), globalValue = $10.trim($10.mobile.keepNative), optionValue = $10.trim(options.keepNativeDefault), newDefault = keepNativeFactoryDefault === globalValue ? "" : globalValue, oldDefault = "" === newDefault ? optionValue : ""; return (keepNative ? [ keepNative ] : []).concat(newDefault ? [ @@ -1302,7 +1306,7 @@ oldDefault ] : []).join(", "); } - }), ($12 = jQuery).widget("mobile.pagecontainer", { + }), ($11 = jQuery).widget("mobile.pagecontainer", { options: { theme: "a" }, @@ -1315,7 +1319,7 @@ navigate: "_filterNavigateEvents" }), this._on({ pagechange: "_afterContentChange" - }), this.window.one("navigate", $12.proxy(function() { + }), this.window.one("navigate", $11.proxy(function() { this.setLastScrollEnabled = !0; }, this)); }, @@ -1340,38 +1344,38 @@ } }, _delayedRecordScroll: function() { - setTimeout($12.proxy(this, "_recordScroll"), 100); + setTimeout($11.proxy(this, "_recordScroll"), 100); }, _getScroll: function() { return this.window.scrollTop(); }, _getMinScroll: function() { - return $12.mobile.minScrollBack; + return $11.mobile.minScrollBack; }, _getDefaultScroll: function() { - return $12.mobile.defaultHomeScroll; + return $11.mobile.defaultHomeScroll; }, _filterNavigateEvents: function(e, data) { var url; - !(e.originalEvent && e.originalEvent.isDefaultPrevented()) && ((url = e.originalEvent.type.indexOf("hashchange") > -1 ? data.state.hash : data.state.url) || (url = this._getHash()), url && "#" !== url && 0 !== url.indexOf("#" + $12.mobile.path.uiStateKey) || (url = location.href), this._handleNavigate(url, data.state)); + !(e.originalEvent && e.originalEvent.isDefaultPrevented()) && ((url = e.originalEvent.type.indexOf("hashchange") > -1 ? data.state.hash : data.state.url) || (url = this._getHash()), url && "#" !== url && 0 !== url.indexOf("#" + $11.mobile.path.uiStateKey) || (url = location.href), this._handleNavigate(url, data.state)); }, _getHash: function() { - return $12.mobile.path.parseLocation().hash; + return $11.mobile.path.parseLocation().hash; }, getActivePage: function() { return this.activePage; }, _getInitialContent: function() { - return $12.mobile.firstPage; + return $11.mobile.firstPage; }, _getHistory: function() { - return $12.mobile.navigate.history; + return $11.mobile.navigate.history; }, _getActiveHistory: function() { - return $12.mobile.navigate.history.getActive(); + return $11.mobile.navigate.history.getActive(); }, _getDocumentBase: function() { - return $12.mobile.path.documentBase; + return $11.mobile.path.documentBase; }, back: function() { this.go(-1); @@ -1380,10 +1384,10 @@ this.go(1); }, go: function(steps) { - if ($12.mobile.hashListeningEnabled) window.history.go(steps); + if ($11.mobile.hashListeningEnabled) window.history.go(steps); else { - var activeIndex = $12.mobile.navigate.history.activeIndex, index = activeIndex + parseInt(steps, 10), url = $12.mobile.navigate.history.stack[index].url; - $12.mobile.navigate.history.activeIndex = index, $12.mobile.navigate.history.previousIndex = activeIndex, this.change(url, { + var activeIndex = $11.mobile.navigate.history.activeIndex, index = activeIndex + parseInt(steps, 10), url = $11.mobile.navigate.history.stack[index].url; + $11.mobile.navigate.history.activeIndex = index, $11.mobile.navigate.history.previousIndex = activeIndex, this.change(url, { direction: steps >= 1 ? "forward" : "back", changeHash: !1, fromHashChange: !0 @@ -1392,34 +1396,34 @@ }, _handleDestination: function(to) { var history1; - return "string" === $12.type(to) && (to = $12.mobile.path.stripHash(to)), to && (history1 = this._getHistory(), (to = $12.mobile.path.isPath(to) ? to : $12.mobile.path.makeUrlAbsolute("#" + to, this._getDocumentBase())) === $12.mobile.path.makeUrlAbsolute("#" + history1.initialDst, this._getDocumentBase()) && history1.stack.length && history1.stack[0].url !== history1.initialDst.replace($12.mobile.dialogHashKey, "") && (to = this._getInitialContent())), to || this._getInitialContent(); + return "string" === $11.type(to) && (to = $11.mobile.path.stripHash(to)), to && (history1 = this._getHistory(), (to = $11.mobile.path.isPath(to) ? to : $11.mobile.path.makeUrlAbsolute("#" + to, this._getDocumentBase())) === $11.mobile.path.makeUrlAbsolute("#" + history1.initialDst, this._getDocumentBase()) && history1.stack.length && history1.stack[0].url !== history1.initialDst.replace($11.mobile.dialogHashKey, "") && (to = this._getInitialContent())), to || this._getInitialContent(); }, _handleDialog: function(changePageOptions, data) { var to, active, activeContent = this.getActivePage(); - return activeContent && !activeContent.hasClass("ui-dialog") ? ("back" === data.direction ? this.back() : this.forward(), !1) : (to = data.pageUrl, active = this._getActiveHistory(), $12.extend(changePageOptions, { + return activeContent && !activeContent.hasClass("ui-dialog") ? ("back" === data.direction ? this.back() : this.forward(), !1) : (to = data.pageUrl, active = this._getActiveHistory(), $11.extend(changePageOptions, { role: active.role, transition: active.transition, reverse: "back" === data.direction }), to); }, _handleNavigate: function(url, data) { - var to = $12.mobile.path.stripHash(url), history1 = this._getHistory(), transition = 0 === history1.stack.length ? "none" : undefined6, changePageOptions = { + var to = $11.mobile.path.stripHash(url), history1 = this._getHistory(), transition = 0 === history1.stack.length ? "none" : undefined6, changePageOptions = { changeHash: !1, fromHashChange: !0, reverse: "back" === data.direction }; - $12.extend(changePageOptions, data, { + $11.extend(changePageOptions, data, { transition: (history1.getLast() || {}).transition || transition - }), (!(history1.activeIndex > 0 && to.indexOf($12.mobile.dialogHashKey) > -1) || history1.initialDst === to || !1 !== (to = this._handleDialog(changePageOptions, data))) && this._changeContent(this._handleDestination(to), changePageOptions); + }), (!(history1.activeIndex > 0 && to.indexOf($11.mobile.dialogHashKey) > -1) || history1.initialDst === to || !1 !== (to = this._handleDialog(changePageOptions, data))) && this._changeContent(this._handleDestination(to), changePageOptions); }, _changeContent: function(to, opts) { - $12.mobile.changePage(to, opts); + $11.mobile.changePage(to, opts); }, _getBase: function() { - return $12.mobile.base; + return $11.mobile.base; }, _getNs: function() { - return $12.mobile.ns; + return $11.mobile.ns; }, _enhance: function(content, role) { return content.page({ @@ -1431,13 +1435,13 @@ }, _find: function(absUrl) { var page, fileUrl = this._createFileUrl(absUrl), dataUrl = this._createDataUrl(absUrl), initialContent = this._getInitialContent(); - return 0 === (page = this.element.children("[data-" + this._getNs() + "url='" + dataUrl + "']")).length && dataUrl && !$12.mobile.path.isPath(dataUrl) && (page = this.element.children($12.mobile.path.hashToSelector("#" + dataUrl)).attr("data-" + this._getNs() + "url", dataUrl).jqmData("url", dataUrl)), 0 === page.length && $12.mobile.path.isFirstPageUrl(fileUrl) && initialContent && initialContent.parent().length && (page = $12(initialContent)), page; + return 0 === (page = this.element.children("[data-" + this._getNs() + "url='" + dataUrl + "']")).length && dataUrl && !$11.mobile.path.isPath(dataUrl) && (page = this.element.children($11.mobile.path.hashToSelector("#" + dataUrl)).attr("data-" + this._getNs() + "url", dataUrl).jqmData("url", dataUrl)), 0 === page.length && $11.mobile.path.isFirstPageUrl(fileUrl) && initialContent && initialContent.parent().length && (page = $11(initialContent)), page; }, _getLoader: function() { - return $12.mobile.loading(); + return $11.mobile.loading(); }, _showLoading: function(delay, theme, msg, textonly) { - !this._loadMsg && (this._loadMsg = setTimeout($12.proxy(function() { + !this._loadMsg && (this._loadMsg = setTimeout($11.proxy(function() { this._getLoader().loader("show", theme, msg, textonly), this._loadMsg = 0; }, this), delay)); }, @@ -1445,27 +1449,27 @@ clearTimeout(this._loadMsg), this._loadMsg = 0, this._getLoader().loader("hide"); }, _showError: function() { - this._hideLoading(), this._showLoading(0, $12.mobile.pageLoadErrorMessageTheme, $12.mobile.pageLoadErrorMessage, !0), setTimeout($12.proxy(this, "_hideLoading"), 1500); + this._hideLoading(), this._showLoading(0, $11.mobile.pageLoadErrorMessageTheme, $11.mobile.pageLoadErrorMessage, !0), setTimeout($11.proxy(this, "_hideLoading"), 1500); }, _parse: function(html, fileUrl) { - var page, all = $12("
"); - return all.get(0).innerHTML = html, (page = all.find(":jqmData(role='page'), :jqmData(role='dialog')").first()).length || (page = $12("
" + (html.split(/<\/?body[^>]*>/gim)[1] || "") + "
")), page.attr("data-" + this._getNs() + "url", $12.mobile.path.convertUrlToDataUrl(fileUrl)).attr("data-" + this._getNs() + "external-page", !0), page; + var page, all = $11("
"); + return all.get(0).innerHTML = html, (page = all.find(":jqmData(role='page'), :jqmData(role='dialog')").first()).length || (page = $11("
" + (html.split(/<\/?body[^>]*>/gim)[1] || "") + "
")), page.attr("data-" + this._getNs() + "url", $11.mobile.path.convertUrlToDataUrl(fileUrl)).attr("data-" + this._getNs() + "external-page", !0), page; }, _setLoadedTitle: function(page, html) { var newPageTitle = html.match(/]*>([^<]*)/) && RegExp.$1; - newPageTitle && !page.jqmData("title") && (newPageTitle = $12("
" + newPageTitle + "
").text(), page.jqmData("title", newPageTitle)); + newPageTitle && !page.jqmData("title") && (newPageTitle = $11("
" + newPageTitle + "
").text(), page.jqmData("title", newPageTitle)); }, _isRewritableBaseTag: function() { - return $12.mobile.dynamicBaseEnabled && !$12.support.dynamicBaseTag; + return $11.mobile.dynamicBaseEnabled && !$11.support.dynamicBaseTag; }, _createDataUrl: function(absoluteUrl) { - return $12.mobile.path.convertUrlToDataUrl(absoluteUrl); + return $11.mobile.path.convertUrlToDataUrl(absoluteUrl); }, _createFileUrl: function(absoluteUrl) { - return $12.mobile.path.getFilePath(absoluteUrl); + return $11.mobile.path.getFilePath(absoluteUrl); }, _triggerWithDeprecated: function(name, data, page) { - var deprecatedEvent = $12.Event("page" + name), newEvent = $12.Event(this.widgetName + name); + var deprecatedEvent = $11.Event("page" + name), newEvent = $11.Event(this.widgetName + name); return (page || this.element).trigger(deprecatedEvent, data), this.element.trigger(newEvent, data), { deprecatedEvent: deprecatedEvent, event: newEvent @@ -1473,9 +1477,9 @@ }, _loadSuccess: function(absUrl, triggerData, settings, deferred) { var fileUrl = this._createFileUrl(absUrl), dataUrl = this._createDataUrl(absUrl); - return $12.proxy(function(html, textStatus, xhr) { + return $11.proxy(function(html, textStatus, xhr) { var content, pageElemRegex = RegExp("(<[^>]+\\bdata-" + this._getNs() + "role=[\"']?page[\"']?[^>]*>)"), dataUrlRegex = RegExp("\\bdata-" + this._getNs() + "url=[\"']?([^\"'>]*)[\"']?"); - pageElemRegex.test(html) && RegExp.$1 && dataUrlRegex.test(RegExp.$1) && RegExp.$1 && (fileUrl = $12.mobile.path.getFilePath($12("
" + RegExp.$1 + "
").text())), undefined6 === settings.prefetch && this._getBase().set(fileUrl), content = this._parse(html, fileUrl), this._setLoadedTitle(content, html), triggerData.xhr = xhr, triggerData.textStatus = textStatus, triggerData.page = content, triggerData.content = content, this._trigger("load", undefined6, triggerData) && (this._isRewritableBaseTag() && content && this._getBase().rewrite(fileUrl, content), this._include(content, settings), absUrl.indexOf("&" + $12.mobile.subPageUrlKey) > -1 && (content = this.element.children("[data-" + this._getNs() + "url='" + dataUrl + "']")), settings.showLoadMsg && this._hideLoading(), this.element.trigger("pageload"), deferred.resolve(absUrl, settings, content)); + pageElemRegex.test(html) && RegExp.$1 && dataUrlRegex.test(RegExp.$1) && RegExp.$1 && (fileUrl = $11.mobile.path.getFilePath($11("
" + RegExp.$1 + "
").text())), undefined6 === settings.prefetch && this._getBase().set(fileUrl), content = this._parse(html, fileUrl), this._setLoadedTitle(content, html), triggerData.xhr = xhr, triggerData.textStatus = textStatus, triggerData.page = content, triggerData.content = content, this._trigger("load", undefined6, triggerData) && (this._isRewritableBaseTag() && content && this._getBase().rewrite(fileUrl, content), this._include(content, settings), absUrl.indexOf("&" + $11.mobile.subPageUrlKey) > -1 && (content = this.element.children("[data-" + this._getNs() + "url='" + dataUrl + "']")), settings.showLoadMsg && this._hideLoading(), this.element.trigger("pageload"), deferred.resolve(absUrl, settings, content)); }, this); }, _loadDefaults: { @@ -1488,8 +1492,8 @@ loadMsgDelay: 50 }, load: function(url, options) { - var fileUrl, dataUrl, pblEvent, triggerData, deferred = options && options.deferred || $12.Deferred(), settings = $12.extend({}, this._loadDefaults, options), content = null, absUrl = $12.mobile.path.makeUrlAbsolute(url, this._findBaseWithDefault()); - if (settings.reload = settings.reloadPage, settings.data && "get" === settings.type && (absUrl = $12.mobile.path.addSearchParams(absUrl, settings.data), settings.data = undefined6), settings.data && "post" === settings.type && (settings.reload = !0), fileUrl = this._createFileUrl(absUrl), dataUrl = this._createDataUrl(absUrl), 0 === (content = this._find(absUrl)).length && $12.mobile.path.isEmbeddedPage(fileUrl) && !$12.mobile.path.isFirstPageUrl(fileUrl)) { + var fileUrl, dataUrl, pblEvent, triggerData, deferred = options && options.deferred || $11.Deferred(), settings = $11.extend({}, this._loadDefaults, options), content = null, absUrl = $11.mobile.path.makeUrlAbsolute(url, this._findBaseWithDefault()); + if (settings.reload = settings.reloadPage, settings.data && "get" === settings.type && (absUrl = $11.mobile.path.addSearchParams(absUrl, settings.data), settings.data = undefined6), settings.data && "post" === settings.type && (settings.reload = !0), fileUrl = this._createFileUrl(absUrl), dataUrl = this._createDataUrl(absUrl), 0 === (content = this._find(absUrl)).length && $11.mobile.path.isEmbeddedPage(fileUrl) && !$11.mobile.path.isFirstPageUrl(fileUrl)) { deferred.reject(absUrl, settings); return; } @@ -1504,11 +1508,11 @@ deferred: deferred, options: settings }, !((pblEvent = this._triggerWithDeprecated("beforeload", triggerData)).deprecatedEvent.isDefaultPrevented() || pblEvent.event.isDefaultPrevented())) { - if (settings.showLoadMsg && this._showLoading(settings.loadMsgDelay), undefined6 === settings.prefetch && this._getBase().reset(), !($12.mobile.allowCrossDomainPages || $12.mobile.path.isSameDomain($12.mobile.path.documentUrl, absUrl))) { + if (settings.showLoadMsg && this._showLoading(settings.loadMsgDelay), undefined6 === settings.prefetch && this._getBase().reset(), !($11.mobile.allowCrossDomainPages || $11.mobile.path.isSameDomain($11.mobile.path.documentUrl, absUrl))) { deferred.reject(absUrl, settings); return; } - $12.ajax({ + $11.ajax({ url: fileUrl, type: settings.type, data: settings.data, @@ -1520,14 +1524,14 @@ } }, _loadError: function(absUrl, triggerData, settings, deferred) { - return $12.proxy(function(xhr, textStatus, errorThrown) { - this._getBase().set($12.mobile.path.get()), triggerData.xhr = xhr, triggerData.textStatus = textStatus, triggerData.errorThrown = errorThrown; + return $11.proxy(function(xhr, textStatus, errorThrown) { + this._getBase().set($11.mobile.path.get()), triggerData.xhr = xhr, triggerData.textStatus = textStatus, triggerData.errorThrown = errorThrown; var plfEvent = this._triggerWithDeprecated("loadfailed", triggerData); !(plfEvent.deprecatedEvent.isDefaultPrevented() || plfEvent.event.isDefaultPrevented()) && (settings.showLoadMsg && this._showError(), deferred.reject(absUrl, settings)); }, this); }, _getTransitionHandler: function(transition) { - return transition = $12.mobile._maybeDegradeTransition(transition), $12.mobile.transitionHandlers[transition] || $12.mobile.defaultTransitionHandler; + return transition = $11.mobile._maybeDegradeTransition(transition), $11.mobile.transitionHandlers[transition] || $11.mobile.defaultTransitionHandler; }, _triggerCssTransitionEvents: function(to, from, prefix) { var samePage = !1; @@ -1535,44 +1539,44 @@ nextPage: to, samePage: samePage }, from)), this._triggerWithDeprecated(prefix + "show", { - prevPage: from || $12("") + prevPage: from || $11("") }, to); }, _cssTransition: function(to, from, options) { var promise, transition = options.transition, reverse = options.reverse, deferred = options.deferred; this._triggerCssTransitionEvents(to, from, "before"), this._hideLoading(), (promise = new (this._getTransitionHandler(transition))(transition, reverse, to, from).transition()).done(function() { deferred.resolve.apply(deferred, arguments); - }), promise.done($12.proxy(function() { + }), promise.done($11.proxy(function() { this._triggerCssTransitionEvents(to, from); }, this)); }, _releaseTransitionLock: function() { - isPageTransitioning = !1, pageTransitionQueue.length > 0 && $12.mobile.changePage.apply(null, pageTransitionQueue.pop()); + isPageTransitioning = !1, pageTransitionQueue.length > 0 && $11.mobile.changePage.apply(null, pageTransitionQueue.pop()); }, _removeActiveLinkClass: function(force) { - $12.mobile.removeActiveLinkClass(force); + $11.mobile.removeActiveLinkClass(force); }, _loadUrl: function(to, triggerData, settings) { - settings.target = to, settings.deferred = $12.Deferred(), this.load(to, settings), settings.deferred.done($12.proxy(function(url, options, content) { + settings.target = to, settings.deferred = $11.Deferred(), this.load(to, settings), settings.deferred.done($11.proxy(function(url, options, content) { isPageTransitioning = !1, options.absUrl = triggerData.absUrl, this.transition(content, triggerData, options); - }, this)), settings.deferred.fail($12.proxy(function() { + }, this)), settings.deferred.fail($11.proxy(function() { this._removeActiveLinkClass(!0), this._releaseTransitionLock(), this._triggerWithDeprecated("changefailed", triggerData); }, this)); }, _triggerPageBeforeChange: function(to, triggerData, settings) { - var pbcEvent = new $12.Event("pagebeforechange"); - return $12.extend(triggerData, { + var pbcEvent = new $11.Event("pagebeforechange"); + return $11.extend(triggerData, { toPage: to, options: settings - }), "string" === $12.type(to) ? triggerData.absUrl = $12.mobile.path.makeUrlAbsolute(to, this._findBaseWithDefault()) : triggerData.absUrl = settings.absUrl, this.element.trigger(pbcEvent, triggerData), !pbcEvent.isDefaultPrevented(); + }), "string" === $11.type(to) ? triggerData.absUrl = $11.mobile.path.makeUrlAbsolute(to, this._findBaseWithDefault()) : triggerData.absUrl = settings.absUrl, this.element.trigger(pbcEvent, triggerData), !pbcEvent.isDefaultPrevented(); }, change: function(to, options) { if (isPageTransitioning) { pageTransitionQueue.unshift(arguments); return; } - var settings = $12.extend({}, $12.mobile.changePage.defaults, options), triggerData = {}; - settings.fromPage = settings.fromPage || this.activePage, this._triggerPageBeforeChange(to, triggerData, settings) && (to = triggerData.toPage, "string" === $12.type(to) ? (isPageTransitioning = !0, this._loadUrl(to, triggerData, settings)) : this.transition(to, triggerData, settings)); + var settings = $11.extend({}, $11.mobile.changePage.defaults, options), triggerData = {}; + settings.fromPage = settings.fromPage || this.activePage, this._triggerPageBeforeChange(to, triggerData, settings) && (to = triggerData.toPage, "string" === $11.type(to) ? (isPageTransitioning = !0, this._loadUrl(to, triggerData, settings)) : this.transition(to, triggerData, settings)); }, transition: function(toPage, triggerData, settings) { var fromPage, url, pageUrl, active, activeIsInitialPage, historyDir, pageTitle, isDialog, alreadyThere, newPageTitle, params, cssTransitionDeferred, beforeTransition; @@ -1584,8 +1588,8 @@ return; } if (!(!this._triggerPageBeforeChange(toPage, triggerData, settings) || (beforeTransition = this._triggerWithDeprecated("beforetransition", triggerData)).deprecatedEvent.isDefaultPrevented() || beforeTransition.event.isDefaultPrevented())) { - if (isPageTransitioning = !0, toPage[0] !== $12.mobile.firstPage[0] || settings.dataUrl || (settings.dataUrl = $12.mobile.path.documentUrl.hrefNoHash), fromPage = settings.fromPage, pageUrl = url = settings.dataUrl && $12.mobile.path.convertUrlToDataUrl(settings.dataUrl) || toPage.jqmData("url"), $12.mobile.path.getFilePath(url), active = $12.mobile.navigate.history.getActive(), activeIsInitialPage = 0 === $12.mobile.navigate.history.activeIndex, historyDir = 0, pageTitle = document1.title, isDialog = ("dialog" === settings.role || "dialog" === toPage.jqmData("role")) && !0 !== toPage.jqmData("dialog"), fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition) { - isPageTransitioning = !1, this._triggerWithDeprecated("transition", triggerData), this.element.trigger("pagechange", triggerData), settings.fromHashChange && $12.mobile.navigate.history.direct({ + if (isPageTransitioning = !0, toPage[0] !== $11.mobile.firstPage[0] || settings.dataUrl || (settings.dataUrl = $11.mobile.path.documentUrl.hrefNoHash), fromPage = settings.fromPage, pageUrl = url = settings.dataUrl && $11.mobile.path.convertUrlToDataUrl(settings.dataUrl) || toPage.jqmData("url"), $11.mobile.path.getFilePath(url), active = $11.mobile.navigate.history.getActive(), activeIsInitialPage = 0 === $11.mobile.navigate.history.activeIndex, historyDir = 0, pageTitle = document1.title, isDialog = ("dialog" === settings.role || "dialog" === toPage.jqmData("role")) && !0 !== toPage.jqmData("dialog"), fromPage && fromPage[0] === toPage[0] && !settings.allowSamePageTransition) { + isPageTransitioning = !1, this._triggerWithDeprecated("transition", triggerData), this.element.trigger("pagechange", triggerData), settings.fromHashChange && $11.mobile.navigate.history.direct({ url: url }); return; @@ -1594,26 +1598,26 @@ role: settings.role }), settings.fromHashChange && (historyDir = "back" === settings.direction ? -1 : 1); try { - document1.activeElement && "body" !== document1.activeElement.nodeName.toLowerCase() ? $12(document1.activeElement).blur() : $12("input:focus, textarea:focus, select:focus").blur(); + document1.activeElement && "body" !== document1.activeElement.nodeName.toLowerCase() ? $11(document1.activeElement).blur() : $11("input:focus, textarea:focus, select:focus").blur(); } catch (e) {} - alreadyThere = !1, isDialog && active && (active.url && active.url.indexOf($12.mobile.dialogHashKey) > -1 && this.activePage && !this.activePage.hasClass("ui-dialog") && $12.mobile.navigate.history.activeIndex > 0 && (settings.changeHash = !1, alreadyThere = !0), url = active.url || "", !alreadyThere && url.indexOf("#") > -1 ? url += $12.mobile.dialogHashKey : url += "#" + $12.mobile.dialogHashKey, 0 === $12.mobile.navigate.history.activeIndex && url === $12.mobile.navigate.history.initialDst && (url += $12.mobile.dialogHashKey)), (newPageTitle = active ? toPage.jqmData("title") || toPage.children(":jqmData(role='header')").find(".ui-title").text() : pageTitle) && pageTitle === document1.title && (pageTitle = newPageTitle), toPage.jqmData("title") || toPage.jqmData("title", pageTitle), settings.transition = settings.transition || (historyDir && !activeIsInitialPage ? active.transition : undefined6) || (isDialog ? $12.mobile.defaultDialogTransition : $12.mobile.defaultPageTransition), !historyDir && alreadyThere && ($12.mobile.navigate.history.getActive().pageUrl = pageUrl), url && !settings.fromHashChange && (!$12.mobile.path.isPath(url) && 0 > url.indexOf("#") && (url = "#" + url), params = { + alreadyThere = !1, isDialog && active && (active.url && active.url.indexOf($11.mobile.dialogHashKey) > -1 && this.activePage && !this.activePage.hasClass("ui-dialog") && $11.mobile.navigate.history.activeIndex > 0 && (settings.changeHash = !1, alreadyThere = !0), url = active.url || "", !alreadyThere && url.indexOf("#") > -1 ? url += $11.mobile.dialogHashKey : url += "#" + $11.mobile.dialogHashKey, 0 === $11.mobile.navigate.history.activeIndex && url === $11.mobile.navigate.history.initialDst && (url += $11.mobile.dialogHashKey)), (newPageTitle = active ? toPage.jqmData("title") || toPage.children(":jqmData(role='header')").find(".ui-title").text() : pageTitle) && pageTitle === document1.title && (pageTitle = newPageTitle), toPage.jqmData("title") || toPage.jqmData("title", pageTitle), settings.transition = settings.transition || (historyDir && !activeIsInitialPage ? active.transition : undefined6) || (isDialog ? $11.mobile.defaultDialogTransition : $11.mobile.defaultPageTransition), !historyDir && alreadyThere && ($11.mobile.navigate.history.getActive().pageUrl = pageUrl), url && !settings.fromHashChange && (!$11.mobile.path.isPath(url) && 0 > url.indexOf("#") && (url = "#" + url), params = { transition: settings.transition, title: pageTitle, pageUrl: pageUrl, role: settings.role - }, !1 !== settings.changeHash && $12.mobile.hashListeningEnabled ? $12.mobile.navigate(url, params, !0) : toPage[0] !== $12.mobile.firstPage[0] && $12.mobile.navigate.history.add(url, params)), document1.title = pageTitle, $12.mobile.activePage = toPage, this.activePage = toPage, settings.reverse = settings.reverse || historyDir < 0, cssTransitionDeferred = $12.Deferred(), this._cssTransition(toPage, fromPage, { + }, !1 !== settings.changeHash && $11.mobile.hashListeningEnabled ? $11.mobile.navigate(url, params, !0) : toPage[0] !== $11.mobile.firstPage[0] && $11.mobile.navigate.history.add(url, params)), document1.title = pageTitle, $11.mobile.activePage = toPage, this.activePage = toPage, settings.reverse = settings.reverse || historyDir < 0, cssTransitionDeferred = $11.Deferred(), this._cssTransition(toPage, fromPage, { transition: settings.transition, reverse: settings.reverse, deferred: cssTransitionDeferred - }), cssTransitionDeferred.done($12.proxy(function(name, reverse, $to, $from, alreadyFocused) { - $12.mobile.removeActiveLinkClass(), settings.duplicateCachedPage && settings.duplicateCachedPage.remove(), alreadyFocused || $12.mobile.focusPage(toPage), this._releaseTransitionLock(), this.element.trigger("pagechange", triggerData), this._triggerWithDeprecated("transition", triggerData); + }), cssTransitionDeferred.done($11.proxy(function(name, reverse, $to, $from, alreadyFocused) { + $11.mobile.removeActiveLinkClass(), settings.duplicateCachedPage && settings.duplicateCachedPage.remove(), alreadyFocused || $11.mobile.focusPage(toPage), this._releaseTransitionLock(), this.element.trigger("pagechange", triggerData), this._triggerWithDeprecated("transition", triggerData); }, this)); } }, _findBaseWithDefault: function() { - return this.activePage && $12.mobile.getClosestBaseUrl(this.activePage) || $12.mobile.path.documentBase.hrefNoHash; + return this.activePage && $11.mobile.getClosestBaseUrl(this.activePage) || $11.mobile.path.documentBase.hrefNoHash; } - }), $12.mobile.navreadyDeferred = $12.Deferred(), pageTransitionQueue = [], isPageTransitioning = !1, function($, undefined) { + }), $11.mobile.navreadyDeferred = $11.Deferred(), pageTransitionQueue = [], isPageTransitioning = !1, function($, undefined) { var domreadyDeferred = $.Deferred(), loadDeferred = $.Deferred(), documentUrl = $.mobile.path.documentUrl, $lastVClicked = null; function findClosestLink(ele) { for(; ele && ("string" != typeof ele.nodeName || "a" !== ele.nodeName.toLowerCase());)ele = ele.parentNode; @@ -1730,27 +1734,27 @@ }), $.when(domreadyDeferred, $.mobile.navreadyDeferred).done(function() { $.mobile._registerInternalEvents(); }); - }(jQuery), $13 = jQuery, window2 = this, $13.mobile.Transition = function() { + }(jQuery), $12 = jQuery, window2 = this, $12.mobile.Transition = function() { this.init.apply(this, arguments); - }, $13.extend($13.mobile.Transition.prototype, { + }, $12.extend($12.mobile.Transition.prototype, { toPreClass: " ui-page-pre-in", init: function(name, reverse, $to, $from) { - $13.extend(this, { + $12.extend(this, { name: name, reverse: reverse, $to: $to, $from: $from, - deferred: new $13.Deferred() + deferred: new $12.Deferred() }); }, cleanFrom: function() { - this.$from.removeClass($13.mobile.activePageClass + " out in reverse " + this.name).height(""); + this.$from.removeClass($12.mobile.activePageClass + " out in reverse " + this.name).height(""); }, beforeDoneIn: function() {}, beforeDoneOut: function() {}, beforeStartOut: function() {}, doneIn: function() { - this.beforeDoneIn(), this.$to.removeClass("out in reverse " + this.name).height(""), this.toggleViewportClass(), $13.mobile.window.scrollTop() !== this.toScroll && this.scrollPage(), this.sequential || this.$to.addClass($13.mobile.activePageClass), this.deferred.resolve(this.name, this.reverse, this.$to, this.$from, !0); + this.beforeDoneIn(), this.$to.removeClass("out in reverse " + this.name).height(""), this.toggleViewportClass(), $12.mobile.window.scrollTop() !== this.toScroll && this.scrollPage(), this.sequential || this.$to.addClass($12.mobile.activePageClass), this.deferred.resolve(this.name, this.reverse, this.$to, this.$from, !0); }, doneOut: function(screenHeight, reverseClass, none, preventFocus) { this.beforeDoneOut(), this.startIn(screenHeight, reverseClass, none, preventFocus); @@ -1759,26 +1763,26 @@ this.$to.css("z-index", -10), callback.call(this), this.$to.css("z-index", ""); }, scrollPage: function() { - $13.event.special.scrollstart.enabled = !1, ($13.mobile.hideUrlBar || this.toScroll !== $13.mobile.defaultHomeScroll) && window2.scrollTo(0, this.toScroll), setTimeout(function() { - $13.event.special.scrollstart.enabled = !0; + $12.event.special.scrollstart.enabled = !1, ($12.mobile.hideUrlBar || this.toScroll !== $12.mobile.defaultHomeScroll) && window2.scrollTo(0, this.toScroll), setTimeout(function() { + $12.event.special.scrollstart.enabled = !0; }, 150); }, startIn: function(screenHeight, reverseClass, none, preventFocus) { this.hideIn(function() { - this.$to.addClass($13.mobile.activePageClass + this.toPreClass), preventFocus || $13.mobile.focusPage(this.$to), this.$to.height(screenHeight + this.toScroll), none || this.scrollPage(); - }), this.$to.removeClass(this.toPreClass).addClass(this.name + " in " + reverseClass), none ? this.doneIn() : this.$to.animationComplete($13.proxy(function() { + this.$to.addClass($12.mobile.activePageClass + this.toPreClass), preventFocus || $12.mobile.focusPage(this.$to), this.$to.height(screenHeight + this.toScroll), none || this.scrollPage(); + }), this.$to.removeClass(this.toPreClass).addClass(this.name + " in " + reverseClass), none ? this.doneIn() : this.$to.animationComplete($12.proxy(function() { this.doneIn(); }, this)); }, startOut: function(screenHeight, reverseClass, none) { - this.beforeStartOut(screenHeight, reverseClass, none), this.$from.height(screenHeight + $13.mobile.window.scrollTop()).addClass(this.name + " out" + reverseClass); + this.beforeStartOut(screenHeight, reverseClass, none), this.$from.height(screenHeight + $12.mobile.window.scrollTop()).addClass(this.name + " out" + reverseClass); }, toggleViewportClass: function() { - $13.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-" + this.name); + $12.mobile.pageContainer.toggleClass("ui-mobile-viewport-transitioning viewport-" + this.name); }, transition: function() { - var none, reverseClass = this.reverse ? " reverse" : "", screenHeight = $13.mobile.getScreenHeight(), maxTransitionOverride = !1 !== $13.mobile.maxTransitionWidth && $13.mobile.window.width() > $13.mobile.maxTransitionWidth; - return this.toScroll = $13.mobile.navigate.history.getActive().lastScroll || $13.mobile.defaultHomeScroll, none = !$13.support.cssTransitions || !$13.support.cssAnimations || maxTransitionOverride || !this.name || "none" === this.name || Math.max($13.mobile.window.scrollTop(), this.toScroll) > $13.mobile.getMaxScrollForTransition(), this.toggleViewportClass(), this.$from && !none ? this.startOut(screenHeight, reverseClass, none) : this.doneOut(screenHeight, reverseClass, none, !0), this.deferred.promise(); + var none, reverseClass = this.reverse ? " reverse" : "", screenHeight = $12.mobile.getScreenHeight(), maxTransitionOverride = !1 !== $12.mobile.maxTransitionWidth && $12.mobile.window.width() > $12.mobile.maxTransitionWidth; + return this.toScroll = $12.mobile.navigate.history.getActive().lastScroll || $12.mobile.defaultHomeScroll, none = !$12.support.cssTransitions || !$12.support.cssAnimations || maxTransitionOverride || !this.name || "none" === this.name || Math.max($12.mobile.window.scrollTop(), this.toScroll) > $12.mobile.getMaxScrollForTransition(), this.toggleViewportClass(), this.$from && !none ? this.startOut(screenHeight, reverseClass, none) : this.doneOut(screenHeight, reverseClass, none, !0), this.deferred.promise(); } }), jQuery.mobile.SerialTransition = function() { this.init.apply(this, arguments); @@ -1802,14 +1806,14 @@ beforeStartOut: function(screenHeight, reverseClass, none) { this.doneOut(screenHeight, reverseClass, none); } - }), $14 = jQuery, defaultGetMaxScrollForTransition = function() { - return 3 * $14.mobile.getScreenHeight(); - }, $14.mobile.transitionHandlers = { - sequential: $14.mobile.SerialTransition, - simultaneous: $14.mobile.ConcurrentTransition - }, $14.mobile.defaultTransitionHandler = $14.mobile.transitionHandlers.sequential, $14.mobile.transitionFallbacks = {}, $14.mobile._maybeDegradeTransition = function(transition) { - return transition && !$14.support.cssTransform3d && $14.mobile.transitionFallbacks[transition] && (transition = $14.mobile.transitionFallbacks[transition]), transition; - }, $14.mobile.getMaxScrollForTransition = $14.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition, jQuery.mobile.transitionFallbacks.flip = "fade", jQuery.mobile.transitionFallbacks.flow = "fade", jQuery.mobile.transitionFallbacks.pop = "fade", ($15 = jQuery).mobile.transitionHandlers.slide = $15.mobile.transitionHandlers.simultaneous, $15.mobile.transitionFallbacks.slide = "fade", jQuery.mobile.transitionFallbacks.slidedown = "fade", jQuery.mobile.transitionFallbacks.slidefade = "fade", jQuery.mobile.transitionFallbacks.slideup = "fade", jQuery.mobile.transitionFallbacks.turn = "fade", ($16 = jQuery).mobile.degradeInputs = { + }), $13 = jQuery, defaultGetMaxScrollForTransition = function() { + return 3 * $13.mobile.getScreenHeight(); + }, $13.mobile.transitionHandlers = { + sequential: $13.mobile.SerialTransition, + simultaneous: $13.mobile.ConcurrentTransition + }, $13.mobile.defaultTransitionHandler = $13.mobile.transitionHandlers.sequential, $13.mobile.transitionFallbacks = {}, $13.mobile._maybeDegradeTransition = function(transition) { + return transition && !$13.support.cssTransform3d && $13.mobile.transitionFallbacks[transition] && (transition = $13.mobile.transitionFallbacks[transition]), transition; + }, $13.mobile.getMaxScrollForTransition = $13.mobile.getMaxScrollForTransition || defaultGetMaxScrollForTransition, jQuery.mobile.transitionFallbacks.flip = "fade", jQuery.mobile.transitionFallbacks.flow = "fade", jQuery.mobile.transitionFallbacks.pop = "fade", ($14 = jQuery).mobile.transitionHandlers.slide = $14.mobile.transitionHandlers.simultaneous, $14.mobile.transitionFallbacks.slide = "fade", jQuery.mobile.transitionFallbacks.slidedown = "fade", jQuery.mobile.transitionFallbacks.slidefade = "fade", jQuery.mobile.transitionFallbacks.slideup = "fade", jQuery.mobile.transitionFallbacks.turn = "fade", ($15 = jQuery).mobile.degradeInputs = { color: !1, date: !1, datetime: !1, @@ -1823,10 +1827,10 @@ time: !1, url: !1, week: !1 - }, $16.mobile.page.prototype.options.degradeInputs = $16.mobile.degradeInputs, $16.mobile.degradeInputsWithin = function(target) { - (target = $16(target)).find("input").not($16.mobile.page.prototype.keepNativeSelector()).each(function() { - var html, hasType, repstr, element = $16(this), type = this.getAttribute("type"), optType = $16.mobile.degradeInputs[type] || "text"; - $16.mobile.degradeInputs[type] && (hasType = (html = $16("
").html(element.clone()).html()).indexOf(" type=") > -1, repstr = ' type="' + optType + '" data-' + $16.mobile.ns + 'type="' + type + '"' + (hasType ? "" : ">"), element.replaceWith(html.replace(hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/, repstr))); + }, $15.mobile.page.prototype.options.degradeInputs = $15.mobile.degradeInputs, $15.mobile.degradeInputsWithin = function(target) { + (target = $15(target)).find("input").not($15.mobile.page.prototype.keepNativeSelector()).each(function() { + var html, hasType, repstr, element = $15(this), type = this.getAttribute("type"), optType = $15.mobile.degradeInputs[type] || "text"; + $15.mobile.degradeInputs[type] && (hasType = (html = $15("
").html(element.clone()).html()).indexOf(" type=") > -1, repstr = ' type="' + optType + '" data-' + $15.mobile.ns + 'type="' + type + '"' + (hasType ? "" : ">"), element.replaceWith(html.replace(hasType ? /\s+type=["']?\w+['"]?/ : /\/?>/, repstr))); }); }, function($, window, undefined) { $.widget("mobile.page", $.mobile.page, { @@ -1917,9 +1921,9 @@ this._isCloseable && (this._isCloseable = !1, $.mobile.hashListeningEnabled && hist.activeIndex > 0 ? $.mobile.back() : $.mobile.pageContainer.pagecontainer("back")); } }); - }(jQuery, 0), $17 = jQuery, rInitialLetter = /([A-Z])/g, iconposClass = function(iconpos) { + }(jQuery, 0), $16 = jQuery, rInitialLetter = /([A-Z])/g, iconposClass = function(iconpos) { return "ui-btn-icon-" + (null === iconpos ? "left" : iconpos); - }, $17.widget("mobile.collapsible", { + }, $16.widget("mobile.collapsible", { options: { enhanced: !1, expandCueText: null, @@ -1937,11 +1941,11 @@ }, _create: function() { var elem = this.element, ui = { - accordion: elem.closest(":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')" + ($17.mobile.collapsibleset ? ", :mobile-collapsibleset" : "")).addClass("ui-collapsible-set") + accordion: elem.closest(":jqmData(role='collapsible-set'),:jqmData(role='collapsibleset')" + ($16.mobile.collapsibleset ? ", :mobile-collapsibleset" : "")).addClass("ui-collapsible-set") }; - this._ui = ui, this._renderedOptions = this._getOptions(this.options), this.options.enhanced ? (ui.heading = $17(".ui-collapsible-heading", this.element[0]), ui.content = ui.heading.next(), ui.anchor = $17("a", ui.heading[0]).first(), ui.status = ui.anchor.children(".ui-collapsible-heading-status")) : this._enhance(elem, ui), this._on(ui.heading, { + this._ui = ui, this._renderedOptions = this._getOptions(this.options), this.options.enhanced ? (ui.heading = $16(".ui-collapsible-heading", this.element[0]), ui.content = ui.heading.next(), ui.anchor = $16("a", ui.heading[0]).first(), ui.status = ui.anchor.children(".ui-collapsible-heading-status")) : this._enhance(elem, ui), this._on(ui.heading, { tap: function() { - ui.heading.find("a").first().addClass($17.mobile.activeBtnClass); + ui.heading.find("a").first().addClass($16.mobile.activeBtnClass); }, click: function(event1) { this._handleExpandCollapse(!ui.heading.hasClass("ui-collapsible-heading-collapsed")), event1.preventDefault(), event1.stopPropagation(); @@ -1950,7 +1954,7 @@ }, _getOptions: function(options) { var key, accordion = this._ui.accordion, accordionWidget = this._ui.accordionWidget; - for(key in options = $17.extend({}, options), accordion.length && !accordionWidget && (this._ui.accordionWidget = accordionWidget = accordion.data("mobile-collapsibleset")), options)options[key] = null != options[key] ? options[key] : accordionWidget ? accordionWidget.options[key] : accordion.length ? $17.mobile.getAttribute(accordion[0], key.replace(rInitialLetter, "-$1").toLowerCase()) : null, null == options[key] && (options[key] = $17.mobile.collapsible.defaults[key]); + for(key in options = $16.extend({}, options), accordion.length && !accordionWidget && (this._ui.accordionWidget = accordionWidget = accordion.data("mobile-collapsibleset")), options)options[key] = null != options[key] ? options[key] : accordionWidget ? accordionWidget.options[key] : accordion.length ? $16.mobile.getAttribute(accordion[0], key.replace(rInitialLetter, "-$1").toLowerCase()) : null, null == options[key] && (options[key] = $16.mobile.collapsible.defaults[key]); return options; }, _themeClassFromOption: function(prefix, value) { @@ -1958,7 +1962,7 @@ }, _enhance: function(elem, ui) { var iconclass, opts = this._renderedOptions, contentThemeClass = this._themeClassFromOption("ui-body-", opts.contentTheme); - return elem.addClass("ui-collapsible " + (opts.inset ? "ui-collapsible-inset " : "") + (opts.inset && opts.corners ? "ui-corner-all " : "") + (contentThemeClass ? "ui-collapsible-themed-content " : "")), ui.originalHeading = elem.children(this.options.heading).first(), ui.content = elem.wrapInner("
").children(".ui-collapsible-content"), ui.heading = ui.originalHeading, ui.heading.is("legend") && (ui.heading = $17("
" + ui.heading.html() + "
"), ui.placeholder = $17("
").insertBefore(ui.originalHeading), ui.originalHeading.remove()), iconclass = opts.collapsed ? opts.collapsedIcon ? "ui-icon-" + opts.collapsedIcon : "" : opts.expandedIcon ? "ui-icon-" + opts.expandedIcon : "", ui.status = $17(""), ui.anchor = ui.heading.detach().addClass("ui-collapsible-heading").append(ui.status).wrapInner("").find("a").first().addClass("ui-btn " + (iconclass ? iconclass + " " : "") + (iconclass ? iconposClass(opts.iconpos) + " " : "") + this._themeClassFromOption("ui-btn-", opts.theme) + " " + (opts.mini ? "ui-mini " : "")), ui.heading.insertBefore(ui.content), this._handleExpandCollapse(this.options.collapsed), ui; + return elem.addClass("ui-collapsible " + (opts.inset ? "ui-collapsible-inset " : "") + (opts.inset && opts.corners ? "ui-corner-all " : "") + (contentThemeClass ? "ui-collapsible-themed-content " : "")), ui.originalHeading = elem.children(this.options.heading).first(), ui.content = elem.wrapInner("
").children(".ui-collapsible-content"), ui.heading = ui.originalHeading, ui.heading.is("legend") && (ui.heading = $16("
" + ui.heading.html() + "
"), ui.placeholder = $16("
").insertBefore(ui.originalHeading), ui.originalHeading.remove()), iconclass = opts.collapsed ? opts.collapsedIcon ? "ui-icon-" + opts.collapsedIcon : "" : opts.expandedIcon ? "ui-icon-" + opts.expandedIcon : "", ui.status = $16(""), ui.anchor = ui.heading.detach().addClass("ui-collapsible-heading").append(ui.status).wrapInner("").find("a").first().addClass("ui-btn " + (iconclass ? iconclass + " " : "") + (iconclass ? iconposClass(opts.iconpos) + " " : "") + this._themeClassFromOption("ui-btn-", opts.theme) + " " + (opts.mini ? "ui-mini " : "")), ui.heading.insertBefore(ui.content), this._handleExpandCollapse(this.options.collapsed), ui; }, refresh: function() { this._applyOptions(this.options), this._renderedOptions = this._getOptions(this.options); @@ -1984,7 +1988,7 @@ }, _handleExpandCollapse: function(isCollapse) { var opts = this._renderedOptions, ui = this._ui; - ui.status.text(isCollapse ? opts.expandCueText : opts.collapseCueText), ui.heading.toggleClass("ui-collapsible-heading-collapsed", isCollapse).find("a").first().toggleClass("ui-icon-" + opts.expandedIcon, !isCollapse).toggleClass("ui-icon-" + opts.collapsedIcon, isCollapse || opts.expandedIcon === opts.collapsedIcon).removeClass($17.mobile.activeBtnClass), this.element.toggleClass("ui-collapsible-collapsed", isCollapse), ui.content.toggleClass("ui-collapsible-content-collapsed", isCollapse).attr("aria-hidden", isCollapse).trigger("updatelayout"), this.options.collapsed = isCollapse, this._trigger(isCollapse ? "collapse" : "expand"); + ui.status.text(isCollapse ? opts.expandCueText : opts.collapseCueText), ui.heading.toggleClass("ui-collapsible-heading-collapsed", isCollapse).find("a").first().toggleClass("ui-icon-" + opts.expandedIcon, !isCollapse).toggleClass("ui-icon-" + opts.collapsedIcon, isCollapse || opts.expandedIcon === opts.collapsedIcon).removeClass($16.mobile.activeBtnClass), this.element.toggleClass("ui-collapsible-collapsed", isCollapse), ui.content.toggleClass("ui-collapsible-content-collapsed", isCollapse).attr("aria-hidden", isCollapse).trigger("updatelayout"), this.options.collapsed = isCollapse, this._trigger(isCollapse ? "collapse" : "expand"); }, expand: function() { this._handleExpandCollapse(!1); @@ -1996,7 +2000,7 @@ var ui = this._ui; !this.options.enhanced && (ui.placeholder ? (ui.originalHeading.insertBefore(ui.placeholder), ui.placeholder.remove(), ui.heading.remove()) : (ui.status.remove(), ui.heading.removeClass("ui-collapsible-heading ui-collapsible-heading-collapsed").children().contents().unwrap()), ui.anchor.contents().unwrap(), ui.content.contents().unwrap(), this.element.removeClass("ui-collapsible ui-collapsible-collapsed ui-collapsible-themed-content ui-collapsible-inset ui-corner-all")); } - }), $17.mobile.collapsible.defaults = { + }), $16.mobile.collapsible.defaults = { expandCueText: " click to expand contents", collapseCueText: " click to collapse contents", collapsedIcon: "plus", @@ -2340,17 +2344,17 @@ }); } }); - }(jQuery), disabledZoom = (initialContent = (meta = ($18 = jQuery)("meta[name=viewport]")).attr("content")) + ",maximum-scale=1, user-scalable=no", enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes", disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test(initialContent), $18.mobile.zoom = $18.extend({}, { + }(jQuery), disabledZoom = (initialContent = (meta = ($17 = jQuery)("meta[name=viewport]")).attr("content")) + ",maximum-scale=1, user-scalable=no", enabledZoom = initialContent + ",maximum-scale=10, user-scalable=yes", disabledInitially = /(user-scalable[\s]*=[\s]*no)|(maximum-scale[\s]*=[\s]*1)[$,\s]/.test(initialContent), $17.mobile.zoom = $17.extend({}, { enabled: !disabledInitially, locked: !1, disable: function(lock) { - disabledInitially || $18.mobile.zoom.locked || (meta.attr("content", disabledZoom), $18.mobile.zoom.enabled = !1, $18.mobile.zoom.locked = lock || !1); + disabledInitially || $17.mobile.zoom.locked || (meta.attr("content", disabledZoom), $17.mobile.zoom.enabled = !1, $17.mobile.zoom.locked = lock || !1); }, enable: function(unlock) { - disabledInitially || $18.mobile.zoom.locked && !0 !== unlock || (meta.attr("content", enabledZoom), $18.mobile.zoom.enabled = !0, $18.mobile.zoom.locked = !1); + disabledInitially || $17.mobile.zoom.locked && !0 !== unlock || (meta.attr("content", enabledZoom), $17.mobile.zoom.enabled = !0, $17.mobile.zoom.locked = !1); }, restore: function() { - disabledInitially || (meta.attr("content", initialContent), $18.mobile.zoom.enabled = !0); + disabledInitially || (meta.attr("content", initialContent), $17.mobile.zoom.enabled = !0); } }), function($, undefined) { $.widget("mobile.textinput", { @@ -4343,9 +4347,9 @@ this._timer && (window.clearTimeout(this._timer), this._timer = 0), this._filterItems((this._search && this._search.val() || "").toLowerCase()); } }); - }(jQuery), rDividerListItem = /(^|\s)ui-li-divider(\s|$)/, origDefaultFilterCallback = ($19 = jQuery).mobile.filterable.prototype.options.filterCallback, $19.mobile.filterable.prototype.options.filterCallback = function(index, searchValue) { + }(jQuery), rDividerListItem = /(^|\s)ui-li-divider(\s|$)/, origDefaultFilterCallback = ($18 = jQuery).mobile.filterable.prototype.options.filterCallback, $18.mobile.filterable.prototype.options.filterCallback = function(index, searchValue) { return !this.className.match(rDividerListItem) && origDefaultFilterCallback.call(this, index, searchValue); - }, $19.widget("mobile.filterable", $19.mobile.filterable, { + }, $18.widget("mobile.filterable", $18.mobile.filterable, { options: { filterPlaceholder: "Filter items...", filterTheme: null @@ -4357,9 +4361,9 @@ "controlgroup", "listview" ], createHandlers = {}; - for(this._super(), $19.extend(this, { + for(this._super(), $18.extend(this, { _widget: null - }), idx = recognizedWidgets.length - 1; idx > -1; idx--)if (widgetName = recognizedWidgets[idx], $19.mobile[widgetName]) { + }), idx = recognizedWidgets.length - 1; idx > -1; idx--)if (widgetName = recognizedWidgets[idx], $18.mobile[widgetName]) { if (this._setWidget(elem.data("mobile-" + widgetName))) break; createHandlers[widgetName + "create"] = "_handleCreate"; } @@ -4387,23 +4391,23 @@ var opts = this.options, updatePlaceholder = !0, textinputOpts = {}; if (!selector) { if (this._isSearchInternal()) return; - updatePlaceholder = !1, selector = $19("").jqmData("ui-filterable-" + this.uuid + "-internal", !0), $19("
").append(selector).submit(function(evt) { + updatePlaceholder = !1, selector = $18("").jqmData("ui-filterable-" + this.uuid + "-internal", !0), $18("
").append(selector).submit(function(evt) { evt.preventDefault(), selector.blur(); - }).insertBefore(this.element), $19.mobile.textinput && (null != this.options.filterTheme && (textinputOpts.theme = opts.filterTheme), selector.textinput(textinputOpts)); + }).insertBefore(this.element), $18.mobile.textinput && (null != this.options.filterTheme && (textinputOpts.theme = opts.filterTheme), selector.textinput(textinputOpts)); } this._super(selector), this._isSearchInternal() && updatePlaceholder && this._search.attr("placeholder", this.options.filterPlaceholder); }, _setOptions: function(options) { var ret = this._super(options); - return undefined8 !== options.filterPlaceholder && this._isSearchInternal() && this._search.attr("placeholder", options.filterPlaceholder), undefined8 !== options.filterTheme && this._search && $19.mobile.textinput && this._search.textinput("option", "theme", options.filterTheme), ret; + return undefined8 !== options.filterPlaceholder && this._isSearchInternal() && this._search.attr("placeholder", options.filterPlaceholder), undefined8 !== options.filterTheme && this._search && $18.mobile.textinput && this._search.textinput("option", "theme", options.filterTheme), ret; }, _destroy: function() { this._isSearchInternal() && this._search.remove(), this._super(); }, _syncTextInputOptions: function(options) { var idx, textinputOptions = {}; - if (this._isSearchInternal() && $19.mobile.textinput) { - for(idx in $19.mobile.textinput.prototype.options)undefined8 !== options[idx] && ("theme" === idx && null != this.options.filterTheme ? textinputOptions[idx] = this.options.filterTheme : textinputOptions[idx] = options[idx]); + if (this._isSearchInternal() && $18.mobile.textinput) { + for(idx in $18.mobile.textinput.prototype.options)undefined8 !== options[idx] && ("theme" === idx && null != this.options.filterTheme ? textinputOptions[idx] = this.options.filterTheme : textinputOptions[idx] = options[idx]); this._search.textinput("option", textinputOptions); } } 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 a11706d79849..09c30b813408 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 @@ -7781,13 +7781,13 @@ return (ensureRootIsScheduled(root, now()), root.callbackNode === originalCallbackNode) ? performConcurrentWorkOnRoot.bind(null, root) : null; } function markRootSuspended$1(root, suspendedLanes) { - !function(root, suspendedLanes) { + suspendedLanes &= ~workInProgressRootPingedLanes, function(root, suspendedLanes) { root.suspendedLanes |= suspendedLanes, root.pingedLanes &= ~suspendedLanes; for(var expirationTimes = root.expirationTimes, lanes = suspendedLanes; lanes > 0;){ var index = pickArbitraryLaneIndex(lanes), lane = 1 << index; expirationTimes[index] = -1, lanes &= ~lane; } - }(root, suspendedLanes = (suspendedLanes &= ~workInProgressRootPingedLanes) & ~workInProgressRootUpdatedLanes); + }(root, suspendedLanes &= ~workInProgressRootUpdatedLanes); } function performSyncWorkOnRoot(root) { if ((48 & executionContext) != 0) throw Error("Should not already be working."); @@ -8107,8 +8107,8 @@ } while (null !== nextEffect) containerInfo1 = root.containerInfo, function(priorSelectionInformation) { - var curFocusedElem = getActiveElementDeep(), priorFocusedElem = priorSelectionInformation.focusedElem, priorSelectionRange = priorSelectionInformation.selectionRange; - if (curFocusedElem !== priorFocusedElem && priorFocusedElem && priorFocusedElem.ownerDocument && function containsNode(outerNode, innerNode) { + var node, curFocusedElem = getActiveElementDeep(), priorFocusedElem = priorSelectionInformation.focusedElem, priorSelectionRange = priorSelectionInformation.selectionRange; + if (curFocusedElem !== priorFocusedElem && (node = priorFocusedElem) && node.ownerDocument && function containsNode(outerNode, innerNode) { if (!outerNode || !innerNode) return !1; if (outerNode === innerNode) return !0; if (isTextNode(outerNode)) return !1; @@ -8116,7 +8116,7 @@ if ("contains" in outerNode) return outerNode.contains(innerNode); else if (outerNode.compareDocumentPosition) return !!(16 & outerNode.compareDocumentPosition(innerNode)); else return !1; - }(priorFocusedElem.ownerDocument.documentElement, priorFocusedElem)) { + }(node.ownerDocument.documentElement, node)) { null !== priorSelectionRange && hasSelectionCapabilities(priorFocusedElem) && (input = priorFocusedElem, start = (offsets = priorSelectionRange).start, void 0 === (end = offsets.end) && (end = start), "selectionStart" in input ? (input.selectionStart = start, input.selectionEnd = Math.min(end, input.value.length)) : function(node, offsets) { var doc = node.ownerDocument || document, win = doc && doc.defaultView || window; if (win.getSelection) { diff --git a/crates/swc_ecma_minifier/tests/terser/compress/negate_iife/negate_iife_2_side_effects/output.js b/crates/swc_ecma_minifier/tests/terser/compress/negate_iife/negate_iife_2_side_effects/output.js index 187cb3e3ef49..e69de29bb2d1 100644 --- a/crates/swc_ecma_minifier/tests/terser/compress/negate_iife/negate_iife_2_side_effects/output.js +++ b/crates/swc_ecma_minifier/tests/terser/compress/negate_iife/negate_iife_2_side_effects/output.js @@ -1 +0,0 @@ -10; diff --git a/crates/swc_ecma_transforms_optimization/src/debug.rs b/crates/swc_ecma_transforms_optimization/src/debug.rs index ed4b011d3909..221e9d3e223d 100644 --- a/crates/swc_ecma_transforms_optimization/src/debug.rs +++ b/crates/swc_ecma_transforms_optimization/src/debug.rs @@ -11,7 +11,7 @@ where N: VisitWith, { #[cfg(debug_assertions)] - node.visit_with(&mut AssertValid { _priv: () }); + node.visit_with(&mut AssertValid); } #[cfg(debug_assertions)] @@ -26,9 +26,7 @@ impl Drop for Ctx<'_> { } } -pub struct AssertValid { - _priv: (), -} +pub struct AssertValid; impl Visit for AssertValid { noop_visit_type!(); @@ -77,4 +75,18 @@ impl Visit for AssertValid { panic!("Found empty var declarators"); } } + + #[cfg(debug_assertions)] + fn visit_seq_expr(&mut self, v: &SeqExpr) { + v.visit_children_with(self); + + // TODO(kdy1): Make parser does not create invalid sequential + // expressions and uncomment this + + // assert!( + // v.exprs.len() >= 2, + // "SeqExpr(len = {}) is invalid", + // v.exprs.len() + // ); + } } diff --git a/crates/swc_ecma_transforms_optimization/src/lib.rs b/crates/swc_ecma_transforms_optimization/src/lib.rs index 5a8fc9dd5696..23d69fc4e730 100644 --- a/crates/swc_ecma_transforms_optimization/src/lib.rs +++ b/crates/swc_ecma_transforms_optimization/src/lib.rs @@ -4,7 +4,7 @@ pub use self::{ const_modules::const_modules, - debug::debug_assert_valid, + debug::{debug_assert_valid, AssertValid}, inline_globals::{inline_globals, inline_globals2, GlobalExprMap}, json_parse::json_parse, simplify::simplifier, diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs index 6332613fb71b..8ac291253b8c 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/branch/mod.rs @@ -108,6 +108,8 @@ impl VisitMut for Remover { Expr::Seq(s) => { if s.exprs.is_empty() { *e = Expr::dummy(); + } else if s.exprs.len() == 1 { + *e = *s.exprs.pop().unwrap(); } } @@ -1719,6 +1721,10 @@ fn ignore_result(e: Expr, drop_str_lit: bool, ctx: &ExprCtx) -> Option { return None; } + if exprs.len() == 1 { + return Some(*exprs.pop().unwrap()); + } + Some(Expr::Seq(SeqExpr { span, exprs })) } diff --git a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs index 02b7b859f486..f18a2b5ccf01 100644 --- a/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs +++ b/crates/swc_ecma_transforms_optimization/src/simplify/dce/mod.rs @@ -806,6 +806,10 @@ impl VisitMut for TreeShaker { *n = *a.right.take(); } } + + if !n.is_invalid() { + debug_assert_valid(n); + } } fn visit_mut_import_specifiers(&mut self, ss: &mut Vec) { @@ -830,6 +834,8 @@ impl VisitMut for TreeShaker { } fn visit_mut_module(&mut self, m: &mut Module) { + debug_assert_valid(m); + let _tracing = span!(Level::ERROR, "tree-shaker", pass = self.pass).entered(); if self.bindings.is_empty() { @@ -924,6 +930,8 @@ impl VisitMut for TreeShaker { } } + debug_assert_valid(s); + if let Stmt::Decl(Decl::Var(v)) = s { let span = v.span; let cnt = v.decls.len(); @@ -951,18 +959,10 @@ impl VisitMut for TreeShaker { if exprs.is_empty() { *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); return; - } else if exprs.len() == 1 { - *s = Stmt::Expr(ExprStmt { - span, - expr: exprs.into_iter().next().unwrap(), - }); } else { *s = Stmt::Expr(ExprStmt { span, - expr: Box::new(Expr::Seq(SeqExpr { - span: DUMMY_SP, - exprs, - })), + expr: Expr::from_exprs(exprs), }); } } @@ -973,6 +973,8 @@ impl VisitMut for TreeShaker { *s = Stmt::Empty(EmptyStmt { span: DUMMY_SP }); } } + + debug_assert_valid(s); } fn visit_mut_stmts(&mut self, s: &mut Vec) {