Skip to main content

oxc_codegen/
gen.rs

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