Skip to main content

oxc_codegen/
gen.rs

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