oxc_codegen/
gen.rs

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