261020.1 · 1d7e0126f3e601103d93586a6f872144f2789dad
chore: self-maintain Node.js features
reading declarations
Changes to deps/swc/crates/swc_ecma_transformer/src/. All files
deps/swc/crates/swc_ecma_transformer/src/bugfix/mod.rs
@@ -1,25 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct BugfixOptions {}--impl BugfixOptions {- /// Returns true if any transform is enabled.- /// Currently no bugfixes are available.- pub fn is_enabled(&self) -> bool {- false- }-}--pub fn hook(options: BugfixOptions) -> impl VisitMutHook<TraverseCtx> {- BugfixPass { options }-}--struct BugfixPass {- options: BugfixOptions,-}--impl VisitMutHook<TraverseCtx> for BugfixPass {}
deps/swc/crates/swc_ecma_transformer/src/common/mod.rs
@@ -1,4 +0,0 @@-pub(crate) use self::{statement_injector::*, var_declarations::*};--mod statement_injector;-mod var_declarations;
deps/swc/crates/swc_ecma_transformer/src/common/statement_injector.rs
@@ -1,346 +0,0 @@-//! Utility transform to add new statements before or after the specified-//! statement.-//!-//! `StatementInjectorStore` contains a `FxHashMap<Address,-//! Vec<AdjacentStatement>>`. It is stored on `TransformCtx`.-//!-//! `StatementInjector` transform inserts new statements before or after a-//! statement which is determined by the address of the statement.-//!-//! Other transforms can add statements to the store with following methods:-//!-//! ```rs-//! self.ctx.statement_injector.insert_before(address, statement);-//! self.ctx.statement_injector.insert_after(address, statement);-//! self.ctx.statement_injector.insert_many_after(address, statements);-//! ```--use rustc_hash::FxHashMap;-use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-pub struct StmtInjector {}--#[derive(Debug)]-enum Direction {- Before,- After,-}--#[derive(Debug)]-struct AdjacentStmt {- stmt: Stmt,- direction: Direction,-}--/// Store for Stmts to be added to the Stmts.-///-/// The key is the address of the statement in the AST, represented as a-/// pointer.-#[derive(Default)]-pub struct StmtInjectorStore {- /// Map from statement address to adjacent statements to insert- stmts: FxHashMap<*const Stmt, Vec<AdjacentStmt>>,-}--impl StmtInjectorStore {- /// Insert a statement before the statement at the given address- pub fn insert_before(&mut self, address: *const Stmt, stmt: Stmt) {- self.stmts.entry(address).or_default().push(AdjacentStmt {- stmt,- direction: Direction::Before,- });- }-- /// Insert a statement after the statement at the given address- pub fn insert_after(&mut self, address: *const Stmt, stmt: Stmt) {- self.stmts.entry(address).or_default().push(AdjacentStmt {- stmt,- direction: Direction::After,- });- }-- /// Insert multiple statements after the statement at the given address- pub fn insert_many_after(&mut self, address: *const Stmt, stmts: Vec<Stmt>) {- let entry = self.stmts.entry(address).or_default();- for stmt in stmts {- entry.push(AdjacentStmt {- stmt,- direction: Direction::After,- });- }- }-- /// Get all statements to be inserted at the given address- fn take_stmts(&mut self, address: *const Stmt) -> Option<Vec<AdjacentStmt>> {- self.stmts.remove(&address)- }-}--impl VisitMutHook<TraverseCtx> for StmtInjector {- fn enter_arrow_expr(&mut self, node: &mut ArrowExpr, _: &mut TraverseCtx) {- // We convert the arrow body to a block statement with a return statement- // because we cannot inject statements after the arrow body.- if let ArrowFunctionBody::Expr(expr) = &mut *node.body {- *node.body = ArrowFunctionBody::FunctionBody(FunctionBody {- span: DUMMY_SP,- stmts: vec![Stmt::Return(ReturnStmt {- span: DUMMY_SP,- arg: Some(expr.take()),- })],- });- }- }-- fn exit_arrow_expr(&mut self, node: &mut ArrowExpr, _: &mut TraverseCtx) {- if let ArrowFunctionBody::FunctionBody(block_stmt) = &mut *node.body {- // If the block statement is something we inserted, we need to- // convert it back to an expression.- if block_stmt.span == DUMMY_SP && block_stmt.stmts.len() == 1 {- if let Stmt::Return(return_stmt) = &mut block_stmt.stmts[0] {- if return_stmt.span == DUMMY_SP {- *node.body = ArrowFunctionBody::Expr(return_stmt.arg.take().unwrap());- }- }- }- }- }-- fn exit_module_items(&mut self, node: &mut Vec<ModuleItem>, ctx: &mut TraverseCtx) {- // First pass: collect all (index, adjacent_stmts) pairs while addresses are- // valid.- let mut insertions = Vec::new();- let mut insertion_count = 0;- for (i, item) in node.iter().enumerate() {- // Only process ModuleItem::Stmt variants- if let ModuleItem::Stmt(stmt) = item {- let address = stmt as *const Stmt;- if let Some(adjacent_stmts) = ctx.statement_injector.take_stmts(address) {- insertion_count += adjacent_stmts.len();- insertions.push((i, adjacent_stmts));- }- }- }-- if insertions.is_empty() {- return;- }-- let mut next_insertion = insertions.into_iter().peekable();- let original = node.take();- let mut rewritten = Vec::with_capacity(original.len() + insertion_count);-- for (i, item) in original.into_iter().enumerate() {- let mut after = Vec::new();-- if matches!(- next_insertion.peek(),- Some(&(insertion_idx, _)) if insertion_idx == i- ) {- let (_, adjacent_stmts) = next_insertion.next().unwrap();-- for adjacent in adjacent_stmts {- match adjacent.direction {- Direction::Before => rewritten.push(ModuleItem::Stmt(adjacent.stmt)),- Direction::After => after.push(ModuleItem::Stmt(adjacent.stmt)),- }- }- }-- rewritten.push(item);- rewritten.extend(after);- }-- *node = rewritten;- }-- fn exit_stmts(&mut self, stmts: &mut Vec<Stmt>, ctx: &mut TraverseCtx) {- // First pass: collect all (index, adjacent_stmts) pairs while addresses are- // valid.- let mut insertions = Vec::new();- let mut insertion_count = 0;- for (i, stmt) in stmts.iter().enumerate() {- let address = stmt as *const Stmt;- if let Some(adjacent_stmts) = ctx.statement_injector.take_stmts(address) {- insertion_count += adjacent_stmts.len();- insertions.push((i, adjacent_stmts));- }- }-- if insertions.is_empty() {- return;- }-- let mut next_insertion = insertions.into_iter().peekable();- let original = stmts.take();- let mut rewritten = Vec::with_capacity(original.len() + insertion_count);-- for (i, stmt) in original.into_iter().enumerate() {- let mut after = Vec::new();-- if matches!(- next_insertion.peek(),- Some(&(insertion_idx, _)) if insertion_idx == i- ) {- let (_, adjacent_stmts) = next_insertion.next().unwrap();-- for adjacent in adjacent_stmts {- match adjacent.direction {- Direction::Before => rewritten.push(adjacent.stmt),- Direction::After => after.push(adjacent.stmt),- }- }- }-- rewritten.push(stmt);- rewritten.extend(after);- }-- *stmts = rewritten;- }-}--#[cfg(test)]-mod tests {- use super::*;-- fn labeled_stmt(label: &str) -> Stmt {- Stmt::Expr(ExprStmt {- span: DUMMY_SP,- expr: Box::new(Expr::Lit(Lit::Str(Str {- span: DUMMY_SP,- value: label.into(),- raw: None,- }))),- })- }-- fn stmt_label(stmt: &Stmt) -> String {- let Stmt::Expr(ExprStmt { expr, .. }) = stmt else {- panic!("expected expression statement")- };- let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr else {- panic!("expected string literal expression")- };-- value.to_string_lossy().into_owned()- }-- fn empty_named_export() -> ModuleItem {- ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {- span: DUMMY_SP,- specifiers: Vec::new(),- src: None,- type_only: false,- with: None,- }))- }-- #[test]- fn exit_stmts_keeps_before_and_after_order_for_one_target() {- let mut stmts = vec![labeled_stmt("base")];- let target = &stmts[0] as *const Stmt;-- let mut ctx = TraverseCtx::default();- ctx.statement_injector- .insert_before(target, labeled_stmt("before_1"));- ctx.statement_injector- .insert_before(target, labeled_stmt("before_2"));- ctx.statement_injector- .insert_after(target, labeled_stmt("after_1"));- ctx.statement_injector- .insert_after(target, labeled_stmt("after_2"));-- StmtInjector::default().exit_stmts(&mut stmts, &mut ctx);-- let labels = stmts.iter().map(stmt_label).collect::<Vec<_>>();- assert_eq!(- labels,- vec![- "before_1".to_string(),- "before_2".to_string(),- "base".to_string(),- "after_1".to_string(),- "after_2".to_string(),- ]- );- }-- #[test]- fn exit_stmts_keeps_order_for_multiple_targets() {- let mut stmts = vec![labeled_stmt("s0"), labeled_stmt("s1"), labeled_stmt("s2")];-- let s0 = &stmts[0] as *const Stmt;- let s1 = &stmts[1] as *const Stmt;- let s2 = &stmts[2] as *const Stmt;-- let mut ctx = TraverseCtx::default();- ctx.statement_injector.insert_after(s0, labeled_stmt("a0"));- ctx.statement_injector.insert_before(s1, labeled_stmt("b1"));- ctx.statement_injector.insert_after(s2, labeled_stmt("a2"));-- StmtInjector::default().exit_stmts(&mut stmts, &mut ctx);-- let labels = stmts.iter().map(stmt_label).collect::<Vec<_>>();- assert_eq!(- labels,- vec![- "s0".to_string(),- "a0".to_string(),- "b1".to_string(),- "s1".to_string(),- "s2".to_string(),- "a2".to_string(),- ]- );- }-- #[test]- fn exit_module_items_only_targets_statement_entries() {- let mut items = vec![- empty_named_export(),- ModuleItem::Stmt(labeled_stmt("s0")),- empty_named_export(),- ModuleItem::Stmt(labeled_stmt("s1")),- ];-- let s0 = match &items[1] {- ModuleItem::Stmt(stmt) => stmt as *const Stmt,- _ => unreachable!(),- };- let s1 = match &items[3] {- ModuleItem::Stmt(stmt) => stmt as *const Stmt,- _ => unreachable!(),- };-- let mut ctx = TraverseCtx::default();- ctx.statement_injector.insert_after(s0, labeled_stmt("a0"));- ctx.statement_injector.insert_before(s1, labeled_stmt("b1"));-- StmtInjector::default().exit_module_items(&mut items, &mut ctx);-- let labels = items- .iter()- .map(|item| match item {- ModuleItem::Stmt(stmt) => stmt_label(stmt),- _ => "module".to_string(),- })- .collect::<Vec<_>>();-- assert_eq!(- labels,- vec![- "module".to_string(),- "s0".to_string(),- "a0".to_string(),- "module".to_string(),- "b1".to_string(),- "s1".to_string(),- ]- );- }-}
deps/swc/crates/swc_ecma_transformer/src/common/var_declarations.rs
@@ -1,305 +0,0 @@-//! Utility transform to add `var` or `let` declarations after directives in-//! statement blocks.-//!-//! `VarDeclarationsStore` contains a stack of `Declarators`, each comprising-//! 2 x `Vec<VarDeclarator>` (1 for `var`s, 1 for `let`s).-//! `VarDeclarationsStore` is stored on `TraverseCtx`.-//!-//! `VarDeclarations` transform pushes an empty entry onto this stack when-//! entering a statement block, and when exiting the block, writes `var` / `let`-//! statements after the block's directive prologue.-//!-//! Other transforms can add declarators to the store by calling methods of-//! `VarDeclarationsStore`:-//!-//! ```rs-//! ctx.var_declarations.insert_var(ident, None, ctx);-//! ctx.var_declarations.insert_let(ident, Some(init), ctx);-//! ```--use std::ptr;--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::StmtLikeInjector;--use crate::TraverseCtx;--/// Transform that maintains the stack of `Vec<VarDeclarator>`s, and adds a-/// `var` statement after directives in a statement block if another transform-/// has requested that.-///-/// Must run after all other transforms.-#[derive(Debug, Default)]-pub struct VarDeclarations {- arrow_exprs: Vec<Option<ArrowExprScope>>,-}--#[derive(Debug)]-struct ArrowExprScope {- /// The `ArrowFunctionBody` for an expression-bodied arrow. Starting the- /// scope here keeps generated temps out of params while still catching- /// body transforms that queue declarations in `enter_expr`.- body: *const ArrowFunctionBody,- started: bool,- declarations: Option<(Option<Stmt>, Option<Stmt>)>,-}--impl VisitMutHook<TraverseCtx> for VarDeclarations {- fn enter_arrow_expr(&mut self, node: &mut ArrowExpr, _ctx: &mut TraverseCtx) {- self.arrow_exprs.push(match &mut *node.body {- ArrowFunctionBody::Expr(_) => Some(ArrowExprScope {- body: &*node.body,- started: false,- declarations: None,- }),- ArrowFunctionBody::FunctionBody(_) => None,- #[cfg(swc_ast_unknown)]- _ => None,- });- }-- fn exit_arrow_expr(&mut self, node: &mut ArrowExpr, ctx: &mut TraverseCtx) {- let Some(mut scope) = self.arrow_exprs.pop().flatten() else {- return;- };-- if scope.started {- scope.declarations = ctx.var_declarations.get_var_statement();- }-- let Some(mut stmts) = Self::declaration_stmts(scope.declarations) else {- return;- };-- match &mut *node.body {- ArrowFunctionBody::Expr(expr) => {- stmts.push(Stmt::Return(ReturnStmt {- span: DUMMY_SP,- arg: Some(expr.take()),- }));-- *node.body = ArrowFunctionBody::FunctionBody(FunctionBody {- span: DUMMY_SP,- stmts,- });- }- ArrowFunctionBody::FunctionBody(body) => Self::insert_arrow_declarations(body, stmts),- #[cfg(swc_ast_unknown)]- _ => {}- }- }-- fn enter_arrow_function_body(&mut self, node: &mut ArrowFunctionBody, ctx: &mut TraverseCtx) {- let Some(Some(scope)) = self.arrow_exprs.last_mut() else {- return;- };-- if !scope.started && ptr::eq(scope.body, node) {- ctx.var_declarations.record_entering_stmts();- scope.started = true;- }- }-- fn exit_arrow_function_body(&mut self, node: &mut ArrowFunctionBody, ctx: &mut TraverseCtx) {- let Some(Some(scope)) = self.arrow_exprs.last_mut() else {- return;- };-- if scope.started && ptr::eq(scope.body, node) {- scope.declarations = ctx.var_declarations.get_var_statement();- scope.started = false;- }- }-- fn enter_stmts(&mut self, _stmts: &mut Vec<Stmt>, ctx: &mut TraverseCtx) {- ctx.var_declarations.record_entering_stmts();- }-- fn exit_stmts(&mut self, stmts: &mut Vec<Stmt>, ctx: &mut TraverseCtx) {- ctx.var_declarations.insert_into_stmts(stmts);- }-- fn enter_module_items(&mut self, _items: &mut Vec<ModuleItem>, ctx: &mut TraverseCtx) {- ctx.var_declarations.record_entering_stmts();- }-- fn exit_module_items(&mut self, items: &mut Vec<ModuleItem>, ctx: &mut TraverseCtx) {- ctx.var_declarations.insert_into_module_items(items);- }-}--impl VarDeclarations {- fn declaration_stmts(declarations: Option<(Option<Stmt>, Option<Stmt>)>) -> Option<Vec<Stmt>> {- let (var_statement, let_statement) = declarations?;- let mut stmts = Vec::with_capacity(2);-- match (var_statement, let_statement) {- (Some(var_statement), Some(let_statement)) => {- stmts.push(var_statement);- stmts.push(let_statement);- }- (Some(statement), None) | (None, Some(statement)) => {- stmts.push(statement);- }- (None, None) => return None,- }-- Some(stmts)- }-- fn insert_arrow_declarations(block: &mut FunctionBody, declarations: Vec<Stmt>) {- if declarations.is_empty() {- return;- }-- if matches!(- block.stmts.last(),- Some(Stmt::Return(ReturnStmt { span: DUMMY_SP, .. }))- ) {- let return_stmt = block.stmts.pop().unwrap();- block.stmts.extend(declarations);- block.stmts.push(return_stmt);- return;- }-- block.stmts.prepend_stmts(declarations);- }-}--/// Store for `VarDeclarator`s to be added to enclosing statement block.-#[derive(Default, Debug)]-pub struct VarDeclarationsStore {- stack: Vec<Option<Declarators>>,-}--/// Declarators to be inserted in a statement block.-#[derive(Debug, Default)]-struct Declarators {- var_declarators: Vec<VarDeclarator>,- let_declarators: Vec<VarDeclarator>,-}--// Public methods-impl VarDeclarationsStore {- /// Create new `VarDeclarationsStore`.- pub fn new() -> Self {- Self { stack: Vec::new() }- }-- /// Add a `var` declaration to be inserted at top of current enclosing- /// statement block, given a `BindingIdent`.- #[inline]- pub fn insert_var(&mut self, ident: BindingIdent, init: Option<Box<Expr>>) {- let declarator = VarDeclarator {- span: DUMMY_SP,- name: Pat::Ident(ident),- init,- definite: false,- };- self.insert_var_declarator(declarator);- }-- /// Add a `let` declaration to be inserted at top of current enclosing- /// statement block, given a `BindingIdent`.- #[inline]- pub fn insert_let(&mut self, ident: BindingIdent, init: Option<Box<Expr>>) {- let declarator = VarDeclarator {- span: DUMMY_SP,- name: Pat::Ident(ident),- init,- definite: false,- };- self.insert_let_declarator(declarator);- }-- /// Add a `var` declaration to be inserted at top of current enclosing- /// statement block, given a `Pat`.- #[inline]- pub fn insert_var_pattern(&mut self, pattern: Pat, init: Option<Box<Expr>>) {- let declarator = VarDeclarator {- span: DUMMY_SP,- name: pattern,- init,- definite: false,- };- self.insert_var_declarator(declarator);- }-- /// Add a `let` declaration to be inserted at top of current enclosing- /// statement block, given a `Pat`.- #[inline]- pub fn insert_let_pattern(&mut self, pattern: Pat, init: Option<Box<Expr>>) {- let declarator = VarDeclarator {- span: DUMMY_SP,- name: pattern,- init,- definite: false,- };- self.insert_let_declarator(declarator);- }-- /// Add a `var` declaration to be inserted at top of current enclosing- /// statement block.- pub fn insert_var_declarator(&mut self, declarator: VarDeclarator) {- if let Some(last) = self.stack.last_mut() {- let declarators = last.get_or_insert_with(Declarators::default);- declarators.var_declarators.push(declarator);- }- }-- /// Add a `let` declaration to be inserted at top of current enclosing- /// statement block.- pub fn insert_let_declarator(&mut self, declarator: VarDeclarator) {- if let Some(last) = self.stack.last_mut() {- let declarators = last.get_or_insert_with(Declarators::default);- declarators.let_declarators.push(declarator);- }- }-}--// Internal methods-impl VarDeclarationsStore {- fn record_entering_stmts(&mut self) {- self.stack.push(None);- }-- fn insert_into_stmts(&mut self, stmts: &mut Vec<Stmt>) {- if let Some((var_statement, let_statement)) = self.get_var_statement() {- stmts.prepend_stmts(var_statement.into_iter().chain(let_statement));- }- }-- fn insert_into_module_items(&mut self, items: &mut Vec<ModuleItem>) {- if let Some((var_statement, let_statement)) = self.get_var_statement() {- items.prepend_stmts(- var_statement- .into_iter()- .chain(let_statement)- .map(ModuleItem::Stmt),- );- }- }-- #[inline]- fn get_var_statement(&mut self) -> Option<(Option<Stmt>, Option<Stmt>)> {- let declarators = self.stack.pop()??;-- let var_statement = (!declarators.var_declarators.is_empty())- .then(|| Self::create_declaration(VarDeclKind::Var, declarators.var_declarators));- let let_statement = (!declarators.let_declarators.is_empty())- .then(|| Self::create_declaration(VarDeclKind::Let, declarators.let_declarators));-- Some((var_statement, let_statement))- }-- fn create_declaration(kind: VarDeclKind, declarators: Vec<VarDeclarator>) -> Stmt {- Stmt::Decl(Decl::Var(Box::new(VarDecl {- span: DUMMY_SP,- kind,- decls: declarators,- ..Default::default()- })))- }-}
deps/swc/crates/swc_ecma_transformer/src/decorators/mod.rs
@@ -1,17 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct DecoratorOptions {}--pub fn hook(options: DecoratorOptions) -> impl VisitMutHook<TraverseCtx> {- DecoratorPass { options }-}--struct DecoratorPass {- options: DecoratorOptions,-}--impl VisitMutHook<TraverseCtx> for DecoratorPass {}
deps/swc/crates/swc_ecma_transformer/src/es2015/duplicate_keys.rs
@@ -1,209 +0,0 @@-//! ES2015: Duplicate Keys-//!-//! This plugin transforms duplicate keys in object literals to computed-//! properties.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! var x = { a: 5, a: 6 };-//! var y = {-//! get a() {},-//! set a(x) {},-//! a: 3-//! };-//! ```-//!-//! Output:-//! ```js-//! var x = { a: 5, ["a"]: 6 };-//! var y = {-//! get a() {},-//! set a(x) {},-//! ["a"]: 3-//! };-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-duplicate-keys](https://babel.dev/docs/babel-plugin-transform-duplicate-keys).--use rustc_hash::FxHashSet;-use swc_atoms::{Atom, Wtf8Atom};-use swc_common::Spanned;-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::quote_str;--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- DuplicateKeysPass-}--struct DuplicateKeysPass;--impl VisitMutHook<TraverseCtx> for DuplicateKeysPass {- fn exit_expr(&mut self, expr: &mut Expr, _ctx: &mut TraverseCtx) {- if let Expr::Object(ObjectLit { props, .. }) = expr {- let mut folder = PropFolder::default();- folder.visit_props(props);- }- }-}--#[derive(Default)]-struct PropFolder {- getter_props: FxHashSet<Atom>,- setter_props: FxHashSet<Atom>,-}--#[inline]-fn atom_from_wtf8(value: &Wtf8Atom) -> Atom {- value- .as_str()- .map(Atom::from)- .unwrap_or_else(|| Atom::from(value.to_string_lossy()))-}--impl PropFolder {- fn visit_props(&mut self, props: &mut [PropOrSpread]) {- for prop_or_spread in props.iter_mut() {- if let PropOrSpread::Prop(prop) = prop_or_spread {- self.visit_prop(prop);- }- }- }-- fn visit_prop(&mut self, prop: &mut Prop) {- match prop {- Prop::Shorthand(ident) => {- if !self.getter_props.insert(ident.sym.clone())- || !self.setter_props.insert(ident.sym.clone())- {- *prop = Prop::KeyValue(KeyValueProp {- key: PropName::Computed(ComputedPropName {- span: ident.span,- expr: quote_str!(ident.sym.clone()).into(),- }),- value: ident.clone().into(),- })- }- }-- Prop::Assign(..) => {}-- Prop::Getter(GetterProp { key, .. }) => {- self.visit_prop_name(key, PropKind::Getter);- }- Prop::Setter(SetterProp { key, .. }) => {- self.visit_prop_name(key, PropKind::Setter);- }- _ => {- self.visit_prop_name_for_key_value_or_method(prop);- }- }- }-- fn visit_prop_name_for_key_value_or_method(&mut self, prop: &mut Prop) {- match prop {- Prop::KeyValue(KeyValueProp { key, .. }) | Prop::Method(MethodProp { key, .. }) => {- // Check in both getter and setter props- let mut should_transform = false;- let span = key.span();-- match key {- PropName::Ident(ident) => {- if !self.getter_props.insert(ident.sym.clone()) {- should_transform = true;- }- if !self.setter_props.insert(ident.sym.clone()) {- should_transform = true;- }- if should_transform {- *key = PropName::Computed(ComputedPropName {- span,- expr: Lit::Str(Str {- span,- raw: None,- value: ident.sym.clone().into(),- })- .into(),- });- }- }- PropName::Str(s) => {- let atom = atom_from_wtf8(&s.value);- if !self.getter_props.insert(atom.clone()) {- should_transform = true;- }- if !self.setter_props.insert(atom) {- should_transform = true;- }- if should_transform {- *key = PropName::Computed(ComputedPropName {- span: s.span,- expr: s.clone().into(),- });- }- }- PropName::Computed(ComputedPropName { expr, .. }) => {- // Computed property might collide- if let Expr::Lit(Lit::Str(Str { ref value, .. })) = &**expr {- let atom = atom_from_wtf8(value);- self.getter_props.insert(atom.clone());- self.setter_props.insert(atom);- }- }- _ => {}- }- }- _ => {}- }- }-- fn visit_prop_name(&mut self, name: &mut PropName, kind: PropKind) {- let props = match kind {- PropKind::Getter => &mut self.getter_props,- PropKind::Setter => &mut self.setter_props,- };-- let span = name.span();-- match name {- PropName::Ident(ident) if !props.insert(ident.sym.clone()) => {- *name = PropName::Computed(ComputedPropName {- span,- expr: Lit::Str(Str {- span,- raw: None,- value: ident.sym.clone().into(),- })- .into(),- })- }- PropName::Str(s) if !props.insert(atom_from_wtf8(&s.value)) => {- *name = PropName::Computed(ComputedPropName {- span: s.span,- expr: s.clone().into(),- })- }- PropName::Ident(_) | PropName::Str(_) => {}- PropName::Computed(ComputedPropName { expr, .. }) => {- // Computed property might collide- if let Expr::Lit(Lit::Str(Str { ref value, .. })) = &**expr {- props.insert(atom_from_wtf8(value));- }- }- _ => {}- }- }-}--enum PropKind {- Getter,- Setter,-}
deps/swc/crates/swc_ecma_transformer/src/es2015/function_name.rs
@@ -1,133 +0,0 @@-//! ES2015: Function Name-//!-//! This plugin transforms anonymous function expressions to named function-//! expressions based on the variable/property they're assigned to.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! var number = function (x) {-//! return x;-//! };-//! var Foo = (class {});-//! ```-//!-//! Output:-//! ```js-//! var number = function number(x) {-//! return x;-//! }-//! var Foo = (class Foo {});-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-function-name](https://babel.dev/docs/babel-plugin-transform-function-name).--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::{private_ident, IdentUsageFinder};--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- FunctionNamePass-}--struct FunctionNamePass;--/// This function makes a new private identifier if required.-fn prepare(i: Ident) -> Ident {- if i.is_reserved() || i.is_reserved_in_strict_mode(true) || i.is_reserved_in_strict_bind() {- return private_ident!(i.span, format!("_{}", i.sym));- }-- private_ident!(i.span, i.sym)-}--impl VisitMutHook<TraverseCtx> for FunctionNamePass {- fn exit_assign_expr(&mut self, expr: &mut AssignExpr, _ctx: &mut TraverseCtx) {- if expr.op != op!("=") {- return;- }-- if let Some(ident) = expr.left.as_ident_mut() {- let name = Ident::from(&*ident);- rename_fn_or_class(&mut expr.right, Some(name));- }- }-- fn exit_key_value_prop(&mut self, p: &mut KeyValueProp, _ctx: &mut TraverseCtx) {- rename_key_value_prop(p);- }-- fn exit_prop(&mut self, prop: &mut Prop, _ctx: &mut TraverseCtx) {- // Handle KeyValue props here too, because shorthand transform may have- // converted Method to KeyValue in its exit_prop handler, which runs- // before this one in the chain.- if let Prop::KeyValue(p) = prop {- rename_key_value_prop(p);- }- }-- fn exit_var_declarator(&mut self, decl: &mut VarDeclarator, _ctx: &mut TraverseCtx) {- if let Pat::Ident(ref ident) = decl.name {- let name = prepare(Ident::from(ident));- if let Some(ref mut init) = decl.init {- rename_fn_or_class(init, Some(name));- }- }- }-}--fn rename_key_value_prop(p: &mut KeyValueProp) {- if let Expr::Fn(expr @ FnExpr { ident: None, .. }) = &mut *p.value {- if let PropName::Ident(ref i) = p.key {- p.value = FnExpr {- ident: Some(prepare(i.clone().into())),- ..expr.take()- }- .into();- }- }-}--fn rename_fn_or_class(expr: &mut Expr, name: Option<Ident>) {- match expr {- Expr::Fn(FnExpr {- ident: ident @ None,- function,- ..- }) => {- let name = match name {- None => return,- Some(name) => name,- };- // If function's body references the name of variable, we just skip- if IdentUsageFinder::find(&name, function.as_ref()) {- return;- }- *ident = Some(private_ident!(DUMMY_SP, name.sym));- }- Expr::Class(ClassExpr {- ident: ident @ None,- class,- ..- }) => {- let name = match name {- None => return,- Some(name) => name,- };- // If class body references the name of variable, we just skip- if IdentUsageFinder::find(&name, class.as_ref()) {- return;- }- *ident = Some(private_ident!(DUMMY_SP, name.sym));- }- _ => {}- }-}
deps/swc/crates/swc_ecma_transformer/src/es2015/instanceof.rs
@@ -1,125 +0,0 @@-//! ES2015: instanceof-//!-//! This plugin transforms the `instanceof` operator to use a helper function-//! that properly handles Symbol.hasInstance.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! foo instanceof Bar;-//! ```-//!-//! Output:-//! ```js-//! function _instanceof(left, right) {-//! if (right != null && typeof Symbol !== "undefined" &&-//! right[Symbol.hasInstance]) {-//! return !!right[Symbol.hasInstance](left);-//! } else {-//! return left instanceof right;-//! }-//! }-//!-//! _instanceof(foo, Bar);-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-instanceof](https://babel.dev/docs/babel-plugin-transform-instanceof).--use swc_common::{util::take::Take, Span, Spanned};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::helper;-use swc_ecma_utils::ExprFactory;--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- InstanceOfPass::default()-}--#[derive(Default)]-struct InstanceOfPass {- /// When non-zero, we're inside a helper function and should skip- /// transformation.- in_helper_fn: u32,-}--impl VisitMutHook<TraverseCtx> for InstanceOfPass {- fn exit_expr(&mut self, expr: &mut Expr, _ctx: &mut TraverseCtx) {- if self.in_helper_fn > 0 {- return;- }-- if let Expr::Bin(BinExpr {- span,- left,- op: op!("instanceof"),- right,- }) = expr- {- let instanceof_span = Span {- lo: left.span_hi(),- hi: right.span_lo(),- };-- *expr = CallExpr {- span: *span,- callee: helper!(instanceof_span, instanceof),- args: vec![left.take().as_arg(), right.take().as_arg()],- ..Default::default()- }- .into();- }- }-- fn enter_fn_decl(&mut self, f: &mut FnDecl, _ctx: &mut TraverseCtx) {- if &f.ident.sym == "_instanceof" {- self.in_helper_fn += 1;- }- }-- fn exit_fn_decl(&mut self, f: &mut FnDecl, _ctx: &mut TraverseCtx) {- if &f.ident.sym == "_instanceof" {- self.in_helper_fn = self.in_helper_fn.saturating_sub(1);- }- }-- fn enter_function(&mut self, f: &mut Function, _ctx: &mut TraverseCtx) {- if let Some(body) = &f.body {- if let Some(Stmt::Expr(first)) = body.stmts.first() {- if let Expr::Lit(Lit::Str(s)) = &*first.expr {- if let Some(text) = s.value.as_str() {- if matches!(- text,- "@swc/helpers - instanceof" | "@babel/helpers - instanceof"- ) {- self.in_helper_fn += 1;- }- }- }- }- }- }-- fn exit_function(&mut self, f: &mut Function, _ctx: &mut TraverseCtx) {- if let Some(body) = &f.body {- if let Some(Stmt::Expr(first)) = body.stmts.first() {- if let Expr::Lit(Lit::Str(s)) = &*first.expr {- if let Some(text) = s.value.as_str() {- if matches!(- text,- "@swc/helpers - instanceof" | "@babel/helpers - instanceof"- ) {- self.in_helper_fn = self.in_helper_fn.saturating_sub(1);- }- }- }- }- }- }-}
deps/swc/crates/swc_ecma_transformer/src/es2015/mod.rs
@@ -1,95 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::{- hook_utils::{HookBuilder, NoopHook},- TraverseCtx,-};--pub(crate) mod duplicate_keys;-pub(crate) mod function_name;-pub(crate) mod instanceof;-pub(crate) mod shorthand;-mod sticky_regex;-pub(crate) mod typeof_symbol;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2015Options {- /// Enable shorthand properties transformation- pub shorthand: bool,-- /// Enable function name transformation- pub function_name: bool,-- /// Enable duplicate keys transformation- pub duplicate_keys: bool,-- /// Enable sticky regex transformation- pub sticky_regex: bool,-- /// Enable instanceof transformation- pub instanceof: bool,-- /// Enable typeof symbol transformation- pub typeof_symbol: bool,-}--impl Es2015Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.shorthand- || self.function_name- || self.duplicate_keys- || self.sticky_regex- || self.instanceof- || self.typeof_symbol- }-}--pub fn hook(options: Es2015Options) -> impl VisitMutHook<TraverseCtx> {- let hook = HookBuilder::new(NoopHook);-- // Shorthand properties: { a } -> { a: a }- let hook = hook.chain(if options.shorthand {- Some(self::shorthand::hook())- } else {- None- });-- // Function name: var f = function() {} -> var f = function f() {}- let hook = hook.chain(if options.function_name {- Some(self::function_name::hook())- } else {- None- });-- // Duplicate keys: { a: 1, a: 2 } -> { a: 1, ["a"]: 2 }- let hook = hook.chain(if options.duplicate_keys {- Some(self::duplicate_keys::hook())- } else {- None- });-- // Sticky regex: /foo/y -> new RegExp("foo", "y")- let hook = hook.chain(if options.sticky_regex {- Some(self::sticky_regex::hook())- } else {- None- });-- // instanceof: a instanceof B -> _instanceof(a, B)- let hook = hook.chain(if options.instanceof {- Some(self::instanceof::hook())- } else {- None- });-- // typeof symbol: typeof x -> _typeof(x)- let hook = hook.chain(if options.typeof_symbol {- Some(self::typeof_symbol::hook())- } else {- None- });-- hook.build()-}
deps/swc/crates/swc_ecma_transformer/src/es2015/shorthand.rs
@@ -1,95 +0,0 @@-//! ES2015: Shorthand Properties-//!-//! This plugin transforms shorthand properties and methods to ES5.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! var o = { a, b, c };-//! var cat = {-//! getName() {-//! return name;-//! }-//! };-//! ```-//!-//! Output:-//! ```js-//! var o = { a: a, b: b, c: c };-//! var cat = {-//! getName: function () {-//! return name;-//! }-//! };-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-shorthand-properties](https://babel.dev/docs/babel-plugin-transform-shorthand-properties).--use swc_common::util::take::Take;-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- ShorthandPass-}--struct ShorthandPass;--impl VisitMutHook<TraverseCtx> for ShorthandPass {- fn exit_prop(&mut self, prop: &mut Prop, _ctx: &mut TraverseCtx) {- match prop {- Prop::Shorthand(ident) => {- let value = ident.clone().into();-- *prop = Prop::KeyValue(KeyValueProp {- key: if ident.sym == "__proto__" {- PropName::Computed(ComputedPropName {- span: ident.span,- expr: ident.sym.clone().into(),- })- } else {- ident.take().into()- },- value,- });- }- Prop::Method(MethodProp { key, function }) => {- let key = match key.take() {- PropName::Ident(IdentName { span, sym, .. }) if sym == "__proto__" => {- ComputedPropName {- span,- expr: sym.into(),- }- .into()- }- PropName::Str(s @ Str { span, .. })- if s.value.as_str() == Some("__proto__") =>- {- ComputedPropName {- span,- expr: s.into(),- }- .into()- }- key => key,- };- *prop = Prop::KeyValue(KeyValueProp {- key,- value: FnExpr {- ident: None,- function: function.take(),- }- .into(),- })- }- _ => {}- }- }-}
deps/swc/crates/swc_ecma_transformer/src/es2015/sticky_regex.rs
@@ -1,49 +0,0 @@-//! ES2015: Sticky Regex-//!-//! This plugin transforms sticky regex literals to RegExp constructor calls.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! /o+/y;-//! ```-//!-//! Output:-//! ```js-//! new RegExp("o+", "y")-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-sticky-regex](https://babel.dev/docs/babel-plugin-transform-sticky-regex).--use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::{quote_ident, ExprFactory};--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- StickyRegexPass-}--struct StickyRegexPass;--impl VisitMutHook<TraverseCtx> for StickyRegexPass {- fn exit_expr(&mut self, e: &mut Expr, _ctx: &mut TraverseCtx) {- if let Expr::Lit(Lit::Regex(Regex { exp, flags, span })) = e {- if flags.contains('y') {- *e = NewExpr {- span: *span,- callee: Box::new(quote_ident!(Default::default(), *span, "RegExp").into()),- args: Some(vec![exp.clone().as_arg(), flags.clone().as_arg()]),- ..Default::default()- }- .into()- }- }- }-}
deps/swc/crates/swc_ecma_transformer/src/es2015/typeof_symbol.rs
@@ -1,224 +0,0 @@-//! ES2015: typeof Symbol-//!-//! This plugin transforms `typeof` expressions to properly handle Symbol type.-//!-//! > This plugin is included in `preset-env`, in ES2015-//!-//! ## Example-//!-//! Input:-//! ```js-//! typeof Symbol() === "symbol";-//! typeof sym;-//! ```-//!-//! Output:-//! ```js-//! typeof Symbol() === "symbol";-//! typeof sym === "undefined" ? "undefined" : _typeof(sym);-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-typeof-symbol](https://babel.dev/docs/babel-plugin-transform-typeof-symbol).--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::helper;-use swc_ecma_utils::{quote_str, ExprFactory};--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- TypeofSymbolPass::default()-}--#[derive(Default)]-struct TypeofSymbolPass {- /// When non-zero, skip transforming typeof expressions.- /// This is incremented when entering a binary comparison with non-symbol- /// literals, and decremented when exiting.- skip_depth: u32,-- /// When non-zero, we're inside a helper function and should skip- /// transformation.- in_helper_fn: u32,-}--impl VisitMutHook<TraverseCtx> for TypeofSymbolPass {- fn enter_bin_expr(&mut self, expr: &mut BinExpr, _ctx: &mut TraverseCtx) {- // Skip transformation for certain comparison patterns- match expr.op {- op!("==") | op!("!=") | op!("===") | op!("!==") => {}- _ => return,- }-- // If comparing typeof with a non-symbol literal, skip transforming children- if let Expr::Unary(UnaryExpr {- op: op!("typeof"), ..- }) = *expr.left- {- if is_non_symbol_literal(&expr.right) {- self.skip_depth += 1;- return;- }- }- if let Expr::Unary(UnaryExpr {- op: op!("typeof"), ..- }) = *expr.right- {- if is_non_symbol_literal(&expr.left) {- self.skip_depth += 1;- }- }- }-- fn exit_bin_expr(&mut self, expr: &mut BinExpr, _ctx: &mut TraverseCtx) {- // Decrement skip_depth when exiting a binary expression we marked- match expr.op {- op!("==") | op!("!=") | op!("===") | op!("!==") => {}- _ => return,- }-- if let Expr::Unary(UnaryExpr {- op: op!("typeof"), ..- }) = *expr.left- {- if is_non_symbol_literal(&expr.right) {- self.skip_depth = self.skip_depth.saturating_sub(1);- return;- }- }- if let Expr::Unary(UnaryExpr {- op: op!("typeof"), ..- }) = *expr.right- {- if is_non_symbol_literal(&expr.left) {- self.skip_depth = self.skip_depth.saturating_sub(1);- }- }- }-- fn exit_expr(&mut self, expr: &mut Expr, _ctx: &mut TraverseCtx) {- // Skip transformation if we're inside a binary comparison with non-symbol- // literals or inside a helper function- if self.skip_depth > 0 || self.in_helper_fn > 0 {- return;- }-- if let Expr::Unary(UnaryExpr {- span,- op: op!("typeof"),- arg,- }) = expr- {- match &**arg {- Expr::Ident(..) => {- let undefined_str: Box<Expr> = quote_str!("undefined").into();-- let test = BinExpr {- span: DUMMY_SP,- op: op!("==="),- left: Box::new(- UnaryExpr {- span: DUMMY_SP,- op: op!("typeof"),- arg: arg.clone(),- }- .into(),- ),- right: undefined_str.clone(),- }- .into();-- let call = CallExpr {- span: *span,- callee: helper!(*span, type_of),- args: vec![arg.take().as_arg()],- ..Default::default()- }- .into();-- *expr = CondExpr {- span: *span,- test,- cons: undefined_str,- alt: Box::new(call),- }- .into();- }- _ => {- let call = CallExpr {- span: *span,- callee: helper!(*span, type_of),- args: vec![arg.take().as_arg()],-- ..Default::default()- }- .into();-- *expr = call;- }- }- }- }-- fn enter_fn_decl(&mut self, f: &mut FnDecl, _ctx: &mut TraverseCtx) {- // Skip helper function- if &f.ident.sym == "_type_of" {- self.in_helper_fn += 1;- }- }-- fn exit_fn_decl(&mut self, f: &mut FnDecl, _ctx: &mut TraverseCtx) {- if &f.ident.sym == "_type_of" {- self.in_helper_fn = self.in_helper_fn.saturating_sub(1);- }- }-- fn enter_function(&mut self, f: &mut Function, _ctx: &mut TraverseCtx) {- // Skip functions with the @swc/helpers - typeof directive- if let Some(body) = &f.body {- if let Some(Stmt::Expr(first)) = body.stmts.first() {- if let Expr::Lit(Lit::Str(s)) = &*first.expr {- if let Some(text) = s.value.as_str() {- if matches!(text, "@swc/helpers - typeof" | "@babel/helpers - typeof") {- self.in_helper_fn += 1;- }- }- }- }- }- }-- fn exit_function(&mut self, f: &mut Function, _ctx: &mut TraverseCtx) {- // Match the enter_function logic to decrement- if let Some(body) = &f.body {- if let Some(Stmt::Expr(first)) = body.stmts.first() {- if let Expr::Lit(Lit::Str(s)) = &*first.expr {- if let Some(text) = s.value.as_str() {- if matches!(text, "@swc/helpers - typeof" | "@babel/helpers - typeof") {- self.in_helper_fn = self.in_helper_fn.saturating_sub(1);- }- }- }- }- }- }-}--#[inline]-fn is_non_symbol_literal(e: &Expr) -> bool {- match e {- Expr::Lit(Lit::Str(Str { value, .. })) => matches!(- value.as_str(),- Some("undefined")- | Some("boolean")- | Some("number")- | Some("string")- | Some("function")- ),- _ => false,- }-}
deps/swc/crates/swc_ecma_transformer/src/es2016/exponentiation_operator.rs
@@ -1,316 +0,0 @@-//! ES2016: Exponentiation Operator-//!-//! This plugin transforms the exponentiation operator (`**`) to `Math.pow`.-//!-//! > This plugin is included in `preset-env`, in ES2016-//!-//! ## Example-//!-//! Input:-//! ```js-//! let x = 10 ** 2;-//! x **= 3;-//! obj.prop **= 4;-//! ```-//!-//! Output:-//! ```js-//! let x = Math.pow(10, 2);-//! x = Math.pow(x, 3);-//! obj["prop"] = Math.pow(obj["prop"], 4);-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-exponentiation-operator](https://babel.dev/docs/babel-plugin-transform-exponentiation-operator).-//!-//! ## References:-//!-//! * Babel plugin implementation: <https://github.com/babel/babel/blob/v7.26.2/packages/babel-plugin-transform-exponentiation-operator>-//! <https://github.com/babel/babel/tree/v7.26.2/packages/babel-helper-builder-binary-assignment-operator-visitor>-//! * Exponentiation operator TC39 proposal: <https://github.com/tc39/proposal-exponentiation-operator>-//! * Exponentiation operator specification: <https://tc39.es/ecma262/#sec-exp-operator>--use swc_common::{util::take::Take, SyntaxContext, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;--use crate::{utils, TraverseCtx};--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- ExponentiationOperatorPass-}--struct ExponentiationOperatorPass;--impl VisitMutHook<TraverseCtx> for ExponentiationOperatorPass {- fn enter_expr(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- match expr {- // `left ** right` -> `Math.pow(left, right)`- Expr::Bin(bin_expr) if bin_expr.op == BinaryOp::Exp => {- // Do not transform BigInt- if is_bigint_literal(&bin_expr.left) || is_bigint_literal(&bin_expr.right) {- return;- }-- let left = bin_expr.left.take();- let right = bin_expr.right.take();- *expr = create_math_pow(left, right);- }- // `left **= right` -> various transformations- Expr::Assign(assign_expr) if assign_expr.op == AssignOp::ExpAssign => {- // Do not transform BigInt- if is_bigint_literal(&assign_expr.right) {- return;- }-- self.transform_exp_assign(expr, ctx);- }- _ => {}- }- }-}--impl ExponentiationOperatorPass {- /// Transform exponentiation assignment expression- ///- /// Transforms based on the type of left side:- /// - Identifier: `x **= 2` -> `x = Math.pow(x, 2)`- /// - Member expression: `obj.prop **= 2` -> `obj.prop = Math.pow(obj.prop,- /// 2)` or with temp var- fn transform_exp_assign(&self, expr: &mut Expr, ctx: &mut TraverseCtx) {- let Expr::Assign(assign_expr) = expr else {- return;- };-- match &mut assign_expr.left {- // Simple identifier: `x **= 2` -> `x = Math.pow(x, 2)`- AssignTarget::Simple(SimpleAssignTarget::Ident(ident)) => {- let left = ident.id.clone();- let right = assign_expr.right.take();-- let pow_left = Box::new(Expr::Ident(left.clone()));- let pow_call = create_math_pow(pow_left, right);-- *expr = Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: left,- type_ann: None,- })),- right: Box::new(pow_call),- });- }- // Member expression: needs special handling to avoid side effects- AssignTarget::Simple(SimpleAssignTarget::Member(member_expr)) => {- // Clone the data we need before borrowing mutably- let obj = member_expr.obj.take();- let prop = member_expr.prop.take();- let right = assign_expr.right.take();-- self.transform_member_exp_assign_impl(expr, ctx, obj, prop, right);- }- _ => {}- }- }-- /// Transform member expression exponentiation assignment implementation- ///- /// Uses temporary variables to avoid side effects:- /// - `obj.prop **= 2` -> `(_obj = obj, _obj.prop = Math.pow(_obj.prop, 2))`- /// - `obj[prop] **= 2` -> `(_obj = obj, _prop = prop, _obj[_prop] =- /// Math.pow(_obj[_prop], 2))`- fn transform_member_exp_assign_impl(- &self,- expr: &mut Expr,- ctx: &mut TraverseCtx,- obj: Box<Expr>,- prop: MemberProp,- right: Box<Expr>,- ) {- // Check if we need a temp variable for the object- let needs_obj_temp = !matches!(*obj, Expr::Ident(_));-- let mut sequence_exprs = Vec::new();-- // Create temp variable for object if needed- let (final_obj, obj_for_pow) = if needs_obj_temp {- let temp_name = utils::generate_temp_var_name(&obj);- let temp_ident = utils::create_private_ident(&temp_name);-- // Add variable declaration- ctx.var_declarations- .insert_var(temp_ident.clone().into(), None);-- // Add assignment to sequence: _obj = obj- sequence_exprs.push(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: temp_ident.clone(),- type_ann: None,- })),- right: obj,- }));-- let obj_expr = Box::new(Expr::Ident(temp_ident.clone()));- (obj_expr.clone(), obj_expr)- } else {- (obj.clone(), obj)- };-- match prop {- // obj.prop **= right -> (_obj = obj, _obj.prop = Math.pow(_obj.prop, right))- MemberProp::Ident(prop_name) => {- // Create Math.pow(obj.prop, right)- let pow_left = Box::new(Expr::Member(MemberExpr {- span: DUMMY_SP,- obj: obj_for_pow,- prop: MemberProp::Ident(prop_name.clone()),- }));- let pow_call = create_math_pow(pow_left, right);-- // obj.prop = Math.pow(obj.prop, right)- let assignment = Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr {- span: DUMMY_SP,- obj: final_obj,- prop: MemberProp::Ident(prop_name),- })),- right: Box::new(pow_call),- });-- if needs_obj_temp {- sequence_exprs.push(assignment);- *expr = Expr::Seq(SeqExpr {- span: DUMMY_SP,- exprs: sequence_exprs.into_iter().map(Box::new).collect(),- });- } else {- *expr = assignment;- }- }- // obj[computed] **= right -> (_obj = obj, _prop = prop, _obj[_prop] =- // Math.pow(_obj[_prop], right))- MemberProp::Computed(computed) => {- let computed_prop = computed.expr;-- // Check if we need a temp variable for the computed property- let needs_prop_temp = !is_literal_expr(&computed_prop);-- let (final_prop, prop_for_pow) = if needs_prop_temp {- let temp_name = match &*computed_prop {- Expr::Ident(ident) => format!("_{}", ident.sym),- _ => "_prop".to_string(),- };- let temp_ident = utils::create_private_ident(&temp_name);-- // Add variable declaration- ctx.var_declarations- .insert_var(temp_ident.clone().into(), None);-- // Add assignment to sequence: _prop = prop- sequence_exprs.push(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: temp_ident.clone(),- type_ann: None,- })),- right: computed_prop,- }));-- let prop_expr = Box::new(Expr::Ident(temp_ident.clone()));- (prop_expr.clone(), prop_expr)- } else {- (computed_prop.clone(), computed_prop)- };-- // Create Math.pow(obj[computed], right)- let pow_left = Box::new(Expr::Member(MemberExpr {- span: DUMMY_SP,- obj: obj_for_pow,- prop: MemberProp::Computed(ComputedPropName {- span: DUMMY_SP,- expr: prop_for_pow,- }),- }));- let pow_call = create_math_pow(pow_left, right);-- // obj[computed] = Math.pow(obj[computed], right)- let assignment = Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Member(MemberExpr {- span: DUMMY_SP,- obj: final_obj,- prop: MemberProp::Computed(ComputedPropName {- span: DUMMY_SP,- expr: final_prop,- }),- })),- right: Box::new(pow_call),- });-- if needs_obj_temp || needs_prop_temp {- sequence_exprs.push(assignment);- *expr = Expr::Seq(SeqExpr {- span: DUMMY_SP,- exprs: sequence_exprs.into_iter().map(Box::new).collect(),- });- } else {- *expr = assignment;- }- }- _ => {}- }- }-}--/// Check if an expression is a literal (and safe to evaluate multiple times)-fn is_literal_expr(expr: &Expr) -> bool {- matches!(- expr,- Expr::Lit(_) | Expr::Ident(_) | Expr::This(_) | Expr::PrivateName(_)- )-}--/// Create `Math.pow(left, right)` call expression-fn create_math_pow(left: Box<Expr>, right: Box<Expr>) -> Expr {- Expr::Call(CallExpr {- span: DUMMY_SP,- ctxt: SyntaxContext::empty(),- callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {- span: DUMMY_SP,- obj: Box::new(Expr::Ident(Ident {- span: DUMMY_SP,- ctxt: SyntaxContext::empty(),- sym: "Math".into(),- optional: false,- })),- prop: MemberProp::Ident(IdentName {- span: DUMMY_SP,- sym: "pow".into(),- }),- }))),- args: vec![- ExprOrSpread {- spread: None,- expr: left,- },- ExprOrSpread {- spread: None,- expr: right,- },- ],- type_args: None,- })-}--/// Check if an expression is a BigInt literal-fn is_bigint_literal(expr: &Expr) -> bool {- matches!(expr, Expr::Lit(Lit::BigInt(_)))-}
deps/swc/crates/swc_ecma_transformer/src/es2016/mod.rs
@@ -1,26 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--pub(crate) mod exponentiation_operator;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2016Options {- pub exponentiation_operator: bool,-}--impl Es2016Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.exponentiation_operator- }-}--pub fn hook(options: Es2016Options) -> impl VisitMutHook<TraverseCtx> {- if options.exponentiation_operator {- Some(self::exponentiation_operator::hook())- } else {- None- }-}
deps/swc/crates/swc_ecma_transformer/src/es2017/async_to_generator.rs
@@ -1,1643 +0,0 @@-use std::mem;--use swc_common::{util::take::Take, Spanned, SyntaxContext, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::{helper, helper_expr};-use swc_ecma_utils::{- function::{init_this, FnEnvHoister},- prepend_stmt, private_ident, quote_ident, ExprFactory,-};-use swc_ecma_visit::VisitMutWith;--use crate::TraverseCtx;--mod loop_head_scope;--use self::loop_head_scope::LoopHeadScope;--pub fn hook(- transform_async_to_generator: bool,- transform_async_generator_functions: bool,- unresolved_ctxt: SyntaxContext,- ignore_function_length: bool,-) -> impl VisitMutHook<TraverseCtx> {- AsyncToGeneratorPass {- fn_state: None,- fn_state_stack: vec![],- in_subclass: false,- in_subclass_stack: vec![],- ignore_function_length,- unresolved_ctxt,- transform_async_to_generator,- transform_async_generator_functions,- this_var: None,- }-}--/// Selects the suspension expression used while lowering a `for await` loop.-#[derive(Clone, Copy, Debug)]-enum AwaitForMode {- NativeAsync,- Generator,- AsyncGenerator,-}--#[derive(Default, Clone, Debug)]-struct FnState {- should_transform: bool,- is_generator: bool,- is_arrow: bool,- /// The iterator operation form required by this function's output.- await_for_mode: Option<AwaitForMode>,- use_this: bool,- use_arguments: bool,- use_super: bool,- /// True if this function is in a constructor body (not nested in another- /// function)- in_constructor: bool,-}--struct AsyncToGeneratorPass {- fn_state: Option<FnState>,- fn_state_stack: Vec<FnState>,- in_subclass: bool,- in_subclass_stack: Vec<bool>,- ignore_function_length: bool,- unresolved_ctxt: SyntaxContext,- /// Whether ordinary async functions should be lowered.- transform_async_to_generator: bool,- /// Whether async generators should be lowered.- transform_async_generator_functions: bool,- /// The `_this` identifier to use in constructor context- this_var: Option<Ident>,-}--impl VisitMutHook<TraverseCtx> for AsyncToGeneratorPass {- fn exit_function(&mut self, function: &mut Function, _ctx: &mut TraverseCtx) {- let Some(body) = &mut function.body else {- return;- };-- let fn_state = self.fn_state.take();- let Some(mut fn_state) = fn_state else {- // Function with no body- return;- };-- if !fn_state.should_transform {- // Restore the previous fn_state from stack- self.fn_state = self.fn_state_stack.pop();- return;- }-- let mut stmts = vec![];- if fn_state.use_super {- // slow path- let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);- fn_env_hoister.disable_this();- fn_env_hoister.disable_arguments();-- body.visit_mut_with(&mut fn_env_hoister);-- stmts.extend(fn_env_hoister.to_stmt());- }-- function.is_async = false;- function.is_generator = false;- if !fn_state.use_arguments {- // Errors thrown during argument evaluation must reject the resulting promise,- // which needs more complex code to handle- fn_state.use_arguments =- could_potentially_throw(&function.params, self.unresolved_ctxt);- }-- let params = if fn_state.use_arguments {- let mut params = vec![];-- if !self.ignore_function_length {- let fn_len = function- .params- .iter()- .filter(|p| !matches!(p.pat, Pat::Assign(..) | Pat::Rest(..)))- .count();- for i in 0..fn_len {- params.push(Param {- pat: private_ident!(format!("_{}", i)).into(),- span: DUMMY_SP,- decorators: vec![],- });- }- }-- mem::replace(&mut function.params, params)- } else {- vec![]- };-- let expr = make_fn_ref(&fn_state, params, body.take());-- stmts.push(- ReturnStmt {- arg: Some(expr.into()),- ..Default::default()- }- .into(),- );-- function.body = Some(FunctionBody {- span: DUMMY_SP,- stmts,- });-- // Restore the previous fn_state from stack after processing async function- self.fn_state = self.fn_state_stack.pop();- }-- fn enter_function(&mut self, function: &mut Function, _ctx: &mut TraverseCtx) {- let Some(_body) = &mut function.body else {- return;- };-- // Save the current fn_state to stack before entering nested function- if let Some(prev) = self.fn_state.take() {- self.fn_state_stack.push(prev);- }-- let should_transform = function.is_async- && if function.is_generator {- self.transform_async_generator_functions- } else {- self.transform_async_to_generator- };- let await_for_mode = if should_transform {- Some(if function.is_generator {- AwaitForMode::AsyncGenerator- } else {- AwaitForMode::Generator- })- } else if function.is_async && self.transform_async_generator_functions {- Some(AwaitForMode::NativeAsync)- } else {- None- };-- self.fn_state = Some(FnState {- should_transform,- is_generator: function.is_generator,- await_for_mode,- ..Default::default()- });- }-- fn exit_arrow_expr(&mut self, arrow_expr: &mut ArrowExpr, _ctx: &mut TraverseCtx) {- if !arrow_expr.is_async- || !(self.transform_async_to_generator || self.transform_async_generator_functions)- {- return;- }-- // arrow expressions cannot be generator- debug_assert!(!arrow_expr.is_generator);-- let fn_state = self.fn_state.take().unwrap();-- // Restore the previous fn_state from stack. Preserved async arrows still- // capture lexical references from a parent that may be transformed.- let parent_fn_state = self.fn_state_stack.pop();-- if let Some(mut parent_fn_state) = parent_fn_state {- if fn_state.should_transform- || parent_fn_state.should_transform- || parent_fn_state.is_arrow- {- parent_fn_state.use_this |= fn_state.use_this;- parent_fn_state.use_arguments |= fn_state.use_arguments;- parent_fn_state.use_super |= fn_state.use_super;- }- self.fn_state = Some(parent_fn_state);- }-- if !fn_state.should_transform {- return;- }-- let mut stmts = vec![];- // When using `super`, we need to hoist- if fn_state.use_super {- // slow path - hoist super references- let mut fn_env_hoister = FnEnvHoister::new(self.unresolved_ctxt);- fn_env_hoister.disable_this();- fn_env_hoister.disable_arguments();-- arrow_expr.body.visit_mut_with(&mut fn_env_hoister);-- stmts.extend(fn_env_hoister.to_stmt());- }-- // In constructor context with `this`, replace `this` with `_this`- if fn_state.in_constructor && fn_state.use_this {- if self.this_var.is_none() {- self.this_var = Some(private_ident!("_this"));- }- let this_var = self.this_var.clone().unwrap();- replace_this_in_arrow_function_body(&mut arrow_expr.body, &this_var);- }-- arrow_expr.is_async = false;-- let body = match *arrow_expr.body.take() {- ArrowFunctionBody::FunctionBody(body) => body,- ArrowFunctionBody::Expr(expr) => FunctionBody {- span: DUMMY_SP,- stmts: vec![ReturnStmt {- arg: Some(expr),- ..Default::default()- }- .into()],- },- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- };-- let expr = make_fn_ref(&fn_state, vec![], body);-- arrow_expr.body = if fn_state.use_super {- stmts.push(expr.into_stmt());- ArrowFunctionBody::FunctionBody(FunctionBody {- span: DUMMY_SP,- stmts,- })- } else {- ArrowFunctionBody::Expr(Box::new(expr))- }- .into()- }-- fn enter_arrow_expr(&mut self, arrow_expr: &mut ArrowExpr, _ctx: &mut TraverseCtx) {- if !arrow_expr.is_async- || !(self.transform_async_to_generator || self.transform_async_generator_functions)- {- return;- }-- // Save the current fn_state to stack before entering nested arrow function- let in_constructor = self- .fn_state- .as_ref()- .map(|s| s.in_constructor)- .unwrap_or(false);-- if let Some(prev) = self.fn_state.take() {- self.fn_state_stack.push(prev);- }-- self.fn_state = Some(FnState {- should_transform: self.transform_async_to_generator,- is_generator: false,- is_arrow: true,- await_for_mode: Some(if self.transform_async_to_generator {- AwaitForMode::Generator- } else {- AwaitForMode::NativeAsync- }),- in_constructor,- ..Default::default()- });- }-- fn enter_class(&mut self, class: &mut Class, _ctx: &mut TraverseCtx) {- self.in_subclass_stack.push(self.in_subclass);- self.in_subclass = class.super_class.is_some();- }-- fn exit_class(&mut self, _class: &mut Class, _ctx: &mut TraverseCtx) {- self.in_subclass = self.in_subclass_stack.pop().unwrap_or(false);- }-- fn enter_constructor(&mut self, _constructor: &mut Constructor, _ctx: &mut TraverseCtx) {- // Mark that we're in a constructor for nested async arrows- if self.in_subclass {- // Save the current fn_state to stack- if let Some(prev) = self.fn_state.take() {- self.fn_state_stack.push(prev);- }-- self.fn_state = Some(FnState {- in_constructor: true,- ..Default::default()- });- }- }-- fn exit_constructor(&mut self, constructor: &mut Constructor, _ctx: &mut TraverseCtx) {- if self.in_subclass {- let fn_state = self.fn_state.take();-- // If any async arrows used `this`, we need to add var _this and _this = this- if let Some(FunctionBody { stmts, .. }) = &mut constructor.body {- if let Some(fn_state) = &fn_state {- if fn_state.use_this {- let this_var = self.this_var.take().unwrap();-- // Add `_this = this` after super() call- init_this(stmts, &this_var);-- // Add `var _this;` at the beginning- let decl = VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Var,- decls: vec![VarDeclarator {- span: DUMMY_SP,- name: this_var.into(),- init: None,- definite: false,- }],- ctxt: Default::default(),- declare: false,- };- prepend_stmt(stmts, decl.into());- }- }- }-- // Restore the previous fn_state from stack- self.fn_state = self.fn_state_stack.pop();- }- }-- fn exit_expr(&mut self, expr: &mut Expr, _ctx: &mut TraverseCtx) {- let Some(fn_state) = &mut self.fn_state else {- return;- };-- match expr {- Expr::This(..) if fn_state.should_transform || fn_state.is_arrow => {- fn_state.use_this = true;- }- Expr::Ident(Ident { sym, .. })- if sym == "arguments" && (fn_state.should_transform || fn_state.is_arrow) =>- {- fn_state.use_arguments = true;- }- Expr::Await(AwaitExpr { arg, span }) if fn_state.should_transform => {- *expr = if fn_state.is_generator {- let callee = helper!(await_async_generator);- let arg = CallExpr {- span: *span,- callee,- args: vec![arg.take().as_arg()],- ..Default::default()- }- .into();- YieldExpr {- span: *span,- delegate: false,- arg: Some(arg),- }- } else {- YieldExpr {- span: *span,- delegate: false,- arg: Some(arg.take()),- }- }- .into();- }- Expr::Yield(YieldExpr {- span,- arg: Some(arg),- delegate: true,- }) if fn_state.should_transform => {- let async_iter =- helper_expr!(async_iterator).as_call(DUMMY_SP, vec![arg.take().as_arg()]);-- let arg = helper_expr!(async_generator_delegate)- .as_call(*span, vec![async_iter.as_arg()])- .into();-- *expr = YieldExpr {- span: *span,- delegate: true,- arg: Some(arg),- }- .into()- }-- _ => {}- }- }-- fn enter_stmt(&mut self, stmt: &mut Stmt, _ctx: &mut TraverseCtx) {- if matches!(stmt, Stmt::Labeled(..)) {- if let Some(mode) = self.fn_state.as_ref().and_then(|s| s.await_for_mode) {- // A label must stay attached to the generated iteration statement.- handle_await_for(stmt, mode, self.unresolved_ctxt);- }- }- }-- fn exit_stmt(&mut self, stmt: &mut Stmt, _ctx: &mut TraverseCtx) {- if let Some(mode) = self.fn_state.as_ref().and_then(|s| s.await_for_mode) {- if matches!(stmt, Stmt::ForOf(..)) {- handle_await_for(stmt, mode, self.unresolved_ctxt);- }- }- }-- fn enter_super(&mut self, _: &mut Super, _ctx: &mut TraverseCtx) {- if let Some(FnState { use_super, .. }) = &mut self.fn_state {- *use_super = true;- }- }-}--/// Creates-///-/// `_async_to_generator(function*() {})()` from `async function() {}`;-#[cfg_attr(debug_assertions, tracing::instrument(level = "debug", skip_all))]-fn make_fn_ref(fn_state: &FnState, params: Vec<Param>, body: FunctionBody) -> Expr {- let helper = if fn_state.is_generator {- helper_expr!(DUMMY_SP, wrap_async_generator)- } else {- helper_expr!(DUMMY_SP, async_to_generator)- }- .as_callee();- let this = ThisExpr { span: DUMMY_SP };- let arguments = quote_ident!("arguments");-- let inner_fn = Function {- is_generator: true,- params,- body: Some(body),- ..Default::default()- };-- let call_async = CallExpr {- callee: helper,- args: vec![inner_fn.as_arg()],- ..Default::default()- };-- if fn_state.use_arguments {- // fn.apply(this, arguments)- call_async- .make_member(quote_ident!("apply"))- .as_call(DUMMY_SP, vec![this.as_arg(), arguments.as_arg()])- } else if fn_state.use_this && !fn_state.in_constructor {- // fn.call(this)- // Note: in constructor context, we don't use .call(this) because- // FnEnvHoister has already replaced `this` with `_this`- call_async- .make_member(quote_ident!("call"))- .as_call(DUMMY_SP, vec![this.as_arg()])- } else {- // fn()- call_async.as_call(DUMMY_SP, vec![])- }-}--#[cfg_attr(debug_assertions, tracing::instrument(level = "debug", skip_all))]-fn could_potentially_throw(param: &[Param], unresolved_ctxt: SyntaxContext) -> bool {- for param in param {- debug_assert!(param.decorators.is_empty());-- match ¶m.pat {- Pat::Ident(..) => continue,- Pat::Rest(RestPat { arg, .. }) if arg.is_ident() => continue,- Pat::Assign(assign_pat) => match &*assign_pat.right {- Expr::Ident(Ident { ctxt, sym, .. })- if sym == "undefined" && *ctxt == unresolved_ctxt =>- {- continue- }- Expr::Lit(- Lit::Null(..) | Lit::Bool(..) | Lit::Num(..) | Lit::BigInt(..) | Lit::Str(..),- )- | Expr::Fn(..)- | Expr::Arrow(..) => continue,-- _ => return true,- },- _ => return true,- }- }-- false-}--#[cfg_attr(debug_assertions, tracing::instrument(level = "debug", skip_all))]-fn handle_await_for(stmt: &mut Stmt, mode: AwaitForMode, unresolved_ctxt: SyntaxContext) {- let mut labels = Vec::new();- let mut body = &mut *stmt;- while let Stmt::Labeled(labeled) = body {- labels.push((labeled.span, labeled.label.clone()));- body = &mut labeled.body;- }-- let mut s = match body {- Stmt::ForOf(s @ ForOfStmt { is_await: true, .. }) => s.take(),- _ => return,- };- let loop_head_scope = if matches!(mode, AwaitForMode::NativeAsync) {- LoopHeadScope::new(&mut s)- } else {- None- };-- let value = private_ident!("_value");- let iterator = private_ident!("_iterator");- let next_method = matches!(mode, AwaitForMode::NativeAsync).then(|| private_ident!("_next"));- let return_method =- matches!(mode, AwaitForMode::NativeAsync).then(|| private_ident!("_return"));- let iterator_error = private_ident!("_iteratorError");- let step = private_ident!("_step");- let did_iteration_error = private_ident!("_didIteratorError");- let iterator_abrupt_completion = private_ident!("_iteratorAbruptCompletion");- let err_param = private_ident!("err");-- let try_body = {- let body_span = s.body.span();- let orig_body = match *s.body {- Stmt::Block(s) => s.stmts,- _ => vec![*s.body],- };-- let mut for_loop_body = Vec::new();- if matches!(mode, AwaitForMode::NativeAsync) {- // Validate the awaited iterator result before accessing its properties.- let iter_next: Expr = CallExpr {- span: DUMMY_SP,- callee: quote_ident!(unresolved_ctxt, "Reflect")- .make_member(quote_ident!("apply"))- .as_callee(),- args: vec![- next_method.as_ref().unwrap().clone().as_arg(),- iterator.clone().as_arg(),- ArrayLit {- span: DUMMY_SP,- elems: vec![],- }- .as_arg(),- ],- ..Default::default()- }- .into();- for_loop_body.push(- ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: step.clone().into(),- right: await_iteration(iter_next, mode).into(),- }- .into(),- }- .into(),- );-- for_loop_body.push(check_iterator_object(&step, unresolved_ctxt));-- for_loop_body.push(- ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: iterator_abrupt_completion.clone().into(),- right: UnaryExpr {- span: DUMMY_SP,- op: op!("!"),- arg: step.clone().make_member(quote_ident!("done")).into(),- }- .into(),- }- .into(),- }- .into(),- );- for_loop_body.push(- IfStmt {- span: DUMMY_SP,- test: UnaryExpr {- span: DUMMY_SP,- op: op!("!"),- arg: iterator_abrupt_completion.clone().into(),- }- .into(),- cons: Box::new(Stmt::Break(BreakStmt {- span: DUMMY_SP,- label: None,- })),- alt: None,- }- .into(),- );- }- {- // let value = _step.value;- let value_var = VarDeclarator {- span: DUMMY_SP,- name: value.clone().into(),- init: Some(step.clone().make_member(quote_ident!("value")).into()),- definite: false,- };- for_loop_body.push(- VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Let,- declare: false,- decls: vec![value_var],- ..Default::default()- }- .into(),- );- }-- match s.left {- ForHead::VarDecl(v) => {- let var = v.decls.into_iter().next().unwrap();- let var_decl = VarDeclarator {- span: DUMMY_SP,- name: var.name,- init: Some(value.into()),- definite: false,- };- for_loop_body.push(- VarDecl {- span: DUMMY_SP,- kind: v.kind,- declare: false,- decls: vec![var_decl],- ..Default::default()- }- .into(),- );- }- ForHead::Pat(p) => {- for_loop_body.push(- ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: p.try_into().unwrap(),- right: Box::new(value.into()),- }- .into(),- }- .into(),- );- }-- ForHead::UsingDecl(..) => {- unreachable!("using declaration must be removed by previous pass")- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }-- for_loop_body.extend(orig_body);-- let for_loop_body = BlockStmt {- span: body_span,- stmts: for_loop_body,- ..Default::default()- };-- let mut try_stmts = Vec::new();- let mut init_var_decls = Vec::new();- // _iterator = _async_iterator(lol())- let iterator_decl = VarDeclarator {- span: DUMMY_SP,- name: iterator.clone().into(),- init: {- let callee = helper!(async_iterator);-- Some(- CallExpr {- span: DUMMY_SP,- callee,- args: vec![s.right.as_arg()],- ..Default::default()- }- .into(),- )- },- definite: false,- };- if matches!(mode, AwaitForMode::NativeAsync) {- // GetIterator rejects a primitive before reading its `next` method.- // Keep acquisition inside the try block so no close is attempted- // if either acquisition or validation fails.- if let Some(loop_head_scope) = loop_head_scope {- loop_head_scope.init_iterator(iterator_decl, &mut try_stmts);- } else {- try_stmts.push(- VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Var,- decls: vec![iterator_decl],- ..Default::default()- }- .into(),- );- }- try_stmts.push(check_iterator_object(&iterator, unresolved_ctxt));- } else {- init_var_decls.push(iterator_decl);- }- if let Some(next_method) = next_method {- init_var_decls.push(VarDeclarator {- span: DUMMY_SP,- name: next_method.into(),- init: Some(iterator.clone().make_member(quote_ident!("next")).into()),- definite: false,- });- }- init_var_decls.push(VarDeclarator {- span: DUMMY_SP,- name: step.clone().into(),- init: None,- definite: false,- });-- let mut for_stmt: Stmt = ForStmt {- span: s.span,- // var _iterator = _async_iterator(lol()), _step;- init: Some(- VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Var,- declare: false,- decls: init_var_decls,- ..Default::default()- }- .into(),- ),- // _iteratorAbruptCompletion = !(_step = yield _iterator.next()).done- test: if matches!(mode, AwaitForMode::NativeAsync) {- None- } else {- let iter_next = iterator.clone().make_member(quote_ident!("next"));- let iter_next = CallExpr {- span: DUMMY_SP,- callee: iter_next.as_callee(),- args: Default::default(),- ..Default::default()- };-- let assign_to_step: Expr = AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: step.clone().into(),- right: await_iteration(iter_next.into(), mode).into(),- }- .into();-- let right = UnaryExpr {- span: DUMMY_SP,- op: op!("!"),- arg: assign_to_step.make_member(quote_ident!("done")).into(),- }- .into();-- let left = iterator_abrupt_completion.clone().into();-- Some(- AssignExpr {- span: DUMMY_SP,- op: op!("="),- left,- right,- }- .into(),- )- },- // _iteratorNormalCompletion = true- update: Some(- AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: iterator_abrupt_completion.clone().into(),- right: false.into(),- }- .into(),- ),- body: Box::new(Stmt::Block(for_loop_body)),- }- .into();-- for (span, label) in labels.into_iter().rev() {- for_stmt = LabeledStmt {- span,- label,- body: Box::new(for_stmt),- }- .into();- }-- try_stmts.push(for_stmt);- BlockStmt {- span: body_span,- stmts: try_stmts,- ..Default::default()- }- };-- let catch_clause = {- // _didIteratorError = true;- let mark_as_errorred = ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: did_iteration_error.clone().into(),- right: true.into(),- }- .into(),- }- .into();- // _iteratorError = err;- let store_error = ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: iterator_error.clone().into(),- right: Box::new(err_param.clone().into()),- }- .into(),- }- .into();-- CatchClause {- span: DUMMY_SP,- param: Some(err_param.into()),- body: BlockStmt {- stmts: vec![mark_as_errorred, store_error],- ..Default::default()- },- }- };-- let finally_block = {- let throw_iterator_error = ThrowStmt {- span: DUMMY_SP,- arg: iterator_error.clone().into(),- }- .into();- let throw_iterator_error = IfStmt {- span: DUMMY_SP,- test: did_iteration_error.clone().into(),- cons: Box::new(Stmt::Block(BlockStmt {- span: DUMMY_SP,- stmts: vec![throw_iterator_error],- ..Default::default()- })),- alt: None,- }- .into();-- // GetMethod reads `return` once. Reflect.apply preserves the receiver- // without consulting a method's own `call` or `apply` properties.- let return_callee = if return_method.is_some() {- quote_ident!(unresolved_ctxt, "Reflect")- .make_member(quote_ident!("apply"))- .as_callee()- } else {- iterator- .clone()- .make_member(quote_ident!("return"))- .as_callee()- };- let return_args = if let Some(return_method) = &return_method {- vec![- return_method.clone().as_arg(),- iterator.clone().as_arg(),- ArrayLit {- span: DUMMY_SP,- elems: vec![],- }- .as_arg(),- ]- } else {- vec![]- };- let iterator_return: Expr = CallExpr {- span: DUMMY_SP,- callee: return_callee,- args: return_args,- ..Default::default()- }- .into();-- let awaited_return = await_iteration(iterator_return, mode);- let close_stmts = if matches!(mode, AwaitForMode::NativeAsync) {- // AsyncIteratorClose validates the awaited result even though its- // properties are unused. The inner finally preserves a body error.- vec![- ExprStmt {- span: DUMMY_SP,- expr: AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: step.clone().into(),- right: awaited_return.into(),- }- .into(),- }- .into(),- check_iterator_object(&step, unresolved_ctxt),- ]- } else {- vec![ExprStmt {- span: DUMMY_SP,- expr: awaited_return.into(),- }- .into()]- };-- let get_return = iterator.make_member(quote_ident!("return"));- let get_return = if let Some(return_method) = &return_method {- Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: return_method.clone().into(),- right: get_return.into(),- })- } else {- get_return.into()- };- let conditional_yield = IfStmt {- span: DUMMY_SP,- // _iteratorAbruptCompletion && _iterator.return != null- test: BinExpr {- span: DUMMY_SP,- op: op!("&&"),- // _iteratorAbruptCompletion- left: Box::new(iterator_abrupt_completion.clone().into()),- // _iterator.return != null- right: Box::new(- BinExpr {- span: DUMMY_SP,- op: op!("!="),- left: get_return.into(),- right: Null { span: DUMMY_SP }.into(),- }- .into(),- ),- }- .into(),- cons: Box::new(Stmt::Block(BlockStmt {- stmts: close_stmts,- ..Default::default()- })),- alt: None,- }- .into();- let body = BlockStmt {- stmts: vec![conditional_yield],- ..Default::default()- };-- let inner_try = TryStmt {- span: DUMMY_SP,- block: body,- handler: None,- finalizer: Some(BlockStmt {- stmts: vec![throw_iterator_error],- ..Default::default()- }),- }- .into();- BlockStmt {- stmts: vec![inner_try],- ..Default::default()- }- };-- let try_stmt = TryStmt {- span: s.span,- block: try_body,- handler: Some(catch_clause),- finalizer: Some(finally_block),- };-- let mut decls = vec![- // var _iteratorAbruptCompletion = false;- VarDeclarator {- span: DUMMY_SP,- name: iterator_abrupt_completion.into(),- init: Some(false.into()),- definite: false,- },- // var _didIteratorError = false;- VarDeclarator {- span: DUMMY_SP,- name: did_iteration_error.into(),- init: Some(false.into()),- definite: false,- },- // var _iteratorError;- VarDeclarator {- span: DUMMY_SP,- name: iterator_error.into(),- init: None,- definite: false,- },- ];- if let Some(return_method) = return_method {- decls.push(VarDeclarator {- span: DUMMY_SP,- name: return_method.into(),- init: None,- definite: false,- });- }- let stmts = vec![- VarDecl {- kind: VarDeclKind::Var,- decls,- ..Default::default()- }- .into(),- try_stmt.into(),- ];-- *stmt = BlockStmt {- span: s.span,- stmts,- ..Default::default()- }- .into();-}--/// Reject primitive iterator objects and operation results, accepting callable-/// objects without accessing any user-defined properties.-fn check_iterator_object(value: &Ident, unresolved_ctxt: SyntaxContext) -> Stmt {- let is_not_type = |kind| -> Expr {- BinExpr {- span: DUMMY_SP,- op: op!("!=="),- left: UnaryExpr {- span: DUMMY_SP,- op: op!("typeof"),- arg: value.clone().into(),- }- .into(),- right: Str {- span: DUMMY_SP,- value: kind,- raw: None,- }- .into(),- }- .into()- };- let non_object = BinExpr {- span: DUMMY_SP,- op: op!("||"),- left: BinExpr {- span: DUMMY_SP,- op: op!("==="),- left: value.clone().into(),- right: Null { span: DUMMY_SP }.into(),- }- .into(),- right: BinExpr {- span: DUMMY_SP,- op: op!("&&"),- left: is_not_type("object".into()).into(),- right: is_not_type("function".into()).into(),- }- .into(),- };- IfStmt {- span: DUMMY_SP,- test: non_object.into(),- cons: Box::new(Stmt::Throw(ThrowStmt {- span: DUMMY_SP,- arg: NewExpr {- span: DUMMY_SP,- callee: quote_ident!(unresolved_ctxt, "TypeError").into(),- args: Some(vec![Str {- span: DUMMY_SP,- value: "Iterator result is not an object".into(),- raw: None,- }- .as_arg()]),- ..Default::default()- }- .into(),- })),- alt: None,- }- .into()-}--/// Wait for an async iterator operation using the surrounding function's form.-fn await_iteration(expr: Expr, mode: AwaitForMode) -> Expr {- match mode {- AwaitForMode::NativeAsync => AwaitExpr {- span: DUMMY_SP,- arg: expr.into(),- }- .into(),- AwaitForMode::Generator => YieldExpr {- span: DUMMY_SP,- arg: Some(expr.into()),- delegate: false,- }- .into(),- AwaitForMode::AsyncGenerator => {- let arg = CallExpr {- span: DUMMY_SP,- callee: helper!(await_async_generator),- args: vec![expr.as_arg()],- ..Default::default()- };- YieldExpr {- span: DUMMY_SP,- arg: Some(arg.into()),- delegate: false,- }- .into()- }- }-}--/// Replace all `this` expressions with the given identifier in a-/// Arrow function body.-fn replace_this_in_arrow_function_body(body: &mut ArrowFunctionBody, this_var: &Ident) {- match body {- ArrowFunctionBody::FunctionBody(block) => {- replace_this_in_stmts(&mut block.stmts, this_var);- }- ArrowFunctionBody::Expr(expr) => {- replace_this_in_expr(expr, this_var);- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }-}--fn replace_this_in_stmts(stmts: &mut [Stmt], this_var: &Ident) {- for stmt in stmts {- replace_this_in_stmt(stmt, this_var);- }-}--fn replace_this_in_stmt(stmt: &mut Stmt, this_var: &Ident) {- match stmt {- Stmt::Block(block) => {- replace_this_in_stmts(&mut block.stmts, this_var);- }- Stmt::With(with) => {- replace_this_in_expr(&mut with.obj, this_var);- replace_this_in_stmt(&mut with.body, this_var);- }- Stmt::Return(ret) => {- if let Some(arg) = &mut ret.arg {- replace_this_in_expr(arg, this_var);- }- }- Stmt::Labeled(labeled) => {- replace_this_in_stmt(&mut labeled.body, this_var);- }- Stmt::If(if_stmt) => {- replace_this_in_expr(&mut if_stmt.test, this_var);- replace_this_in_stmt(&mut if_stmt.cons, this_var);- if let Some(alt) = &mut if_stmt.alt {- replace_this_in_stmt(alt, this_var);- }- }- Stmt::Switch(switch) => {- replace_this_in_expr(&mut switch.discriminant, this_var);- for case in &mut switch.cases {- if let Some(test) = &mut case.test {- replace_this_in_expr(test, this_var);- }- replace_this_in_stmts(&mut case.cons, this_var);- }- }- Stmt::Throw(throw) => {- replace_this_in_expr(&mut throw.arg, this_var);- }- Stmt::Try(try_stmt) => {- replace_this_in_stmts(&mut try_stmt.block.stmts, this_var);- if let Some(handler) = &mut try_stmt.handler {- if let Some(param) = &mut handler.param {- replace_this_in_pat_inner(param, this_var);- }- replace_this_in_stmts(&mut handler.body.stmts, this_var);- }- if let Some(finalizer) = &mut try_stmt.finalizer {- replace_this_in_stmts(&mut finalizer.stmts, this_var);- }- }- Stmt::While(while_stmt) => {- replace_this_in_expr(&mut while_stmt.test, this_var);- replace_this_in_stmt(&mut while_stmt.body, this_var);- }- Stmt::DoWhile(do_while) => {- replace_this_in_stmt(&mut do_while.body, this_var);- replace_this_in_expr(&mut do_while.test, this_var);- }- Stmt::For(for_stmt) => {- if let Some(init) = &mut for_stmt.init {- match init {- VarDeclOrExpr::VarDecl(var_decl) => {- for decl in &mut var_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- VarDeclOrExpr::Expr(expr) => {- replace_this_in_expr(expr, this_var);- }- #[cfg(swc_ast_unknown)]- _ => {}- }- }- if let Some(test) = &mut for_stmt.test {- replace_this_in_expr(test, this_var);- }- if let Some(update) = &mut for_stmt.update {- replace_this_in_expr(update, this_var);- }- replace_this_in_stmt(&mut for_stmt.body, this_var);- }- Stmt::ForIn(for_in) => {- match &mut for_in.left {- ForHead::VarDecl(var_decl) => {- for decl in &mut var_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- ForHead::Pat(pat) => {- replace_this_in_pat_inner(pat, this_var);- }- ForHead::UsingDecl(using_decl) => {- for decl in &mut using_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- #[cfg(swc_ast_unknown)]- _ => {}- }- replace_this_in_expr(&mut for_in.right, this_var);- replace_this_in_stmt(&mut for_in.body, this_var);- }- Stmt::ForOf(for_of) => {- match &mut for_of.left {- ForHead::VarDecl(var_decl) => {- for decl in &mut var_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- ForHead::Pat(pat) => {- replace_this_in_pat_inner(pat, this_var);- }- ForHead::UsingDecl(using_decl) => {- for decl in &mut using_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- #[cfg(swc_ast_unknown)]- _ => {}- }- replace_this_in_expr(&mut for_of.right, this_var);- replace_this_in_stmt(&mut for_of.body, this_var);- }- Stmt::Expr(expr_stmt) => {- replace_this_in_expr(&mut expr_stmt.expr, this_var);- }- Stmt::Decl(decl) => match decl {- Decl::Class(_)- | Decl::Fn(_)- | Decl::TsInterface(_)- | Decl::TsTypeAlias(_)- | Decl::TsEnum(_)- | Decl::TsModule(_) => {- // Don't traverse into nested function/class declarations- }- Decl::Var(var_decl) => {- for decl in &mut var_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- Decl::Using(using_decl) => {- for decl in &mut using_decl.decls {- replace_this_in_var_declarator(decl, this_var);- }- }- #[cfg(swc_ast_unknown)]- _ => {}- },- Stmt::Empty(_) | Stmt::Debugger(_) | Stmt::Break(_) | Stmt::Continue(_) => {- // These statements don't contain expressions- }- #[cfg(swc_ast_unknown)]- _ => {}- }-}--fn replace_this_in_expr(expr: &mut Expr, this_var: &Ident) {- match expr {- Expr::This(_) => {- *expr = Expr::Ident(this_var.clone());- }- Expr::Array(array) => {- for elem in array.elems.iter_mut().flatten() {- replace_this_in_expr(&mut elem.expr, this_var);- }- }- Expr::Object(obj) => {- for prop in &mut obj.props {- match prop {- PropOrSpread::Spread(spread) => {- replace_this_in_expr(&mut spread.expr, this_var);- }- PropOrSpread::Prop(prop) => match &mut **prop {- Prop::Shorthand(_) => {}- Prop::KeyValue(kv) => {- if let PropName::Computed(computed) = &mut kv.key {- replace_this_in_expr(&mut computed.expr, this_var);- }- replace_this_in_expr(&mut kv.value, this_var);- }- Prop::Assign(assign) => {- replace_this_in_expr(&mut assign.value, this_var);- }- Prop::Getter(_) | Prop::Setter(_) | Prop::Method(_) => {- // Don't traverse into nested functions- }- #[cfg(swc_ast_unknown)]- _ => {}- },- #[cfg(swc_ast_unknown)]- _ => {}- }- }- }- Expr::Member(member) => {- replace_this_in_expr(&mut member.obj, this_var);- if let MemberProp::Computed(computed) = &mut member.prop {- replace_this_in_expr(&mut computed.expr, this_var);- }- }- Expr::SuperProp(super_prop) => {- if let SuperProp::Computed(computed) = &mut super_prop.prop {- replace_this_in_expr(&mut computed.expr, this_var);- }- }- Expr::Call(call) => {- if let Callee::Expr(expr) = &mut call.callee {- replace_this_in_expr(expr, this_var)- }- for arg in &mut call.args {- replace_this_in_expr(&mut arg.expr, this_var);- }- }- Expr::New(new) => {- replace_this_in_expr(&mut new.callee, this_var);- if let Some(args) = &mut new.args {- for arg in args {- replace_this_in_expr(&mut arg.expr, this_var);- }- }- }- Expr::Bin(bin) => {- replace_this_in_expr(&mut bin.left, this_var);- replace_this_in_expr(&mut bin.right, this_var);- }- Expr::Unary(unary) => {- replace_this_in_expr(&mut unary.arg, this_var);- }- Expr::Update(update) => {- replace_this_in_expr(&mut update.arg, this_var);- }- Expr::Cond(cond) => {- replace_this_in_expr(&mut cond.test, this_var);- replace_this_in_expr(&mut cond.cons, this_var);- replace_this_in_expr(&mut cond.alt, this_var);- }- Expr::Await(await_expr) => {- replace_this_in_expr(&mut await_expr.arg, this_var);- }- Expr::Yield(yield_expr) => {- if let Some(arg) = &mut yield_expr.arg {- replace_this_in_expr(arg, this_var);- }- }- Expr::Tpl(tpl) => {- for expr in &mut tpl.exprs {- replace_this_in_expr(expr, this_var);- }- }- Expr::TaggedTpl(tagged) => {- replace_this_in_expr(&mut tagged.tag, this_var);- for expr in &mut tagged.tpl.exprs {- replace_this_in_expr(expr, this_var);- }- }- Expr::Assign(assign) => {- match &mut assign.left {- AssignTarget::Simple(simple) => match simple {- SimpleAssignTarget::Member(member) => {- replace_this_in_member_expr(member, this_var);- }- SimpleAssignTarget::SuperProp(super_prop) => {- if let SuperProp::Computed(computed) = &mut super_prop.prop {- replace_this_in_expr(&mut computed.expr, this_var);- }- }- SimpleAssignTarget::Paren(paren) => {- replace_this_in_expr(&mut paren.expr, this_var);- }- SimpleAssignTarget::OptChain(opt) => {- replace_this_in_opt_chain_base(&mut opt.base, this_var);- }- SimpleAssignTarget::TsAs(ts_as) => {- replace_this_in_expr(&mut ts_as.expr, this_var);- }- SimpleAssignTarget::TsSatisfies(ts_satisfies) => {- replace_this_in_expr(&mut ts_satisfies.expr, this_var);- }- SimpleAssignTarget::TsNonNull(ts_non_null) => {- replace_this_in_expr(&mut ts_non_null.expr, this_var);- }- SimpleAssignTarget::TsTypeAssertion(ts_type_assertion) => {- replace_this_in_expr(&mut ts_type_assertion.expr, this_var);- }- SimpleAssignTarget::TsInstantiation(ts_instantiation) => {- replace_this_in_expr(&mut ts_instantiation.expr, this_var);- }- SimpleAssignTarget::Ident(_) | SimpleAssignTarget::Invalid(_) => {}- #[cfg(swc_ast_unknown)]- _ => {}- },- AssignTarget::Pat(pat) => {- replace_this_in_pat(pat, this_var);- }- #[cfg(swc_ast_unknown)]- _ => {}- }- replace_this_in_expr(&mut assign.right, this_var);- }- Expr::Paren(paren) => {- replace_this_in_expr(&mut paren.expr, this_var);- }- Expr::Seq(seq) => {- for expr in &mut seq.exprs {- replace_this_in_expr(expr, this_var);- }- }- Expr::OptChain(opt) => {- replace_this_in_opt_chain_base(&mut opt.base, this_var);- }- // Arrow functions don't have their own `this` context - they inherit from the- // enclosing scope, so we need to traverse into them- Expr::Arrow(arrow) => {- replace_this_in_arrow_function_body(&mut arrow.body, this_var);- }- // Don't traverse into nested functions/classes as they have their own `this` context- Expr::Fn(_) | Expr::Class(_) => {}- // These don't contain expressions that could have `this`- Expr::Ident(_)- | Expr::Lit(_)- | Expr::PrivateName(_)- | Expr::JSXMember(_)- | Expr::JSXNamespacedName(_)- | Expr::JSXEmpty(_)- | Expr::JSXElement(_)- | Expr::JSXFragment(_)- | Expr::TsTypeAssertion(_)- | Expr::TsConstAssertion(_)- | Expr::TsNonNull(_)- | Expr::TsAs(_)- | Expr::TsInstantiation(_)- | Expr::TsSatisfies(_)- | Expr::MetaProp(_)- | Expr::Invalid(_) => {}- #[cfg(swc_ast_unknown)]- _ => {}- }-}--fn replace_this_in_member_expr(member: &mut MemberExpr, this_var: &Ident) {- replace_this_in_expr(&mut member.obj, this_var);- if let MemberProp::Computed(computed) = &mut member.prop {- replace_this_in_expr(&mut computed.expr, this_var);- }-}--fn replace_this_in_opt_chain_base(base: &mut OptChainBase, this_var: &Ident) {- match base {- OptChainBase::Member(member) => {- replace_this_in_expr(&mut member.obj, this_var);- if let MemberProp::Computed(computed) = &mut member.prop {- replace_this_in_expr(&mut computed.expr, this_var);- }- }- OptChainBase::Call(call) => {- replace_this_in_expr(&mut call.callee, this_var);- for arg in &mut call.args {- replace_this_in_expr(&mut arg.expr, this_var);- }- }- #[cfg(swc_ast_unknown)]- _ => {}- }-}--/// Replaces `this` in variable declarator initializers and binding-pattern-/// default values after an async arrow body is moved into a generator function.-fn replace_this_in_var_declarator(decl: &mut VarDeclarator, this_var: &Ident) {- replace_this_in_pat_inner(&mut decl.name, this_var);- if let Some(init) = &mut decl.init {- replace_this_in_expr(init, this_var);- }-}--fn replace_this_in_pat(pat: &mut AssignTargetPat, this_var: &Ident) {- match pat {- AssignTargetPat::Array(array) => {- for elem in array.elems.iter_mut().flatten() {- replace_this_in_pat_inner(elem, this_var);- }- }- AssignTargetPat::Object(obj) => {- for prop in &mut obj.props {- match prop {- ObjectPatProp::KeyValue(kv) => {- if let PropName::Computed(computed) = &mut kv.key {- replace_this_in_expr(&mut computed.expr, this_var);- }- replace_this_in_pat_inner(&mut kv.value, this_var);- }- ObjectPatProp::Assign(assign) => {- if let Some(value) = &mut assign.value {- replace_this_in_expr(value, this_var);- }- }- ObjectPatProp::Rest(rest) => {- replace_this_in_pat_inner(&mut rest.arg, this_var);- }- #[cfg(swc_ast_unknown)]- _ => {}- }- }- }- AssignTargetPat::Invalid(_) => {}- #[cfg(swc_ast_unknown)]- _ => {}- }-}--fn replace_this_in_pat_inner(pat: &mut Pat, this_var: &Ident) {- match pat {- Pat::Array(array) => {- for elem in array.elems.iter_mut().flatten() {- replace_this_in_pat_inner(elem, this_var);- }- }- Pat::Object(obj) => {- for prop in &mut obj.props {- match prop {- ObjectPatProp::KeyValue(kv) => {- if let PropName::Computed(computed) = &mut kv.key {- replace_this_in_expr(&mut computed.expr, this_var);- }- replace_this_in_pat_inner(&mut kv.value, this_var);- }- ObjectPatProp::Assign(assign) => {- if let Some(value) = &mut assign.value {- replace_this_in_expr(value, this_var);- }- }- ObjectPatProp::Rest(rest) => {- replace_this_in_pat_inner(&mut rest.arg, this_var);- }- #[cfg(swc_ast_unknown)]- _ => {}- }- }- }- Pat::Assign(assign) => {- replace_this_in_pat_inner(&mut assign.left, this_var);- replace_this_in_expr(&mut assign.right, this_var);- }- Pat::Rest(rest) => {- replace_this_in_pat_inner(&mut rest.arg, this_var);- }- Pat::Expr(expr) => {- replace_this_in_expr(expr, this_var);- }- // Don't need to traverse these as they're just identifiers or invalid- Pat::Ident(_) | Pat::Invalid(_) => {}- #[cfg(swc_ast_unknown)]- _ => {}- }-}
deps/swc/crates/swc_ecma_transformer/src/es2017/mod.rs
@@ -1,41 +0,0 @@-pub(crate) mod async_to_generator;--use swc_common::SyntaxContext;-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2017Options {- /// Lower async functions to generators. This also lowers async generators- /// to preserve the existing behavior of this option.- pub async_to_generator: bool,-- /// Lower async generators without lowering ordinary async functions.- pub async_generator_functions: bool,-}--impl Es2017Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.async_to_generator || self.async_generator_functions- }-}--pub fn hook(- options: Es2017Options,- unresolved_ctxt: SyntaxContext,- ignore_function_length: bool,-) -> impl VisitMutHook<TraverseCtx> {- if options.is_enabled() {- Some(async_to_generator::hook(- options.async_to_generator,- options.async_to_generator || options.async_generator_functions,- unresolved_ctxt,- ignore_function_length,- ))- } else {- None- }-}
deps/swc/crates/swc_ecma_transformer/src/es2018/mod.rs
@@ -1,30 +0,0 @@-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::assumptions::Assumptions;--use crate::TraverseCtx;--pub(crate) mod object_rest_spread;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2018Options {- pub object_rest_spread: bool,-}--impl Es2018Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.object_rest_spread- }-}--pub(crate) fn hook(- options: Es2018Options,- assumptions: Assumptions,-) -> impl VisitMutHook<TraverseCtx> {- if options.object_rest_spread {- Some(object_rest_spread::hook(assumptions))- } else {- None- }-}
deps/swc/crates/swc_ecma_transformer/src/es2018/object_rest_spread.rs
@@ -1,1423 +0,0 @@-use std::mem;--use rustc_hash::FxHashMap;-use swc_common::{util::take::Take, Spanned, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::{assumptions::Assumptions, helper, helper_expr};-use swc_ecma_utils::{- alias_if_required, number::ToJsString, private_ident, quote_ident, ExprFactory,-};--use crate::TraverseCtx;--#[derive(Debug, Clone, Copy, Default)]-struct Config {- pub no_symbol: bool,- pub set_property: bool,- pub pure_getters: bool,-}--pub fn hook(assumptions: Assumptions) -> impl VisitMutHook<TraverseCtx> {- ObjectRestSpreadPass {- config: Config {- no_symbol: assumptions.object_rest_no_symbols,- set_property: assumptions.set_spread_properties,- pure_getters: assumptions.pure_getters,- },- export_idents: FxHashMap::default(),- }-}--struct ObjectRestSpreadPass {- config: Config,- /// Map from VarDecl address to original identifiers to export (before- /// transformation)- export_idents: FxHashMap<*const VarDecl, Vec<Ident>>,-}--impl VisitMutHook<TraverseCtx> for ObjectRestSpreadPass {- fn enter_module_items(&mut self, items: &mut Vec<ModuleItem>, _ctx: &mut TraverseCtx) {- // Collect original identifiers from export var declarations before- // transformation- for item in items.iter() {- if let ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {- decl: Decl::Var(var_decl),- ..- })) = item- {- // Only collect if the var declaration needs transformation- let needs_transform = var_decl- .decls- .iter()- .any(|decl| has_object_rest_in_pat(&decl.name));-- if needs_transform {- let var_decl_ptr = &**var_decl as *const VarDecl;- let mut idents = Vec::new();- for decl in &var_decl.decls {- collect_idents_from_pat(&decl.name, &mut idents);- }- self.export_idents.insert(var_decl_ptr, idents);- }- }- }- }-- // Object Spread and Rest: Transform { ...x } and ({ ...x } = y)- fn exit_expr(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- // Handle object spread FIRST (fast path for most common case)- if let Expr::Object(ObjectLit { span, props }) = expr {- // Quick check for spread- if !props.iter().any(|p| matches!(p, PropOrSpread::Spread(..))) {- return;- }-- let mut callee = if self.config.set_property {- helper!(extends)- } else {- helper!(object_spread)- };-- // { foo, ...x } => ({ foo }, x)- let args = {- let mut buf = Vec::new();- let mut obj = ObjectLit {- span: DUMMY_SP,- props: Vec::new(),- };- let mut first = true;- for prop in props.take() {- match prop {- PropOrSpread::Prop(..) => {- // before is spread element- if !first && obj.props.is_empty() && !self.config.pure_getters {- buf = vec![Expr::Call(CallExpr {- span: DUMMY_SP,- callee: callee.clone(),- args: buf.take(),- ..Default::default()- })- .as_arg()];- }- obj.props.push(prop)- }- PropOrSpread::Spread(SpreadElement { expr, .. }) => {- // Push object if it's not empty- if first || !obj.props.is_empty() {- buf.push(obj.take().as_arg());- if !first && !self.config.pure_getters {- buf = vec![Expr::Call(CallExpr {- span: DUMMY_SP,- callee: helper!(object_spread_props),- args: buf.take(),- ..Default::default()- })- .as_arg()];- }- first = false;- }-- buf.push(expr.as_arg());- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }- }-- if !obj.props.is_empty() {- if !self.config.pure_getters {- callee = helper!(object_spread_props);- }- buf.push(obj.as_arg());- }-- buf- };-- *expr = CallExpr {- span: *span,- callee,- args,- ..Default::default()- }- .into();- return;- }-- // Handle assignment with rest: ({ ...x } = y)- let Expr::Assign(AssignExpr {- span,- left: AssignTarget::Pat(pat),- op: op!("="),- right,- }) = expr- else {- return;- };-- // Take pattern- let inner_pat: Pat = pat.take().into();-- // Check if has rest- if !has_object_rest_in_pat(&inner_pat) {- *pat = pat_to_assign_target_pat(inner_pat);- return;- }-- // Preserve the RHS value for every extraction and the assignment result.- // Even an identifier may be overwritten by the pattern or its side effects.- let mut out = ExprOutput::new(ctx);- let ref_ident = out.declare_temp("_ref");- out.assign(ref_ident.clone().into(), right.take());-- let mut lowerer = RestLowerer::new(self.config, out);- lowerer.visit(inner_pat, Box::new(ref_ident.clone().into()));-- lowerer.out.exprs.push(ref_ident.into());-- let exprs = lowerer.out.into_exprs();-- let exprs = exprs.into_iter().map(Box::new).collect();- *expr = SeqExpr { span: *span, exprs }.into();- }-- // Object Rest: Transform variable declarations- fn exit_var_decl(&mut self, decl: &mut VarDecl, ctx: &mut TraverseCtx) {- // Fast path: check if any declarator needs transformation- if !decl.decls.iter().any(|d| has_object_rest_in_pat(&d.name)) {- return;- }-- let mut new_decls = Vec::with_capacity(decl.decls.len());-- for declarator in decl.decls.take() {- // Take init for processing- let Some(init) = declarator.init else {- new_decls.push(declarator);- continue;- };-- // Check if pattern contains object rest- if !has_object_rest_in_pat(&declarator.name) {- new_decls.push(VarDeclarator {- init: Some(init),- ..declarator- });- continue;- }-- // Has rest - create temp for init if needed- let (ref_ident, aliased) = alias_if_required(&init, "_ref");- let source_init = if aliased {- // Need temp variable for complex expression- new_decls.push(VarDeclarator {- span: DUMMY_SP,- name: ref_ident.clone().into(),- init: Some(init),- definite: false,- });- Box::new(ref_ident.into())- } else {- init- };-- // Use unified lowering- let mut lowerer = RestLowerer::new(self.config, DeclOutput::new(ctx));- lowerer.visit(declarator.name, source_init);- new_decls.extend(lowerer.out.into_decls());- }-- decl.decls = new_decls;- }-- // Object Rest: Transform functions- fn exit_function(&mut self, func: &mut Function, ctx: &mut TraverseCtx) {- let Some(body) = &mut func.body else {- return;- };-- // Fast path: check if params need transformation- if !params_have_rest(&func.params) {- return;- }-- {- let mut collector = ParamCollector::new(self.config, ctx);-- for (index, param) in func- .params- .iter_mut()- .enumerate()- .skip_while(|(_, param)| param.pat.is_ident())- {- collector.collect(index, &mut param.pat);- }-- let stmts = collector.into_stmts();- prepend_stmts_to_front(&mut body.stmts, stmts);- }- }-- // Object Rest: Transform arrow functions- fn exit_arrow_expr(&mut self, arrow: &mut ArrowExpr, ctx: &mut TraverseCtx) {- // Fast path: check if params need transformation- if !params_have_rest(&arrow.params) {- return;- }-- {- let mut collector = ParamCollector::new(self.config, ctx);-- for (index, param) in arrow- .params- .iter_mut()- .enumerate()- .skip_while(|(_, param)| param.is_ident())- {- collector.collect(index, param);- }-- let stmts = collector.into_stmts();- if !stmts.is_empty() {- // Insert into body- match &mut *arrow.body {- ArrowFunctionBody::FunctionBody(block) => {- prepend_stmts_to_front(&mut block.stmts, stmts);- }- ArrowFunctionBody::Expr(expr) => {- let mut body_stmts = stmts;- body_stmts.push(- ReturnStmt {- span: DUMMY_SP,- arg: Some(expr.take()),- }- .into(),- );- *arrow.body = ArrowFunctionBody::FunctionBody(FunctionBody {- span: DUMMY_SP,- stmts: body_stmts,- });- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }- }- }- }-- // Object Rest: Transform constructor- fn exit_constructor(&mut self, cons: &mut Constructor, ctx: &mut TraverseCtx) {- let Some(body) = &mut cons.body else {- return;- };-- // Fast path: check if params need transformation- if !constructor_params_have_rest(&cons.params) {- return;- }-- {- let mut collector = ParamCollector::new(self.config, ctx);-- for (index, param) in cons.params.iter_mut().enumerate().skip_while(- |(_, param)| matches!(param, ParamOrTsParamProp::Param(p) if p.pat.is_ident()),- ) {- if let ParamOrTsParamProp::Param(param) = param {- collector.collect(index, &mut param.pat);- }- }-- let stmts = collector.into_stmts();- prepend_stmts_to_front(&mut body.stmts, stmts);- }- }-- // Object Rest: Transform class (manually handle methods)- fn exit_class(&mut self, class: &mut Class, ctx: &mut TraverseCtx) {- for member in &mut class.body {- match member {- ClassMember::Method(method) => {- let Some(body) = &mut method.function.body else {- continue;- };-- if params_have_rest(&method.function.params) {- let mut collector = ParamCollector::new(self.config, ctx);-- for (index, param) in method- .function- .params- .iter_mut()- .enumerate()- .skip_while(|(_, param)| param.pat.is_ident())- {- collector.collect(index, &mut param.pat);- }-- let stmts = collector.into_stmts();- prepend_stmts_to_front(&mut body.stmts, stmts);- }- }- ClassMember::PrivateMethod(method) => {- let Some(body) = &mut method.function.body else {- continue;- };-- if params_have_rest(&method.function.params) {- let mut collector = ParamCollector::new(self.config, ctx);-- for (index, param) in method- .function- .params- .iter_mut()- .enumerate()- .skip_while(|(_, param)| param.pat.is_ident())- {- collector.collect(index, &mut param.pat);- }-- let stmts = collector.into_stmts();- prepend_stmts_to_front(&mut body.stmts, stmts);- }- }- _ => {}- }- }- }-- // Object Rest: Transform catch clause- fn exit_catch_clause(&mut self, clause: &mut CatchClause, ctx: &mut TraverseCtx) {- let Some(ref param) = clause.param else {- return;- };-- // Fast path: check if param needs transformation- if !has_object_rest_in_pat(param) {- return;- }-- let ref_ident = private_ident!("_param");- let pat = clause.param.take().unwrap();- clause.param = Some(ref_ident.clone().into());-- let mut lowerer = RestLowerer::new(self.config, DeclOutput::new(ctx));- lowerer.visit(pat, Box::new(ref_ident.into()));-- let stmt: Stmt = VarDecl {- kind: VarDeclKind::Let,- decls: lowerer.out.into_decls(),- ..Default::default()- }- .into();-- prepend_stmts_to_front(&mut clause.body.stmts, vec![stmt]);- }-- // Object Rest: Transform for-in statement- fn exit_for_in_stmt(&mut self, stmt: &mut ForInStmt, ctx: &mut TraverseCtx) {- self.transform_for_loop(&mut stmt.left, &mut stmt.body, ctx);- }-- // Object Rest: Transform for-of statement- fn exit_for_of_stmt(&mut self, stmt: &mut ForOfStmt, ctx: &mut TraverseCtx) {- self.transform_for_loop(&mut stmt.left, &mut stmt.body, ctx);- }-- fn exit_module_items(&mut self, items: &mut Vec<ModuleItem>, _: &mut TraverseCtx) {- let original = items.take();- let mut rewritten = Vec::with_capacity(original.len() + self.export_idents.len());-- for item in original {- match item {- ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {- span,- decl: Decl::Var(var_decl),- })) => {- let var_decl_ptr = &*var_decl as *const VarDecl;-- if let Some(exported_names) = self.export_idents.remove(&var_decl_ptr) {- rewritten.push(ModuleItem::Stmt((*var_decl).into()));-- if !exported_names.is_empty() {- rewritten.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(- NamedExport {- span,- specifiers: exported_names- .into_iter()- .map(|id| {- ExportSpecifier::Named(ExportNamedSpecifier {- span: DUMMY_SP,- orig: ModuleExportName::Ident(id),- exported: None,- is_type_only: false,- })- })- .collect(),- src: None,- type_only: false,- with: None,- },- )));- }- } else {- rewritten.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(- ExportDecl {- span,- decl: Decl::Var(var_decl),- },- )));- }- }- _ => rewritten.push(item),- }- }-- *items = rewritten;- }-}--impl ObjectRestSpreadPass {- fn transform_for_loop(- &mut self,- left: &mut ForHead,- body: &mut Box<Stmt>,- ctx: &mut TraverseCtx,- ) {- // Fast path: check if transformation is needed- let needs_transform = match left {- ForHead::VarDecl(var_decl) => has_object_rest_in_pat(&var_decl.decls[0].name),- ForHead::Pat(pat) => has_object_rest_in_pat(pat),- _ => false,- };-- if !needs_transform {- return;- }-- match left {- ForHead::VarDecl(var_decl) => {- // Keep the original declaration kind: `var` bindings are- // function-scoped, while `let` and `const` need per-iteration- // lexical bindings.- let kind = var_decl.kind;- let ref_ident = private_ident!("_ref");- let pat = var_decl.decls[0].name.take();- var_decl.decls[0].name = ref_ident.clone().into();-- let mut lowerer = RestLowerer::new(self.config, DeclOutput::new(ctx));- lowerer.visit(pat, Box::new(ref_ident.into()));-- let stmt: Stmt = VarDecl {- kind,- decls: lowerer.out.into_decls(),- ..Default::default()- }- .into();-- match &mut **body {- Stmt::Block(block) => prepend_stmts_to_front(&mut block.stmts, vec![stmt]),- _ => {- **body = BlockStmt {- stmts: vec![stmt, (**body).take()],- ..Default::default()- }- .into();- }- }- }- ForHead::Pat(pat) => {- let ref_ident = private_ident!("_ref");-- ctx.var_declarations.insert_var_declarator(VarDeclarator {- span: DUMMY_SP,- name: ref_ident.clone().into(),- init: None,- definite: false,- });-- let old_pat = mem::replace(&mut **pat, ref_ident.clone().into());-- let mut lowerer = RestLowerer::new(self.config, ExprOutput::new(ctx));- lowerer.visit(old_pat, Box::new(ref_ident.clone().into()));- lowerer.out.exprs.push(ref_ident.into());-- let exprs = lowerer.out.into_exprs();-- let exprs = exprs.into_iter().map(Box::new).collect();- let assign_stmt: Stmt = SeqExpr {- span: DUMMY_SP,- exprs,- }- .into_stmt();-- match &mut **body {- Stmt::Block(block) => {- prepend_stmts_to_front(&mut block.stmts, vec![assign_stmt])- }- _ => {- **body = BlockStmt {- stmts: vec![assign_stmt, (**body).take()],- ..Default::default()- }- .into();- }- }- }- _ => {}- }- }-}--fn prepend_stmts_to_front(stmts: &mut Vec<Stmt>, mut prepended: Vec<Stmt>) {- if prepended.is_empty() {- return;- }-- let mut original = mem::take(stmts);- let mut merged = Vec::with_capacity(prepended.len() + original.len());- merged.append(&mut prepended);- merged.append(&mut original);- *stmts = merged;-}--// ========================================-// Fast-path checks-// ========================================--/// Check if a pattern contains object rest (doesn't traverse into expressions).-fn has_object_rest_in_pat(pat: &Pat) -> bool {- match pat {- Pat::Object(obj) => has_object_rest(obj),- Pat::Array(arr) => arr- .elems- .iter()- .any(|elem| elem.as_ref().is_some_and(has_object_rest_in_pat)),- Pat::Rest(rest) => has_object_rest_in_pat(&rest.arg),- Pat::Assign(assign) => has_object_rest_in_pat(&assign.left),- _ => false,- }-}--/// Check if an object pattern has rest or nested rest.-fn has_object_rest(obj: &ObjectPat) -> bool {- obj.props.iter().any(|prop| match prop {- ObjectPatProp::Rest(_) => true,- ObjectPatProp::KeyValue(kv) => has_object_rest_in_pat(&kv.value),- _ => false,- })-}--/// Check if params contain object rest patterns.-fn params_have_rest<T>(params: &[T]) -> bool-where- T: HasPat,-{- params.iter().any(|p| has_object_rest_in_pat(p.pat()))-}--trait HasPat {- fn pat(&self) -> &Pat;-}--impl HasPat for Param {- fn pat(&self) -> &Pat {- &self.pat- }-}--impl HasPat for Pat {- fn pat(&self) -> &Pat {- self- }-}--/// Check if constructor params contain object rest patterns.-fn constructor_params_have_rest(params: &[ParamOrTsParamProp]) -> bool {- params.iter().any(|p| match p {- ParamOrTsParamProp::Param(param) => has_object_rest_in_pat(¶m.pat),- _ => false,- })-}--// ========================================-// Rest lowering algorithm-// ========================================--/// Output context trait - adapts the algorithm for declaration vs expression.-trait RestOutput {- /// Emit an assignment: `pattern = init`- fn assign(&mut self, pat: Pat, init: Box<Expr>);-- /// Declare a temp variable and return its identifier.- fn declare_temp(&mut self, name: &str) -> Ident;-- /// Capture init into a temp if needed, return (temp_ident, init_expr).- fn capture_init(&mut self, init: Box<Expr>) -> (Ident, Box<Expr>);-}--struct RestLowerer<O: RestOutput> {- config: Config,- out: O,-}--impl<O: RestOutput> RestLowerer<O> {- fn new(config: Config, out: O) -> Self {- Self { config, out }- }-- /// Main entry point: lower a pattern with potential object rest.- fn visit(&mut self, pat: Pat, init: Box<Expr>) {- match pat {- Pat::Object(obj) => self.visit_object(obj, init, &mut Vec::new()),- Pat::Array(arr) => self.visit_array(arr, init),- _ => self.out.assign(pat, init),- }- }-- fn visit_object(- &mut self,- mut obj: ObjectPat,- init: Box<Expr>,- captured_keys: &mut Vec<PropName>,- ) {- let has_rest = matches!(obj.props.last(), Some(ObjectPatProp::Rest(_)));-- // Pre-evaluate impure computed keys- for prop in &mut obj.props {- if let ObjectPatProp::KeyValue(KeyValuePatProp {- key: PropName::Computed(computed),- ..- }) = prop- {- if !is_pure_expr(&computed.expr) {- let temp = self.out.declare_temp("_key");- self.out.assign(temp.clone().into(), computed.expr.take());- *computed.expr = temp.into();- }- }- }-- // Sequential processing: find first property with nested rest- for i in 0..obj.props.len() {- match &obj.props[i] {- ObjectPatProp::KeyValue(kv) => {- if has_rest {- captured_keys.push(kv.key.clone());- }- if has_object_rest_in_pat(&kv.value) {- self.split_object_pattern(obj, i, init, captured_keys);- return;- }- }- ObjectPatProp::Assign(assign) => {- if has_rest {- captured_keys.push(PropName::Ident(IdentName::from(assign.key.clone())));- }- }- ObjectPatProp::Rest(_) => {- // Extract rest_arg by taking from props- let rest_arg = match obj.props.pop() {- Some(ObjectPatProp::Rest(rest)) => *rest.arg,- _ => unreachable!(),- };- self.lower_object_rest(obj, i, rest_arg, init, mem::take(captured_keys));- return;- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }- }-- // No rest pattern found- self.out.assign(obj.into(), init);- }-- fn split_object_pattern(- &mut self,- mut obj: ObjectPat,- split_idx: usize,- init: Box<Expr>,- captured_keys: &mut Vec<PropName>,- ) {- let split_ref = self.out.declare_temp("_ref");-- // Split props: take remaining, keep up to split_idx- let remaining_props: Vec<_> = obj.props.drain(split_idx + 1..).collect();-- // Extract nested pattern before modifying- let nested_pat: Pat = match &mut obj.props[split_idx] {- ObjectPatProp::KeyValue(kv) => match kv.value.as_mut() {- Pat::Assign(assign) => {- let nested = assign.left.take();- *assign.left = split_ref.clone().into();- *nested- }- pat => {- let nested = pat.take();- *kv.value = split_ref.clone().into();- nested- }- },- _ => unreachable!(),- };-- // Capture init if there are remaining properties- let (destructure_init, after_init) = if !remaining_props.is_empty() {- let (obj_ref, init_expr) = self.out.capture_init(init);- (init_expr, Some(Box::new(Expr::Ident(obj_ref))))- } else {- (init, None)- };-- let span = obj.span;-- // Emit destructuring up to split point- self.out.assign(obj.into(), destructure_init);-- // Process nested pattern- self.visit(nested_pat, Box::new(split_ref.into()));-- // Continue with remaining properties- if let Some(after_init) = after_init {- let remaining = ObjectPat {- span,- props: remaining_props,- optional: false,- type_ann: None,- };- self.visit_object(remaining, after_init, captured_keys);- }- }-- fn lower_object_rest(- &mut self,- mut obj: ObjectPat,- rest_idx: usize,- rest_pat: Pat,- init: Box<Expr>,- captured_keys: Vec<PropName>,- ) {- let (source, init_expr) = self.out.capture_init(init);-- // Remove rest pattern and beyond- obj.props.truncate(rest_idx);-- // Emit destructuring for properties before rest.- let is_fresh_source = captured_keys.is_empty();- if rest_idx > 0 || is_fresh_source {- self.out.assign(obj.into(), init_expr);- }-- // Emit rest call- let rest_call = make_rest_call(self.config, source, captured_keys);- self.out.assign(rest_pat, Box::new(rest_call));- }-- fn visit_array(&mut self, arr: ArrayPat, init: Box<Expr>) {- for i in 0..arr.elems.len() {- let Some(elem) = &arr.elems[i] else {- continue;- };- if has_object_rest_in_pat(elem) {- self.split_array_pattern(arr, i, init);- return;- }- }- self.out.assign(arr.into(), init);- }-- fn split_array_pattern(&mut self, mut arr: ArrayPat, split_idx: usize, init: Box<Expr>) {- let split_ref = self.out.declare_temp("_ref");-- // Split: take remaining elements- let remaining_elems: Vec<_> = arr.elems.drain(split_idx + 1..).collect();-- // Extract nested pattern and replace with temp- let nested_pat: Pat = match arr.elems[split_idx].as_mut() {- Some(Pat::Rest(rest)) => {- let nested = rest.arg.take();- *rest.arg = split_ref.clone().into();- *nested- }- Some(Pat::Assign(assign)) => {- let nested = assign.left.take();- *assign.left = split_ref.clone().into();- *nested- }- Some(pat) => {- let nested = pat.take();- arr.elems[split_idx] = Some(split_ref.clone().into());- nested- }- None => unreachable!(),- };-- // Add rest pattern to capture remaining if needed- let remaining = if !remaining_elems.is_empty() {- let tail_ref = self.out.declare_temp("_rest");- arr.elems.push(Some(Pat::Rest(RestPat {- span: DUMMY_SP,- arg: Box::new(tail_ref.clone().into()),- dot3_token: DUMMY_SP,- type_ann: None,- })));- Some((tail_ref, remaining_elems))- } else {- None- };-- let span = arr.span;- self.out.assign(arr.into(), init);-- // Process nested pattern- self.visit(nested_pat, Box::new(split_ref.into()));-- // Continue with remaining elements- if let Some((tail_ref, remaining_elems)) = remaining {- let remaining_arr = ArrayPat {- span,- elems: remaining_elems,- optional: false,- type_ann: None,- };- self.visit_array(remaining_arr, Box::new(tail_ref.into()));- }- }-}--// ========================================-// Output contexts-// ========================================--/// Declaration context output.-struct DeclOutput<'a> {- ctx: &'a mut TraverseCtx,- decls: Vec<VarDeclarator>,-}--impl<'a> DeclOutput<'a> {- fn new(ctx: &'a mut TraverseCtx) -> Self {- Self {- ctx,- decls: Vec::new(),- }- }-- fn into_decls(self) -> Vec<VarDeclarator> {- self.decls- }-}--impl<'a> RestOutput for DeclOutput<'a> {- fn assign(&mut self, pat: Pat, init: Box<Expr>) {- self.decls.push(VarDeclarator {- span: DUMMY_SP,- name: pat,- init: Some(init),- definite: false,- });- }-- fn declare_temp(&mut self, name: &str) -> Ident {- private_ident!(name)- }-- fn capture_init(&mut self, init: Box<Expr>) -> (Ident, Box<Expr>) {- match init.as_ref() {- Expr::Ident(id) => (id.clone(), init),- _ => {- let temp = private_ident!("_ref");- self.decls.push(VarDeclarator {- span: DUMMY_SP,- name: temp.clone().into(),- init: Some(init),- definite: false,- });- (temp.clone(), Box::new(temp.into()))- }- }- }-}--/// Expression context output.-struct ExprOutput<'a> {- exprs: Vec<Expr>,- ctx: &'a mut TraverseCtx,-}--impl<'a> ExprOutput<'a> {- fn new(ctx: &'a mut TraverseCtx) -> Self {- Self {- exprs: Vec::new(),- ctx,- }- }-- fn into_exprs(self) -> Vec<Expr> {- self.exprs- }-}--impl<'a> RestOutput for ExprOutput<'a> {- fn assign(&mut self, pat: Pat, init: Box<Expr>) {- if let Ok(target) = pat.try_into() {- self.exprs.push(- AssignExpr {- span: DUMMY_SP,- left: target,- op: op!("="),- right: init,- }- .into(),- );- }- }-- fn declare_temp(&mut self, name: &str) -> Ident {- let temp = private_ident!(name);-- self.ctx- .var_declarations- .insert_var_declarator(VarDeclarator {- span: DUMMY_SP,- name: temp.clone().into(),- init: None,- definite: false,- });-- temp- }-- fn capture_init(&mut self, init: Box<Expr>) -> (Ident, Box<Expr>) {- match init.as_ref() {- Expr::Ident(id) => (id.clone(), init),- _ => {- let temp = self.declare_temp("_ref");- self.exprs.push(- AssignExpr {- span: DUMMY_SP,- left: temp.clone().into(),- op: op!("="),- right: init,- }- .into(),- );- (temp.clone(), Box::new(temp.into()))- }- }- }-}--// ========================================-// Helper functions-// ========================================--fn make_rest_call(config: Config, source: Ident, excluded: Vec<PropName>) -> Expr {- if excluded.is_empty() {- return CallExpr {- callee: helper!(extends),- args: vec![ObjectLit::default().as_arg(), source.as_arg()],- ..Default::default()- }- .into();- }-- let helper = if config.no_symbol {- helper!(object_without_properties_loose)- } else {- helper!(object_without_properties)- };-- let impure_count = excluded- .iter()- .filter(|k| matches!(k, PropName::Computed(expr) if !is_lit_str(&expr.expr)))- .count();-- let keys: Vec<Option<ExprOrSpread>> = excluded- .into_iter()- .map(|key| {- let key_expr = match key {- PropName::Ident(id) => Expr::Lit(Lit::Str(id.sym.into())),- PropName::Str(s) => Expr::Lit(Lit::Str(s)),- PropName::Num(n) => Expr::Lit(Lit::Str(Str {- span: n.span,- value: n.value.to_js_string().into(),- raw: None,- })),- PropName::Computed(c) if impure_count == 1 && !is_lit_str(&c.expr) => CallExpr {- callee: helper!(to_property_key),- args: vec![c.expr.as_arg()],- ..Default::default()- }- .into(),- PropName::Computed(c) => *c.expr,- PropName::BigInt(b) => Expr::Lit(Lit::Str(Str {- span: b.span,- value: b.value.to_string().into(),- raw: None,- })),- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- };- Some(key_expr.as_arg())- })- .collect();-- let mut expr: Expr = ArrayLit {- elems: keys,- ..Default::default()- }- .into();-- // Optimization: If there is exactly one impure computed key, we can- // directly call to_property_key on it here, rather than mapping over- // the array later. This avoids unnecessary array creation and mapping.- if impure_count > 1 {- // [].map(to_property_key)- expr = expr- .make_member(quote_ident!("map"))- .as_call(DUMMY_SP, vec![helper_expr!(to_property_key).as_arg()]);- }-- CallExpr {- callee: helper,- args: vec![source.as_arg(), expr.as_arg()],- ..Default::default()- }- .into()-}--/// Collector for function parameters that need to be destructured in body.-struct ParamCollector<'a> {- collected_pats: Vec<Pat>,- temp_exprs: Vec<ExprOrSpread>,- config: Config,- ctx: &'a mut TraverseCtx,-}--impl<'a> ParamCollector<'a> {- fn new(config: Config, ctx: &'a mut TraverseCtx) -> Self {- Self {- collected_pats: Vec::new(),- temp_exprs: Vec::new(),- config,- ctx,- }- }-- /// Process a single parameter: extract pattern, replace with temp variable.- fn collect(&mut self, index: usize, pat: &mut Pat) {- let temp = private_ident!(format!("_{}", index));-- let original_pat = match pat {- Pat::Rest(rest_pat) => mem::replace(&mut *rest_pat.arg, temp.clone().into()),- Pat::Assign(pat) => {- let init = AssignPat {- span: DUMMY_SP,- left: Box::new(temp.clone().into()),- right: Expr::undefined(DUMMY_SP),- };- mem::replace(pat, init).into()- }- pat => mem::replace(pat, temp.clone().into()),- };-- self.collected_pats.push(original_pat);- self.temp_exprs.push(temp.as_arg());- }-- /// Create array destructuring declaration with lowering: `let [patterns...]- /// = [temps...]`- fn into_stmts(mut self) -> Vec<Stmt> {- if self.collected_pats.is_empty() {- return Vec::new();- }-- let mut stmts = Vec::new();-- // Special case: single non-assign pattern- if self.collected_pats.len() == 1 {- let pat = self.collected_pats.pop().unwrap();- let Some(init_arg) = self.temp_exprs.pop() else {- return stmts;- };-- if !matches!(pat, Pat::Assign(_)) {- // Check if has rest and needs lowering- if has_object_rest_in_pat(&pat) {- let mut lowerer = RestLowerer::new(self.config, DeclOutput::new(self.ctx));- lowerer.visit(pat, init_arg.expr);- let decl = VarDecl {- kind: VarDeclKind::Let,- decls: lowerer.out.into_decls(),- ..Default::default()- };- stmts.push(decl.into());- } else {- stmts.push(- VarDecl {- kind: VarDeclKind::Let,- decls: vec![VarDeclarator {- span: DUMMY_SP,- name: pat,- init: Some(init_arg.expr),- definite: false,- }],- ..Default::default()- }- .into(),- );- }- return stmts;- }- // Put it back if it's an assign pattern- self.collected_pats.push(pat);- self.temp_exprs.push(init_arg);- }-- // Multiple patterns - check if any need lowering- let has_rest = self.collected_pats.iter().any(has_object_rest_in_pat);-- if has_rest {- // Need special handling: create array variable first, then destructure- // iteratively- let mut decls = Vec::new();-- // Step 1: Create array variable: _ref = [temps...]- let array_temp = private_ident!("_ref");- decls.push(VarDeclarator {- span: DUMMY_SP,- name: array_temp.clone().into(),- init: Some(Box::new(- ArrayLit {- span: DUMMY_SP,- elems: self.temp_exprs.into_iter().map(Some).collect(),- }- .into(),- )),- definite: false,- });-- // Step 2: Process patterns iteratively- let mut current_array: Ident = array_temp;- let num_pats = self.collected_pats.len();-- for (i, pat) in self.collected_pats.into_iter().enumerate() {- let is_last = i == num_pats - 1;-- // Check if this pattern needs lowering- let inner_pat = if let Pat::Assign(ref assign_pat) = pat {- &*assign_pat.left- } else {- &pat- };- let needs_lowering = has_object_rest_in_pat(inner_pat);-- if needs_lowering {- // Pattern needs lowering - create temp- let temp = private_ident!("_ref");-- // Create the element pattern, preserving default value if present- let elem_pat = if let Pat::Assign(ref assign_pat) = pat {- Pat::Assign(AssignPat {- span: DUMMY_SP,- left: Box::new(temp.clone().into()),- right: assign_pat.right.clone(),- })- } else {- temp.clone().into()- };-- // Destructure array to extract this pattern- if is_last {- // Last element: [temp] = current_array or [temp = default] = current_array- decls.push(VarDeclarator {- span: DUMMY_SP,- name: ArrayPat {- span: DUMMY_SP,- elems: vec![Some(elem_pat)],- optional: false,- type_ann: None,- }- .into(),- init: Some(Box::new(current_array.clone().into())),- definite: false,- });- } else {- // Not last: [temp, ...rest] = current_array or [temp = default, ...rest] =- // current_array- let rest = private_ident!("_rest");- decls.push(VarDeclarator {- span: DUMMY_SP,- name: ArrayPat {- span: DUMMY_SP,- elems: vec![- Some(elem_pat),- Some(Pat::Rest(RestPat {- span: DUMMY_SP,- arg: Box::new(rest.clone().into()),- dot3_token: DUMMY_SP,- type_ann: None,- })),- ],- optional: false,- type_ann: None,- }- .into(),- init: Some(Box::new(current_array.clone().into())),- definite: false,- });- current_array = rest;- }-- // Lower the pattern- let inner_pat = if let Pat::Assign(assign_pat) = pat {- *assign_pat.left- } else {- pat- };-- let mut lowerer = RestLowerer::new(self.config, DeclOutput::new(self.ctx));- lowerer.visit(inner_pat, Box::new(temp.into()));- decls.extend(lowerer.out.into_decls());- } else {- // Pattern doesn't need lowering - use directly- if is_last {- // Last element: [pattern] = current_array- decls.push(VarDeclarator {- span: DUMMY_SP,- name: ArrayPat {- span: DUMMY_SP,- elems: vec![Some(pat)],- optional: false,- type_ann: None,- }- .into(),- init: Some(Box::new(current_array.clone().into())),- definite: false,- });- } else {- // Not last: [pattern, ...rest] = current_array- let rest = private_ident!("_rest");- decls.push(VarDeclarator {- span: DUMMY_SP,- name: ArrayPat {- span: DUMMY_SP,- elems: vec![- Some(pat),- Some(Pat::Rest(RestPat {- span: DUMMY_SP,- arg: Box::new(rest.clone().into()),- dot3_token: DUMMY_SP,- type_ann: None,- })),- ],- optional: false,- type_ann: None,- }- .into(),- init: Some(Box::new(current_array.clone().into())),- definite: false,- });- current_array = rest;- }- }- }-- stmts.push(- VarDecl {- kind: VarDeclKind::Let,- decls,- ..Default::default()- }- .into(),- );- } else {- // No rest - simple array destructuring- let array_pat = Pat::Array(ArrayPat {- span: DUMMY_SP,- elems: self.collected_pats.into_iter().map(Some).collect(),- optional: false,- type_ann: None,- });-- let array_init = Box::new(- ArrayLit {- span: DUMMY_SP,- elems: self.temp_exprs.into_iter().map(Some).collect(),- }- .into(),- );-- stmts.push(- VarDecl {- kind: VarDeclKind::Let,- decls: vec![VarDeclarator {- span: DUMMY_SP,- name: array_pat,- init: Some(array_init),- definite: false,- }],- ..Default::default()- }- .into(),- );- }-- stmts- }-}--fn collect_idents_from_pat(pat: &Pat, out: &mut Vec<Ident>) {- match pat {- Pat::Ident(id) => out.push(id.id.clone()),- Pat::Object(obj) => {- for prop in &obj.props {- match prop {- ObjectPatProp::KeyValue(kv) => collect_idents_from_pat(&kv.value, out),- ObjectPatProp::Assign(a) => out.push(a.key.id.clone()),- ObjectPatProp::Rest(r) => collect_idents_from_pat(&r.arg, out),- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }- }- }- Pat::Array(arr) => {- for elem in arr.elems.iter().flatten() {- collect_idents_from_pat(elem, out);- }- }- Pat::Rest(r) => collect_idents_from_pat(&r.arg, out),- Pat::Assign(a) => collect_idents_from_pat(&a.left, out),- _ => {}- }-}--fn pat_to_assign_target_pat(pat: Pat) -> AssignTargetPat {- pat.try_into()- .unwrap_or_else(|p: Pat| AssignTargetPat::Invalid(Invalid { span: p.span() }))-}--fn is_lit_str(expr: &Expr) -> bool {- match expr {- Expr::Lit(Lit::Str(_)) => true,- Expr::Tpl(tpl) => tpl.exprs.is_empty(),- _ => false,- }-}--/// Check if an expression is "pure" (has no side effects).-fn is_pure_expr(expr: &Expr) -> bool {- match expr {- Expr::Ident(_) | Expr::Lit(_) => true,- Expr::Tpl(tpl) => tpl.exprs.is_empty(),- // Symbol.iterator, Symbol.toStringTag, etc.- Expr::Member(MemberExpr {- obj,- prop: MemberProp::Ident(_),- ..- }) => matches!(&**obj, Expr::Ident(i) if &*i.sym == "Symbol"),- _ => false,- }-}
deps/swc/crates/swc_ecma_transformer/src/es2019/mod.rs
@@ -1,26 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--pub(crate) mod optional_catch_binding;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2019Options {- pub optional_catch_binding: bool,-}--impl Es2019Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.optional_catch_binding- }-}--pub(crate) fn hook(options: Es2019Options) -> impl VisitMutHook<TraverseCtx> {- if options.optional_catch_binding {- Some(self::optional_catch_binding::hook())- } else {- None- }-}
deps/swc/crates/swc_ecma_transformer/src/es2019/optional_catch_binding.rs
@@ -1,41 +0,0 @@-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::private_ident;-use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- OptionalCatchBindingPass {}-}--pub(crate) fn pass() -> impl Pass {- visit_mut_pass(OptionalCatchBindingPass {})-}--struct OptionalCatchBindingPass {}--impl OptionalCatchBindingPass {- fn transform_catch_clause(&mut self, node: &mut CatchClause) {- if node.param.is_none() {- // TODO: Do not use private_ident! here.- // All private identifiers should be tracked using TraverseCtx.- node.param = Some(Pat::Ident(private_ident!("unused").into()));- }- }-}--impl VisitMutHook<TraverseCtx> for OptionalCatchBindingPass {- fn enter_catch_clause(&mut self, node: &mut CatchClause, _: &mut TraverseCtx) {- self.transform_catch_clause(node);- }-}--impl VisitMut for OptionalCatchBindingPass {- noop_visit_mut_type!(fail);-- fn visit_mut_catch_clause(&mut self, node: &mut CatchClause) {- self.transform_catch_clause(node);- node.body.visit_mut_with(self);- }-}
deps/swc/crates/swc_ecma_transformer/src/es2020/export_namespace_from.rs
@@ -1,149 +0,0 @@-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::private_ident;-use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut};--use crate::{utils::normalize_module_export_name, TraverseCtx};--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- ExportNamespaceFromPass-}--pub(crate) fn pass() -> impl Pass {- visit_mut_pass(ExportNamespaceFromPass)-}--struct ExportNamespaceFromPass;--impl ExportNamespaceFromPass {- fn transform_export_namespace_from(&mut self, items: &mut Vec<ModuleItem>) {- let count = items- .iter()- .filter(|m| {- matches!(m, ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {- specifiers,- src: Some(..),- type_only: false,- ..- })) if specifiers.iter().any(|s| s.is_namespace()))- })- .count();-- if count == 0 {- return;- }-- let mut stmts = Vec::<ModuleItem>::with_capacity(items.len() + count);-- for item in items.drain(..) {- match item {- ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {- span,- specifiers,- src: Some(src),- type_only: false,- with,- })) if specifiers.iter().any(|s| s.is_namespace()) => {- let mut origin_specifiers = Vec::new();-- let mut import_specifiers = Vec::new();- let mut export_specifiers = Vec::new();-- for s in specifiers.into_iter() {- match s {- ExportSpecifier::Namespace(ExportNamespaceSpecifier { span, name }) => {- let local_bridge = private_ident!(format!(- "_{}",- normalize_module_export_name(&name)- ));-- import_specifiers.push(ImportSpecifier::Namespace(- ImportStarAsSpecifier {- span,- local: local_bridge.clone(),- },- ));- export_specifiers.push(ExportSpecifier::Named(- ExportNamedSpecifier {- span,- orig: local_bridge.into(),- exported: Some(name),- is_type_only: false,- },- ))- }- ExportSpecifier::Default(..) | ExportSpecifier::Named(..) => {- origin_specifiers.push(s);- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }- }-- stmts.push(- ImportDecl {- span,- specifiers: import_specifiers,- src: src.clone(),- type_only: false,- with: with.clone(),- phase: Default::default(),- }- .into(),- );-- stmts.push(- NamedExport {- span,- specifiers: export_specifiers,- src: None,- type_only: false,- with: None,- }- .into(),- );-- if !origin_specifiers.is_empty() {- stmts.push(- NamedExport {- span,- specifiers: origin_specifiers,- src: Some(src),- type_only: false,- with,- }- .into(),- );- }- }- _ => {- stmts.push(item);- }- }- }-- *items = stmts;- }-}--impl VisitMutHook<TraverseCtx> for ExportNamespaceFromPass {- fn exit_program(&mut self, node: &mut Program, _: &mut TraverseCtx) {- let Program::Module(module) = node else {- return;- };-- self.transform_export_namespace_from(&mut module.body);- }-}--impl VisitMut for ExportNamespaceFromPass {- noop_visit_mut_type!(fail);-- fn visit_mut_program(&mut self, node: &mut Program) {- let Program::Module(module) = node else {- return;- };-- self.transform_export_namespace_from(&mut module.body);- }-}
deps/swc/crates/swc_ecma_transformer/src/es2020/mod.rs
@@ -1,49 +0,0 @@-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_transforms_base::assumptions::Assumptions;--use crate::{- hook_utils::{HookBuilder, NoopHook},- TraverseCtx,-};--pub(crate) mod export_namespace_from;-pub(crate) mod nullish_coalescing;-mod optional_chaining;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2020Options {- pub export_namespace_from: bool,-- pub nullish_coalescing: bool,-- pub optional_chaining: bool,-}--impl Es2020Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.export_namespace_from || self.nullish_coalescing || self.optional_chaining- }-}--pub(crate) fn hook(- options: Es2020Options,- assumptions: Assumptions,-) -> impl VisitMutHook<TraverseCtx> {- let hook = HookBuilder::new(NoopHook);-- let hook = hook.chain(if options.export_namespace_from {- Some(self::export_namespace_from::hook())- } else {- None- });-- let hook = hook.chain(if options.nullish_coalescing {- Some(self::nullish_coalescing::hook(assumptions.no_document_all))- } else {- None- });-- hook.build()-}
deps/swc/crates/swc_ecma_transformer/src/es2020/nullish_coalescing.rs
@@ -1,253 +0,0 @@-//! ES2020: Nullish Coalescing Operator-//!-//! This plugin transforms the nullish coalescing operator (`??`) and nullish-//! coalescing assignment operator (`??=`) to conditional expressions.-//!-//! > This plugin is included in `preset-env`, in ES2020-//!-//! ## Example-//!-//! Input:-//! ```js-//! var foo = object.foo ?? "default";-//! x ??= 5;-//! ```-//!-//! Output:-//! ```js-//! var _object$foo;-//! var foo = (_object$foo = object.foo) !== null && _object$foo !== void 0-//! ? _object$foo-//! : "default";-//! x = x !== null && x !== void 0 ? x : 5;-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-nullish-coalescing-operator](https://babel.dev/docs/babel-plugin-transform-nullish-coalescing-operator).-//!-//! ## References:-//!-//! * Babel plugin implementation: <https://github.com/babel/babel/blob/v7.26.2/packages/babel-plugin-transform-nullish-coalescing-operator>-//! * Nullish coalescing TC39 proposal: <https://github.com/tc39/proposal-nullish-coalescing>-//! * Nullish coalescing specification: <https://tc39.es/ecma262/#sec-binary-logical-operators>--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::{alias_ident_for_simple_assign_tatget, alias_if_required};--use crate::TraverseCtx;--/// Creates a nullish coalescing transformation hook.-///-/// The `no_document_all` parameter controls whether to use a simplified-/// transformation for environments that don't support `document.all`:-/// - `true`: `a ?? b` -> `a != null ? a : b`-/// - `false`: `a ?? b` -> `a !== null && a !== void 0 ? a : b`-pub fn hook(no_document_all: bool) -> impl VisitMutHook<TraverseCtx> {- NullishCoalescingPass { no_document_all }-}--struct NullishCoalescingPass {- no_document_all: bool,-}--impl VisitMutHook<TraverseCtx> for NullishCoalescingPass {- fn enter_expr(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- match expr {- // Transform `left ?? right`- Expr::Bin(bin_expr) if bin_expr.op == BinaryOp::NullishCoalescing => {- self.transform_nullish_coalescing(expr, ctx);- }- // Transform `left ??= right`- Expr::Assign(assign_expr) if assign_expr.op == AssignOp::NullishAssign => {- self.transform_nullish_coalescing_assign(expr, ctx);- }- _ => {}- }- }-}--impl NullishCoalescingPass {- /// Transform `left ?? right` to a conditional expression- ///- /// Depending on the complexity of the left side:- /// - Simple (ident, this, literal): `left !== null && left !== void 0 ?- /// left : right`- /// - Complex: `(_ref = left) !== null && _ref !== void 0 ? _ref : right`- fn transform_nullish_coalescing(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- let Expr::Bin(bin_expr) = expr else {- return;- };-- let left = bin_expr.left.take();- let right = bin_expr.right.take();-- // Determine if we need to create a temporary variable- let (alias_ident, needs_temp) = alias_if_required(&left, "ref");-- if needs_temp {- // Inject variable declaration for temporary variable- ctx.var_declarations- .insert_var(alias_ident.clone().into(), None);- }-- // Create the test expression and consequent- let (test_expr, cons_expr) = if needs_temp {- // Complex left side: (_ref = left) !== null && _ref !== void 0 ? _ref : right- let assign_expr = Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias_ident.clone(),- type_ann: None,- })),- right: left,- }));-- let test = create_nullish_test(self.no_document_all, assign_expr, &alias_ident);- let cons = Box::new(Expr::Ident(alias_ident));-- (test, cons)- } else {- // Simple left side: left !== null && left !== void 0 ? left : right- let test = create_nullish_test(self.no_document_all, left.clone(), &alias_ident);- let cons = left;-- (test, cons)- };-- *expr = Expr::Cond(CondExpr {- span: DUMMY_SP,- test: test_expr,- cons: cons_expr,- alt: right,- });- }-- /// Transform `left ??= right` to assignment with conditional- ///- /// Depending on the type of left side:- /// - Identifier: `x ??= 5` -> `x = x !== null && x !== void 0 ? x : 5`- /// - Member/Super: Needs temporary variables to avoid side effects- fn transform_nullish_coalescing_assign(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- let Expr::Assign(assign_expr) = expr else {- return;- };-- match &mut assign_expr.left {- // Simple identifier: `x ??= right` -> `x = x !== null && x !== void 0 ? x : right`- AssignTarget::Simple(SimpleAssignTarget::Ident(ident)) => {- let ident_ref = ident.id.clone();- let right = assign_expr.right.take();-- let test = create_nullish_test(- self.no_document_all,- Box::new(Expr::Ident(ident_ref.clone())),- &ident_ref,- );-- *expr = Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: ident_ref.clone(),- type_ann: None,- })),- right: Box::new(Expr::Cond(CondExpr {- span: DUMMY_SP,- test,- cons: Box::new(Expr::Ident(ident_ref)),- alt: right,- })),- });- }- // Member expression or super property: needs temporary variable- AssignTarget::Simple(left) => {- let alias = alias_ident_for_simple_assign_tatget(left, "refs");-- // Inject variable declaration- ctx.var_declarations.insert_var(alias.clone().into(), None);-- let right = assign_expr.right.take();- let left_clone = left.clone();-- // Create: (_ref = left) !== null && _ref !== void 0 ? _ref : (left = right)- let assign_to_temp = Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias.clone(),- type_ann: None,- })),- right: left.take().into(),- }));-- let test = create_nullish_test(self.no_document_all, assign_to_temp, &alias);-- let cons = Box::new(Expr::Ident(alias.clone()));-- let alt = Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(left_clone),- right,- }));-- // Final: _ref = (_ref = left) !== null && _ref !== void 0 ? _ref : (left =- // right)- *expr = Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias,- type_ann: None,- })),- right: Box::new(Expr::Cond(CondExpr {- span: DUMMY_SP,- test,- cons,- alt,- })),- });- }- _ => {}- }- }-}--/// Create a test expression for nullish check-///-/// Returns:-/// - If `no_document_all` is true: `test_expr != null`-/// - If `no_document_all` is false: `test_expr !== null && alias !== void 0`-fn create_nullish_test(no_document_all: bool, test_expr: Box<Expr>, alias: &Ident) -> Box<Expr> {- if no_document_all {- // Simplified: test_expr != null- Box::new(Expr::Bin(BinExpr {- span: DUMMY_SP,- left: test_expr,- op: BinaryOp::NotEq,- right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),- }))- } else {- // Standard: test_expr !== null && alias !== void 0- Box::new(Expr::Bin(BinExpr {- span: DUMMY_SP,- left: Box::new(Expr::Bin(BinExpr {- span: DUMMY_SP,- left: test_expr,- op: BinaryOp::NotEqEq,- right: Box::new(Expr::Lit(Lit::Null(Null { span: DUMMY_SP }))),- })),- op: BinaryOp::LogicalAnd,- right: Box::new(Expr::Bin(BinExpr {- span: DUMMY_SP,- left: Box::new(Expr::Ident(alias.clone())),- op: BinaryOp::NotEqEq,- right: Expr::undefined(DUMMY_SP),- })),- }))- }-}
deps/swc/crates/swc_ecma_transformer/src/es2020/optional_chaining.rs
@@ -1 +0,0 @@-
deps/swc/crates/swc_ecma_transformer/src/es2021/logical_assignment_operators.rs
@@ -1,257 +0,0 @@-//! ES2021: Logical Assignment Operators-//!-//! This plugin transforms logical assignment operators (`&&=`, `||=`, `??=`)-//! to a series of logical expressions.-//!-//! > This plugin is included in `preset-env`, in ES2021-//!-//! ## Example-//!-//! Input:-//! ```js-//! a ||= b;-//! obj.a.b ||= c;-//!-//! a &&= b;-//! obj.a.b &&= c;-//! ```-//!-//! Output:-//! ```js-//! var _obj$a, _obj$a2;-//!-//! a || (a = b);-//! (_obj$a = obj.a).b || (_obj$a.b = c);-//!-//! a && (a = b);-//! (_obj$a2 = obj.a).b && (_obj$a2.b = c);-//! ```-//!-//! ## Implementation-//!-//! Implementation based on [@babel/plugin-transform-logical-assignment-operators](https://babel.dev/docs/babel-plugin-transform-logical-assignment-operators).-//!-//! ## References:-//! * Babel plugin implementation: <https://github.com/babel/babel/tree/v7.26.2/packages/babel-plugin-transform-logical-assignment-operators>-//! * Logical Assignment TC39 proposal: <https://github.com/tc39/proposal-logical-assignment>--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::alias_ident_for;--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- LogicalAssignmentOperatorsPass-}--struct LogicalAssignmentOperatorsPass;--impl VisitMutHook<TraverseCtx> for LogicalAssignmentOperatorsPass {- fn enter_expr(&mut self, expr: &mut Expr, ctx: &mut TraverseCtx) {- let Expr::Assign(assign_expr) = expr else {- return;- };-- // Check if this is a logical assignment operator- let op = match assign_expr.op {- AssignOp::AndAssign => BinaryOp::LogicalAnd,- AssignOp::OrAssign => BinaryOp::LogicalOr,- AssignOp::NullishAssign => BinaryOp::NullishCoalescing,- _ => return,- };-- // Only handle simple assignment targets- let AssignTarget::Simple(left) = &mut assign_expr.left else {- return;- };-- let span = assign_expr.span;-- // Generate left expression and assignment target- let (left_expr, assign_target) = match left {- // `a &&= c` -> `a && (a = c)`- SimpleAssignTarget::Ident(ident) => {- let left_expr = Box::new(Expr::Ident(ident.id.clone()));- let assign_target = left.clone();- (left_expr, assign_target)- }-- // `a.b &&= c` -> `var _a; (_a = a).b && (_a.b = c)`- SimpleAssignTarget::Member(member_expr) => {- self.transform_member_expression(member_expr, ctx)- }-- // `super.prop &&= c` -> handle super property- SimpleAssignTarget::SuperProp(super_prop_expr) => {- self.transform_super_prop(super_prop_expr, ctx)- }-- // Other cases like optional member expressions- _ => {- let left_expr: Box<Expr> = left.clone().into();- (left_expr.clone(), left.clone())- }- };-- // Create assignment: `assign_target = right`- let assignment = Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(assign_target),- right: assign_expr.right.take(),- }));-- // Create binary expression: `left_expr op assignment`- *expr = Expr::Bin(BinExpr {- span,- op,- left: left_expr,- right: assignment,- });- }-}--impl LogicalAssignmentOperatorsPass {- fn transform_member_expression(- &mut self,- member_expr: &mut MemberExpr,- ctx: &mut TraverseCtx,- ) -> (Box<Expr>, SimpleAssignTarget) {- // Handle object: create temp var unless it's `this`- let (left_obj, right_obj) = match &*member_expr.obj {- // `this` doesn't need a temp var- Expr::This(_) => (member_expr.obj.clone(), member_expr.obj.clone()),- // For other expressions, create a temp var- obj => {- let alias = alias_ident_for(obj, "_ref");-- // Inject variable declaration- self.inject_var_decl(&alias, ctx);-- let left_obj = Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias.clone(),- type_ann: None,- })),- right: member_expr.obj.clone(),- }));-- let right_obj = Box::new(Expr::Ident(alias));-- (left_obj, right_obj)- }- };-- // Handle property: create temp var for computed properties- let (left_prop, right_prop) = match &member_expr.prop {- MemberProp::Computed(computed) => {- let alias = alias_ident_for(&computed.expr, "_ref");-- // Inject variable declaration- self.inject_var_decl(&alias, ctx);-- let left_prop = MemberProp::Computed(ComputedPropName {- span: computed.span,- expr: Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias.clone(),- type_ann: None,- })),- right: computed.expr.clone(),- })),- });-- let right_prop = MemberProp::Computed(ComputedPropName {- span: computed.span,- expr: Box::new(Expr::Ident(alias)),- });-- (left_prop, right_prop)- }- // Static properties don't need temp vars- prop => (prop.clone(), prop.clone()),- };-- // Build left expression: `(_a = a).b` or `(_a = a)[_b = b]`- let left_expr = Box::new(Expr::Member(MemberExpr {- span: member_expr.span,- obj: left_obj,- prop: left_prop,- }));-- // Build assignment target: `_a.b` or `_a[_b]`- let assign_target = SimpleAssignTarget::Member(MemberExpr {- span: member_expr.span,- obj: right_obj,- prop: right_prop,- });-- (left_expr, assign_target)- }-- fn transform_super_prop(- &mut self,- super_prop_expr: &mut SuperPropExpr,- ctx: &mut TraverseCtx,- ) -> (Box<Expr>, SimpleAssignTarget) {- let (left_prop, right_prop) = match &super_prop_expr.prop {- SuperProp::Computed(computed) => {- let alias = alias_ident_for(&computed.expr, "_ref");-- // Inject variable declaration- self.inject_var_decl(&alias, ctx);-- let left_prop = SuperProp::Computed(ComputedPropName {- span: computed.span,- expr: Box::new(Expr::Assign(AssignExpr {- span: DUMMY_SP,- op: AssignOp::Assign,- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: alias.clone(),- type_ann: None,- })),- right: computed.expr.clone(),- })),- });-- let right_prop = SuperProp::Computed(ComputedPropName {- span: computed.span,- expr: Box::new(Expr::Ident(alias)),- });-- (left_prop, right_prop)- }- prop => (prop.clone(), prop.clone()),- };-- let left_expr = Box::new(Expr::SuperProp(SuperPropExpr {- span: super_prop_expr.span,- obj: super_prop_expr.obj,- prop: left_prop,- }));-- let assign_target = SimpleAssignTarget::SuperProp(SuperPropExpr {- span: super_prop_expr.span,- obj: super_prop_expr.obj,- prop: right_prop,- });-- (left_expr, assign_target)- }-- fn inject_var_decl(&mut self, ident: &Ident, ctx: &mut TraverseCtx) {- ctx.var_declarations.insert_var(- BindingIdent {- id: ident.clone(),- type_ann: None,- },- None,- );- }-}
deps/swc/crates/swc_ecma_transformer/src/es2021/mod.rs
@@ -1,33 +0,0 @@-pub(crate) mod logical_assignment_operators;--use swc_ecma_hooks::VisitMutHook;--use crate::{- hook_utils::{HookBuilder, NoopHook},- TraverseCtx,-};--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2021Options {- pub logical_assignment_operators: bool,-}--impl Es2021Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.logical_assignment_operators- }-}--pub fn hook(options: Es2021Options) -> impl VisitMutHook<TraverseCtx> {- let hook = HookBuilder::new(NoopHook);-- let hook = hook.chain(if options.logical_assignment_operators {- Some(self::logical_assignment_operators::hook())- } else {- None- });-- hook.build()-}
deps/swc/crates/swc_ecma_transformer/src/es2022/class_properties/mod.rs
@@ -1 +0,0 @@-
deps/swc/crates/swc_ecma_transformer/src/es2022/class_static_block.rs
@@ -1,210 +0,0 @@-//! ES2022: Class Static Block-//!-//! This module transforms ES2022 class static blocks into private properties-//! with initializers.-//!-//! ## Example-//!-//! Input:-//! ```js-//! class C {-//! static { foo(); }-//! }-//! ```-//!-//! Output:-//! ```js-//! class C {-//! static #_ = foo();-//! }-//! ```-//!-//! For multiple statements:-//! ```js-//! class C {-//! static { foo(); bar(); }-//! }-//! ```-//!-//! Output:-//! ```js-//! class C {-//! static #_ = (() => { foo(); bar(); })();-//! }-//! ```-//!-//! ## References-//! * TC39 proposal: <https://github.com/tc39/proposal-class-static-block>--use rustc_hash::FxHashSet;-use swc_atoms::Atom;-use swc_common::{source_map::PLACEHOLDER_SP, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::ExprFactory;--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- ClassStaticBlock::default()-}--#[derive(Default)]-struct ClassStaticBlock {- /// Stack of sets of existing private names for nested classes- existing_names_stack: Vec<FxHashSet<Atom>>,-}--impl ClassStaticBlock {- /// Generate a unique private property name that doesn't conflict with- /// existing names- fn generate_unique_name(&self, existing_names: &FxHashSet<Atom>) -> Atom {- // Start with "_"- let base: Atom = "_".into();- if !existing_names.contains(&base) {- return base;- }-- // Try "_2", "_3", etc.- let mut counter = 2;- loop {- let name: Atom = format!("_{counter}").into();- if !existing_names.contains(&name) {- return name;- }- counter += 1;- }- }-- /// Collect all existing private names in the class- fn collect_existing_private_names(&self, class: &Class) -> FxHashSet<Atom> {- let mut names = FxHashSet::default();- for member in &class.body {- if let ClassMember::PrivateProp(prop) = member {- names.insert(prop.key.name.clone());- } else if let ClassMember::PrivateMethod(method) = member {- names.insert(method.key.name.clone());- }- }- names- }-- /// Transform a static block into a private property- fn transform_static_block(- &self,- block: StaticBlock,- existing_names: &mut FxHashSet<Atom>,- ) -> ClassMember {- let span = block.span;- let mut stmts = block.body.stmts;-- // Generate a unique private name- let private_name = self.generate_unique_name(existing_names);- existing_names.insert(private_name.clone());-- let value = if stmts.len() == 1 {- // For single statement, try to extract the expression directly- let stmt = stmts.pop().unwrap();- match stmt {- Stmt::Expr(ExprStmt { expr, .. }) => {- // Single expression statement - use the expression directly (no clone)- Some(expr)- }- other => {- // Other single statement - wrap in IIFE- Some(Box::new(self.wrap_in_iife(vec![other])))- }- }- } else if stmts.is_empty() {- // Empty block - no initializer needed- None- } else {- // Multiple statements - wrap in IIFE- Some(Box::new(self.wrap_in_iife(stmts)))- };-- ClassMember::PrivateProp(PrivateProp {- span,- ctxt: Default::default(),- key: PrivateName {- // Use PLACEHOLDER_SP to signal to class_properties- // that this came from a static block- span: PLACEHOLDER_SP,- name: private_name,- },- value,- type_ann: None,- is_static: true,- decorators: vec![],- accessibility: None,- is_optional: false,- is_override: false,- readonly: false,- definite: false,- })- }-- /// Wrap statements in an immediately-invoked arrow function expression- fn wrap_in_iife(&self, stmts: Vec<Stmt>) -> Expr {- let arrow = ArrowExpr {- span: DUMMY_SP,- params: vec![],- body: Box::new(ArrowFunctionBody::FunctionBody(FunctionBody {- span: DUMMY_SP,- stmts,- })),- is_async: false,- is_generator: false,- type_params: None,- return_type: None,- ctxt: Default::default(),- };-- CallExpr {- span: DUMMY_SP,- callee: arrow.as_callee(),- args: vec![],- type_args: None,- ctxt: Default::default(),- }- .into()- }-}--impl VisitMutHook<TraverseCtx> for ClassStaticBlock {- fn enter_class(&mut self, _class: &mut Class, _ctx: &mut TraverseCtx) {- // Push an empty set for this class level- // We'll collect names in exit_class after nested classes are transformed- self.existing_names_stack.push(FxHashSet::default());- }-- fn exit_class(&mut self, class: &mut Class, _ctx: &mut TraverseCtx) {- // Pop the parent set (not used currently but maintained for stack integrity)- let _parent_names = self.existing_names_stack.pop().expect(- "existing_names_stack underflow: exit_class called without matching enter_class",- );-- // Collect existing private names after nested classes have been transformed- // This ensures we see all private names including those generated from- // static blocks in nested classes- let mut existing_names = self.collect_existing_private_names(class);-- // Transform all static blocks in the class body- let mut new_body = Vec::with_capacity(class.body.len());- for member in class.body.drain(..) {- match member {- ClassMember::StaticBlock(block) => {- // Skip empty static blocks entirely- if !block.body.stmts.is_empty() {- let transformed = self.transform_static_block(block, &mut existing_names);- new_body.push(transformed);- }- }- other => {- new_body.push(other);- }- }- }- class.body = new_body;- }-}
deps/swc/crates/swc_ecma_transformer/src/es2022/mod.rs
@@ -1,45 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::{- hook_utils::{HookBuilder, NoopHook},- TraverseCtx,-};--mod class_properties;-pub(crate) mod class_static_block;-pub(crate) mod private_property_in_object;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2022Options {- pub class_properties: bool,-- pub class_static_block: bool,-- pub private_property_in_object: bool,-}--impl Es2022Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.class_properties || self.class_static_block || self.private_property_in_object- }-}--pub fn hook(options: Es2022Options) -> impl VisitMutHook<TraverseCtx> {- let hook = HookBuilder::new(NoopHook);-- let hook = hook.chain(if options.class_static_block {- Some(self::class_static_block::hook())- } else {- None- });-- let hook = hook.chain(if options.private_property_in_object {- Some(self::private_property_in_object::hook())- } else {- None- });-- hook.build()-}
deps/swc/crates/swc_ecma_transformer/src/es2022/private_property_in_object.rs
@@ -1,650 +0,0 @@-//! ES2022: Private Property in Object-//!-//! This module transforms `#private in object` expressions into WeakSet-based-//! brand checks.-//!-//! ## Example-//!-//! Input:-//! ```js-//! class Foo {-//! #foo() {}-//! test(other) {-//! return #foo in other;-//! }-//! }-//! ```-//!-//! Output:-//! ```js-//! var _brand_check_foo = new WeakSet();-//! class Foo {-//! constructor() {-//! _brand_check_foo.add(this);-//! }-//! #foo() {}-//! test(other) {-//! return _brand_check_foo.has(other);-//! }-//! }-//! ```-//!-//! ## References-//! * TC39 proposal: <https://github.com/tc39/proposal-private-fields-in-in>--use std::mem::take;--use rustc_hash::FxHashSet;-use swc_atoms::Atom;-use swc_common::{util::take::Take, Mark, Spanned, SyntaxContext, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::{VisitMutHook, VisitMutWithHook};-use swc_ecma_utils::{default_constructor_with_span, private_ident, quote_ident, ExprFactory};-use swc_ecma_visit::{noop_visit_type, Visit, VisitMutWith, VisitWith};--use crate::TraverseCtx;--pub fn hook() -> impl VisitMutHook<TraverseCtx> {- PrivatePropertyInObjectPass::default()-}--pub(crate) fn pass() -> impl Pass {- PrivatePropertyInObjectFastPass-}--struct PrivatePropertyInObjectFastPass;--impl Pass for PrivatePropertyInObjectFastPass {- fn process(&mut self, program: &mut Program) {- let mut finder = PrivateInFinder { found: false };- program.visit_with(&mut finder);-- if finder.found {- program.visit_mut_with(&mut VisitMutWithHook {- hook: PrivatePropertyInObjectPass::default(),- context: TraverseCtx::default(),- });- }- }-}--#[derive(Debug)]-enum Mode {- ClassExpr {- vars: Vec<VarDeclarator>,- init_exprs: Vec<Expr>,- },- ClassDecl {- vars: Vec<VarDeclarator>,- },-}--impl Default for Mode {- fn default() -> Self {- Self::ClassDecl {- vars: Default::default(),- }- }-}--impl Mode {- fn push_var(&mut self, n: Ident, init: Option<Box<Expr>>) {- match self {- Mode::ClassExpr { vars, init_exprs } => {- vars.push(VarDeclarator {- span: DUMMY_SP,- name: n.clone().into(),- init: None,- definite: Default::default(),- });- if let Some(init) = init {- init_exprs.push(- AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: n,- type_ann: None,- })),- right: init,- }- .into(),- );- }- }- Mode::ClassDecl { vars } => {- vars.push(VarDeclarator {- span: DUMMY_SP,- name: n.into(),- init,- definite: Default::default(),- });- }- }- }-}--#[derive(Default)]-struct PrivatePropertyInObjectPass {- vars: Vec<VarDeclarator>,- vars_stack: Vec<Vec<VarDeclarator>>,- prepend_exprs: Vec<Expr>,- prepend_exprs_stack: Vec<Vec<Expr>>,-- injected_vars: FxHashSet<Id>,- cls: ClassData,- cls_stack: Vec<ClassData>,-}--#[derive(Default)]-struct ClassData {- ident: Option<Ident>,-- vars: Mode,-- /// [Mark] for the current class.- ///- /// This is modified by the class visitor.- mark: Mark,-- privates: FxHashSet<Atom>,-- /// Name of private methods.- methods: FxHashSet<Atom>,-- /// Name of private statics.- statics: FxHashSet<Atom>,-- constructor_exprs: Vec<Expr>,-- names_used_for_brand_checks: FxHashSet<Atom>,-}--impl PrivatePropertyInObjectPass {- fn var_name_for_brand_check(&self, n: &PrivateName) -> Ident {- let is_static = self.cls.statics.contains(&n.name);-- let span = n.span;- let ctxt = SyntaxContext::empty().apply_mark(self.cls.mark);-- if !is_static && self.cls.methods.contains(&n.name) {- if let Some(cls_name) = &self.cls.ident {- return Ident::new(format!("_brand_check_{}", cls_name.sym).into(), span, ctxt);- }- }-- Ident::new(format!("_brand_check_{}", n.name).into(), span, ctxt)- }-- fn analyze_class(&mut self, n: &Class) {- n.visit_children_with(&mut ClassAnalyzer {- brand_check_names: &mut self.cls.names_used_for_brand_checks,- ignore_class: true,- });-- for m in &n.body {- match m {- ClassMember::PrivateMethod(m) => {- self.cls.privates.insert(m.key.name.clone());- self.cls.methods.insert(m.key.name.clone());-- if m.is_static {- self.cls.statics.insert(m.key.name.clone());- }- }- ClassMember::PrivateProp(m) => {- self.cls.privates.insert(m.key.name.clone());-- if m.is_static {- self.cls.statics.insert(m.key.name.clone());- }- }- _ => {}- }- }- }-- fn inject_constructor_exprs(&mut self, n: &mut Class) {- if self.cls.constructor_exprs.is_empty() {- return;- }-- let has_constructor = n- .body- .iter()- .any(|m| matches!(m, ClassMember::Constructor(_)));-- if !has_constructor {- let has_super = n.super_class.is_some();- n.body- .push(ClassMember::Constructor(default_constructor_with_span(- has_super, n.span,- )));- }-- for m in &mut n.body {- if let ClassMember::Constructor(Constructor {- body: Some(body), ..- }) = m- {- for expr in take(&mut self.cls.constructor_exprs) {- body.stmts.push(- ExprStmt {- span: DUMMY_SP,- expr: Box::new(expr),- }- .into(),- );- }- }- }- }-}--impl VisitMutHook<TraverseCtx> for PrivatePropertyInObjectPass {- fn enter_class_decl(&mut self, n: &mut ClassDecl, _ctx: &mut TraverseCtx) {- let old_cls = take(&mut self.cls);- self.cls_stack.push(old_cls);-- self.cls.mark = Mark::fresh(Mark::root());- self.cls.ident = Some(n.ident.clone());- self.cls.vars = Mode::ClassDecl {- vars: Default::default(),- };-- self.analyze_class(&n.class);- }-- fn exit_class_decl(&mut self, _n: &mut ClassDecl, _ctx: &mut TraverseCtx) {- match &mut self.cls.vars {- Mode::ClassDecl { vars } => {- self.vars.extend(take(vars));- }- _ => {- unreachable!()- }- }-- self.cls = self.cls_stack.pop().unwrap();- }-- fn enter_class_expr(&mut self, n: &mut ClassExpr, _ctx: &mut TraverseCtx) {- let old_cls = take(&mut self.cls);- self.cls_stack.push(old_cls);-- self.cls.mark = Mark::fresh(Mark::root());- self.cls.ident.clone_from(&n.ident);- self.cls.vars = Mode::ClassExpr {- vars: Default::default(),- init_exprs: Default::default(),- };-- self.analyze_class(&n.class);- }-- fn exit_class_expr(&mut self, _n: &mut ClassExpr, _ctx: &mut TraverseCtx) {- match &mut self.cls.vars {- Mode::ClassExpr { vars, init_exprs } => {- self.vars.extend(take(vars));- self.prepend_exprs.extend(take(init_exprs));- }- _ => {- unreachable!()- }- }-- self.cls = self.cls_stack.pop().unwrap();- }-- fn exit_class(&mut self, n: &mut Class, _ctx: &mut TraverseCtx) {- self.inject_constructor_exprs(n);- }-- fn enter_assign_pat(&mut self, p: &mut AssignPat, _ctx: &mut TraverseCtx) {- // Check if the right side has any private-in expressions- let mut buf = FxHashSet::default();- let mut v = ClassAnalyzer {- brand_check_names: &mut buf,- ignore_class: false,- };- p.right.visit_with(&mut v);-- if !buf.is_empty() {- // Wrap the right side in an IIFE to handle nested classes- let mut bs = BlockStmt {- span: DUMMY_SP,- stmts: Vec::new(),- ..Default::default()- };- bs.stmts.push(- ReturnStmt {- span: DUMMY_SP,- arg: Some(p.right.take()),- }- .into(),- );-- p.right = CallExpr {- span: DUMMY_SP,- callee: ArrowExpr {- span: DUMMY_SP,- params: Default::default(),- body: Box::new(ArrowFunctionBody::FunctionBody(FunctionBody {- span: bs.span,- stmts: bs.stmts,- })),- is_async: false,- is_generator: false,- type_params: Default::default(),- return_type: Default::default(),- ctxt: Default::default(),- }- .as_callee(),- args: Default::default(),- type_args: Default::default(),- ctxt: Default::default(),- }- .into();- }- }-- fn enter_expr(&mut self, _e: &mut Expr, _ctx: &mut TraverseCtx) {- // Save the current prepend_exprs before visiting children- self.prepend_exprs_stack.push(take(&mut self.prepend_exprs));- }-- fn exit_expr(&mut self, e: &mut Expr, _ctx: &mut TraverseCtx) {- // Get accumulated prepend_exprs from children- let mut prepend_exprs = take(&mut self.prepend_exprs);-- // Restore parent's prepend_exprs- self.prepend_exprs = self.prepend_exprs_stack.pop().unwrap();-- // If we have expressions to prepend, wrap in SeqExpr- if !prepend_exprs.is_empty() {- match e {- Expr::Seq(seq) => {- seq.exprs = prepend_exprs- .into_iter()- .map(Box::new)- .chain(seq.exprs.take())- .collect();- }- _ => {- prepend_exprs.push(e.take());- *e = SeqExpr {- span: DUMMY_SP,- exprs: prepend_exprs.into_iter().map(Box::new).collect(),- }- .into();- }- }- return;- }-- // Transform `#private in object` to `WeakSet.has(object)`- match e {- Expr::Bin(BinExpr {- span,- op: op!("in"),- left,- right,- }) if left.is_private_name() => {- let left = left.take().expect_private_name();-- let is_static = self.cls.statics.contains(&left.name);- let is_method = self.cls.methods.contains(&left.name);-- // Optimize: static methods can use simple === comparison- if let Some(cls_ident) = self.cls.ident.clone() {- if is_static && is_method {- *e = BinExpr {- span: *span,- op: op!("==="),- left: cls_ident.into(),- right: right.take(),- }- .into();- return;- }- }-- let var_name = self.var_name_for_brand_check(&left);-- // Create WeakSet if not already created- if self.cls.privates.contains(&left.name)- && self.injected_vars.insert(var_name.to_id())- {- self.cls.vars.push_var(- var_name.clone(),- Some(- NewExpr {- span: DUMMY_SP,- callee: Box::new(quote_ident!("WeakSet").into()),- args: Some(Default::default()),- type_args: Default::default(),- ctxt: Default::default(),- }- .into(),- ),- );-- // For methods, add initialization in constructor- if is_method {- self.cls.constructor_exprs.push(- CallExpr {- span: DUMMY_SP,- callee: var_name- .clone()- .make_member(quote_ident!("add"))- .as_callee(),- args: vec![ExprOrSpread {- spread: None,- expr: Box::new(ThisExpr { span: DUMMY_SP }.into()),- }],- type_args: Default::default(),- ctxt: Default::default(),- }- .into(),- );- }- }-- // Transform to WeakSet.has() call- *e = CallExpr {- span: *span,- callee: var_name.make_member(quote_ident!("has")).as_callee(),- args: vec![ExprOrSpread {- spread: None,- expr: right.take(),- }],- type_args: Default::default(),- ctxt: Default::default(),- }- .into();- }-- _ => {}- }- }-- fn exit_private_prop(&mut self, n: &mut PrivateProp, _ctx: &mut TraverseCtx) {- if !self.cls.names_used_for_brand_checks.contains(&n.key.name) {- return;- }-- let var_name = self.var_name_for_brand_check(&n.key);-- match &mut n.value {- Some(init) => {- let init_span = init.span();-- let tmp = private_ident!("_tmp");-- self.cls.vars.push_var(tmp.clone(), None);-- let assign = AssignExpr {- span: DUMMY_SP,- op: op!("="),- left: AssignTarget::Simple(SimpleAssignTarget::Ident(BindingIdent {- id: tmp.clone(),- type_ann: None,- })),- right: init.take(),- }- .into();-- let add_to_checker = CallExpr {- span: DUMMY_SP,- callee: var_name.make_member(quote_ident!("add")).as_callee(),- args: vec![ExprOrSpread {- spread: None,- expr: Box::new(ThisExpr { span: DUMMY_SP }.into()),- }],- type_args: Default::default(),- ctxt: Default::default(),- }- .into();-- *init = SeqExpr {- span: init_span,- exprs: vec![- Box::new(assign),- Box::new(add_to_checker),- Box::new(tmp.into()),- ],- }- .into();- }- None => {- n.value = Some(- UnaryExpr {- span: DUMMY_SP,- op: op!("void"),- arg: Box::new(- CallExpr {- span: DUMMY_SP,- callee: var_name.make_member(quote_ident!("add")).as_callee(),- args: vec![ExprOrSpread {- spread: None,- expr: Box::new(ThisExpr { span: DUMMY_SP }.into()),- }],- type_args: Default::default(),- ctxt: Default::default(),- }- .into(),- ),- }- .into(),- )- }- }- }-- fn enter_stmts(&mut self, _s: &mut Vec<Stmt>, _ctx: &mut TraverseCtx) {- self.vars_stack.push(take(&mut self.vars));- }-- fn exit_stmts(&mut self, s: &mut Vec<Stmt>, _ctx: &mut TraverseCtx) {- let current_vars = take(&mut self.vars);- self.vars = self.vars_stack.pop().unwrap_or_default();-- if current_vars.is_empty() {- return;- }-- s.insert(- 0,- VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Var,- declare: Default::default(),- decls: current_vars,- ctxt: Default::default(),- }- .into(),- );- }-- fn enter_module_items(&mut self, _items: &mut Vec<ModuleItem>, _ctx: &mut TraverseCtx) {- self.vars_stack.push(take(&mut self.vars));- }-- fn exit_module_items(&mut self, items: &mut Vec<ModuleItem>, _ctx: &mut TraverseCtx) {- let current_vars = take(&mut self.vars);- self.vars = self.vars_stack.pop().unwrap_or_default();-- if current_vars.is_empty() {- return;- }-- items.insert(- 0,- VarDecl {- span: DUMMY_SP,- kind: VarDeclKind::Var,- declare: Default::default(),- decls: current_vars,- ctxt: Default::default(),- }- .into(),- );- }-}--struct PrivateInFinder {- found: bool,-}--impl Visit for PrivateInFinder {- noop_visit_type!(fail);-- fn visit_expr(&mut self, node: &Expr) {- if self.found {- return;- }-- node.visit_children_with(self);- }-- fn visit_bin_expr(&mut self, node: &BinExpr) {- if self.found {- return;- }-- if node.op == op!("in") && node.left.is_private_name() {- self.found = true;- return;- }-- node.visit_children_with(self);- }-}--struct ClassAnalyzer<'a> {- brand_check_names: &'a mut FxHashSet<Atom>,- ignore_class: bool,-}--impl Visit for ClassAnalyzer<'_> {- noop_visit_type!(fail);-- fn visit_bin_expr(&mut self, n: &BinExpr) {- n.visit_children_with(self);-- if n.op == op!("in") {- if let Expr::PrivateName(left) = &*n.left {- self.brand_check_names.insert(left.name.clone());- }- }- }-- /// Noop- fn visit_class(&mut self, n: &Class) {- if self.ignore_class {- return;- }-- n.visit_children_with(self);- }-}
deps/swc/crates/swc_ecma_transformer/src/es2026/mod.rs
@@ -1,25 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es2026Options {}--impl Es2026Options {- /// Returns true if any transform is enabled.- /// Currently no transforms are available for ES2026.- pub fn is_enabled(&self) -> bool {- false- }-}--pub fn hook(options: Es2026Options) -> impl VisitMutHook<TraverseCtx> {- Es2026Pass { options }-}--struct Es2026Pass {- options: Es2026Options,-}--impl VisitMutHook<TraverseCtx> for Es2026Pass {}
deps/swc/crates/swc_ecma_transformer/src/es3/member_expr_lits.rs
@@ -1,55 +0,0 @@-//! babel: `transform-member-expression-literals`-//!-//! # Input-//! ```js-//! obj["foo"] = "isValid";-//!-//! obj.const = "isKeyword";-//! obj["var"] = "isKeyword";-//! ```-//!-//! # Output-//! ```js-//! obj.foo = "isValid";-//!-//! obj["const"] = "isKeyword";-//! obj["var"] = "isKeyword";-//! ```--use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::is_valid_ident;--use crate::TraverseCtx;--/// Creates a member expression literals transformation hook.-pub(crate) fn hook() -> impl VisitMutHook<TraverseCtx> {- MemberExprLitHook-}--struct MemberExprLitHook;--impl VisitMutHook<TraverseCtx> for MemberExprLitHook {- fn exit_member_expr(&mut self, e: &mut MemberExpr, _ctx: &mut TraverseCtx) {- if let MemberProp::Ident(i) = &e.prop {- if i.sym.is_reserved()- || i.sym.is_reserved_in_strict_mode(true)- || i.sym.is_reserved_in_es3()- // it's not bind, so you could use eval- || !is_valid_ident(&i.sym)- {- e.prop = MemberProp::Computed(ComputedPropName {- span: i.span,- expr: Lit::Str(Str {- span: i.span,- raw: None,- value: i.sym.clone().into(),- })- .into(),- });- } else {- e.prop = MemberProp::Ident(IdentName::new(i.sym.clone(), i.span));- }- }- }-}
deps/swc/crates/swc_ecma_transformer/src/es3/mod.rs
@@ -1,78 +0,0 @@-//! ES3 compatibility transforms.-//!-//! This module provides transforms for making JavaScript code compatible with-//! ES3 environments.--use swc_ecma_hooks::VisitMutHook;--use crate::{- hook_utils::{HookBuilder, NoopHook},- TraverseCtx,-};--mod member_expr_lits;-mod prop_lits;-mod reserved_word;--pub use reserved_word::ReservedWordContext;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Es3Options {- /// Enable property literals transformation- ///- /// Transforms property names from strings to identifiers where possible:- /// `{ "bar": 1 }` -> `{ bar: 1 }`- pub property_literals: bool,-- /// Enable member expression literals transformation- ///- /// Transforms member expressions with reserved/invalid identifiers:- /// `obj.const` -> `obj["const"]`- pub member_expression_literals: bool,-- /// Enable reserved words transformation- ///- /// Renames ES3 reserved words used as identifiers:- /// `var abstract = 1` -> `var _abstract = 1`- pub reserved_words: bool,-- /// Preserve `import` identifier without renaming.- ///- /// Only used when `reserved_words` is true.- pub preserve_import: bool,-}--impl Es3Options {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.property_literals || self.member_expression_literals || self.reserved_words- }-}--pub fn hook(options: Es3Options) -> impl VisitMutHook<TraverseCtx> {- let hook = HookBuilder::new(NoopHook);-- // Member expression literals: obj.const -> obj["const"]- let hook = hook.chain(if options.member_expression_literals {- Some(self::member_expr_lits::hook())- } else {- None- });-- // Property literals: { "bar": 1 } -> { bar: 1 }- let hook = hook.chain(if options.property_literals {- Some(self::prop_lits::hook())- } else {- None- });-- // Reserved words: var abstract = 1 -> var _abstract = 1- let hook = hook.chain(if options.reserved_words {- Some(self::reserved_word::hook(options.preserve_import))- } else {- None- });-- hook.build()-}
deps/swc/crates/swc_ecma_transformer/src/es3/prop_lits.rs
@@ -1,75 +0,0 @@-//! babel: `transform-property-literals`-//!-//! # Input-//! ```js-//! var foo = {-//! // changed-//! "bar": function () {},-//! "1": function () {},-//!-//! // not changed-//! "default": 1,-//! [a]: 2,-//! foo: 1-//! };-//! ```-//!-//! # Output-//! ```js-//! var foo = {-//! bar: function () {},-//! 1: function () {},-//!-//! "default": 1,-//! [a]: 2,-//! foo: 1-//! };-//! ```--use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_utils::{is_valid_ident, swc_atoms::Atom};--use crate::TraverseCtx;--/// Creates a property literals transformation hook.-pub(crate) fn hook() -> impl VisitMutHook<TraverseCtx> {- PropertyLiteralHook-}--struct PropertyLiteralHook;--impl VisitMutHook<TraverseCtx> for PropertyLiteralHook {- fn exit_prop_name(&mut self, n: &mut PropName, _ctx: &mut TraverseCtx) {- match n {- PropName::Str(Str {- raw: _,- value,- span,- ..- }) if value.as_str().is_some() => {- let v = value.as_str().unwrap();- if v.is_reserved() || !is_valid_ident(v) {- // Keep as is- } else {- *n = PropName::Ident(IdentName::new(- // SAFETY: checked above- unsafe { Atom::from_wtf8_unchecked(value.clone()) },- *span,- ));- }- }- PropName::Ident(i) => {- let IdentName { sym, span, .. } = i;- if sym.is_reserved() || sym.contains('-') || sym.contains('.') {- *n = PropName::Str(Str {- span: *span,- raw: None,- value: sym.clone().into(),- });- }- }- _ => {}- }- }-}
deps/swc/crates/swc_ecma_transformer/src/es3/reserved_word.rs
@@ -1,305 +0,0 @@-//! babel: `@babel/plugin-transform-reserved-words`-//!-//! Some words were reserved in ES3 as potential future keywords but were not-//! reserved in ES5 and later. This plugin, to be used when targeting ES3-//! environments, renames variables from that set of words.-//!-//! # Input-//! ```js-//! var abstract = 1;-//! var x = abstract + 1;-//! ```-//!-//! # Output-//! ```js-//! var _abstract = 1;-//! var x = _abstract + 1;-//! ```--use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--/// Context for tracking when to skip identifier transformation.-#[derive(Default)]-pub struct ReservedWordContext {- /// Skip transforming identifiers when inside these contexts- skip_depth: u32,- /// Skip transforming identifiers in named exports with source- in_named_export_with_src: bool,- /// Skip transforming the `imported` field in import specifiers- skip_imported: bool,- /// Track how many ModuleExportNames we've seen in the current export- /// specifier to skip the exported (second one) but not the orig (first- /// one)- export_specifier_module_export_name_count: u32,- /// Whether we're in an export specifier with a reserved orig- in_reserved_export_specifier: bool,-}--/// Creates a reserved words transformation hook.-pub(crate) fn hook(preserve_import: bool) -> impl VisitMutHook<TraverseCtx> {- ReservedWordHook { preserve_import }-}--struct ReservedWordHook {- preserve_import: bool,-}--impl VisitMutHook<TraverseCtx> for ReservedWordHook {- // Skip transforming identifiers in member expression properties- fn enter_member_prop(&mut self, _n: &mut MemberProp, ctx: &mut TraverseCtx) {- ctx.es3.skip_depth += 1;- }-- fn exit_member_prop(&mut self, _n: &mut MemberProp, ctx: &mut TraverseCtx) {- ctx.es3.skip_depth -= 1;- }-- // Skip transforming identifiers in property names- fn enter_prop_name(&mut self, _n: &mut PropName, ctx: &mut TraverseCtx) {- ctx.es3.skip_depth += 1;- }-- fn exit_prop_name(&mut self, _n: &mut PropName, ctx: &mut TraverseCtx) {- ctx.es3.skip_depth -= 1;- }-- // Track when we're in a named export with source (re-export)- fn enter_named_export(&mut self, n: &mut NamedExport, ctx: &mut TraverseCtx) {- if n.src.is_some() {- ctx.es3.in_named_export_with_src = true;- ctx.es3.skip_depth += 1;- }- }-- fn exit_named_export(&mut self, n: &mut NamedExport, ctx: &mut TraverseCtx) {- if n.src.is_some() {- ctx.es3.in_named_export_with_src = false;- ctx.es3.skip_depth -= 1;- }- }-- // Handle import specifiers specially - set imported before the ident is visited- fn enter_import_named_specifier(- &mut self,- s: &mut ImportNamedSpecifier,- ctx: &mut TraverseCtx,- ) {- // Preserve the original imported name if the local is reserved- if s.local.is_reserved_in_es3() && s.imported.is_none() {- s.imported = Some(s.local.clone().into());- }- // Mark that we should skip the imported field (the ModuleExportName)- ctx.es3.skip_imported = true;- }-- fn exit_import_named_specifier(- &mut self,- _s: &mut ImportNamedSpecifier,- ctx: &mut TraverseCtx,- ) {- ctx.es3.skip_imported = false;- }-- // Handle export specifiers specially - set exported before the ident is visited- fn enter_export_named_specifier(- &mut self,- n: &mut ExportNamedSpecifier,- ctx: &mut TraverseCtx,- ) {- // Don't transform in re-exports- if ctx.es3.in_named_export_with_src {- return;- }-- // Check if orig is reserved- let orig_is_reserved =- matches!(&n.orig, ModuleExportName::Ident(ident) if ident.is_reserved_in_es3());-- // Check if exported is reserved (for specifiers we created in- // enter_module_items)- let exported_is_reserved = matches!(- &n.exported,- Some(ModuleExportName::Ident(ident)) if ident.is_reserved_in_es3()- );-- if orig_is_reserved && n.exported.is_none() {- n.exported = Some(n.orig.clone());- }-- // If either orig or exported contains a reserved word, we need to skip the- // exported field- if orig_is_reserved || exported_is_reserved {- ctx.es3.in_reserved_export_specifier = true;- ctx.es3.export_specifier_module_export_name_count = 0;- }- }-- fn exit_export_named_specifier(- &mut self,- _n: &mut ExportNamedSpecifier,- ctx: &mut TraverseCtx,- ) {- // Reset state- ctx.es3.in_reserved_export_specifier = false;- ctx.es3.export_specifier_module_export_name_count = 0;- }-- // Track ModuleExportName visits within export specifiers to skip the second one- // (exported)- fn enter_module_export_name(&mut self, _n: &mut ModuleExportName, ctx: &mut TraverseCtx) {- // Handle import specifiers - skip the imported field- if ctx.es3.skip_imported {- ctx.es3.skip_depth += 1;- return;- }-- // Handle export specifiers - skip the second ModuleExportName (exported)- if ctx.es3.in_reserved_export_specifier {- ctx.es3.export_specifier_module_export_name_count += 1;- // The second ModuleExportName is the exported field - skip it- if ctx.es3.export_specifier_module_export_name_count == 2 {- ctx.es3.skip_depth += 1;- }- }- }-- fn exit_module_export_name(&mut self, _n: &mut ModuleExportName, ctx: &mut TraverseCtx) {- // Handle import specifiers- if ctx.es3.skip_imported {- ctx.es3.skip_depth -= 1;- return;- }-- // Handle export specifiers - only decrement if we incremented- if ctx.es3.in_reserved_export_specifier- && ctx.es3.export_specifier_module_export_name_count == 2- {- ctx.es3.skip_depth -= 1;- }- }-- fn exit_ident(&mut self, i: &mut Ident, ctx: &mut TraverseCtx) {- // Skip if we're in a context where identifiers shouldn't be transformed- if ctx.es3.skip_depth > 0 {- return;- }-- if self.preserve_import && i.sym == *"import" {- return;- }-- if i.is_reserved_in_es3() {- i.sym = format!("_{}", i.sym).into()- }- }-- // Use enter_module_items to process BEFORE children are visited- fn enter_module_items(&mut self, n: &mut Vec<ModuleItem>, _ctx: &mut TraverseCtx) {- let mut extra_exports = Vec::new();-- for module_item in n.iter_mut() {- match module_item {- ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {- decl: decl @ Decl::Fn(..) | decl @ Decl::Class(..),- ..- })) => {- let ident = match decl {- Decl::Class(d) => d.ident.clone(),- Decl::Fn(d) => d.ident.clone(),- _ => {- unreachable!()- }- };-- if ident.is_reserved_in_es3() {- // Take the declaration out and make it a regular statement- let new_decl = decl.take();- *module_item = new_decl.into();-- // Create the renamed identifier- let mut orig = ident.clone();- rename_reserved_ident(&mut orig, self.preserve_import);-- // Add an export with the original name as the exported name- extra_exports.push(- ExportNamedSpecifier {- span: DUMMY_SP,- orig: orig.into(),- exported: Some(ident.into()),- is_type_only: false,- }- .into(),- );- }- }-- ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {- decl: Decl::Var(var),- ..- })) => {- // Check if any variable name is a reserved word- let has_reserved = var.decls.iter().any(|v| {- if let Pat::Ident(i) = &v.name {- i.sym.is_reserved_in_es3()- } else {- false- }- });-- if has_reserved {- for v in &var.decls {- let ident = Ident::from(v.name.clone().expect_ident());-- if ident.is_reserved_in_es3() {- let mut orig = ident.clone();- rename_reserved_ident(&mut orig, self.preserve_import);-- extra_exports.push(- ExportNamedSpecifier {- span: DUMMY_SP,- orig: orig.into(),- exported: Some(ident.into()),- is_type_only: false,- }- .into(),- );- }- }-- *module_item = var.take().into();- }- }-- _ => {}- }- }-- if !extra_exports.is_empty() {- let module_item = NamedExport {- span: DUMMY_SP,- specifiers: extra_exports,- src: None,- type_only: false,- with: None,- }- .into();-- n.push(module_item);- }- }-}--/// Renames an identifier if it's a reserved word in ES3.-fn rename_reserved_ident(i: &mut Ident, preserve_import: bool) {- if preserve_import && i.sym == *"import" {- return;- }-- if i.is_reserved_in_es3() {- i.sym = format!("_{}", i.sym).into()- }-}
deps/swc/crates/swc_ecma_transformer/src/hook_utils.rs
@@ -1,175 +0,0 @@-use swc_ecma_ast::*;-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--macro_rules! chained_method {- ($enter_name:ident, $exit_name:ident, $T:ty) => {- #[inline]- fn $enter_name(&mut self, node: &mut $T, ctx: &mut TraverseCtx) {- self.0.$enter_name(node, ctx);- self.1.$enter_name(node, ctx);- }-- #[inline]- fn $exit_name(&mut self, node: &mut $T, ctx: &mut TraverseCtx) {- self.0.$exit_name(node, ctx);- self.1.$exit_name(node, ctx);- }- };-}--/// Execution order: A => B (both for enter and exit)-pub(crate) struct OrderedChain<A, B>(pub A, pub B)-where- A: VisitMutHook<TraverseCtx>,- B: VisitMutHook<TraverseCtx>;--impl<A, B> VisitMutHook<TraverseCtx> for OrderedChain<A, B>-where- A: VisitMutHook<TraverseCtx>,- B: VisitMutHook<TraverseCtx>,-{- chained_method!(enter_expr, exit_expr, Expr);-- chained_method!(enter_expr_stmt, exit_expr_stmt, ExprStmt);-- chained_method!(enter_pat, exit_pat, Pat);-- chained_method!(enter_stmt, exit_stmt, Stmt);-- chained_method!(enter_stmts, exit_stmts, Vec<Stmt>);-- chained_method!(enter_block_stmt, exit_block_stmt, BlockStmt);-- chained_method!(- enter_arrow_function_body,- exit_arrow_function_body,- ArrowFunctionBody- );-- chained_method!(enter_module_item, exit_module_item, ModuleItem);-- chained_method!(enter_module_items, exit_module_items, Vec<ModuleItem>);-- chained_method!(enter_module, exit_module, Module);-- chained_method!(enter_script, exit_script, Script);-- chained_method!(enter_program, exit_program, Program);-- chained_method!(enter_catch_clause, exit_catch_clause, CatchClause);-- chained_method!(enter_function, exit_function, Function);-- chained_method!(enter_arrow_expr, exit_arrow_expr, ArrowExpr);-- chained_method!(enter_class, exit_class, Class);-- chained_method!(enter_constructor, exit_constructor, Constructor);-- chained_method!(enter_getter_prop, exit_getter_prop, GetterProp);-- chained_method!(enter_setter_prop, exit_setter_prop, SetterProp);-- chained_method!(enter_super, exit_super, Super);-- chained_method!(enter_var_decl, exit_var_decl, VarDecl);-- chained_method!(enter_for_in_stmt, exit_for_in_stmt, ForInStmt);-- chained_method!(enter_for_of_stmt, exit_for_of_stmt, ForOfStmt);-- chained_method!(enter_class_decl, exit_class_decl, ClassDecl);-- chained_method!(enter_class_expr, exit_class_expr, ClassExpr);-- chained_method!(enter_assign_pat, exit_assign_pat, AssignPat);-- chained_method!(enter_private_prop, exit_private_prop, PrivateProp);-- chained_method!(enter_prop, exit_prop, Prop);-- chained_method!(enter_assign_expr, exit_assign_expr, AssignExpr);-- chained_method!(enter_key_value_prop, exit_key_value_prop, KeyValueProp);-- chained_method!(enter_var_declarator, exit_var_declarator, VarDeclarator);-- chained_method!(enter_bin_expr, exit_bin_expr, BinExpr);-- chained_method!(enter_fn_decl, exit_fn_decl, FnDecl);-- // ES3 hooks: member expression literals- chained_method!(enter_member_expr, exit_member_expr, MemberExpr);-- // ES3 hooks: property literals- chained_method!(enter_prop_name, exit_prop_name, PropName);-- // ES3 hooks: reserved words - identifier handling- chained_method!(enter_ident, exit_ident, Ident);-- // ES3 hooks: reserved words - member property handling- chained_method!(enter_member_prop, exit_member_prop, MemberProp);-- // ES3 hooks: reserved words - export/import handling- chained_method!(enter_named_export, exit_named_export, NamedExport);-- chained_method!(- enter_import_named_specifier,- exit_import_named_specifier,- ImportNamedSpecifier- );-- chained_method!(- enter_export_named_specifier,- exit_export_named_specifier,- ExportNamedSpecifier- );-- chained_method!(- enter_module_export_name,- exit_module_export_name,- ModuleExportName- );-}--pub(crate) struct NoopHook;--impl VisitMutHook<TraverseCtx> for NoopHook {}--pub(crate) struct HookBuilder<H>-where- H: VisitMutHook<TraverseCtx>,-{- hook: H,-}--impl<H> HookBuilder<H>-where- H: VisitMutHook<TraverseCtx>,-{- pub fn new(hook: H) -> Self {- Self { hook }- }-- pub fn chain<B>(self, hook: B) -> HookBuilder<impl VisitMutHook<TraverseCtx>>- where- B: VisitMutHook<TraverseCtx>,- {- HookBuilder {- hook: OrderedChain(self.hook, hook),- }- }-- pub fn chain_optional<B>(self, hook: Option<B>) -> HookBuilder<impl VisitMutHook<TraverseCtx>>- where- B: VisitMutHook<TraverseCtx>,- {- self.chain(hook)- }-- pub fn build(self) -> impl VisitMutHook<TraverseCtx> {- self.hook- }-}
deps/swc/crates/swc_ecma_transformer/src/jsx/mod.rs
@@ -1,17 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct JsxOptions {}--pub fn hook(options: JsxOptions) -> impl VisitMutHook<TraverseCtx> {- JsxPass { options }-}--struct JsxPass {- options: JsxOptions,-}--impl VisitMutHook<TraverseCtx> for JsxPass {}
deps/swc/crates/swc_ecma_transformer/src/lib.rs
@@ -1,248 +0,0 @@-#![allow(dead_code)]--use swc_ecma_ast::*;-use swc_ecma_hooks::{VisitMutHook, VisitMutWithHook};-use swc_ecma_transforms_base::assumptions::Assumptions;-use swc_ecma_visit::visit_mut_pass;--use crate::hook_utils::{HookBuilder, NoopHook};-pub use crate::options::*;--mod bugfix;-mod common;-mod decorators;-mod es2015;-mod es2016;-mod es2017;-mod es2018;-mod es2019;-mod es2020;-mod es2021;-mod es2022;-mod es2026;-#[cfg(feature = "es3")]-mod es3;-mod hook_utils;-mod jsx;-mod options;-mod regexp;-mod typescript;-mod utils;--#[derive(Default)]-pub struct TraverseCtx {- pub(crate) statement_injector: common::StmtInjectorStore,- pub(crate) var_declarations: common::VarDeclarationsStore,- #[cfg(feature = "es3")]- pub(crate) es3: es3::ReservedWordContext,-}--pub fn transform_hook(options: Options) -> impl VisitMutHook<TraverseCtx> {- let needs_var_declarations = options.env.es2021.logical_assignment_operators- || options.env.es2020.nullish_coalescing- || options.env.es2018.object_rest_spread- || options.env.es2016.exponentiation_operator;-- let hook = HookBuilder::new(NoopHook);-- let hook = hook.chain_optional(options.typescript.map(crate::typescript::hook));- let hook = hook.chain_optional(options.decorator.map(crate::decorators::hook));- let hook = hook.chain_optional(options.jsx.map(crate::jsx::hook));-- let hook = hook.chain(crate::es2026::hook(options.env.es2026));- let hook = hook.chain(crate::es2022::hook(options.env.es2022));- let hook = hook.chain(crate::es2021::hook(options.env.es2021));- let hook = hook.chain(crate::es2020::hook(options.env.es2020, options.assumptions));- let hook = hook.chain(crate::es2019::hook(options.env.es2019));- let hook = hook.chain(crate::es2018::hook(options.env.es2018, options.assumptions));- let hook = hook.chain(crate::es2017::hook(- options.env.es2017,- options.unresolved_ctxt,- options.assumptions.ignore_function_length,- ));- let hook = hook.chain(crate::es2016::hook(options.env.es2016));- let hook = hook.chain(crate::es2015::hook(options.env.es2015));- let hook = hook.chain_optional(crate::regexp::hook(options.env.regexp));- let hook = hook.chain(crate::bugfix::hook(options.env.bugfix));-- // ES3 transforms should run after all higher ES versions- #[cfg(feature = "es3")]- let hook = hook.chain(crate::es3::hook(options.env.es3));-- // VarDeclarations must run after all transforms that may queue generated- // declarations. Most transformer passes do not need it, and keeping it in- // the hook chain for those passes only pushes/pops empty declaration scopes.- let hook = hook.chain(if needs_var_declarations {- Some(common::VarDeclarations::default())- } else {- None- });-- hook.build()-}--pub fn hook_pass<H: VisitMutHook<TraverseCtx>>(hook: H) -> impl Pass {- let ctx = TraverseCtx::default();-- visit_mut_pass(VisitMutWithHook { hook, context: ctx })-}--fn hook_pass_with_var_declarations<H: VisitMutHook<TraverseCtx>>(hook: H) -> impl Pass {- hook_pass(- HookBuilder::new(hook)- .chain(common::VarDeclarations::default())- .build(),- )-}--struct OptionalPass<P> {- pass: P,- enabled: bool,-}--impl<P> Pass for OptionalPass<P>-where- P: Pass,-{- fn process(&mut self, program: &mut Program) {- if self.enabled {- self.pass.process(program);- }- }-}--pub fn es2022_static_blocks() -> impl Pass {- hook_pass(crate::es2022::class_static_block::hook())-}--pub fn es2022_private_in_object() -> impl Pass {- crate::es2022::private_property_in_object::pass()-}--pub fn es2022_runtime_transforms(regexp_options: crate::regexp::RegExpOptions) -> impl Pass {- (- hook_pass(- HookBuilder::new(NoopHook)- .chain(crate::es2022::class_static_block::hook())- .chain_optional(crate::regexp::hook(regexp_options))- .build(),- ),- crate::es2022::private_property_in_object::pass(),- )-}--pub fn es2021_logical_assignments() -> impl Pass {- hook_pass_with_var_declarations(crate::es2021::logical_assignment_operators::hook())-}--pub fn es2020_export_namespace_from() -> impl Pass {- crate::es2020::export_namespace_from::pass()-}--pub fn es2020_nullish_coalescing(no_document_all: bool) -> impl Pass {- hook_pass_with_var_declarations(crate::es2020::nullish_coalescing::hook(no_document_all))-}--pub fn es2020_runtime_transforms(no_document_all: bool) -> impl Pass {- hook_pass_with_var_declarations(- HookBuilder::new(NoopHook)- .chain(crate::es2020::export_namespace_from::hook())- .chain(crate::es2020::nullish_coalescing::hook(no_document_all))- .build(),- )-}--pub fn es2019_optional_catch_binding() -> impl Pass {- crate::es2019::optional_catch_binding::pass()-}--pub fn es2018_object_rest_spread(assumptions: Assumptions) -> impl Pass {- hook_pass_with_var_declarations(crate::es2018::object_rest_spread::hook(assumptions))-}--pub fn es2018_runtime_transforms(- assumptions: Assumptions,- regexp_options: crate::regexp::RegExpOptions,-) -> impl Pass {- hook_pass_with_var_declarations(- HookBuilder::new(NoopHook)- .chain(crate::es2018::object_rest_spread::hook(assumptions))- .chain_optional(crate::regexp::hook(regexp_options))- .build(),- )-}--pub fn es2017_async_to_generator(- unresolved_ctxt: swc_common::SyntaxContext,- ignore_function_length: bool,-) -> impl Pass {- hook_pass(crate::es2017::async_to_generator::hook(- true,- true,- unresolved_ctxt,- ignore_function_length,- ))-}--pub fn es2016_exponentiation() -> impl Pass {- hook_pass_with_var_declarations(crate::es2016::exponentiation_operator::hook())-}--pub fn es2015_shorthand() -> impl Pass {- hook_pass(crate::es2015::shorthand::hook())-}--pub fn es2015_function_name() -> impl Pass {- hook_pass(crate::es2015::function_name::hook())-}--pub fn es2015_duplicate_keys() -> impl Pass {- hook_pass(crate::es2015::duplicate_keys::hook())-}--pub fn es2015_sticky_regex() -> impl Pass {- regexp_pass(crate::regexp::RegExpOptions {- sticky_regex: true,- ..Default::default()- })-}--pub fn es2015_instanceof() -> impl Pass {- hook_pass(crate::es2015::instanceof::hook())-}--pub fn es2015_typeof_symbol() -> impl Pass {- hook_pass(crate::es2015::typeof_symbol::hook())-}--pub fn es2015_runtime_transforms() -> impl Pass {- hook_pass(- HookBuilder::new(NoopHook)- .chain(crate::es2015::shorthand::hook())- .chain(crate::es2015::duplicate_keys::hook())- .chain(crate::es2015::instanceof::hook())- .chain(crate::es2015::typeof_symbol::hook())- .chain_optional(crate::regexp::hook(crate::regexp::RegExpOptions {- sticky_regex: true,- ..Default::default()- }))- .build(),- )-}--pub fn regexp_pass(options: crate::regexp::RegExpOptions) -> impl Pass {- let enabled = options.is_enabled();-- OptionalPass {- pass: crate::regexp::pass(options),- enabled,- }-}--impl Options {- pub fn into_pass(self) -> impl Pass {- let hook = transform_hook(self);-- hook_pass(hook)- }-}
deps/swc/crates/swc_ecma_transformer/src/options/mod.rs
@@ -1,67 +0,0 @@-use swc_common::SyntaxContext;-use swc_ecma_transforms_base::assumptions::Assumptions;--#[cfg(feature = "es3")]-pub use crate::es3::Es3Options;-pub use crate::{- bugfix::BugfixOptions, decorators::DecoratorOptions, es2015::Es2015Options,- es2016::Es2016Options, es2017::Es2017Options, es2018::Es2018Options, es2019::Es2019Options,- es2020::Es2020Options, es2021::Es2021Options, es2022::Es2022Options, es2026::Es2026Options,- jsx::JsxOptions, regexp::RegExpOptions, typescript::TypescriptOptions,-};--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct Options {- pub unresolved_ctxt: SyntaxContext,- pub assumptions: Assumptions,-- pub typescript: Option<TypescriptOptions>,- pub decorator: Option<DecoratorOptions>,- pub jsx: Option<JsxOptions>,-- pub env: EnvOptions,-}--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct EnvOptions {- pub es2026: Es2026Options,- pub es2022: Es2022Options,- pub es2021: Es2021Options,- pub es2020: Es2020Options,- pub es2019: Es2019Options,- pub es2018: Es2018Options,- pub es2017: Es2017Options,- pub es2016: Es2016Options,- pub es2015: Es2015Options,- pub regexp: RegExpOptions,- pub bugfix: BugfixOptions,- #[cfg(feature = "es3")]- pub es3: Es3Options,-}--impl EnvOptions {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- #[allow(unused_mut)]- let mut enabled = self.es2026.is_enabled()- || self.es2022.is_enabled()- || self.es2021.is_enabled()- || self.es2020.is_enabled()- || self.es2019.is_enabled()- || self.es2018.is_enabled()- || self.es2017.is_enabled()- || self.es2016.is_enabled()- || self.es2015.is_enabled()- || self.regexp.is_enabled()- || self.bugfix.is_enabled();-- #[cfg(feature = "es3")]- {- enabled = enabled || self.es3.is_enabled();- }-- enabled- }-}
deps/swc/crates/swc_ecma_transformer/src/regexp.rs
@@ -1,435 +0,0 @@-use swc_atoms::Atom;-use swc_common::{util::take::Take, DUMMY_SP};-use swc_ecma_ast::*;-use swc_ecma_compat_regexp::transform_unicode_property_escapes;-use swc_ecma_hooks::VisitMutHook;-use swc_ecma_regexp::{- ast::{Disjunction, IndexedReference, Term},- LiteralParser, Options as RegexpOptions,-};-use swc_ecma_transforms_base::helper;-use swc_ecma_utils::{quote_ident, ExprFactory};-use swc_ecma_visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith};--use crate::TraverseCtx;--/// If true, the syntax will be transformed.-#[derive(Debug, Default)]-#[non_exhaustive]-pub struct RegExpOptions {- /// [s/dotAll flag for regular expressions](https://tc39.github.io/proposal-regexp-dotall-flag/)- pub dot_all_regex: bool,- /// [RegExp.prototype.hasIndices](https://262.ecma-international.org/13.0/#sec-get-regexp.prototype.hasIndices)- pub has_indices: bool,- /// [RegExp Lookbehind Assertions](https://tc39.es/proposal-regexp-lookbehind/)- pub lookbehind_assertion: bool,- /// [Named capture groups in regular expressions](https://tc39.es/proposal-regexp-named-groups/)- pub named_capturing_groups_regex: bool,- /// [RegExp.prototype.sticky](https://tc39.es/ecma262/multipage/text-processing.html#sec-get-regexp.prototype.sticky)- pub sticky_regex: bool,- /// [Unicode property escapes in regular expressions](https://tc39.es/proposal-regexp-unicode-property-escapes/)- pub unicode_property_regex: bool,- /// [RegExp.prototype.unicode](https://tc39.es/ecma262/multipage/text-processing.html#sec-get-regexp.prototype.unicode)- pub unicode_regex: bool,- // [RegExp.prototype.unicodeSets](https://github.com/tc39/proposal-regexp-v-flag)- pub unicode_sets_regex: bool,-}--impl RegExpOptions {- /// Returns true if any transform is enabled.- pub fn is_enabled(&self) -> bool {- self.dot_all_regex- || self.has_indices- || self.lookbehind_assertion- || self.named_capturing_groups_regex- || self.sticky_regex- || self.unicode_property_regex- || self.unicode_regex- || self.unicode_sets_regex- }-}--pub(crate) fn hook(options: RegExpOptions) -> Option<impl VisitMutHook<TraverseCtx>> {- if options.dot_all_regex- || options.has_indices- || options.lookbehind_assertion- || options.named_capturing_groups_regex- || options.sticky_regex- || options.unicode_property_regex- || options.unicode_regex- || options.unicode_sets_regex- {- Some(RegexpPass { options })- } else {- None- }-}--pub(crate) fn pass(options: RegExpOptions) -> impl Pass {- visit_mut_pass(RegexpPass { options })-}--struct RegexpPass {- options: RegExpOptions,-}--impl RegexpPass {- /// Transform the regex pattern if it contains unicode property escapes.- /// Returns the transformed pattern string.- fn transform_pattern(&self, pattern: &str, flags: &str) -> Option<String> {- // Only transform if unicode_property_regex is enabled and pattern contains- // \p{ or \P{- if !self.options.unicode_property_regex {- return None;- }- if !pattern.contains("\\p{") && !pattern.contains("\\P{") {- return None;- }-- // Parse the regex pattern- let mut ast = LiteralParser::new(pattern, Some(flags), RegexpOptions::default())- .parse()- .ok()?;-- // Transform unicode property escapes- transform_unicode_property_escapes(&mut ast);-- // Serialize back to string- Some(ast.to_string())- }-- fn transform_regexp_args(&self, args: &mut [ExprOrSpread]) {- if !self.options.unicode_property_regex {- return;- }-- let Some((pattern_arg, rest_args)) = args.split_first_mut() else {- return;- };- if pattern_arg.spread.is_some() {- return;- }-- let Expr::Lit(Lit::Str(pattern_lit)) = &*pattern_arg.expr else {- return;- };- let Some(pattern) = pattern_lit.value.as_str() else {- return;- };-- let flags = match rest_args.first() {- Some(flags_arg) => {- if flags_arg.spread.is_some() {- return;- }-- let Expr::Lit(Lit::Str(flags_lit)) = &*flags_arg.expr else {- return;- };- let Some(flags) = flags_lit.value.as_str() else {- return;- };-- flags- }- None => "",- };-- if !flags.contains(['u', 'v']) {- return;- }-- let Some(transformed_pattern) = self.transform_pattern(pattern, flags) else {- return;- };-- let Expr::Lit(Lit::Str(pattern_lit)) = &mut *pattern_arg.expr else {- return;- };- pattern_lit.value = transformed_pattern.into();- pattern_lit.raw = None;- }-- /// Parse a regex pattern, extract named capturing groups, strip them,- /// convert named backreferences to indexed ones, and return the stripped- /// pattern string along with the name-to-index mapping.- ///- /// Returns `None` if parsing fails or if there are no named groups.- fn extract_and_strip_named_groups(- &self,- pattern: &str,- flags: &str,- ) -> Option<(String, Vec<(Atom, u32)>)> {- let mut ast = LiteralParser::new(pattern, Some(flags), RegexpOptions::default())- .parse()- .ok()?;-- // First pass: collect all named capturing groups and their indices- let mut mapping = Vec::new();- let mut counter = 0u32;- collect_named_groups(&ast.body, &mut counter, &mut mapping);-- if mapping.is_empty() {- return None;- }-- // Second pass: strip names from groups and convert named references- strip_named_groups(&mut ast.body, &mapping);-- Some((ast.to_string(), mapping))- }-- /// Check if non-named-group transforms require converting to RegExp()- /// constructor.- fn needs_regexp_constructor(&self, pattern: &str, flags: &str) -> bool {- (self.options.dot_all_regex && flags.contains('s'))- || (self.options.sticky_regex && flags.contains('y'))- || (self.options.unicode_regex && flags.contains('u'))- || (self.options.unicode_sets_regex && flags.contains('v'))- || (self.options.has_indices && flags.contains('d'))- || (self.options.lookbehind_assertion- && (pattern.contains("(?<=") || pattern.contains("(?<!")))- || (self.options.unicode_property_regex- && (pattern.contains("\\p{") || pattern.contains("\\P{")))- }-- /// Build an object expression for the group name-to-index mapping.- fn build_mapping_object(&self, mapping: Vec<(Atom, u32)>) -> Expr {- let props = mapping- .into_iter()- .map(|(name, idx)| {- PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {- key: PropName::Ident(IdentName {- span: DUMMY_SP,- sym: name,- }),- value: Box::new(Expr::Lit(Lit::Num(Number {- span: DUMMY_SP,- value: idx as f64,- raw: None,- }))),- })))- })- .collect();-- Expr::Object(ObjectLit {- span: DUMMY_SP,- props,- })- }-}--impl VisitMutHook<TraverseCtx> for RegexpPass {- fn exit_expr(&mut self, expr: &mut Expr, _: &mut TraverseCtx) {- self.transform_expr(expr);- }-}--impl VisitMut for RegexpPass {- noop_visit_mut_type!(fail);-- fn visit_mut_expr(&mut self, expr: &mut Expr) {- expr.visit_mut_children_with(self);- self.transform_expr(expr);- }-}--impl RegexpPass {- fn transform_expr(&mut self, expr: &mut Expr) {- match expr {- Expr::Lit(Lit::Regex(regex)) => {- // Try named groups transform first- if self.options.named_capturing_groups_regex && regex.exp.contains("(?<") {- let original_exp = regex.exp.clone();-- if let Some((stripped_exp, group_mapping)) =- self.extract_and_strip_named_groups(&original_exp, ®ex.flags)- {- let Regex { flags, span, .. } = regex.take();-- // Check if other transforms also need the regex to be a- // RegExp() constructor call- let needs_constructor =- self.needs_regexp_constructor(&stripped_exp, &flags);-- let regex_arg: Expr = if needs_constructor {- // Apply unicode property transform if needed- let pattern = self- .transform_pattern(&stripped_exp, &flags)- .unwrap_or(stripped_exp);-- let exp: Expr = Atom::from(pattern).into();- let mut args = vec![exp.into()];- if !flags.is_empty() {- let f: Expr = flags.into();- args.push(f.into());- }-- CallExpr {- span,- callee: quote_ident!("RegExp").as_callee(),- args,- ..Default::default()- }- .into()- } else {- // Keep as regex literal with stripped named groups- Lit::Regex(Regex {- span,- exp: stripped_exp.into(),- flags,- })- .into()- };-- let mapping_expr = self.build_mapping_object(group_mapping);- let source_expr: Expr = original_exp.into();-- *expr = CallExpr {- span,- callee: helper!(span, wrap_reg_exp),- args: vec![- regex_arg.as_arg(),- mapping_expr.as_arg(),- source_expr.as_arg(),- ],- ..Default::default()- }- .into();-- return;- }- }-- // Non-named-group transforms (or named group extraction failed)- let needs_transform = self.needs_regexp_constructor(®ex.exp, ®ex.flags);-- if needs_transform {- let Regex { exp, flags, span } = regex.take();-- // Transform the pattern if it contains unicode property escapes- let transformed_pattern = self- .transform_pattern(&exp, &flags)- .unwrap_or_else(|| exp.to_string());-- let exp: Expr = Atom::from(transformed_pattern).into();- let mut args = vec![exp.into()];-- if !flags.is_empty() {- let flags: Expr = flags.into();- args.push(flags.into());- }-- *expr = CallExpr {- span,- callee: quote_ident!("RegExp").as_callee(),- args,- ..Default::default()- }- .into()- }- }- Expr::Call(CallExpr {- callee: Callee::Expr(callee),- args,- ..- }) if callee.is_ident_ref_to("RegExp") => {- self.transform_regexp_args(args);- }- Expr::New(NewExpr {- callee,- args: Some(args),- ..- }) if callee.is_ident_ref_to("RegExp") => {- self.transform_regexp_args(args);- }- _ => {}- }- }-}--/// First pass: collect all named capturing groups and their 1-based indices.-/// Groups are counted in left-to-right order by the position of their opening-/// parenthesis.-fn collect_named_groups(- disjunction: &Disjunction,- counter: &mut u32,- mapping: &mut Vec<(Atom, u32)>,-) {- for alt in &disjunction.body {- for term in &alt.body {- collect_named_groups_term(term, counter, mapping);- }- }-}--fn collect_named_groups_term(term: &Term, counter: &mut u32, mapping: &mut Vec<(Atom, u32)>) {- match term {- Term::CapturingGroup(g) => {- *counter += 1;- if let Some(name) = &g.name {- mapping.push((name.clone(), *counter));- }- collect_named_groups(&g.body, counter, mapping);- }- Term::Quantifier(q) => {- collect_named_groups_term(&q.body, counter, mapping);- }- Term::LookAroundAssertion(la) => {- collect_named_groups(&la.body, counter, mapping);- }- Term::IgnoreGroup(ig) => {- collect_named_groups(&ig.body, counter, mapping);- }- _ => {}- }-}--/// Second pass: strip names from named groups and convert named references-/// to indexed references.-fn strip_named_groups(disjunction: &mut Disjunction, mapping: &[(Atom, u32)]) {- for alt in &mut disjunction.body {- for term in &mut alt.body {- strip_named_groups_term(term, mapping);- }- }-}--fn strip_named_groups_term(term: &mut Term, mapping: &[(Atom, u32)]) {- // Check if this is a NamedReference that needs conversion- let replacement = if let Term::NamedReference(nr) = &*term {- mapping.iter().find(|(n, _)| *n == nr.name).map(|(_, idx)| {- Term::IndexedReference(Box::new(IndexedReference {- span: nr.span,- index: *idx,- }))- })- } else {- None- };-- if let Some(new_term) = replacement {- *term = new_term;- return;- }-- // Recurse into children- match term {- Term::CapturingGroup(g) => {- if g.name.is_some() {- g.name = None;- }- strip_named_groups(&mut g.body, mapping);- }- Term::Quantifier(q) => {- strip_named_groups_term(&mut q.body, mapping);- }- Term::LookAroundAssertion(la) => {- strip_named_groups(&mut la.body, mapping);- }- Term::IgnoreGroup(ig) => {- strip_named_groups(&mut ig.body, mapping);- }- _ => {}- }-}
deps/swc/crates/swc_ecma_transformer/src/typescript/mod.rs
@@ -1,17 +0,0 @@-use swc_ecma_hooks::VisitMutHook;--use crate::TraverseCtx;--#[derive(Debug, Default)]-#[non_exhaustive]-pub struct TypescriptOptions {}--pub fn hook(options: TypescriptOptions) -> impl VisitMutHook<TraverseCtx> {- TypeScriptPass { options }-}--struct TypeScriptPass {- options: TypescriptOptions,-}--impl VisitMutHook<TraverseCtx> for TypeScriptPass {}
deps/swc/crates/swc_ecma_transformer/src/utils/mod.rs
@@ -1,52 +0,0 @@-use std::borrow::Cow;--use swc_atoms::Atom;-use swc_common::{Mark, SyntaxContext, DUMMY_SP};-use swc_ecma_ast::*;--pub(crate) fn normalize_module_export_name(module_export_name: &ModuleExportName) -> Cow<'_, Atom> {- match module_export_name {- ModuleExportName::Ident(Ident { sym: name, .. }) => Cow::Borrowed(name),- ModuleExportName::Str(Str { value: name, .. }) => {- // Normally, the export name should be valid UTF-8. But it might also contain- // unpaired surrogates. Node would give an error in this case:- // `SyntaxError: Invalid module export name: contains unpaired- // surrogate`. Here, we temporarily replace the unpaired surrogates- // with U+FFFD REPLACEMENT CHARACTER by using Wtf8::to_string_lossy.- Cow::Owned(Atom::from(name.to_string_lossy()))- }- #[cfg(swc_ast_unknown)]- _ => panic!("unable to access unknown nodes"),- }-}--/// Create a private identifier with the given name.-///-/// The identifier will have a unique syntax context to avoid conflicts.-pub(crate) fn create_private_ident(name: &str) -> Ident {- let mark = Mark::new();- let ctxt = SyntaxContext::empty().apply_mark(mark);- Ident::new(name.into(), DUMMY_SP, ctxt)-}--/// Generate a temporary variable name based on an expression.-///-/// For example:-/// - `obj.prop` -> `_obj_prop`-/// - `obj[expr]` -> `_obj`-pub(crate) fn generate_temp_var_name(expr: &Expr) -> String {- match expr {- Expr::Ident(ident) => format!("_{}", ident.sym),- Expr::Member(member) => {- let obj_name = match &*member.obj {- Expr::Ident(ident) => ident.sym.to_string(),- _ => "ref".to_string(),- };- match &member.prop {- MemberProp::Ident(prop) => format!("_{}_{}", obj_name, prop.sym),- _ => format!("_{obj_name}"),- }- }- _ => "_ref".to_string(),- }-}