Skip to main content

react_compiler_swc/
convert_ast.rs

1// Copyright (c) Meta Platforms, Inc. and affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use react_compiler_ast::File;
7use react_compiler_ast::Program;
8use react_compiler_ast::SourceType;
9use react_compiler_ast::common::BaseNode;
10use react_compiler_ast::common::RawNode;
11use react_compiler_ast::common::Position;
12use react_compiler_ast::common::SourceLocation;
13use react_compiler_ast::declarations::*;
14use react_compiler_ast::expressions::*;
15use react_compiler_ast::jsx::*;
16use react_compiler_ast::literals::*;
17use react_compiler_ast::operators::*;
18use react_compiler_ast::patterns::*;
19use react_compiler_ast::statements::*;
20use swc_common::Span;
21use swc_common::Spanned;
22use swc_ecma_ast as swc;
23
24/// Helper to convert SWC's Wtf8Atom (which doesn't impl Display) to a String.
25fn wtf8_to_string(value: &swc_atoms::Wtf8Atom) -> String {
26    value.to_string_lossy().into_owned()
27}
28
29/// Wrap a raw Babel-shaped JSON node in [`Statement::Unknown`]. The caller
30/// constructs `raw` with a `type` tag, so `from_raw` cannot fail.
31fn unknown_statement(raw: serde_json::Value) -> Statement {
32    Statement::Unknown(
33        UnknownStatement::from_raw(RawNode::from_value(&raw))
34            .expect("raw unknown node is constructed with a `type` tag"),
35    )
36}
37
38/// Converts an SWC Module AST to the React compiler's Babel-compatible AST.
39pub fn convert_module(module: &swc::Module, source_text: &str) -> File {
40    convert_module_with_source_type(module, source_text, SourceType::Module)
41}
42
43/// Converts an SWC Module AST to the React compiler's Babel-compatible AST
44/// with an explicit source type.
45pub fn convert_module_with_source_type(
46    module: &swc::Module,
47    source_text: &str,
48    source_type: SourceType,
49) -> File {
50    let ctx = ConvertCtx::new(source_text);
51    let base = ctx.make_base_node(module.span);
52
53    let mut body: Vec<Statement> = Vec::new();
54    let mut directives: Vec<Directive> = Vec::new();
55    let mut past_directives = false;
56
57    for item in &module.body {
58        if !past_directives {
59            if let Some(dir) = try_extract_directive(item, &ctx) {
60                directives.push(dir);
61                continue;
62            }
63            past_directives = true;
64        }
65        body.push(ctx.convert_module_item(item));
66    }
67
68    // Extract comments from source text for suppression detection
69    let comments = extract_comments_from_source(source_text);
70
71    File {
72        base: ctx.make_base_node(module.span),
73        program: Program {
74            base,
75            body,
76            directives,
77            source_type,
78            interpreter: None,
79            source_file: None,
80        },
81        comments,
82        errors: vec![],
83    }
84}
85
86/// Extract comments from source text for suppression detection.
87/// This uses simple regex-style parsing to find block and line comments.
88fn extract_comments_from_source(source: &str) -> Vec<react_compiler_ast::common::Comment> {
89    use react_compiler_ast::common::Comment;
90    use react_compiler_ast::common::CommentData;
91    let mut comments = Vec::new();
92    let bytes = source.as_bytes();
93    let len = bytes.len();
94    let mut i = 0;
95    let mut line_offsets = vec![0u32];
96    for (i, ch) in source.char_indices() {
97        if ch == '\n' {
98            line_offsets.push((i + 1) as u32);
99        }
100    }
101    let position = |offset: u32| {
102        let line_idx = match line_offsets.binary_search(&offset) {
103            Ok(idx) => idx,
104            Err(idx) => idx.saturating_sub(1),
105        };
106        let line_start = line_offsets[line_idx];
107        Position {
108            line: (line_idx as u32) + 1,
109            column: offset - line_start,
110            index: Some(offset),
111        }
112    };
113    let source_location = |start: u32, end: u32| SourceLocation {
114        start: position(start),
115        end: position(end),
116        filename: None,
117        identifier_name: None,
118    };
119
120    while i < len {
121        if bytes[i] == b'/' && i + 1 < len {
122            if bytes[i + 1] == b'/' {
123                // Line comment
124                let start = i as u32;
125                let content_start = i + 2;
126                let mut end = content_start;
127                while end < len && bytes[end] != b'\n' {
128                    end += 1;
129                }
130                let value = String::from_utf8_lossy(&bytes[content_start..end]).to_string();
131                let end_u32 = end as u32;
132                comments.push(Comment::CommentLine(CommentData {
133                    value: value.trim().to_string(),
134                    start: Some(start),
135                    end: Some(end_u32),
136                    loc: Some(source_location(start, end_u32)),
137                }));
138                i = end;
139                continue;
140            } else if bytes[i + 1] == b'*' {
141                // Block comment
142                let start = i as u32;
143                let content_start = i + 2;
144                let mut end = content_start;
145                while end + 1 < len {
146                    if bytes[end] == b'*' && bytes[end + 1] == b'/' {
147                        break;
148                    }
149                    end += 1;
150                }
151                let value = String::from_utf8_lossy(&bytes[content_start..end]).to_string();
152                let comment_end = if end + 1 < len { end + 2 } else { end };
153                let comment_end_u32 = comment_end as u32;
154                comments.push(Comment::CommentBlock(CommentData {
155                    value: value.trim().to_string(),
156                    start: Some(start),
157                    end: Some(comment_end_u32),
158                    loc: Some(source_location(start, comment_end_u32)),
159                }));
160                i = comment_end;
161                continue;
162            }
163        }
164        // Skip string literals to avoid matching // inside strings
165        if bytes[i] == b'"' || bytes[i] == b'\'' || bytes[i] == b'`' {
166            let quote = bytes[i];
167            i += 1;
168            while i < len {
169                if bytes[i] == b'\\' {
170                    i += 2; // skip escaped char
171                    continue;
172                }
173                if bytes[i] == quote {
174                    break;
175                }
176                i += 1;
177            }
178        }
179        i += 1;
180    }
181
182    comments
183}
184
185fn try_extract_directive(item: &swc::ModuleItem, ctx: &ConvertCtx) -> Option<Directive> {
186    if let swc::ModuleItem::Stmt(swc::Stmt::Expr(expr_stmt)) = item {
187        if let swc::Expr::Lit(swc::Lit::Str(s)) = &*expr_stmt.expr {
188            return Some(Directive {
189                base: ctx.make_base_node(expr_stmt.span),
190                value: DirectiveLiteral {
191                    base: ctx.make_base_node(s.span),
192                    value: wtf8_to_string(&s.value),
193                },
194            });
195        }
196    }
197    None
198}
199
200struct ConvertCtx<'a> {
201    #[allow(dead_code)]
202    source_text: &'a str,
203    line_offsets: Vec<u32>,
204    utf16_offsets: Vec<u32>,
205}
206
207impl<'a> ConvertCtx<'a> {
208    fn new(source_text: &'a str) -> Self {
209        let mut line_offsets = vec![0u32];
210        let mut utf16_offsets = vec![0u32; source_text.len() + 1];
211        let mut utf16_offset = 0u32;
212        for (i, ch) in source_text.char_indices() {
213            let next = i + ch.len_utf8();
214            utf16_offsets[i..next].fill(utf16_offset);
215            utf16_offset += ch.len_utf16() as u32;
216            if ch == '\n' {
217                line_offsets.push(next as u32);
218            }
219        }
220        utf16_offsets[source_text.len()] = utf16_offset;
221        Self {
222            source_text,
223            line_offsets,
224            utf16_offsets,
225        }
226    }
227
228    fn make_base_node(&self, span: Span) -> BaseNode {
229        BaseNode {
230            node_type: None,
231            start: Some(span.lo.0),
232            end: Some(span.hi.0),
233            loc: Some(self.source_location(span)),
234            range: None,
235            extra: None,
236            node_id: Some(span.lo.0),
237            leading_comments: None,
238            inner_comments: None,
239            trailing_comments: None,
240        }
241    }
242
243    /// `BytePos` is 1-based; emit 0-based UTF-16 `loc` to match Babel.
244    /// (`BaseNode.start`/`end` stays 1-based: `convert_scope` keys on it.)
245    fn position(&self, offset: u32) -> Position {
246        let zero_based = offset.saturating_sub(1);
247        let line_idx = match self.line_offsets.binary_search(&zero_based) {
248            Ok(idx) => idx,
249            Err(idx) => idx.saturating_sub(1),
250        };
251        let line_start = self.line_offsets[line_idx];
252        // Synthetic spans can point past EOF; clamp to the sentinel.
253        let byte_idx = (zero_based as usize).min(self.utf16_offsets.len() - 1);
254        let utf16_offset = self.utf16_offsets[byte_idx];
255        let line_start_utf16 = self.utf16_offsets[line_start as usize];
256        Position {
257            line: (line_idx as u32) + 1,
258            column: utf16_offset - line_start_utf16,
259            index: Some(utf16_offset),
260        }
261    }
262
263    fn source_location(&self, span: Span) -> SourceLocation {
264        SourceLocation {
265            start: self.position(span.lo.0),
266            end: self.position(span.hi.0),
267            filename: None,
268            identifier_name: None,
269        }
270    }
271
272    fn convert_module_item(&self, item: &swc::ModuleItem) -> Statement {
273        match item {
274            swc::ModuleItem::Stmt(stmt) => self.convert_statement(stmt),
275            swc::ModuleItem::ModuleDecl(decl) => self.convert_module_decl(decl),
276        }
277    }
278
279    fn convert_module_decl(&self, decl: &swc::ModuleDecl) -> Statement {
280        match decl {
281            swc::ModuleDecl::Import(d) => {
282                Statement::ImportDeclaration(self.convert_import_declaration(d))
283            }
284            swc::ModuleDecl::ExportDecl(d) => {
285                Statement::ExportNamedDeclaration(self.convert_export_decl(d))
286            }
287            swc::ModuleDecl::ExportNamed(d) => {
288                Statement::ExportNamedDeclaration(self.convert_export_named(d))
289            }
290            swc::ModuleDecl::ExportDefaultDecl(d) => {
291                Statement::ExportDefaultDeclaration(self.convert_export_default_decl(d))
292            }
293            swc::ModuleDecl::ExportDefaultExpr(d) => {
294                Statement::ExportDefaultDeclaration(self.convert_export_default_expr(d))
295            }
296            swc::ModuleDecl::ExportAll(d) => {
297                Statement::ExportAllDeclaration(self.convert_export_all(d))
298            }
299            // These TS module-interop statements are not modeled by the
300            // typed AST. Carry them as raw Babel-compatible
301            // `Statement::Unknown` nodes (field names and nesting match
302            // `@babel/parser`, not byte-exact details like `extra`) so they
303            // survive the pipeline the same way Babel/NAPI input does.
304            swc::ModuleDecl::TsImportEquals(d) => self.convert_ts_import_equals(d),
305            swc::ModuleDecl::TsExportAssignment(d) => self.convert_ts_export_assignment(d),
306            swc::ModuleDecl::TsNamespaceExport(d) => self.convert_ts_namespace_export(d),
307        }
308    }
309
310    // ===== TS module interop (raw unknown statements) =====
311
312    /// Build the base of a raw Babel-shaped JSON node: the `type` tag plus
313    /// the same `start`/`end`/`loc` fields the converter emits on typed
314    /// nodes via [`Self::make_base_node`].
315    fn raw_node_json(&self, node_type: &str, span: Span) -> serde_json::Value {
316        let mut base = self.make_base_node(span);
317        base.node_type = Some(node_type.to_string());
318        serde_json::to_value(base).expect("BaseNode serializes to JSON")
319    }
320
321    fn identifier_to_json(&self, id: &swc::Ident) -> serde_json::Value {
322        serde_json::to_value(Expression::Identifier(self.convert_ident_to_identifier(id)))
323            .expect("Identifier serializes to JSON")
324    }
325
326    fn ident_name_to_json(&self, id: &swc::IdentName) -> serde_json::Value {
327        serde_json::to_value(Expression::Identifier(Identifier {
328            base: self.make_base_node(id.span),
329            name: id.sym.to_string(),
330            type_annotation: None,
331            optional: None,
332            decorators: None,
333        }))
334        .expect("Identifier serializes to JSON")
335    }
336
337    /// Serialize a TS entity name (`a` or `a.b.c`) as the Babel
338    /// `Identifier` / `TSQualifiedName` shape.
339    fn ts_entity_name_to_json(&self, name: &swc::TsEntityName) -> serde_json::Value {
340        match name {
341            swc::TsEntityName::Ident(id) => self.identifier_to_json(id),
342            swc::TsEntityName::TsQualifiedName(q) => {
343                let mut raw = self.raw_node_json("TSQualifiedName", q.span);
344                raw["left"] = self.ts_entity_name_to_json(&q.left);
345                raw["right"] = self.ident_name_to_json(&q.right);
346                raw
347            }
348        }
349    }
350
351    /// `import x = require("mod")` / `import a = b.c` →
352    /// `TSImportEqualsDeclaration`.
353    fn convert_ts_import_equals(&self, d: &swc::TsImportEqualsDecl) -> Statement {
354        let mut raw = self.raw_node_json("TSImportEqualsDeclaration", d.span);
355        raw["importKind"] = serde_json::json!(if d.is_type_only { "type" } else { "value" });
356        raw["isExport"] = serde_json::json!(d.is_export);
357        raw["id"] = self.identifier_to_json(&d.id);
358        raw["moduleReference"] = match &d.module_ref {
359            swc::TsModuleRef::TsExternalModuleRef(r) => {
360                let mut module_ref = self.raw_node_json("TSExternalModuleReference", r.span);
361                module_ref["expression"] =
362                    serde_json::to_value(Expression::StringLiteral(StringLiteral {
363                        base: self.make_base_node(r.expr.span),
364                        value: wtf8_to_string(&r.expr.value),
365                    }))
366                    .expect("StringLiteral serializes to JSON");
367                module_ref
368            }
369            swc::TsModuleRef::TsEntityName(name) => self.ts_entity_name_to_json(name),
370        };
371        unknown_statement(raw)
372    }
373
374    /// `export = x` → `TSExportAssignment`. The expression goes through the
375    /// normal forward conversion; the typed AST serializes to the Babel
376    /// shape by construction.
377    fn convert_ts_export_assignment(&self, d: &swc::TsExportAssignment) -> Statement {
378        let mut raw = self.raw_node_json("TSExportAssignment", d.span);
379        raw["expression"] = serde_json::to_value(self.convert_expression(&d.expr))
380            .expect("Expression serializes to JSON");
381        unknown_statement(raw)
382    }
383
384    /// `export as namespace X` → `TSNamespaceExportDeclaration`.
385    fn convert_ts_namespace_export(&self, d: &swc::TsNamespaceExportDecl) -> Statement {
386        let mut raw = self.raw_node_json("TSNamespaceExportDeclaration", d.span);
387        raw["id"] = self.identifier_to_json(&d.id);
388        unknown_statement(raw)
389    }
390
391    // ===== Statements =====
392
393    fn convert_statement(&self, stmt: &swc::Stmt) -> Statement {
394        match stmt {
395            swc::Stmt::Block(s) => Statement::BlockStatement(self.convert_block_statement(s)),
396            swc::Stmt::Break(s) => Statement::BreakStatement(BreakStatement {
397                base: self.make_base_node(s.span),
398                label: s
399                    .label
400                    .as_ref()
401                    .map(|l| self.convert_ident_to_identifier(l)),
402            }),
403            swc::Stmt::Continue(s) => Statement::ContinueStatement(ContinueStatement {
404                base: self.make_base_node(s.span),
405                label: s
406                    .label
407                    .as_ref()
408                    .map(|l| self.convert_ident_to_identifier(l)),
409            }),
410            swc::Stmt::Debugger(s) => Statement::DebuggerStatement(DebuggerStatement {
411                base: self.make_base_node(s.span),
412            }),
413            swc::Stmt::DoWhile(s) => Statement::DoWhileStatement(DoWhileStatement {
414                base: self.make_base_node(s.span),
415                test: Box::new(self.convert_expression(&s.test)),
416                body: Box::new(self.convert_statement(&s.body)),
417            }),
418            swc::Stmt::Empty(s) => Statement::EmptyStatement(EmptyStatement {
419                base: self.make_base_node(s.span),
420            }),
421            swc::Stmt::Expr(s) => Statement::ExpressionStatement(ExpressionStatement {
422                base: self.make_base_node(s.span),
423                expression: Box::new(self.convert_expression(&s.expr)),
424            }),
425            swc::Stmt::ForIn(s) => Statement::ForInStatement(ForInStatement {
426                base: self.make_base_node(s.span),
427                left: Box::new(self.convert_for_head(&s.left)),
428                right: Box::new(self.convert_expression(&s.right)),
429                body: Box::new(self.convert_statement(&s.body)),
430            }),
431            swc::Stmt::ForOf(s) => Statement::ForOfStatement(ForOfStatement {
432                base: self.make_base_node(s.span),
433                left: Box::new(self.convert_for_head(&s.left)),
434                right: Box::new(self.convert_expression(&s.right)),
435                body: Box::new(self.convert_statement(&s.body)),
436                is_await: s.is_await,
437            }),
438            swc::Stmt::For(s) => Statement::ForStatement(ForStatement {
439                base: self.make_base_node(s.span),
440                init: s
441                    .init
442                    .as_ref()
443                    .map(|i| Box::new(self.convert_var_decl_or_expr_to_for_init(i))),
444                test: s
445                    .test
446                    .as_ref()
447                    .map(|t| Box::new(self.convert_expression(t))),
448                update: s
449                    .update
450                    .as_ref()
451                    .map(|u| Box::new(self.convert_expression(u))),
452                body: Box::new(self.convert_statement(&s.body)),
453            }),
454            swc::Stmt::If(s) => Statement::IfStatement(IfStatement {
455                base: self.make_base_node(s.span),
456                test: Box::new(self.convert_expression(&s.test)),
457                consequent: Box::new(self.convert_statement(&s.cons)),
458                alternate: s.alt.as_ref().map(|a| Box::new(self.convert_statement(a))),
459            }),
460            swc::Stmt::Labeled(s) => Statement::LabeledStatement(LabeledStatement {
461                base: self.make_base_node(s.span),
462                label: self.convert_ident_to_identifier(&s.label),
463                body: Box::new(self.convert_statement(&s.body)),
464            }),
465            swc::Stmt::Return(s) => Statement::ReturnStatement(ReturnStatement {
466                base: self.make_base_node(s.span),
467                argument: s.arg.as_ref().map(|a| Box::new(self.convert_expression(a))),
468            }),
469            swc::Stmt::Switch(s) => Statement::SwitchStatement(SwitchStatement {
470                base: self.make_base_node(s.span),
471                discriminant: Box::new(self.convert_expression(&s.discriminant)),
472                cases: s
473                    .cases
474                    .iter()
475                    .map(|c| SwitchCase {
476                        base: self.make_base_node(c.span),
477                        test: c
478                            .test
479                            .as_ref()
480                            .map(|t| Box::new(self.convert_expression(t))),
481                        consequent: c.cons.iter().map(|s| self.convert_statement(s)).collect(),
482                    })
483                    .collect(),
484            }),
485            swc::Stmt::Throw(s) => Statement::ThrowStatement(ThrowStatement {
486                base: self.make_base_node(s.span),
487                argument: Box::new(self.convert_expression(&s.arg)),
488            }),
489            swc::Stmt::Try(s) => Statement::TryStatement(TryStatement {
490                base: self.make_base_node(s.span),
491                block: self.convert_block_statement(&s.block),
492                handler: s.handler.as_ref().map(|h| self.convert_catch_clause(h)),
493                finalizer: s
494                    .finalizer
495                    .as_ref()
496                    .map(|f| self.convert_block_statement(f)),
497            }),
498            swc::Stmt::While(s) => Statement::WhileStatement(WhileStatement {
499                base: self.make_base_node(s.span),
500                test: Box::new(self.convert_expression(&s.test)),
501                body: Box::new(self.convert_statement(&s.body)),
502            }),
503            swc::Stmt::With(s) => Statement::WithStatement(WithStatement {
504                base: self.make_base_node(s.span),
505                object: Box::new(self.convert_expression(&s.obj)),
506                body: Box::new(self.convert_statement(&s.body)),
507            }),
508            swc::Stmt::Decl(d) => self.convert_decl_to_statement(d),
509        }
510    }
511
512    fn convert_decl_to_statement(&self, decl: &swc::Decl) -> Statement {
513        match decl {
514            swc::Decl::Var(v) => {
515                Statement::VariableDeclaration(self.convert_variable_declaration(v))
516            }
517            swc::Decl::Fn(f) => Statement::FunctionDeclaration(self.convert_fn_decl(f)),
518            swc::Decl::Class(c) => Statement::ClassDeclaration(self.convert_class_decl(c)),
519            swc::Decl::TsTypeAlias(d) => {
520                Statement::TSTypeAliasDeclaration(self.convert_ts_type_alias(d))
521            }
522            swc::Decl::TsInterface(d) => {
523                Statement::TSInterfaceDeclaration(self.convert_ts_interface(d))
524            }
525            swc::Decl::TsEnum(d) => Statement::TSEnumDeclaration(self.convert_ts_enum(d)),
526            swc::Decl::TsModule(d) => Statement::TSModuleDeclaration(self.convert_ts_module(d)),
527            swc::Decl::Using(u) => Statement::VariableDeclaration(self.convert_using_decl(u)),
528        }
529    }
530
531    fn convert_block_statement(&self, block: &swc::BlockStmt) -> BlockStatement {
532        let mut body: Vec<Statement> = Vec::new();
533        let mut directives: Vec<Directive> = Vec::new();
534        let mut past_directives = false;
535
536        for stmt in &block.stmts {
537            if !past_directives {
538                if let Some(dir) = self.try_extract_block_directive(stmt) {
539                    directives.push(dir);
540                    continue;
541                }
542                past_directives = true;
543            }
544            body.push(self.convert_statement(stmt));
545        }
546
547        BlockStatement {
548            base: self.make_base_node(block.span),
549            body,
550            directives,
551        }
552    }
553
554    /// Try to extract a directive from a statement in a block body.
555    /// Directives are expression statements whose expression is a string literal.
556    fn try_extract_block_directive(&self, stmt: &swc::Stmt) -> Option<Directive> {
557        if let swc::Stmt::Expr(expr_stmt) = stmt {
558            if let swc::Expr::Lit(swc::Lit::Str(s)) = &*expr_stmt.expr {
559                return Some(Directive {
560                    base: self.make_base_node(expr_stmt.span),
561                    value: DirectiveLiteral {
562                        base: self.make_base_node(s.span),
563                        value: wtf8_to_string(&s.value),
564                    },
565                });
566            }
567        }
568        None
569    }
570
571    fn convert_catch_clause(&self, clause: &swc::CatchClause) -> CatchClause {
572        CatchClause {
573            base: self.make_base_node(clause.span),
574            param: clause.param.as_ref().map(|p| self.convert_pat(p)),
575            body: self.convert_block_statement(&clause.body),
576        }
577    }
578
579    fn convert_var_decl_or_expr_to_for_init(&self, init: &swc::VarDeclOrExpr) -> ForInit {
580        match init {
581            swc::VarDeclOrExpr::VarDecl(v) => {
582                ForInit::VariableDeclaration(self.convert_variable_declaration(v))
583            }
584            swc::VarDeclOrExpr::Expr(e) => {
585                ForInit::Expression(Box::new(self.convert_expression(e)))
586            }
587        }
588    }
589
590    fn convert_for_head(&self, head: &swc::ForHead) -> ForInOfLeft {
591        match head {
592            swc::ForHead::VarDecl(v) => {
593                ForInOfLeft::VariableDeclaration(self.convert_variable_declaration(v))
594            }
595            swc::ForHead::Pat(p) => ForInOfLeft::Pattern(Box::new(self.convert_pat(p))),
596            swc::ForHead::UsingDecl(u) => {
597                ForInOfLeft::VariableDeclaration(self.convert_using_decl(u))
598            }
599        }
600    }
601
602    fn convert_variable_declaration(&self, decl: &swc::VarDecl) -> VariableDeclaration {
603        VariableDeclaration {
604            base: self.make_base_node(decl.span),
605            declarations: decl
606                .decls
607                .iter()
608                .map(|d| self.convert_variable_declarator(d))
609                .collect(),
610            kind: match decl.kind {
611                swc::VarDeclKind::Var => VariableDeclarationKind::Var,
612                swc::VarDeclKind::Let => VariableDeclarationKind::Let,
613                swc::VarDeclKind::Const => VariableDeclarationKind::Const,
614            },
615            declare: if decl.declare { Some(true) } else { None },
616        }
617    }
618
619    fn convert_using_decl(&self, decl: &swc::UsingDecl) -> VariableDeclaration {
620        VariableDeclaration {
621            base: self.make_base_node(decl.span),
622            declarations: decl
623                .decls
624                .iter()
625                .map(|d| self.convert_variable_declarator(d))
626                .collect(),
627            kind: VariableDeclarationKind::Using,
628            declare: None,
629        }
630    }
631
632    fn convert_variable_declarator(&self, d: &swc::VarDeclarator) -> VariableDeclarator {
633        VariableDeclarator {
634            base: self.make_base_node(d.span),
635            id: self.convert_pat(&d.name),
636            init: d
637                .init
638                .as_ref()
639                .map(|e| Box::new(self.convert_expression(e))),
640            definite: if d.definite { Some(true) } else { None },
641        }
642    }
643
644    // ===== Expressions =====
645
646    fn convert_expression(&self, expr: &swc::Expr) -> Expression {
647        match expr {
648            swc::Expr::Lit(lit) => self.convert_lit(lit),
649            swc::Expr::Ident(id) => Expression::Identifier(self.convert_ident_to_identifier(id)),
650            swc::Expr::This(t) => Expression::ThisExpression(ThisExpression {
651                base: self.make_base_node(t.span),
652            }),
653            swc::Expr::Array(arr) => {
654                Expression::ArrayExpression(self.convert_array_expression(arr))
655            }
656            swc::Expr::Object(obj) => {
657                Expression::ObjectExpression(self.convert_object_expression(obj))
658            }
659            swc::Expr::Fn(f) => Expression::FunctionExpression(self.convert_fn_expr(f)),
660            swc::Expr::Unary(un) => Expression::UnaryExpression(UnaryExpression {
661                base: self.make_base_node(un.span),
662                operator: self.convert_unary_operator(un.op),
663                prefix: true,
664                argument: Box::new(self.convert_expression(&un.arg)),
665            }),
666            swc::Expr::Update(up) => Expression::UpdateExpression(UpdateExpression {
667                base: self.make_base_node(up.span),
668                operator: self.convert_update_operator(up.op),
669                argument: Box::new(self.convert_expression(&up.arg)),
670                prefix: up.prefix,
671            }),
672            swc::Expr::Bin(bin) => {
673                if let Some(log_op) = self.try_convert_logical_operator(bin.op) {
674                    Expression::LogicalExpression(LogicalExpression {
675                        base: self.make_base_node(bin.span),
676                        operator: log_op,
677                        left: Box::new(self.convert_expression(&bin.left)),
678                        right: Box::new(self.convert_expression(&bin.right)),
679                    })
680                } else {
681                    Expression::BinaryExpression(BinaryExpression {
682                        base: self.make_base_node(bin.span),
683                        operator: self.convert_binary_operator(bin.op),
684                        left: Box::new(self.convert_expression(&bin.left)),
685                        right: Box::new(self.convert_expression(&bin.right)),
686                    })
687                }
688            }
689            swc::Expr::Assign(a) => {
690                Expression::AssignmentExpression(self.convert_assignment_expression(a))
691            }
692            swc::Expr::Member(m) => Expression::MemberExpression(self.convert_member_expression(m)),
693            swc::Expr::SuperProp(sp) => {
694                let (property, computed) = self.convert_super_prop(&sp.prop);
695                Expression::MemberExpression(MemberExpression {
696                    base: self.make_base_node(sp.span),
697                    object: Box::new(Expression::Super(Super {
698                        base: self.make_base_node(sp.obj.span),
699                    })),
700                    property: Box::new(property),
701                    computed,
702                })
703            }
704            swc::Expr::Cond(c) => Expression::ConditionalExpression(ConditionalExpression {
705                base: self.make_base_node(c.span),
706                test: Box::new(self.convert_expression(&c.test)),
707                consequent: Box::new(self.convert_expression(&c.cons)),
708                alternate: Box::new(self.convert_expression(&c.alt)),
709            }),
710            swc::Expr::Call(call) => Expression::CallExpression(self.convert_call_expression(call)),
711            swc::Expr::New(n) => Expression::NewExpression(NewExpression {
712                base: self.make_base_node(n.span),
713                callee: Box::new(self.convert_expression(&n.callee)),
714                arguments: n.args.as_ref().map_or_else(Vec::new, |args| {
715                    args.iter()
716                        .map(|a| self.convert_expr_or_spread(a))
717                        .collect()
718                }),
719                type_parameters: None,
720                type_arguments: None,
721            }),
722            swc::Expr::Seq(seq) => Expression::SequenceExpression(SequenceExpression {
723                base: self.make_base_node(seq.span),
724                expressions: seq
725                    .exprs
726                    .iter()
727                    .map(|e| self.convert_expression(e))
728                    .collect(),
729            }),
730            swc::Expr::Arrow(arrow) => {
731                Expression::ArrowFunctionExpression(self.convert_arrow_function(arrow))
732            }
733            swc::Expr::Class(class) => {
734                Expression::ClassExpression(self.convert_class_expression(class))
735            }
736            swc::Expr::Yield(y) => Expression::YieldExpression(YieldExpression {
737                base: self.make_base_node(y.span),
738                argument: y.arg.as_ref().map(|a| Box::new(self.convert_expression(a))),
739                delegate: y.delegate,
740            }),
741            swc::Expr::Await(a) => Expression::AwaitExpression(AwaitExpression {
742                base: self.make_base_node(a.span),
743                argument: Box::new(self.convert_expression(&a.arg)),
744            }),
745            swc::Expr::MetaProp(mp) => {
746                let (meta_name, prop_name) = match mp.kind {
747                    swc::MetaPropKind::NewTarget => ("new", "target"),
748                    swc::MetaPropKind::ImportMeta => ("import", "meta"),
749                };
750                Expression::MetaProperty(MetaProperty {
751                    base: self.make_base_node(mp.span),
752                    meta: Identifier {
753                        base: self.make_base_node(mp.span),
754                        name: meta_name.to_string(),
755                        type_annotation: None,
756                        optional: None,
757                        decorators: None,
758                    },
759                    property: Identifier {
760                        base: self.make_base_node(mp.span),
761                        name: prop_name.to_string(),
762                        type_annotation: None,
763                        optional: None,
764                        decorators: None,
765                    },
766                })
767            }
768            swc::Expr::Tpl(tpl) => Expression::TemplateLiteral(self.convert_template_literal(tpl)),
769            swc::Expr::TaggedTpl(tag) => {
770                Expression::TaggedTemplateExpression(TaggedTemplateExpression {
771                    base: self.make_base_node(tag.span),
772                    tag: Box::new(self.convert_expression(&tag.tag)),
773                    quasi: self.convert_template_literal(&tag.tpl),
774                    type_parameters: None,
775                })
776            }
777            swc::Expr::Paren(p) => Expression::ParenthesizedExpression(ParenthesizedExpression {
778                base: self.make_base_node(p.span),
779                expression: Box::new(self.convert_expression(&p.expr)),
780            }),
781            swc::Expr::OptChain(chain) => self.convert_opt_chain_expression(chain),
782            swc::Expr::PrivateName(p) => Expression::PrivateName(PrivateName {
783                base: self.make_base_node(p.span),
784                id: Identifier {
785                    base: self.make_base_node(p.span),
786                    name: p.name.to_string(),
787                    type_annotation: None,
788                    optional: None,
789                    decorators: None,
790                },
791            }),
792            swc::Expr::JSXElement(el) => {
793                Expression::JSXElement(Box::new(self.convert_jsx_element(el)))
794            }
795            swc::Expr::JSXFragment(frag) => {
796                Expression::JSXFragment(self.convert_jsx_fragment(frag))
797            }
798            swc::Expr::JSXEmpty(e) => Expression::Identifier(Identifier {
799                base: self.make_base_node(e.span),
800                name: "undefined".to_string(),
801                type_annotation: None,
802                optional: None,
803                decorators: None,
804            }),
805            swc::Expr::JSXMember(m) => Expression::Identifier(Identifier {
806                base: self.make_base_node(m.prop.span),
807                name: m.prop.sym.to_string(),
808                type_annotation: None,
809                optional: None,
810                decorators: None,
811            }),
812            swc::Expr::JSXNamespacedName(n) => Expression::Identifier(Identifier {
813                base: self.make_base_node(n.name.span),
814                name: format!("{}:{}", n.ns.sym, n.name.sym),
815                type_annotation: None,
816                optional: None,
817                decorators: None,
818            }),
819            swc::Expr::TsAs(e) => Expression::TSAsExpression(TSAsExpression {
820                base: self.make_base_node(e.span),
821                expression: Box::new(self.convert_expression(&e.expr)),
822                type_annotation: RawNode::from_value(
823                    &self.convert_ts_type_to_json(&e.type_ann)
824                        .unwrap_or(serde_json::Value::Null),
825                    ),
826            }),
827            swc::Expr::TsSatisfies(e) => Expression::TSSatisfiesExpression(TSSatisfiesExpression {
828                base: self.make_base_node(e.span),
829                expression: Box::new(self.convert_expression(&e.expr)),
830                type_annotation: RawNode::from_value(
831                    &self.convert_ts_type_to_json(&e.type_ann)
832                        .unwrap_or(serde_json::Value::Null),
833                    ),
834            }),
835            swc::Expr::TsTypeAssertion(e) => Expression::TSTypeAssertion(TSTypeAssertion {
836                base: self.make_base_node(e.span),
837                expression: Box::new(self.convert_expression(&e.expr)),
838                type_annotation: RawNode::from_value(
839                    &self.convert_ts_type_to_json(&e.type_ann)
840                        .unwrap_or(serde_json::Value::Null),
841                    ),
842            }),
843            swc::Expr::TsNonNull(e) => Expression::TSNonNullExpression(TSNonNullExpression {
844                base: self.make_base_node(e.span),
845                expression: Box::new(self.convert_expression(&e.expr)),
846            }),
847            swc::Expr::TsInstantiation(e) => {
848                Expression::TSInstantiationExpression(TSInstantiationExpression {
849                    base: self.make_base_node(e.span),
850                    expression: Box::new(self.convert_expression(&e.expr)),
851                    type_parameters: RawNode::null(),
852                })
853            }
854            swc::Expr::TsConstAssertion(e) => {
855                // "as const" → TSAsExpression with typeAnnotation: TSTypeReference { typeName: Identifier { name: "const" } }
856                // This matches Babel's AST representation of `as const`.
857                let type_ann = serde_json::json!({
858                    "type": "TSTypeReference",
859                    "typeName": {
860                        "type": "Identifier",
861                        "name": "const"
862                    }
863                });
864                Expression::TSAsExpression(TSAsExpression {
865                    base: self.make_base_node(e.span),
866                    expression: Box::new(self.convert_expression(&e.expr)),
867                    type_annotation: RawNode::from_value(&type_ann),
868                })
869            }
870            swc::Expr::Invalid(i) => Expression::Identifier(Identifier {
871                base: self.make_base_node(i.span),
872                name: "__invalid__".to_string(),
873                type_annotation: None,
874                optional: None,
875                decorators: None,
876            }),
877        }
878    }
879
880    fn convert_lit(&self, lit: &swc::Lit) -> Expression {
881        match lit {
882            swc::Lit::Str(s) => Expression::StringLiteral(StringLiteral {
883                base: self.make_base_node(s.span),
884                value: wtf8_to_string(&s.value),
885            }),
886            swc::Lit::Bool(b) => Expression::BooleanLiteral(BooleanLiteral {
887                base: self.make_base_node(b.span),
888                value: b.value,
889            }),
890            swc::Lit::Null(n) => Expression::NullLiteral(NullLiteral {
891                base: self.make_base_node(n.span),
892            }),
893            swc::Lit::Num(n) => Expression::NumericLiteral(NumericLiteral {
894                base: self.make_base_node(n.span),
895                value: n.value,
896                extra: None,
897            }),
898            swc::Lit::BigInt(b) => Expression::BigIntLiteral(BigIntLiteral {
899                base: self.make_base_node(b.span),
900                value: b.value.to_string(),
901            }),
902            swc::Lit::Regex(r) => Expression::RegExpLiteral(RegExpLiteral {
903                base: self.make_base_node(r.span),
904                pattern: r.exp.to_string(),
905                flags: r.flags.to_string(),
906            }),
907            swc::Lit::JSXText(t) => Expression::StringLiteral(StringLiteral {
908                base: self.make_base_node(t.span),
909                value: t.value.to_string(),
910            }),
911        }
912    }
913
914    // ===== Optional chaining =====
915
916    fn convert_opt_chain_expression(&self, chain: &swc::OptChainExpr) -> Expression {
917        match &*chain.base {
918            swc::OptChainBase::Member(m) => {
919                let (property, computed) = self.convert_member_prop(&m.prop);
920                Expression::OptionalMemberExpression(OptionalMemberExpression {
921                    base: self.make_base_node(chain.span),
922                    object: Box::new(self.convert_opt_chain_callee(&m.obj)),
923                    property: Box::new(property),
924                    computed,
925                    optional: chain.optional,
926                })
927            }
928            swc::OptChainBase::Call(call) => {
929                Expression::OptionalCallExpression(OptionalCallExpression {
930                    base: self.make_base_node(chain.span),
931                    callee: Box::new(self.convert_opt_chain_callee(&call.callee)),
932                    arguments: call
933                        .args
934                        .iter()
935                        .map(|a| self.convert_expr_or_spread(a))
936                        .collect(),
937                    optional: chain.optional,
938                    type_parameters: None,
939                    type_arguments: None,
940                })
941            }
942        }
943    }
944
945    fn convert_opt_chain_callee(&self, expr: &swc::Expr) -> Expression {
946        if let swc::Expr::OptChain(chain) = expr {
947            return self.convert_opt_chain_expression(chain);
948        }
949        self.convert_expression(expr)
950    }
951
952    // ===== Member expression =====
953
954    fn convert_member_expression(&self, m: &swc::MemberExpr) -> MemberExpression {
955        let (property, computed) = self.convert_member_prop(&m.prop);
956        MemberExpression {
957            base: self.make_base_node(m.span),
958            object: Box::new(self.convert_expression(&m.obj)),
959            property: Box::new(property),
960            computed,
961        }
962    }
963
964    fn convert_member_prop(&self, prop: &swc::MemberProp) -> (Expression, bool) {
965        match prop {
966            swc::MemberProp::Ident(id) => (
967                Expression::Identifier(Identifier {
968                    base: self.make_base_node(id.span),
969                    name: id.sym.to_string(),
970                    type_annotation: None,
971                    optional: None,
972                    decorators: None,
973                }),
974                false,
975            ),
976            swc::MemberProp::Computed(c) => (self.convert_expression(&c.expr), true),
977            swc::MemberProp::PrivateName(p) => (
978                Expression::PrivateName(PrivateName {
979                    base: self.make_base_node(p.span),
980                    id: Identifier {
981                        base: self.make_base_node(p.span),
982                        name: p.name.to_string(),
983                        type_annotation: None,
984                        optional: None,
985                        decorators: None,
986                    },
987                }),
988                false,
989            ),
990        }
991    }
992
993    fn convert_super_prop(&self, prop: &swc::SuperProp) -> (Expression, bool) {
994        match prop {
995            swc::SuperProp::Ident(id) => (
996                Expression::Identifier(Identifier {
997                    base: self.make_base_node(id.span),
998                    name: id.sym.to_string(),
999                    type_annotation: None,
1000                    optional: None,
1001                    decorators: None,
1002                }),
1003                false,
1004            ),
1005            swc::SuperProp::Computed(c) => (self.convert_expression(&c.expr), true),
1006        }
1007    }
1008
1009    // ===== Call expression =====
1010
1011    fn convert_call_expression(&self, call: &swc::CallExpr) -> CallExpression {
1012        CallExpression {
1013            base: self.make_base_node(call.span),
1014            callee: Box::new(self.convert_callee(&call.callee)),
1015            arguments: call
1016                .args
1017                .iter()
1018                .map(|a| self.convert_expr_or_spread(a))
1019                .collect(),
1020            type_parameters: None,
1021            type_arguments: None,
1022            optional: None,
1023        }
1024    }
1025
1026    fn convert_callee(&self, callee: &swc::Callee) -> Expression {
1027        match callee {
1028            swc::Callee::Expr(e) => self.convert_expression(e),
1029            swc::Callee::Super(s) => Expression::Super(Super {
1030                base: self.make_base_node(s.span),
1031            }),
1032            swc::Callee::Import(i) => Expression::Import(Import {
1033                base: self.make_base_node(i.span),
1034            }),
1035        }
1036    }
1037
1038    fn convert_expr_or_spread(&self, arg: &swc::ExprOrSpread) -> Expression {
1039        if let Some(spread_span) = arg.spread {
1040            Expression::SpreadElement(SpreadElement {
1041                base: self.make_base_node(Span::new(spread_span.lo, arg.expr.span().hi)),
1042                argument: Box::new(self.convert_expression(&arg.expr)),
1043            })
1044        } else {
1045            self.convert_expression(&arg.expr)
1046        }
1047    }
1048
1049    // ===== Function helpers =====
1050
1051    fn convert_fn_decl(&self, func: &swc::FnDecl) -> FunctionDeclaration {
1052        let f = &func.function;
1053        let body = f
1054            .body
1055            .as_ref()
1056            .map(|b| self.convert_block_statement(b))
1057            .unwrap_or_else(|| BlockStatement {
1058                base: self.make_base_node(f.span),
1059                body: vec![],
1060                directives: vec![],
1061            });
1062        FunctionDeclaration {
1063            base: self.make_base_node(f.span),
1064            id: Some(self.convert_ident_to_identifier(&func.ident)),
1065            params: self.convert_params(&f.params),
1066            body,
1067            generator: f.is_generator,
1068            is_async: f.is_async,
1069            declare: if func.declare { Some(true) } else { None },
1070            return_type: f
1071                .return_type
1072                .as_ref()
1073                .map(|_| RawNode::null()),
1074            type_parameters: f
1075                .type_params
1076                .as_ref()
1077                .map(|_| RawNode::null()),
1078            predicate: None,
1079            component_declaration: false,
1080            hook_declaration: false,
1081        }
1082    }
1083
1084    fn convert_fn_expr(&self, func: &swc::FnExpr) -> FunctionExpression {
1085        let f = &func.function;
1086        let body = f
1087            .body
1088            .as_ref()
1089            .map(|b| self.convert_block_statement(b))
1090            .unwrap_or_else(|| BlockStatement {
1091                base: self.make_base_node(f.span),
1092                body: vec![],
1093                directives: vec![],
1094            });
1095        FunctionExpression {
1096            base: self.make_base_node(f.span),
1097            id: func
1098                .ident
1099                .as_ref()
1100                .map(|id| self.convert_ident_to_identifier(id)),
1101            params: self.convert_params(&f.params),
1102            body,
1103            generator: f.is_generator,
1104            is_async: f.is_async,
1105            return_type: f
1106                .return_type
1107                .as_ref()
1108                .map(|_| RawNode::null()),
1109            type_parameters: f
1110                .type_params
1111                .as_ref()
1112                .map(|_| RawNode::null()),
1113            predicate: None,
1114        }
1115    }
1116
1117    fn convert_arrow_function(&self, arrow: &swc::ArrowExpr) -> ArrowFunctionExpression {
1118        let is_expression = matches!(&*arrow.body, swc::BlockStmtOrExpr::Expr(_));
1119        let body = match &*arrow.body {
1120            swc::BlockStmtOrExpr::BlockStmt(block) => {
1121                ArrowFunctionBody::BlockStatement(self.convert_block_statement(block))
1122            }
1123            swc::BlockStmtOrExpr::Expr(expr) => {
1124                ArrowFunctionBody::Expression(Box::new(self.convert_expression(expr)))
1125            }
1126        };
1127        ArrowFunctionExpression {
1128            base: self.make_base_node(arrow.span),
1129            params: arrow.params.iter().map(|p| self.convert_pat(p)).collect(),
1130            body: Box::new(body),
1131            id: None,
1132            generator: arrow.is_generator,
1133            is_async: arrow.is_async,
1134            expression: Some(is_expression),
1135            return_type: arrow
1136                .return_type
1137                .as_ref()
1138                .map(|_| RawNode::null()),
1139            type_parameters: arrow
1140                .type_params
1141                .as_ref()
1142                .map(|_| RawNode::null()),
1143            predicate: None,
1144        }
1145    }
1146
1147    fn convert_params(&self, params: &[swc::Param]) -> Vec<PatternLike> {
1148        params.iter().map(|p| self.convert_pat(&p.pat)).collect()
1149    }
1150
1151    // ===== Patterns =====
1152
1153    fn convert_pat(&self, pat: &swc::Pat) -> PatternLike {
1154        match pat {
1155            swc::Pat::Ident(id) => PatternLike::Identifier(self.convert_binding_ident(id)),
1156            swc::Pat::Array(arr) => PatternLike::ArrayPattern(self.convert_array_pattern(arr)),
1157            swc::Pat::Object(obj) => PatternLike::ObjectPattern(self.convert_object_pattern(obj)),
1158            swc::Pat::Assign(a) => PatternLike::AssignmentPattern(AssignmentPattern {
1159                base: self.make_base_node(a.span),
1160                left: Box::new(self.convert_pat(&a.left)),
1161                right: Box::new(self.convert_expression(&a.right)),
1162                type_annotation: None,
1163                decorators: None,
1164            }),
1165            swc::Pat::Rest(r) => PatternLike::RestElement(RestElement {
1166                base: self.make_base_node(r.span),
1167                argument: Box::new(self.convert_pat(&r.arg)),
1168                type_annotation: None,
1169                decorators: None,
1170            }),
1171            swc::Pat::Expr(e) => self.convert_expression_to_pattern(e),
1172            swc::Pat::Invalid(i) => PatternLike::Identifier(Identifier {
1173                base: self.make_base_node(i.span),
1174                name: "__invalid__".to_string(),
1175                type_annotation: None,
1176                optional: None,
1177                decorators: None,
1178            }),
1179        }
1180    }
1181
1182    fn convert_expression_to_pattern(&self, expr: &swc::Expr) -> PatternLike {
1183        match expr {
1184            swc::Expr::Ident(id) => PatternLike::Identifier(self.convert_ident_to_identifier(id)),
1185            swc::Expr::Member(m) => {
1186                PatternLike::MemberExpression(self.convert_member_expression(m))
1187            }
1188            _ => PatternLike::Identifier(Identifier {
1189                base: self.make_base_node(expr.span()),
1190                name: "__unknown_target__".to_string(),
1191                type_annotation: None,
1192                optional: None,
1193                decorators: None,
1194            }),
1195        }
1196    }
1197
1198    fn convert_object_pattern(&self, obj: &swc::ObjectPat) -> ObjectPattern {
1199        let properties = obj
1200            .props
1201            .iter()
1202            .map(|p| match p {
1203                swc::ObjectPatProp::KeyValue(kv) => {
1204                    ObjectPatternProperty::ObjectProperty(ObjectPatternProp {
1205                        base: self.make_base_node(kv.span()),
1206                        key: Box::new(self.convert_prop_name(&kv.key)),
1207                        value: Box::new(self.convert_pat(&kv.value)),
1208                        computed: matches!(kv.key, swc::PropName::Computed(_)),
1209                        shorthand: false,
1210                        decorators: None,
1211                        method: None,
1212                    })
1213                }
1214                swc::ObjectPatProp::Assign(a) => {
1215                    let id = self.convert_ident_to_identifier(&a.key.id);
1216                    let (value, shorthand) = if let Some(ref init) = a.value {
1217                        (
1218                            Box::new(PatternLike::AssignmentPattern(AssignmentPattern {
1219                                base: self.make_base_node(a.span),
1220                                left: Box::new(PatternLike::Identifier(id.clone())),
1221                                right: Box::new(self.convert_expression(init)),
1222                                type_annotation: None,
1223                                decorators: None,
1224                            })),
1225                            true,
1226                        )
1227                    } else {
1228                        (Box::new(PatternLike::Identifier(id.clone())), true)
1229                    };
1230                    ObjectPatternProperty::ObjectProperty(ObjectPatternProp {
1231                        base: self.make_base_node(a.span),
1232                        key: Box::new(Expression::Identifier(id)),
1233                        value,
1234                        computed: false,
1235                        shorthand,
1236                        decorators: None,
1237                        method: None,
1238                    })
1239                }
1240                swc::ObjectPatProp::Rest(r) => ObjectPatternProperty::RestElement(RestElement {
1241                    base: self.make_base_node(r.span),
1242                    argument: Box::new(self.convert_pat(&r.arg)),
1243                    type_annotation: None,
1244                    decorators: None,
1245                }),
1246            })
1247            .collect();
1248        ObjectPattern {
1249            base: self.make_base_node(obj.span),
1250            properties,
1251            type_annotation: obj
1252                .type_ann
1253                .as_ref()
1254                .map(|_| RawNode::null()),
1255            decorators: None,
1256        }
1257    }
1258
1259    fn convert_array_pattern(&self, arr: &swc::ArrayPat) -> ArrayPattern {
1260        ArrayPattern {
1261            base: self.make_base_node(arr.span),
1262            elements: arr
1263                .elems
1264                .iter()
1265                .map(|e| e.as_ref().map(|p| self.convert_pat(p)))
1266                .collect(),
1267            type_annotation: arr
1268                .type_ann
1269                .as_ref()
1270                .map(|_| RawNode::null()),
1271            decorators: None,
1272        }
1273    }
1274
1275    // ===== AssignmentTarget =====
1276
1277    fn convert_assign_target(&self, target: &swc::AssignTarget) -> PatternLike {
1278        match target {
1279            swc::AssignTarget::Simple(s) => self.convert_simple_assign_target(s),
1280            swc::AssignTarget::Pat(p) => self.convert_assign_target_pat(p),
1281        }
1282    }
1283
1284    fn convert_simple_assign_target(&self, target: &swc::SimpleAssignTarget) -> PatternLike {
1285        match target {
1286            swc::SimpleAssignTarget::Ident(id) => {
1287                PatternLike::Identifier(self.convert_binding_ident(id))
1288            }
1289            swc::SimpleAssignTarget::Member(m) => {
1290                PatternLike::MemberExpression(self.convert_member_expression(m))
1291            }
1292            swc::SimpleAssignTarget::SuperProp(sp) => {
1293                let (property, computed) = self.convert_super_prop(&sp.prop);
1294                PatternLike::MemberExpression(MemberExpression {
1295                    base: self.make_base_node(sp.span),
1296                    object: Box::new(Expression::Super(Super {
1297                        base: self.make_base_node(sp.obj.span),
1298                    })),
1299                    property: Box::new(property),
1300                    computed,
1301                })
1302            }
1303            swc::SimpleAssignTarget::Paren(p) => self.convert_expression_to_pattern(&p.expr),
1304            swc::SimpleAssignTarget::OptChain(o) => PatternLike::Identifier(Identifier {
1305                base: self.make_base_node(o.span),
1306                name: "__unknown_target__".to_string(),
1307                type_annotation: None,
1308                optional: None,
1309                decorators: None,
1310            }),
1311            swc::SimpleAssignTarget::TsAs(e) => self.convert_expression_to_pattern(&e.expr),
1312            swc::SimpleAssignTarget::TsSatisfies(e) => self.convert_expression_to_pattern(&e.expr),
1313            swc::SimpleAssignTarget::TsNonNull(e) => self.convert_expression_to_pattern(&e.expr),
1314            swc::SimpleAssignTarget::TsTypeAssertion(e) => {
1315                self.convert_expression_to_pattern(&e.expr)
1316            }
1317            swc::SimpleAssignTarget::TsInstantiation(e) => {
1318                self.convert_expression_to_pattern(&e.expr)
1319            }
1320            swc::SimpleAssignTarget::Invalid(i) => PatternLike::Identifier(Identifier {
1321                base: self.make_base_node(i.span),
1322                name: "__invalid__".to_string(),
1323                type_annotation: None,
1324                optional: None,
1325                decorators: None,
1326            }),
1327        }
1328    }
1329
1330    fn convert_assign_target_pat(&self, target: &swc::AssignTargetPat) -> PatternLike {
1331        match target {
1332            swc::AssignTargetPat::Array(a) => {
1333                PatternLike::ArrayPattern(self.convert_array_pattern(a))
1334            }
1335            swc::AssignTargetPat::Object(o) => {
1336                PatternLike::ObjectPattern(self.convert_object_pattern(o))
1337            }
1338            swc::AssignTargetPat::Invalid(i) => PatternLike::Identifier(Identifier {
1339                base: self.make_base_node(i.span),
1340                name: "__invalid__".to_string(),
1341                type_annotation: None,
1342                optional: None,
1343                decorators: None,
1344            }),
1345        }
1346    }
1347
1348    fn convert_assignment_expression(&self, assign: &swc::AssignExpr) -> AssignmentExpression {
1349        AssignmentExpression {
1350            base: self.make_base_node(assign.span),
1351            operator: self.convert_assignment_operator(assign.op),
1352            left: Box::new(self.convert_assign_target(&assign.left)),
1353            right: Box::new(self.convert_expression(&assign.right)),
1354        }
1355    }
1356
1357    // ===== Object expression =====
1358
1359    fn convert_object_expression(&self, obj: &swc::ObjectLit) -> ObjectExpression {
1360        ObjectExpression {
1361            base: self.make_base_node(obj.span),
1362            properties: obj
1363                .props
1364                .iter()
1365                .map(|p| self.convert_prop_or_spread(p))
1366                .collect(),
1367        }
1368    }
1369
1370    fn convert_prop_or_spread(&self, prop: &swc::PropOrSpread) -> ObjectExpressionProperty {
1371        match prop {
1372            swc::PropOrSpread::Spread(s) => {
1373                ObjectExpressionProperty::SpreadElement(SpreadElement {
1374                    base: self.make_base_node(s.span()),
1375                    argument: Box::new(self.convert_expression(&s.expr)),
1376                })
1377            }
1378            swc::PropOrSpread::Prop(p) => self.convert_prop(p),
1379        }
1380    }
1381
1382    fn convert_prop(&self, prop: &swc::Prop) -> ObjectExpressionProperty {
1383        match prop {
1384            swc::Prop::Shorthand(id) => {
1385                let ident = self.convert_ident_to_identifier(id);
1386                ObjectExpressionProperty::ObjectProperty(ObjectProperty {
1387                    base: self.make_base_node(id.span),
1388                    key: Box::new(Expression::Identifier(ident.clone())),
1389                    value: Box::new(Expression::Identifier(ident)),
1390                    computed: false,
1391                    shorthand: true,
1392                    decorators: None,
1393                    method: Some(false),
1394                })
1395            }
1396            swc::Prop::KeyValue(kv) => ObjectExpressionProperty::ObjectProperty(ObjectProperty {
1397                base: self.make_base_node(kv.span()),
1398                key: Box::new(self.convert_prop_name(&kv.key)),
1399                value: Box::new(self.convert_expression(&kv.value)),
1400                computed: matches!(kv.key, swc::PropName::Computed(_)),
1401                shorthand: false,
1402                decorators: None,
1403                method: Some(false),
1404            }),
1405            swc::Prop::Getter(g) => ObjectExpressionProperty::ObjectMethod(ObjectMethod {
1406                base: self.make_base_node(g.span),
1407                method: false,
1408                kind: ObjectMethodKind::Get,
1409                key: Box::new(self.convert_prop_name(&g.key)),
1410                params: vec![],
1411                body: g
1412                    .body
1413                    .as_ref()
1414                    .map(|b| self.convert_block_statement(b))
1415                    .unwrap_or_else(|| BlockStatement {
1416                        base: self.make_base_node(g.span),
1417                        body: vec![],
1418                        directives: vec![],
1419                    }),
1420                computed: matches!(g.key, swc::PropName::Computed(_)),
1421                id: None,
1422                generator: false,
1423                is_async: false,
1424                decorators: None,
1425                return_type: g
1426                    .type_ann
1427                    .as_ref()
1428                    .map(|_| RawNode::null()),
1429                type_parameters: None,
1430                predicate: None,
1431            }),
1432            swc::Prop::Setter(s) => ObjectExpressionProperty::ObjectMethod(ObjectMethod {
1433                base: self.make_base_node(s.span),
1434                method: false,
1435                kind: ObjectMethodKind::Set,
1436                key: Box::new(self.convert_prop_name(&s.key)),
1437                params: vec![self.convert_pat(&s.param)],
1438                body: s
1439                    .body
1440                    .as_ref()
1441                    .map(|b| self.convert_block_statement(b))
1442                    .unwrap_or_else(|| BlockStatement {
1443                        base: self.make_base_node(s.span),
1444                        body: vec![],
1445                        directives: vec![],
1446                    }),
1447                computed: matches!(s.key, swc::PropName::Computed(_)),
1448                id: None,
1449                generator: false,
1450                is_async: false,
1451                decorators: None,
1452                return_type: None,
1453                type_parameters: None,
1454                predicate: None,
1455            }),
1456            swc::Prop::Method(m) => ObjectExpressionProperty::ObjectMethod(ObjectMethod {
1457                base: self.make_base_node(m.span()),
1458                method: true,
1459                kind: ObjectMethodKind::Method,
1460                key: Box::new(self.convert_prop_name(&m.key)),
1461                params: self.convert_params(&m.function.params),
1462                body: m
1463                    .function
1464                    .body
1465                    .as_ref()
1466                    .map(|b| self.convert_block_statement(b))
1467                    .unwrap_or_else(|| BlockStatement {
1468                        base: self.make_base_node(m.function.span),
1469                        body: vec![],
1470                        directives: vec![],
1471                    }),
1472                computed: matches!(m.key, swc::PropName::Computed(_)),
1473                id: None,
1474                generator: m.function.is_generator,
1475                is_async: m.function.is_async,
1476                decorators: None,
1477                return_type: m
1478                    .function
1479                    .return_type
1480                    .as_ref()
1481                    .map(|_| RawNode::null()),
1482                type_parameters: m
1483                    .function
1484                    .type_params
1485                    .as_ref()
1486                    .map(|_| RawNode::null()),
1487                predicate: None,
1488            }),
1489            swc::Prop::Assign(a) => {
1490                let ident = self.convert_ident_to_identifier(&a.key);
1491                ObjectExpressionProperty::ObjectProperty(ObjectProperty {
1492                    base: self.make_base_node(a.span),
1493                    key: Box::new(Expression::Identifier(ident.clone())),
1494                    value: Box::new(Expression::AssignmentExpression(AssignmentExpression {
1495                        base: self.make_base_node(a.span),
1496                        operator: AssignmentOperator::Assign,
1497                        left: Box::new(PatternLike::Identifier(ident)),
1498                        right: Box::new(self.convert_expression(&a.value)),
1499                    })),
1500                    computed: false,
1501                    shorthand: true,
1502                    decorators: None,
1503                    method: Some(false),
1504                })
1505            }
1506        }
1507    }
1508
1509    fn convert_array_expression(&self, arr: &swc::ArrayLit) -> ArrayExpression {
1510        ArrayExpression {
1511            base: self.make_base_node(arr.span),
1512            elements: arr
1513                .elems
1514                .iter()
1515                .map(|e| e.as_ref().map(|elem| self.convert_expr_or_spread(elem)))
1516                .collect(),
1517        }
1518    }
1519
1520    fn convert_template_literal(&self, tpl: &swc::Tpl) -> TemplateLiteral {
1521        TemplateLiteral {
1522            base: self.make_base_node(tpl.span),
1523            quasis: tpl
1524                .quasis
1525                .iter()
1526                .map(|q| TemplateElement {
1527                    base: self.make_base_node(q.span),
1528                    value: TemplateElementValue {
1529                        raw: q.raw.to_string(),
1530                        cooked: q.cooked.as_ref().map(|c| wtf8_to_string(c)),
1531                    },
1532                    tail: q.tail,
1533                })
1534                .collect(),
1535            expressions: tpl
1536                .exprs
1537                .iter()
1538                .map(|e| self.convert_expression(e))
1539                .collect(),
1540        }
1541    }
1542
1543    // ===== Class =====
1544
1545    fn convert_class_decl(&self, class: &swc::ClassDecl) -> ClassDeclaration {
1546        let c = &class.class;
1547        ClassDeclaration {
1548            base: self.make_base_node(c.span),
1549            id: Some(self.convert_ident_to_identifier(&class.ident)),
1550            super_class: c
1551                .super_class
1552                .as_ref()
1553                .map(|s| Box::new(self.convert_expression(s))),
1554            body: ClassBody {
1555                base: self.make_base_node(c.span),
1556                body: vec![],
1557            },
1558            decorators: None,
1559            is_abstract: if c.is_abstract { Some(true) } else { None },
1560            declare: if class.declare { Some(true) } else { None },
1561            implements: None,
1562            super_type_parameters: None,
1563            type_parameters: c
1564                .type_params
1565                .as_ref()
1566                .map(|_| RawNode::null()),
1567            mixins: None,
1568        }
1569    }
1570
1571    fn convert_class_expression(&self, class: &swc::ClassExpr) -> ClassExpression {
1572        let c = &class.class;
1573        ClassExpression {
1574            base: self.make_base_node(c.span),
1575            id: class
1576                .ident
1577                .as_ref()
1578                .map(|id| self.convert_ident_to_identifier(id)),
1579            super_class: c
1580                .super_class
1581                .as_ref()
1582                .map(|s| Box::new(self.convert_expression(s))),
1583            body: ClassBody {
1584                base: self.make_base_node(c.span),
1585                body: vec![],
1586            },
1587            decorators: None,
1588            implements: None,
1589            super_type_parameters: None,
1590            type_parameters: c
1591                .type_params
1592                .as_ref()
1593                .map(|_| RawNode::null()),
1594        }
1595    }
1596
1597    // ===== JSX =====
1598
1599    fn convert_jsx_element(&self, el: &swc::JSXElement) -> JSXElement {
1600        let self_closing = el.closing.is_none();
1601        JSXElement {
1602            base: self.make_base_node(el.span),
1603            opening_element: self.convert_jsx_opening_element(&el.opening, self_closing),
1604            closing_element: el
1605                .closing
1606                .as_ref()
1607                .map(|c| self.convert_jsx_closing_element(c)),
1608            children: el
1609                .children
1610                .iter()
1611                .map(|c| self.convert_jsx_child(c))
1612                .collect(),
1613            self_closing: Some(self_closing),
1614        }
1615    }
1616
1617    fn convert_jsx_opening_element(
1618        &self,
1619        el: &swc::JSXOpeningElement,
1620        self_closing: bool,
1621    ) -> JSXOpeningElement {
1622        JSXOpeningElement {
1623            base: self.make_base_node(el.span),
1624            name: self.convert_jsx_element_name(&el.name),
1625            attributes: el
1626                .attrs
1627                .iter()
1628                .map(|a| self.convert_jsx_attr_or_spread(a))
1629                .collect(),
1630            self_closing,
1631            type_parameters: el
1632                .type_args
1633                .as_ref()
1634                .map(|_| RawNode::null()),
1635        }
1636    }
1637
1638    fn convert_jsx_closing_element(&self, el: &swc::JSXClosingElement) -> JSXClosingElement {
1639        JSXClosingElement {
1640            base: self.make_base_node(el.span),
1641            name: self.convert_jsx_element_name(&el.name),
1642        }
1643    }
1644
1645    fn convert_jsx_element_name(&self, name: &swc::JSXElementName) -> JSXElementName {
1646        match name {
1647            swc::JSXElementName::Ident(id) => JSXElementName::JSXIdentifier(JSXIdentifier {
1648                base: self.make_base_node(id.span),
1649                name: id.sym.to_string(),
1650            }),
1651            swc::JSXElementName::JSXMemberExpr(m) => {
1652                JSXElementName::JSXMemberExpression(self.convert_jsx_member_expression(m))
1653            }
1654            swc::JSXElementName::JSXNamespacedName(ns) => {
1655                JSXElementName::JSXNamespacedName(JSXNamespacedName {
1656                    base: self.make_base_node(ns.span()),
1657                    namespace: JSXIdentifier {
1658                        base: self.make_base_node(ns.ns.span),
1659                        name: ns.ns.sym.to_string(),
1660                    },
1661                    name: JSXIdentifier {
1662                        base: self.make_base_node(ns.name.span),
1663                        name: ns.name.sym.to_string(),
1664                    },
1665                })
1666            }
1667        }
1668    }
1669
1670    fn convert_jsx_member_expression(&self, m: &swc::JSXMemberExpr) -> JSXMemberExpression {
1671        JSXMemberExpression {
1672            base: self.make_base_node(m.span()),
1673            object: Box::new(self.convert_jsx_object(&m.obj)),
1674            property: JSXIdentifier {
1675                base: self.make_base_node(m.prop.span),
1676                name: m.prop.sym.to_string(),
1677            },
1678        }
1679    }
1680
1681    fn convert_jsx_object(&self, obj: &swc::JSXObject) -> JSXMemberExprObject {
1682        match obj {
1683            swc::JSXObject::Ident(id) => JSXMemberExprObject::JSXIdentifier(JSXIdentifier {
1684                base: self.make_base_node(id.span),
1685                name: id.sym.to_string(),
1686            }),
1687            swc::JSXObject::JSXMemberExpr(m) => JSXMemberExprObject::JSXMemberExpression(Box::new(
1688                self.convert_jsx_member_expression(m),
1689            )),
1690        }
1691    }
1692
1693    fn convert_jsx_attr_or_spread(&self, attr: &swc::JSXAttrOrSpread) -> JSXAttributeItem {
1694        match attr {
1695            swc::JSXAttrOrSpread::JSXAttr(a) => {
1696                JSXAttributeItem::JSXAttribute(self.convert_jsx_attribute(a))
1697            }
1698            swc::JSXAttrOrSpread::SpreadElement(s) => {
1699                JSXAttributeItem::JSXSpreadAttribute(JSXSpreadAttribute {
1700                    base: self.make_base_node(s.span()),
1701                    argument: Box::new(self.convert_expression(&s.expr)),
1702                })
1703            }
1704        }
1705    }
1706
1707    fn convert_jsx_attribute(&self, attr: &swc::JSXAttr) -> JSXAttribute {
1708        JSXAttribute {
1709            base: self.make_base_node(attr.span),
1710            name: self.convert_jsx_attr_name(&attr.name),
1711            value: attr.value.as_ref().map(|v| self.convert_jsx_attr_value(v)),
1712        }
1713    }
1714
1715    fn convert_jsx_attr_name(&self, name: &swc::JSXAttrName) -> JSXAttributeName {
1716        match name {
1717            swc::JSXAttrName::Ident(id) => JSXAttributeName::JSXIdentifier(JSXIdentifier {
1718                base: self.make_base_node(id.span),
1719                name: id.sym.to_string(),
1720            }),
1721            swc::JSXAttrName::JSXNamespacedName(ns) => {
1722                JSXAttributeName::JSXNamespacedName(JSXNamespacedName {
1723                    base: self.make_base_node(ns.span()),
1724                    namespace: JSXIdentifier {
1725                        base: self.make_base_node(ns.ns.span),
1726                        name: ns.ns.sym.to_string(),
1727                    },
1728                    name: JSXIdentifier {
1729                        base: self.make_base_node(ns.name.span),
1730                        name: ns.name.sym.to_string(),
1731                    },
1732                })
1733            }
1734        }
1735    }
1736
1737    fn convert_jsx_attr_value(&self, value: &swc::JSXAttrValue) -> JSXAttributeValue {
1738        match value {
1739            swc::JSXAttrValue::Str(s) => JSXAttributeValue::StringLiteral(StringLiteral {
1740                base: self.make_base_node(s.span),
1741                value: wtf8_to_string(&s.value),
1742            }),
1743            swc::JSXAttrValue::JSXExprContainer(ec) => {
1744                JSXAttributeValue::JSXExpressionContainer(self.convert_jsx_expr_container(ec))
1745            }
1746            swc::JSXAttrValue::JSXElement(el) => {
1747                JSXAttributeValue::JSXElement(Box::new(self.convert_jsx_element(el)))
1748            }
1749            swc::JSXAttrValue::JSXFragment(frag) => {
1750                JSXAttributeValue::JSXFragment(self.convert_jsx_fragment(frag))
1751            }
1752        }
1753    }
1754
1755    fn convert_jsx_expr_container(&self, ec: &swc::JSXExprContainer) -> JSXExpressionContainer {
1756        JSXExpressionContainer {
1757            base: self.make_base_node(ec.span),
1758            expression: match &ec.expr {
1759                swc::JSXExpr::JSXEmptyExpr(e) => {
1760                    JSXExpressionContainerExpr::JSXEmptyExpression(JSXEmptyExpression {
1761                        base: self.make_base_node(e.span),
1762                    })
1763                }
1764                swc::JSXExpr::Expr(e) => {
1765                    JSXExpressionContainerExpr::Expression(Box::new(self.convert_expression(e)))
1766                }
1767            },
1768        }
1769    }
1770
1771    fn convert_jsx_child(&self, child: &swc::JSXElementChild) -> JSXChild {
1772        match child {
1773            swc::JSXElementChild::JSXText(t) => JSXChild::JSXText(JSXText {
1774                base: self.make_base_node(t.span),
1775                value: t.value.to_string(),
1776            }),
1777            swc::JSXElementChild::JSXExprContainer(ec) => {
1778                JSXChild::JSXExpressionContainer(self.convert_jsx_expr_container(ec))
1779            }
1780            swc::JSXElementChild::JSXSpreadChild(s) => JSXChild::JSXSpreadChild(JSXSpreadChild {
1781                base: self.make_base_node(s.span),
1782                expression: Box::new(self.convert_expression(&s.expr)),
1783            }),
1784            swc::JSXElementChild::JSXElement(el) => {
1785                JSXChild::JSXElement(Box::new(self.convert_jsx_element(el)))
1786            }
1787            swc::JSXElementChild::JSXFragment(frag) => {
1788                JSXChild::JSXFragment(self.convert_jsx_fragment(frag))
1789            }
1790        }
1791    }
1792
1793    fn convert_jsx_fragment(&self, frag: &swc::JSXFragment) -> JSXFragment {
1794        JSXFragment {
1795            base: self.make_base_node(frag.span),
1796            opening_fragment: JSXOpeningFragment {
1797                base: self.make_base_node(frag.opening.span),
1798            },
1799            closing_fragment: JSXClosingFragment {
1800                base: self.make_base_node(frag.closing.span),
1801            },
1802            children: frag
1803                .children
1804                .iter()
1805                .map(|c| self.convert_jsx_child(c))
1806                .collect(),
1807        }
1808    }
1809
1810    // ===== Import/Export =====
1811
1812    fn convert_import_declaration(&self, decl: &swc::ImportDecl) -> ImportDeclaration {
1813        ImportDeclaration {
1814            base: self.make_base_node(decl.span),
1815            specifiers: decl
1816                .specifiers
1817                .iter()
1818                .map(|s| self.convert_import_specifier(s))
1819                .collect(),
1820            source: StringLiteral {
1821                base: self.make_base_node(decl.src.span),
1822                value: wtf8_to_string(&decl.src.value),
1823            },
1824            import_kind: if decl.type_only {
1825                Some(ImportKind::Type)
1826            } else {
1827                Some(ImportKind::Value)
1828            },
1829            assertions: None,
1830            attributes: decl
1831                .with
1832                .as_ref()
1833                .map(|with| self.convert_object_lit_to_import_attributes(with)),
1834        }
1835    }
1836
1837    fn convert_object_lit_to_import_attributes(
1838        &self,
1839        obj: &swc::ObjectLit,
1840    ) -> Vec<ImportAttribute> {
1841        obj.props
1842            .iter()
1843            .filter_map(|prop| {
1844                if let swc::PropOrSpread::Prop(p) = prop {
1845                    if let swc::Prop::KeyValue(kv) = &**p {
1846                        let (key_name, key_span) = match &kv.key {
1847                            swc::PropName::Ident(id) => (id.sym.to_string(), id.span),
1848                            swc::PropName::Str(s) => (wtf8_to_string(&s.value), s.span),
1849                            swc::PropName::Num(n) => (n.value.to_string(), n.span),
1850                            _ => return None,
1851                        };
1852                        if let swc::Expr::Lit(swc::Lit::Str(s)) = &*kv.value {
1853                            return Some(ImportAttribute {
1854                                base: self.make_base_node(kv.span()),
1855                                key: Identifier {
1856                                    base: self.make_base_node(key_span),
1857                                    name: key_name,
1858                                    type_annotation: None,
1859                                    optional: None,
1860                                    decorators: None,
1861                                },
1862                                value: StringLiteral {
1863                                    base: self.make_base_node(s.span),
1864                                    value: wtf8_to_string(&s.value),
1865                                },
1866                            });
1867                        }
1868                    }
1869                }
1870                None
1871            })
1872            .collect()
1873    }
1874
1875    fn convert_import_specifier(&self, spec: &swc::ImportSpecifier) -> ImportSpecifier {
1876        match spec {
1877            swc::ImportSpecifier::Named(s) => {
1878                let local = self.convert_ident_to_identifier(&s.local);
1879                let imported = s
1880                    .imported
1881                    .as_ref()
1882                    .map(|i| match i {
1883                        swc::ModuleExportName::Ident(id) => {
1884                            ModuleExportName::Identifier(self.convert_ident_to_identifier(id))
1885                        }
1886                        swc::ModuleExportName::Str(s) => {
1887                            ModuleExportName::StringLiteral(StringLiteral {
1888                                base: self.make_base_node(s.span),
1889                                value: wtf8_to_string(&s.value),
1890                            })
1891                        }
1892                    })
1893                    .unwrap_or_else(|| ModuleExportName::Identifier(local.clone()));
1894                ImportSpecifier::ImportSpecifier(ImportSpecifierData {
1895                    base: self.make_base_node(s.span),
1896                    local,
1897                    imported,
1898                    import_kind: if s.is_type_only {
1899                        Some(ImportKind::Type)
1900                    } else {
1901                        Some(ImportKind::Value)
1902                    },
1903                })
1904            }
1905            swc::ImportSpecifier::Default(s) => {
1906                ImportSpecifier::ImportDefaultSpecifier(ImportDefaultSpecifierData {
1907                    base: self.make_base_node(s.span),
1908                    local: self.convert_ident_to_identifier(&s.local),
1909                })
1910            }
1911            swc::ImportSpecifier::Namespace(s) => {
1912                ImportSpecifier::ImportNamespaceSpecifier(ImportNamespaceSpecifierData {
1913                    base: self.make_base_node(s.span),
1914                    local: self.convert_ident_to_identifier(&s.local),
1915                })
1916            }
1917        }
1918    }
1919
1920    fn convert_export_decl(&self, decl: &swc::ExportDecl) -> ExportNamedDeclaration {
1921        ExportNamedDeclaration {
1922            base: self.make_base_node(decl.span),
1923            declaration: Some(Box::new(self.convert_decl_to_declaration(&decl.decl))),
1924            specifiers: vec![],
1925            source: None,
1926            export_kind: Some(ExportKind::Value),
1927            assertions: None,
1928            attributes: None,
1929        }
1930    }
1931
1932    fn convert_export_named(&self, decl: &swc::NamedExport) -> ExportNamedDeclaration {
1933        ExportNamedDeclaration {
1934            base: self.make_base_node(decl.span),
1935            declaration: None,
1936            specifiers: decl
1937                .specifiers
1938                .iter()
1939                .map(|s| self.convert_export_specifier(s))
1940                .collect(),
1941            source: decl.src.as_ref().map(|s| StringLiteral {
1942                base: self.make_base_node(s.span),
1943                value: wtf8_to_string(&s.value),
1944            }),
1945            export_kind: if decl.type_only {
1946                Some(ExportKind::Type)
1947            } else {
1948                Some(ExportKind::Value)
1949            },
1950            assertions: None,
1951            attributes: decl
1952                .with
1953                .as_ref()
1954                .map(|with| self.convert_object_lit_to_import_attributes(with)),
1955        }
1956    }
1957
1958    fn convert_export_default_decl(
1959        &self,
1960        decl: &swc::ExportDefaultDecl,
1961    ) -> ExportDefaultDeclaration {
1962        let declaration = match &decl.decl {
1963            swc::DefaultDecl::Fn(f) => {
1964                let func = &f.function;
1965                let body = func
1966                    .body
1967                    .as_ref()
1968                    .map(|b| self.convert_block_statement(b))
1969                    .unwrap_or_else(|| BlockStatement {
1970                        base: self.make_base_node(func.span),
1971                        body: vec![],
1972                        directives: vec![],
1973                    });
1974                ExportDefaultDecl::FunctionDeclaration(FunctionDeclaration {
1975                    base: self.make_base_node(func.span),
1976                    id: f
1977                        .ident
1978                        .as_ref()
1979                        .map(|id| self.convert_ident_to_identifier(id)),
1980                    params: self.convert_params(&func.params),
1981                    body,
1982                    generator: func.is_generator,
1983                    is_async: func.is_async,
1984                    declare: None,
1985                    return_type: func
1986                        .return_type
1987                        .as_ref()
1988                        .map(|_| RawNode::null()),
1989                    type_parameters: func
1990                        .type_params
1991                        .as_ref()
1992                        .map(|_| RawNode::null()),
1993                    predicate: None,
1994                    component_declaration: false,
1995                    hook_declaration: false,
1996                })
1997            }
1998            swc::DefaultDecl::Class(c) => {
1999                let class = &c.class;
2000                ExportDefaultDecl::ClassDeclaration(ClassDeclaration {
2001                    base: self.make_base_node(class.span),
2002                    id: c
2003                        .ident
2004                        .as_ref()
2005                        .map(|id| self.convert_ident_to_identifier(id)),
2006                    super_class: class
2007                        .super_class
2008                        .as_ref()
2009                        .map(|s| Box::new(self.convert_expression(s))),
2010                    body: ClassBody {
2011                        base: self.make_base_node(class.span),
2012                        body: vec![],
2013                    },
2014                    decorators: None,
2015                    is_abstract: if class.is_abstract { Some(true) } else { None },
2016                    declare: None,
2017                    implements: None,
2018                    super_type_parameters: None,
2019                    type_parameters: class
2020                        .type_params
2021                        .as_ref()
2022                        .map(|_| RawNode::null()),
2023                    mixins: None,
2024                })
2025            }
2026            swc::DefaultDecl::TsInterfaceDecl(_) => {
2027                ExportDefaultDecl::Expression(Box::new(Expression::NullLiteral(NullLiteral {
2028                    base: self.make_base_node(decl.span),
2029                })))
2030            }
2031        };
2032        ExportDefaultDeclaration {
2033            base: self.make_base_node(decl.span),
2034            declaration: Box::new(declaration),
2035            export_kind: None,
2036        }
2037    }
2038
2039    fn convert_export_default_expr(
2040        &self,
2041        decl: &swc::ExportDefaultExpr,
2042    ) -> ExportDefaultDeclaration {
2043        ExportDefaultDeclaration {
2044            base: self.make_base_node(decl.span),
2045            declaration: Box::new(ExportDefaultDecl::Expression(Box::new(
2046                self.convert_expression(&decl.expr),
2047            ))),
2048            export_kind: None,
2049        }
2050    }
2051
2052    fn convert_export_all(&self, decl: &swc::ExportAll) -> ExportAllDeclaration {
2053        ExportAllDeclaration {
2054            base: self.make_base_node(decl.span),
2055            source: StringLiteral {
2056                base: self.make_base_node(decl.src.span),
2057                value: wtf8_to_string(&decl.src.value),
2058            },
2059            export_kind: if decl.type_only {
2060                Some(ExportKind::Type)
2061            } else {
2062                Some(ExportKind::Value)
2063            },
2064            assertions: None,
2065            attributes: decl
2066                .with
2067                .as_ref()
2068                .map(|with| self.convert_object_lit_to_import_attributes(with)),
2069        }
2070    }
2071
2072    fn convert_decl_to_declaration(&self, decl: &swc::Decl) -> Declaration {
2073        match decl {
2074            swc::Decl::Var(v) => {
2075                Declaration::VariableDeclaration(self.convert_variable_declaration(v))
2076            }
2077            swc::Decl::Fn(f) => Declaration::FunctionDeclaration(self.convert_fn_decl(f)),
2078            swc::Decl::Class(c) => Declaration::ClassDeclaration(self.convert_class_decl(c)),
2079            swc::Decl::TsTypeAlias(d) => {
2080                Declaration::TSTypeAliasDeclaration(self.convert_ts_type_alias(d))
2081            }
2082            swc::Decl::TsInterface(d) => {
2083                Declaration::TSInterfaceDeclaration(self.convert_ts_interface(d))
2084            }
2085            swc::Decl::TsEnum(d) => Declaration::TSEnumDeclaration(self.convert_ts_enum(d)),
2086            swc::Decl::TsModule(d) => Declaration::TSModuleDeclaration(self.convert_ts_module(d)),
2087            swc::Decl::Using(u) => Declaration::VariableDeclaration(self.convert_using_decl(u)),
2088        }
2089    }
2090
2091    fn convert_export_specifier(&self, spec: &swc::ExportSpecifier) -> ExportSpecifier {
2092        match spec {
2093            swc::ExportSpecifier::Named(s) => {
2094                let local = self.convert_module_export_name(&s.orig);
2095                let exported = s
2096                    .exported
2097                    .as_ref()
2098                    .map(|e| self.convert_module_export_name(e))
2099                    .unwrap_or_else(|| local.clone());
2100                ExportSpecifier::ExportSpecifier(ExportSpecifierData {
2101                    base: self.make_base_node(s.span),
2102                    local,
2103                    exported,
2104                    export_kind: if s.is_type_only {
2105                        Some(ExportKind::Type)
2106                    } else {
2107                        Some(ExportKind::Value)
2108                    },
2109                })
2110            }
2111            swc::ExportSpecifier::Default(s) => {
2112                ExportSpecifier::ExportDefaultSpecifier(ExportDefaultSpecifierData {
2113                    base: self.make_base_node(s.exported.span),
2114                    exported: self.convert_ident_to_identifier(&s.exported),
2115                })
2116            }
2117            swc::ExportSpecifier::Namespace(s) => {
2118                ExportSpecifier::ExportNamespaceSpecifier(ExportNamespaceSpecifierData {
2119                    base: self.make_base_node(s.span),
2120                    exported: self.convert_module_export_name(&s.name),
2121                })
2122            }
2123        }
2124    }
2125
2126    fn convert_module_export_name(&self, name: &swc::ModuleExportName) -> ModuleExportName {
2127        match name {
2128            swc::ModuleExportName::Ident(id) => {
2129                ModuleExportName::Identifier(self.convert_ident_to_identifier(id))
2130            }
2131            swc::ModuleExportName::Str(s) => ModuleExportName::StringLiteral(StringLiteral {
2132                base: self.make_base_node(s.span),
2133                value: wtf8_to_string(&s.value),
2134            }),
2135        }
2136    }
2137
2138    // ===== TS declarations =====
2139
2140    fn convert_ts_type_alias(&self, d: &swc::TsTypeAliasDecl) -> TSTypeAliasDeclaration {
2141        TSTypeAliasDeclaration {
2142            base: self.make_base_node(d.span),
2143            id: self.convert_ident_to_identifier(&d.id),
2144            type_annotation: RawNode::null(),
2145            type_parameters: d
2146                .type_params
2147                .as_ref()
2148                .map(|_| RawNode::null()),
2149            declare: if d.declare { Some(true) } else { None },
2150        }
2151    }
2152
2153    fn convert_ts_interface(&self, d: &swc::TsInterfaceDecl) -> TSInterfaceDeclaration {
2154        TSInterfaceDeclaration {
2155            base: self.make_base_node(d.span),
2156            id: self.convert_ident_to_identifier(&d.id),
2157            body: RawNode::null(),
2158            type_parameters: d
2159                .type_params
2160                .as_ref()
2161                .map(|_| RawNode::null()),
2162            extends: if d.extends.is_empty() {
2163                None
2164            } else {
2165                Some(vec![])
2166            },
2167            declare: if d.declare { Some(true) } else { None },
2168        }
2169    }
2170
2171    fn convert_ts_enum(&self, d: &swc::TsEnumDecl) -> TSEnumDeclaration {
2172        TSEnumDeclaration {
2173            base: self.make_base_node(d.span),
2174            id: self.convert_ident_to_identifier(&d.id),
2175            members: vec![],
2176            declare: if d.declare { Some(true) } else { None },
2177            is_const: if d.is_const { Some(true) } else { None },
2178        }
2179    }
2180
2181    fn convert_ts_module(&self, d: &swc::TsModuleDecl) -> TSModuleDeclaration {
2182        TSModuleDeclaration {
2183            base: self.make_base_node(d.span),
2184            id: RawNode::null(),
2185            body: RawNode::null(),
2186            declare: if d.declare { Some(true) } else { None },
2187            global: if d.global { Some(true) } else { None },
2188        }
2189    }
2190
2191    // ===== TS type JSON (binding ident annotations) =====
2192
2193    fn convert_ts_type_to_json(&self, ty: &swc::TsType) -> Option<serde_json::Value> {
2194        match ty {
2195            swc::TsType::TsKeywordType(k) if k.kind == swc::TsKeywordTypeKind::TsNumberKeyword => {
2196                Some(serde_json::json!({ "type": "TSNumberKeyword" }))
2197            }
2198            // Skip generics: `convert_ts_type_annotation_from_json` ignores
2199            // type params, so silently emitting `Foo` for `Foo<T>` loses
2200            // information. Fall back to `Null` instead.
2201            swc::TsType::TsTypeRef(r) if r.type_params.is_none() => match &r.type_name {
2202                swc::TsEntityName::Ident(id) => Some(serde_json::json!({
2203                    "type": "TSTypeReference",
2204                    "typeName": {
2205                        "type": "Identifier",
2206                        "name": id.sym.to_string()
2207                    }
2208                })),
2209                _ => None,
2210            },
2211            _ => None,
2212        }
2213    }
2214
2215    fn convert_ts_type_ann_to_json(&self, ann: &swc::TsTypeAnn) -> Option<serde_json::Value> {
2216        Some(serde_json::json!({
2217            "type": "TSTypeAnnotation",
2218            "typeAnnotation": self.convert_ts_type_to_json(&ann.type_ann)?,
2219        }))
2220    }
2221
2222    // ===== Identifiers =====
2223
2224    fn convert_ident_to_identifier(&self, id: &swc::Ident) -> Identifier {
2225        Identifier {
2226            base: self.make_base_node(id.span),
2227            name: id.sym.to_string(),
2228            type_annotation: None,
2229            optional: if id.optional { Some(true) } else { None },
2230            decorators: None,
2231        }
2232    }
2233
2234    fn convert_binding_ident(&self, id: &swc::BindingIdent) -> Identifier {
2235        Identifier {
2236            base: self.make_base_node(id.id.span),
2237            name: id.id.sym.to_string(),
2238            type_annotation: id.type_ann.as_ref().map(|ann| {
2239                RawNode::from_value(
2240                    &self
2241                        .convert_ts_type_ann_to_json(ann)
2242                        .unwrap_or(serde_json::Value::Null),
2243                )
2244            }),
2245            optional: if id.id.optional { Some(true) } else { None },
2246            decorators: None,
2247        }
2248    }
2249
2250    fn convert_prop_name(&self, key: &swc::PropName) -> Expression {
2251        match key {
2252            swc::PropName::Ident(id) => Expression::Identifier(Identifier {
2253                base: self.make_base_node(id.span),
2254                name: id.sym.to_string(),
2255                type_annotation: None,
2256                optional: None,
2257                decorators: None,
2258            }),
2259            swc::PropName::Str(s) => Expression::StringLiteral(StringLiteral {
2260                base: self.make_base_node(s.span),
2261                value: wtf8_to_string(&s.value),
2262            }),
2263            swc::PropName::Num(n) => Expression::NumericLiteral(NumericLiteral {
2264                base: self.make_base_node(n.span),
2265                value: n.value,
2266                extra: None,
2267            }),
2268            swc::PropName::Computed(c) => self.convert_expression(&c.expr),
2269            swc::PropName::BigInt(b) => Expression::BigIntLiteral(BigIntLiteral {
2270                base: self.make_base_node(b.span),
2271                value: b.value.to_string(),
2272            }),
2273        }
2274    }
2275
2276    // ===== Operators =====
2277
2278    fn convert_binary_operator(&self, op: swc::BinaryOp) -> BinaryOperator {
2279        match op {
2280            swc::BinaryOp::EqEq => BinaryOperator::Eq,
2281            swc::BinaryOp::NotEq => BinaryOperator::Neq,
2282            swc::BinaryOp::EqEqEq => BinaryOperator::StrictEq,
2283            swc::BinaryOp::NotEqEq => BinaryOperator::StrictNeq,
2284            swc::BinaryOp::Lt => BinaryOperator::Lt,
2285            swc::BinaryOp::LtEq => BinaryOperator::Lte,
2286            swc::BinaryOp::Gt => BinaryOperator::Gt,
2287            swc::BinaryOp::GtEq => BinaryOperator::Gte,
2288            swc::BinaryOp::LShift => BinaryOperator::Shl,
2289            swc::BinaryOp::RShift => BinaryOperator::Shr,
2290            swc::BinaryOp::ZeroFillRShift => BinaryOperator::UShr,
2291            swc::BinaryOp::Add => BinaryOperator::Add,
2292            swc::BinaryOp::Sub => BinaryOperator::Sub,
2293            swc::BinaryOp::Mul => BinaryOperator::Mul,
2294            swc::BinaryOp::Div => BinaryOperator::Div,
2295            swc::BinaryOp::Mod => BinaryOperator::Rem,
2296            swc::BinaryOp::Exp => BinaryOperator::Exp,
2297            swc::BinaryOp::BitOr => BinaryOperator::BitOr,
2298            swc::BinaryOp::BitXor => BinaryOperator::BitXor,
2299            swc::BinaryOp::BitAnd => BinaryOperator::BitAnd,
2300            swc::BinaryOp::In => BinaryOperator::In,
2301            swc::BinaryOp::InstanceOf => BinaryOperator::Instanceof,
2302            swc::BinaryOp::LogicalOr
2303            | swc::BinaryOp::LogicalAnd
2304            | swc::BinaryOp::NullishCoalescing => BinaryOperator::Eq,
2305        }
2306    }
2307
2308    fn try_convert_logical_operator(&self, op: swc::BinaryOp) -> Option<LogicalOperator> {
2309        match op {
2310            swc::BinaryOp::LogicalOr => Some(LogicalOperator::Or),
2311            swc::BinaryOp::LogicalAnd => Some(LogicalOperator::And),
2312            swc::BinaryOp::NullishCoalescing => Some(LogicalOperator::NullishCoalescing),
2313            _ => None,
2314        }
2315    }
2316
2317    fn convert_unary_operator(&self, op: swc::UnaryOp) -> UnaryOperator {
2318        match op {
2319            swc::UnaryOp::Minus => UnaryOperator::Neg,
2320            swc::UnaryOp::Plus => UnaryOperator::Plus,
2321            swc::UnaryOp::Bang => UnaryOperator::Not,
2322            swc::UnaryOp::Tilde => UnaryOperator::BitNot,
2323            swc::UnaryOp::TypeOf => UnaryOperator::TypeOf,
2324            swc::UnaryOp::Void => UnaryOperator::Void,
2325            swc::UnaryOp::Delete => UnaryOperator::Delete,
2326        }
2327    }
2328
2329    fn convert_update_operator(&self, op: swc::UpdateOp) -> UpdateOperator {
2330        match op {
2331            swc::UpdateOp::PlusPlus => UpdateOperator::Increment,
2332            swc::UpdateOp::MinusMinus => UpdateOperator::Decrement,
2333        }
2334    }
2335
2336    fn convert_assignment_operator(&self, op: swc::AssignOp) -> AssignmentOperator {
2337        match op {
2338            swc::AssignOp::Assign => AssignmentOperator::Assign,
2339            swc::AssignOp::AddAssign => AssignmentOperator::AddAssign,
2340            swc::AssignOp::SubAssign => AssignmentOperator::SubAssign,
2341            swc::AssignOp::MulAssign => AssignmentOperator::MulAssign,
2342            swc::AssignOp::DivAssign => AssignmentOperator::DivAssign,
2343            swc::AssignOp::ModAssign => AssignmentOperator::RemAssign,
2344            swc::AssignOp::ExpAssign => AssignmentOperator::ExpAssign,
2345            swc::AssignOp::LShiftAssign => AssignmentOperator::ShlAssign,
2346            swc::AssignOp::RShiftAssign => AssignmentOperator::ShrAssign,
2347            swc::AssignOp::ZeroFillRShiftAssign => AssignmentOperator::UShrAssign,
2348            swc::AssignOp::BitOrAssign => AssignmentOperator::BitOrAssign,
2349            swc::AssignOp::BitXorAssign => AssignmentOperator::BitXorAssign,
2350            swc::AssignOp::BitAndAssign => AssignmentOperator::BitAndAssign,
2351            swc::AssignOp::OrAssign => AssignmentOperator::OrAssign,
2352            swc::AssignOp::AndAssign => AssignmentOperator::AndAssign,
2353            swc::AssignOp::NullishAssign => AssignmentOperator::NullishAssign,
2354        }
2355    }
2356}