Skip to main content

bamts_compiler/
emitter.rs

1//! Deterministic AST-to-JavaScript and declaration emit.
2//!
3//! The emitter walks an immutable [`SourceFile`] and prints either runtime
4//! JavaScript ([`EmitMode::JavaScript`]) or a TypeScript declaration file
5//! ([`EmitMode::Declaration`]). It is a pure printer: it never parses source,
6//! reads files, mutates the tree, or performs semantic analysis.
7//!
8//! # Guarantees
9//! * **Deterministic.** The same tree and [`EmitOptions`] always produce byte-
10//!   identical output. Structural line breaks follow [`Newline`]; newlines that
11//!   live inside a literal (template/string/regex lexeme) are copied verbatim so
12//!   the value is never altered.
13//! * **Type erasure.** In JavaScript mode all type-only syntax is removed:
14//!   annotations, type parameters/arguments, `interface`/`type`, `declare`,
15//!   `import type`, `as`/`satisfies`/`!`/`<T>` assertions, `implements`, and
16//!   parameter `?`/`!` markers. Parameter properties are lowered to constructor
17//!   assignments and `enum` is lowered to its canonical runtime object.
18//! * **Correct precedence.** Parentheses are re-derived from operator
19//!   precedence and associativity rather than copied from the source, so the
20//!   printed grouping always matches the tree.
21//! * **Stable recovery diagnostics.** Nodes the parser could only recover as a
22//!   [`MissingNode`], and constructs that cannot be lowered without the checker
23//!   (`namespace` runtime lowering, decorator lowering), yield ordered typed
24//!   [`Diagnostic`] values while a best-effort product is still returned.
25//!
26//! Constant folding, type inference for un-annotated declarations, and lexical
27//! reference rewriting are the checker's responsibility and are intentionally
28//! out of scope here.
29
30use crate::diagnostic::{Diagnostic, DiagnosticCode};
31use crate::source::{SourceId, SourceText, TextRange};
32use crate::syntax::*;
33
34/// Stable diagnostic identifiers produced by the emitter.
35pub mod codes {
36    use crate::diagnostic::DiagnosticCode;
37
38    /// A recovered expression node has no printable form.
39    pub const MISSING_EXPRESSION: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1001");
40    /// A recovered statement node has no printable form.
41    pub const MISSING_STATEMENT: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1002");
42    /// A recovered type node has no printable form.
43    pub const MISSING_TYPE: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1003");
44    /// A recovered binding pattern has no printable form.
45    pub const MISSING_BINDING: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1004");
46    /// A recovered assignment target has no printable form.
47    pub const MISSING_TARGET: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1005");
48    /// A recovered property name has no printable form.
49    pub const MISSING_PROPERTY_NAME: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1006");
50    /// A recovered module or entity name has no printable form.
51    pub const MISSING_NAME: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1007");
52    /// A recovered member (class/object/type) node has no printable form.
53    pub const MISSING_MEMBER: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1008");
54    /// A recovered element (array/argument) node has no printable form.
55    pub const MISSING_ELEMENT: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1009");
56    /// A token range is not a valid slice of the source text.
57    pub const UNRESOLVED_TOKEN: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1010");
58    /// `namespace` runtime lowering needs semantic analysis unavailable here.
59    pub const NAMESPACE_UNLOWERED: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1011");
60    /// Decorator runtime lowering needs semantic analysis unavailable here.
61    pub const DECORATOR_UNLOWERED: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1012");
62    /// A non-first `enum` member without an initializer needs a constant value.
63    pub const ENUM_MEMBER_INITIALIZER: DiagnosticCode = DiagnosticCode::new("TS-EMIT-1013");
64}
65
66/// Which surface the emitter prints.
67#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
68pub enum EmitMode {
69    /// Runtime JavaScript with all type-only syntax erased.
70    JavaScript,
71    /// A TypeScript declaration (`.d.ts`) file.
72    Declaration,
73}
74
75/// The structural line terminator the emitter inserts between lines.
76#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
77pub enum Newline {
78    /// Unix line feed (`\n`).
79    Lf,
80    /// Windows carriage return + line feed (`\r\n`).
81    CrLf,
82}
83
84impl Newline {
85    const fn as_str(self) -> &'static str {
86        match self {
87            Self::Lf => "\n",
88            Self::CrLf => "\r\n",
89        }
90    }
91}
92
93/// Immutable printing options.
94#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
95pub struct EmitOptions {
96    /// The surface to print.
97    pub mode: EmitMode,
98    /// The structural newline sequence.
99    pub newline: Newline,
100    /// The number of spaces per indentation level.
101    pub indent_width: u8,
102}
103
104impl Default for EmitOptions {
105    fn default() -> Self {
106        Self {
107            mode: EmitMode::JavaScript,
108            newline: Newline::Lf,
109            indent_width: 4,
110        }
111    }
112}
113
114impl EmitOptions {
115    /// Default JavaScript options (LF newlines, four-space indentation).
116    #[must_use]
117    pub const fn javascript() -> Self {
118        Self {
119            mode: EmitMode::JavaScript,
120            newline: Newline::Lf,
121            indent_width: 4,
122        }
123    }
124
125    /// Default declaration options (LF newlines, four-space indentation).
126    #[must_use]
127    pub const fn declaration() -> Self {
128        Self {
129            mode: EmitMode::Declaration,
130            newline: Newline::Lf,
131            indent_width: 4,
132        }
133    }
134
135    /// Returns a copy using `newline` for structural line breaks.
136    #[must_use]
137    pub const fn with_newline(mut self, newline: Newline) -> Self {
138        self.newline = newline;
139        self
140    }
141
142    /// Returns a copy using `indent_width` spaces per level.
143    #[must_use]
144    pub const fn with_indent_width(mut self, indent_width: u8) -> Self {
145        self.indent_width = indent_width;
146        self
147    }
148}
149
150/// The recovered emitter product: printed text plus ordered diagnostics.
151#[derive(Clone, Debug, Eq, PartialEq)]
152pub struct EmitOutput {
153    /// The printed program text.
154    pub code: String,
155    /// Diagnostics in canonical [`Diagnostic`] order.
156    pub diagnostics: Vec<Diagnostic>,
157}
158
159impl EmitOutput {
160    /// Returns whether any diagnostic is an error.
161    #[must_use]
162    pub fn has_errors(&self) -> bool {
163        self.diagnostics.iter().any(|d| !d.is_warning())
164    }
165}
166
167/// Prints `file` to JavaScript or a declaration file per `options`.
168#[must_use]
169pub fn emit(file: &SourceFile, options: EmitOptions) -> EmitOutput {
170    let mut emitter = Emitter {
171        source: file.source_text(),
172        source_id: file.source_id(),
173        options,
174        out: String::new(),
175        indent: 0,
176        pending_indent: false,
177        anchor: file.range(),
178        diagnostics: Vec::new(),
179        enum_context: None,
180        decl_ambient: false,
181        decl_in_export: false,
182    };
183    match options.mode {
184        EmitMode::JavaScript => emitter.emit_module_js(file.statements()),
185        EmitMode::Declaration => emitter.emit_module_decl(file.statements()),
186    }
187    emitter.diagnostics.sort();
188    EmitOutput {
189        code: emitter.out,
190        diagnostics: emitter.diagnostics,
191    }
192}
193
194// Operator precedence levels: larger binds tighter.
195const P_SEQUENCE: u8 = 1;
196const P_ASSIGN: u8 = 2;
197const P_CONDITIONAL: u8 = 3;
198const P_NULLISH: u8 = 4;
199const P_LOGICAL_OR: u8 = 4;
200const P_LOGICAL_AND: u8 = 5;
201const P_BIT_OR: u8 = 6;
202const P_BIT_XOR: u8 = 7;
203const P_BIT_AND: u8 = 8;
204const P_EQUALITY: u8 = 9;
205const P_RELATIONAL: u8 = 10;
206const P_SHIFT: u8 = 11;
207const P_ADDITIVE: u8 = 12;
208const P_MULTIPLICATIVE: u8 = 13;
209const P_EXPONENT: u8 = 14;
210const P_UNARY: u8 = 15;
211const P_POSTFIX: u8 = 16;
212const P_CALL_MEMBER: u8 = 17;
213const P_PRIMARY: u8 = 18;
214
215struct EnumContext {
216    object: String,
217    members: Vec<String>,
218}
219
220struct Emitter<'a> {
221    source: &'a SourceText,
222    source_id: SourceId,
223    options: EmitOptions,
224    out: String,
225    indent: usize,
226    pending_indent: bool,
227    anchor: TextRange,
228    diagnostics: Vec<Diagnostic>,
229    enum_context: Option<EnumContext>,
230    decl_ambient: bool,
231    decl_in_export: bool,
232}
233
234impl<'a> Emitter<'a> {
235    // ---- low level output -------------------------------------------------
236
237    fn raw(&mut self, text: &str) {
238        if text.is_empty() {
239            return;
240        }
241        if self.pending_indent {
242            let spaces = self.indent * self.options.indent_width as usize;
243            for _ in 0..spaces {
244                self.out.push(' ');
245            }
246            self.pending_indent = false;
247        }
248        self.out.push_str(text);
249    }
250
251    fn newline(&mut self) {
252        self.out.push_str(self.options.newline.as_str());
253        self.pending_indent = true;
254    }
255
256    fn diag(&mut self, code: DiagnosticCode, message: &'static str, range: TextRange) {
257        self.diagnostics
258            .push(Diagnostic::error(code, self.source_id, range, message));
259    }
260
261    fn diag_here(&mut self, code: DiagnosticCode, message: &'static str) {
262        let range = self.anchor;
263        self.diag(code, message, range);
264    }
265
266    /// Zero-copy lexeme for a token, or `None` for an invalid slice.
267    fn text(&self, token: &Token) -> Option<&'a str> {
268        if token.is_missing() {
269            return Some("");
270        }
271        let source: &'a SourceText = self.source;
272        let range = token.range();
273        let start = source.utf16_to_byte(range.start()).ok()?;
274        let end = source.utf16_to_byte(range.end()).ok()?;
275        source.as_str().get(start..end)
276    }
277
278    fn emit_token(&mut self, token: &Token) {
279        match self.text(token) {
280            Some(text) => self.raw(text),
281            None => {
282                let range = token.range();
283                self.diag(
284                    codes::UNRESOLVED_TOKEN,
285                    "token text is not a valid slice of the source",
286                    range,
287                );
288            }
289        }
290    }
291
292    fn emit_ident(&mut self, ident: &IdentifierNode) {
293        self.emit_token(ident.data().token());
294    }
295
296    fn emit_string(&mut self, literal: &StringLiteralNode) {
297        self.emit_token(literal.data().token());
298    }
299
300    // ---- module drivers ---------------------------------------------------
301
302    fn emit_module_js(&mut self, statements: &[Stmt]) {
303        for statement in statements {
304            if self.emit_statement(statement) {
305                self.newline();
306            }
307        }
308    }
309
310    fn emit_module_decl(&mut self, statements: &[Stmt]) {
311        self.decl_ambient = true;
312        for statement in statements {
313            if self.emit_declaration(statement) {
314                self.newline();
315            }
316        }
317    }
318
319    // =======================================================================
320    // JavaScript statements
321    // =======================================================================
322
323    fn emit_statement(&mut self, statement: &Stmt) -> bool {
324        let previous = self.anchor;
325        self.anchor = statement.range();
326        let emitted = match statement.data() {
327            Statement::Import(import) => self.emit_import(import, false),
328            Statement::ImportEquals(import) => {
329                if import.is_type_only {
330                    false
331                } else {
332                    self.emit_import_equals_js(import);
333                    true
334                }
335            }
336            Statement::Export(export) => self.emit_export_js(export),
337            Statement::Variable(declaration) => {
338                self.emit_variable_head(declaration);
339                self.raw(";");
340                true
341            }
342            Statement::Function(function) => {
343                if function.function.body.is_none() {
344                    false
345                } else {
346                    self.emit_function_declaration_js(&function.function);
347                    true
348                }
349            }
350            Statement::Class(class) => {
351                self.emit_class_js(class);
352                true
353            }
354            Statement::Interface(_) | Statement::TypeAlias(_) | Statement::Declare(_) => false,
355            Statement::Enum(declaration) => self.emit_enum_js(declaration),
356            Statement::Namespace(_) => {
357                self.diag_here(
358                    codes::NAMESPACE_UNLOWERED,
359                    "namespace runtime lowering requires semantic analysis",
360                );
361                false
362            }
363            Statement::Block(block) => {
364                self.emit_block(block.data());
365                true
366            }
367            Statement::Empty => false,
368            Statement::Expression(statement) => {
369                self.emit_expression_statement(statement);
370                true
371            }
372            Statement::If(_) => {
373                self.emit_if(statement);
374                true
375            }
376            Statement::Switch(switch) => {
377                self.emit_switch(switch);
378                true
379            }
380            Statement::For(statement) => {
381                self.emit_for(statement);
382                true
383            }
384            Statement::ForIn(statement) => {
385                self.emit_for_in(statement);
386                true
387            }
388            Statement::ForOf(statement) => {
389                self.emit_for_of(statement);
390                true
391            }
392            Statement::While(statement) => {
393                self.raw("while (");
394                self.emit_expression(&statement.test);
395                self.raw(")");
396                self.emit_control_body(&statement.body);
397                true
398            }
399            Statement::DoWhile(statement) => {
400                self.raw("do");
401                self.emit_control_body(&statement.body);
402                self.raw(" while (");
403                self.emit_expression(&statement.test);
404                self.raw(");");
405                true
406            }
407            Statement::Try(statement) => {
408                self.emit_try(statement);
409                true
410            }
411            Statement::With(statement) => {
412                self.raw("with (");
413                self.emit_expression(&statement.object);
414                self.raw(")");
415                self.emit_control_body(&statement.body);
416                true
417            }
418            Statement::Labeled(statement) => {
419                self.emit_ident(&statement.label);
420                self.raw(": ");
421                self.emit_statement(&statement.body);
422                true
423            }
424            Statement::Break(jump) => {
425                self.raw("break");
426                if let Some(label) = &jump.label {
427                    self.raw(" ");
428                    self.emit_ident(label);
429                }
430                self.raw(";");
431                true
432            }
433            Statement::Continue(jump) => {
434                self.raw("continue");
435                if let Some(label) = &jump.label {
436                    self.raw(" ");
437                    self.emit_ident(label);
438                }
439                self.raw(";");
440                true
441            }
442            Statement::Return(statement) => {
443                self.raw("return");
444                if let Some(argument) = &statement.argument {
445                    self.raw(" ");
446                    self.emit_expression(argument);
447                }
448                self.raw(";");
449                true
450            }
451            Statement::Throw(statement) => {
452                self.raw("throw ");
453                self.emit_expression(&statement.argument);
454                self.raw(";");
455                true
456            }
457            Statement::Debugger => {
458                self.raw("debugger;");
459                true
460            }
461            Statement::Missing(_) => {
462                self.diag_here(
463                    codes::MISSING_STATEMENT,
464                    "cannot emit a missing statement node",
465                );
466                self.raw(";");
467                true
468            }
469        };
470        self.anchor = previous;
471        emitted
472    }
473
474    fn emit_expression_statement(&mut self, statement: &ExpressionStatement) {
475        let expression = &statement.expression;
476        let wrap = self.leads_with_bad_token(expression, false);
477        if wrap {
478            self.raw("(");
479            self.emit_expression_prec(expression, 0);
480            self.raw(")");
481        } else {
482            self.emit_expression_prec(expression, 0);
483        }
484        self.raw(";");
485    }
486
487    fn emit_if(&mut self, statement: &Stmt) {
488        let Statement::If(if_statement) = statement.data() else {
489            return;
490        };
491        self.raw("if (");
492        self.emit_expression(&if_statement.test);
493        self.raw(")");
494        self.emit_control_body(&if_statement.consequent);
495        if let Some(alternate) = &if_statement.alternate {
496            if matches!(alternate.data(), Statement::If(_)) {
497                self.raw(" else ");
498                self.emit_if(alternate);
499            } else {
500                self.raw(" else");
501                self.emit_control_body(alternate);
502            }
503        }
504    }
505
506    fn emit_control_body(&mut self, statement: &Stmt) {
507        self.raw(" ");
508        match statement.data() {
509            Statement::Block(block) => self.emit_block(block.data()),
510            Statement::Empty => self.raw("{}"),
511            _ => {
512                self.raw("{");
513                self.newline();
514                self.indent += 1;
515                if self.emit_statement(statement) {
516                    self.newline();
517                }
518                self.indent -= 1;
519                self.raw("}");
520            }
521        }
522    }
523
524    fn emit_block(&mut self, block: &Block) {
525        if block.statements.is_empty() {
526            self.raw("{}");
527            return;
528        }
529        self.raw("{");
530        self.newline();
531        self.indent += 1;
532        for statement in &block.statements {
533            if self.emit_statement(statement) {
534                self.newline();
535            }
536        }
537        self.indent -= 1;
538        self.raw("}");
539    }
540
541    fn emit_switch(&mut self, switch: &SwitchStatement) {
542        self.raw("switch (");
543        self.emit_expression(&switch.discriminant);
544        self.raw(") ");
545        if switch.cases.is_empty() {
546            self.raw("{}");
547            return;
548        }
549        self.raw("{");
550        self.newline();
551        self.indent += 1;
552        for case in &switch.cases {
553            let case = case.data();
554            match &case.test {
555                Some(test) => {
556                    self.raw("case ");
557                    self.emit_expression(test);
558                    self.raw(":");
559                }
560                None => self.raw("default:"),
561            }
562            self.newline();
563            if !case.consequent.is_empty() {
564                self.indent += 1;
565                for statement in &case.consequent {
566                    if self.emit_statement(statement) {
567                        self.newline();
568                    }
569                }
570                self.indent -= 1;
571            }
572        }
573        self.indent -= 1;
574        self.raw("}");
575    }
576
577    fn emit_for(&mut self, statement: &ForStatement) {
578        self.raw("for (");
579        match &statement.initializer {
580            Some(ForInitializer::Variable(declaration)) => self.emit_variable_head(declaration),
581            Some(ForInitializer::Expression(expression)) => {
582                self.emit_expression_prec(expression, 0);
583            }
584            None => {}
585        }
586        self.raw(";");
587        if let Some(test) = &statement.test {
588            self.raw(" ");
589            self.emit_expression(test);
590        }
591        self.raw(";");
592        if let Some(update) = &statement.update {
593            self.raw(" ");
594            self.emit_expression(update);
595        }
596        self.raw(")");
597        self.emit_control_body(&statement.body);
598    }
599
600    fn emit_for_in(&mut self, statement: &ForInStatement) {
601        self.raw("for (");
602        self.emit_for_binding(&statement.binding);
603        self.raw(" in ");
604        self.emit_expression_prec(&statement.object, P_ASSIGN);
605        self.raw(")");
606        self.emit_control_body(&statement.body);
607    }
608
609    fn emit_for_of(&mut self, statement: &ForOfStatement) {
610        if matches!(statement.mode, ForOfMode::Async) {
611            self.raw("for await (");
612        } else {
613            self.raw("for (");
614        }
615        self.emit_for_binding(&statement.binding);
616        self.raw(" of ");
617        self.emit_expression_prec(&statement.iterable, P_ASSIGN);
618        self.raw(")");
619        self.emit_control_body(&statement.body);
620    }
621
622    fn emit_for_binding(&mut self, binding: &ForBinding) {
623        match binding {
624            ForBinding::Variable(declaration) => self.emit_variable_head(declaration),
625            ForBinding::Target(target) => self.emit_assignment_target(target),
626        }
627    }
628
629    fn emit_try(&mut self, statement: &TryStatement) {
630        self.raw("try ");
631        self.emit_block(statement.block.data());
632        if let Some(handler) = &statement.handler {
633            let handler = handler.data();
634            self.raw(" catch");
635            if let Some(binding) = &handler.binding {
636                self.raw(" (");
637                self.emit_pattern(binding);
638                self.raw(")");
639            }
640            self.raw(" ");
641            self.emit_block(handler.body.data());
642        }
643        if let Some(finalizer) = &statement.finalizer {
644            self.raw(" finally ");
645            self.emit_block(finalizer.data());
646        }
647    }
648
649    fn emit_variable_head(&mut self, declaration: &VariableDeclaration) {
650        self.raw(variable_kind_str(declaration.kind));
651        self.raw(" ");
652        for (index, declarator) in declaration.declarations.iter().enumerate() {
653            if index > 0 {
654                self.raw(", ");
655            }
656            let declarator = declarator.data();
657            self.emit_pattern(&declarator.binding);
658            if let Some(initializer) = &declarator.initializer {
659                self.raw(" = ");
660                self.emit_expression_prec(initializer, P_ASSIGN);
661            }
662        }
663    }
664
665    // ---- imports / exports (JavaScript) -----------------------------------
666
667    fn emit_import(&mut self, import: &ImportDeclaration, keep_types: bool) -> bool {
668        if import.type_only && !keep_types {
669            return false;
670        }
671
672        // A clause that resolves to no value bindings is fully type-only and is
673        // erased in JavaScript (a bare side-effect import keeps its clause-less
674        // form below).
675        if !keep_types && let Some(clause) = &import.clause {
676            let has_value = clause.default.is_some()
677                || matches!(&clause.binding, Some(ImportBinding::Namespace(_)))
678                || matches!(
679                    &clause.binding,
680                    Some(ImportBinding::Named(specifiers))
681                        if specifiers
682                            .iter()
683                            .any(|s| matches!(s.data().mode, ImportSpecifierMode::Value))
684                );
685            if !has_value {
686                return false;
687            }
688        }
689
690        self.raw("import ");
691        if keep_types && import.type_only {
692            self.raw("type ");
693        }
694        if let Some(clause) = &import.clause {
695            let mut wrote = false;
696            if let Some(default) = &clause.default {
697                self.emit_ident(default);
698                wrote = true;
699            }
700            if let Some(binding) = &clause.binding {
701                match binding {
702                    ImportBinding::Namespace(name) => {
703                        if wrote {
704                            self.raw(", ");
705                        }
706                        self.raw("* as ");
707                        self.emit_ident(name);
708                    }
709                    ImportBinding::Named(specifiers) => {
710                        if wrote {
711                            self.raw(", ");
712                        }
713                        self.emit_named_imports(specifiers, keep_types);
714                    }
715                }
716            }
717            self.raw(" from ");
718        }
719        self.emit_string(&import.source);
720        if let Some(attributes) = &import.attributes {
721            self.emit_import_attributes(attributes);
722        }
723        self.raw(";");
724        true
725    }
726
727    fn emit_named_imports(&mut self, specifiers: &[ImportSpecifierNode], keep_types: bool) {
728        let visible: Vec<&ImportSpecifierNode> = specifiers
729            .iter()
730            .filter(|s| keep_types || matches!(s.data().mode, ImportSpecifierMode::Value))
731            .collect();
732        if visible.is_empty() {
733            self.raw("{}");
734            return;
735        }
736        self.raw("{ ");
737        for (index, specifier) in visible.iter().enumerate() {
738            if index > 0 {
739                self.raw(", ");
740            }
741            let specifier = specifier.data();
742            if keep_types && matches!(specifier.mode, ImportSpecifierMode::TypeOnly) {
743                self.raw("type ");
744            }
745            if self.module_name_matches_ident(&specifier.imported, &specifier.local) {
746                self.emit_ident(&specifier.local);
747            } else {
748                self.emit_module_export_name(&specifier.imported);
749                self.raw(" as ");
750                self.emit_ident(&specifier.local);
751            }
752        }
753        self.raw(" }");
754    }
755
756    fn emit_import_attributes(&mut self, attributes: &ImportAttributes) {
757        if attributes.entries.is_empty() {
758            return;
759        }
760        self.raw(" with { ");
761        for (index, entry) in attributes.entries.iter().enumerate() {
762            if index > 0 {
763                self.raw(", ");
764            }
765            self.emit_module_export_name(&entry.name);
766            self.raw(": ");
767            self.emit_string(&entry.value);
768        }
769        self.raw(" }");
770    }
771
772    fn emit_import_equals_js(&mut self, import: &ImportEqualsDeclaration) {
773        self.raw("const ");
774        self.emit_ident(&import.local);
775        self.raw(" = ");
776        match &import.reference {
777            ExternalModuleReference::Require(source) => {
778                self.raw("require(");
779                self.emit_string(source);
780                self.raw(")");
781            }
782            ExternalModuleReference::Qualified(name) => self.emit_entity_name(name),
783            ExternalModuleReference::Missing(_) => {
784                self.diag_here(
785                    codes::MISSING_NAME,
786                    "cannot emit a missing module reference",
787                );
788            }
789        }
790        self.raw(";");
791    }
792
793    fn emit_export_js(&mut self, export: &ExportDeclaration) -> bool {
794        match export {
795            ExportDeclaration::Named(ExportNamedDeclaration::Declaration(inner)) => {
796                if !self.js_statement_emits(inner) {
797                    // Trigger any recovery diagnostics without a dangling `export`.
798                    self.emit_statement(inner);
799                    return false;
800                }
801                self.raw("export ");
802                self.emit_statement(inner)
803            }
804            ExportDeclaration::Named(ExportNamedDeclaration::Specifiers {
805                type_only,
806                specifiers,
807                source,
808                attributes,
809            }) => {
810                if *type_only {
811                    return false;
812                }
813                let visible: Vec<&ExportSpecifierNode> = specifiers
814                    .iter()
815                    .filter(|s| matches!(s.data().mode, ExportSpecifierMode::Value))
816                    .collect();
817                if visible.is_empty() {
818                    return false;
819                }
820                self.raw("export { ");
821                for (index, specifier) in visible.iter().enumerate() {
822                    if index > 0 {
823                        self.raw(", ");
824                    }
825                    self.emit_export_specifier(specifier.data(), false);
826                }
827                self.raw(" }");
828                if let Some(source) = source {
829                    self.raw(" from ");
830                    self.emit_string(source);
831                    if let Some(attributes) = attributes {
832                        self.emit_import_attributes(attributes);
833                    }
834                }
835                self.raw(";");
836                true
837            }
838            ExportDeclaration::All(all) => {
839                if all.type_only {
840                    return false;
841                }
842                self.raw("export * ");
843                if let Some(name) = &all.exported {
844                    self.raw("as ");
845                    self.emit_module_export_name(name);
846                    self.raw(" ");
847                }
848                self.raw("from ");
849                self.emit_string(&all.source);
850                if let Some(attributes) = &all.attributes {
851                    self.emit_import_attributes(attributes);
852                }
853                self.raw(";");
854                true
855            }
856            ExportDeclaration::Default(default) => match &default.value {
857                ExportDefaultValue::Function(function) => {
858                    self.raw("export default ");
859                    self.emit_function_declaration_js(function);
860                    true
861                }
862                ExportDefaultValue::Class(class) => {
863                    self.raw("export default ");
864                    self.emit_class_core_js(class);
865                    true
866                }
867                ExportDefaultValue::Expression(expression) => {
868                    self.raw("export default ");
869                    self.emit_expression_prec(expression, P_ASSIGN);
870                    self.raw(";");
871                    true
872                }
873                ExportDefaultValue::Missing(_) => {
874                    self.diag_here(
875                        codes::MISSING_EXPRESSION,
876                        "cannot emit a missing default export",
877                    );
878                    false
879                }
880            },
881            ExportDeclaration::Assignment(expression) => {
882                self.raw("module.exports = ");
883                self.emit_expression_prec(expression, P_ASSIGN);
884                self.raw(";");
885                true
886            }
887        }
888    }
889
890    fn emit_export_specifier(&mut self, specifier: &ExportSpecifier, keep_type: bool) {
891        if keep_type && matches!(specifier.mode, ExportSpecifierMode::TypeOnly) {
892            self.raw("type ");
893        }
894        if self.module_names_match(&specifier.local, &specifier.exported) {
895            self.emit_module_export_name(&specifier.local);
896        } else {
897            self.emit_module_export_name(&specifier.local);
898            self.raw(" as ");
899            self.emit_module_export_name(&specifier.exported);
900        }
901    }
902
903    fn js_statement_emits(&self, statement: &Stmt) -> bool {
904        match statement.data() {
905            Statement::Interface(_)
906            | Statement::TypeAlias(_)
907            | Statement::Declare(_)
908            | Statement::Namespace(_)
909            | Statement::Empty => false,
910            Statement::Function(function) => function.function.body.is_some(),
911            Statement::Import(import) => !import.type_only,
912            _ => true,
913        }
914    }
915
916    // =======================================================================
917    // enum lowering (JavaScript)
918    // =======================================================================
919
920    fn emit_enum_js(&mut self, declaration: &EnumDeclaration) -> bool {
921        let Some(name) = self
922            .text(declaration.name.data().token())
923            .map(str::to_owned)
924        else {
925            self.diag(
926                codes::UNRESOLVED_TOKEN,
927                "token text is not a valid slice of the source",
928                declaration.name.range(),
929            );
930            return false;
931        };
932        if name.is_empty() {
933            return false;
934        }
935
936        let members: Vec<String> = declaration
937            .members
938            .iter()
939            .filter_map(|member| match &member.data().name {
940                PropertyName::Identifier(ident) => {
941                    self.text(ident.data().token()).map(str::to_owned)
942                }
943                _ => None,
944            })
945            .collect();
946
947        self.raw("var ");
948        self.raw(&name);
949        self.raw(";");
950        self.newline();
951        self.raw("(function (");
952        self.raw(&name);
953        self.raw(") {");
954        self.newline();
955        self.indent += 1;
956
957        self.enum_context = Some(EnumContext {
958            object: name.clone(),
959            members,
960        });
961        let mut auto: Option<i64> = Some(0);
962        for member in &declaration.members {
963            self.emit_enum_member(&name, member.data(), &mut auto);
964            self.newline();
965        }
966        self.enum_context = None;
967
968        self.indent -= 1;
969        self.raw("})(");
970        self.raw(&name);
971        self.raw(" || (");
972        self.raw(&name);
973        self.raw(" = {}));");
974        true
975    }
976
977    fn emit_enum_member(&mut self, object: &str, member: &EnumMember, auto: &mut Option<i64>) {
978        let Some(key) = self.enum_member_key(&member.name) else {
979            self.diag_here(
980                codes::MISSING_PROPERTY_NAME,
981                "cannot emit an enum member with this name",
982            );
983            return;
984        };
985
986        match &member.initializer {
987            None => match *auto {
988                Some(value) => {
989                    self.raw(object);
990                    self.raw("[");
991                    self.raw(object);
992                    self.raw("[");
993                    self.raw(&key);
994                    self.raw("] = ");
995                    self.raw(&value.to_string());
996                    self.raw("] = ");
997                    self.raw(&key);
998                    self.raw(";");
999                    *auto = value.checked_add(1);
1000                }
1001                None => {
1002                    self.diag_here(
1003                        codes::ENUM_MEMBER_INITIALIZER,
1004                        "enum member without initializer requires a constant predecessor",
1005                    );
1006                    self.raw(object);
1007                    self.raw("[");
1008                    self.raw(&key);
1009                    self.raw("] = void 0;");
1010                }
1011            },
1012            Some(initializer) => {
1013                if let Some(value) = numeric_literal_value(initializer) {
1014                    self.raw(object);
1015                    self.raw("[");
1016                    self.raw(object);
1017                    self.raw("[");
1018                    self.raw(&key);
1019                    self.raw("] = ");
1020                    self.emit_expression_prec(initializer, P_ASSIGN);
1021                    self.raw("] = ");
1022                    self.raw(&key);
1023                    self.raw(";");
1024                    *auto = value.and_then(|v| v.checked_add(1));
1025                } else {
1026                    self.raw(object);
1027                    self.raw("[");
1028                    self.raw(&key);
1029                    self.raw("] = ");
1030                    self.emit_expression_prec(initializer, P_ASSIGN);
1031                    self.raw(";");
1032                    *auto = None;
1033                }
1034            }
1035        }
1036    }
1037
1038    fn enum_member_key(&self, name: &PropertyName) -> Option<String> {
1039        match name {
1040            PropertyName::Identifier(ident) => {
1041                self.text(ident.data().token()).map(|s| format!("\"{s}\""))
1042            }
1043            PropertyName::String(string) => self.text(string.data().token()).map(str::to_owned),
1044            PropertyName::Number(number) => {
1045                self.text(number.data().token()).map(|s| format!("\"{s}\""))
1046            }
1047            PropertyName::Private(_) | PropertyName::Computed(_) | PropertyName::Missing(_) => None,
1048        }
1049    }
1050
1051    // =======================================================================
1052    // functions / classes (JavaScript)
1053    // =======================================================================
1054
1055    fn emit_function_declaration_js(&mut self, function: &FunctionLike) {
1056        if function.is_async {
1057            self.raw("async ");
1058        }
1059        self.raw("function");
1060        if function.is_generator {
1061            self.raw("*");
1062        }
1063        if let Some(name) = &function.name {
1064            self.raw(" ");
1065            self.emit_ident(name);
1066        }
1067        self.emit_params_js(&function.parameters);
1068        self.raw(" ");
1069        self.emit_function_body_js(function.body.as_ref());
1070    }
1071
1072    fn emit_function_expression_js(&mut self, function: &FunctionLike) {
1073        if function.is_async {
1074            self.raw("async ");
1075        }
1076        self.raw("function");
1077        if function.is_generator {
1078            self.raw("*");
1079        }
1080        if let Some(name) = &function.name {
1081            self.raw(" ");
1082            self.emit_ident(name);
1083        }
1084        self.emit_params_js(&function.parameters);
1085        self.raw(" ");
1086        self.emit_function_body_js(function.body.as_ref());
1087    }
1088
1089    fn emit_arrow_js(&mut self, arrow: &ArrowFunction) {
1090        if arrow.is_async {
1091            self.raw("async ");
1092        }
1093        self.emit_params_js(&arrow.parameters);
1094        self.raw(" => ");
1095        match &arrow.body {
1096            FunctionBody::Block(block) => self.emit_block(block.data()),
1097            FunctionBody::Expression(expression) => {
1098                if self.leads_with_bad_token(expression, true) {
1099                    self.raw("(");
1100                    self.emit_expression_prec(expression, 0);
1101                    self.raw(")");
1102                } else {
1103                    self.emit_expression_prec(expression, P_ASSIGN);
1104                }
1105            }
1106            FunctionBody::Missing(_) => {
1107                self.diag_here(
1108                    codes::MISSING_STATEMENT,
1109                    "cannot emit a missing function body",
1110                );
1111                self.raw("{}");
1112            }
1113        }
1114    }
1115
1116    fn emit_function_body_js(&mut self, body: Option<&FunctionBody>) {
1117        match body {
1118            Some(FunctionBody::Block(block)) => self.emit_block(block.data()),
1119            Some(FunctionBody::Expression(expression)) => {
1120                self.raw("{ return ");
1121                self.emit_expression_prec(expression, 0);
1122                self.raw("; }");
1123            }
1124            Some(FunctionBody::Missing(_)) | None => {
1125                self.diag_here(
1126                    codes::MISSING_STATEMENT,
1127                    "cannot emit a missing function body",
1128                );
1129                self.raw("{}");
1130            }
1131        }
1132    }
1133
1134    fn emit_params_js(&mut self, parameters: &[ParameterNode]) {
1135        self.raw("(");
1136        let mut first = true;
1137        for parameter in parameters {
1138            let parameter = parameter.data();
1139            if self.is_this_parameter(parameter) {
1140                continue;
1141            }
1142            for decorator in &parameter.decorators {
1143                self.emit_decorator_diag(decorator);
1144            }
1145            if !first {
1146                self.raw(", ");
1147            }
1148            first = false;
1149            self.emit_pattern(&parameter.binding);
1150            if let Some(initializer) = &parameter.initializer {
1151                self.raw(" = ");
1152                self.emit_expression_prec(initializer, P_ASSIGN);
1153            }
1154        }
1155        self.raw(")");
1156    }
1157
1158    fn is_this_parameter(&self, parameter: &Parameter) -> bool {
1159        if let BindingPattern::Identifier(ident) = parameter.binding.data() {
1160            matches!(self.text(ident.data().token()), Some("this"))
1161        } else {
1162            false
1163        }
1164    }
1165
1166    fn emit_decorator_diag(&mut self, decorator: &DecoratorNode) {
1167        let range = decorator.range();
1168        self.diag(
1169            codes::DECORATOR_UNLOWERED,
1170            "decorator runtime lowering requires semantic analysis",
1171            range,
1172        );
1173    }
1174
1175    fn emit_class_js(&mut self, class: &ClassDeclaration) {
1176        self.emit_class_core_js(class);
1177    }
1178
1179    fn emit_class_core_js(&mut self, class: &ClassDeclaration) {
1180        for decorator in &class.decorators {
1181            self.emit_decorator_diag(decorator);
1182        }
1183        self.raw("class");
1184        if let Some(name) = &class.name {
1185            self.raw(" ");
1186            self.emit_ident(name);
1187        }
1188        if let Some(heritage) = &class.extends {
1189            self.raw(" extends ");
1190            self.emit_expression_prec(&heritage.expression, P_CALL_MEMBER);
1191        }
1192        self.raw(" ");
1193        self.emit_class_body_js(&class.members);
1194    }
1195
1196    fn emit_class_body_js(&mut self, members: &[ClassMemberNode]) {
1197        self.raw("{");
1198        let has = members
1199            .iter()
1200            .any(|member| self.class_member_emits_js(member.data()));
1201        if has {
1202            self.newline();
1203            self.indent += 1;
1204        }
1205        for member in members {
1206            if self.emit_class_member_js(member.data()) {
1207                self.newline();
1208            }
1209        }
1210        if has {
1211            self.indent -= 1;
1212        }
1213        self.raw("}");
1214    }
1215
1216    fn class_member_emits_js(&self, member: &ClassMember) -> bool {
1217        match member {
1218            ClassMember::Constructor(_) | ClassMember::StaticBlock(_) => true,
1219            ClassMember::Method(method) => {
1220                method.function.body.is_some() && !method.modifiers.is_abstract
1221            }
1222            ClassMember::Property(property) => {
1223                !property.modifiers.is_abstract && !property.modifiers.is_declare
1224            }
1225            ClassMember::AutoAccessor(accessor) => {
1226                !accessor.modifiers.is_abstract && !accessor.modifiers.is_declare
1227            }
1228            ClassMember::IndexSignature(_) | ClassMember::Missing(_) => false,
1229        }
1230    }
1231
1232    fn emit_class_member_js(&mut self, member: &ClassMember) -> bool {
1233        match member {
1234            ClassMember::Constructor(constructor) => {
1235                self.emit_constructor_js(constructor);
1236                true
1237            }
1238            ClassMember::Method(method) => {
1239                if method.function.body.is_none() || method.modifiers.is_abstract {
1240                    return false;
1241                }
1242                self.emit_method_js(method);
1243                true
1244            }
1245            ClassMember::Property(property) => {
1246                if property.modifiers.is_abstract || property.modifiers.is_declare {
1247                    return false;
1248                }
1249                if property.modifiers.is_static {
1250                    self.raw("static ");
1251                }
1252                self.emit_property_name(&property.name);
1253                if let Some(initializer) = &property.initializer {
1254                    self.raw(" = ");
1255                    self.emit_expression_prec(initializer, P_ASSIGN);
1256                }
1257                self.raw(";");
1258                true
1259            }
1260            ClassMember::AutoAccessor(accessor) => {
1261                if accessor.modifiers.is_abstract || accessor.modifiers.is_declare {
1262                    return false;
1263                }
1264                if accessor.modifiers.is_static {
1265                    self.raw("static ");
1266                }
1267                self.raw("accessor ");
1268                self.emit_property_name(&accessor.name);
1269                if let Some(initializer) = &accessor.initializer {
1270                    self.raw(" = ");
1271                    self.emit_expression_prec(initializer, P_ASSIGN);
1272                }
1273                self.raw(";");
1274                true
1275            }
1276            ClassMember::StaticBlock(block) => {
1277                self.raw("static ");
1278                self.emit_block(block.data());
1279                true
1280            }
1281            ClassMember::IndexSignature(_) => false,
1282            ClassMember::Missing(_) => {
1283                self.diag_here(codes::MISSING_MEMBER, "cannot emit a missing class member");
1284                false
1285            }
1286        }
1287    }
1288
1289    fn emit_method_js(&mut self, method: &MethodDeclaration) {
1290        if method.modifiers.is_static {
1291            self.raw("static ");
1292        }
1293        match method.modifier {
1294            PropertyModifier::Get => self.raw("get "),
1295            PropertyModifier::Set => self.raw("set "),
1296            PropertyModifier::None => {
1297                if method.function.is_async {
1298                    self.raw("async ");
1299                }
1300                if method.function.is_generator {
1301                    self.raw("*");
1302                }
1303            }
1304        }
1305        self.emit_property_name(&method.name);
1306        self.emit_params_js(&method.function.parameters);
1307        self.raw(" ");
1308        self.emit_function_body_js(method.function.body.as_ref());
1309    }
1310
1311    fn emit_constructor_js(&mut self, constructor: &ConstructorDeclaration) {
1312        self.raw("constructor");
1313        self.emit_params_js(&constructor.parameters);
1314        self.raw(" ");
1315
1316        let injections: Vec<&ParameterNode> = constructor
1317            .parameters
1318            .iter()
1319            .filter(|parameter| is_parameter_property(parameter.data()))
1320            .collect();
1321        let body = constructor.body.data();
1322        if injections.is_empty() && body.statements.is_empty() {
1323            self.raw("{}");
1324            return;
1325        }
1326        self.raw("{");
1327        self.newline();
1328        self.indent += 1;
1329        for parameter in injections {
1330            if let BindingPattern::Identifier(name) = parameter.data().binding.data() {
1331                self.raw("this.");
1332                self.emit_ident(name);
1333                self.raw(" = ");
1334                self.emit_ident(name);
1335                self.raw(";");
1336                self.newline();
1337            } else {
1338                self.diag(
1339                    codes::MISSING_TARGET,
1340                    "parameter property must bind a plain identifier",
1341                    parameter.range(),
1342                );
1343            }
1344        }
1345        for statement in &body.statements {
1346            if self.emit_statement(statement) {
1347                self.newline();
1348            }
1349        }
1350        self.indent -= 1;
1351        self.raw("}");
1352    }
1353
1354    // =======================================================================
1355    // expressions (precedence-aware)
1356    // =======================================================================
1357
1358    fn emit_expression(&mut self, expression: &Expr) {
1359        self.emit_expression_prec(expression, 0);
1360    }
1361
1362    fn emit_expression_prec(&mut self, expression: &Expr, min_prec: u8) {
1363        let previous = self.anchor;
1364        self.anchor = expression.range();
1365        let prec = self.expression_prec(expression);
1366        let parenthesize = prec < min_prec;
1367        if parenthesize {
1368            self.raw("(");
1369        }
1370        self.emit_expression_inner(expression);
1371        if parenthesize {
1372            self.raw(")");
1373        }
1374        self.anchor = previous;
1375    }
1376
1377    fn expression_prec(&self, expression: &Expr) -> u8 {
1378        match expression.data() {
1379            Expression::Sequence(_) => P_SEQUENCE,
1380            Expression::Assignment(_) | Expression::Arrow(_) | Expression::Yield(_) => P_ASSIGN,
1381            Expression::Conditional(_) => P_CONDITIONAL,
1382            Expression::Logical(logical) => match logical.operator {
1383                LogicalOperator::And => P_LOGICAL_AND,
1384                LogicalOperator::Or => P_LOGICAL_OR,
1385                LogicalOperator::Nullish => P_NULLISH,
1386            },
1387            Expression::Binary(binary) => binary_prec(binary.operator),
1388            Expression::Unary(_) | Expression::Await(_) => P_UNARY,
1389            Expression::Update(update) => {
1390                if update.prefix {
1391                    P_UNARY
1392                } else {
1393                    P_POSTFIX
1394                }
1395            }
1396            Expression::Call(_)
1397            | Expression::New(_)
1398            | Expression::Member(_)
1399            | Expression::TaggedTemplate(_)
1400            | Expression::Import(_) => P_CALL_MEMBER,
1401            Expression::Parenthesized(inner) => self.expression_prec(inner),
1402            Expression::As(as_expr) => self.expression_prec(&as_expr.expression),
1403            Expression::Satisfies(satisfies) => self.expression_prec(&satisfies.expression),
1404            Expression::TypeAssertion(assertion) => self.expression_prec(&assertion.expression),
1405            Expression::NonNull(non_null) => self.expression_prec(&non_null.expression),
1406            _ => P_PRIMARY,
1407        }
1408    }
1409
1410    fn emit_expression_inner(&mut self, expression: &Expr) {
1411        match expression.data() {
1412            Expression::Identifier(ident) => self.emit_ident_expression(ident),
1413            Expression::This => self.raw("this"),
1414            Expression::Super => self.raw("super"),
1415            Expression::Literal(literal) => self.emit_literal(literal),
1416            Expression::Template(template) => self.emit_template(template),
1417            Expression::TaggedTemplate(tagged) => {
1418                self.emit_expression_prec(&tagged.tag, P_CALL_MEMBER);
1419                self.emit_template(&tagged.template);
1420            }
1421            Expression::Array(array) => self.emit_array(array),
1422            Expression::Object(object) => self.emit_object(object),
1423            Expression::Function(function) => self.emit_function_expression_js(&function.function),
1424            Expression::Class(class) => self.emit_class_core_js(&class.class),
1425            Expression::Arrow(arrow) => self.emit_arrow_js(arrow),
1426            Expression::Call(call) => self.emit_call(call),
1427            Expression::Member(member) => self.emit_member(member),
1428            Expression::New(new) => self.emit_new(new),
1429            Expression::Await(await_expr) => {
1430                self.raw("await ");
1431                self.emit_expression_prec(&await_expr.argument, P_UNARY);
1432            }
1433            Expression::Yield(yield_expr) => self.emit_yield(yield_expr),
1434            Expression::Unary(unary) => self.emit_unary(unary),
1435            Expression::Update(update) => self.emit_update(update),
1436            Expression::Binary(binary) => self.emit_binary(binary),
1437            Expression::Logical(logical) => self.emit_logical(logical),
1438            Expression::Conditional(conditional) => self.emit_conditional(conditional),
1439            Expression::Assignment(assignment) => self.emit_assignment(assignment),
1440            Expression::Sequence(sequence) => self.emit_sequence(sequence),
1441            Expression::Parenthesized(inner) => self.emit_expression_prec(inner, 0),
1442            Expression::As(as_expr) => self.emit_expression_prec(&as_expr.expression, 0),
1443            Expression::Satisfies(satisfies) => {
1444                self.emit_expression_prec(&satisfies.expression, 0);
1445            }
1446            Expression::TypeAssertion(assertion) => {
1447                self.emit_expression_prec(&assertion.expression, 0);
1448            }
1449            Expression::NonNull(non_null) => self.emit_expression_prec(&non_null.expression, 0),
1450            Expression::Import(import) => {
1451                self.raw("import(");
1452                self.emit_expression_prec(&import.source, P_ASSIGN);
1453                if let Some(options) = &import.options {
1454                    self.raw(", ");
1455                    self.emit_expression_prec(options, P_ASSIGN);
1456                }
1457                self.raw(")");
1458            }
1459            Expression::Meta(meta) => match meta {
1460                MetaProperty::NewTarget => self.raw("new.target"),
1461                MetaProperty::ImportMeta => self.raw("import.meta"),
1462            },
1463            Expression::Missing(_) => {
1464                self.diag_here(
1465                    codes::MISSING_EXPRESSION,
1466                    "cannot emit a missing expression node",
1467                );
1468                self.raw("void 0");
1469            }
1470        }
1471    }
1472
1473    fn emit_ident_expression(&mut self, ident: &IdentifierNode) {
1474        let Some(text) = self.text(ident.data().token()) else {
1475            let range = ident.range();
1476            self.diag(
1477                codes::UNRESOLVED_TOKEN,
1478                "token text is not a valid slice of the source",
1479                range,
1480            );
1481            return;
1482        };
1483        let qualified = self
1484            .enum_context
1485            .as_ref()
1486            .filter(|context| context.members.iter().any(|member| member == text))
1487            .map(|context| context.object.clone());
1488        if let Some(object) = qualified {
1489            self.raw(&object);
1490            self.raw(".");
1491        }
1492        self.raw(text);
1493    }
1494
1495    fn emit_literal(&mut self, literal: &Literal) {
1496        match literal {
1497            Literal::String(node) => self.emit_token(node.data().token()),
1498            Literal::Number(node) => self.emit_token(node.data().token()),
1499            Literal::BigInt(node) => self.emit_token(node.data().token()),
1500            Literal::Boolean(node) => self.emit_token(node.data().token()),
1501            Literal::Null(node) => match self.text(node.data().token()) {
1502                Some(text) if !text.is_empty() => self.raw(text),
1503                _ => self.raw("null"),
1504            },
1505            Literal::Regex(node) => self.emit_token(node.data().token()),
1506        }
1507    }
1508
1509    fn emit_template(&mut self, template: &TemplateLiteral) {
1510        if template.elements.is_empty() {
1511            return;
1512        }
1513        self.emit_token(template.elements[0].data().token());
1514        for (index, expression) in template.expressions.iter().enumerate() {
1515            self.emit_expression_prec(expression, 0);
1516            if let Some(element) = template.elements.get(index + 1) {
1517                self.emit_token(element.data().token());
1518            }
1519        }
1520    }
1521
1522    fn emit_array(&mut self, array: &ArrayLiteral) {
1523        self.raw("[");
1524        let elements = &array.elements;
1525        for (index, element) in elements.iter().enumerate() {
1526            if index > 0 {
1527                self.raw(", ");
1528            }
1529            match element {
1530                ArrayElement::Expression(expression) => {
1531                    self.emit_expression_prec(expression, P_ASSIGN);
1532                }
1533                ArrayElement::Spread(spread) => {
1534                    self.raw("...");
1535                    self.emit_expression_prec(&spread.argument, P_ASSIGN);
1536                }
1537                ArrayElement::Elision => {}
1538                ArrayElement::Missing(_) => {
1539                    self.diag_here(
1540                        codes::MISSING_ELEMENT,
1541                        "cannot emit a missing array element",
1542                    );
1543                }
1544            }
1545        }
1546        if matches!(elements.last(), Some(ArrayElement::Elision)) {
1547            self.raw(",");
1548        }
1549        self.raw("]");
1550    }
1551
1552    fn emit_object(&mut self, object: &ObjectLiteral) {
1553        if object.members.is_empty() {
1554            self.raw("{}");
1555            return;
1556        }
1557        self.raw("{");
1558        self.newline();
1559        self.indent += 1;
1560        let count = object.members.len();
1561        for (index, member) in object.members.iter().enumerate() {
1562            self.emit_object_member(member.data());
1563            if index + 1 < count {
1564                self.raw(",");
1565            }
1566            self.newline();
1567        }
1568        self.indent -= 1;
1569        self.raw("}");
1570    }
1571
1572    fn emit_object_member(&mut self, member: &ObjectMember) {
1573        match member {
1574            ObjectMember::Property(property) => {
1575                if property.shorthand && matches!(property.name, PropertyName::Identifier(_)) {
1576                    self.emit_property_name(&property.name);
1577                } else {
1578                    self.emit_property_name(&property.name);
1579                    self.raw(": ");
1580                    self.emit_expression_prec(&property.value, P_ASSIGN);
1581                }
1582            }
1583            ObjectMember::Method(method) => self.emit_object_method(method),
1584            ObjectMember::Spread(spread) => {
1585                self.raw("...");
1586                self.emit_expression_prec(&spread.argument, P_ASSIGN);
1587            }
1588            ObjectMember::Missing(_) => {
1589                self.diag_here(codes::MISSING_MEMBER, "cannot emit a missing object member");
1590            }
1591        }
1592    }
1593
1594    fn emit_object_method(&mut self, method: &ObjectMethod) {
1595        match method.modifier {
1596            PropertyModifier::Get => self.raw("get "),
1597            PropertyModifier::Set => self.raw("set "),
1598            PropertyModifier::None => {
1599                if method.function.is_async {
1600                    self.raw("async ");
1601                }
1602                if method.function.is_generator {
1603                    self.raw("*");
1604                }
1605            }
1606        }
1607        self.emit_property_name(&method.name);
1608        self.emit_params_js(&method.function.parameters);
1609        self.raw(" ");
1610        self.emit_function_body_js(method.function.body.as_ref());
1611    }
1612
1613    fn emit_property_name(&mut self, name: &PropertyName) {
1614        match name {
1615            PropertyName::Identifier(ident) => self.emit_ident(ident),
1616            PropertyName::Private(private) => self.emit_token(private.data().token()),
1617            PropertyName::String(string) => self.emit_string(string),
1618            PropertyName::Number(number) => self.emit_token(number.data().token()),
1619            PropertyName::Computed(expression) => {
1620                self.raw("[");
1621                self.emit_expression_prec(expression, P_ASSIGN);
1622                self.raw("]");
1623            }
1624            PropertyName::Missing(_) => {
1625                self.diag_here(
1626                    codes::MISSING_PROPERTY_NAME,
1627                    "cannot emit a missing property name",
1628                );
1629            }
1630        }
1631    }
1632
1633    fn emit_call(&mut self, call: &CallExpression) {
1634        self.emit_expression_prec(&call.callee, P_CALL_MEMBER);
1635        if call.optional {
1636            self.raw("?.(");
1637        } else {
1638            self.raw("(");
1639        }
1640        self.emit_arguments(&call.arguments);
1641        self.raw(")");
1642    }
1643
1644    fn emit_new(&mut self, new: &NewExpression) {
1645        self.raw("new ");
1646        let callee = self.unwrap_expression(&new.callee);
1647        let wrap = matches!(callee.data(), Expression::Call(_)) || self.chain_has_optional(callee);
1648        if wrap {
1649            self.raw("(");
1650            self.emit_expression_prec(callee, 0);
1651            self.raw(")");
1652        } else {
1653            self.emit_expression_prec(callee, P_CALL_MEMBER);
1654        }
1655        self.raw("(");
1656        self.emit_arguments(&new.arguments);
1657        self.raw(")");
1658    }
1659
1660    fn emit_arguments(&mut self, arguments: &[CallArgument]) {
1661        for (index, argument) in arguments.iter().enumerate() {
1662            if index > 0 {
1663                self.raw(", ");
1664            }
1665            match argument {
1666                CallArgument::Expression(expression) => {
1667                    self.emit_expression_prec(expression, P_ASSIGN);
1668                }
1669                CallArgument::Spread(spread) => {
1670                    self.raw("...");
1671                    self.emit_expression_prec(&spread.argument, P_ASSIGN);
1672                }
1673                CallArgument::Missing(_) => {
1674                    self.diag_here(
1675                        codes::MISSING_ELEMENT,
1676                        "cannot emit a missing call argument",
1677                    );
1678                }
1679            }
1680        }
1681    }
1682
1683    fn emit_member(&mut self, member: &MemberExpression) {
1684        let dotted = !matches!(member.property, MemberProperty::Computed(_));
1685        let numeric_object = dotted
1686            && matches!(
1687                self.unwrap_expression(&member.object).data(),
1688                Expression::Literal(Literal::Number(_))
1689            );
1690        if numeric_object {
1691            self.raw("(");
1692            self.emit_expression_prec(&member.object, 0);
1693            self.raw(")");
1694        } else {
1695            self.emit_expression_prec(&member.object, P_CALL_MEMBER);
1696        }
1697        match &member.property {
1698            MemberProperty::Named(name) => {
1699                self.raw(if member.optional { "?." } else { "." });
1700                self.emit_ident(name);
1701            }
1702            MemberProperty::Private(private) => {
1703                self.raw(if member.optional { "?." } else { "." });
1704                self.emit_token(private.data().token());
1705            }
1706            MemberProperty::Computed(expression) => {
1707                self.raw(if member.optional { "?.[" } else { "[" });
1708                self.emit_expression_prec(expression, 0);
1709                self.raw("]");
1710            }
1711        }
1712    }
1713
1714    fn emit_yield(&mut self, expression: &YieldExpression) {
1715        self.raw("yield");
1716        if expression.delegate {
1717            self.raw("*");
1718        }
1719        if let Some(argument) = &expression.argument {
1720            self.raw(" ");
1721            self.emit_expression_prec(argument, P_ASSIGN);
1722        }
1723    }
1724
1725    fn emit_unary(&mut self, unary: &UnaryExpression) {
1726        match unary.operator {
1727            UnaryOperator::Typeof => self.raw("typeof "),
1728            UnaryOperator::Void => self.raw("void "),
1729            UnaryOperator::Delete => self.raw("delete "),
1730            UnaryOperator::Plus => self.raw("+"),
1731            UnaryOperator::Minus => self.raw("-"),
1732            UnaryOperator::Not => self.raw("!"),
1733            UnaryOperator::BitNot => self.raw("~"),
1734        }
1735        if matches!(unary.operator, UnaryOperator::Plus | UnaryOperator::Minus)
1736            && self.needs_unary_space(&unary.argument)
1737        {
1738            self.raw(" ");
1739        }
1740        self.emit_expression_prec(&unary.argument, P_UNARY);
1741    }
1742
1743    fn needs_unary_space(&self, argument: &Expr) -> bool {
1744        match self.unwrap_expression(argument).data() {
1745            Expression::Unary(inner) => {
1746                matches!(inner.operator, UnaryOperator::Plus | UnaryOperator::Minus)
1747            }
1748            Expression::Update(inner) => inner.prefix,
1749            _ => false,
1750        }
1751    }
1752
1753    fn emit_update(&mut self, update: &UpdateExpression) {
1754        let operator = match update.operator {
1755            UpdateOperator::Increment => "++",
1756            UpdateOperator::Decrement => "--",
1757        };
1758        if update.prefix {
1759            self.raw(operator);
1760            self.emit_assignment_target(&update.argument);
1761        } else {
1762            self.emit_assignment_target(&update.argument);
1763            self.raw(operator);
1764        }
1765    }
1766
1767    fn emit_binary(&mut self, binary: &BinaryExpression) {
1768        let prec = binary_prec(binary.operator);
1769        if matches!(binary.operator, BinaryOperator::Exponentiate) {
1770            let left = self.unwrap_expression(&binary.left);
1771            if matches!(left.data(), Expression::Unary(_) | Expression::Await(_))
1772                || matches!(left.data(), Expression::Update(update) if update.prefix)
1773            {
1774                self.raw("(");
1775                self.emit_expression_prec(left, 0);
1776                self.raw(")");
1777            } else {
1778                self.emit_expression_prec(&binary.left, P_EXPONENT + 1);
1779            }
1780            self.raw(" ** ");
1781            self.emit_expression_prec(&binary.right, P_EXPONENT);
1782        } else {
1783            self.emit_expression_prec(&binary.left, prec);
1784            self.raw(" ");
1785            self.raw(binary_str(binary.operator));
1786            self.raw(" ");
1787            self.emit_expression_prec(&binary.right, prec + 1);
1788        }
1789    }
1790
1791    fn emit_logical(&mut self, logical: &LogicalExpression) {
1792        let prec = match logical.operator {
1793            LogicalOperator::And => P_LOGICAL_AND,
1794            LogicalOperator::Or => P_LOGICAL_OR,
1795            LogicalOperator::Nullish => P_NULLISH,
1796        };
1797        self.emit_logical_operand(&logical.left, logical.operator, prec, true);
1798        self.raw(" ");
1799        self.raw(logical_str(logical.operator));
1800        self.raw(" ");
1801        self.emit_logical_operand(&logical.right, logical.operator, prec, false);
1802    }
1803
1804    fn emit_logical_operand(
1805        &mut self,
1806        operand: &Expr,
1807        parent: LogicalOperator,
1808        prec: u8,
1809        is_left: bool,
1810    ) {
1811        if self.coalesce_mix(parent, operand) {
1812            self.raw("(");
1813            self.emit_expression_prec(operand, 0);
1814            self.raw(")");
1815            return;
1816        }
1817        let min_prec = if is_left { prec } else { prec + 1 };
1818        self.emit_expression_prec(operand, min_prec);
1819    }
1820
1821    fn coalesce_mix(&self, parent: LogicalOperator, operand: &Expr) -> bool {
1822        if let Expression::Logical(child) = self.unwrap_expression(operand).data() {
1823            let parent_nullish = matches!(parent, LogicalOperator::Nullish);
1824            let child_nullish = matches!(child.operator, LogicalOperator::Nullish);
1825            parent_nullish != child_nullish
1826        } else {
1827            false
1828        }
1829    }
1830
1831    fn emit_conditional(&mut self, conditional: &ConditionalExpression) {
1832        self.emit_expression_prec(&conditional.test, P_CONDITIONAL + 1);
1833        self.raw(" ? ");
1834        self.emit_expression_prec(&conditional.consequent, P_ASSIGN);
1835        self.raw(" : ");
1836        self.emit_expression_prec(&conditional.alternate, P_ASSIGN);
1837    }
1838
1839    fn emit_assignment(&mut self, assignment: &AssignmentExpression) {
1840        self.emit_assignment_target(&assignment.left);
1841        self.raw(" ");
1842        self.raw(assignment_str(assignment.operator));
1843        self.raw(" ");
1844        self.emit_expression_prec(&assignment.right, P_ASSIGN);
1845    }
1846
1847    fn emit_sequence(&mut self, sequence: &SequenceExpression) {
1848        for (index, expression) in sequence.expressions.iter().enumerate() {
1849            if index > 0 {
1850                self.raw(", ");
1851            }
1852            self.emit_expression_prec(expression, P_ASSIGN);
1853        }
1854    }
1855
1856    // ---- assignment targets / patterns ------------------------------------
1857
1858    fn emit_assignment_target(&mut self, target: &AssignmentTargetNode) {
1859        match target.data() {
1860            AssignmentTarget::Identifier(ident) => self.emit_ident(ident),
1861            AssignmentTarget::Member(member) => {
1862                let dotted = !matches!(member.property, MemberProperty::Computed(_));
1863                let numeric_object = dotted
1864                    && matches!(
1865                        self.unwrap_expression(&member.object).data(),
1866                        Expression::Literal(Literal::Number(_))
1867                    );
1868                if numeric_object {
1869                    self.raw("(");
1870                    self.emit_expression_prec(&member.object, 0);
1871                    self.raw(")");
1872                } else {
1873                    self.emit_expression_prec(&member.object, P_CALL_MEMBER);
1874                }
1875                match &member.property {
1876                    MemberProperty::Named(name) => {
1877                        self.raw(".");
1878                        self.emit_ident(name);
1879                    }
1880                    MemberProperty::Private(private) => {
1881                        self.raw(".");
1882                        self.emit_token(private.data().token());
1883                    }
1884                    MemberProperty::Computed(expression) => {
1885                        self.raw("[");
1886                        self.emit_expression_prec(expression, 0);
1887                        self.raw("]");
1888                    }
1889                }
1890            }
1891            AssignmentTarget::Object(pattern) => {
1892                self.raw("{");
1893                for (index, property) in pattern.properties.iter().enumerate() {
1894                    if index > 0 {
1895                        self.raw(", ");
1896                    } else {
1897                        self.raw(" ");
1898                    }
1899                    self.emit_assignment_object_property(property);
1900                }
1901                if pattern.properties.is_empty() {
1902                    self.raw("}");
1903                } else {
1904                    self.raw(" }");
1905                }
1906            }
1907            AssignmentTarget::Array(pattern) => {
1908                self.raw("[");
1909                for (index, element) in pattern.elements.iter().enumerate() {
1910                    if index > 0 {
1911                        self.raw(", ");
1912                    }
1913                    match element {
1914                        AssignmentArrayElement::Target(target) => {
1915                            self.emit_assignment_target(target)
1916                        }
1917                        AssignmentArrayElement::Elision => {}
1918                        AssignmentArrayElement::Missing(_) => {
1919                            self.diag_here(codes::MISSING_TARGET, "cannot emit a missing target");
1920                        }
1921                    }
1922                }
1923                if matches!(
1924                    pattern.elements.last(),
1925                    Some(AssignmentArrayElement::Elision)
1926                ) {
1927                    self.raw(",");
1928                }
1929                self.raw("]");
1930            }
1931            AssignmentTarget::Missing(_) => {
1932                self.diag_here(
1933                    codes::MISSING_TARGET,
1934                    "cannot emit a missing assignment target",
1935                );
1936            }
1937        }
1938    }
1939
1940    fn emit_assignment_object_property(&mut self, property: &AssignmentObjectProperty) {
1941        let shorthand = property.initializer.is_none()
1942            && self.target_matches_name(&property.name, &property.target);
1943        if shorthand {
1944            self.emit_property_name(&property.name);
1945        } else {
1946            self.emit_property_name(&property.name);
1947            self.raw(": ");
1948            self.emit_assignment_target(&property.target);
1949        }
1950        if let Some(initializer) = &property.initializer {
1951            self.raw(" = ");
1952            self.emit_expression_prec(initializer, P_ASSIGN);
1953        }
1954    }
1955
1956    fn emit_pattern(&mut self, pattern: &Pattern) {
1957        match pattern.data() {
1958            BindingPattern::Identifier(ident) => self.emit_ident(ident),
1959            BindingPattern::Object(object) => {
1960                if object.properties.is_empty() {
1961                    self.raw("{}");
1962                    return;
1963                }
1964                self.raw("{ ");
1965                for (index, property) in object.properties.iter().enumerate() {
1966                    if index > 0 {
1967                        self.raw(", ");
1968                    }
1969                    self.emit_object_binding_property(property);
1970                }
1971                self.raw(" }");
1972            }
1973            BindingPattern::Array(array) => {
1974                self.raw("[");
1975                for (index, element) in array.elements.iter().enumerate() {
1976                    if index > 0 {
1977                        self.raw(", ");
1978                    }
1979                    match element {
1980                        ArrayBindingElement::Binding(binding) => self.emit_pattern(binding),
1981                        ArrayBindingElement::Elision => {}
1982                        ArrayBindingElement::Missing(_) => {
1983                            self.diag_here(codes::MISSING_BINDING, "cannot emit a missing binding");
1984                        }
1985                    }
1986                }
1987                if matches!(array.elements.last(), Some(ArrayBindingElement::Elision)) {
1988                    self.raw(",");
1989                }
1990                self.raw("]");
1991            }
1992            BindingPattern::Rest(rest) => {
1993                self.raw("...");
1994                self.emit_pattern(&rest.argument);
1995            }
1996            BindingPattern::Assignment(assignment) => {
1997                self.emit_pattern(&assignment.left);
1998                self.raw(" = ");
1999                self.emit_expression_prec(&assignment.right, P_ASSIGN);
2000            }
2001            BindingPattern::Missing(_) => {
2002                self.diag_here(
2003                    codes::MISSING_BINDING,
2004                    "cannot emit a missing binding pattern",
2005                );
2006            }
2007        }
2008    }
2009
2010    fn emit_object_binding_property(&mut self, property: &ObjectBindingProperty) {
2011        if let BindingPattern::Rest(rest) = property.binding.data() {
2012            self.raw("...");
2013            self.emit_pattern(&rest.argument);
2014            return;
2015        }
2016        let shorthand = self.binding_matches_name(&property.name, &property.binding);
2017        if shorthand {
2018            self.emit_property_name(&property.name);
2019        } else {
2020            self.emit_property_name(&property.name);
2021            self.raw(": ");
2022            self.emit_pattern(&property.binding);
2023        }
2024        if let Some(initializer) = &property.initializer {
2025            self.raw(" = ");
2026            self.emit_expression_prec(initializer, P_ASSIGN);
2027        }
2028    }
2029
2030    // ---- shorthand / name matching helpers --------------------------------
2031
2032    fn module_name_matches_ident(&self, name: &ModuleExportName, ident: &IdentifierNode) -> bool {
2033        match name {
2034            ModuleExportName::Identifier(imported) => self.same_ident_text(imported, ident),
2035            _ => false,
2036        }
2037    }
2038
2039    fn module_names_match(&self, left: &ModuleExportName, right: &ModuleExportName) -> bool {
2040        match (left, right) {
2041            (ModuleExportName::Identifier(a), ModuleExportName::Identifier(b)) => {
2042                self.same_ident_text(a, b)
2043            }
2044            _ => false,
2045        }
2046    }
2047
2048    fn target_matches_name(&self, name: &PropertyName, target: &AssignmentTargetNode) -> bool {
2049        if let (PropertyName::Identifier(a), AssignmentTarget::Identifier(b)) =
2050            (name, target.data())
2051        {
2052            self.same_ident_text(a, b)
2053        } else {
2054            false
2055        }
2056    }
2057
2058    fn binding_matches_name(&self, name: &PropertyName, binding: &Pattern) -> bool {
2059        if let (PropertyName::Identifier(a), BindingPattern::Identifier(b)) = (name, binding.data())
2060        {
2061            self.same_ident_text(a, b)
2062        } else {
2063            false
2064        }
2065    }
2066
2067    fn same_ident_text(&self, left: &IdentifierNode, right: &IdentifierNode) -> bool {
2068        match (
2069            self.text(left.data().token()),
2070            self.text(right.data().token()),
2071        ) {
2072            (Some(a), Some(b)) => a == b,
2073            _ => false,
2074        }
2075    }
2076
2077    fn emit_module_export_name(&mut self, name: &ModuleExportName) {
2078        match name {
2079            ModuleExportName::Identifier(ident) => self.emit_ident(ident),
2080            ModuleExportName::String(string) => self.emit_string(string),
2081            ModuleExportName::Missing(_) => {
2082                self.diag_here(
2083                    codes::MISSING_NAME,
2084                    "cannot emit a missing module export name",
2085                );
2086            }
2087        }
2088    }
2089
2090    fn emit_entity_name(&mut self, name: &EntityName) {
2091        match name {
2092            EntityName::Identifier(ident) => self.emit_ident(ident),
2093            EntityName::Qualified { left, right } => {
2094                self.emit_entity_name(left);
2095                self.raw(".");
2096                self.emit_ident(right);
2097            }
2098            EntityName::Missing(_) => {
2099                self.diag_here(codes::MISSING_NAME, "cannot emit a missing entity name");
2100            }
2101        }
2102    }
2103
2104    // ---- expression classification ----------------------------------------
2105
2106    fn unwrap_expression<'e>(&self, expression: &'e Expr) -> &'e Expr {
2107        match expression.data() {
2108            Expression::Parenthesized(inner) => self.unwrap_expression(inner),
2109            Expression::As(as_expr) => self.unwrap_expression(&as_expr.expression),
2110            Expression::Satisfies(satisfies) => self.unwrap_expression(&satisfies.expression),
2111            Expression::TypeAssertion(assertion) => self.unwrap_expression(&assertion.expression),
2112            Expression::NonNull(non_null) => self.unwrap_expression(&non_null.expression),
2113            _ => expression,
2114        }
2115    }
2116
2117    fn chain_has_optional(&self, expression: &Expr) -> bool {
2118        match expression.data() {
2119            Expression::Member(member) => {
2120                member.optional || self.chain_has_optional(&member.object)
2121            }
2122            Expression::Call(call) => call.optional || self.chain_has_optional(&call.callee),
2123            Expression::NonNull(non_null) => self.chain_has_optional(&non_null.expression),
2124            Expression::Parenthesized(inner) => self.chain_has_optional(inner),
2125            Expression::As(as_expr) => self.chain_has_optional(&as_expr.expression),
2126            Expression::Satisfies(satisfies) => self.chain_has_optional(&satisfies.expression),
2127            Expression::TypeAssertion(assertion) => self.chain_has_optional(&assertion.expression),
2128            _ => false,
2129        }
2130    }
2131
2132    /// Whether an expression, at a statement or arrow-body position, would begin
2133    /// with a token requiring wrapping parentheses (`{`, `function`, `class`).
2134    fn leads_with_bad_token(&self, expression: &Expr, objects_only: bool) -> bool {
2135        match expression.data() {
2136            Expression::Object(_) => true,
2137            Expression::Function(_) | Expression::Class(_) => !objects_only,
2138            Expression::Binary(binary) => self.leads_with_bad_token(&binary.left, objects_only),
2139            Expression::Logical(logical) => self.leads_with_bad_token(&logical.left, objects_only),
2140            Expression::Conditional(conditional) => {
2141                self.leads_with_bad_token(&conditional.test, objects_only)
2142            }
2143            Expression::Assignment(assignment) => self.target_leads_with_object(&assignment.left),
2144            Expression::Sequence(sequence) => sequence
2145                .expressions
2146                .first()
2147                .is_some_and(|first| self.leads_with_bad_token(first, objects_only)),
2148            Expression::Call(call) => self.leads_with_bad_token(&call.callee, objects_only),
2149            Expression::Member(member) => self.leads_with_bad_token(&member.object, objects_only),
2150            Expression::TaggedTemplate(tagged) => {
2151                self.leads_with_bad_token(&tagged.tag, objects_only)
2152            }
2153            Expression::Update(update) => {
2154                !update.prefix && self.target_leads_with_object(&update.argument)
2155            }
2156            Expression::NonNull(non_null) => {
2157                self.leads_with_bad_token(&non_null.expression, objects_only)
2158            }
2159            Expression::As(as_expr) => self.leads_with_bad_token(&as_expr.expression, objects_only),
2160            Expression::Satisfies(satisfies) => {
2161                self.leads_with_bad_token(&satisfies.expression, objects_only)
2162            }
2163            Expression::TypeAssertion(assertion) => {
2164                self.leads_with_bad_token(&assertion.expression, objects_only)
2165            }
2166            Expression::Parenthesized(inner) => self.leads_with_bad_token(inner, objects_only),
2167            _ => false,
2168        }
2169    }
2170
2171    fn target_leads_with_object(&self, target: &AssignmentTargetNode) -> bool {
2172        match target.data() {
2173            AssignmentTarget::Object(_) => true,
2174            AssignmentTarget::Member(member) => self.leads_with_bad_token(&member.object, false),
2175            _ => false,
2176        }
2177    }
2178
2179    // =======================================================================
2180    // Declaration (.d.ts) emit
2181    // =======================================================================
2182
2183    fn emit_declaration(&mut self, statement: &Stmt) -> bool {
2184        let previous = self.anchor;
2185        self.anchor = statement.range();
2186        let emitted = match statement.data() {
2187            Statement::Import(import) => self.emit_import(import, true),
2188            Statement::ImportEquals(import) => {
2189                self.emit_import_equals_decl(import);
2190                true
2191            }
2192            Statement::Export(export) => self.emit_export_decl(export),
2193            Statement::Variable(declaration) => {
2194                self.emit_variable_decl(declaration);
2195                true
2196            }
2197            Statement::Function(function) => {
2198                self.emit_declare_prefix();
2199                self.emit_function_signature_decl(&function.function);
2200                true
2201            }
2202            Statement::Class(class) => {
2203                self.emit_declare_prefix();
2204                self.emit_class_core_decl(class);
2205                true
2206            }
2207            Statement::Interface(interface) => {
2208                self.emit_interface_decl(interface);
2209                true
2210            }
2211            Statement::TypeAlias(alias) => {
2212                self.emit_type_alias_decl(alias);
2213                true
2214            }
2215            Statement::Enum(declaration) => {
2216                self.emit_enum_decl(declaration);
2217                true
2218            }
2219            Statement::Namespace(namespace) => {
2220                self.emit_namespace_decl(namespace);
2221                true
2222            }
2223            Statement::Declare(inner) => self.emit_declaration(inner),
2224            Statement::Missing(_) => {
2225                self.diag_here(
2226                    codes::MISSING_STATEMENT,
2227                    "cannot emit a missing statement node",
2228                );
2229                false
2230            }
2231            _ => false,
2232        };
2233        self.anchor = previous;
2234        emitted
2235    }
2236
2237    fn decl_statement_emits(&self, statement: &Stmt) -> bool {
2238        matches!(
2239            statement.data(),
2240            Statement::Import(_)
2241                | Statement::ImportEquals(_)
2242                | Statement::Variable(_)
2243                | Statement::Function(_)
2244                | Statement::Class(_)
2245                | Statement::Interface(_)
2246                | Statement::TypeAlias(_)
2247                | Statement::Enum(_)
2248                | Statement::Namespace(_)
2249                | Statement::Declare(_)
2250        )
2251    }
2252
2253    fn emit_declare_prefix(&mut self) {
2254        if self.decl_ambient && !self.decl_in_export {
2255            self.raw("declare ");
2256        }
2257    }
2258
2259    fn emit_import_equals_decl(&mut self, import: &ImportEqualsDeclaration) {
2260        self.emit_declare_prefix();
2261        self.raw("import ");
2262        if import.is_type_only {
2263            self.raw("type ");
2264        }
2265        self.emit_ident(&import.local);
2266        self.raw(" = ");
2267        match &import.reference {
2268            ExternalModuleReference::Require(source) => {
2269                self.raw("require(");
2270                self.emit_string(source);
2271                self.raw(")");
2272            }
2273            ExternalModuleReference::Qualified(name) => self.emit_entity_name(name),
2274            ExternalModuleReference::Missing(_) => {
2275                self.diag_here(
2276                    codes::MISSING_NAME,
2277                    "cannot emit a missing module reference",
2278                );
2279            }
2280        }
2281        self.raw(";");
2282    }
2283
2284    fn emit_export_decl(&mut self, export: &ExportDeclaration) -> bool {
2285        match export {
2286            ExportDeclaration::Named(ExportNamedDeclaration::Declaration(inner)) => {
2287                if !self.decl_statement_emits(inner) {
2288                    return false;
2289                }
2290                self.raw("export ");
2291                self.decl_in_export = true;
2292                let emitted = self.emit_declaration(inner);
2293                self.decl_in_export = false;
2294                emitted
2295            }
2296            ExportDeclaration::Named(ExportNamedDeclaration::Specifiers {
2297                type_only,
2298                specifiers,
2299                source,
2300                attributes,
2301            }) => {
2302                self.raw("export ");
2303                if *type_only {
2304                    self.raw("type ");
2305                }
2306                if specifiers.is_empty() {
2307                    self.raw("{}");
2308                } else {
2309                    self.raw("{ ");
2310                    for (index, specifier) in specifiers.iter().enumerate() {
2311                        if index > 0 {
2312                            self.raw(", ");
2313                        }
2314                        self.emit_export_specifier(specifier.data(), !*type_only);
2315                    }
2316                    self.raw(" }");
2317                }
2318                if let Some(source) = source {
2319                    self.raw(" from ");
2320                    self.emit_string(source);
2321                    if let Some(attributes) = attributes {
2322                        self.emit_import_attributes(attributes);
2323                    }
2324                }
2325                self.raw(";");
2326                true
2327            }
2328            ExportDeclaration::All(all) => {
2329                self.raw("export ");
2330                if all.type_only {
2331                    self.raw("type ");
2332                }
2333                self.raw("* ");
2334                if let Some(name) = &all.exported {
2335                    self.raw("as ");
2336                    self.emit_module_export_name(name);
2337                    self.raw(" ");
2338                }
2339                self.raw("from ");
2340                self.emit_string(&all.source);
2341                if let Some(attributes) = &all.attributes {
2342                    self.emit_import_attributes(attributes);
2343                }
2344                self.raw(";");
2345                true
2346            }
2347            ExportDeclaration::Default(default) => match &default.value {
2348                ExportDefaultValue::Function(function) => {
2349                    self.raw("export default ");
2350                    self.emit_function_signature_decl(function);
2351                    true
2352                }
2353                ExportDefaultValue::Class(class) => {
2354                    self.raw("export default ");
2355                    self.emit_class_core_decl(class);
2356                    true
2357                }
2358                ExportDefaultValue::Expression(expression) => {
2359                    self.raw("export default ");
2360                    self.emit_expression_prec(expression, P_ASSIGN);
2361                    self.raw(";");
2362                    true
2363                }
2364                ExportDefaultValue::Missing(_) => {
2365                    self.diag_here(
2366                        codes::MISSING_EXPRESSION,
2367                        "cannot emit a missing default export",
2368                    );
2369                    false
2370                }
2371            },
2372            ExportDeclaration::Assignment(expression) => {
2373                self.raw("export = ");
2374                self.emit_expression_prec(expression, P_ASSIGN);
2375                self.raw(";");
2376                true
2377            }
2378        }
2379    }
2380
2381    fn emit_variable_decl(&mut self, declaration: &VariableDeclaration) {
2382        self.emit_declare_prefix();
2383        self.raw(variable_kind_str(declaration.kind));
2384        self.raw(" ");
2385        for (index, declarator) in declaration.declarations.iter().enumerate() {
2386            if index > 0 {
2387                self.raw(", ");
2388            }
2389            let declarator = declarator.data();
2390            self.emit_pattern(&declarator.binding);
2391            if let Some(annotation) = &declarator.type_annotation {
2392                self.raw(": ");
2393                self.emit_type(&annotation.data().type_node);
2394            }
2395        }
2396        self.raw(";");
2397    }
2398
2399    fn emit_function_signature_decl(&mut self, function: &FunctionLike) {
2400        self.raw("function");
2401        if let Some(name) = &function.name {
2402            self.raw(" ");
2403            self.emit_ident(name);
2404        }
2405        self.emit_type_parameters(&function.type_parameters);
2406        self.emit_params_decl(&function.parameters);
2407        if let Some(return_type) = &function.return_type {
2408            self.raw(": ");
2409            self.emit_type(&return_type.data().type_node);
2410        }
2411        self.raw(";");
2412    }
2413
2414    fn emit_params_decl(&mut self, parameters: &[ParameterNode]) {
2415        self.raw("(");
2416        for (index, parameter) in parameters.iter().enumerate() {
2417            if index > 0 {
2418                self.raw(", ");
2419            }
2420            let parameter = parameter.data();
2421            if let Some(accessibility) = parameter.modifiers.accessibility {
2422                self.raw(accessibility_str(accessibility));
2423                self.raw(" ");
2424            }
2425            if parameter.modifiers.is_readonly {
2426                self.raw("readonly ");
2427            }
2428            self.emit_pattern(&parameter.binding);
2429            if parameter.optional {
2430                self.raw("?");
2431            }
2432            if let Some(annotation) = &parameter.type_annotation {
2433                self.raw(": ");
2434                self.emit_type(&annotation.data().type_node);
2435            }
2436        }
2437        self.raw(")");
2438    }
2439
2440    fn emit_class_core_decl(&mut self, class: &ClassDeclaration) {
2441        if class.modifiers.is_abstract {
2442            self.raw("abstract ");
2443        }
2444        self.raw("class");
2445        if let Some(name) = &class.name {
2446            self.raw(" ");
2447            self.emit_ident(name);
2448        }
2449        self.emit_type_parameters(&class.type_parameters);
2450        if let Some(heritage) = &class.extends {
2451            self.raw(" extends ");
2452            self.emit_expression_prec(&heritage.expression, P_CALL_MEMBER);
2453            self.emit_type_arguments(&heritage.type_arguments);
2454        }
2455        if !class.implements.is_empty() {
2456            self.raw(" implements ");
2457            for (index, interface) in class.implements.iter().enumerate() {
2458                if index > 0 {
2459                    self.raw(", ");
2460                }
2461                self.emit_type(interface);
2462            }
2463        }
2464        self.raw(" ");
2465        self.emit_class_body_decl(&class.members);
2466    }
2467
2468    fn emit_class_body_decl(&mut self, members: &[ClassMemberNode]) {
2469        self.raw("{");
2470        let has = members
2471            .iter()
2472            .any(|member| self.class_member_emits_decl(member.data()));
2473        if has {
2474            self.newline();
2475            self.indent += 1;
2476        }
2477        for member in members {
2478            if self.emit_class_member_decl(member.data()) {
2479                self.newline();
2480            }
2481        }
2482        if has {
2483            self.indent -= 1;
2484        }
2485        self.raw("}");
2486    }
2487
2488    fn class_member_emits_decl(&self, member: &ClassMember) -> bool {
2489        !matches!(
2490            member,
2491            ClassMember::StaticBlock(_) | ClassMember::Missing(_)
2492        )
2493    }
2494
2495    fn emit_class_member_decl(&mut self, member: &ClassMember) -> bool {
2496        match member {
2497            ClassMember::Constructor(constructor) => {
2498                if let Some(accessibility) = constructor.modifiers.accessibility {
2499                    self.raw(accessibility_str(accessibility));
2500                    self.raw(" ");
2501                }
2502                self.raw("constructor");
2503                self.emit_params_decl(&constructor.parameters);
2504                self.raw(";");
2505                true
2506            }
2507            ClassMember::Method(method) => {
2508                self.emit_member_modifiers_decl(&method.modifiers);
2509                match method.modifier {
2510                    PropertyModifier::Get => self.raw("get "),
2511                    PropertyModifier::Set => self.raw("set "),
2512                    PropertyModifier::None => {}
2513                }
2514                self.emit_property_name(&method.name);
2515                if method.optional {
2516                    self.raw("?");
2517                }
2518                self.emit_type_parameters(&method.function.type_parameters);
2519                self.emit_params_decl(&method.function.parameters);
2520                if let Some(return_type) = &method.function.return_type {
2521                    self.raw(": ");
2522                    self.emit_type(&return_type.data().type_node);
2523                }
2524                self.raw(";");
2525                true
2526            }
2527            ClassMember::Property(property) => {
2528                self.emit_member_modifiers_decl(&property.modifiers);
2529                self.emit_property_name(&property.name);
2530                if property.optional {
2531                    self.raw("?");
2532                }
2533                if let Some(annotation) = &property.type_annotation {
2534                    self.raw(": ");
2535                    self.emit_type(&annotation.data().type_node);
2536                }
2537                self.raw(";");
2538                true
2539            }
2540            ClassMember::AutoAccessor(accessor) => {
2541                self.emit_member_modifiers_decl(&accessor.modifiers);
2542                self.raw("accessor ");
2543                self.emit_property_name(&accessor.name);
2544                if let Some(annotation) = &accessor.type_annotation {
2545                    self.raw(": ");
2546                    self.emit_type(&annotation.data().type_node);
2547                }
2548                self.raw(";");
2549                true
2550            }
2551            ClassMember::IndexSignature(signature) => {
2552                if signature.readonly {
2553                    self.raw("readonly ");
2554                }
2555                self.raw("[");
2556                self.emit_params_decl_inner(&signature.parameters);
2557                self.raw("]: ");
2558                self.emit_type(&signature.type_annotation.data().type_node);
2559                self.raw(";");
2560                true
2561            }
2562            ClassMember::StaticBlock(_) => false,
2563            ClassMember::Missing(_) => {
2564                self.diag_here(codes::MISSING_MEMBER, "cannot emit a missing class member");
2565                false
2566            }
2567        }
2568    }
2569
2570    fn emit_params_decl_inner(&mut self, parameters: &[ParameterNode]) {
2571        for (index, parameter) in parameters.iter().enumerate() {
2572            if index > 0 {
2573                self.raw(", ");
2574            }
2575            let parameter = parameter.data();
2576            self.emit_pattern(&parameter.binding);
2577            if let Some(annotation) = &parameter.type_annotation {
2578                self.raw(": ");
2579                self.emit_type(&annotation.data().type_node);
2580            }
2581        }
2582    }
2583
2584    fn emit_member_modifiers_decl(&mut self, modifiers: &DeclarationModifiers) {
2585        if let Some(accessibility) = modifiers.accessibility {
2586            self.raw(accessibility_str(accessibility));
2587            self.raw(" ");
2588        }
2589        if modifiers.is_static {
2590            self.raw("static ");
2591        }
2592        if modifiers.is_abstract {
2593            self.raw("abstract ");
2594        }
2595        if modifiers.is_readonly {
2596            self.raw("readonly ");
2597        }
2598    }
2599
2600    fn emit_interface_decl(&mut self, interface: &InterfaceDeclaration) {
2601        self.raw("interface ");
2602        self.emit_ident(&interface.name);
2603        self.emit_type_parameters(&interface.type_parameters);
2604        if !interface.extends.is_empty() {
2605            self.raw(" extends ");
2606            for (index, reference) in interface.extends.iter().enumerate() {
2607                if index > 0 {
2608                    self.raw(", ");
2609                }
2610                self.emit_type_reference(reference);
2611            }
2612        }
2613        self.raw(" ");
2614        self.emit_type_members_block(&interface.members);
2615    }
2616
2617    fn emit_type_alias_decl(&mut self, alias: &TypeAliasDeclaration) {
2618        self.raw("type ");
2619        self.emit_ident(&alias.name);
2620        self.emit_type_parameters(&alias.type_parameters);
2621        self.raw(" = ");
2622        self.emit_type(&alias.type_node);
2623        self.raw(";");
2624    }
2625
2626    fn emit_enum_decl(&mut self, declaration: &EnumDeclaration) {
2627        self.emit_declare_prefix();
2628        if declaration.is_const {
2629            self.raw("const ");
2630        }
2631        self.raw("enum ");
2632        self.emit_ident(&declaration.name);
2633        self.raw(" ");
2634        if declaration.members.is_empty() {
2635            self.raw("{}");
2636            return;
2637        }
2638        self.raw("{");
2639        self.newline();
2640        self.indent += 1;
2641        let count = declaration.members.len();
2642        for (index, member) in declaration.members.iter().enumerate() {
2643            let member = member.data();
2644            self.emit_property_name(&member.name);
2645            if let Some(initializer) = &member.initializer {
2646                self.raw(" = ");
2647                self.emit_expression_prec(initializer, P_ASSIGN);
2648            }
2649            if index + 1 < count {
2650                self.raw(",");
2651            }
2652            self.newline();
2653        }
2654        self.indent -= 1;
2655        self.raw("}");
2656    }
2657
2658    fn emit_namespace_decl(&mut self, namespace: &NamespaceDeclaration) {
2659        self.emit_declare_prefix();
2660        self.raw("namespace ");
2661        self.emit_ident(&namespace.name);
2662        self.raw(" {");
2663        let body = namespace.body.data();
2664        if body.statements.is_empty() {
2665            self.raw("}");
2666            return;
2667        }
2668        self.newline();
2669        self.indent += 1;
2670        let saved_ambient = self.decl_ambient;
2671        self.decl_ambient = false;
2672        for statement in &body.statements {
2673            if self.emit_declaration(statement) {
2674                self.newline();
2675            }
2676        }
2677        self.decl_ambient = saved_ambient;
2678        self.indent -= 1;
2679        self.raw("}");
2680    }
2681
2682    // ---- types ------------------------------------------------------------
2683
2684    fn emit_type_parameters(&mut self, parameters: &Option<TypeParameterList>) {
2685        let Some(list) = parameters else {
2686            return;
2687        };
2688        if list.parameters.is_empty() {
2689            return;
2690        }
2691        self.raw("<");
2692        for (index, parameter) in list.parameters.iter().enumerate() {
2693            if index > 0 {
2694                self.raw(", ");
2695            }
2696            self.emit_type_parameter(parameter.data());
2697        }
2698        self.raw(">");
2699    }
2700
2701    fn emit_type_parameter(&mut self, parameter: &TypeParameter) {
2702        match parameter.variance {
2703            Variance::In => self.raw("in "),
2704            Variance::Out => self.raw("out "),
2705            Variance::InOut => self.raw("in out "),
2706            Variance::Invariant => {}
2707        }
2708        self.emit_ident(&parameter.name);
2709        if let Some(constraint) = &parameter.constraint {
2710            self.raw(" extends ");
2711            self.emit_type(constraint);
2712        }
2713        if let Some(default) = &parameter.default {
2714            self.raw(" = ");
2715            self.emit_type(default);
2716        }
2717    }
2718
2719    fn emit_type_arguments(&mut self, arguments: &Option<TypeArgumentList>) {
2720        let Some(list) = arguments else {
2721            return;
2722        };
2723        if list.arguments.is_empty() {
2724            return;
2725        }
2726        self.raw("<");
2727        for (index, argument) in list.arguments.iter().enumerate() {
2728            if index > 0 {
2729                self.raw(", ");
2730            }
2731            self.emit_type(argument);
2732        }
2733        self.raw(">");
2734    }
2735
2736    fn emit_type_reference(&mut self, reference: &TypeReference) {
2737        self.emit_entity_name(&reference.name);
2738        self.emit_type_arguments(&reference.type_arguments);
2739    }
2740
2741    fn emit_type(&mut self, ty: &Ty) {
2742        let previous = self.anchor;
2743        self.anchor = ty.range();
2744        match ty.data() {
2745            TypeNode::Keyword(keyword) => self.raw(keyword_type_str(*keyword)),
2746            TypeNode::Literal(literal) => self.emit_type_literal(literal),
2747            TypeNode::Reference(reference) => self.emit_type_reference(reference),
2748            TypeNode::Union(members) => self.emit_union(members),
2749            TypeNode::Intersection(members) => self.emit_intersection(members),
2750            TypeNode::Array(element) => {
2751                self.emit_type_postfix_operand(element);
2752                self.raw("[]");
2753            }
2754            TypeNode::Tuple(tuple) => self.emit_tuple(tuple),
2755            TypeNode::Object(object) => self.emit_object_type(object),
2756            TypeNode::Function(function) => self.emit_function_type(function),
2757            TypeNode::Constructor(constructor) => {
2758                if constructor.is_abstract {
2759                    self.raw("abstract ");
2760                }
2761                self.raw("new ");
2762                self.emit_function_type_body(&constructor.function);
2763            }
2764            TypeNode::Query(query) => {
2765                self.raw("typeof ");
2766                self.emit_entity_name(&query.name);
2767                self.emit_type_arguments(&query.type_arguments);
2768            }
2769            TypeNode::Operator { operator, operand } => {
2770                self.raw(type_operator_str(*operator));
2771                self.raw(" ");
2772                self.emit_type_operator_operand(operand);
2773            }
2774            TypeNode::IndexedAccess(indexed) => {
2775                self.emit_type_postfix_operand(&indexed.object_type);
2776                self.raw("[");
2777                self.emit_type(&indexed.index_type);
2778                self.raw("]");
2779            }
2780            TypeNode::Conditional(conditional) => {
2781                self.emit_type(&conditional.check_type);
2782                self.raw(" extends ");
2783                self.emit_type(&conditional.extends_type);
2784                self.raw(" ? ");
2785                self.emit_type(&conditional.true_type);
2786                self.raw(" : ");
2787                self.emit_type(&conditional.false_type);
2788            }
2789            TypeNode::Mapped(mapped) => self.emit_mapped_type(mapped),
2790            TypeNode::Infer(infer) => {
2791                self.raw("infer ");
2792                self.emit_ident(&infer.parameter.data().name);
2793                if let Some(constraint) = &infer.parameter.data().constraint {
2794                    self.raw(" extends ");
2795                    self.emit_type(constraint);
2796                }
2797            }
2798            TypeNode::Import(import) => {
2799                self.raw("import(");
2800                self.emit_string(&import.argument);
2801                self.raw(")");
2802                if let Some(qualifier) = &import.qualifier {
2803                    self.raw(".");
2804                    self.emit_entity_name(qualifier);
2805                }
2806                self.emit_type_arguments(&import.type_arguments);
2807            }
2808            TypeNode::TemplateLiteral(template) => self.emit_template_literal_type(template),
2809            TypeNode::Parenthesized(inner) => self.emit_type(inner),
2810            TypeNode::This => self.raw("this"),
2811            TypeNode::Predicate(predicate) => self.emit_type_predicate(predicate),
2812            TypeNode::Missing(_) => {
2813                self.diag_here(codes::MISSING_TYPE, "cannot emit a missing type node");
2814                self.raw("any");
2815            }
2816        }
2817        self.anchor = previous;
2818    }
2819
2820    fn emit_type_literal(&mut self, literal: &TypeLiteral) {
2821        match literal {
2822            TypeLiteral::String(node) => self.emit_token(node.data().token()),
2823            TypeLiteral::Number(node) => self.emit_token(node.data().token()),
2824            TypeLiteral::BigInt(node) => self.emit_token(node.data().token()),
2825            TypeLiteral::Boolean(node) => self.emit_token(node.data().token()),
2826            TypeLiteral::Null(node) => match self.text(node.data().token()) {
2827                Some(text) if !text.is_empty() => self.raw(text),
2828                _ => self.raw("null"),
2829            },
2830            TypeLiteral::Unary { operator, operand } => {
2831                self.raw(unary_operator_str(*operator));
2832                self.emit_type(operand);
2833            }
2834        }
2835    }
2836
2837    fn emit_union(&mut self, members: &[Ty]) {
2838        for (index, member) in members.iter().enumerate() {
2839            if index > 0 {
2840                self.raw(" | ");
2841            }
2842            if is_low_precedence_type(self.unwrap_type(member)) {
2843                self.raw("(");
2844                self.emit_type(member);
2845                self.raw(")");
2846            } else {
2847                self.emit_type(member);
2848            }
2849        }
2850    }
2851
2852    fn emit_intersection(&mut self, members: &[Ty]) {
2853        for (index, member) in members.iter().enumerate() {
2854            if index > 0 {
2855                self.raw(" & ");
2856            }
2857            let inner = self.unwrap_type(member);
2858            if is_low_precedence_type(inner) || matches!(inner.data(), TypeNode::Union(_)) {
2859                self.raw("(");
2860                self.emit_type(member);
2861                self.raw(")");
2862            } else {
2863                self.emit_type(member);
2864            }
2865        }
2866    }
2867
2868    fn emit_type_postfix_operand(&mut self, ty: &Ty) {
2869        let inner = self.unwrap_type(ty);
2870        let wrap = is_low_precedence_type(inner)
2871            || matches!(
2872                inner.data(),
2873                TypeNode::Union(_) | TypeNode::Intersection(_) | TypeNode::Operator { .. }
2874            );
2875        if wrap {
2876            self.raw("(");
2877            self.emit_type(ty);
2878            self.raw(")");
2879        } else {
2880            self.emit_type(ty);
2881        }
2882    }
2883
2884    fn emit_type_operator_operand(&mut self, ty: &Ty) {
2885        let inner = self.unwrap_type(ty);
2886        if is_low_precedence_type(inner)
2887            || matches!(inner.data(), TypeNode::Union(_) | TypeNode::Intersection(_))
2888        {
2889            self.raw("(");
2890            self.emit_type(ty);
2891            self.raw(")");
2892        } else {
2893            self.emit_type(ty);
2894        }
2895    }
2896
2897    fn emit_tuple(&mut self, tuple: &TupleType) {
2898        if tuple.readonly {
2899            self.raw("readonly ");
2900        }
2901        self.raw("[");
2902        for (index, element) in tuple.elements.iter().enumerate() {
2903            if index > 0 {
2904                self.raw(", ");
2905            }
2906            if element.rest {
2907                self.raw("...");
2908            }
2909            if let Some(name) = &element.name {
2910                self.emit_ident(name);
2911                if element.optional {
2912                    self.raw("?");
2913                }
2914                self.raw(": ");
2915                self.emit_type(&element.type_node);
2916            } else {
2917                self.emit_type(&element.type_node);
2918                if element.optional {
2919                    self.raw("?");
2920                }
2921            }
2922        }
2923        self.raw("]");
2924    }
2925
2926    fn emit_object_type(&mut self, object: &ObjectType) {
2927        if object.members.is_empty() {
2928            self.raw("{}");
2929            return;
2930        }
2931        self.raw("{ ");
2932        for (index, member) in object.members.iter().enumerate() {
2933            if index > 0 {
2934                self.raw(" ");
2935            }
2936            self.emit_type_member(member.data());
2937        }
2938        self.raw(" }");
2939    }
2940
2941    fn emit_type_members_block(&mut self, members: &[TypeMemberNode]) {
2942        if members.is_empty() {
2943            self.raw("{}");
2944            return;
2945        }
2946        self.raw("{");
2947        self.newline();
2948        self.indent += 1;
2949        for member in members {
2950            self.emit_type_member(member.data());
2951            self.newline();
2952        }
2953        self.indent -= 1;
2954        self.raw("}");
2955    }
2956
2957    fn emit_type_member(&mut self, member: &TypeMember) {
2958        match member {
2959            TypeMember::Property(property) => {
2960                if property.readonly {
2961                    self.raw("readonly ");
2962                }
2963                self.emit_property_name(&property.name);
2964                if property.optional {
2965                    self.raw("?");
2966                }
2967                if let Some(annotation) = &property.type_annotation {
2968                    self.raw(": ");
2969                    self.emit_type(&annotation.data().type_node);
2970                }
2971                self.raw(";");
2972            }
2973            TypeMember::Method(method) => {
2974                self.emit_property_name(&method.name);
2975                if method.optional {
2976                    self.raw("?");
2977                }
2978                self.emit_function_type_body(&method.function);
2979                self.raw(";");
2980            }
2981            TypeMember::Call(call) => {
2982                self.emit_function_type_body(&call.function);
2983                self.raw(";");
2984            }
2985            TypeMember::Construct(construct) => {
2986                self.raw("new ");
2987                self.emit_function_type_body(&construct.function.function);
2988                self.raw(";");
2989            }
2990            TypeMember::Index(index) => {
2991                if index.readonly {
2992                    self.raw("readonly ");
2993                }
2994                self.raw("[");
2995                self.emit_function_type_parameters(&index.parameters);
2996                self.raw("]: ");
2997                self.emit_type(&index.type_annotation.data().type_node);
2998                self.raw(";");
2999            }
3000            TypeMember::Missing(_) => {
3001                self.diag_here(codes::MISSING_MEMBER, "cannot emit a missing type member");
3002            }
3003        }
3004    }
3005
3006    fn emit_function_type(&mut self, function: &FunctionType) {
3007        self.emit_function_type_body_arrow(function);
3008    }
3009
3010    fn emit_function_type_body_arrow(&mut self, function: &FunctionType) {
3011        self.emit_type_parameters(&function.type_parameters);
3012        self.raw("(");
3013        self.emit_function_type_parameters(&function.parameters);
3014        self.raw(") => ");
3015        self.emit_type(&function.return_type);
3016    }
3017
3018    fn emit_function_type_body(&mut self, function: &FunctionType) {
3019        self.emit_type_parameters(&function.type_parameters);
3020        self.raw("(");
3021        self.emit_function_type_parameters(&function.parameters);
3022        self.raw("): ");
3023        self.emit_type(&function.return_type);
3024    }
3025
3026    fn emit_function_type_parameters(&mut self, parameters: &[FunctionTypeParameter]) {
3027        for (index, parameter) in parameters.iter().enumerate() {
3028            if index > 0 {
3029                self.raw(", ");
3030            }
3031            if parameter.rest {
3032                self.raw("...");
3033            }
3034            self.emit_ident(&parameter.name);
3035            if parameter.optional {
3036                self.raw("?");
3037            }
3038            self.raw(": ");
3039            self.emit_type(&parameter.type_annotation.data().type_node);
3040        }
3041    }
3042
3043    fn emit_mapped_type(&mut self, mapped: &MappedType) {
3044        self.raw("{ ");
3045        match mapped.readonly_modifier {
3046            MappedModifier::Preserve => {}
3047            MappedModifier::Add => self.raw("readonly "),
3048            MappedModifier::Remove => self.raw("-readonly "),
3049        }
3050        self.raw("[");
3051        self.emit_ident(&mapped.parameter.data().name);
3052        self.raw(" in ");
3053        if let Some(constraint) = &mapped.parameter.data().constraint {
3054            self.emit_type(constraint);
3055        }
3056        if let Some(name_type) = &mapped.name_type {
3057            self.raw(" as ");
3058            self.emit_type(name_type);
3059        }
3060        self.raw("]");
3061        match mapped.optional_modifier {
3062            MappedModifier::Preserve => {}
3063            MappedModifier::Add => self.raw("?"),
3064            MappedModifier::Remove => self.raw("-?"),
3065        }
3066        if let Some(value_type) = &mapped.value_type {
3067            self.raw(": ");
3068            self.emit_type(value_type);
3069        }
3070        self.raw("; }");
3071    }
3072
3073    fn emit_template_literal_type(&mut self, template: &TemplateLiteralType) {
3074        if template.elements.is_empty() {
3075            return;
3076        }
3077        self.emit_token(template.elements[0].data().token());
3078        for (index, ty) in template.types.iter().enumerate() {
3079            self.emit_type(ty);
3080            if let Some(element) = template.elements.get(index + 1) {
3081                self.emit_token(element.data().token());
3082            }
3083        }
3084    }
3085
3086    fn emit_type_predicate(&mut self, predicate: &TypePredicate) {
3087        if predicate.asserts {
3088            self.raw("asserts ");
3089        }
3090        self.emit_entity_name(&predicate.parameter_name);
3091        if let Some(ty) = &predicate.type_node {
3092            self.raw(" is ");
3093            self.emit_type(ty);
3094        }
3095    }
3096
3097    fn unwrap_type<'t>(&self, ty: &'t Ty) -> &'t Ty {
3098        match ty.data() {
3099            TypeNode::Parenthesized(inner) => self.unwrap_type(inner),
3100            _ => ty,
3101        }
3102    }
3103}
3104
3105// ---- free helpers ---------------------------------------------------------
3106
3107fn is_parameter_property(parameter: &Parameter) -> bool {
3108    parameter.modifiers.accessibility.is_some()
3109        || parameter.modifiers.is_readonly
3110        || parameter.modifiers.is_override
3111}
3112
3113/// Returns `Some` when `expression` is a numeric literal (optionally behind a
3114/// unary `+`/`-`), with the integer value when it is an exact integer.
3115fn numeric_literal_value(expression: &Expr) -> Option<Option<i64>> {
3116    match expression.data() {
3117        Expression::Literal(Literal::Number(_)) => Some(None),
3118        Expression::Unary(unary)
3119            if matches!(unary.operator, UnaryOperator::Plus | UnaryOperator::Minus)
3120                && matches!(
3121                    unary.argument.data(),
3122                    Expression::Literal(Literal::Number(_))
3123                ) =>
3124        {
3125            Some(None)
3126        }
3127        Expression::Parenthesized(inner) => numeric_literal_value(inner),
3128        _ => None,
3129    }
3130}
3131
3132const fn variable_kind_str(kind: VariableKind) -> &'static str {
3133    match kind {
3134        VariableKind::Var => "var",
3135        VariableKind::Let => "let",
3136        VariableKind::Const => "const",
3137        VariableKind::Using => "using",
3138        VariableKind::AwaitUsing => "await using",
3139    }
3140}
3141
3142const fn accessibility_str(accessibility: Accessibility) -> &'static str {
3143    match accessibility {
3144        Accessibility::Public => "public",
3145        Accessibility::Protected => "protected",
3146        Accessibility::Private => "private",
3147    }
3148}
3149
3150const fn binary_prec(operator: BinaryOperator) -> u8 {
3151    match operator {
3152        BinaryOperator::BitOr => P_BIT_OR,
3153        BinaryOperator::BitXor => P_BIT_XOR,
3154        BinaryOperator::BitAnd => P_BIT_AND,
3155        BinaryOperator::Equal
3156        | BinaryOperator::NotEqual
3157        | BinaryOperator::StrictEqual
3158        | BinaryOperator::StrictNotEqual => P_EQUALITY,
3159        BinaryOperator::LessThan
3160        | BinaryOperator::LessThanOrEqual
3161        | BinaryOperator::GreaterThan
3162        | BinaryOperator::GreaterThanOrEqual
3163        | BinaryOperator::In
3164        | BinaryOperator::Instanceof => P_RELATIONAL,
3165        BinaryOperator::LeftShift
3166        | BinaryOperator::SignedRightShift
3167        | BinaryOperator::UnsignedRightShift => P_SHIFT,
3168        BinaryOperator::Add | BinaryOperator::Subtract => P_ADDITIVE,
3169        BinaryOperator::Multiply | BinaryOperator::Divide | BinaryOperator::Remainder => {
3170            P_MULTIPLICATIVE
3171        }
3172        BinaryOperator::Exponentiate => P_EXPONENT,
3173    }
3174}
3175
3176const fn binary_str(operator: BinaryOperator) -> &'static str {
3177    match operator {
3178        BinaryOperator::Add => "+",
3179        BinaryOperator::Subtract => "-",
3180        BinaryOperator::Multiply => "*",
3181        BinaryOperator::Divide => "/",
3182        BinaryOperator::Remainder => "%",
3183        BinaryOperator::Exponentiate => "**",
3184        BinaryOperator::LeftShift => "<<",
3185        BinaryOperator::SignedRightShift => ">>",
3186        BinaryOperator::UnsignedRightShift => ">>>",
3187        BinaryOperator::LessThan => "<",
3188        BinaryOperator::LessThanOrEqual => "<=",
3189        BinaryOperator::GreaterThan => ">",
3190        BinaryOperator::GreaterThanOrEqual => ">=",
3191        BinaryOperator::In => "in",
3192        BinaryOperator::Instanceof => "instanceof",
3193        BinaryOperator::Equal => "==",
3194        BinaryOperator::NotEqual => "!=",
3195        BinaryOperator::StrictEqual => "===",
3196        BinaryOperator::StrictNotEqual => "!==",
3197        BinaryOperator::BitAnd => "&",
3198        BinaryOperator::BitXor => "^",
3199        BinaryOperator::BitOr => "|",
3200    }
3201}
3202
3203const fn logical_str(operator: LogicalOperator) -> &'static str {
3204    match operator {
3205        LogicalOperator::And => "&&",
3206        LogicalOperator::Or => "||",
3207        LogicalOperator::Nullish => "??",
3208    }
3209}
3210
3211const fn assignment_str(operator: AssignmentOperator) -> &'static str {
3212    match operator {
3213        AssignmentOperator::Assign => "=",
3214        AssignmentOperator::AddAssign => "+=",
3215        AssignmentOperator::SubtractAssign => "-=",
3216        AssignmentOperator::MultiplyAssign => "*=",
3217        AssignmentOperator::DivideAssign => "/=",
3218        AssignmentOperator::RemainderAssign => "%=",
3219        AssignmentOperator::ExponentiateAssign => "**=",
3220        AssignmentOperator::LeftShiftAssign => "<<=",
3221        AssignmentOperator::SignedRightShiftAssign => ">>=",
3222        AssignmentOperator::UnsignedRightShiftAssign => ">>>=",
3223        AssignmentOperator::BitAndAssign => "&=",
3224        AssignmentOperator::BitXorAssign => "^=",
3225        AssignmentOperator::BitOrAssign => "|=",
3226        AssignmentOperator::LogicalAndAssign => "&&=",
3227        AssignmentOperator::LogicalOrAssign => "||=",
3228        AssignmentOperator::NullishAssign => "??=",
3229    }
3230}
3231
3232const fn unary_operator_str(operator: UnaryOperator) -> &'static str {
3233    match operator {
3234        UnaryOperator::Plus => "+",
3235        UnaryOperator::Minus => "-",
3236        UnaryOperator::Not => "!",
3237        UnaryOperator::BitNot => "~",
3238        UnaryOperator::Typeof => "typeof ",
3239        UnaryOperator::Void => "void ",
3240        UnaryOperator::Delete => "delete ",
3241    }
3242}
3243
3244const fn keyword_type_str(keyword: KeywordType) -> &'static str {
3245    match keyword {
3246        KeywordType::Any => "any",
3247        KeywordType::Unknown => "unknown",
3248        KeywordType::Never => "never",
3249        KeywordType::Void => "void",
3250        KeywordType::Undefined => "undefined",
3251        KeywordType::Null => "null",
3252        KeywordType::Boolean => "boolean",
3253        KeywordType::Number => "number",
3254        KeywordType::BigInt => "bigint",
3255        KeywordType::String => "string",
3256        KeywordType::Symbol => "symbol",
3257        KeywordType::Object => "object",
3258        KeywordType::Intrinsic => "intrinsic",
3259    }
3260}
3261
3262const fn type_operator_str(operator: TypeOperator) -> &'static str {
3263    match operator {
3264        TypeOperator::Keyof => "keyof",
3265        TypeOperator::Unique => "unique",
3266        TypeOperator::Readonly => "readonly",
3267    }
3268}
3269
3270fn is_low_precedence_type(ty: &Ty) -> bool {
3271    matches!(
3272        ty.data(),
3273        TypeNode::Function(_)
3274            | TypeNode::Constructor(_)
3275            | TypeNode::Conditional(_)
3276            | TypeNode::Infer(_)
3277    )
3278}
3279
3280#[cfg(test)]
3281mod tests {
3282    use super::*;
3283    use crate::source::{ScriptKind, Utf16Pos};
3284    use std::sync::Arc;
3285
3286    /// Builds an AST with token ranges that point into a real source string, so
3287    /// the emitter resolves identifier and literal lexemes exactly as it would
3288    /// for a parser product.
3289    struct Builder {
3290        text: String,
3291        len: usize,
3292    }
3293
3294    impl Builder {
3295        fn new() -> Self {
3296            Self {
3297                text: String::new(),
3298                len: 0,
3299            }
3300        }
3301
3302        fn range(start: usize, end: usize) -> TextRange {
3303            TextRange::new(Utf16Pos::new(start), Utf16Pos::new(end)).expect("ordered range")
3304        }
3305
3306        fn token(&mut self, kind: TokenKind, lexeme: &str) -> Token {
3307            let start = self.len;
3308            self.text.push_str(lexeme);
3309            self.len += lexeme.encode_utf16().count();
3310            Token::new(kind, Self::range(start, self.len))
3311        }
3312
3313        fn ident(&mut self, name: &str) -> IdentifierNode {
3314            let token = self.token(TokenKind::Identifier, name);
3315            Node::new(NodeId::new(0), token.range(), Identifier::new(token))
3316        }
3317
3318        fn ident_expr(&mut self, name: &str) -> Expr {
3319            let ident = self.ident(name);
3320            let range = ident.range();
3321            Node::new(NodeId::new(0), range, Expression::Identifier(ident))
3322        }
3323
3324        fn number(&mut self, literal: &str) -> Expr {
3325            let token = self.token(TokenKind::NumericLiteral, literal);
3326            let node = Node::new(NodeId::new(0), token.range(), NumericLiteral::new(token));
3327            let range = node.range();
3328            Node::new(
3329                NodeId::new(0),
3330                range,
3331                Expression::Literal(Literal::Number(node)),
3332            )
3333        }
3334
3335        fn string(&mut self, literal: &str) -> StringLiteralNode {
3336            let token = self.token(TokenKind::StringLiteral, literal);
3337            Node::new(NodeId::new(0), token.range(), StringLiteral::new(token))
3338        }
3339
3340        fn finish(self, statements: Vec<Stmt>) -> SourceFile {
3341            let source = Arc::new(SourceText::new(self.text));
3342            let len = source.len_utf16();
3343            let full = TextRange::new(Utf16Pos::ZERO, len).expect("range");
3344            let eof = Token::new(
3345                TokenKind::EndOfFile,
3346                TextRange::new(len, len).expect("range"),
3347            );
3348            SourceFile::new(
3349                NodeId::new(0),
3350                SourceId::new(0),
3351                ScriptKind::TypeScript,
3352                full,
3353                source,
3354                Vec::new(),
3355                statements,
3356                eof,
3357                Vec::new(),
3358            )
3359        }
3360    }
3361
3362    fn dummy() -> TextRange {
3363        TextRange::new(Utf16Pos::ZERO, Utf16Pos::ZERO).expect("range")
3364    }
3365
3366    fn expr(data: Expression) -> Expr {
3367        Node::new(NodeId::new(0), dummy(), data)
3368    }
3369
3370    fn stmt(data: Statement) -> Stmt {
3371        Node::new(NodeId::new(0), dummy(), data)
3372    }
3373
3374    fn expr_stmt(expression: Expr) -> Stmt {
3375        stmt(Statement::Expression(ExpressionStatement {
3376            expression: Box::new(expression),
3377        }))
3378    }
3379
3380    fn binary(operator: BinaryOperator, left: Expr, right: Expr) -> Expr {
3381        expr(Expression::Binary(BinaryExpression {
3382            operator,
3383            left: Box::new(left),
3384            right: Box::new(right),
3385        }))
3386    }
3387
3388    fn emit_js(file: &SourceFile) -> EmitOutput {
3389        emit(file, EmitOptions::javascript())
3390    }
3391
3392    #[test]
3393    fn multiplication_binds_tighter_than_addition() {
3394        let mut b = Builder::new();
3395        let a = b.ident_expr("a");
3396        let bb = b.ident_expr("b");
3397        let c = b.ident_expr("c");
3398        // a + b * c -- no parentheses required.
3399        let tree = binary(
3400            BinaryOperator::Add,
3401            a,
3402            binary(BinaryOperator::Multiply, bb, c),
3403        );
3404        let file = b.finish(vec![expr_stmt(tree)]);
3405        assert_eq!(emit_js(&file).code, "a + b * c;\n");
3406    }
3407
3408    #[test]
3409    fn lower_precedence_left_operand_is_parenthesized() {
3410        let mut b = Builder::new();
3411        let a = b.ident_expr("a");
3412        let bb = b.ident_expr("b");
3413        let c = b.ident_expr("c");
3414        // (a + b) * c -- the additive left operand needs parentheses.
3415        let tree = binary(
3416            BinaryOperator::Multiply,
3417            binary(BinaryOperator::Add, a, bb),
3418            c,
3419        );
3420        let file = b.finish(vec![expr_stmt(tree)]);
3421        assert_eq!(emit_js(&file).code, "(a + b) * c;\n");
3422    }
3423
3424    #[test]
3425    fn exponent_is_right_associative_and_forces_left_grouping() {
3426        let mut b = Builder::new();
3427        let a = b.ident_expr("a");
3428        let bb = b.ident_expr("b");
3429        let c = b.ident_expr("c");
3430        // (a ** b) ** c must keep the left grouping; a ** b ** c must not add any.
3431        let left_grouped = binary(
3432            BinaryOperator::Exponentiate,
3433            binary(BinaryOperator::Exponentiate, a, bb),
3434            c,
3435        );
3436        let file = b.finish(vec![expr_stmt(left_grouped)]);
3437        assert_eq!(emit_js(&file).code, "(a ** b) ** c;\n");
3438    }
3439
3440    #[test]
3441    fn unary_left_of_exponent_is_parenthesized() {
3442        let mut b = Builder::new();
3443        let a = b.ident_expr("a");
3444        let bb = b.ident_expr("b");
3445        let neg = expr(Expression::Unary(UnaryExpression {
3446            operator: UnaryOperator::Minus,
3447            argument: Box::new(a),
3448        }));
3449        let tree = binary(BinaryOperator::Exponentiate, neg, bb);
3450        let file = b.finish(vec![expr_stmt(tree)]);
3451        assert_eq!(emit_js(&file).code, "(-a) ** b;\n");
3452    }
3453
3454    #[test]
3455    fn nullish_and_logical_or_require_parentheses_when_mixed() {
3456        let mut b = Builder::new();
3457        let a = b.ident_expr("a");
3458        let bb = b.ident_expr("b");
3459        let c = b.ident_expr("c");
3460        // (a || b) ?? c -- mixing ?? with || is a syntax error without parens.
3461        let or = expr(Expression::Logical(LogicalExpression {
3462            operator: LogicalOperator::Or,
3463            left: Box::new(a),
3464            right: Box::new(bb),
3465        }));
3466        let tree = expr(Expression::Logical(LogicalExpression {
3467            operator: LogicalOperator::Nullish,
3468            left: Box::new(or),
3469            right: Box::new(c),
3470        }));
3471        let file = b.finish(vec![expr_stmt(tree)]);
3472        assert_eq!(emit_js(&file).code, "(a || b) ?? c;\n");
3473    }
3474
3475    #[test]
3476    fn object_literal_expression_statement_is_parenthesized() {
3477        let b = Builder::new();
3478        let object = expr(Expression::Object(ObjectLiteral {
3479            members: Vec::new(),
3480        }));
3481        let file = b.finish(vec![expr_stmt(object)]);
3482        assert_eq!(emit_js(&file).code, "({});\n");
3483    }
3484
3485    #[test]
3486    fn arrow_object_body_is_parenthesized() {
3487        let b = Builder::new();
3488        let object = expr(Expression::Object(ObjectLiteral {
3489            members: Vec::new(),
3490        }));
3491        let arrow = expr(Expression::Arrow(ArrowFunction {
3492            is_async: false,
3493            type_parameters: None,
3494            parameters: Vec::new(),
3495            return_type: None,
3496            body: FunctionBody::Expression(Box::new(object)),
3497        }));
3498        let file = b.finish(vec![expr_stmt(arrow)]);
3499        assert_eq!(emit_js(&file).code, "() => ({});\n");
3500    }
3501
3502    #[test]
3503    fn type_annotation_is_erased_in_javascript() {
3504        let mut b = Builder::new();
3505        let name = b.ident("x");
3506        let init = b.number("1");
3507        let annotation = Node::new(
3508            NodeId::new(0),
3509            dummy(),
3510            TypeAnnotation {
3511                type_node: Box::new(Node::new(
3512                    NodeId::new(0),
3513                    dummy(),
3514                    TypeNode::Keyword(KeywordType::Number),
3515                )),
3516            },
3517        );
3518        let binding = Node::new(
3519            NodeId::new(0),
3520            name.range(),
3521            BindingPattern::Identifier(name),
3522        );
3523        let declarator = Node::new(
3524            NodeId::new(0),
3525            dummy(),
3526            VariableDeclarator {
3527                binding,
3528                definite: false,
3529                type_annotation: Some(annotation),
3530                initializer: Some(Box::new(init)),
3531            },
3532        );
3533        let declaration = stmt(Statement::Variable(VariableDeclaration {
3534            kind: VariableKind::Let,
3535            declarations: vec![declarator],
3536        }));
3537        let file = b.finish(vec![declaration]);
3538        assert_eq!(emit_js(&file).code, "let x = 1;\n");
3539    }
3540
3541    #[test]
3542    fn as_expression_is_erased_but_keeps_needed_parentheses() {
3543        let mut b = Builder::new();
3544        let a = b.ident_expr("a");
3545        let bb = b.ident_expr("b");
3546        let c = b.ident_expr("c");
3547        // (a + b as T) * c erases to (a + b) * c.
3548        let as_expr = expr(Expression::As(AsExpression {
3549            expression: Box::new(binary(BinaryOperator::Add, a, bb)),
3550            type_node: Some(Box::new(Node::new(
3551                NodeId::new(0),
3552                dummy(),
3553                TypeNode::Keyword(KeywordType::Any),
3554            ))),
3555        }));
3556        let tree = binary(BinaryOperator::Multiply, as_expr, c);
3557        let file = b.finish(vec![expr_stmt(tree)]);
3558        assert_eq!(emit_js(&file).code, "(a + b) * c;\n");
3559    }
3560
3561    #[test]
3562    fn newline_policy_uses_configured_terminator() {
3563        let mut b = Builder::new();
3564        let first = expr_stmt(b.ident_expr("a"));
3565        let second = expr_stmt(b.ident_expr("b"));
3566        let file = b.finish(vec![first, second]);
3567        let output = emit(&file, EmitOptions::javascript().with_newline(Newline::CrLf));
3568        assert_eq!(output.code, "a;\r\nb;\r\n");
3569    }
3570
3571    #[test]
3572    fn missing_expression_reports_stable_diagnostic() {
3573        let b = Builder::new();
3574        let missing = expr(Expression::Missing(MissingNode::new(
3575            NodeKind::IdentifierExpression,
3576        )));
3577        let file = b.finish(vec![expr_stmt(missing)]);
3578        let output = emit_js(&file);
3579        assert_eq!(output.code, "void 0;\n");
3580        assert_eq!(output.diagnostics.len(), 1);
3581        assert_eq!(output.diagnostics[0].code(), codes::MISSING_EXPRESSION);
3582        assert!(output.has_errors());
3583    }
3584
3585    #[test]
3586    fn enum_lowers_to_runtime_object_with_reverse_mapping() {
3587        let mut b = Builder::new();
3588        let enum_name = b.ident("E");
3589        let member_a = Node::new(
3590            NodeId::new(0),
3591            dummy(),
3592            EnumMember {
3593                name: PropertyName::Identifier(b.ident("A")),
3594                initializer: None,
3595            },
3596        );
3597        let member_b = Node::new(
3598            NodeId::new(0),
3599            dummy(),
3600            EnumMember {
3601                name: PropertyName::Identifier(b.ident("B")),
3602                initializer: None,
3603            },
3604        );
3605        let declaration = stmt(Statement::Enum(EnumDeclaration {
3606            is_const: false,
3607            name: enum_name,
3608            members: vec![member_a, member_b],
3609        }));
3610        let file = b.finish(vec![declaration]);
3611        let expected = "var E;\n(function (E) {\n    E[E[\"A\"] = 0] = \"A\";\n    E[E[\"B\"] = 1] = \"B\";\n})(E || (E = {}));\n";
3612        assert_eq!(emit_js(&file).code, expected);
3613    }
3614
3615    #[test]
3616    fn enum_string_member_has_no_reverse_mapping() {
3617        let mut b = Builder::new();
3618        let enum_name = b.ident("E");
3619        let value = b.string("\"hi\"");
3620        let member = Node::new(
3621            NodeId::new(0),
3622            dummy(),
3623            EnumMember {
3624                name: PropertyName::Identifier(b.ident("A")),
3625                initializer: Some(Box::new(expr(Expression::Literal(Literal::String(value))))),
3626            },
3627        );
3628        let declaration = stmt(Statement::Enum(EnumDeclaration {
3629            is_const: false,
3630            name: enum_name,
3631            members: vec![member],
3632        }));
3633        let file = b.finish(vec![declaration]);
3634        let expected = "var E;\n(function (E) {\n    E[\"A\"] = \"hi\";\n})(E || (E = {}));\n";
3635        assert_eq!(emit_js(&file).code, expected);
3636    }
3637
3638    #[test]
3639    fn namespace_reports_unlowered_diagnostic_in_javascript() {
3640        let mut b = Builder::new();
3641        let name = b.ident("N");
3642        let body = Node::new(
3643            NodeId::new(0),
3644            dummy(),
3645            Block {
3646                statements: Vec::new(),
3647            },
3648        );
3649        let declaration = stmt(Statement::Namespace(NamespaceDeclaration { name, body }));
3650        let file = b.finish(vec![declaration]);
3651        let output = emit_js(&file);
3652        assert_eq!(output.code, "");
3653        assert_eq!(output.diagnostics.len(), 1);
3654        assert_eq!(output.diagnostics[0].code(), codes::NAMESPACE_UNLOWERED);
3655    }
3656
3657    #[test]
3658    fn parameter_property_is_lowered_to_constructor_assignment() {
3659        let mut b = Builder::new();
3660        let class_name = b.ident("C");
3661        let param_name = b.ident("x");
3662        let binding = Node::new(
3663            NodeId::new(0),
3664            param_name.range(),
3665            BindingPattern::Identifier(param_name),
3666        );
3667        let parameter = Node::new(
3668            NodeId::new(0),
3669            dummy(),
3670            Parameter {
3671                decorators: Vec::new(),
3672                modifiers: ParameterModifiers {
3673                    accessibility: Some(Accessibility::Private),
3674                    is_readonly: false,
3675                    is_override: false,
3676                },
3677                binding,
3678                optional: false,
3679                type_annotation: None,
3680                initializer: None,
3681            },
3682        );
3683        let constructor = Node::new(
3684            NodeId::new(0),
3685            dummy(),
3686            ClassMember::Constructor(ConstructorDeclaration {
3687                modifiers: DeclarationModifiers::default(),
3688                parameters: vec![parameter],
3689                body: Node::new(
3690                    NodeId::new(0),
3691                    dummy(),
3692                    Block {
3693                        statements: Vec::new(),
3694                    },
3695                ),
3696            }),
3697        );
3698        let class = stmt(Statement::Class(ClassDeclaration {
3699            decorators: Vec::new(),
3700            modifiers: DeclarationModifiers::default(),
3701            name: Some(class_name),
3702            type_parameters: None,
3703            extends: None,
3704            implements: Vec::new(),
3705            members: vec![constructor],
3706        }));
3707        let file = b.finish(vec![class]);
3708        let expected = "class C {\n    constructor(x) {\n        this.x = x;\n    }\n}\n";
3709        assert_eq!(emit_js(&file).code, expected);
3710    }
3711
3712    #[test]
3713    fn declaration_mode_prints_type_alias_and_erases_bodies() {
3714        let mut b = Builder::new();
3715        let alias_name = b.ident("Id");
3716        let alias = stmt(Statement::TypeAlias(TypeAliasDeclaration {
3717            name: alias_name,
3718            type_parameters: None,
3719            type_node: Box::new(Node::new(
3720                NodeId::new(0),
3721                dummy(),
3722                TypeNode::Keyword(KeywordType::Number),
3723            )),
3724        }));
3725        let file = b.finish(vec![alias]);
3726        let output = emit(&file, EmitOptions::declaration());
3727        assert_eq!(output.code, "type Id = number;\n");
3728    }
3729
3730    #[test]
3731    fn declaration_mode_emits_function_signature_without_body() {
3732        let mut b = Builder::new();
3733        let function_name = b.ident("f");
3734        let function = stmt(Statement::Function(FunctionDeclaration {
3735            function: FunctionLike {
3736                decorators: Vec::new(),
3737                name: Some(function_name),
3738                is_async: false,
3739                is_generator: false,
3740                type_parameters: None,
3741                parameters: Vec::new(),
3742                return_type: Some(Node::new(
3743                    NodeId::new(0),
3744                    dummy(),
3745                    TypeAnnotation {
3746                        type_node: Box::new(Node::new(
3747                            NodeId::new(0),
3748                            dummy(),
3749                            TypeNode::Keyword(KeywordType::Void),
3750                        )),
3751                    },
3752                )),
3753                body: None,
3754            },
3755        }));
3756        let file = b.finish(vec![function]);
3757        let output = emit(&file, EmitOptions::declaration());
3758        assert_eq!(output.code, "declare function f(): void;\n");
3759    }
3760
3761    #[test]
3762    fn union_type_parenthesizes_function_members() {
3763        let mut b = Builder::new();
3764        let alias_name = b.ident("U");
3765        let func_type = Node::new(
3766            NodeId::new(0),
3767            dummy(),
3768            TypeNode::Function(FunctionType {
3769                type_parameters: None,
3770                parameters: Vec::new(),
3771                return_type: Box::new(Node::new(
3772                    NodeId::new(0),
3773                    dummy(),
3774                    TypeNode::Keyword(KeywordType::Void),
3775                )),
3776            }),
3777        );
3778        let number = Node::new(
3779            NodeId::new(0),
3780            dummy(),
3781            TypeNode::Keyword(KeywordType::Number),
3782        );
3783        let union = Node::new(
3784            NodeId::new(0),
3785            dummy(),
3786            TypeNode::Union(vec![func_type, number]),
3787        );
3788        let alias = stmt(Statement::TypeAlias(TypeAliasDeclaration {
3789            name: alias_name,
3790            type_parameters: None,
3791            type_node: Box::new(union),
3792        }));
3793        let file = b.finish(vec![alias]);
3794        let output = emit(&file, EmitOptions::declaration());
3795        assert_eq!(output.code, "type U = (() => void) | number;\n");
3796    }
3797
3798    #[test]
3799    fn optional_call_and_member_chain_round_trips() {
3800        let mut b = Builder::new();
3801        let object = b.ident_expr("a");
3802        let member = expr(Expression::Member(MemberExpression {
3803            object: Box::new(object),
3804            property: MemberProperty::Named(b.ident("b")),
3805            optional: true,
3806        }));
3807        let call = expr(Expression::Call(CallExpression {
3808            callee: Box::new(member),
3809            optional: true,
3810            type_arguments: None,
3811            arguments: Vec::new(),
3812        }));
3813        let file = b.finish(vec![expr_stmt(call)]);
3814        assert_eq!(emit_js(&file).code, "a?.b?.();\n");
3815    }
3816
3817    #[test]
3818    fn conditional_test_lower_precedence_gets_parentheses() {
3819        let mut b = Builder::new();
3820        let bb = b.ident_expr("b");
3821        let c = b.ident_expr("c");
3822        let d = b.ident_expr("d");
3823        // (a = b) ? c : d -- assignment test must be parenthesized.
3824        let assign = expr(Expression::Assignment(AssignmentExpression {
3825            operator: AssignmentOperator::Assign,
3826            left: Node::new(
3827                NodeId::new(0),
3828                dummy(),
3829                AssignmentTarget::Identifier(b.ident("a2")),
3830            ),
3831            right: Box::new(bb),
3832        }));
3833        let conditional = expr(Expression::Conditional(ConditionalExpression {
3834            test: Box::new(assign),
3835            consequent: Box::new(c),
3836            alternate: Box::new(d),
3837        }));
3838        let file = b.finish(vec![expr_stmt(conditional)]);
3839        assert_eq!(emit_js(&file).code, "(a2 = b) ? c : d;\n");
3840    }
3841
3842    #[test]
3843    fn export_type_reexport_with_source_erased_in_js() {
3844        let mut b = Builder::new();
3845        let specifier = Node::new(
3846            NodeId::new(0),
3847            dummy(),
3848            ExportSpecifier {
3849                mode: ExportSpecifierMode::TypeOnly,
3850                local: ModuleExportName::Identifier(b.ident("A")),
3851                exported: ModuleExportName::Identifier(b.ident("A")),
3852            },
3853        );
3854        let export_stmt = stmt(Statement::Export(ExportDeclaration::Named(
3855            ExportNamedDeclaration::Specifiers {
3856                type_only: false,
3857                specifiers: vec![specifier],
3858                source: Some(b.string("\"./mod\"")),
3859                attributes: None,
3860            },
3861        )));
3862        let file = b.finish(vec![export_stmt]);
3863        assert_eq!(emit_js(&file).code, "");
3864    }
3865
3866    #[test]
3867    fn mixed_type_and_value_reexport_retains_value_exports() {
3868        let mut b = Builder::new();
3869        let type_spec = Node::new(
3870            NodeId::new(0),
3871            dummy(),
3872            ExportSpecifier {
3873                mode: ExportSpecifierMode::TypeOnly,
3874                local: ModuleExportName::Identifier(b.ident("A")),
3875                exported: ModuleExportName::Identifier(b.ident("A")),
3876            },
3877        );
3878        let val_spec = Node::new(
3879            NodeId::new(0),
3880            dummy(),
3881            ExportSpecifier {
3882                mode: ExportSpecifierMode::Value,
3883                local: ModuleExportName::Identifier(b.ident("B")),
3884                exported: ModuleExportName::Identifier(b.ident("B")),
3885            },
3886        );
3887        let export_stmt = stmt(Statement::Export(ExportDeclaration::Named(
3888            ExportNamedDeclaration::Specifiers {
3889                type_only: false,
3890                specifiers: vec![type_spec, val_spec],
3891                source: Some(b.string("\"./mod\"")),
3892                attributes: None,
3893            },
3894        )));
3895        let file = b.finish(vec![export_stmt]);
3896        assert_eq!(emit_js(&file).code, "export { B } from \"./mod\";\n");
3897    }
3898}