oxc_codegen/
gen.rs

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