oxc_codegen/
gen.rs

1use std::ops::Not;
2
3use cow_utils::CowUtils;
4
5use oxc_ast::ast::*;
6use oxc_span::GetSpan;
7use oxc_syntax::{
8    operator::UnaryOperator,
9    precedence::{GetPrecedence, Precedence},
10};
11
12use crate::{
13    Codegen, Context, Operator, Quote,
14    binary_expr_visitor::{BinaryExpressionVisitor, Binaryish, BinaryishOperator},
15};
16
17const PURE_COMMENT: &str = "/* @__PURE__ */ ";
18const NO_SIDE_EFFECTS_NEW_LINE_COMMENT: &str = "/* @__NO_SIDE_EFFECTS__ */\n";
19const NO_SIDE_EFFECTS_COMMENT: &str = "/* @__NO_SIDE_EFFECTS__ */ ";
20
21/// Generate source code for an AST node.
22pub trait Gen: GetSpan {
23    /// Generate code for an AST node.
24    fn r#gen(&self, p: &mut Codegen, ctx: Context);
25
26    /// Generate code for an AST node. Alias for `gen`.
27    #[inline]
28    fn print(&self, p: &mut Codegen, ctx: Context) {
29        self.r#gen(p, ctx);
30    }
31}
32
33/// Generate source code for an expression.
34pub trait GenExpr: GetSpan {
35    /// Generate code for an expression, respecting operator precedence.
36    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context);
37
38    /// Generate code for an expression, respecting operator precedence. Alias for `gen_expr`.
39    #[inline]
40    fn print_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
41        self.gen_expr(p, precedence, ctx);
42    }
43}
44
45impl Gen for Program<'_> {
46    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
47        p.is_jsx = self.source_type.is_jsx();
48
49        // Allow for inserting comments to the top of the file.
50        p.print_comments_at(0);
51        if let Some(hashbang) = &self.hashbang {
52            hashbang.print(p, ctx);
53        }
54        p.print_directives_and_statements(&self.directives, &self.body, ctx);
55        p.print_semicolon_if_needed();
56        // Print trailing statement comments.
57        p.print_comments_at(self.span.end);
58    }
59}
60
61impl Gen for Hashbang<'_> {
62    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
63        p.print_str("#!");
64        p.print_str(self.value.as_str());
65        p.print_hard_newline();
66    }
67}
68
69impl Gen for Directive<'_> {
70    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
71        p.print_comments_at(self.span.start);
72        p.add_source_mapping(self.span);
73        p.print_indent();
74        // A Use Strict Directive may not contain an EscapeSequence or LineContinuation.
75        // So here should print original `directive` value, the `expression` value is escaped str.
76        // See https://github.com/babel/babel/blob/v7.26.2/packages/babel-generator/src/generators/base.ts#L64
77        let directive = self.directive.as_str();
78
79        let mut bytes = directive.as_bytes().iter();
80        let mut quote = p.quote;
81        while let Some(&b) = bytes.next() {
82            match b {
83                b'"' => {
84                    quote = Quote::Single;
85                    break;
86                }
87                b'\'' => {
88                    quote = Quote::Double;
89                    break;
90                }
91                b'\\' => {
92                    bytes.next();
93                }
94                _ => {}
95            }
96        }
97        quote.print(p);
98        p.print_str(directive);
99        quote.print(p);
100        p.print_ascii_byte(b';');
101        p.print_soft_newline();
102    }
103}
104
105impl Gen for Statement<'_> {
106    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
107        match self {
108            // Most common statements first (based on parser order and frequency)
109            Self::BlockStatement(stmt) => {
110                p.print_comments_at(stmt.span.start);
111                stmt.print(p, ctx);
112            }
113            Self::ExpressionStatement(stmt) => stmt.print(p, ctx),
114            Self::VariableDeclaration(decl) => {
115                p.print_comments_at(decl.span.start);
116                p.print_indent();
117                decl.print(p, ctx);
118                p.print_semicolon_after_statement();
119            }
120            Self::IfStatement(stmt) => stmt.print(p, ctx),
121            Self::ReturnStatement(stmt) => stmt.print(p, ctx),
122            Self::FunctionDeclaration(decl) => {
123                p.print_comments_at(decl.span.start);
124                if decl.pure && p.options.print_annotation_comment() {
125                    p.print_indent();
126                    p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
127                }
128                p.print_indent();
129                decl.print(p, ctx);
130                p.print_soft_newline();
131            }
132            Self::ForStatement(stmt) => stmt.print(p, ctx),
133            Self::WhileStatement(stmt) => stmt.print(p, ctx),
134            Self::DoWhileStatement(stmt) => stmt.print(p, ctx),
135            Self::SwitchStatement(stmt) => stmt.print(p, ctx),
136            Self::BreakStatement(stmt) => stmt.print(p, ctx),
137            Self::ContinueStatement(stmt) => stmt.print(p, ctx),
138            Self::TryStatement(stmt) => stmt.print(p, ctx),
139            Self::ThrowStatement(stmt) => stmt.print(p, ctx),
140            Self::ForInStatement(stmt) => stmt.print(p, ctx),
141            Self::ForOfStatement(stmt) => stmt.print(p, ctx),
142            Self::ClassDeclaration(decl) => {
143                p.print_comments_at(decl.span.start);
144                p.print_indent();
145                decl.print(p, ctx);
146                p.print_soft_newline();
147            }
148            Self::LabeledStatement(stmt) => stmt.print(p, ctx),
149            Self::EmptyStatement(stmt) => stmt.print(p, ctx),
150            Self::ImportDeclaration(decl) => decl.print(p, ctx),
151            Self::ExportNamedDeclaration(decl) => decl.print(p, ctx),
152            Self::ExportDefaultDeclaration(decl) => decl.print(p, ctx),
153            Self::ExportAllDeclaration(decl) => decl.print(p, ctx),
154            Self::WithStatement(stmt) => stmt.print(p, ctx),
155            Self::DebuggerStatement(stmt) => stmt.print(p, ctx),
156            // TypeScript-specific (less common)
157            Self::TSModuleDeclaration(decl) => {
158                p.print_comments_at(decl.span.start);
159                p.print_indent();
160                decl.print(p, ctx);
161                p.print_soft_newline();
162            }
163            Self::TSGlobalDeclaration(decl) => {
164                p.print_comments_at(decl.span.start);
165                p.print_indent();
166                decl.print(p, ctx);
167                p.print_soft_newline();
168            }
169            Self::TSTypeAliasDeclaration(decl) => {
170                p.print_indent();
171                p.print_comments_at(decl.span.start);
172                decl.print(p, ctx);
173                p.print_semicolon_after_statement();
174            }
175            Self::TSInterfaceDeclaration(decl) => {
176                p.print_indent();
177                p.print_comments_at(decl.span.start);
178                decl.print(p, ctx);
179                p.print_soft_newline();
180            }
181            Self::TSEnumDeclaration(decl) => {
182                p.print_indent();
183                p.print_comments_at(decl.span.start);
184                decl.print(p, ctx);
185                p.print_soft_newline();
186            }
187            Self::TSExportAssignment(decl) => decl.print(p, ctx),
188            Self::TSNamespaceExportDeclaration(decl) => decl.print(p, ctx),
189            Self::TSImportEqualsDeclaration(decl) => {
190                p.print_indent();
191                p.print_comments_at(decl.span.start);
192                decl.print(p, ctx);
193                p.print_semicolon_after_statement();
194            }
195        }
196    }
197}
198
199impl Gen for ExpressionStatement<'_> {
200    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
201        p.print_comments_at(self.span.start);
202        if !p.options.minify && (p.indent > 0 || p.print_next_indent_as_space) {
203            p.add_source_mapping(self.span);
204            p.print_indent();
205        }
206        p.start_of_stmt = p.code_len();
207        p.print_expression(&self.expression);
208        p.print_semicolon_after_statement();
209    }
210}
211
212impl Gen for IfStatement<'_> {
213    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
214        p.print_comments_at(self.span.start);
215        p.add_source_mapping(self.span);
216        p.print_indent();
217        print_if(self, p, ctx);
218    }
219}
220
221fn print_if(if_stmt: &IfStatement<'_>, p: &mut Codegen, ctx: Context) {
222    p.print_space_before_identifier();
223    p.print_str("if");
224    p.print_soft_space();
225    p.print_ascii_byte(b'(');
226    p.print_expression(&if_stmt.test);
227    p.print_ascii_byte(b')');
228
229    match &if_stmt.consequent {
230        Statement::BlockStatement(block) => {
231            p.print_soft_space();
232            p.print_block_statement(block, ctx);
233            if if_stmt.alternate.is_some() {
234                p.print_soft_space();
235            } else {
236                p.print_soft_newline();
237            }
238        }
239        stmt if wrap_to_avoid_ambiguous_else(stmt) => {
240            p.print_soft_space();
241            p.print_block_start(stmt.span());
242            stmt.print(p, ctx);
243            p.needs_semicolon = false;
244            p.print_block_end(stmt.span());
245            if if_stmt.alternate.is_some() {
246                p.print_soft_space();
247            } else {
248                p.print_soft_newline();
249            }
250        }
251        stmt => {
252            p.print_body(stmt, false, ctx);
253            if if_stmt.alternate.is_some() {
254                p.print_indent();
255            }
256        }
257    }
258    if let Some(alternate) = if_stmt.alternate.as_ref() {
259        p.print_semicolon_if_needed();
260        p.print_space_before_identifier();
261        p.print_str("else");
262        match alternate {
263            Statement::BlockStatement(block) => {
264                p.print_soft_space();
265                p.print_block_statement(block, ctx);
266                p.print_soft_newline();
267            }
268            Statement::IfStatement(if_stmt) => {
269                p.print_hard_space();
270                print_if(if_stmt, p, ctx);
271            }
272            stmt => p.print_body(stmt, true, ctx),
273        }
274    }
275}
276
277// <https://github.com/evanw/esbuild/blob/e6a8169c3a574f4c67d4cdd5f31a938b53eb7421/internal/js_printer/js_printer.go#L3444>
278fn wrap_to_avoid_ambiguous_else(stmt: &Statement) -> bool {
279    let mut current = stmt;
280    loop {
281        current = match current {
282            Statement::IfStatement(if_stmt) => {
283                if let Some(stmt) = &if_stmt.alternate {
284                    stmt
285                } else {
286                    return true;
287                }
288            }
289            Statement::ForStatement(for_stmt) => &for_stmt.body,
290            Statement::ForOfStatement(for_of_stmt) => &for_of_stmt.body,
291            Statement::ForInStatement(for_in_stmt) => &for_in_stmt.body,
292            Statement::WhileStatement(while_stmt) => &while_stmt.body,
293            Statement::WithStatement(with_stmt) => &with_stmt.body,
294            Statement::LabeledStatement(labeled_stmt) => &labeled_stmt.body,
295            _ => return false,
296        }
297    }
298}
299
300impl Gen for BlockStatement<'_> {
301    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
302        p.print_indent();
303        p.print_block_statement(self, ctx);
304        p.print_soft_newline();
305    }
306}
307
308impl Gen for ForStatement<'_> {
309    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
310        p.print_comments_at(self.span.start);
311        p.add_source_mapping(self.span);
312        p.print_indent();
313        p.print_space_before_identifier();
314        p.print_str("for");
315        p.print_soft_space();
316        p.print_ascii_byte(b'(');
317
318        if let Some(init) = &self.init {
319            init.print(p, Context::FORBID_IN);
320        }
321
322        p.print_semicolon();
323
324        if let Some(test) = self.test.as_ref() {
325            p.print_soft_space();
326            p.print_expression(test);
327        }
328
329        p.print_semicolon();
330
331        if let Some(update) = self.update.as_ref() {
332            p.print_soft_space();
333            p.print_expression(update);
334        }
335
336        p.print_ascii_byte(b')');
337        p.print_body(&self.body, false, ctx);
338    }
339}
340
341impl Gen for ForInStatement<'_> {
342    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
343        p.print_comments_at(self.span.start);
344        p.add_source_mapping(self.span);
345        p.print_indent();
346        p.print_space_before_identifier();
347        p.print_str("for");
348        p.print_soft_space();
349        p.print_ascii_byte(b'(');
350        self.left.print(p, Context::FORBID_IN);
351        p.print_soft_space();
352        p.print_space_before_identifier();
353        p.print_str("in");
354        p.print_soft_space();
355        p.print_expression(&self.right);
356        p.print_ascii_byte(b')');
357        p.print_body(&self.body, false, ctx);
358    }
359}
360
361impl Gen for ForOfStatement<'_> {
362    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
363        p.print_comments_at(self.span.start);
364        p.add_source_mapping(self.span);
365        p.print_indent();
366        p.print_space_before_identifier();
367        p.print_str("for");
368        if self.r#await {
369            p.print_str(" await");
370        }
371        p.print_soft_space();
372        p.print_ascii_byte(b'(');
373        self.left.print(p, ctx);
374        p.print_soft_space();
375        p.print_space_before_identifier();
376        p.print_str("of");
377        p.print_soft_space();
378        self.right.print_expr(p, Precedence::Comma, Context::empty());
379        p.print_ascii_byte(b')');
380        p.print_body(&self.body, false, ctx);
381    }
382}
383
384impl Gen for ForStatementInit<'_> {
385    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
386        match self {
387            Self::VariableDeclaration(var) => var.print(p, ctx),
388            _ => self.to_expression().print_expr(p, Precedence::Lowest, ctx),
389        }
390    }
391}
392
393impl Gen for ForStatementLeft<'_> {
394    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
395        match self {
396            ForStatementLeft::VariableDeclaration(var) => var.print(p, ctx),
397            ForStatementLeft::AssignmentTargetIdentifier(identifier) => {
398                let wrap = identifier.name == "async";
399                p.wrap(wrap, |p| self.to_assignment_target().print(p, ctx));
400            }
401            match_assignment_target!(ForStatementLeft) => {
402                p.wrap(false, |p| self.to_assignment_target().print(p, ctx));
403            }
404        }
405    }
406}
407
408impl Gen for WhileStatement<'_> {
409    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
410        p.print_comments_at(self.span.start);
411        p.add_source_mapping(self.span);
412        p.print_indent();
413        p.print_space_before_identifier();
414        p.print_str("while");
415        p.print_soft_space();
416        p.print_ascii_byte(b'(');
417        p.print_expression(&self.test);
418        p.print_ascii_byte(b')');
419        p.print_body(&self.body, false, ctx);
420    }
421}
422
423impl Gen for DoWhileStatement<'_> {
424    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
425        p.print_comments_at(self.span.start);
426        p.add_source_mapping(self.span);
427        p.print_indent();
428        p.print_space_before_identifier();
429        p.print_str("do");
430        match &self.body {
431            Statement::BlockStatement(block) => {
432                p.print_soft_space();
433                p.print_block_statement(block, ctx);
434                p.print_soft_space();
435            }
436            Statement::EmptyStatement(s) => s.print(p, ctx),
437            _ => {
438                p.print_soft_newline();
439                p.indent();
440                self.body.print(p, ctx);
441                p.print_semicolon_if_needed();
442                p.dedent();
443                p.print_indent();
444            }
445        }
446        p.print_str("while");
447        p.print_soft_space();
448        p.print_ascii_byte(b'(');
449        p.print_expression(&self.test);
450        p.print_ascii_byte(b')');
451        p.print_semicolon_after_statement();
452    }
453}
454
455impl Gen for EmptyStatement {
456    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
457        p.print_comments_at(self.span.start);
458        p.add_source_mapping(self.span);
459        p.print_indent();
460        p.print_semicolon();
461        p.print_soft_newline();
462    }
463}
464
465impl Gen for ContinueStatement<'_> {
466    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
467        p.print_comments_at(self.span.start);
468        p.add_source_mapping(self.span);
469        p.print_indent();
470        p.print_space_before_identifier();
471        p.print_str("continue");
472        if let Some(label) = &self.label {
473            p.print_soft_space();
474            label.print(p, ctx);
475        }
476        p.print_semicolon_after_statement();
477    }
478}
479
480impl Gen for BreakStatement<'_> {
481    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
482        p.print_comments_at(self.span.start);
483        p.add_source_mapping(self.span);
484        p.print_indent();
485        p.print_space_before_identifier();
486        p.print_str("break");
487        if let Some(label) = &self.label {
488            p.print_soft_space();
489            label.print(p, ctx);
490        }
491        p.print_semicolon_after_statement();
492    }
493}
494
495impl Gen for SwitchStatement<'_> {
496    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
497        p.print_comments_at(self.span.start);
498        p.add_source_mapping(self.span);
499        p.print_indent();
500        p.print_space_before_identifier();
501        p.print_str("switch");
502        p.print_soft_space();
503        p.print_ascii_byte(b'(');
504        p.print_expression(&self.discriminant);
505        p.print_ascii_byte(b')');
506        p.print_soft_space();
507        p.print_curly_braces(self.span, self.cases.is_empty(), |p| {
508            for case in &self.cases {
509                case.print(p, ctx);
510            }
511        });
512        p.print_soft_newline();
513        p.needs_semicolon = false;
514    }
515}
516
517impl Gen for SwitchCase<'_> {
518    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
519        p.print_semicolon_if_needed();
520        p.print_indent();
521        p.add_source_mapping(self.span);
522        match &self.test {
523            Some(test) => {
524                p.print_str("case");
525                p.print_soft_space();
526                p.print_expression(test);
527            }
528            None => p.print_str("default"),
529        }
530        p.print_colon();
531
532        if self.consequent.len() == 1 {
533            p.print_body(&self.consequent[0], false, ctx);
534            return;
535        }
536
537        p.print_soft_newline();
538        p.indent();
539        for item in &self.consequent {
540            p.print_semicolon_if_needed();
541            item.print(p, ctx);
542        }
543        p.dedent();
544    }
545}
546
547impl Gen for ReturnStatement<'_> {
548    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
549        p.print_comments_at(self.span.start);
550        p.add_source_mapping(self.span);
551        p.print_indent();
552        p.print_space_before_identifier();
553        p.print_str("return");
554        if let Some(arg) = &self.argument {
555            p.print_soft_space();
556            p.print_expression(arg);
557        }
558        p.print_semicolon_after_statement();
559    }
560}
561
562impl Gen for LabeledStatement<'_> {
563    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
564        p.print_comments_at(self.span.start);
565        if !p.options.minify && (p.indent > 0 || p.print_next_indent_as_space) {
566            p.add_source_mapping(self.span);
567            p.print_indent();
568        }
569        p.print_space_before_identifier();
570        self.label.print(p, ctx);
571        p.print_colon();
572        p.print_body(&self.body, false, ctx);
573    }
574}
575
576impl Gen for TryStatement<'_> {
577    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
578        p.print_comments_at(self.span.start);
579        p.add_source_mapping(self.span);
580        p.print_indent();
581        p.print_space_before_identifier();
582        p.print_str("try");
583        p.print_soft_space();
584        p.print_block_statement(&self.block, ctx);
585        if let Some(handler) = &self.handler {
586            handler.r#gen(p, ctx);
587        }
588        if let Some(finalizer) = &self.finalizer {
589            p.print_soft_space();
590            p.print_str("finally");
591            p.print_soft_space();
592            p.print_block_statement(finalizer, ctx);
593        }
594        p.print_soft_newline();
595    }
596}
597
598impl Gen for CatchClause<'_> {
599    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
600        p.print_soft_space();
601        p.print_comments_at(self.span.start);
602        p.print_str("catch");
603        if let Some(param) = &self.param {
604            p.print_soft_space();
605            p.print_str("(");
606            param.pattern.print(p, ctx);
607            p.print_str(")");
608        }
609        p.print_soft_space();
610        p.print_block_statement(&self.body, ctx);
611    }
612}
613
614impl Gen for ThrowStatement<'_> {
615    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
616        p.print_comments_at(self.span.start);
617        p.add_source_mapping(self.span);
618        p.print_indent();
619        p.print_space_before_identifier();
620        p.print_str("throw");
621        p.print_soft_space();
622        p.print_expression(&self.argument);
623        p.print_semicolon_after_statement();
624    }
625}
626
627impl Gen for WithStatement<'_> {
628    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
629        p.print_comments_at(self.span.start);
630        p.add_source_mapping(self.span);
631        p.print_indent();
632        p.print_space_before_identifier();
633        p.print_str("with");
634        p.print_ascii_byte(b'(');
635        p.print_expression(&self.object);
636        p.print_ascii_byte(b')');
637        p.print_body(&self.body, false, ctx);
638    }
639}
640
641impl Gen for DebuggerStatement {
642    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
643        p.print_comments_at(self.span.start);
644        p.add_source_mapping(self.span);
645        p.print_indent();
646        p.print_space_before_identifier();
647        p.print_str("debugger");
648        p.print_semicolon_after_statement();
649    }
650}
651
652impl Gen for VariableDeclaration<'_> {
653    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
654        p.add_source_mapping(self.span);
655        p.print_space_before_identifier();
656        if self.declare {
657            p.print_str("declare ");
658        }
659
660        p.print_str(match self.kind {
661            VariableDeclarationKind::Const => "const",
662            VariableDeclarationKind::Let => "let",
663            VariableDeclarationKind::Var => "var",
664            VariableDeclarationKind::Using => "using",
665            VariableDeclarationKind::AwaitUsing => "await using",
666        });
667        if !self.declarations.is_empty() {
668            p.print_soft_space();
669        }
670        p.print_list(&self.declarations, ctx);
671    }
672}
673
674impl Gen for VariableDeclarator<'_> {
675    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
676        self.id.kind.print(p, ctx);
677        if self.definite {
678            p.print_ascii_byte(b'!');
679        }
680        if self.id.optional {
681            p.print_str("?");
682        }
683        if let Some(type_annotation) = &self.id.type_annotation {
684            p.print_colon();
685            p.print_soft_space();
686            type_annotation.print(p, ctx);
687        }
688        if let Some(init) = &self.init {
689            p.print_soft_space();
690            p.print_equal();
691            p.print_soft_space();
692            init.print_expr(p, Precedence::Comma, ctx);
693        }
694    }
695}
696
697impl Gen for Function<'_> {
698    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
699        let n = p.code_len();
700        let wrap = self.is_expression()
701            && ((p.start_of_stmt == n || p.start_of_default_export == n) || self.pife);
702        let ctx = ctx.and_forbid_call(false);
703        p.wrap(wrap, |p| {
704            p.print_space_before_identifier();
705            p.add_source_mapping(self.span);
706            if self.declare {
707                p.print_str("declare ");
708            }
709            if self.r#async {
710                p.print_str("async ");
711            }
712            p.print_str("function");
713            if self.generator {
714                p.print_ascii_byte(b'*');
715                p.print_soft_space();
716            }
717            if let Some(id) = &self.id {
718                p.print_space_before_identifier();
719                id.print(p, ctx);
720            }
721            if let Some(type_parameters) = &self.type_parameters {
722                type_parameters.print(p, ctx);
723            }
724            p.print_ascii_byte(b'(');
725            if let Some(this_param) = &self.this_param {
726                this_param.print(p, ctx);
727                if !self.params.is_empty() || self.params.rest.is_some() {
728                    p.print_str(",");
729                    p.print_soft_space();
730                }
731            }
732            self.params.print(p, ctx);
733            p.print_ascii_byte(b')');
734            if let Some(return_type) = &self.return_type {
735                p.print_str(": ");
736                return_type.print(p, ctx);
737            }
738            if let Some(body) = &self.body {
739                p.print_soft_space();
740                body.print(p, ctx);
741            } else {
742                p.print_semicolon();
743            }
744        });
745    }
746}
747
748impl Gen for FunctionBody<'_> {
749    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
750        let span_end = self.span.end;
751        let comments_at_end = if span_end > 0 { p.get_comments(span_end - 1) } else { None };
752        let single_line = if self.is_empty() {
753            comments_at_end.as_ref().is_none_or(|comments| {
754                comments.iter().all(|c| !c.preceded_by_newline() && !c.followed_by_newline())
755            })
756        } else {
757            false
758        };
759        p.print_curly_braces(self.span, single_line, |p| {
760            p.print_directives_and_statements(&self.directives, &self.statements, ctx);
761            // Print trailing statement comments.
762            if let Some(comments) = comments_at_end {
763                p.print_comments(&comments);
764                p.print_next_indent_as_space = false;
765            }
766        });
767        p.needs_semicolon = false;
768    }
769}
770
771impl Gen for FormalParameter<'_> {
772    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
773        p.add_source_mapping(self.span);
774        p.print_decorators(&self.decorators, ctx);
775        if let Some(accessibility) = self.accessibility {
776            p.print_space_before_identifier();
777            p.print_str(accessibility.as_str());
778            p.print_soft_space();
779        }
780        if self.r#override {
781            p.print_space_before_identifier();
782            p.print_str("override");
783            p.print_soft_space();
784        }
785        if self.readonly {
786            p.print_space_before_identifier();
787            p.print_str("readonly");
788            p.print_soft_space();
789        }
790        self.pattern.print(p, ctx);
791    }
792}
793
794impl Gen for FormalParameters<'_> {
795    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
796        p.print_list(&self.items, ctx);
797        if let Some(rest) = &self.rest {
798            if !self.items.is_empty() {
799                p.print_comma();
800                p.print_soft_space();
801            }
802            rest.print(p, ctx);
803        }
804    }
805}
806
807impl Gen for ImportDeclaration<'_> {
808    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
809        p.print_comments_at(self.span.start);
810        p.add_source_mapping(self.span);
811        p.print_indent();
812        p.print_space_before_identifier();
813        p.print_str("import");
814        if self.import_kind.is_type() {
815            p.print_str(" type");
816        }
817        if let Some(phase) = self.phase {
818            p.print_hard_space();
819            p.print_str(phase.as_str());
820        }
821        if let Some(specifiers) = &self.specifiers {
822            if specifiers.is_empty() {
823                p.print_soft_space();
824                p.print_str("{}");
825                p.print_soft_space();
826                p.print_str("from");
827                p.print_soft_space();
828                p.print_ascii_byte(b'"');
829                p.print_str(self.source.value.as_str());
830                p.print_ascii_byte(b'"');
831                if let Some(with_clause) = &self.with_clause {
832                    p.print_hard_space();
833                    with_clause.print(p, ctx);
834                }
835                p.print_semicolon_after_statement();
836                return;
837            }
838
839            let mut in_block = false;
840            for (index, specifier) in specifiers.iter().enumerate() {
841                match specifier {
842                    ImportDeclarationSpecifier::ImportDefaultSpecifier(spec) => {
843                        if in_block {
844                            p.print_soft_space();
845                            p.print_str("},");
846                            in_block = false;
847                        } else if index == 0 {
848                            p.print_hard_space();
849                        } else {
850                            p.print_comma();
851                            p.print_soft_space();
852                        }
853                        spec.local.print(p, ctx);
854                        if index == specifiers.len() - 1 {
855                            p.print_hard_space();
856                        }
857                    }
858                    ImportDeclarationSpecifier::ImportNamespaceSpecifier(spec) => {
859                        if in_block {
860                            p.print_soft_space();
861                            p.print_str("},");
862                            in_block = false;
863                        } else if index == 0 {
864                            p.print_soft_space();
865                        } else {
866                            p.print_comma();
867                            p.print_soft_space();
868                        }
869                        p.print_ascii_byte(b'*');
870                        p.print_soft_space();
871                        p.print_str("as ");
872                        spec.local.print(p, ctx);
873                        p.print_hard_space();
874                    }
875                    ImportDeclarationSpecifier::ImportSpecifier(spec) => {
876                        if in_block {
877                            p.print_comma();
878                            p.print_soft_space();
879                        } else {
880                            if index != 0 {
881                                p.print_comma();
882                            }
883                            in_block = true;
884                            p.print_soft_space();
885                            p.print_ascii_byte(b'{');
886                            p.print_soft_space();
887                        }
888
889                        if spec.import_kind.is_type() {
890                            p.print_str("type ");
891                        }
892
893                        spec.imported.print(p, ctx);
894                        let local_name = p.get_binding_identifier_name(&spec.local);
895                        let imported_name = get_module_export_name(&spec.imported, p);
896                        if imported_name != local_name {
897                            p.print_str(" as ");
898                            spec.local.print(p, ctx);
899                        }
900                    }
901                }
902            }
903            if in_block {
904                p.print_soft_space();
905                p.print_ascii_byte(b'}');
906                p.print_soft_space();
907            }
908            p.print_str("from");
909        }
910        p.print_soft_space();
911        p.print_string_literal(&self.source, false);
912        if let Some(with_clause) = &self.with_clause {
913            p.print_soft_space();
914            with_clause.print(p, ctx);
915        }
916        p.print_semicolon_after_statement();
917    }
918}
919
920impl Gen for WithClause<'_> {
921    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
922        p.add_source_mapping(self.span);
923        p.print_str(match self.keyword {
924            WithClauseKeyword::With => "with",
925            WithClauseKeyword::Assert => "assert",
926        });
927        p.print_soft_space();
928        p.add_source_mapping(self.span);
929        p.print_ascii_byte(b'{');
930        if !self.with_entries.is_empty() {
931            p.print_soft_space();
932            p.print_list(&self.with_entries, ctx);
933            p.print_soft_space();
934        }
935        p.print_ascii_byte(b'}');
936    }
937}
938
939impl Gen for ImportAttribute<'_> {
940    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
941        match &self.key {
942            ImportAttributeKey::Identifier(identifier) => {
943                p.print_str(identifier.name.as_str());
944            }
945            ImportAttributeKey::StringLiteral(literal) => {
946                p.print_string_literal(literal, false);
947            }
948        }
949        p.print_colon();
950        p.print_soft_space();
951        p.print_string_literal(&self.value, false);
952    }
953}
954
955impl Gen for ExportNamedDeclaration<'_> {
956    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
957        p.print_comments_at(self.span.start);
958        if let Some(Declaration::FunctionDeclaration(func)) = &self.declaration
959            && func.pure
960            && p.options.print_annotation_comment()
961        {
962            p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
963        }
964        p.add_source_mapping(self.span);
965        p.print_indent();
966        p.print_str("export");
967        if let Some(decl) = &self.declaration {
968            p.print_hard_space();
969            match decl {
970                Declaration::VariableDeclaration(decl) => decl.print(p, ctx),
971                Declaration::FunctionDeclaration(decl) => decl.print(p, ctx),
972                Declaration::ClassDeclaration(decl) => decl.print(p, ctx),
973                Declaration::TSModuleDeclaration(decl) => decl.print(p, ctx),
974                Declaration::TSGlobalDeclaration(decl) => decl.print(p, ctx),
975                Declaration::TSTypeAliasDeclaration(decl) => decl.print(p, ctx),
976                Declaration::TSInterfaceDeclaration(decl) => decl.print(p, ctx),
977                Declaration::TSEnumDeclaration(decl) => decl.print(p, ctx),
978                Declaration::TSImportEqualsDeclaration(decl) => decl.print(p, ctx),
979            }
980            if matches!(
981                decl,
982                Declaration::VariableDeclaration(_)
983                    | Declaration::TSTypeAliasDeclaration(_)
984                    | Declaration::TSImportEqualsDeclaration(_)
985            ) {
986                p.print_semicolon_after_statement();
987            } else {
988                p.print_soft_newline();
989                p.needs_semicolon = false;
990            }
991        } else {
992            if self.export_kind.is_type() {
993                p.print_hard_space();
994                p.print_str("type");
995            }
996            p.print_soft_space();
997            p.print_ascii_byte(b'{');
998            if !self.specifiers.is_empty() {
999                p.print_soft_space();
1000                p.print_list(&self.specifiers, ctx);
1001                p.print_soft_space();
1002            }
1003            p.print_ascii_byte(b'}');
1004            if let Some(source) = &self.source {
1005                p.print_soft_space();
1006                p.print_str("from");
1007                p.print_soft_space();
1008                p.print_string_literal(source, false);
1009            }
1010            p.print_semicolon_after_statement();
1011        }
1012    }
1013}
1014
1015impl Gen for TSExportAssignment<'_> {
1016    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1017        p.print_indent();
1018        p.print_comments_at(self.span.start);
1019        p.print_str("export = ");
1020        self.expression.print_expr(p, Precedence::Lowest, ctx);
1021        p.print_semicolon_after_statement();
1022    }
1023}
1024
1025impl Gen for TSNamespaceExportDeclaration<'_> {
1026    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1027        p.print_indent();
1028        p.print_comments_at(self.span.start);
1029        p.print_str("export as namespace ");
1030        self.id.print(p, ctx);
1031        p.print_semicolon_after_statement();
1032    }
1033}
1034
1035fn get_module_export_name<'a>(
1036    module_export_name: &ModuleExportName<'a>,
1037    p: &Codegen<'a>,
1038) -> &'a str {
1039    match module_export_name {
1040        ModuleExportName::IdentifierName(ident) => ident.name.as_str(),
1041        ModuleExportName::IdentifierReference(ident) => p.get_identifier_reference_name(ident),
1042        ModuleExportName::StringLiteral(s) => s.value.as_str(),
1043    }
1044}
1045
1046impl Gen for ExportSpecifier<'_> {
1047    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1048        if self.export_kind.is_type() {
1049            p.print_str("type ");
1050        }
1051        self.local.print(p, ctx);
1052        let local_name = get_module_export_name(&self.local, p);
1053        let exported_name = get_module_export_name(&self.exported, p);
1054        if local_name != exported_name {
1055            p.print_str(" as ");
1056            self.exported.print(p, ctx);
1057        }
1058    }
1059}
1060
1061impl Gen for ModuleExportName<'_> {
1062    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1063        match self {
1064            Self::IdentifierName(ident) => ident.print(p, ctx),
1065            Self::IdentifierReference(ident) => ident.print(p, ctx),
1066            Self::StringLiteral(literal) => p.print_string_literal(literal, false),
1067        }
1068    }
1069}
1070
1071impl Gen for ExportAllDeclaration<'_> {
1072    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1073        p.print_comments_at(self.span.start);
1074        p.add_source_mapping(self.span);
1075        p.print_indent();
1076        p.print_str("export");
1077        if self.export_kind.is_type() {
1078            p.print_str(" type ");
1079        } else {
1080            p.print_soft_space();
1081        }
1082        p.print_ascii_byte(b'*');
1083
1084        if let Some(exported) = &self.exported {
1085            p.print_soft_space();
1086            p.print_str("as ");
1087            exported.print(p, ctx);
1088            p.print_hard_space();
1089        } else {
1090            p.print_soft_space();
1091        }
1092
1093        p.print_str("from");
1094        p.print_soft_space();
1095        p.print_string_literal(&self.source, false);
1096        if let Some(with_clause) = &self.with_clause {
1097            p.print_hard_space();
1098            with_clause.print(p, ctx);
1099        }
1100        p.print_semicolon_after_statement();
1101    }
1102}
1103
1104impl Gen for ExportDefaultDeclaration<'_> {
1105    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1106        p.print_comments_at(self.span.start);
1107        if let ExportDefaultDeclarationKind::FunctionDeclaration(func) = &self.declaration
1108            && func.pure
1109            && p.options.print_annotation_comment()
1110        {
1111            p.print_str(NO_SIDE_EFFECTS_NEW_LINE_COMMENT);
1112        }
1113        p.add_source_mapping(self.span);
1114        p.print_indent();
1115        p.print_str("export default ");
1116        self.declaration.print(p, ctx);
1117    }
1118}
1119impl Gen for ExportDefaultDeclarationKind<'_> {
1120    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1121        match self {
1122            Self::FunctionDeclaration(func) => {
1123                func.print(p, ctx);
1124                p.print_soft_newline();
1125            }
1126            Self::ClassDeclaration(class) => {
1127                class.print(p, ctx);
1128                p.print_soft_newline();
1129            }
1130            Self::TSInterfaceDeclaration(interface) => interface.print(p, ctx),
1131            _ => {
1132                p.start_of_default_export = p.code_len();
1133                self.to_expression().print_expr(p, Precedence::Comma, Context::empty());
1134                p.print_semicolon_after_statement();
1135            }
1136        }
1137    }
1138}
1139
1140impl GenExpr for Expression<'_> {
1141    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1142        match self {
1143            // Most common expressions first (identifiers, member access, calls)
1144            Self::Identifier(ident) => ident.print(p, ctx),
1145            Self::StaticMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1146            Self::ComputedMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1147            Self::CallExpression(expr) => expr.print_expr(p, precedence, ctx),
1148            // Literals (very common)
1149            Self::NumericLiteral(lit) => lit.print_expr(p, precedence, ctx),
1150            Self::StringLiteral(lit) => lit.print(p, ctx),
1151            Self::BooleanLiteral(lit) => lit.print(p, ctx),
1152            Self::NullLiteral(lit) => lit.print(p, ctx),
1153            // Binary and logical operations (common)
1154            Self::BinaryExpression(expr) => expr.print_expr(p, precedence, ctx),
1155            Self::LogicalExpression(expr) => expr.print_expr(p, precedence, ctx),
1156            // Object and array literals (common)
1157            Self::ObjectExpression(expr) => expr.print_expr(p, precedence, ctx),
1158            Self::ArrayExpression(expr) => expr.print(p, ctx),
1159            // Assignment and update (common)
1160            Self::AssignmentExpression(expr) => expr.print_expr(p, precedence, ctx),
1161            Self::UpdateExpression(expr) => expr.print_expr(p, precedence, ctx),
1162            Self::UnaryExpression(expr) => expr.print_expr(p, precedence, ctx),
1163            // Conditional and sequence
1164            Self::ConditionalExpression(expr) => expr.print_expr(p, precedence, ctx),
1165            Self::SequenceExpression(expr) => expr.print_expr(p, precedence, ctx),
1166            // Function expressions
1167            Self::ArrowFunctionExpression(func) => {
1168                if func.pure && p.options.print_annotation_comment() {
1169                    p.print_str(NO_SIDE_EFFECTS_COMMENT);
1170                }
1171                func.print_expr(p, precedence, ctx);
1172            }
1173            Self::FunctionExpression(func) => {
1174                if func.pure && p.options.print_annotation_comment() {
1175                    p.print_str(NO_SIDE_EFFECTS_COMMENT);
1176                }
1177                func.print(p, ctx);
1178            }
1179            // This and super
1180            Self::ThisExpression(expr) => expr.print(p, ctx),
1181            Self::Super(sup) => sup.print(p, ctx),
1182            // New expression
1183            Self::NewExpression(expr) => expr.print_expr(p, precedence, ctx),
1184            // Template literals
1185            Self::TemplateLiteral(literal) => literal.print(p, ctx),
1186            Self::TaggedTemplateExpression(expr) => expr.print(p, ctx),
1187            // Other literals
1188            Self::RegExpLiteral(lit) => lit.print(p, ctx),
1189            Self::BigIntLiteral(lit) => lit.print_expr(p, precedence, ctx),
1190            // Class expression
1191            Self::ClassExpression(expr) => expr.print(p, ctx),
1192            // Async/await and yield
1193            Self::AwaitExpression(expr) => expr.print_expr(p, precedence, ctx),
1194            Self::YieldExpression(expr) => expr.print_expr(p, precedence, ctx),
1195            // Import expression
1196            Self::ImportExpression(expr) => expr.print_expr(p, precedence, ctx),
1197            // Meta property
1198            Self::MetaProperty(expr) => expr.print(p, ctx),
1199            // Chain expression
1200            Self::ChainExpression(expr) => expr.print_expr(p, precedence, ctx),
1201            // Private field
1202            Self::PrivateFieldExpression(expr) => expr.print_expr(p, precedence, ctx),
1203            Self::PrivateInExpression(expr) => expr.print_expr(p, precedence, ctx),
1204            // Parenthesized
1205            Self::ParenthesizedExpression(e) => e.print_expr(p, precedence, ctx),
1206            // JSX (less common in typical JS code)
1207            Self::JSXElement(el) => el.print(p, ctx),
1208            Self::JSXFragment(fragment) => fragment.print(p, ctx),
1209            // TypeScript (less common in runtime)
1210            Self::TSAsExpression(e) => e.print_expr(p, precedence, ctx),
1211            Self::TSSatisfiesExpression(e) => e.print_expr(p, precedence, ctx),
1212            Self::TSTypeAssertion(e) => e.print_expr(p, precedence, ctx),
1213            Self::TSNonNullExpression(e) => e.print_expr(p, precedence, ctx),
1214            Self::TSInstantiationExpression(e) => e.print_expr(p, precedence, ctx),
1215            // V8 intrinsics (rare)
1216            Self::V8IntrinsicExpression(e) => e.print_expr(p, precedence, ctx),
1217        }
1218    }
1219}
1220
1221impl GenExpr for ParenthesizedExpression<'_> {
1222    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1223        self.expression.print_expr(p, precedence, ctx);
1224    }
1225}
1226
1227impl Gen for IdentifierReference<'_> {
1228    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1229        let name = p.get_identifier_reference_name(self);
1230        p.print_space_before_identifier();
1231        p.add_source_mapping_for_name(self.span, name);
1232        p.print_str(name);
1233    }
1234}
1235
1236impl Gen for IdentifierName<'_> {
1237    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1238        p.print_space_before_identifier();
1239        p.add_source_mapping_for_name(self.span, &self.name);
1240        p.print_str(self.name.as_str());
1241    }
1242}
1243
1244impl Gen for BindingIdentifier<'_> {
1245    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1246        let name = p.get_binding_identifier_name(self);
1247        p.print_space_before_identifier();
1248        p.add_source_mapping_for_name(self.span, name);
1249        p.print_str(name);
1250    }
1251}
1252
1253impl Gen for LabelIdentifier<'_> {
1254    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1255        p.print_space_before_identifier();
1256        p.add_source_mapping_for_name(self.span, &self.name);
1257        p.print_str(self.name.as_str());
1258    }
1259}
1260
1261impl Gen for BooleanLiteral {
1262    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1263        p.add_source_mapping(self.span);
1264        p.print_space_before_identifier();
1265        p.print_str(self.as_str());
1266    }
1267}
1268
1269impl Gen for NullLiteral {
1270    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1271        p.print_space_before_identifier();
1272        p.add_source_mapping(self.span);
1273        p.print_str("null");
1274    }
1275}
1276
1277impl GenExpr for NumericLiteral<'_> {
1278    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1279        p.add_source_mapping(self.span);
1280        let value = self.value;
1281        if ctx.contains(Context::TYPESCRIPT) {
1282            p.print_str(&self.raw_str());
1283        } else if value.is_nan() {
1284            p.print_space_before_identifier();
1285            p.print_str("NaN");
1286        } else if value.is_infinite() {
1287            let wrap = (p.options.minify && precedence >= Precedence::Multiply)
1288                || (value.is_sign_negative() && precedence >= Precedence::Prefix);
1289            p.wrap(wrap, |p| {
1290                if value.is_sign_negative() {
1291                    p.print_space_before_operator(Operator::Unary(UnaryOperator::UnaryNegation));
1292                    p.print_ascii_byte(b'-');
1293                } else {
1294                    p.print_space_before_identifier();
1295                }
1296                if p.options.minify {
1297                    p.print_str("1/0");
1298                } else {
1299                    p.print_str("Infinity");
1300                }
1301            });
1302        } else if value.is_sign_positive() {
1303            p.print_space_before_identifier();
1304            p.print_non_negative_float(value);
1305        } else if precedence >= Precedence::Prefix {
1306            p.print_str("(-");
1307            p.print_non_negative_float(value.abs());
1308            p.print_ascii_byte(b')');
1309        } else {
1310            p.print_space_before_operator(Operator::Unary(UnaryOperator::UnaryNegation));
1311            p.print_ascii_byte(b'-');
1312            p.print_non_negative_float(value.abs());
1313        }
1314    }
1315}
1316
1317impl GenExpr for BigIntLiteral<'_> {
1318    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, _ctx: Context) {
1319        p.print_space_before_identifier();
1320        p.add_source_mapping(self.span);
1321        let value = self.value.as_str();
1322        if value.starts_with('-') && precedence >= Precedence::Prefix {
1323            p.print_ascii_byte(b'(');
1324            p.print_str(value);
1325            p.print_str("n)");
1326        } else {
1327            p.print_str(value);
1328            p.print_ascii_byte(b'n');
1329        }
1330    }
1331}
1332
1333impl Gen for RegExpLiteral<'_> {
1334    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1335        p.add_source_mapping(self.span);
1336        // Avoid forming a single-line comment or "</script" sequence
1337        let last = p.last_byte();
1338        if last == Some(b'/')
1339            || (last == Some(b'<')
1340                && self
1341                    .regex
1342                    .pattern
1343                    .text
1344                    .get(..6)
1345                    .is_some_and(|first_six| first_six.cow_to_ascii_lowercase() == "script"))
1346        {
1347            p.print_hard_space();
1348        }
1349        p.print_ascii_byte(b'/');
1350        p.print_str(self.regex.pattern.text.as_str());
1351        p.print_ascii_byte(b'/');
1352        p.print_str(self.regex.flags.to_inline_string().as_str());
1353        p.prev_reg_exp_end = p.code().len();
1354    }
1355}
1356
1357impl Gen for StringLiteral<'_> {
1358    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1359        p.print_string_literal(self, true);
1360    }
1361}
1362
1363impl Gen for ThisExpression {
1364    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1365        p.print_space_before_identifier();
1366        p.add_source_mapping(self.span);
1367        p.print_str("this");
1368    }
1369}
1370
1371impl GenExpr for MemberExpression<'_> {
1372    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1373        match self {
1374            Self::ComputedMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1375            Self::StaticMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1376            Self::PrivateFieldExpression(expr) => expr.print_expr(p, precedence, ctx),
1377        }
1378    }
1379}
1380
1381impl GenExpr for ComputedMemberExpression<'_> {
1382    fn gen_expr(&self, p: &mut Codegen, _precedence: Precedence, ctx: Context) {
1383        // `(let[0] = 100);` -> `(let)[0] = 100`;
1384        let wrap = self.object.get_identifier_reference().is_some_and(|r| r.name == "let");
1385        p.wrap(wrap, |p| {
1386            self.object.print_expr(p, Precedence::Postfix, ctx.intersection(Context::FORBID_CALL));
1387        });
1388        if self.optional {
1389            p.print_str("?.");
1390        }
1391        p.print_ascii_byte(b'[');
1392        self.expression.print_expr(p, Precedence::Lowest, Context::empty());
1393        p.print_ascii_byte(b']');
1394    }
1395}
1396
1397impl GenExpr for StaticMemberExpression<'_> {
1398    fn gen_expr(&self, p: &mut Codegen, _precedence: Precedence, ctx: Context) {
1399        self.object.print_expr(p, Precedence::Postfix, ctx.intersection(Context::FORBID_CALL));
1400        if self.optional {
1401            p.print_ascii_byte(b'?');
1402        } else if p.need_space_before_dot == p.code_len() {
1403            // `0.toExponential()` is invalid, add a space before the dot, `0 .toExponential()` is valid
1404            p.print_hard_space();
1405        }
1406        p.print_ascii_byte(b'.');
1407        self.property.print(p, ctx);
1408    }
1409}
1410
1411impl GenExpr for PrivateFieldExpression<'_> {
1412    fn gen_expr(&self, p: &mut Codegen, _precedence: Precedence, ctx: Context) {
1413        self.object.print_expr(p, Precedence::Postfix, ctx.intersection(Context::FORBID_CALL));
1414        if self.optional {
1415            p.print_str("?");
1416        }
1417        p.print_ascii_byte(b'.');
1418        self.field.print(p, ctx);
1419    }
1420}
1421
1422impl GenExpr for CallExpression<'_> {
1423    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1424        let is_statement = p.start_of_stmt == p.code_len();
1425        let is_export_default = p.start_of_default_export == p.code_len();
1426        let mut wrap = precedence >= Precedence::New || ctx.intersects(Context::FORBID_CALL);
1427        let pure = self.pure && p.options.print_annotation_comment();
1428        if !wrap && pure && precedence >= Precedence::Postfix {
1429            wrap = true;
1430        }
1431
1432        p.wrap(wrap, |p| {
1433            if pure {
1434                p.add_source_mapping(self.span);
1435                p.print_str(PURE_COMMENT);
1436            }
1437            if is_export_default {
1438                p.start_of_default_export = p.code_len();
1439            } else if is_statement {
1440                p.start_of_stmt = p.code_len();
1441            }
1442            self.callee.print_expr(p, Precedence::Postfix, Context::empty());
1443            if self.optional {
1444                p.print_str("?.");
1445            }
1446            if let Some(type_parameters) = &self.type_arguments {
1447                type_parameters.print(p, ctx);
1448            }
1449            p.print_arguments(self.span, &self.arguments, ctx);
1450        });
1451    }
1452}
1453
1454impl Gen for Argument<'_> {
1455    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1456        match self {
1457            Self::SpreadElement(elem) => elem.print(p, ctx),
1458            _ => self.to_expression().print_expr(p, Precedence::Comma, Context::empty()),
1459        }
1460    }
1461}
1462
1463impl Gen for ArrayExpressionElement<'_> {
1464    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1465        match self {
1466            Self::SpreadElement(elem) => elem.print(p, ctx),
1467            Self::Elision(_span) => {}
1468            _ => self.to_expression().print_expr(p, Precedence::Comma, Context::empty()),
1469        }
1470    }
1471}
1472
1473impl Gen for SpreadElement<'_> {
1474    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
1475        p.add_source_mapping(self.span);
1476        p.print_ellipsis();
1477        self.argument.print_expr(p, Precedence::Comma, Context::empty());
1478    }
1479}
1480
1481impl Gen for ArrayExpression<'_> {
1482    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1483        let is_multi_line = self.elements.len() > 2;
1484        p.add_source_mapping(self.span);
1485        p.print_ascii_byte(b'[');
1486        if is_multi_line {
1487            p.indent();
1488        }
1489        for (i, item) in self.elements.iter().enumerate() {
1490            if i != 0 {
1491                p.print_comma();
1492            }
1493            if is_multi_line {
1494                p.print_soft_newline();
1495                p.print_indent();
1496            } else if i != 0 {
1497                p.print_soft_space();
1498            }
1499            item.print(p, ctx);
1500            if i == self.elements.len() - 1 && matches!(item, ArrayExpressionElement::Elision(_)) {
1501                p.print_comma();
1502            }
1503        }
1504        if is_multi_line {
1505            p.print_soft_newline();
1506            p.dedent();
1507            p.print_indent();
1508        }
1509        p.print_ascii_byte(b']');
1510        p.add_source_mapping_end(self.span);
1511    }
1512}
1513
1514impl GenExpr for ObjectExpression<'_> {
1515    fn gen_expr(&self, p: &mut Codegen, _precedence: Precedence, ctx: Context) {
1516        let n = p.code_len();
1517        let len = self.properties.len();
1518        let is_multi_line = len > 1;
1519        let has_comment = p.has_comment(self.span.start);
1520        let wrap = has_comment || p.start_of_stmt == n || p.start_of_arrow_expr == n;
1521        p.wrap(wrap, |p| {
1522            // Print comments for lingui https://lingui.dev/ref/macro#definemessage
1523            // `const message = /*i18n*/ { };`
1524            if has_comment {
1525                p.print_leading_comments(self.span.start);
1526                p.print_indent();
1527            }
1528            p.add_source_mapping(self.span);
1529            p.print_ascii_byte(b'{');
1530            if is_multi_line {
1531                p.indent();
1532            }
1533            for (i, item) in self.properties.iter().enumerate() {
1534                if i != 0 {
1535                    p.print_comma();
1536                }
1537                if is_multi_line {
1538                    p.print_soft_newline();
1539                    p.print_indent();
1540                } else {
1541                    p.print_soft_space();
1542                }
1543                item.print(p, ctx);
1544            }
1545            if is_multi_line {
1546                p.print_soft_newline();
1547                p.dedent();
1548                p.print_indent();
1549            } else if len > 0 {
1550                p.print_soft_space();
1551            }
1552            p.print_ascii_byte(b'}');
1553            p.add_source_mapping_end(self.span);
1554        });
1555    }
1556}
1557
1558impl Gen for ObjectPropertyKind<'_> {
1559    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1560        match self {
1561            Self::ObjectProperty(prop) => prop.print(p, ctx),
1562            Self::SpreadProperty(elem) => elem.print(p, ctx),
1563        }
1564    }
1565}
1566
1567impl Gen for ObjectProperty<'_> {
1568    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1569        if let Expression::FunctionExpression(func) = &self.value {
1570            p.add_source_mapping(self.span);
1571            let is_accessor = match &self.kind {
1572                PropertyKind::Init => false,
1573                PropertyKind::Get => {
1574                    p.print_str("get");
1575                    p.print_soft_space();
1576                    true
1577                }
1578                PropertyKind::Set => {
1579                    p.print_str("set");
1580                    p.print_soft_space();
1581                    true
1582                }
1583            };
1584            if self.method || is_accessor {
1585                if func.r#async {
1586                    p.print_space_before_identifier();
1587                    p.print_str("async");
1588                    p.print_soft_space();
1589                }
1590                if func.generator {
1591                    p.print_str("*");
1592                }
1593                if self.computed {
1594                    p.print_ascii_byte(b'[');
1595                }
1596                self.key.print(p, ctx);
1597                if self.computed {
1598                    p.print_ascii_byte(b']');
1599                }
1600                if let Some(type_parameters) = &func.type_parameters {
1601                    type_parameters.print(p, ctx);
1602                }
1603                p.print_ascii_byte(b'(');
1604                func.params.print(p, ctx);
1605                p.print_ascii_byte(b')');
1606                if let Some(return_type) = &func.return_type {
1607                    p.print_colon();
1608                    p.print_soft_space();
1609                    return_type.print(p, ctx);
1610                }
1611                if let Some(body) = &func.body {
1612                    p.print_soft_space();
1613                    body.print(p, ctx);
1614                }
1615                return;
1616            }
1617        }
1618
1619        let mut shorthand = false;
1620        if let PropertyKey::StaticIdentifier(key) = &self.key {
1621            if key.name == "__proto__" {
1622                shorthand = self.shorthand;
1623            } else if let Expression::Identifier(ident) = self.value.without_parentheses()
1624                && key.name == p.get_identifier_reference_name(ident)
1625            {
1626                shorthand = true;
1627            }
1628        }
1629
1630        let mut computed = self.computed;
1631
1632        // "{ -1: 0 }" must be printed as "{ [-1]: 0 }"
1633        // "{ 1/0: 0 }" must be printed as "{ [1/0]: 0 }"
1634        if !computed
1635            && let Some(Expression::NumericLiteral(n)) = self.key.as_expression()
1636            && (n.value.is_sign_negative() || n.value.is_infinite())
1637        {
1638            computed = true;
1639        }
1640
1641        if !shorthand {
1642            if computed {
1643                p.print_ascii_byte(b'[');
1644            }
1645            self.key.print(p, ctx);
1646            if computed {
1647                p.print_ascii_byte(b']');
1648            }
1649            p.print_colon();
1650            p.print_soft_space();
1651        }
1652
1653        self.value.print_expr(p, Precedence::Comma, Context::empty());
1654    }
1655}
1656
1657impl Gen for PropertyKey<'_> {
1658    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1659        match self {
1660            Self::StaticIdentifier(ident) => ident.print(p, ctx),
1661            Self::PrivateIdentifier(ident) => ident.print(p, ctx),
1662            Self::StringLiteral(s) => p.print_string_literal(s, /* allow_backtick */ false),
1663            _ => self.to_expression().print_expr(p, Precedence::Comma, Context::empty()),
1664        }
1665    }
1666}
1667
1668impl GenExpr for ArrowFunctionExpression<'_> {
1669    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1670        p.wrap(precedence >= Precedence::Assign || self.pife, |p| {
1671            if self.r#async {
1672                p.print_space_before_identifier();
1673                p.add_source_mapping(self.span);
1674                p.print_str("async");
1675                p.print_soft_space();
1676            }
1677            if let Some(type_parameters) = &self.type_parameters {
1678                type_parameters.print(p, ctx);
1679            }
1680            let remove_params_wrap = p.options.minify
1681                && self.params.items.len() == 1
1682                && self.params.rest.is_none()
1683                && self.type_parameters.is_none()
1684                && self.return_type.is_none()
1685                && {
1686                    let param = &self.params.items[0];
1687                    param.decorators.is_empty()
1688                        && !param.has_modifier()
1689                        && param.pattern.kind.is_binding_identifier()
1690                        && param.pattern.type_annotation.is_none()
1691                        && !param.pattern.optional
1692                };
1693            p.wrap(!remove_params_wrap, |p| {
1694                self.params.print(p, ctx);
1695            });
1696            if let Some(return_type) = &self.return_type {
1697                p.print_str(":");
1698                p.print_soft_space();
1699                return_type.print(p, ctx);
1700            }
1701            p.print_soft_space();
1702            p.print_str("=>");
1703            p.print_soft_space();
1704            if self.expression {
1705                if let Some(Statement::ExpressionStatement(stmt)) = &self.body.statements.first() {
1706                    p.start_of_arrow_expr = p.code_len();
1707                    stmt.expression.print_expr(p, Precedence::Comma, ctx);
1708                }
1709            } else {
1710                self.body.print(p, ctx);
1711            }
1712        });
1713    }
1714}
1715
1716impl GenExpr for YieldExpression<'_> {
1717    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, _ctx: Context) {
1718        p.wrap(precedence >= Precedence::Assign, |p| {
1719            p.print_space_before_identifier();
1720            p.add_source_mapping(self.span);
1721            p.print_str("yield");
1722            if self.delegate {
1723                p.print_ascii_byte(b'*');
1724            }
1725            if let Some(argument) = self.argument.as_ref() {
1726                p.print_soft_space();
1727                argument.print_expr(p, Precedence::Yield, Context::empty());
1728            }
1729        });
1730    }
1731}
1732
1733impl GenExpr for UpdateExpression<'_> {
1734    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1735        let operator = self.operator.as_str();
1736        p.wrap(precedence >= self.precedence(), |p| {
1737            if self.prefix {
1738                p.print_space_before_operator(self.operator.into());
1739                p.add_source_mapping(self.span);
1740                p.print_str(operator);
1741                p.prev_op = Some(self.operator.into());
1742                p.prev_op_end = p.code().len();
1743                self.argument.print_expr(p, Precedence::Prefix, ctx);
1744            } else {
1745                p.print_space_before_operator(self.operator.into());
1746                p.add_source_mapping(self.span);
1747                self.argument.print_expr(p, Precedence::Postfix, ctx);
1748                p.print_str(operator);
1749                p.prev_op = Some(self.operator.into());
1750                p.prev_op_end = p.code().len();
1751            }
1752        });
1753    }
1754}
1755
1756impl GenExpr for UnaryExpression<'_> {
1757    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1758        p.wrap(precedence >= self.precedence(), |p| {
1759            let operator = self.operator.as_str();
1760            if self.operator.is_keyword() {
1761                p.print_space_before_identifier();
1762                p.add_source_mapping(self.span);
1763                p.print_str(operator);
1764                p.print_soft_space();
1765            } else {
1766                p.print_space_before_operator(self.operator.into());
1767                p.add_source_mapping(self.span);
1768                p.print_str(operator);
1769                p.prev_op = Some(self.operator.into());
1770                p.prev_op_end = p.code().len();
1771            }
1772            // Forbid `delete Infinity`, which is syntax error in strict mode.
1773            let is_delete_infinity = self.operator == UnaryOperator::Delete
1774                && !p.options.minify
1775                && matches!(&self.argument, Expression::NumericLiteral(lit) if lit.value.is_sign_positive() && lit.value.is_infinite());
1776            if is_delete_infinity {
1777                p.print_str("(0,");
1778                p.print_soft_space();
1779            }
1780            self.argument.print_expr(p, Precedence::Exponentiation, ctx);
1781            if is_delete_infinity{
1782                p.print_ascii_byte(b')');
1783            }
1784        });
1785    }
1786}
1787
1788impl GenExpr for BinaryExpression<'_> {
1789    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1790        let v = BinaryExpressionVisitor {
1791            // SAFETY:
1792            // The pointer is stored on the heap and all will be consumed in the binary expression visitor.
1793            e: Binaryish::Binary(unsafe {
1794                std::mem::transmute::<&BinaryExpression<'_>, &BinaryExpression<'_>>(self)
1795            }),
1796            precedence,
1797            ctx,
1798            left_precedence: Precedence::Lowest,
1799            operator: BinaryishOperator::Binary(self.operator),
1800            wrap: false,
1801            right_precedence: Precedence::Lowest,
1802        };
1803        BinaryExpressionVisitor::gen_expr(v, p);
1804    }
1805}
1806
1807impl GenExpr for PrivateInExpression<'_> {
1808    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1809        p.wrap(precedence >= Precedence::Compare, |p| {
1810            p.add_source_mapping(self.span);
1811            self.left.print(p, ctx);
1812            p.print_str(" in ");
1813            self.right.print_expr(p, Precedence::Equals, Context::FORBID_IN);
1814        });
1815    }
1816}
1817
1818impl GenExpr for LogicalExpression<'_> {
1819    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1820        let v = BinaryExpressionVisitor {
1821            // SAFETY:
1822            // The pointer is stored on the heap and all will be consumed in the binary expression visitor.
1823            e: Binaryish::Logical(unsafe {
1824                std::mem::transmute::<&LogicalExpression<'_>, &LogicalExpression<'_>>(self)
1825            }),
1826            precedence,
1827            ctx,
1828            left_precedence: Precedence::Lowest,
1829            operator: BinaryishOperator::Logical(self.operator),
1830            wrap: false,
1831            right_precedence: Precedence::Lowest,
1832        };
1833        BinaryExpressionVisitor::gen_expr(v, p);
1834    }
1835}
1836
1837impl GenExpr for ConditionalExpression<'_> {
1838    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1839        let mut ctx = ctx;
1840        let wrap = precedence >= self.precedence();
1841        if wrap {
1842            ctx &= Context::FORBID_IN.not();
1843        }
1844        p.wrap(wrap, |p| {
1845            self.test.print_expr(p, Precedence::Conditional, ctx & Context::FORBID_IN);
1846            p.print_soft_space();
1847            p.print_ascii_byte(b'?');
1848            p.print_soft_space();
1849            self.consequent.print_expr(p, Precedence::Yield, Context::empty());
1850            p.print_soft_space();
1851            p.print_colon();
1852            p.print_soft_space();
1853            self.alternate.print_expr(p, Precedence::Yield, ctx & Context::FORBID_IN);
1854        });
1855    }
1856}
1857
1858impl GenExpr for AssignmentExpression<'_> {
1859    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1860        let n = p.code_len();
1861        // Destructuring assignments must be parenthesized
1862        let wrap = (p.start_of_stmt == n || p.start_of_arrow_expr == n)
1863            && matches!(self.left, AssignmentTarget::ObjectAssignmentTarget(_));
1864        p.wrap(wrap || precedence >= self.precedence(), |p| {
1865            p.add_source_mapping(self.span);
1866            self.left.print(p, ctx);
1867            p.print_soft_space();
1868            p.print_str(self.operator.as_str());
1869            p.print_soft_space();
1870            self.right.print_expr(p, Precedence::Comma, ctx);
1871        });
1872    }
1873}
1874
1875impl Gen for AssignmentTarget<'_> {
1876    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1877        match self {
1878            match_simple_assignment_target!(Self) => {
1879                self.to_simple_assignment_target().print_expr(
1880                    p,
1881                    Precedence::Comma,
1882                    Context::empty(),
1883                );
1884            }
1885            match_assignment_target_pattern!(Self) => {
1886                self.to_assignment_target_pattern().print(p, ctx);
1887            }
1888        }
1889    }
1890}
1891
1892impl GenExpr for SimpleAssignmentTarget<'_> {
1893    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
1894        match self {
1895            Self::AssignmentTargetIdentifier(ident) => ident.print(p, ctx),
1896            Self::ComputedMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1897            Self::StaticMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
1898            Self::PrivateFieldExpression(expr) => expr.print_expr(p, precedence, ctx),
1899            Self::TSAsExpression(e) => e.print_expr(p, precedence, ctx),
1900            Self::TSSatisfiesExpression(e) => e.print_expr(p, precedence, ctx),
1901            Self::TSNonNullExpression(e) => e.print_expr(p, precedence, ctx),
1902            Self::TSTypeAssertion(e) => e.print_expr(p, precedence, ctx),
1903        }
1904    }
1905}
1906
1907impl Gen for AssignmentTargetPattern<'_> {
1908    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1909        match self {
1910            Self::ArrayAssignmentTarget(target) => target.print(p, ctx),
1911            Self::ObjectAssignmentTarget(target) => target.print(p, ctx),
1912        }
1913    }
1914}
1915
1916impl Gen for ArrayAssignmentTarget<'_> {
1917    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1918        p.add_source_mapping(self.span);
1919        p.print_ascii_byte(b'[');
1920        for (i, item) in self.elements.iter().enumerate() {
1921            if i != 0 {
1922                p.print_comma();
1923                p.print_soft_space();
1924            }
1925            if let Some(item) = item {
1926                item.print(p, ctx);
1927            }
1928            if i == self.elements.len() - 1 && (item.is_none() || self.rest.is_some()) {
1929                p.print_comma();
1930            }
1931        }
1932        if let Some(target) = &self.rest {
1933            if !self.elements.is_empty() {
1934                p.print_soft_space();
1935            }
1936            target.print(p, ctx);
1937        }
1938        p.print_ascii_byte(b']');
1939    }
1940}
1941
1942impl Gen for ObjectAssignmentTarget<'_> {
1943    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1944        p.add_source_mapping(self.span);
1945        p.print_ascii_byte(b'{');
1946        p.print_list(&self.properties, ctx);
1947        if let Some(target) = &self.rest {
1948            if !self.properties.is_empty() {
1949                p.print_comma();
1950                p.print_soft_space();
1951            }
1952            target.print(p, ctx);
1953        }
1954        p.print_ascii_byte(b'}');
1955    }
1956}
1957
1958impl Gen for AssignmentTargetMaybeDefault<'_> {
1959    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1960        match self {
1961            match_assignment_target!(Self) => self.to_assignment_target().print(p, ctx),
1962            Self::AssignmentTargetWithDefault(target) => target.print(p, ctx),
1963        }
1964    }
1965}
1966
1967impl Gen for AssignmentTargetWithDefault<'_> {
1968    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1969        self.binding.print(p, ctx);
1970        p.print_soft_space();
1971        p.print_equal();
1972        p.print_soft_space();
1973        self.init.print_expr(p, Precedence::Comma, Context::empty());
1974    }
1975}
1976
1977impl Gen for AssignmentTargetProperty<'_> {
1978    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1979        match self {
1980            Self::AssignmentTargetPropertyIdentifier(ident) => ident.print(p, ctx),
1981            Self::AssignmentTargetPropertyProperty(prop) => prop.print(p, ctx),
1982        }
1983    }
1984}
1985
1986impl Gen for AssignmentTargetPropertyIdentifier<'_> {
1987    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
1988        let ident_name = p.get_identifier_reference_name(&self.binding);
1989        if ident_name == self.binding.name.as_str() {
1990            self.binding.print(p, ctx);
1991        } else {
1992            // `({x: a} = y);`
1993            p.print_str(self.binding.name.as_str());
1994            p.print_colon();
1995            p.print_soft_space();
1996            p.print_str(ident_name);
1997        }
1998        if let Some(expr) = &self.init {
1999            p.print_soft_space();
2000            p.print_equal();
2001            p.print_soft_space();
2002            expr.print_expr(p, Precedence::Comma, Context::empty());
2003        }
2004    }
2005}
2006
2007impl Gen for AssignmentTargetPropertyProperty<'_> {
2008    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2009        let omit_key = if p.options.minify {
2010            let key_name = match &self.name {
2011                PropertyKey::StaticIdentifier(ident) => Some(&ident.name),
2012                _ => None,
2013            };
2014            let value_name =
2015                self.binding.identifier().map(|id| p.get_identifier_reference_name(id));
2016            match (key_name, value_name) {
2017                (Some(key_name), Some(value_name)) => key_name == value_name,
2018                _ => false,
2019            }
2020        } else {
2021            false
2022        };
2023        if !omit_key {
2024            match &self.name {
2025                PropertyKey::StaticIdentifier(ident) => {
2026                    ident.print(p, ctx);
2027                }
2028                PropertyKey::PrivateIdentifier(ident) => {
2029                    ident.print(p, ctx);
2030                }
2031                PropertyKey::StringLiteral(s) => {
2032                    if self.computed {
2033                        p.print_ascii_byte(b'[');
2034                    }
2035                    p.print_string_literal(s, /* allow_backtick */ false);
2036                    if self.computed {
2037                        p.print_ascii_byte(b']');
2038                    }
2039                }
2040                key => {
2041                    if self.computed {
2042                        p.print_ascii_byte(b'[');
2043                    }
2044                    key.to_expression().print_expr(p, Precedence::Comma, Context::empty());
2045                    if self.computed {
2046                        p.print_ascii_byte(b']');
2047                    }
2048                }
2049            }
2050            p.print_colon();
2051            p.print_soft_space();
2052        }
2053        self.binding.print(p, ctx);
2054    }
2055}
2056
2057impl Gen for AssignmentTargetRest<'_> {
2058    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2059        p.print_ellipsis();
2060        self.target.print(p, ctx);
2061    }
2062}
2063
2064impl GenExpr for SequenceExpression<'_> {
2065    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2066        p.wrap(precedence >= self.precedence(), |p| {
2067            p.print_expressions(&self.expressions, Precedence::Lowest, ctx.and_forbid_call(false));
2068        });
2069    }
2070}
2071
2072impl GenExpr for ImportExpression<'_> {
2073    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2074        let wrap = precedence >= Precedence::New || ctx.intersects(Context::FORBID_CALL);
2075
2076        let has_comment_before_right_paren = p.options.print_annotation_comment()
2077            && self.span.end > 0
2078            && p.has_comment(self.span.end - 1);
2079        let has_comment = p.options.print_annotation_comment()
2080            && (has_comment_before_right_paren
2081                || p.has_comment(self.source.span().start)
2082                || self
2083                    .options
2084                    .as_ref()
2085                    .is_some_and(|options| p.has_comment(options.span().start)));
2086
2087        p.wrap(wrap, |p| {
2088            p.print_space_before_identifier();
2089            p.add_source_mapping(self.span);
2090            p.print_str("import");
2091            if let Some(phase) = self.phase {
2092                p.print_ascii_byte(b'.');
2093                p.print_str(phase.as_str());
2094            }
2095            p.print_ascii_byte(b'(');
2096            if has_comment {
2097                p.indent();
2098            }
2099            if p.print_expr_comments(self.source.span().start) {
2100                p.print_indent();
2101            } else if has_comment {
2102                p.print_soft_newline();
2103                p.print_indent();
2104            }
2105            self.source.print_expr(p, Precedence::Comma, Context::empty());
2106            if let Some(options) = &self.options {
2107                p.print_comma();
2108                if has_comment {
2109                    p.print_soft_newline();
2110                    p.print_indent();
2111                } else {
2112                    p.print_soft_space();
2113                }
2114                options.gen_expr(p, Precedence::Comma, Context::empty());
2115            }
2116            if has_comment {
2117                // Handle `/* comment */);`
2118                if !has_comment_before_right_paren || !p.print_expr_comments(self.span.end - 1) {
2119                    p.print_soft_newline();
2120                }
2121                p.dedent();
2122            }
2123            p.print_ascii_byte(b')');
2124        });
2125    }
2126}
2127
2128impl Gen for TemplateLiteral<'_> {
2129    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2130        p.add_source_mapping(self.span);
2131        p.print_ascii_byte(b'`');
2132        debug_assert_eq!(self.quasis.len(), self.expressions.len() + 1);
2133        let (first_quasi, remaining_quasis) = self.quasis.split_first().unwrap();
2134        p.print_str_escaping_script_close_tag(first_quasi.value.raw.as_str());
2135        for (expr, quasi) in self.expressions.iter().zip(remaining_quasis) {
2136            p.print_str("${");
2137            p.print_expression(expr);
2138            p.print_ascii_byte(b'}');
2139            p.add_source_mapping(quasi.span);
2140            p.print_str_escaping_script_close_tag(quasi.value.raw.as_str());
2141        }
2142        p.print_ascii_byte(b'`');
2143    }
2144}
2145
2146impl Gen for TaggedTemplateExpression<'_> {
2147    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2148        p.add_source_mapping(self.span);
2149        self.tag.print_expr(p, Precedence::Postfix, Context::empty());
2150        if let Some(type_parameters) = &self.type_arguments {
2151            type_parameters.print(p, ctx);
2152        }
2153        self.quasi.print(p, ctx);
2154    }
2155}
2156
2157impl Gen for Super {
2158    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2159        p.print_space_before_identifier();
2160        p.add_source_mapping(self.span);
2161        p.print_str("super");
2162    }
2163}
2164
2165impl GenExpr for AwaitExpression<'_> {
2166    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2167        p.wrap(precedence >= self.precedence(), |p| {
2168            p.print_space_before_identifier();
2169            p.add_source_mapping(self.span);
2170            p.print_str("await");
2171            p.print_soft_space();
2172            self.argument.print_expr(p, Precedence::Exponentiation, ctx);
2173        });
2174    }
2175}
2176
2177impl GenExpr for ChainExpression<'_> {
2178    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2179        p.wrap(precedence >= Precedence::Postfix, |p| match &self.expression {
2180            ChainElement::CallExpression(expr) => expr.print_expr(p, precedence, ctx),
2181            ChainElement::TSNonNullExpression(expr) => expr.print_expr(p, precedence, ctx),
2182            ChainElement::ComputedMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
2183            ChainElement::StaticMemberExpression(expr) => expr.print_expr(p, precedence, ctx),
2184            ChainElement::PrivateFieldExpression(expr) => expr.print_expr(p, precedence, ctx),
2185        });
2186    }
2187}
2188
2189impl GenExpr for NewExpression<'_> {
2190    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2191        let mut wrap = precedence >= self.precedence();
2192        let pure = self.pure && p.options.print_annotation_comment();
2193        if precedence >= Precedence::Postfix && pure {
2194            wrap = true;
2195        }
2196        p.wrap(wrap, |p| {
2197            if pure {
2198                p.print_str(PURE_COMMENT);
2199            }
2200            p.print_space_before_identifier();
2201            p.add_source_mapping(self.span);
2202            p.print_str("new");
2203            p.print_soft_space();
2204            self.callee.print_expr(p, Precedence::New, Context::FORBID_CALL);
2205            if let Some(type_parameters) = &self.type_arguments {
2206                type_parameters.print(p, ctx);
2207            }
2208
2209            // Omit the "()" when minifying, but only when safe to do so
2210            if !p.options.minify || !self.arguments.is_empty() || precedence >= Precedence::Postfix
2211            {
2212                p.print_arguments(self.span, &self.arguments, ctx);
2213            }
2214        });
2215    }
2216}
2217
2218impl GenExpr for TSAsExpression<'_> {
2219    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2220        let wrap = precedence >= Precedence::Shift;
2221
2222        p.wrap(wrap, |p| {
2223            self.expression.print_expr(p, Precedence::Exponentiation, ctx);
2224            p.print_str(" as ");
2225            self.type_annotation.print(p, ctx);
2226        });
2227    }
2228}
2229
2230impl GenExpr for TSSatisfiesExpression<'_> {
2231    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2232        p.print_ascii_byte(b'(');
2233        let should_wrap =
2234            if let Expression::FunctionExpression(func) = &self.expression.without_parentheses() {
2235                // pife is handled on Function side
2236                !func.pife
2237            } else {
2238                true
2239            };
2240        p.wrap(should_wrap, |p| {
2241            self.expression.print_expr(p, precedence, Context::default());
2242        });
2243        p.print_str(" satisfies ");
2244        self.type_annotation.print(p, ctx);
2245        p.print_ascii_byte(b')');
2246    }
2247}
2248
2249impl GenExpr for TSNonNullExpression<'_> {
2250    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2251        p.wrap(matches!(self.expression, Expression::ParenthesizedExpression(_)), |p| {
2252            self.expression.print_expr(p, precedence, ctx);
2253        });
2254        p.print_ascii_byte(b'!');
2255        if p.options.minify {
2256            p.print_hard_space();
2257        }
2258    }
2259}
2260
2261impl GenExpr for TSInstantiationExpression<'_> {
2262    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2263        self.expression.print_expr(p, precedence, ctx);
2264        self.type_arguments.print(p, ctx);
2265        if p.options.minify {
2266            p.print_hard_space();
2267        }
2268    }
2269}
2270
2271impl GenExpr for TSTypeAssertion<'_> {
2272    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
2273        p.wrap(precedence >= self.precedence(), |p| {
2274            p.print_str("<");
2275            // var r = < <T>(x: T) => T > ((x) => { return null; });
2276            //          ^ make sure space is printed here.
2277            if matches!(self.type_annotation, TSType::TSFunctionType(_)) {
2278                p.print_hard_space();
2279            }
2280            self.type_annotation.print(p, ctx);
2281            p.print_str(">");
2282            self.expression.print_expr(p, Precedence::Member, ctx);
2283        });
2284    }
2285}
2286
2287impl Gen for MetaProperty<'_> {
2288    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2289        p.print_space_before_identifier();
2290        p.add_source_mapping(self.span);
2291        self.meta.print(p, ctx);
2292        p.print_ascii_byte(b'.');
2293        self.property.print(p, ctx);
2294    }
2295}
2296
2297impl Gen for Class<'_> {
2298    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2299        let n = p.code_len();
2300        let wrap = self.is_expression() && (p.start_of_stmt == n || p.start_of_default_export == n);
2301        let ctx = ctx.and_forbid_call(false);
2302        p.wrap(wrap, |p| {
2303            p.enter_class();
2304            p.print_decorators(&self.decorators, ctx);
2305            p.print_space_before_identifier();
2306            p.add_source_mapping(self.span);
2307            if self.declare {
2308                p.print_str("declare ");
2309            }
2310            if self.r#abstract {
2311                p.print_str("abstract ");
2312            }
2313            p.print_str("class");
2314            if let Some(id) = &self.id {
2315                p.print_hard_space();
2316                id.print(p, ctx);
2317                if let Some(type_parameters) = self.type_parameters.as_ref() {
2318                    type_parameters.print(p, ctx);
2319                }
2320            }
2321            if let Some(super_class) = self.super_class.as_ref() {
2322                p.print_str(" extends ");
2323                super_class.print_expr(p, Precedence::Postfix, Context::empty());
2324                if let Some(super_type_parameters) = &self.super_type_arguments {
2325                    super_type_parameters.print(p, ctx);
2326                }
2327            }
2328            if !self.implements.is_empty() {
2329                p.print_str(" implements ");
2330                p.print_list(&self.implements, ctx);
2331            }
2332            p.print_soft_space();
2333            self.body.print(p, ctx);
2334            p.needs_semicolon = false;
2335            p.exit_class();
2336        });
2337    }
2338}
2339
2340impl Gen for ClassBody<'_> {
2341    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2342        p.print_curly_braces(self.span, self.body.is_empty(), |p| {
2343            for item in &self.body {
2344                p.print_semicolon_if_needed();
2345                p.print_leading_comments(item.span().start);
2346                p.print_indent();
2347                item.print(p, ctx);
2348            }
2349        });
2350    }
2351}
2352
2353impl Gen for ClassElement<'_> {
2354    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2355        match self {
2356            Self::StaticBlock(elem) => {
2357                elem.print(p, ctx);
2358                p.print_soft_newline();
2359            }
2360            Self::MethodDefinition(elem) => {
2361                elem.print(p, ctx);
2362                p.print_soft_newline();
2363            }
2364            Self::PropertyDefinition(elem) => {
2365                elem.print(p, ctx);
2366                p.print_semicolon_after_statement();
2367            }
2368            Self::AccessorProperty(elem) => {
2369                elem.print(p, ctx);
2370                p.print_semicolon_after_statement();
2371            }
2372            Self::TSIndexSignature(elem) => {
2373                elem.print(p, ctx);
2374                p.print_semicolon_after_statement();
2375            }
2376        }
2377    }
2378}
2379
2380impl Gen for JSXIdentifier<'_> {
2381    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2382        p.add_source_mapping_for_name(self.span, &self.name);
2383        p.print_str(self.name.as_str());
2384    }
2385}
2386
2387impl Gen for JSXMemberExpressionObject<'_> {
2388    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2389        match self {
2390            Self::IdentifierReference(ident) => ident.print(p, ctx),
2391            Self::MemberExpression(member_expr) => member_expr.print(p, ctx),
2392            Self::ThisExpression(expr) => expr.print(p, ctx),
2393        }
2394    }
2395}
2396
2397impl Gen for JSXMemberExpression<'_> {
2398    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2399        self.object.print(p, ctx);
2400        p.print_ascii_byte(b'.');
2401        self.property.print(p, ctx);
2402    }
2403}
2404
2405impl Gen for JSXElementName<'_> {
2406    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2407        match self {
2408            Self::Identifier(identifier) => identifier.print(p, ctx),
2409            Self::IdentifierReference(identifier) => identifier.print(p, ctx),
2410            Self::NamespacedName(namespaced_name) => namespaced_name.print(p, ctx),
2411            Self::MemberExpression(member_expr) => member_expr.print(p, ctx),
2412            Self::ThisExpression(expr) => expr.print(p, ctx),
2413        }
2414    }
2415}
2416
2417impl Gen for JSXNamespacedName<'_> {
2418    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2419        self.namespace.print(p, ctx);
2420        p.print_colon();
2421        self.name.print(p, ctx);
2422    }
2423}
2424
2425impl Gen for JSXAttributeName<'_> {
2426    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2427        match self {
2428            Self::Identifier(ident) => ident.print(p, ctx),
2429            Self::NamespacedName(namespaced_name) => namespaced_name.print(p, ctx),
2430        }
2431    }
2432}
2433
2434impl Gen for JSXAttribute<'_> {
2435    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2436        self.name.print(p, ctx);
2437        if let Some(value) = &self.value {
2438            p.print_equal();
2439            value.print(p, ctx);
2440        }
2441    }
2442}
2443
2444impl Gen for JSXEmptyExpression {
2445    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2446        p.print_comments_at(self.span.end);
2447    }
2448}
2449
2450impl Gen for JSXExpression<'_> {
2451    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2452        match self {
2453            Self::EmptyExpression(expr) => expr.print(p, ctx),
2454            _ => p.print_expression(self.to_expression()),
2455        }
2456    }
2457}
2458
2459impl Gen for JSXExpressionContainer<'_> {
2460    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2461        p.print_ascii_byte(b'{');
2462        self.expression.print(p, ctx);
2463        p.print_ascii_byte(b'}');
2464    }
2465}
2466
2467impl Gen for JSXAttributeValue<'_> {
2468    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2469        match self {
2470            Self::Fragment(fragment) => fragment.print(p, ctx),
2471            Self::Element(el) => el.print(p, ctx),
2472            Self::StringLiteral(lit) => {
2473                let quote = if lit.value.contains('"') { b'\'' } else { b'"' };
2474                p.print_ascii_byte(quote);
2475                p.print_str(&lit.value);
2476                p.print_ascii_byte(quote);
2477            }
2478            Self::ExpressionContainer(expr_container) => expr_container.print(p, ctx),
2479        }
2480    }
2481}
2482
2483impl Gen for JSXSpreadAttribute<'_> {
2484    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2485        p.print_str("{...");
2486        self.argument.print_expr(p, Precedence::Comma, Context::empty());
2487        p.print_ascii_byte(b'}');
2488    }
2489}
2490
2491impl Gen for JSXAttributeItem<'_> {
2492    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2493        match self {
2494            Self::Attribute(attr) => attr.print(p, ctx),
2495            Self::SpreadAttribute(spread_attr) => spread_attr.print(p, ctx),
2496        }
2497    }
2498}
2499
2500impl Gen for JSXElement<'_> {
2501    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2502        // Opening element.
2503        // Cannot `impl Gen for JSXOpeningElement` because it needs to know value of `self.closing_element`
2504        // to determine whether to print a trailing `/`.
2505        p.add_source_mapping(self.opening_element.span);
2506        p.print_ascii_byte(b'<');
2507        self.opening_element.name.print(p, ctx);
2508        for attr in &self.opening_element.attributes {
2509            match attr {
2510                JSXAttributeItem::Attribute(_) => {
2511                    p.print_hard_space();
2512                }
2513                JSXAttributeItem::SpreadAttribute(_) => {
2514                    p.print_soft_space();
2515                }
2516            }
2517            attr.print(p, ctx);
2518        }
2519        if self.closing_element.is_none() {
2520            p.print_soft_space();
2521            p.print_str("/");
2522        }
2523        p.print_ascii_byte(b'>');
2524
2525        // Children
2526        for child in &self.children {
2527            child.print(p, ctx);
2528        }
2529
2530        // Closing element
2531        if let Some(closing_element) = &self.closing_element {
2532            p.add_source_mapping(closing_element.span);
2533            p.print_str("</");
2534            closing_element.name.print(p, ctx);
2535            p.print_ascii_byte(b'>');
2536        }
2537    }
2538}
2539
2540impl Gen for JSXOpeningFragment {
2541    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2542        p.add_source_mapping(self.span);
2543        p.print_str("<>");
2544    }
2545}
2546
2547impl Gen for JSXClosingFragment {
2548    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2549        p.add_source_mapping(self.span);
2550        p.print_str("</>");
2551    }
2552}
2553
2554impl Gen for JSXText<'_> {
2555    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2556        p.add_source_mapping(self.span);
2557        p.print_str(self.value.as_str());
2558    }
2559}
2560
2561impl Gen for JSXSpreadChild<'_> {
2562    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2563        p.print_str("{...");
2564        p.print_expression(&self.expression);
2565        p.print_ascii_byte(b'}');
2566    }
2567}
2568
2569impl Gen for JSXChild<'_> {
2570    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2571        match self {
2572            Self::Fragment(fragment) => fragment.print(p, ctx),
2573            Self::Element(el) => el.print(p, ctx),
2574            Self::Spread(spread) => spread.print(p, ctx),
2575            Self::ExpressionContainer(expr_container) => expr_container.print(p, ctx),
2576            Self::Text(text) => text.print(p, ctx),
2577        }
2578    }
2579}
2580
2581impl Gen for JSXFragment<'_> {
2582    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2583        self.opening_fragment.print(p, ctx);
2584        for child in &self.children {
2585            child.print(p, ctx);
2586        }
2587        self.closing_fragment.print(p, ctx);
2588    }
2589}
2590
2591impl Gen for StaticBlock<'_> {
2592    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2593        p.add_source_mapping(self.span);
2594        p.print_str("static");
2595        p.print_soft_space();
2596        p.print_curly_braces(self.span, self.body.is_empty(), |p| {
2597            for stmt in &self.body {
2598                p.print_semicolon_if_needed();
2599                stmt.print(p, ctx);
2600            }
2601        });
2602        p.needs_semicolon = false;
2603    }
2604}
2605
2606impl Gen for MethodDefinition<'_> {
2607    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2608        p.add_source_mapping(self.span);
2609        p.print_decorators(&self.decorators, ctx);
2610        if let Some(accessibility) = &self.accessibility {
2611            p.print_space_before_identifier();
2612            p.print_str(accessibility.as_str());
2613            p.print_soft_space();
2614        }
2615        if self.r#type == MethodDefinitionType::TSAbstractMethodDefinition {
2616            p.print_space_before_identifier();
2617            p.print_str("abstract");
2618            p.print_soft_space();
2619        }
2620        if self.r#static {
2621            p.print_space_before_identifier();
2622            p.print_str("static");
2623            p.print_soft_space();
2624        }
2625        match &self.kind {
2626            MethodDefinitionKind::Constructor | MethodDefinitionKind::Method => {}
2627            MethodDefinitionKind::Get => {
2628                p.print_space_before_identifier();
2629                p.print_str("get");
2630                p.print_soft_space();
2631            }
2632            MethodDefinitionKind::Set => {
2633                p.print_space_before_identifier();
2634                p.print_str("set");
2635                p.print_soft_space();
2636            }
2637        }
2638        if self.value.r#async {
2639            p.print_space_before_identifier();
2640            p.print_str("async");
2641            p.print_soft_space();
2642        }
2643        if self.value.generator {
2644            p.print_str("*");
2645        }
2646        if self.computed {
2647            p.print_ascii_byte(b'[');
2648        }
2649        self.key.print(p, ctx);
2650        if self.computed {
2651            p.print_ascii_byte(b']');
2652        }
2653        if self.optional {
2654            p.print_ascii_byte(b'?');
2655        }
2656        if let Some(type_parameters) = self.value.type_parameters.as_ref() {
2657            type_parameters.print(p, ctx);
2658        }
2659        p.print_ascii_byte(b'(');
2660        if let Some(this_param) = &self.value.this_param {
2661            this_param.print(p, ctx);
2662            if !self.value.params.is_empty() || self.value.params.rest.is_some() {
2663                p.print_str(",");
2664                p.print_soft_space();
2665            }
2666        }
2667        self.value.params.print(p, ctx);
2668        p.print_ascii_byte(b')');
2669        if let Some(return_type) = &self.value.return_type {
2670            p.print_colon();
2671            p.print_soft_space();
2672            return_type.print(p, ctx);
2673        }
2674        if let Some(body) = &self.value.body {
2675            p.print_soft_space();
2676            body.print(p, ctx);
2677        } else {
2678            p.print_semicolon();
2679        }
2680    }
2681}
2682
2683impl Gen for PropertyDefinition<'_> {
2684    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2685        p.add_source_mapping(self.span);
2686        p.print_decorators(&self.decorators, ctx);
2687        if self.declare {
2688            p.print_space_before_identifier();
2689            p.print_str("declare");
2690            p.print_soft_space();
2691        }
2692        if let Some(accessibility) = self.accessibility {
2693            p.print_space_before_identifier();
2694            p.print_str(accessibility.as_str());
2695            p.print_soft_space();
2696        }
2697        if self.r#type == PropertyDefinitionType::TSAbstractPropertyDefinition {
2698            p.print_space_before_identifier();
2699            p.print_str("abstract");
2700            p.print_soft_space();
2701        }
2702        if self.r#static {
2703            p.print_space_before_identifier();
2704            p.print_str("static");
2705            p.print_soft_space();
2706        }
2707        if self.readonly {
2708            p.print_space_before_identifier();
2709            p.print_str("readonly");
2710            p.print_soft_space();
2711        }
2712        if self.computed {
2713            p.print_ascii_byte(b'[');
2714        }
2715        self.key.print(p, ctx);
2716        if self.computed {
2717            p.print_ascii_byte(b']');
2718        }
2719        if self.optional {
2720            p.print_str("?");
2721        }
2722        if let Some(type_annotation) = &self.type_annotation {
2723            p.print_colon();
2724            p.print_soft_space();
2725            type_annotation.print(p, ctx);
2726        }
2727        if let Some(value) = &self.value {
2728            p.print_soft_space();
2729            p.print_equal();
2730            p.print_soft_space();
2731            value.print_expr(p, Precedence::Comma, Context::empty());
2732        }
2733    }
2734}
2735
2736impl Gen for AccessorProperty<'_> {
2737    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2738        p.add_source_mapping(self.span);
2739        p.print_decorators(&self.decorators, ctx);
2740        if self.r#type.is_abstract() {
2741            p.print_space_before_identifier();
2742            p.print_str("abstract");
2743            p.print_soft_space();
2744        }
2745        if let Some(accessibility) = self.accessibility {
2746            p.print_space_before_identifier();
2747            p.print_str(accessibility.as_str());
2748            p.print_soft_space();
2749        }
2750        if self.r#static {
2751            p.print_space_before_identifier();
2752            p.print_str("static");
2753            p.print_soft_space();
2754        }
2755        if self.r#override {
2756            p.print_space_before_identifier();
2757            p.print_str("override");
2758            p.print_soft_space();
2759        }
2760        p.print_space_before_identifier();
2761        p.print_str("accessor");
2762        if self.computed {
2763            p.print_soft_space();
2764            p.print_ascii_byte(b'[');
2765        } else {
2766            p.print_hard_space();
2767        }
2768        self.key.print(p, ctx);
2769        if self.computed {
2770            p.print_ascii_byte(b']');
2771        }
2772        if let Some(type_annotation) = &self.type_annotation {
2773            p.print_colon();
2774            p.print_soft_space();
2775            type_annotation.print(p, ctx);
2776        }
2777        if let Some(value) = &self.value {
2778            p.print_soft_space();
2779            p.print_equal();
2780            p.print_soft_space();
2781            value.print_expr(p, Precedence::Comma, Context::empty());
2782        }
2783    }
2784}
2785
2786impl Gen for PrivateIdentifier<'_> {
2787    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2788        let name = if let Some(private_member_mappings) = &p.private_member_mappings
2789            && let Some(mangled) = p.current_class_ids().find_map(|class_id| {
2790                private_member_mappings.get(class_id).and_then(|m| m.get(self.name.as_str()))
2791            }) {
2792            (*mangled).clone()
2793        } else {
2794            self.name.into_compact_str()
2795        };
2796
2797        p.print_ascii_byte(b'#');
2798        p.add_source_mapping_for_name(self.span, &self.name);
2799        p.print_str(name.as_str());
2800    }
2801}
2802
2803impl Gen for BindingPattern<'_> {
2804    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2805        self.kind.print(p, ctx);
2806        if self.optional {
2807            p.print_str("?");
2808        }
2809        if let Some(type_annotation) = &self.type_annotation {
2810            p.print_colon();
2811            p.print_soft_space();
2812            type_annotation.print(p, ctx);
2813        }
2814    }
2815}
2816
2817impl Gen for BindingPatternKind<'_> {
2818    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2819        match self {
2820            BindingPatternKind::BindingIdentifier(ident) => ident.print(p, ctx),
2821            BindingPatternKind::ObjectPattern(pattern) => pattern.print(p, ctx),
2822            BindingPatternKind::ArrayPattern(pattern) => pattern.print(p, ctx),
2823            BindingPatternKind::AssignmentPattern(pattern) => pattern.print(p, ctx),
2824        }
2825    }
2826}
2827
2828impl Gen for ObjectPattern<'_> {
2829    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2830        p.add_source_mapping(self.span);
2831        if self.is_empty() {
2832            p.print_str("{}");
2833            return;
2834        }
2835        p.print_ascii_byte(b'{');
2836        p.print_soft_space();
2837        p.print_list(&self.properties, ctx);
2838        if let Some(rest) = &self.rest {
2839            if !self.properties.is_empty() {
2840                p.print_comma();
2841                p.print_soft_space();
2842            }
2843            rest.print(p, ctx);
2844        }
2845        p.print_soft_space();
2846        p.print_ascii_byte(b'}');
2847    }
2848}
2849
2850impl Gen for BindingProperty<'_> {
2851    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2852        let mut shorthand = false;
2853        if let PropertyKey::StaticIdentifier(key) = &self.key {
2854            match &self.value.kind {
2855                BindingPatternKind::BindingIdentifier(ident)
2856                    if key.name == p.get_binding_identifier_name(ident) =>
2857                {
2858                    shorthand = true;
2859                }
2860                BindingPatternKind::AssignmentPattern(assignment_pattern) => {
2861                    if let BindingPatternKind::BindingIdentifier(ident) =
2862                        &assignment_pattern.left.kind
2863                        && key.name == p.get_binding_identifier_name(ident)
2864                    {
2865                        shorthand = true;
2866                    }
2867                }
2868                _ => {}
2869            }
2870        }
2871
2872        if !shorthand {
2873            if self.computed {
2874                p.print_ascii_byte(b'[');
2875            }
2876            self.key.print(p, ctx);
2877            if self.computed {
2878                p.print_ascii_byte(b']');
2879            }
2880            p.print_colon();
2881            p.print_soft_space();
2882        }
2883
2884        self.value.print(p, ctx);
2885    }
2886}
2887
2888impl Gen for BindingRestElement<'_> {
2889    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2890        p.add_source_mapping(self.span);
2891        p.print_ellipsis();
2892        self.argument.print(p, ctx);
2893    }
2894}
2895
2896impl Gen for ArrayPattern<'_> {
2897    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2898        p.add_source_mapping(self.span);
2899        p.print_ascii_byte(b'[');
2900        for (index, item) in self.elements.iter().enumerate() {
2901            if index != 0 {
2902                p.print_comma();
2903                p.print_soft_space();
2904            }
2905            if let Some(item) = item {
2906                item.print(p, ctx);
2907            }
2908            if index == self.elements.len() - 1 && (item.is_none() || self.rest.is_some()) {
2909                p.print_comma();
2910            }
2911        }
2912        if let Some(rest) = &self.rest {
2913            p.print_soft_space();
2914            rest.print(p, ctx);
2915        }
2916        p.print_ascii_byte(b']');
2917    }
2918}
2919
2920impl Gen for AssignmentPattern<'_> {
2921    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2922        self.left.print(p, ctx);
2923        p.print_soft_space();
2924        p.print_equal();
2925        p.print_soft_space();
2926        self.right.print_expr(p, Precedence::Comma, Context::empty());
2927    }
2928}
2929
2930impl Gen for Decorator<'_> {
2931    fn r#gen(&self, p: &mut Codegen, _ctx: Context) {
2932        fn need_wrap(expr: &Expression) -> bool {
2933            match expr {
2934                // "@foo"
2935                // "@foo.bar"
2936                // "@foo.#bar"
2937                Expression::Identifier(_)
2938                | Expression::StaticMemberExpression(_)
2939                | Expression::PrivateFieldExpression(_) => false,
2940                Expression::CallExpression(call_expr) => need_wrap(&call_expr.callee),
2941                // "@(foo + bar)"
2942                // "@(() => {})"
2943                // "@(foo['bar'])"
2944                _ => true,
2945            }
2946        }
2947
2948        p.add_source_mapping(self.span);
2949        p.print_ascii_byte(b'@');
2950        let wrap = need_wrap(&self.expression);
2951        p.wrap(wrap, |p| {
2952            self.expression.print_expr(p, Precedence::Lowest, Context::empty());
2953        });
2954    }
2955}
2956
2957impl Gen for TSClassImplements<'_> {
2958    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2959        self.expression.print(p, ctx);
2960        if let Some(type_parameters) = self.type_arguments.as_ref() {
2961            type_parameters.print(p, ctx);
2962        }
2963    }
2964}
2965
2966impl Gen for TSTypeParameterDeclaration<'_> {
2967    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
2968        let is_multi_line = self.params.len() >= 2;
2969        p.print_ascii_byte(b'<');
2970        if is_multi_line {
2971            p.indent();
2972        }
2973        for (index, item) in self.params.iter().enumerate() {
2974            if index != 0 {
2975                p.print_comma();
2976            }
2977            if is_multi_line {
2978                p.print_soft_newline();
2979                p.print_indent();
2980            } else if index != 0 {
2981                p.print_soft_space();
2982            }
2983            item.print(p, ctx);
2984        }
2985        if is_multi_line {
2986            p.print_soft_newline();
2987            p.dedent();
2988            p.print_indent();
2989        } else if p.is_jsx {
2990            // `<T,>() => {}`
2991            //    ^ We need a comma here, otherwise it will be regarded as a JSX element.
2992            p.print_str(",");
2993        }
2994        p.print_ascii_byte(b'>');
2995    }
2996}
2997
2998impl Gen for TSTypeAnnotation<'_> {
2999    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3000        self.type_annotation.print(p, ctx);
3001    }
3002}
3003
3004impl Gen for TSType<'_> {
3005    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3006        let ctx = ctx.with_typescript();
3007        match self {
3008            Self::TSFunctionType(ty) => ty.print(p, ctx),
3009            Self::TSConstructorType(ty) => ty.print(p, ctx),
3010            Self::TSArrayType(ty) => ty.print(p, ctx),
3011            Self::TSTupleType(ty) => ty.print(p, ctx),
3012            Self::TSUnionType(ty) => ty.print(p, ctx),
3013            Self::TSParenthesizedType(ty) => ty.print(p, ctx),
3014            Self::TSIntersectionType(ty) => ty.print(p, ctx),
3015            Self::TSConditionalType(ty) => ty.print(p, ctx),
3016            Self::TSInferType(ty) => ty.print(p, ctx),
3017            Self::TSIndexedAccessType(ty) => ty.print(p, ctx),
3018            Self::TSMappedType(ty) => ty.print(p, ctx),
3019            Self::TSNamedTupleMember(ty) => ty.print(p, ctx),
3020            Self::TSLiteralType(ty) => ty.literal.print(p, ctx),
3021            Self::TSImportType(ty) => ty.print(p, ctx),
3022            Self::TSAnyKeyword(_) => p.print_str("any"),
3023            Self::TSBigIntKeyword(_) => p.print_str("bigint"),
3024            Self::TSBooleanKeyword(_) => p.print_str("boolean"),
3025            Self::TSIntrinsicKeyword(_) => p.print_str("intrinsic"),
3026            Self::TSNeverKeyword(_) => p.print_str("never"),
3027            Self::TSNullKeyword(_) => p.print_str("null"),
3028            Self::TSNumberKeyword(_) => p.print_str("number"),
3029            Self::TSObjectKeyword(_) => p.print_str("object"),
3030            Self::TSStringKeyword(_) => p.print_str("string"),
3031            Self::TSSymbolKeyword(_) => p.print_str("symbol"),
3032            Self::TSThisType(_) => p.print_str("this"),
3033            Self::TSUndefinedKeyword(_) => p.print_str("undefined"),
3034            Self::TSUnknownKeyword(_) => p.print_str("unknown"),
3035            Self::TSVoidKeyword(_) => p.print_str("void"),
3036            Self::TSTemplateLiteralType(ty) => ty.print(p, ctx),
3037            Self::TSTypeLiteral(ty) => ty.print(p, ctx),
3038            Self::TSTypeOperatorType(ty) => ty.print(p, ctx),
3039            Self::TSTypePredicate(ty) => ty.print(p, ctx),
3040            Self::TSTypeQuery(ty) => ty.print(p, ctx),
3041            Self::TSTypeReference(ty) => ty.print(p, ctx),
3042            Self::JSDocNullableType(ty) => ty.print(p, ctx),
3043            Self::JSDocNonNullableType(ty) => ty.print(p, ctx),
3044            Self::JSDocUnknownType(_ty) => p.print_str("unknown"),
3045        }
3046    }
3047}
3048
3049impl Gen for TSArrayType<'_> {
3050    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3051        self.element_type.print(p, ctx);
3052        p.print_str("[]");
3053    }
3054}
3055
3056impl Gen for TSTupleType<'_> {
3057    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3058        p.print_str("[");
3059        p.print_list(&self.element_types, ctx);
3060        p.print_str("]");
3061    }
3062}
3063
3064fn parenthesize_check_type_of_conditional_type(ty: &TSType<'_>) -> bool {
3065    matches!(
3066        ty,
3067        TSType::TSFunctionType(_) | TSType::TSConstructorType(_) | TSType::TSConditionalType(_)
3068    )
3069}
3070
3071impl Gen for TSUnionType<'_> {
3072    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3073        let Some((first, rest)) = self.types.split_first() else {
3074            return;
3075        };
3076        p.wrap(parenthesize_check_type_of_conditional_type(first), |p| {
3077            first.print(p, ctx);
3078        });
3079        for item in rest {
3080            p.print_soft_space();
3081            p.print_str("|");
3082            p.print_soft_space();
3083            p.wrap(parenthesize_check_type_of_conditional_type(item), |p| {
3084                item.print(p, ctx);
3085            });
3086        }
3087    }
3088}
3089
3090impl Gen for TSParenthesizedType<'_> {
3091    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3092        p.print_ascii_byte(b'(');
3093        self.type_annotation.print(p, ctx);
3094        p.print_ascii_byte(b')');
3095    }
3096}
3097
3098impl Gen for TSIntersectionType<'_> {
3099    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3100        let Some((first, rest)) = self.types.split_first() else {
3101            return;
3102        };
3103        first.print(p, ctx);
3104        for item in rest {
3105            p.print_soft_space();
3106            p.print_str("&");
3107            p.print_soft_space();
3108            item.print(p, ctx);
3109        }
3110    }
3111}
3112
3113impl Gen for TSConditionalType<'_> {
3114    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3115        self.check_type.print(p, ctx);
3116        p.print_str(" extends ");
3117        self.extends_type.print(p, ctx);
3118        p.print_str(" ? ");
3119        self.true_type.print(p, ctx);
3120        p.print_str(" : ");
3121        self.false_type.print(p, ctx);
3122    }
3123}
3124
3125impl Gen for TSInferType<'_> {
3126    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3127        p.print_str("infer ");
3128        self.type_parameter.print(p, ctx);
3129    }
3130}
3131
3132impl Gen for TSIndexedAccessType<'_> {
3133    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3134        self.object_type.print(p, ctx);
3135        p.print_str("[");
3136        self.index_type.print(p, ctx);
3137        p.print_str("]");
3138    }
3139}
3140
3141impl Gen for TSMappedType<'_> {
3142    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3143        p.print_str("{");
3144        p.print_soft_space();
3145        match self.readonly {
3146            Some(TSMappedTypeModifierOperator::True) => p.print_str("readonly "),
3147            Some(TSMappedTypeModifierOperator::Plus) => p.print_str("+readonly "),
3148            Some(TSMappedTypeModifierOperator::Minus) => p.print_str("-readonly "),
3149            None => {}
3150        }
3151        p.print_str("[");
3152        self.type_parameter.name.print(p, ctx);
3153        if let Some(constraint) = &self.type_parameter.constraint {
3154            p.print_str(" in ");
3155            constraint.print(p, ctx);
3156        }
3157        if let Some(default) = &self.type_parameter.default {
3158            p.print_str(" = ");
3159            default.print(p, ctx);
3160        }
3161        if let Some(name_type) = &self.name_type {
3162            p.print_str(" as ");
3163            name_type.print(p, ctx);
3164        }
3165        p.print_str("]");
3166        match self.optional {
3167            Some(TSMappedTypeModifierOperator::True) => p.print_str("?"),
3168            Some(TSMappedTypeModifierOperator::Plus) => p.print_str("+?"),
3169            Some(TSMappedTypeModifierOperator::Minus) => p.print_str("-?"),
3170            None => {}
3171        }
3172        p.print_soft_space();
3173        if let Some(type_annotation) = &self.type_annotation {
3174            p.print_str(":");
3175            p.print_soft_space();
3176            type_annotation.print(p, ctx);
3177        }
3178        p.print_soft_space();
3179        p.print_str("}");
3180    }
3181}
3182
3183impl Gen for TSQualifiedName<'_> {
3184    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3185        self.left.print(p, ctx);
3186        p.print_str(".");
3187        self.right.print(p, ctx);
3188    }
3189}
3190
3191impl Gen for TSTypeOperator<'_> {
3192    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3193        p.print_str(self.operator.to_str());
3194        p.print_hard_space();
3195        self.type_annotation.print(p, ctx);
3196    }
3197}
3198
3199impl Gen for TSTypePredicate<'_> {
3200    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3201        if self.asserts {
3202            p.print_str("asserts ");
3203        }
3204        match &self.parameter_name {
3205            TSTypePredicateName::Identifier(ident) => {
3206                ident.print(p, ctx);
3207            }
3208            TSTypePredicateName::This(_ident) => {
3209                p.print_str("this");
3210            }
3211        }
3212        if let Some(type_annotation) = &self.type_annotation {
3213            p.print_str(" is ");
3214            type_annotation.print(p, ctx);
3215        }
3216    }
3217}
3218
3219impl Gen for TSTypeReference<'_> {
3220    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3221        self.type_name.print(p, ctx);
3222        if let Some(type_parameters) = &self.type_arguments {
3223            type_parameters.print(p, ctx);
3224        }
3225    }
3226}
3227
3228impl Gen for JSDocNullableType<'_> {
3229    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3230        if self.postfix {
3231            self.type_annotation.print(p, ctx);
3232            p.print_str("?");
3233        } else {
3234            p.print_str("?");
3235            self.type_annotation.print(p, ctx);
3236        }
3237    }
3238}
3239
3240impl Gen for JSDocNonNullableType<'_> {
3241    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3242        if self.postfix {
3243            self.type_annotation.print(p, ctx);
3244            p.print_str("!");
3245        } else {
3246            p.print_str("!");
3247            self.type_annotation.print(p, ctx);
3248        }
3249    }
3250}
3251
3252impl Gen for TSTemplateLiteralType<'_> {
3253    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3254        p.print_str("`");
3255        for (index, item) in self.quasis.iter().enumerate() {
3256            if index != 0
3257                && let Some(types) = self.types.get(index - 1)
3258            {
3259                p.print_str("${");
3260                types.print(p, ctx);
3261                p.print_str("}");
3262            }
3263            p.print_str(item.value.raw.as_str());
3264        }
3265        p.print_str("`");
3266    }
3267}
3268
3269impl Gen for TSTypeLiteral<'_> {
3270    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3271        p.print_curly_braces(self.span, self.members.is_empty(), |p| {
3272            for item in &self.members {
3273                p.print_leading_comments(item.span().start);
3274                p.print_indent();
3275                item.print(p, ctx);
3276                p.print_semicolon();
3277                p.print_soft_newline();
3278            }
3279        });
3280    }
3281}
3282
3283impl Gen for TSTypeName<'_> {
3284    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3285        match self {
3286            Self::IdentifierReference(ident) => {
3287                ident.print(p, ctx);
3288            }
3289            Self::QualifiedName(decl) => {
3290                decl.left.print(p, ctx);
3291                p.print_str(".");
3292                decl.right.print(p, ctx);
3293            }
3294            Self::ThisExpression(e) => {
3295                e.print(p, ctx);
3296            }
3297        }
3298    }
3299}
3300
3301impl Gen for TSLiteral<'_> {
3302    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3303        match self {
3304            Self::BooleanLiteral(decl) => decl.print(p, ctx),
3305            Self::NumericLiteral(decl) => decl.print_expr(p, Precedence::Lowest, ctx),
3306            Self::BigIntLiteral(decl) => decl.print_expr(p, Precedence::Lowest, ctx),
3307            Self::StringLiteral(decl) => decl.print(p, ctx),
3308            Self::TemplateLiteral(decl) => decl.print(p, ctx),
3309            Self::UnaryExpression(decl) => decl.print_expr(p, Precedence::Comma, ctx),
3310        }
3311    }
3312}
3313
3314impl Gen for TSTypeParameter<'_> {
3315    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3316        if self.r#const {
3317            p.print_str("const ");
3318        }
3319        if self.r#in {
3320            p.print_str("in ");
3321        }
3322        if self.out {
3323            p.print_str("out ");
3324        }
3325        self.name.print(p, ctx);
3326        if let Some(constraint) = &self.constraint {
3327            p.print_str(" extends ");
3328            constraint.print(p, ctx);
3329        }
3330        if let Some(default) = &self.default {
3331            p.print_str(" = ");
3332            default.print(p, ctx);
3333        }
3334    }
3335}
3336
3337impl Gen for TSFunctionType<'_> {
3338    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3339        if let Some(type_parameters) = &self.type_parameters {
3340            type_parameters.print(p, ctx);
3341        }
3342        p.print_str("(");
3343        if let Some(this_param) = &self.this_param {
3344            this_param.print(p, ctx);
3345            if !self.params.is_empty() || self.params.rest.is_some() {
3346                p.print_str(",");
3347                p.print_soft_space();
3348            }
3349        }
3350        self.params.print(p, ctx);
3351        p.print_str(")");
3352        p.print_soft_space();
3353        p.print_str("=>");
3354        p.print_soft_space();
3355        self.return_type.print(p, ctx);
3356    }
3357}
3358
3359impl Gen for TSThisParameter<'_> {
3360    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3361        p.print_str("this");
3362        if let Some(type_annotation) = &self.type_annotation {
3363            p.print_str(": ");
3364            type_annotation.print(p, ctx);
3365        }
3366    }
3367}
3368
3369impl Gen for TSSignature<'_> {
3370    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3371        match self {
3372            Self::TSIndexSignature(signature) => signature.print(p, ctx),
3373            Self::TSPropertySignature(signature) => signature.r#gen(p, ctx),
3374            Self::TSCallSignatureDeclaration(signature) => {
3375                if let Some(type_parameters) = signature.type_parameters.as_ref() {
3376                    type_parameters.print(p, ctx);
3377                }
3378                p.print_str("(");
3379                if let Some(this_param) = &signature.this_param {
3380                    this_param.print(p, ctx);
3381                    if !signature.params.is_empty() || signature.params.rest.is_some() {
3382                        p.print_str(",");
3383                        p.print_soft_space();
3384                    }
3385                }
3386                signature.params.print(p, ctx);
3387                p.print_str(")");
3388                if let Some(return_type) = &signature.return_type {
3389                    p.print_colon();
3390                    p.print_soft_space();
3391                    return_type.print(p, ctx);
3392                }
3393            }
3394            Self::TSConstructSignatureDeclaration(signature) => {
3395                p.print_str("new ");
3396                if let Some(type_parameters) = signature.type_parameters.as_ref() {
3397                    type_parameters.print(p, ctx);
3398                }
3399                p.print_str("(");
3400                signature.params.print(p, ctx);
3401                p.print_str(")");
3402                if let Some(return_type) = &signature.return_type {
3403                    p.print_colon();
3404                    p.print_soft_space();
3405                    return_type.print(p, ctx);
3406                }
3407            }
3408            Self::TSMethodSignature(signature) => {
3409                match signature.kind {
3410                    TSMethodSignatureKind::Method => {}
3411                    TSMethodSignatureKind::Get => p.print_str("get "),
3412                    TSMethodSignatureKind::Set => p.print_str("set "),
3413                }
3414                if signature.computed {
3415                    p.print_ascii_byte(b'[');
3416                    signature.key.print(p, ctx);
3417                    p.print_ascii_byte(b']');
3418                } else {
3419                    match &signature.key {
3420                        PropertyKey::StaticIdentifier(key) => {
3421                            key.print(p, ctx);
3422                        }
3423                        PropertyKey::PrivateIdentifier(key) => {
3424                            p.print_str(key.name.as_str());
3425                        }
3426                        PropertyKey::StringLiteral(key) => {
3427                            p.print_string_literal(key, false);
3428                        }
3429                        key => {
3430                            key.to_expression().print_expr(p, Precedence::Comma, ctx);
3431                        }
3432                    }
3433                }
3434                if signature.optional {
3435                    p.print_str("?");
3436                }
3437                if let Some(type_parameters) = &signature.type_parameters {
3438                    type_parameters.print(p, ctx);
3439                }
3440                p.print_str("(");
3441                if let Some(this_param) = &signature.this_param {
3442                    this_param.print(p, ctx);
3443                    if !signature.params.is_empty() || signature.params.rest.is_some() {
3444                        p.print_str(",");
3445                        p.print_soft_space();
3446                    }
3447                }
3448                signature.params.print(p, ctx);
3449                p.print_str(")");
3450                if let Some(return_type) = &signature.return_type {
3451                    p.print_colon();
3452                    p.print_soft_space();
3453                    return_type.print(p, ctx);
3454                }
3455            }
3456        }
3457    }
3458}
3459
3460impl Gen for TSPropertySignature<'_> {
3461    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3462        if self.readonly {
3463            p.print_str("readonly ");
3464        }
3465        if self.computed {
3466            p.print_ascii_byte(b'[');
3467            self.key.print(p, ctx);
3468            p.print_ascii_byte(b']');
3469        } else {
3470            match &self.key {
3471                PropertyKey::StaticIdentifier(key) => {
3472                    key.print(p, ctx);
3473                }
3474                PropertyKey::PrivateIdentifier(key) => {
3475                    p.print_str(key.name.as_str());
3476                }
3477                PropertyKey::StringLiteral(key) => {
3478                    p.print_string_literal(key, false);
3479                }
3480                key => {
3481                    key.to_expression().print_expr(p, Precedence::Comma, ctx);
3482                }
3483            }
3484        }
3485        if self.optional {
3486            p.print_str("?");
3487        }
3488        if let Some(type_annotation) = &self.type_annotation {
3489            p.print_colon();
3490            p.print_soft_space();
3491            type_annotation.print(p, ctx);
3492        }
3493    }
3494}
3495
3496impl Gen for TSTypeQuery<'_> {
3497    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3498        p.print_str("typeof ");
3499        self.expr_name.print(p, ctx);
3500        if let Some(type_params) = &self.type_arguments {
3501            type_params.print(p, ctx);
3502        }
3503    }
3504}
3505
3506impl Gen for TSTypeQueryExprName<'_> {
3507    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3508        match self {
3509            match_ts_type_name!(Self) => self.to_ts_type_name().print(p, ctx),
3510            Self::TSImportType(decl) => decl.print(p, ctx),
3511        }
3512    }
3513}
3514
3515impl Gen for TSImportType<'_> {
3516    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3517        p.print_str("import(");
3518        self.argument.print(p, ctx);
3519        if let Some(options) = &self.options {
3520            p.print_str(", ");
3521            options.print_expr(p, Precedence::Lowest, ctx);
3522        }
3523        p.print_str(")");
3524        if let Some(qualifier) = &self.qualifier {
3525            p.print_ascii_byte(b'.');
3526            qualifier.print(p, ctx);
3527        }
3528        if let Some(type_parameters) = &self.type_arguments {
3529            type_parameters.print(p, ctx);
3530        }
3531    }
3532}
3533
3534impl Gen for TSImportTypeQualifier<'_> {
3535    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3536        match self {
3537            TSImportTypeQualifier::Identifier(ident) => {
3538                p.print_str(ident.name.as_str());
3539            }
3540            TSImportTypeQualifier::QualifiedName(qualified) => {
3541                qualified.print(p, ctx);
3542            }
3543        }
3544    }
3545}
3546
3547impl Gen for TSImportTypeQualifiedName<'_> {
3548    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3549        self.left.print(p, ctx);
3550        p.print_ascii_byte(b'.');
3551        p.print_str(self.right.name.as_str());
3552    }
3553}
3554
3555impl Gen for TSTypeParameterInstantiation<'_> {
3556    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3557        p.print_str("<");
3558        p.print_list(&self.params, ctx);
3559        p.print_str(">");
3560    }
3561}
3562
3563impl Gen for TSIndexSignature<'_> {
3564    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3565        if self.readonly {
3566            p.print_str("readonly ");
3567        }
3568        p.print_str("[");
3569        for (index, parameter) in self.parameters.iter().enumerate() {
3570            if index != 0 {
3571                p.print_str(",");
3572                p.print_soft_space();
3573            }
3574            p.print_str(parameter.name.as_str());
3575            p.print_colon();
3576            p.print_soft_space();
3577            parameter.type_annotation.print(p, ctx);
3578        }
3579        p.print_str("]");
3580        p.print_colon();
3581        p.print_soft_space();
3582        self.type_annotation.print(p, ctx);
3583    }
3584}
3585
3586impl Gen for TSTupleElement<'_> {
3587    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3588        match self {
3589            match_ts_type!(TSTupleElement) => self.to_ts_type().print(p, ctx),
3590            TSTupleElement::TSOptionalType(ts_type) => {
3591                ts_type.type_annotation.print(p, ctx);
3592                p.print_str("?");
3593            }
3594            TSTupleElement::TSRestType(ts_type) => {
3595                p.print_str("...");
3596                ts_type.type_annotation.print(p, ctx);
3597            }
3598        }
3599    }
3600}
3601
3602impl Gen for TSNamedTupleMember<'_> {
3603    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3604        self.label.print(p, ctx);
3605        if self.optional {
3606            p.print_str("?");
3607        }
3608        p.print_str(":");
3609        p.print_soft_space();
3610        self.element_type.print(p, ctx);
3611    }
3612}
3613
3614impl Gen for TSModuleDeclaration<'_> {
3615    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3616        if self.declare {
3617            p.print_str("declare ");
3618        }
3619        p.print_str(self.kind.as_str());
3620        p.print_space_before_identifier();
3621        self.id.print(p, ctx);
3622
3623        if let Some(body) = &self.body {
3624            let mut body = body;
3625            loop {
3626                match body {
3627                    TSModuleDeclarationBody::TSModuleDeclaration(b) => {
3628                        p.print_ascii_byte(b'.');
3629                        b.id.print(p, ctx);
3630                        if let Some(b) = &b.body {
3631                            body = b;
3632                        } else {
3633                            break;
3634                        }
3635                    }
3636                    TSModuleDeclarationBody::TSModuleBlock(body) => {
3637                        p.print_soft_space();
3638                        body.print(p, ctx);
3639                        break;
3640                    }
3641                }
3642            }
3643        } else {
3644            p.print_semicolon();
3645        }
3646        p.needs_semicolon = false;
3647    }
3648}
3649
3650impl Gen for TSModuleDeclarationName<'_> {
3651    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3652        match self {
3653            Self::Identifier(ident) => ident.print(p, ctx),
3654            Self::StringLiteral(s) => p.print_string_literal(s, false),
3655        }
3656    }
3657}
3658
3659impl Gen for TSGlobalDeclaration<'_> {
3660    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3661        if self.declare {
3662            p.print_str("declare ");
3663        }
3664        p.print_str("global");
3665        p.print_soft_space();
3666        self.body.print(p, ctx);
3667        p.needs_semicolon = false;
3668    }
3669}
3670
3671impl Gen for TSModuleBlock<'_> {
3672    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3673        let is_empty = self.directives.is_empty() && self.body.is_empty();
3674        p.print_curly_braces(self.span, is_empty, |p| {
3675            p.print_directives_and_statements(&self.directives, &self.body, ctx);
3676        });
3677        p.needs_semicolon = false;
3678    }
3679}
3680
3681impl Gen for TSTypeAliasDeclaration<'_> {
3682    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3683        if self.declare {
3684            p.print_str("declare ");
3685        }
3686        p.print_str("type");
3687        p.print_space_before_identifier();
3688        self.id.print(p, ctx);
3689        if let Some(type_parameters) = &self.type_parameters {
3690            type_parameters.print(p, ctx);
3691        }
3692        p.print_soft_space();
3693        p.print_str("=");
3694        p.print_soft_space();
3695        self.type_annotation.print(p, ctx);
3696    }
3697}
3698
3699impl Gen for TSInterfaceDeclaration<'_> {
3700    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3701        p.print_str("interface");
3702        p.print_hard_space();
3703        self.id.print(p, ctx);
3704        if let Some(type_parameters) = &self.type_parameters {
3705            type_parameters.print(p, ctx);
3706        }
3707        if !self.extends.is_empty() {
3708            p.print_str(" extends ");
3709            p.print_list(&self.extends, ctx);
3710        }
3711        p.print_soft_space();
3712        p.print_curly_braces(self.body.span, self.body.body.is_empty(), |p| {
3713            for item in &self.body.body {
3714                p.print_leading_comments(item.span().start);
3715                p.print_indent();
3716                item.print(p, ctx);
3717                p.print_semicolon();
3718                p.print_soft_newline();
3719            }
3720        });
3721    }
3722}
3723
3724impl Gen for TSInterfaceHeritage<'_> {
3725    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3726        self.expression.print_expr(p, Precedence::Call, ctx);
3727        if let Some(type_parameters) = &self.type_arguments {
3728            type_parameters.print(p, ctx);
3729        }
3730    }
3731}
3732
3733impl Gen for TSEnumDeclaration<'_> {
3734    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3735        p.print_indent();
3736        if self.declare {
3737            p.print_str("declare ");
3738        }
3739        if self.r#const {
3740            p.print_str("const ");
3741        }
3742        p.print_space_before_identifier();
3743        p.print_str("enum ");
3744        self.id.print(p, ctx);
3745        p.print_space_before_identifier();
3746        self.body.print(p, ctx);
3747    }
3748}
3749
3750impl Gen for TSEnumBody<'_> {
3751    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3752        p.print_curly_braces(self.span, self.members.is_empty(), |p| {
3753            for (index, member) in self.members.iter().enumerate() {
3754                p.print_leading_comments(member.span().start);
3755                p.print_indent();
3756                member.print(p, ctx);
3757                if index != self.members.len() - 1 {
3758                    p.print_comma();
3759                }
3760                p.print_soft_newline();
3761            }
3762        });
3763    }
3764}
3765
3766impl Gen for TSEnumMember<'_> {
3767    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3768        match &self.id {
3769            TSEnumMemberName::Identifier(decl) => decl.print(p, ctx),
3770            TSEnumMemberName::String(decl) => p.print_string_literal(decl, false),
3771            TSEnumMemberName::ComputedString(decl) => {
3772                p.print_ascii_byte(b'[');
3773                p.print_string_literal(decl, false);
3774                p.print_ascii_byte(b']');
3775            }
3776            TSEnumMemberName::ComputedTemplateString(decl) => {
3777                let quasi = decl.quasis.first().unwrap();
3778                p.add_source_mapping(quasi.span);
3779
3780                p.print_str("[`");
3781                p.print_str(quasi.value.raw.as_str());
3782                p.print_str("`]");
3783            }
3784        }
3785
3786        if let Some(init) = &self.initializer {
3787            p.print_soft_space();
3788            p.print_equal();
3789            p.print_soft_space();
3790            init.print_expr(p, Precedence::Lowest, ctx);
3791        }
3792    }
3793}
3794
3795impl Gen for TSConstructorType<'_> {
3796    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3797        if self.r#abstract {
3798            p.print_str("abstract ");
3799        }
3800        p.print_str("new ");
3801        if let Some(type_parameters) = &self.type_parameters {
3802            type_parameters.print(p, ctx);
3803        }
3804        p.print_str("(");
3805        self.params.print(p, ctx);
3806        p.print_str(")");
3807        p.print_soft_space();
3808        p.print_str("=>");
3809        p.print_soft_space();
3810        self.return_type.print(p, ctx);
3811    }
3812}
3813
3814impl Gen for TSImportEqualsDeclaration<'_> {
3815    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3816        p.print_str("import ");
3817        self.id.print(p, ctx);
3818        p.print_str(" = ");
3819        self.module_reference.print(p, ctx);
3820    }
3821}
3822
3823impl Gen for TSModuleReference<'_> {
3824    fn r#gen(&self, p: &mut Codegen, ctx: Context) {
3825        match self {
3826            Self::ExternalModuleReference(decl) => {
3827                p.print_str("require(");
3828                p.print_string_literal(&decl.expression, false);
3829                p.print_str(")");
3830            }
3831            match_ts_type_name!(Self) => self.to_ts_type_name().print(p, ctx),
3832        }
3833    }
3834}
3835
3836impl GenExpr for V8IntrinsicExpression<'_> {
3837    fn gen_expr(&self, p: &mut Codegen, precedence: Precedence, ctx: Context) {
3838        let is_statement = p.start_of_stmt == p.code_len();
3839        let is_export_default = p.start_of_default_export == p.code_len();
3840        let mut wrap = precedence >= Precedence::New || ctx.intersects(Context::FORBID_CALL);
3841        if precedence >= Precedence::Postfix {
3842            wrap = true;
3843        }
3844
3845        p.wrap(wrap, |p| {
3846            if is_export_default {
3847                p.start_of_default_export = p.code_len();
3848            } else if is_statement {
3849                p.start_of_stmt = p.code_len();
3850            }
3851            p.add_source_mapping(self.span);
3852            p.print_ascii_byte(b'%');
3853            self.name.print(p, Context::empty());
3854            p.print_arguments(self.span, &self.arguments, ctx);
3855        });
3856    }
3857}