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