oxc_codegen/
gen.rs

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