swc_ecma_lexer/common/parser/
typescript.rs

1use std::{fmt::Write, mem};
2
3use either::Either;
4use swc_atoms::{atom, Atom};
5use swc_common::{BytePos, Span, Spanned};
6use swc_ecma_ast::*;
7
8use super::{
9    class_and_fn::{parse_class_decl, parse_fn_block_or_expr_body, parse_fn_decl},
10    eof_error,
11    expr::{is_start_of_left_hand_side_expr, parse_new_expr},
12    ident::parse_maybe_private_name,
13    is_simple_param_list::IsSimpleParameterList,
14    make_decl_declare,
15    stmt::parse_var_stmt,
16    PResult, Parser,
17};
18use crate::{
19    common::{
20        context::Context,
21        lexer::token::TokenFactory,
22        parser::{
23            buffer::Buffer,
24            expr::{parse_assignment_expr, parse_lit, parse_str_lit, parse_subscripts},
25            ident::{parse_ident, parse_ident_name},
26            module_item::parse_module_item_block_body,
27            object::parse_object_expr,
28            pat::{parse_binding_pat_or_ident, parse_formal_params},
29        },
30    },
31    error::SyntaxError,
32};
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub enum ParsingContext {
36    EnumMembers,
37    HeritageClauseElement,
38    TupleElementTypes,
39    TypeMembers,
40    TypeParametersOrArguments,
41}
42
43#[derive(Clone, Copy, PartialEq, Eq)]
44enum UnionOrIntersection {
45    Union,
46    Intersection,
47}
48
49#[derive(Clone, Copy, PartialEq, Eq)]
50enum SignatureParsingMode {
51    TSCallSignatureDeclaration,
52    TSConstructSignatureDeclaration,
53}
54
55/// `tsParseList`
56fn parse_ts_list<'a, P: Parser<'a>, T, F>(
57    p: &mut P,
58    kind: ParsingContext,
59    mut parse_element: F,
60) -> PResult<Vec<T>>
61where
62    F: FnMut(&mut P) -> PResult<T>,
63{
64    debug_assert!(p.input().syntax().typescript());
65    let mut buf = Vec::with_capacity(8);
66    while !is_ts_list_terminator(p, kind) {
67        // Skipping "parseListElement" from the TS source since that's just for error
68        // handling.
69        buf.push(parse_element(p)?);
70    }
71    Ok(buf)
72}
73
74/// `tsTryParse`
75pub(super) fn try_parse_ts_bool<'a, P: Parser<'a>, F>(p: &mut P, op: F) -> PResult<bool>
76where
77    F: FnOnce(&mut P) -> PResult<Option<bool>>,
78{
79    if !p.input().syntax().typescript() {
80        return Ok(false);
81    }
82
83    let prev_ignore_error = p.input().get_ctx().contains(Context::IgnoreError);
84    let checkpoint = p.checkpoint_save();
85    p.set_ctx(p.ctx() | Context::IgnoreError);
86    let res = op(p);
87    match res {
88        Ok(Some(res)) if res => {
89            let mut ctx = p.ctx();
90            ctx.set(Context::IgnoreError, prev_ignore_error);
91            p.input_mut().set_ctx(ctx);
92            Ok(res)
93        }
94        _ => {
95            p.checkpoint_load(checkpoint);
96            Ok(false)
97        }
98    }
99}
100
101/// `tsParseDelimitedList`
102fn parse_ts_delimited_list_inner<'a, P: Parser<'a>, T, F>(
103    p: &mut P,
104    kind: ParsingContext,
105    mut parse_element: F,
106) -> PResult<Vec<T>>
107where
108    F: FnMut(&mut P) -> PResult<(BytePos, T)>,
109{
110    debug_assert!(p.input().syntax().typescript());
111    let mut buf = Vec::new();
112    loop {
113        trace_cur!(p, parse_ts_delimited_list_inner__element);
114
115        if is_ts_list_terminator(p, kind) {
116            break;
117        }
118
119        let (_, element) = parse_element(p)?;
120        buf.push(element);
121
122        if p.input_mut().eat(&P::Token::COMMA) {
123            continue;
124        }
125
126        if is_ts_list_terminator(p, kind) {
127            break;
128        }
129
130        if kind == ParsingContext::EnumMembers {
131            let expect = P::Token::COMMA;
132            let cur = p.input().cur();
133            let cur = cur.clone().to_string(p.input());
134            p.emit_err(
135                p.input().cur_span(),
136                SyntaxError::Expected(format!("{expect:?}"), cur),
137            );
138            continue;
139        }
140        // This will fail with an error about a missing comma
141        expect!(p, &P::Token::COMMA);
142    }
143
144    Ok(buf)
145}
146
147/// In no lexer context
148pub(crate) fn ts_in_no_context<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> PResult<T>
149where
150    F: FnOnce(&mut P) -> PResult<T>,
151{
152    debug_assert!(p.input().syntax().typescript());
153    trace_cur!(p, ts_in_no_context__before);
154    let saved = std::mem::take(p.input_mut().token_context_mut());
155    p.input_mut().token_context_mut().push(saved.0[0]);
156    debug_assert_eq!(p.input().token_context().len(), 1);
157    let res = op(p);
158    p.input_mut().set_token_context(saved);
159    trace_cur!(p, ts_in_no_context__after);
160    res
161}
162
163/// `tsIsListTerminator`
164fn is_ts_list_terminator<'a>(p: &mut impl Parser<'a>, kind: ParsingContext) -> bool {
165    debug_assert!(p.input().syntax().typescript());
166    let cur = p.input().cur();
167    match kind {
168        ParsingContext::EnumMembers | ParsingContext::TypeMembers => cur.is_rbrace(),
169        ParsingContext::HeritageClauseElement => {
170            cur.is_lbrace() || cur.is_implements() || cur.is_extends()
171        }
172        ParsingContext::TupleElementTypes => cur.is_rbracket(),
173        ParsingContext::TypeParametersOrArguments => cur.is_greater(),
174    }
175}
176
177/// `tsNextTokenCanFollowModifier`
178pub(super) fn ts_next_token_can_follow_modifier<'a>(p: &mut impl Parser<'a>) -> bool {
179    debug_assert!(p.input().syntax().typescript());
180    // Note: TypeScript's implementation is much more complicated because
181    // more things are considered modifiers there.
182    // This implementation only handles modifiers not handled by @babel/parser
183    // itself. And "static". TODO: Would be nice to avoid lookahead. Want a
184    // hasLineBreakUpNext() method...
185    p.bump();
186
187    let cur = p.input().cur();
188    !p.input().had_line_break_before_cur() && cur.is_lbracket()
189        || cur.is_lbrace()
190        || cur.is_star()
191        || cur.is_dotdotdot()
192        || cur.is_hash()
193        || cur.is_word()
194        || cur.is_str()
195        || cur.is_num()
196        || cur.is_bigint()
197}
198
199/// `tsTryParse`
200pub fn try_parse_ts<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> Option<T>
201where
202    F: FnOnce(&mut P) -> PResult<Option<T>>,
203{
204    if !p.input().syntax().typescript() {
205        return None;
206    }
207    debug_tracing!(p, "try_parse_ts");
208
209    trace_cur!(p, try_parse_ts);
210
211    let prev_ignore_error = p.input().get_ctx().contains(Context::IgnoreError);
212    let checkpoint = p.checkpoint_save();
213    p.set_ctx(p.ctx() | Context::IgnoreError);
214    let res = op(p);
215    match res {
216        Ok(Some(res)) => {
217            trace_cur!(p, try_parse_ts__success_value);
218            let mut ctx = p.ctx();
219            ctx.set(Context::IgnoreError, prev_ignore_error);
220            p.input_mut().set_ctx(ctx);
221            Some(res)
222        }
223        Ok(None) => {
224            trace_cur!(p, try_parse_ts__success_no_value);
225            p.checkpoint_load(checkpoint);
226            None
227        }
228        Err(..) => {
229            trace_cur!(p, try_parse_ts__fail);
230            p.checkpoint_load(checkpoint);
231            None
232        }
233    }
234}
235
236/// `tsParseTypeMemberSemicolon`
237fn parse_ts_type_member_semicolon<'a, P: Parser<'a>>(p: &mut P) -> PResult<()> {
238    debug_assert!(p.input().syntax().typescript());
239
240    if !p.input_mut().eat(&P::Token::COMMA) {
241        p.expect_general_semi()
242    } else {
243        Ok(())
244    }
245}
246
247/// `tsIsStartOfConstructSignature`
248fn is_ts_start_of_construct_signature<'a, P: Parser<'a>>(p: &mut P) -> bool {
249    debug_assert!(p.input().syntax().typescript());
250
251    p.bump();
252    let cur = p.input().cur();
253    cur.is_lparen() || cur.is_less()
254}
255
256/// `tsParseDelimitedList`
257fn parse_ts_delimited_list<'a, P: Parser<'a>, T, F>(
258    p: &mut P,
259    kind: ParsingContext,
260    mut parse_element: F,
261) -> PResult<Vec<T>>
262where
263    F: FnMut(&mut P) -> PResult<T>,
264{
265    parse_ts_delimited_list_inner(p, kind, |p| {
266        let start = p.input().cur_pos();
267        Ok((start, parse_element(p)?))
268    })
269}
270
271/// `tsParseUnionOrIntersectionType`
272fn parse_ts_union_or_intersection_type<'a, P: Parser<'a>, F>(
273    p: &mut P,
274    kind: UnionOrIntersection,
275    mut parse_constituent_type: F,
276    operator: &P::Token,
277) -> PResult<Box<TsType>>
278where
279    F: FnMut(&mut P) -> PResult<Box<TsType>>,
280{
281    trace_cur!(p, parse_ts_union_or_intersection_type);
282
283    debug_assert!(p.input().syntax().typescript());
284
285    let start = p.input().cur_pos(); // include the leading operator in the start
286    p.input_mut().eat(operator);
287    trace_cur!(p, parse_ts_union_or_intersection_type__first_type);
288
289    let ty = parse_constituent_type(p)?;
290    trace_cur!(p, parse_ts_union_or_intersection_type__after_first);
291
292    if p.input().is(operator) {
293        let mut types = vec![ty];
294
295        while p.input_mut().eat(operator) {
296            trace_cur!(p, parse_ts_union_or_intersection_type__constituent);
297
298            types.push(parse_constituent_type(p)?);
299        }
300
301        return Ok(Box::new(TsType::TsUnionOrIntersectionType(match kind {
302            UnionOrIntersection::Union => TsUnionOrIntersectionType::TsUnionType(TsUnionType {
303                span: p.span(start),
304                types,
305            }),
306            UnionOrIntersection::Intersection => {
307                TsUnionOrIntersectionType::TsIntersectionType(TsIntersectionType {
308                    span: p.span(start),
309                    types,
310                })
311            }
312        })));
313    }
314    Ok(ty)
315}
316
317pub fn eat_any_ts_modifier<'a>(p: &mut impl Parser<'a>) -> PResult<bool> {
318    if p.syntax().typescript()
319        && {
320            let cur = p.input().cur();
321            cur.is_public() || cur.is_protected() || cur.is_private() || cur.is_readonly()
322        }
323        && peek!(p).is_some_and(|t| t.is_word() || t.is_lbrace() || t.is_lbracket())
324    {
325        let _ = parse_ts_modifier(p, &["public", "protected", "private", "readonly"], false);
326        Ok(true)
327    } else {
328        Ok(false)
329    }
330}
331
332/// Parses a modifier matching one the given modifier names.
333///
334/// `tsParseModifier`
335pub fn parse_ts_modifier<'a, P: Parser<'a>>(
336    p: &mut P,
337    allowed_modifiers: &[&'static str],
338    stop_on_start_of_class_static_blocks: bool,
339) -> PResult<Option<&'static str>> {
340    debug_assert!(p.input().syntax().typescript());
341    let pos = {
342        let cur = p.input().cur();
343        let modifier = if cur.is_unknown_ident() {
344            cur.clone().take_unknown_ident_ref(p.input()).clone()
345        } else if cur.is_known_ident() {
346            cur.take_known_ident()
347        } else if cur.is_in() {
348            atom!("in")
349        } else if cur.is_const() {
350            atom!("const")
351        } else if cur.is_error() {
352            let err = p.input_mut().expect_error_token_and_bump();
353            return Err(err);
354        } else if cur.is_eof() {
355            return Err(eof_error(p));
356        } else {
357            return Ok(None);
358        };
359        // TODO: compare atom rather than string.
360        allowed_modifiers
361            .iter()
362            .position(|s| **s == *modifier.as_str())
363    };
364    if let Some(pos) = pos {
365        if stop_on_start_of_class_static_blocks
366            && p.input().is(&P::Token::STATIC)
367            && peek!(p).is_some_and(|peek| peek.is_lbrace())
368        {
369            return Ok(None);
370        }
371        if try_parse_ts_bool(p, |p| Ok(Some(ts_next_token_can_follow_modifier(p))))? {
372            return Ok(Some(allowed_modifiers[pos]));
373        }
374    }
375    Ok(None)
376}
377
378fn parse_ts_bracketed_list<'a, P: Parser<'a>, T, F>(
379    p: &mut P,
380    kind: ParsingContext,
381    parse_element: F,
382    bracket: bool,
383    skip_first_token: bool,
384) -> PResult<Vec<T>>
385where
386    F: FnMut(&mut P) -> PResult<T>,
387{
388    debug_assert!(p.input().syntax().typescript());
389    if !skip_first_token {
390        if bracket {
391            expect!(p, &P::Token::LBRACKET);
392        } else {
393            expect!(p, &P::Token::LESS);
394        }
395    }
396    let result = parse_ts_delimited_list(p, kind, parse_element)?;
397    if bracket {
398        expect!(p, &P::Token::RBRACKET);
399    } else {
400        expect!(p, &P::Token::GREATER);
401    }
402    Ok(result)
403}
404
405/// `tsParseThisTypeNode`
406pub fn parse_ts_this_type_node<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsThisType> {
407    debug_assert!(p.input().syntax().typescript());
408    expect!(p, &P::Token::THIS);
409    Ok(TsThisType {
410        span: p.input().prev_span(),
411    })
412}
413
414/// `tsParseEntityName`
415pub fn parse_ts_entity_name<'a, P: Parser<'a>>(
416    p: &mut P,
417    allow_reserved_words: bool,
418) -> PResult<TsEntityName> {
419    debug_assert!(p.input().syntax().typescript());
420    trace_cur!(p, parse_ts_entity_name);
421    let start = p.input().cur_pos();
422    let init = parse_ident_name(p)?;
423    if &*init.sym == "void" {
424        let dot_start = p.input().cur_pos();
425        let dot_span = p.span(dot_start);
426        p.emit_err(dot_span, SyntaxError::TS1005)
427    }
428    let mut entity = TsEntityName::Ident(init.into());
429    while p.input_mut().eat(&P::Token::DOT) {
430        let dot_start = p.input().cur_pos();
431        let cur = p.input().cur();
432        if !cur.is_hash() && !cur.is_word() {
433            p.emit_err(
434                Span::new_with_checked(dot_start, dot_start),
435                SyntaxError::TS1003,
436            );
437            return Ok(entity);
438        }
439        let left = entity;
440        let right = if allow_reserved_words {
441            parse_ident_name(p)?
442        } else {
443            parse_ident(p, false, false)?.into()
444        };
445        let span = p.span(start);
446        entity = TsEntityName::TsQualifiedName(Box::new(TsQualifiedName { span, left, right }));
447    }
448    Ok(entity)
449}
450
451pub fn ts_look_ahead<'a, P: Parser<'a>, T, F>(p: &mut P, op: F) -> T
452where
453    F: FnOnce(&mut P) -> T,
454{
455    debug_assert!(p.input().syntax().typescript());
456    let checkpoint = p.checkpoint_save();
457    p.set_ctx(p.ctx() | Context::IgnoreError);
458    let ret = op(p);
459    p.checkpoint_load(checkpoint);
460    ret
461}
462
463/// `tsParseTypeArguments`
464pub fn parse_ts_type_args<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsTypeParamInstantiation>> {
465    trace_cur!(p, parse_ts_type_args);
466    debug_assert!(p.input().syntax().typescript());
467
468    let start = p.input().cur_pos();
469    let params = p.in_type(|p| {
470        // Temporarily remove a JSX parsing context, which makes us scan different
471        // tokens.
472        p.ts_in_no_context(|p| {
473            if p.input().is(&P::Token::LSHIFT) {
474                p.input_mut().cut_lshift();
475            } else {
476                expect!(p, &P::Token::LESS);
477            }
478            parse_ts_delimited_list(p, ParsingContext::TypeParametersOrArguments, |p| {
479                trace_cur!(p, parse_ts_type_args__arg);
480
481                parse_ts_type(p)
482            })
483        })
484    })?;
485    // This reads the next token after the `>` too, so do this in the enclosing
486    // context. But be sure not to parse a regex in the jsx expression
487    // `<C<number> />`, so set exprAllowed = false
488    p.input_mut().set_expr_allowed(false);
489    p.expect_without_advance(&P::Token::GREATER)?;
490    let span = Span::new_with_checked(start, p.input().cur_span().hi);
491    Ok(Box::new(TsTypeParamInstantiation { span, params }))
492}
493
494/// `tsParseTypeReference`
495pub fn parse_ts_type_ref<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeRef> {
496    trace_cur!(p, parse_ts_type_ref);
497    debug_assert!(p.input().syntax().typescript());
498
499    let start = p.input().cur_pos();
500
501    let has_modifier = eat_any_ts_modifier(p)?;
502
503    let type_name = parse_ts_entity_name(p, /* allow_reserved_words */ true)?;
504    trace_cur!(p, parse_ts_type_ref__type_args);
505    let type_params = if !p.input().had_line_break_before_cur()
506        && (p.input().is(&P::Token::LESS) || p.input().is(&P::Token::LSHIFT))
507    {
508        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
509        p.assert_and_bump(&P::Token::GREATER);
510        Some(ret)
511    } else {
512        None
513    };
514
515    if has_modifier {
516        p.emit_err(p.span(start), SyntaxError::TS2369);
517    }
518
519    Ok(TsTypeRef {
520        span: p.span(start),
521        type_name,
522        type_params,
523    })
524}
525
526#[cfg_attr(
527    feature = "tracing-spans",
528    tracing::instrument(level = "debug", skip_all)
529)]
530pub fn parse_ts_type_ann<'a, P: Parser<'a>>(
531    p: &mut P,
532    eat_colon: bool,
533    start: BytePos,
534) -> PResult<Box<TsTypeAnn>> {
535    trace_cur!(p, parse_ts_type_ann);
536
537    debug_assert!(p.input().syntax().typescript());
538
539    p.in_type(|p| {
540        if eat_colon {
541            p.assert_and_bump(&P::Token::COLON);
542        }
543
544        trace_cur!(p, parse_ts_type_ann__after_colon);
545
546        let type_ann = parse_ts_type(p)?;
547
548        Ok(Box::new(TsTypeAnn {
549            span: p.span(start),
550            type_ann,
551        }))
552    })
553}
554
555/// `tsParseThisTypePredicate`
556pub fn parse_ts_this_type_predicate<'a, P: Parser<'a>>(
557    p: &mut P,
558    start: BytePos,
559    has_asserts_keyword: bool,
560    lhs: TsThisType,
561) -> PResult<TsTypePredicate> {
562    debug_assert!(p.input().syntax().typescript());
563
564    let param_name = TsThisTypeOrIdent::TsThisType(lhs);
565    let type_ann = if p.input_mut().eat(&P::Token::IS) {
566        let cur_pos = p.input().cur_pos();
567        Some(parse_ts_type_ann(
568            p, // eat_colon
569            false, cur_pos,
570        )?)
571    } else {
572        None
573    };
574
575    Ok(TsTypePredicate {
576        span: p.span(start),
577        asserts: has_asserts_keyword,
578        param_name,
579        type_ann,
580    })
581}
582
583/// `tsEatThenParseType`
584fn eat_then_parse_ts_type<'a, P: Parser<'a>>(
585    p: &mut P,
586    token_to_eat: &P::Token,
587) -> PResult<Option<Box<TsType>>> {
588    if !cfg!(feature = "typescript") {
589        return Ok(Default::default());
590    }
591
592    p.in_type(|p| {
593        if !p.input_mut().eat(token_to_eat) {
594            return Ok(None);
595        }
596
597        parse_ts_type(p).map(Some)
598    })
599}
600
601/// `tsExpectThenParseType`
602fn expect_then_parse_ts_type<'a, P: Parser<'a>>(
603    p: &mut P,
604    token: &P::Token,
605    token_str: &'static str,
606) -> PResult<Box<TsType>> {
607    debug_assert!(p.input().syntax().typescript());
608
609    p.in_type(|p| {
610        if !p.input_mut().eat(token) {
611            let got = format!("{:?}", p.input().cur());
612            syntax_error!(
613                p,
614                p.input().cur_span(),
615                SyntaxError::Unexpected {
616                    got,
617                    expected: token_str
618                }
619            );
620        }
621
622        parse_ts_type(p)
623    })
624}
625
626/// `tsParseMappedTypeParameter`
627fn parse_ts_mapped_type_param<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeParam> {
628    debug_assert!(p.input().syntax().typescript());
629
630    let start = p.input().cur_pos();
631    let name = parse_ident_name(p)?;
632    let constraint = Some(expect_then_parse_ts_type(p, &P::Token::IN, "in")?);
633
634    Ok(TsTypeParam {
635        span: p.span(start),
636        name: name.into(),
637        is_in: false,
638        is_out: false,
639        is_const: false,
640        constraint,
641        default: None,
642    })
643}
644
645/// `tsParseTypeParameter`
646fn parse_ts_type_param<'a, P: Parser<'a>>(
647    p: &mut P,
648    permit_in_out: bool,
649    permit_const: bool,
650) -> PResult<TsTypeParam> {
651    debug_assert!(p.input().syntax().typescript());
652
653    let mut is_in = false;
654    let mut is_out = false;
655    let mut is_const = false;
656
657    let start = p.input().cur_pos();
658
659    while let Some(modifer) = parse_ts_modifier(
660        p,
661        &[
662            "public",
663            "private",
664            "protected",
665            "readonly",
666            "abstract",
667            "const",
668            "override",
669            "in",
670            "out",
671        ],
672        false,
673    )? {
674        match modifer {
675            "const" => {
676                is_const = true;
677                if !permit_const {
678                    p.emit_err(p.input().prev_span(), SyntaxError::TS1277(atom!("const")));
679                }
680            }
681            "in" => {
682                if !permit_in_out {
683                    p.emit_err(p.input().prev_span(), SyntaxError::TS1274(atom!("in")));
684                } else if is_in {
685                    p.emit_err(p.input().prev_span(), SyntaxError::TS1030(atom!("in")));
686                } else if is_out {
687                    p.emit_err(
688                        p.input().prev_span(),
689                        SyntaxError::TS1029(atom!("in"), atom!("out")),
690                    );
691                }
692                is_in = true;
693            }
694            "out" => {
695                if !permit_in_out {
696                    p.emit_err(p.input().prev_span(), SyntaxError::TS1274(atom!("out")));
697                } else if is_out {
698                    p.emit_err(p.input().prev_span(), SyntaxError::TS1030(atom!("out")));
699                }
700                is_out = true;
701            }
702            other => p.emit_err(p.input().prev_span(), SyntaxError::TS1273(other.into())),
703        };
704    }
705
706    let name = p.in_type(parse_ident_name)?.into();
707    let constraint = eat_then_parse_ts_type(p, &P::Token::EXTENDS)?;
708    let default = eat_then_parse_ts_type(p, &P::Token::EQUAL)?;
709
710    Ok(TsTypeParam {
711        span: p.span(start),
712        name,
713        is_in,
714        is_out,
715        is_const,
716        constraint,
717        default,
718    })
719}
720
721/// `tsParseTypeParameter`
722pub fn parse_ts_type_params<'a, P: Parser<'a>>(
723    p: &mut P,
724    permit_in_out: bool,
725    permit_const: bool,
726) -> PResult<Box<TsTypeParamDecl>> {
727    p.in_type(|p| {
728        p.ts_in_no_context(|p| {
729            let start = p.input().cur_pos();
730            let cur = p.input().cur();
731            if !cur.is_less() && !cur.is_jsx_tag_start() {
732                unexpected!(p, "< (jsx tag start)")
733            }
734            p.bump();
735
736            let params = parse_ts_bracketed_list(
737                p,
738                ParsingContext::TypeParametersOrArguments,
739                |p| parse_ts_type_param(p, permit_in_out, permit_const), // bracket
740                false,
741                // skip_first_token
742                true,
743            )?;
744
745            Ok(Box::new(TsTypeParamDecl {
746                span: p.span(start),
747                params,
748            }))
749        })
750    })
751}
752
753/// `tsTryParseTypeParameters`
754pub fn try_parse_ts_type_params<'a, P: Parser<'a>>(
755    p: &mut P,
756    permit_in_out: bool,
757    permit_const: bool,
758) -> PResult<Option<Box<TsTypeParamDecl>>> {
759    if !cfg!(feature = "typescript") {
760        return Ok(None);
761    }
762
763    if p.input().cur().is_less() {
764        return parse_ts_type_params(p, permit_in_out, permit_const).map(Some);
765    }
766
767    Ok(None)
768}
769
770/// `tsParseTypeOrTypePredicateAnnotation`
771pub fn parse_ts_type_or_type_predicate_ann<'a, P: Parser<'a>>(
772    p: &mut P,
773    return_token: &P::Token,
774) -> PResult<Box<TsTypeAnn>> {
775    debug_assert!(p.input().syntax().typescript());
776
777    p.in_type(|p| {
778        let return_token_start = p.input().cur_pos();
779        if !p.input_mut().eat(return_token) {
780            let cur = format!("{:?}", p.input().cur());
781            let span = p.input().cur_span();
782            syntax_error!(
783                p,
784                span,
785                SyntaxError::Expected(format!("{return_token:?}"), cur)
786            )
787        }
788
789        let type_pred_start = p.input().cur_pos();
790        let has_type_pred_asserts = p.input().cur().is_asserts() && {
791            let ctx = p.ctx();
792            peek!(p).is_some_and(|peek| {
793                if peek.is_word() {
794                    !peek.is_reserved(ctx)
795                } else {
796                    false
797                }
798            })
799        };
800
801        if has_type_pred_asserts {
802            p.assert_and_bump(&P::Token::ASSERTS);
803        }
804
805        let has_type_pred_is = p.is_ident_ref()
806            && peek!(p).is_some_and(|peek| peek.is_is())
807            && !p.input_mut().has_linebreak_between_cur_and_peeked();
808        let is_type_predicate = has_type_pred_asserts || has_type_pred_is;
809        if !is_type_predicate {
810            return parse_ts_type_ann(
811                p,
812                // eat_colon
813                false,
814                return_token_start,
815            );
816        }
817
818        let type_pred_var = parse_ident_name(p)?;
819        let type_ann = if has_type_pred_is {
820            p.assert_and_bump(&P::Token::IS);
821            let pos = p.input().cur_pos();
822            Some(parse_ts_type_ann(
823                p, // eat_colon
824                false, pos,
825            )?)
826        } else {
827            None
828        };
829
830        let node = Box::new(TsType::TsTypePredicate(TsTypePredicate {
831            span: p.span(type_pred_start),
832            asserts: has_type_pred_asserts,
833            param_name: TsThisTypeOrIdent::Ident(type_pred_var.into()),
834            type_ann,
835        }));
836
837        Ok(Box::new(TsTypeAnn {
838            span: p.span(return_token_start),
839            type_ann: node,
840        }))
841    })
842}
843
844fn is_start_of_expr<'a>(p: &mut impl Parser<'a>) -> bool {
845    is_start_of_left_hand_side_expr(p) || {
846        let cur = p.input().cur();
847        cur.is_plus()
848            || cur.is_minus()
849            || cur.is_tilde()
850            || cur.is_bang()
851            || cur.is_delete()
852            || cur.is_typeof()
853            || cur.is_void()
854            || cur.is_plus_plus()
855            || cur.is_minus_minus()
856            || cur.is_less()
857            || cur.is_await()
858            || cur.is_yield()
859            || (cur.is_hash() && peek!(p).is_some_and(|peek| peek.is_word()))
860    }
861}
862
863#[cfg_attr(
864    feature = "tracing-spans",
865    tracing::instrument(level = "debug", skip_all)
866)]
867pub(super) fn try_parse_ts_type_args<'a, P: Parser<'a>>(
868    p: &mut P,
869) -> Option<Box<TsTypeParamInstantiation>> {
870    trace_cur!(p, try_parse_ts_type_args);
871    debug_assert!(p.input().syntax().typescript());
872
873    try_parse_ts(p, |p| {
874        let type_args = parse_ts_type_args(p)?;
875        p.assert_and_bump(&P::Token::GREATER);
876        let cur = p.input().cur();
877        if cur.is_less() // invalid syntax
878            || cur.is_greater() || cur.is_equal() || cur.is_rshift() || cur.is_greater_eq() || cur.is_plus() || cur.is_minus() // becomes relational expression
879            || cur.is_lparen() || cur.is_no_substitution_template_literal() || cur.is_template_head() || cur.is_backquote()
880        // these should be type
881        // arguments in function
882        // call or template, not
883        // instantiation
884        // expression
885        {
886            Ok(None)
887        } else if p.input().had_line_break_before_cur()
888            || p.input().cur().is_bin_op()
889            || !is_start_of_expr(p)
890        {
891            Ok(Some(type_args))
892        } else {
893            Ok(None)
894        }
895    })
896}
897
898/// `tsTryParseType`
899fn try_parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<Box<TsType>>> {
900    if !cfg!(feature = "typescript") {
901        return Ok(None);
902    }
903
904    eat_then_parse_ts_type(p, &P::Token::COLON)
905}
906
907/// `tsTryParseTypeAnnotation`
908#[cfg_attr(
909    feature = "tracing-spans",
910    tracing::instrument(level = "debug", skip_all)
911)]
912pub fn try_parse_ts_type_ann<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<Box<TsTypeAnn>>> {
913    if !cfg!(feature = "typescript") {
914        return Ok(None);
915    }
916
917    if p.input().is(&P::Token::COLON) {
918        let pos = p.cur_pos();
919        return parse_ts_type_ann(p, /* eat_colon */ true, pos).map(Some);
920    }
921
922    Ok(None)
923}
924
925/// `tsNextThenParseType`
926pub(super) fn next_then_parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
927    debug_assert!(p.input().syntax().typescript());
928
929    let result = p.in_type(|p| {
930        p.bump();
931        parse_ts_type(p)
932    });
933
934    if !p.ctx().contains(Context::InType) && {
935        let cur = p.input().cur();
936        cur.is_less() || cur.is_greater()
937    } {
938        p.input_mut().merge_lt_gt();
939    }
940
941    result
942}
943
944/// `tsParseEnumMember`
945fn parse_ts_enum_member<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsEnumMember> {
946    debug_assert!(p.input().syntax().typescript());
947
948    let start = p.cur_pos();
949    // TypeScript allows computed property names with literal expressions in enums.
950    // Non-literal computed properties (like ["a" + "b"]) are rejected.
951    // We normalize literal computed properties (["\t"] → "\t") to keep AST simple.
952    // See https://github.com/swc-project/swc/issues/11160
953    let cur = p.input().cur();
954    let id = if cur.is_str() {
955        TsEnumMemberId::Str(parse_str_lit(p))
956    } else if cur.is_num() {
957        let (value, raw) = p.input_mut().expect_number_token_and_bump();
958        let mut new_raw = String::new();
959
960        new_raw.push('"');
961        new_raw.push_str(raw.as_str());
962        new_raw.push('"');
963
964        let span = p.span(start);
965
966        // Recover from error
967        p.emit_err(span, SyntaxError::TS2452);
968
969        TsEnumMemberId::Str(Str {
970            span,
971            value: value.to_string().into(),
972            raw: Some(new_raw.into()),
973        })
974    } else if cur.is_lbracket() {
975        p.assert_and_bump(&P::Token::LBRACKET);
976        let expr = p.parse_expr()?;
977        p.assert_and_bump(&P::Token::RBRACKET);
978        let bracket_span = p.span(start);
979
980        match *expr {
981            Expr::Lit(Lit::Str(str_lit)) => {
982                // String literal: ["\t"] → "\t"
983                TsEnumMemberId::Str(str_lit)
984            }
985            Expr::Tpl(mut tpl) if tpl.exprs.is_empty() => {
986                // Template literal without substitution: [`hello`] → "hello"
987
988                let tpl = mem::take(tpl.quasis.first_mut().unwrap());
989
990                let span = tpl.span;
991                let value = tpl.cooked.unwrap();
992
993                TsEnumMemberId::Str(Str {
994                    span,
995                    value,
996                    raw: None,
997                })
998            }
999            _ => {
1000                // Non-literal expression: report error
1001                p.emit_err(bracket_span, SyntaxError::TS1164);
1002                TsEnumMemberId::Ident(Ident::new_no_ctxt(atom!(""), bracket_span))
1003            }
1004        }
1005    } else if cur.is_error() {
1006        let err = p.input_mut().expect_error_token_and_bump();
1007        return Err(err);
1008    } else {
1009        parse_ident_name(p)
1010            .map(Ident::from)
1011            .map(TsEnumMemberId::from)?
1012    };
1013
1014    let init = if p.input_mut().eat(&P::Token::EQUAL) {
1015        Some(parse_assignment_expr(p)?)
1016    } else if p.input().cur().is_comma() || p.input().cur().is_rbrace() {
1017        None
1018    } else {
1019        let start = p.cur_pos();
1020        p.bump();
1021        p.input_mut().store(P::Token::COMMA);
1022        p.emit_err(Span::new_with_checked(start, start), SyntaxError::TS1005);
1023        None
1024    };
1025
1026    Ok(TsEnumMember {
1027        span: p.span(start),
1028        id,
1029        init,
1030    })
1031}
1032
1033/// `tsParseEnumDeclaration`
1034pub fn parse_ts_enum_decl<'a, P: Parser<'a>>(
1035    p: &mut P,
1036    start: BytePos,
1037    is_const: bool,
1038) -> PResult<Box<TsEnumDecl>> {
1039    debug_assert!(p.input().syntax().typescript());
1040
1041    let id = parse_ident_name(p)?;
1042    expect!(p, &P::Token::LBRACE);
1043    let members = parse_ts_delimited_list(p, ParsingContext::EnumMembers, parse_ts_enum_member)?;
1044    expect!(p, &P::Token::RBRACE);
1045
1046    Ok(Box::new(TsEnumDecl {
1047        span: p.span(start),
1048        declare: false,
1049        is_const,
1050        id: id.into(),
1051        members,
1052    }))
1053}
1054
1055/// `tsTryParseTypeOrTypePredicateAnnotation`
1056///
1057/// Used for parsing return types.
1058pub fn try_parse_ts_type_or_type_predicate_ann<'a, P: Parser<'a>>(
1059    p: &mut P,
1060) -> PResult<Option<Box<TsTypeAnn>>> {
1061    if !cfg!(feature = "typescript") {
1062        return Ok(None);
1063    }
1064
1065    if p.input().is(&P::Token::COLON) {
1066        parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON).map(Some)
1067    } else {
1068        Ok(None)
1069    }
1070}
1071
1072/// `tsParseTemplateLiteralType`
1073fn parse_ts_tpl_lit_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTplLitType> {
1074    debug_assert!(p.input().syntax().typescript());
1075
1076    let start = p.cur_pos();
1077
1078    p.assert_and_bump(&P::Token::BACKQUOTE);
1079
1080    let (types, quasis) = parse_ts_tpl_type_elements(p)?;
1081
1082    expect!(p, &P::Token::BACKQUOTE);
1083
1084    Ok(TsTplLitType {
1085        span: p.span(start),
1086        types,
1087        quasis,
1088    })
1089}
1090
1091fn parse_ts_tpl_type_elements<'a, P: Parser<'a>>(
1092    p: &mut P,
1093) -> PResult<(Vec<Box<TsType>>, Vec<TplElement>)> {
1094    if !cfg!(feature = "typescript") {
1095        return Ok(Default::default());
1096    }
1097
1098    trace_cur!(p, parse_tpl_elements);
1099
1100    let mut types = Vec::new();
1101
1102    let cur_elem = p.parse_tpl_element(false)?;
1103    let mut is_tail = cur_elem.tail;
1104    let mut quasis = vec![cur_elem];
1105
1106    while !is_tail {
1107        expect!(p, &P::Token::DOLLAR_LBRACE);
1108        types.push(parse_ts_type(p)?);
1109        expect!(p, &P::Token::RBRACE);
1110        let elem = p.parse_tpl_element(false)?;
1111        is_tail = elem.tail;
1112        quasis.push(elem);
1113    }
1114
1115    Ok((types, quasis))
1116}
1117
1118/// `tsParseLiteralTypeNode`
1119fn parse_ts_lit_type_node<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsLitType> {
1120    debug_assert!(p.input().syntax().typescript());
1121
1122    let start = p.cur_pos();
1123
1124    let lit = if p.input().is(&P::Token::BACKQUOTE) {
1125        let tpl = parse_ts_tpl_lit_type(p)?;
1126        TsLit::Tpl(tpl)
1127    } else {
1128        match parse_lit(p)? {
1129            Lit::BigInt(n) => TsLit::BigInt(n),
1130            Lit::Bool(n) => TsLit::Bool(n),
1131            Lit::Num(n) => TsLit::Number(n),
1132            Lit::Str(n) => TsLit::Str(n),
1133            _ => unreachable!(),
1134        }
1135    };
1136
1137    Ok(TsLitType {
1138        span: p.span(start),
1139        lit,
1140    })
1141}
1142
1143/// `tsParseHeritageClause`
1144pub fn parse_ts_heritage_clause<'a>(p: &mut impl Parser<'a>) -> PResult<Vec<TsExprWithTypeArgs>> {
1145    debug_assert!(p.input().syntax().typescript());
1146
1147    parse_ts_delimited_list(
1148        p,
1149        ParsingContext::HeritageClauseElement,
1150        parse_ts_heritage_clause_element,
1151    )
1152}
1153
1154fn parse_ts_heritage_clause_element<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsExprWithTypeArgs> {
1155    debug_assert!(p.input().syntax().typescript());
1156
1157    let start = p.cur_pos();
1158    // Note: TS uses parseLeftHandSideExpressionOrHigher,
1159    // then has grammar errors later if it's not an EntityName.
1160
1161    let ident = parse_ident_name(p)?.into();
1162    let expr = parse_subscripts(p, Callee::Expr(ident), true, true)?;
1163    if !matches!(
1164        &*expr,
1165        Expr::Ident(..) | Expr::Member(..) | Expr::TsInstantiation(..)
1166    ) {
1167        p.emit_err(p.span(start), SyntaxError::TS2499);
1168    }
1169
1170    match *expr {
1171        Expr::TsInstantiation(v) => Ok(TsExprWithTypeArgs {
1172            span: v.span,
1173            expr: v.expr,
1174            type_args: Some(v.type_args),
1175        }),
1176        _ => {
1177            let type_args = if p.input().is(&P::Token::LESS) {
1178                let ret = parse_ts_type_args(p)?;
1179                p.assert_and_bump(&P::Token::GREATER);
1180                Some(ret)
1181            } else {
1182                None
1183            };
1184
1185            Ok(TsExprWithTypeArgs {
1186                span: p.span(start),
1187                expr,
1188                type_args,
1189            })
1190        }
1191    }
1192}
1193
1194/// `tsSkipParameterStart`
1195fn skip_ts_parameter_start<'a, P: Parser<'a>>(p: &mut P) -> PResult<bool> {
1196    debug_assert!(p.input().syntax().typescript());
1197
1198    let _ = eat_any_ts_modifier(p)?;
1199
1200    let cur = p.input().cur();
1201
1202    if cur.is_void() {
1203        Ok(false)
1204    } else if cur.is_word() || cur.is_this() {
1205        p.bump();
1206        Ok(true)
1207    } else if (cur.is_lbrace() || cur.is_lbracket()) && parse_binding_pat_or_ident(p, false).is_ok()
1208    {
1209        Ok(true)
1210    } else {
1211        Ok(false)
1212    }
1213}
1214
1215/// `tsIsUnambiguouslyStartOfFunctionType`
1216fn is_ts_unambiguously_start_of_fn_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<bool> {
1217    debug_assert!(p.input().syntax().typescript());
1218
1219    p.assert_and_bump(&P::Token::LPAREN);
1220
1221    let cur = p.input().cur();
1222    if cur.is_rparen() || cur.is_dotdotdot() {
1223        // ( )
1224        // ( ...
1225        return Ok(true);
1226    }
1227    if skip_ts_parameter_start(p)? {
1228        let cur = p.input().cur();
1229        if cur.is_colon() || cur.is_comma() || cur.is_equal() || cur.is_question() {
1230            // ( xxx :
1231            // ( xxx ,
1232            // ( xxx ?
1233            // ( xxx =
1234            return Ok(true);
1235        }
1236        if p.input_mut().eat(&P::Token::RPAREN) && p.input().cur().is_arrow() {
1237            // ( xxx ) =>
1238            return Ok(true);
1239        }
1240    }
1241    Ok(false)
1242}
1243
1244fn is_ts_start_of_fn_type<'a, P: Parser<'a>>(p: &mut P) -> bool {
1245    debug_assert!(p.input().syntax().typescript());
1246
1247    if p.input().cur().is_less() {
1248        return true;
1249    }
1250
1251    p.input().cur().is_lparen()
1252        && ts_look_ahead(p, is_ts_unambiguously_start_of_fn_type).unwrap_or_default()
1253}
1254
1255/// `tsIsUnambiguouslyIndexSignature`
1256fn is_ts_unambiguously_index_signature<'a, P: Parser<'a>>(p: &mut P) -> bool {
1257    debug_assert!(p.input().syntax().typescript());
1258
1259    // Note: babel's comment is wrong
1260    p.assert_and_bump(&P::Token::LBRACKET); // Skip '['
1261
1262    // ',' is for error recovery
1263    p.eat_ident_ref() && {
1264        let cur = p.input().cur();
1265        cur.is_comma() || cur.is_colon()
1266    }
1267}
1268
1269/// `tsTryParseIndexSignature`
1270pub fn try_parse_ts_index_signature<'a, P: Parser<'a>>(
1271    p: &mut P,
1272    index_signature_start: BytePos,
1273    readonly: bool,
1274    is_static: bool,
1275) -> PResult<Option<TsIndexSignature>> {
1276    if !cfg!(feature = "typescript") {
1277        return Ok(Default::default());
1278    }
1279
1280    if !(p.input().cur().is_lbracket() && ts_look_ahead(p, is_ts_unambiguously_index_signature)) {
1281        return Ok(None);
1282    }
1283
1284    expect!(p, &P::Token::LBRACKET);
1285
1286    let ident_start = p.cur_pos();
1287    let mut id = parse_ident_name(p).map(BindingIdent::from)?;
1288    let type_ann_start = p.cur_pos();
1289
1290    if p.input_mut().eat(&P::Token::COMMA) {
1291        p.emit_err(id.span, SyntaxError::TS1096);
1292    } else {
1293        expect!(p, &P::Token::COLON);
1294    }
1295
1296    let type_ann = parse_ts_type_ann(p, /* eat_colon */ false, type_ann_start)?;
1297    id.span = p.span(ident_start);
1298    id.type_ann = Some(type_ann);
1299
1300    expect!(p, &P::Token::RBRACKET);
1301
1302    let params = vec![TsFnParam::Ident(id)];
1303
1304    let ty = try_parse_ts_type_ann(p)?;
1305    let type_ann = ty;
1306
1307    parse_ts_type_member_semicolon(p)?;
1308
1309    Ok(Some(TsIndexSignature {
1310        span: p.span(index_signature_start),
1311        readonly,
1312        is_static,
1313        params,
1314        type_ann,
1315    }))
1316}
1317
1318/// `tsIsExternalModuleReference`
1319fn is_ts_external_module_ref<'a, P: Parser<'a>>(p: &mut P) -> bool {
1320    debug_assert!(p.input().syntax().typescript());
1321    p.input().is(&P::Token::REQUIRE) && peek!(p).is_some_and(|t| t.is_lparen())
1322}
1323
1324/// `tsParseModuleReference`
1325fn parse_ts_module_ref<'a>(p: &mut impl Parser<'a>) -> PResult<TsModuleRef> {
1326    debug_assert!(p.input().syntax().typescript());
1327
1328    if is_ts_external_module_ref(p) {
1329        parse_ts_external_module_ref(p).map(From::from)
1330    } else {
1331        parse_ts_entity_name(p, /* allow_reserved_words */ false).map(From::from)
1332    }
1333}
1334
1335/// `tsParseExternalModuleReference`
1336fn parse_ts_external_module_ref<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsExternalModuleRef> {
1337    debug_assert!(p.input().syntax().typescript());
1338
1339    let start = p.cur_pos();
1340    expect!(p, &P::Token::REQUIRE);
1341    expect!(p, &P::Token::LPAREN);
1342    let cur = p.input().cur();
1343    if cur.is_error() {
1344        let err = p.input_mut().expect_error_token_and_bump();
1345        return Err(err);
1346    } else if !cur.is_str() {
1347        unexpected!(p, "a string literal")
1348    }
1349    let expr = parse_str_lit(p);
1350    expect!(p, &P::Token::RPAREN);
1351    Ok(TsExternalModuleRef {
1352        span: p.span(start),
1353        expr,
1354    })
1355}
1356
1357/// `tsParseImportEqualsDeclaration`
1358pub fn parse_ts_import_equals_decl<'a, P: Parser<'a>>(
1359    p: &mut P,
1360    start: BytePos,
1361    id: Ident,
1362    is_export: bool,
1363    is_type_only: bool,
1364) -> PResult<Box<TsImportEqualsDecl>> {
1365    debug_assert!(p.input().syntax().typescript());
1366
1367    expect!(p, &P::Token::EQUAL);
1368    let module_ref = parse_ts_module_ref(p)?;
1369    p.expect_general_semi()?;
1370
1371    Ok(Box::new(TsImportEqualsDecl {
1372        span: p.span(start),
1373        id,
1374        is_export,
1375        is_type_only,
1376        module_ref,
1377    }))
1378}
1379
1380/// `tsParseBindingListForSignature`
1381///
1382/// Eats ')` at the end but does not eat `(` at start.
1383fn parse_ts_binding_list_for_signature<'a, P: Parser<'a>>(p: &mut P) -> PResult<Vec<TsFnParam>> {
1384    if !cfg!(feature = "typescript") {
1385        return Ok(Default::default());
1386    }
1387
1388    debug_assert!(p.input().syntax().typescript());
1389
1390    let params = parse_formal_params(p)?;
1391    let mut list = Vec::with_capacity(4);
1392
1393    for param in params {
1394        let item = match param.pat {
1395            Pat::Ident(pat) => TsFnParam::Ident(pat),
1396            Pat::Array(pat) => TsFnParam::Array(pat),
1397            Pat::Object(pat) => TsFnParam::Object(pat),
1398            Pat::Rest(pat) => TsFnParam::Rest(pat),
1399            _ => unexpected!(
1400                p,
1401                "an identifier, [ for an array pattern, { for an object patter or ... for a rest \
1402                 pattern"
1403            ),
1404        };
1405        list.push(item);
1406    }
1407    expect!(p, &P::Token::RPAREN);
1408    Ok(list)
1409}
1410
1411/// `tsIsStartOfMappedType`
1412pub fn is_ts_start_of_mapped_type<'a, P: Parser<'a>>(p: &mut P) -> bool {
1413    debug_assert!(p.input().syntax().typescript());
1414
1415    p.bump();
1416    if p.input_mut().eat(&P::Token::PLUS) || p.input_mut().eat(&P::Token::MINUS) {
1417        return p.input().is(&P::Token::READONLY);
1418    }
1419
1420    p.input_mut().eat(&P::Token::READONLY);
1421
1422    if !p.input().is(&P::Token::LBRACKET) {
1423        return false;
1424    }
1425    p.bump();
1426    if !p.is_ident_ref() {
1427        return false;
1428    }
1429    p.bump();
1430
1431    p.input().is(&P::Token::IN)
1432}
1433
1434/// `tsParseSignatureMember`
1435fn parse_ts_signature_member<'a, P: Parser<'a>>(
1436    p: &mut P,
1437    kind: SignatureParsingMode,
1438) -> PResult<Either<TsCallSignatureDecl, TsConstructSignatureDecl>> {
1439    debug_assert!(p.input().syntax().typescript());
1440
1441    let start = p.cur_pos();
1442
1443    if kind == SignatureParsingMode::TSConstructSignatureDeclaration {
1444        expect!(p, &P::Token::NEW);
1445    }
1446
1447    // ----- inlined p.tsFillSignature(tt.colon, node);
1448    let type_params = try_parse_ts_type_params(p, false, true)?;
1449    expect!(p, &P::Token::LPAREN);
1450    let params = parse_ts_binding_list_for_signature(p)?;
1451    let type_ann = if p.input().is(&P::Token::COLON) {
1452        Some(parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?)
1453    } else {
1454        None
1455    };
1456    // -----
1457
1458    parse_ts_type_member_semicolon(p)?;
1459
1460    match kind {
1461        SignatureParsingMode::TSCallSignatureDeclaration => Ok(Either::Left(TsCallSignatureDecl {
1462            span: p.span(start),
1463            params,
1464            type_ann,
1465            type_params,
1466        })),
1467        SignatureParsingMode::TSConstructSignatureDeclaration => {
1468            Ok(Either::Right(TsConstructSignatureDecl {
1469                span: p.span(start),
1470                params,
1471                type_ann,
1472                type_params,
1473            }))
1474        }
1475    }
1476}
1477
1478fn try_parse_ts_tuple_element_name<'a, P: Parser<'a>>(p: &mut P) -> Option<Pat> {
1479    if !cfg!(feature = "typescript") {
1480        return Default::default();
1481    }
1482
1483    try_parse_ts(p, |p| {
1484        let start = p.cur_pos();
1485
1486        let rest = if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1487            Some(p.input().prev_span())
1488        } else {
1489            None
1490        };
1491
1492        let mut ident = parse_ident_name(p).map(Ident::from)?;
1493        if p.input_mut().eat(&P::Token::QUESTION) {
1494            ident.optional = true;
1495            ident.span = ident.span.with_hi(p.input().prev_span().hi);
1496        }
1497        expect!(p, &P::Token::COLON);
1498
1499        Ok(Some(if let Some(dot3_token) = rest {
1500            RestPat {
1501                span: p.span(start),
1502                dot3_token,
1503                arg: ident.into(),
1504                type_ann: None,
1505            }
1506            .into()
1507        } else {
1508            ident.into()
1509        }))
1510    })
1511}
1512
1513/// `tsParseTupleElementType`
1514fn parse_ts_tuple_element_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTupleElement> {
1515    debug_assert!(p.input().syntax().typescript());
1516
1517    // parses `...TsType[]`
1518    let start = p.cur_pos();
1519
1520    let label = try_parse_ts_tuple_element_name(p);
1521
1522    if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1523        let type_ann = parse_ts_type(p)?;
1524        return Ok(TsTupleElement {
1525            span: p.span(start),
1526            label,
1527            ty: Box::new(TsType::TsRestType(TsRestType {
1528                span: p.span(start),
1529                type_ann,
1530            })),
1531        });
1532    }
1533
1534    let ty = parse_ts_type(p)?;
1535    // parses `TsType?`
1536    if p.input_mut().eat(&P::Token::QUESTION) {
1537        let type_ann = ty;
1538        return Ok(TsTupleElement {
1539            span: p.span(start),
1540            label,
1541            ty: Box::new(TsType::TsOptionalType(TsOptionalType {
1542                span: p.span(start),
1543                type_ann,
1544            })),
1545        });
1546    }
1547
1548    Ok(TsTupleElement {
1549        span: p.span(start),
1550        label,
1551        ty,
1552    })
1553}
1554
1555/// `tsParseTupleType`
1556pub fn parse_ts_tuple_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTupleType> {
1557    debug_assert!(p.input().syntax().typescript());
1558
1559    let start = p.cur_pos();
1560    let elems = parse_ts_bracketed_list(
1561        p,
1562        ParsingContext::TupleElementTypes,
1563        parse_ts_tuple_element_type,
1564        /* bracket */ true,
1565        /* skipFirstToken */ false,
1566    )?;
1567
1568    // Validate the elementTypes to ensure:
1569    //   No mandatory elements may follow optional elements
1570    //   If there's a rest element, it must be at the end of the tuple
1571
1572    let mut seen_optional_element = false;
1573
1574    for elem in elems.iter() {
1575        match *elem.ty {
1576            TsType::TsRestType(..) => {}
1577            TsType::TsOptionalType(..) => {
1578                seen_optional_element = true;
1579            }
1580            _ if seen_optional_element => {
1581                syntax_error!(p, p.span(start), SyntaxError::TsRequiredAfterOptional)
1582            }
1583            _ => {}
1584        }
1585    }
1586
1587    Ok(TsTupleType {
1588        span: p.span(start),
1589        elem_types: elems,
1590    })
1591}
1592
1593/// `tsParseMappedType`
1594pub fn parse_ts_mapped_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsMappedType> {
1595    debug_assert!(p.input().syntax().typescript());
1596
1597    let start = p.cur_pos();
1598    expect!(p, &P::Token::LBRACE);
1599    let mut readonly = None;
1600    let cur = p.input().cur();
1601    if cur.is_plus() || cur.is_minus() {
1602        readonly = Some(if cur.is_plus() {
1603            TruePlusMinus::Plus
1604        } else {
1605            TruePlusMinus::Minus
1606        });
1607        p.bump();
1608        expect!(p, &P::Token::READONLY)
1609    } else if p.input_mut().eat(&P::Token::READONLY) {
1610        readonly = Some(TruePlusMinus::True);
1611    }
1612
1613    expect!(p, &P::Token::LBRACKET);
1614    let type_param = parse_ts_mapped_type_param(p)?;
1615    let name_type = if p.input_mut().eat(&P::Token::AS) {
1616        Some(parse_ts_type(p)?)
1617    } else {
1618        None
1619    };
1620    expect!(p, &P::Token::RBRACKET);
1621
1622    let mut optional = None;
1623    let cur = p.input().cur();
1624    if cur.is_plus() || cur.is_minus() {
1625        optional = Some(if cur.is_plus() {
1626            TruePlusMinus::Plus
1627        } else {
1628            TruePlusMinus::Minus
1629        });
1630        p.bump(); // +, -
1631        expect!(p, &P::Token::QUESTION);
1632    } else if p.input_mut().eat(&P::Token::QUESTION) {
1633        optional = Some(TruePlusMinus::True);
1634    }
1635
1636    let type_ann = try_parse_ts_type(p)?;
1637    p.expect_general_semi()?;
1638    expect!(p, &P::Token::RBRACE);
1639
1640    Ok(TsMappedType {
1641        span: p.span(start),
1642        readonly,
1643        optional,
1644        type_param,
1645        name_type,
1646        type_ann,
1647    })
1648}
1649
1650/// `tsParseParenthesizedType`
1651pub fn parse_ts_parenthesized_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsParenthesizedType> {
1652    debug_assert!(p.input().syntax().typescript());
1653    trace_cur!(p, parse_ts_parenthesized_type);
1654
1655    let start = p.cur_pos();
1656    expect!(p, &P::Token::LPAREN);
1657    let type_ann = parse_ts_type(p)?;
1658    expect!(p, &P::Token::RPAREN);
1659    Ok(TsParenthesizedType {
1660        span: p.span(start),
1661        type_ann,
1662    })
1663}
1664
1665/// `tsParseTypeAliasDeclaration`
1666pub fn parse_ts_type_alias_decl<'a, P: Parser<'a>>(
1667    p: &mut P,
1668    start: BytePos,
1669) -> PResult<Box<TsTypeAliasDecl>> {
1670    debug_assert!(p.input().syntax().typescript());
1671
1672    let id = parse_ident_name(p)?;
1673    let type_params = try_parse_ts_type_params(p, true, false)?;
1674    let type_ann = expect_then_parse_ts_type(p, &P::Token::EQUAL, "=")?;
1675    p.expect_general_semi()?;
1676    Ok(Box::new(TsTypeAliasDecl {
1677        declare: false,
1678        span: p.span(start),
1679        id: id.into(),
1680        type_params,
1681        type_ann,
1682    }))
1683}
1684
1685/// `tsParseFunctionOrConstructorType`
1686fn parse_ts_fn_or_constructor_type<'a, P: Parser<'a>>(
1687    p: &mut P,
1688    is_fn_type: bool,
1689) -> PResult<TsFnOrConstructorType> {
1690    trace_cur!(p, parse_ts_fn_or_constructor_type);
1691
1692    debug_assert!(p.input().syntax().typescript());
1693
1694    let start = p.cur_pos();
1695    let is_abstract = if !is_fn_type {
1696        p.input_mut().eat(&P::Token::ABSTRACT)
1697    } else {
1698        false
1699    };
1700    if !is_fn_type {
1701        expect!(p, &P::Token::NEW);
1702    }
1703
1704    // ----- inlined `p.tsFillSignature(tt.arrow, node)`
1705    let type_params = try_parse_ts_type_params(p, false, true)?;
1706    expect!(p, &P::Token::LPAREN);
1707    let params = parse_ts_binding_list_for_signature(p)?;
1708    let type_ann = parse_ts_type_or_type_predicate_ann(p, &P::Token::ARROW)?;
1709    // ----- end
1710
1711    Ok(if is_fn_type {
1712        TsFnOrConstructorType::TsFnType(TsFnType {
1713            span: p.span(start),
1714            type_params,
1715            params,
1716            type_ann,
1717        })
1718    } else {
1719        TsFnOrConstructorType::TsConstructorType(TsConstructorType {
1720            span: p.span(start),
1721            type_params,
1722            params,
1723            type_ann,
1724            is_abstract,
1725        })
1726    })
1727}
1728
1729/// `tsParseUnionTypeOrHigher`
1730fn parse_ts_union_type_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1731    trace_cur!(p, parse_ts_union_type_or_higher);
1732    debug_assert!(p.input().syntax().typescript());
1733
1734    parse_ts_union_or_intersection_type(
1735        p,
1736        UnionOrIntersection::Union,
1737        parse_ts_intersection_type_or_higher,
1738        &P::Token::BIT_OR,
1739    )
1740}
1741
1742/// `tsParseIntersectionTypeOrHigher`
1743fn parse_ts_intersection_type_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1744    trace_cur!(p, parse_ts_intersection_type_or_higher);
1745
1746    debug_assert!(p.input().syntax().typescript());
1747
1748    parse_ts_union_or_intersection_type(
1749        p,
1750        UnionOrIntersection::Intersection,
1751        parse_ts_type_operator_or_higher,
1752        &P::Token::BIT_AND,
1753    )
1754}
1755
1756/// `tsParseTypeOperatorOrHigher`
1757fn parse_ts_type_operator_or_higher<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1758    trace_cur!(p, parse_ts_type_operator_or_higher);
1759    debug_assert!(p.input().syntax().typescript());
1760
1761    let operator = if p.input().is(&P::Token::KEYOF) {
1762        Some(TsTypeOperatorOp::KeyOf)
1763    } else if p.input().is(&P::Token::UNIQUE) {
1764        Some(TsTypeOperatorOp::Unique)
1765    } else if p.input().is(&P::Token::READONLY) {
1766        Some(TsTypeOperatorOp::ReadOnly)
1767    } else {
1768        None
1769    };
1770
1771    match operator {
1772        Some(operator) => parse_ts_type_operator(p, operator)
1773            .map(TsType::from)
1774            .map(Box::new),
1775        None => {
1776            trace_cur!(p, parse_ts_type_operator_or_higher__not_operator);
1777
1778            if p.input().is(&P::Token::INFER) {
1779                parse_ts_infer_type(p).map(TsType::from).map(Box::new)
1780            } else {
1781                let readonly = parse_ts_modifier(p, &["readonly"], false)?.is_some();
1782                parse_ts_array_type_or_higher(p, readonly)
1783            }
1784        }
1785    }
1786}
1787
1788/// `tsParseTypeOperator`
1789fn parse_ts_type_operator<'a, P: Parser<'a>>(
1790    p: &mut P,
1791    op: TsTypeOperatorOp,
1792) -> PResult<TsTypeOperator> {
1793    debug_assert!(p.input().syntax().typescript());
1794
1795    let start = p.cur_pos();
1796    match op {
1797        TsTypeOperatorOp::Unique => expect!(p, &P::Token::UNIQUE),
1798        TsTypeOperatorOp::KeyOf => expect!(p, &P::Token::KEYOF),
1799        TsTypeOperatorOp::ReadOnly => expect!(p, &P::Token::READONLY),
1800        #[cfg(swc_ast_unknown)]
1801        _ => unreachable!(),
1802    }
1803
1804    let type_ann = parse_ts_type_operator_or_higher(p)?;
1805    Ok(TsTypeOperator {
1806        span: p.span(start),
1807        op,
1808        type_ann,
1809    })
1810}
1811
1812/// `tsParseInferType`
1813fn parse_ts_infer_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsInferType> {
1814    debug_assert!(p.input().syntax().typescript());
1815
1816    let start = p.cur_pos();
1817    expect!(p, &P::Token::INFER);
1818    let type_param_name = parse_ident_name(p)?;
1819    let constraint = try_parse_ts(p, |p| {
1820        expect!(p, &P::Token::EXTENDS);
1821        let constraint = parse_ts_non_conditional_type(p);
1822        if p.ctx().contains(Context::DisallowConditionalTypes) || !p.input().is(&P::Token::QUESTION)
1823        {
1824            constraint.map(Some)
1825        } else {
1826            Ok(None)
1827        }
1828    });
1829    let type_param = TsTypeParam {
1830        span: type_param_name.span(),
1831        name: type_param_name.into(),
1832        is_in: false,
1833        is_out: false,
1834        is_const: false,
1835        constraint,
1836        default: None,
1837    };
1838    Ok(TsInferType {
1839        span: p.span(start),
1840        type_param,
1841    })
1842}
1843
1844/// `tsParseNonConditionalType`
1845fn parse_ts_non_conditional_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1846    trace_cur!(p, parse_ts_non_conditional_type);
1847
1848    debug_assert!(p.input().syntax().typescript());
1849
1850    if is_ts_start_of_fn_type(p) {
1851        return parse_ts_fn_or_constructor_type(p, true)
1852            .map(TsType::from)
1853            .map(Box::new);
1854    }
1855    if (p.input().is(&P::Token::ABSTRACT) && peek!(p).is_some_and(|cur| cur.is_new()))
1856        || p.input().is(&P::Token::NEW)
1857    {
1858        // As in `new () => Date`
1859        return parse_ts_fn_or_constructor_type(p, false)
1860            .map(TsType::from)
1861            .map(Box::new);
1862    }
1863
1864    parse_ts_union_type_or_higher(p)
1865}
1866
1867/// `tsParseArrayTypeOrHigher`
1868fn parse_ts_array_type_or_higher<'a, P: Parser<'a>>(
1869    p: &mut P,
1870    readonly: bool,
1871) -> PResult<Box<TsType>> {
1872    trace_cur!(p, parse_ts_array_type_or_higher);
1873    debug_assert!(p.input().syntax().typescript());
1874
1875    let mut ty = parse_ts_non_array_type(p)?;
1876
1877    while !p.input().had_line_break_before_cur() && p.input_mut().eat(&P::Token::LBRACKET) {
1878        if p.input_mut().eat(&P::Token::RBRACKET) {
1879            ty = Box::new(TsType::TsArrayType(TsArrayType {
1880                span: p.span(ty.span_lo()),
1881                elem_type: ty,
1882            }));
1883        } else {
1884            let index_type = parse_ts_type(p)?;
1885            expect!(p, &P::Token::RBRACKET);
1886            ty = Box::new(TsType::TsIndexedAccessType(TsIndexedAccessType {
1887                span: p.span(ty.span_lo()),
1888                readonly,
1889                obj_type: ty,
1890                index_type,
1891            }))
1892        }
1893    }
1894
1895    Ok(ty)
1896}
1897
1898/// Be sure to be in a type context before calling p.
1899///
1900/// `tsParseType`
1901pub fn parse_ts_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
1902    trace_cur!(p, parse_ts_type);
1903
1904    debug_assert!(p.input().syntax().typescript());
1905
1906    // Need to set `state.inType` so that we don't parse JSX in a type context.
1907    debug_assert!(p.ctx().contains(Context::InType));
1908
1909    let start = p.cur_pos();
1910
1911    p.do_outside_of_context(Context::DisallowConditionalTypes, |p| {
1912        let ty = parse_ts_non_conditional_type(p)?;
1913        if p.input().had_line_break_before_cur() || !p.input_mut().eat(&P::Token::EXTENDS) {
1914            return Ok(ty);
1915        }
1916
1917        let check_type = ty;
1918        let extends_type = p.do_inside_of_context(
1919            Context::DisallowConditionalTypes,
1920            parse_ts_non_conditional_type,
1921        )?;
1922
1923        expect!(p, &P::Token::QUESTION);
1924
1925        let true_type = parse_ts_type(p)?;
1926
1927        expect!(p, &P::Token::COLON);
1928
1929        let false_type = parse_ts_type(p)?;
1930
1931        Ok(Box::new(TsType::TsConditionalType(TsConditionalType {
1932            span: p.span(start),
1933            check_type,
1934            extends_type,
1935            true_type,
1936            false_type,
1937        })))
1938    })
1939}
1940
1941/// `parsePropertyName` in babel.
1942///
1943/// Returns `(computed, key)`.
1944fn parse_ts_property_name<'a, P: Parser<'a>>(p: &mut P) -> PResult<(bool, Box<Expr>)> {
1945    let (computed, key) = if p.input_mut().eat(&P::Token::LBRACKET) {
1946        let key = parse_assignment_expr(p)?;
1947        expect!(p, &P::Token::RBRACKET);
1948        (true, key)
1949    } else {
1950        p.do_inside_of_context(Context::InPropertyName, |p| {
1951            // We check if it's valid for it to be a private name when we push it.
1952            let cur = p.input().cur();
1953
1954            let key = if cur.is_num() || cur.is_str() {
1955                parse_new_expr(p)
1956            } else if cur.is_error() {
1957                let err = p.input_mut().expect_error_token_and_bump();
1958                return Err(err);
1959            } else {
1960                parse_maybe_private_name(p).map(|e| match e {
1961                    Either::Left(e) => {
1962                        p.emit_err(e.span(), SyntaxError::PrivateNameInInterface);
1963
1964                        e.into()
1965                    }
1966                    Either::Right(e) => e.into(),
1967                })
1968            };
1969            key.map(|key| (false, key))
1970        })?
1971    };
1972
1973    Ok((computed, key))
1974}
1975
1976/// `tsParsePropertyOrMethodSignature`
1977fn parse_ts_property_or_method_signature<'a, P: Parser<'a>>(
1978    p: &mut P,
1979    start: BytePos,
1980    readonly: bool,
1981) -> PResult<Either<TsPropertySignature, TsMethodSignature>> {
1982    debug_assert!(p.input().syntax().typescript());
1983
1984    let (computed, key) = parse_ts_property_name(p)?;
1985
1986    let optional = p.input_mut().eat(&P::Token::QUESTION);
1987
1988    let cur = p.input().cur();
1989    if cur.is_lparen() || cur.is_less() {
1990        if readonly {
1991            syntax_error!(p, SyntaxError::ReadOnlyMethod)
1992        }
1993
1994        let type_params = try_parse_ts_type_params(p, false, true)?;
1995        expect!(p, &P::Token::LPAREN);
1996        let params = parse_ts_binding_list_for_signature(p)?;
1997        let type_ann = if p.input().is(&P::Token::COLON) {
1998            parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON).map(Some)?
1999        } else {
2000            None
2001        };
2002        // -----
2003
2004        parse_ts_type_member_semicolon(p)?;
2005        Ok(Either::Right(TsMethodSignature {
2006            span: p.span(start),
2007            computed,
2008            key,
2009            optional,
2010            type_params,
2011            params,
2012            type_ann,
2013        }))
2014    } else {
2015        let type_ann = try_parse_ts_type_ann(p)?;
2016
2017        parse_ts_type_member_semicolon(p)?;
2018        Ok(Either::Left(TsPropertySignature {
2019            span: p.span(start),
2020            computed,
2021            readonly,
2022            key,
2023            optional,
2024            type_ann,
2025        }))
2026    }
2027}
2028
2029/// `tsParseTypeMember`
2030fn parse_ts_type_member<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeElement> {
2031    debug_assert!(p.input().syntax().typescript());
2032
2033    fn into_type_elem(e: Either<TsCallSignatureDecl, TsConstructSignatureDecl>) -> TsTypeElement {
2034        match e {
2035            Either::Left(e) => e.into(),
2036            Either::Right(e) => e.into(),
2037        }
2038    }
2039    let cur = p.input().cur();
2040    if cur.is_lparen() || cur.is_less() {
2041        return parse_ts_signature_member(p, SignatureParsingMode::TSCallSignatureDeclaration)
2042            .map(into_type_elem);
2043    }
2044    if p.input().is(&P::Token::NEW) && ts_look_ahead(p, is_ts_start_of_construct_signature) {
2045        return parse_ts_signature_member(p, SignatureParsingMode::TSConstructSignatureDeclaration)
2046            .map(into_type_elem);
2047    }
2048    // Instead of fullStart, we create a node here.
2049    let start = p.cur_pos();
2050    let readonly = parse_ts_modifier(p, &["readonly"], false)?.is_some();
2051
2052    let idx = try_parse_ts_index_signature(p, start, readonly, false)?;
2053    if let Some(idx) = idx {
2054        return Ok(idx.into());
2055    }
2056
2057    if let Some(v) = try_parse_ts(p, |p| {
2058        let start = p.input().cur_pos();
2059
2060        if readonly {
2061            syntax_error!(p, SyntaxError::GetterSetterCannotBeReadonly)
2062        }
2063
2064        let is_get = if p.input_mut().eat(&P::Token::GET) {
2065            true
2066        } else {
2067            expect!(p, &P::Token::SET);
2068            false
2069        };
2070
2071        let (computed, key) = parse_ts_property_name(p)?;
2072
2073        if is_get {
2074            expect!(p, &P::Token::LPAREN);
2075            expect!(p, &P::Token::RPAREN);
2076            let type_ann = try_parse_ts_type_ann(p)?;
2077
2078            parse_ts_type_member_semicolon(p)?;
2079
2080            Ok(Some(TsTypeElement::TsGetterSignature(TsGetterSignature {
2081                span: p.span(start),
2082                key,
2083                computed,
2084                type_ann,
2085            })))
2086        } else {
2087            expect!(p, &P::Token::LPAREN);
2088            let params = parse_ts_binding_list_for_signature(p)?;
2089            if params.is_empty() {
2090                syntax_error!(p, SyntaxError::SetterParamRequired)
2091            }
2092            let param = params.into_iter().next().unwrap();
2093
2094            parse_ts_type_member_semicolon(p)?;
2095
2096            Ok(Some(TsTypeElement::TsSetterSignature(TsSetterSignature {
2097                span: p.span(start),
2098                key,
2099                computed,
2100                param,
2101            })))
2102        }
2103    }) {
2104        return Ok(v);
2105    }
2106
2107    parse_ts_property_or_method_signature(p, start, readonly).map(|e| match e {
2108        Either::Left(e) => e.into(),
2109        Either::Right(e) => e.into(),
2110    })
2111}
2112
2113/// `tsParseObjectTypeMembers`
2114fn parse_ts_object_type_members<'a, P: Parser<'a>>(p: &mut P) -> PResult<Vec<TsTypeElement>> {
2115    debug_assert!(p.input().syntax().typescript());
2116
2117    expect!(p, &P::Token::LBRACE);
2118    let members = parse_ts_list(p, ParsingContext::TypeMembers, |p| parse_ts_type_member(p))?;
2119    expect!(p, &P::Token::RBRACE);
2120    Ok(members)
2121}
2122
2123/// `tsParseTypeLiteral`
2124pub fn parse_ts_type_lit<'a>(p: &mut impl Parser<'a>) -> PResult<TsTypeLit> {
2125    debug_assert!(p.input().syntax().typescript());
2126
2127    let start = p.cur_pos();
2128    let members = parse_ts_object_type_members(p)?;
2129    Ok(TsTypeLit {
2130        span: p.span(start),
2131        members,
2132    })
2133}
2134
2135/// `tsParseInterfaceDeclaration`
2136pub fn parse_ts_interface_decl<'a, P: Parser<'a>>(
2137    p: &mut P,
2138    start: BytePos,
2139) -> PResult<Box<TsInterfaceDecl>> {
2140    debug_assert!(p.input().syntax().typescript());
2141
2142    let id = parse_ident_name(p)?;
2143    match &*id.sym {
2144        "string" | "null" | "number" | "object" | "any" | "unknown" | "boolean" | "bigint"
2145        | "symbol" | "void" | "never" | "intrinsic" => {
2146            p.emit_err(id.span, SyntaxError::TS2427);
2147        }
2148        _ => {}
2149    }
2150
2151    let type_params = try_parse_ts_type_params(p, true, false)?;
2152
2153    let extends = if p.input_mut().eat(&P::Token::EXTENDS) {
2154        parse_ts_heritage_clause(p)?
2155    } else {
2156        Vec::new()
2157    };
2158
2159    // Recover from
2160    //
2161    //     interface I extends A extends B {}
2162    if p.input().is(&P::Token::EXTENDS) {
2163        p.emit_err(p.input().cur_span(), SyntaxError::TS1172);
2164
2165        while !p.input().cur().is_eof() && !p.input().is(&P::Token::LBRACE) {
2166            p.bump();
2167        }
2168    }
2169
2170    let body_start = p.cur_pos();
2171    let body = p.in_type(parse_ts_object_type_members)?;
2172    let body = TsInterfaceBody {
2173        span: p.span(body_start),
2174        body,
2175    };
2176    Ok(Box::new(TsInterfaceDecl {
2177        span: p.span(start),
2178        declare: false,
2179        id: id.into(),
2180        type_params,
2181        extends,
2182        body,
2183    }))
2184}
2185
2186/// `tsParseTypeAssertion`
2187pub fn parse_ts_type_assertion<'a, P: Parser<'a>>(
2188    p: &mut P,
2189    start: BytePos,
2190) -> PResult<TsTypeAssertion> {
2191    debug_assert!(p.input().syntax().typescript());
2192
2193    if p.input().syntax().disallow_ambiguous_jsx_like() {
2194        p.emit_err(p.span(start), SyntaxError::ReservedTypeAssertion);
2195    }
2196
2197    // Not actually necessary to set state.inType because we never reach here if JSX
2198    // plugin is enabled, but need `tsInType` to satisfy the assertion in
2199    // `tsParseType`.
2200    let type_ann = p.in_type(parse_ts_type)?;
2201    expect!(p, &P::Token::GREATER);
2202    let expr = p.parse_unary_expr()?;
2203    Ok(TsTypeAssertion {
2204        span: p.span(start),
2205        type_ann,
2206        expr,
2207    })
2208}
2209
2210/// `tsParseImportType`
2211fn parse_ts_import_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsImportType> {
2212    let start = p.cur_pos();
2213    p.assert_and_bump(&P::Token::IMPORT);
2214
2215    expect!(p, &P::Token::LPAREN);
2216
2217    let cur = p.input().cur();
2218
2219    let arg = if cur.is_str() {
2220        parse_str_lit(p)
2221    } else if cur.is_error() {
2222        let err = p.input_mut().expect_error_token_and_bump();
2223        return Err(err);
2224    } else {
2225        let arg_span = p.input().cur_span();
2226        p.bump();
2227        p.emit_err(arg_span, SyntaxError::TS1141);
2228        Str {
2229            span: arg_span,
2230            value: atom!(""),
2231            raw: Some(atom!("\"\"")),
2232        }
2233    };
2234
2235    // the "assert" keyword is deprecated and this syntax is niche, so
2236    // don't support it
2237    let attributes = if p.input_mut().eat(&P::Token::COMMA)
2238        && p.input().syntax().import_attributes()
2239        && p.input().is(&P::Token::LBRACE)
2240    {
2241        Some(parse_ts_call_options(p)?)
2242    } else {
2243        None
2244    };
2245
2246    expect!(p, &P::Token::RPAREN);
2247
2248    let qualifier = if p.input_mut().eat(&P::Token::DOT) {
2249        parse_ts_entity_name(p, false).map(Some)?
2250    } else {
2251        None
2252    };
2253
2254    let type_args = if p.input().is(&P::Token::LESS) {
2255        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
2256        p.assert_and_bump(&P::Token::GREATER);
2257        Some(ret)
2258    } else {
2259        None
2260    };
2261
2262    Ok(TsImportType {
2263        span: p.span(start),
2264        arg,
2265        qualifier,
2266        type_args,
2267        attributes,
2268    })
2269}
2270
2271fn parse_ts_call_options<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsImportCallOptions> {
2272    debug_assert!(p.input().syntax().typescript());
2273    let start = p.cur_pos();
2274    p.assert_and_bump(&P::Token::LBRACE);
2275
2276    expect!(p, &P::Token::WITH);
2277    expect!(p, &P::Token::COLON);
2278
2279    let value = match parse_object_expr(p)? {
2280        Expr::Object(v) => v,
2281        _ => unreachable!(),
2282    };
2283    p.input_mut().eat(&P::Token::COMMA);
2284    expect!(p, &P::Token::RBRACE);
2285    Ok(TsImportCallOptions {
2286        span: p.span(start),
2287        with: Box::new(value),
2288    })
2289}
2290
2291/// `tsParseTypeQuery`
2292fn parse_ts_type_query<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsTypeQuery> {
2293    debug_assert!(p.input().syntax().typescript());
2294
2295    let start = p.cur_pos();
2296    expect!(p, &P::Token::TYPEOF);
2297    let expr_name = if p.input().is(&P::Token::IMPORT) {
2298        parse_ts_import_type(p).map(From::from)?
2299    } else {
2300        parse_ts_entity_name(
2301            p, // allow_reserved_word
2302            true,
2303        )
2304        .map(From::from)?
2305    };
2306
2307    let type_args = if !p.input().had_line_break_before_cur() && p.input().is(&P::Token::LESS) {
2308        let ret = p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
2309        p.assert_and_bump(&P::Token::GREATER);
2310        Some(ret)
2311    } else {
2312        None
2313    };
2314
2315    Ok(TsTypeQuery {
2316        span: p.span(start),
2317        expr_name,
2318        type_args,
2319    })
2320}
2321
2322/// `tsParseModuleBlock`
2323fn parse_ts_module_block<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsModuleBlock> {
2324    trace_cur!(p, parse_ts_module_block);
2325
2326    debug_assert!(p.input().syntax().typescript());
2327
2328    let start = p.cur_pos();
2329    expect!(p, &P::Token::LBRACE);
2330    let body = p.do_inside_of_context(Context::TsModuleBlock, |p| {
2331        p.do_outside_of_context(Context::TopLevel, |p| {
2332            parse_module_item_block_body(p, false, Some(&P::Token::RBRACE))
2333        })
2334    })?;
2335
2336    Ok(TsModuleBlock {
2337        span: p.span(start),
2338        body,
2339    })
2340}
2341
2342/// `tsParseModuleOrNamespaceDeclaration`
2343fn parse_ts_module_or_ns_decl<'a, P: Parser<'a>>(
2344    p: &mut P,
2345    start: BytePos,
2346    namespace: bool,
2347) -> PResult<Box<TsModuleDecl>> {
2348    debug_assert!(p.input().syntax().typescript());
2349
2350    let id = parse_ident_name(p)?;
2351    let body: TsNamespaceBody = if p.input_mut().eat(&P::Token::DOT) {
2352        let inner_start = p.cur_pos();
2353        let inner = parse_ts_module_or_ns_decl(p, inner_start, namespace)?;
2354        let inner = TsNamespaceDecl {
2355            span: inner.span,
2356            id: match inner.id {
2357                TsModuleName::Ident(i) => i,
2358                _ => unreachable!(),
2359            },
2360            body: Box::new(inner.body.unwrap()),
2361            declare: inner.declare,
2362            global: inner.global,
2363        };
2364        inner.into()
2365    } else {
2366        parse_ts_module_block(p).map(From::from)?
2367    };
2368
2369    Ok(Box::new(TsModuleDecl {
2370        span: p.span(start),
2371        declare: false,
2372        id: TsModuleName::Ident(id.into()),
2373        body: Some(body),
2374        global: false,
2375        namespace,
2376    }))
2377}
2378
2379/// `tsParseAmbientExternalModuleDeclaration`
2380fn parse_ts_ambient_external_module_decl<'a, P: Parser<'a>>(
2381    p: &mut P,
2382    start: BytePos,
2383) -> PResult<Box<TsModuleDecl>> {
2384    debug_assert!(p.input().syntax().typescript());
2385
2386    let (global, id) = if p.input().is(&P::Token::GLOBAL) {
2387        let id = parse_ident_name(p)?;
2388        (true, TsModuleName::Ident(id.into()))
2389    } else if p.input().cur().is_str() {
2390        let id = TsModuleName::Str(parse_str_lit(p));
2391        (false, id)
2392    } else {
2393        unexpected!(p, "global or a string literal");
2394    };
2395
2396    let body = if p.input().is(&P::Token::LBRACE) {
2397        Some(parse_ts_module_block(p).map(TsNamespaceBody::from)?)
2398    } else {
2399        p.expect_general_semi()?;
2400        None
2401    };
2402
2403    Ok(Box::new(TsModuleDecl {
2404        span: p.span(start),
2405        declare: false,
2406        id,
2407        global,
2408        body,
2409        namespace: false,
2410    }))
2411}
2412
2413/// `tsParseNonArrayType`
2414fn parse_ts_non_array_type<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<TsType>> {
2415    if !cfg!(feature = "typescript") {
2416        unreachable!()
2417    }
2418    trace_cur!(p, parse_ts_non_array_type);
2419    debug_assert!(p.input().syntax().typescript());
2420
2421    let start = p.cur_pos();
2422
2423    let cur = p.input().cur();
2424    if cur.is_known_ident()
2425        || cur.is_unknown_ident()
2426        || cur.is_void()
2427        || cur.is_yield()
2428        || cur.is_null()
2429        || cur.is_await()
2430        || cur.is_break()
2431    {
2432        if p.input().is(&P::Token::ASSERTS) && peek!(p).is_some_and(|peek| peek.is_this()) {
2433            p.bump();
2434            let this_keyword = parse_ts_this_type_node(p)?;
2435            return parse_ts_this_type_predicate(p, start, true, this_keyword)
2436                .map(TsType::from)
2437                .map(Box::new);
2438        }
2439        let kind = if p.input().is(&P::Token::VOID) {
2440            Some(TsKeywordTypeKind::TsVoidKeyword)
2441        } else if p.input().is(&P::Token::NULL) {
2442            Some(TsKeywordTypeKind::TsNullKeyword)
2443        } else if p.input().is(&P::Token::ANY) {
2444            Some(TsKeywordTypeKind::TsAnyKeyword)
2445        } else if p.input().is(&P::Token::BOOLEAN) {
2446            Some(TsKeywordTypeKind::TsBooleanKeyword)
2447        } else if p.input().is(&P::Token::BIGINT) {
2448            Some(TsKeywordTypeKind::TsBigIntKeyword)
2449        } else if p.input().is(&P::Token::NEVER) {
2450            Some(TsKeywordTypeKind::TsNeverKeyword)
2451        } else if p.input().is(&P::Token::NUMBER) {
2452            Some(TsKeywordTypeKind::TsNumberKeyword)
2453        } else if p.input().is(&P::Token::OBJECT) {
2454            Some(TsKeywordTypeKind::TsObjectKeyword)
2455        } else if p.input().is(&P::Token::STRING) {
2456            Some(TsKeywordTypeKind::TsStringKeyword)
2457        } else if p.input().is(&P::Token::SYMBOL) {
2458            Some(TsKeywordTypeKind::TsSymbolKeyword)
2459        } else if p.input().is(&P::Token::UNKNOWN) {
2460            Some(TsKeywordTypeKind::TsUnknownKeyword)
2461        } else if p.input().is(&P::Token::UNDEFINED) {
2462            Some(TsKeywordTypeKind::TsUndefinedKeyword)
2463        } else if p.input().is(&P::Token::INTRINSIC) {
2464            Some(TsKeywordTypeKind::TsIntrinsicKeyword)
2465        } else {
2466            None
2467        };
2468
2469        let peeked_is_dot = peek!(p).is_some_and(|cur| cur.is_dot());
2470
2471        match kind {
2472            Some(kind) if !peeked_is_dot => {
2473                p.bump();
2474                return Ok(Box::new(TsType::TsKeywordType(TsKeywordType {
2475                    span: p.span(start),
2476                    kind,
2477                })));
2478            }
2479            _ => {
2480                return parse_ts_type_ref(p).map(TsType::from).map(Box::new);
2481            }
2482        }
2483    } else if cur.is_bigint()
2484        || cur.is_str()
2485        || cur.is_num()
2486        || cur.is_true()
2487        || cur.is_false()
2488        || cur.is_backquote()
2489    {
2490        return parse_ts_lit_type_node(p).map(TsType::from).map(Box::new);
2491    } else if cur.is_no_substitution_template_literal() || cur.is_template_head() {
2492        return p.parse_tagged_tpl_ty().map(TsType::from).map(Box::new);
2493    } else if cur.is_minus() {
2494        let start = p.cur_pos();
2495
2496        p.bump();
2497
2498        let cur = p.input().cur();
2499        if !(cur.is_num() || cur.is_bigint()) {
2500            unexpected!(p, "numeric literal or bigint literal")
2501        }
2502
2503        let lit = parse_lit(p)?;
2504        let lit = match lit {
2505            Lit::Num(Number { span, value, raw }) => {
2506                let mut new_raw = String::from("-");
2507
2508                match raw {
2509                    Some(raw) => {
2510                        new_raw.push_str(&raw);
2511                    }
2512                    _ => {
2513                        write!(new_raw, "{value}").unwrap();
2514                    }
2515                };
2516
2517                TsLit::Number(Number {
2518                    span,
2519                    value: -value,
2520                    raw: Some(new_raw.into()),
2521                })
2522            }
2523            Lit::BigInt(BigInt { span, value, raw }) => {
2524                let mut new_raw = String::from("-");
2525
2526                match raw {
2527                    Some(raw) => {
2528                        new_raw.push_str(&raw);
2529                    }
2530                    _ => {
2531                        write!(new_raw, "{value}").unwrap();
2532                    }
2533                };
2534
2535                TsLit::BigInt(BigInt {
2536                    span,
2537                    value: Box::new(-*value),
2538                    raw: Some(new_raw.into()),
2539                })
2540            }
2541            _ => unreachable!(),
2542        };
2543
2544        return Ok(Box::new(TsType::TsLitType(TsLitType {
2545            span: p.span(start),
2546            lit,
2547        })));
2548    } else if cur.is_import() {
2549        return parse_ts_import_type(p).map(TsType::from).map(Box::new);
2550    } else if cur.is_this() {
2551        let start = p.cur_pos();
2552        let this_keyword = parse_ts_this_type_node(p)?;
2553        return if !p.input().had_line_break_before_cur() && p.input().is(&P::Token::IS) {
2554            parse_ts_this_type_predicate(p, start, false, this_keyword)
2555                .map(TsType::from)
2556                .map(Box::new)
2557        } else {
2558            Ok(Box::new(TsType::TsThisType(this_keyword)))
2559        };
2560    } else if cur.is_typeof() {
2561        return parse_ts_type_query(p).map(TsType::from).map(Box::new);
2562    } else if cur.is_lbrace() {
2563        return if ts_look_ahead(p, is_ts_start_of_mapped_type) {
2564            parse_ts_mapped_type(p).map(TsType::from).map(Box::new)
2565        } else {
2566            parse_ts_type_lit(p).map(TsType::from).map(Box::new)
2567        };
2568    } else if cur.is_lbracket() {
2569        return parse_ts_tuple_type(p).map(TsType::from).map(Box::new);
2570    } else if cur.is_lparen() {
2571        return parse_ts_parenthesized_type(p)
2572            .map(TsType::from)
2573            .map(Box::new);
2574    }
2575
2576    //   switch (p.state.type) {
2577    //   }
2578
2579    unexpected!(
2580        p,
2581        "an identifier, void, yield, null, await, break, a string literal, a numeric literal, \
2582         true, false, `, -, import, this, typeof, {, [, ("
2583    )
2584}
2585
2586/// `tsParseExpressionStatement`
2587pub fn parse_ts_expr_stmt<'a, P: Parser<'a>>(
2588    p: &mut P,
2589    decorators: Vec<Decorator>,
2590    expr: Ident,
2591) -> PResult<Option<Decl>> {
2592    if !cfg!(feature = "typescript") {
2593        return Ok(Default::default());
2594    }
2595
2596    let start = expr.span_lo();
2597
2598    match &*expr.sym {
2599        "declare" => {
2600            let decl = try_parse_ts_declare(p, start, decorators)?;
2601            if let Some(decl) = decl {
2602                Ok(Some(make_decl_declare(decl)))
2603            } else {
2604                Ok(None)
2605            }
2606        }
2607        "global" => {
2608            // `global { }` (with no `declare`) may appear inside an ambient module
2609            // declaration.
2610            // Would like to use tsParseAmbientExternalModuleDeclaration here, but already
2611            // ran past "global".
2612            if p.input().is(&P::Token::LBRACE) {
2613                let global = true;
2614                let id = TsModuleName::Ident(expr);
2615                let body = parse_ts_module_block(p)
2616                    .map(TsNamespaceBody::from)
2617                    .map(Some)?;
2618                Ok(Some(
2619                    TsModuleDecl {
2620                        span: p.span(start),
2621                        global,
2622                        declare: false,
2623                        namespace: false,
2624                        id,
2625                        body,
2626                    }
2627                    .into(),
2628                ))
2629            } else {
2630                Ok(None)
2631            }
2632        }
2633        _ => parse_ts_decl(p, start, decorators, expr.sym, /* next */ false),
2634    }
2635}
2636
2637/// `tsTryParseDeclare`
2638pub fn try_parse_ts_declare<'a, P: Parser<'a>>(
2639    p: &mut P,
2640    start: BytePos,
2641    decorators: Vec<Decorator>,
2642) -> PResult<Option<Decl>> {
2643    if !p.syntax().typescript() {
2644        return Ok(None);
2645    }
2646
2647    if p.ctx()
2648        .contains(Context::InDeclare | Context::TsModuleBlock)
2649    {
2650        let span_of_declare = p.span(start);
2651        p.emit_err(span_of_declare, SyntaxError::TS1038);
2652    }
2653
2654    let declare_start = start;
2655    p.do_inside_of_context(Context::InDeclare, |p| {
2656        if p.input().is(&P::Token::FUNCTION) {
2657            return parse_fn_decl(p, decorators)
2658                .map(|decl| match decl {
2659                    Decl::Fn(f) => FnDecl {
2660                        declare: true,
2661                        function: Box::new(Function {
2662                            span: Span {
2663                                lo: declare_start,
2664                                ..f.function.span
2665                            },
2666                            ..*f.function
2667                        }),
2668                        ..f
2669                    }
2670                    .into(),
2671                    _ => decl,
2672                })
2673                .map(Some);
2674        }
2675
2676        if p.input().is(&P::Token::CLASS) {
2677            return parse_class_decl(p, start, start, decorators, false)
2678                .map(|decl| match decl {
2679                    Decl::Class(c) => ClassDecl {
2680                        declare: true,
2681                        class: Box::new(Class {
2682                            span: Span {
2683                                lo: declare_start,
2684                                ..c.class.span
2685                            },
2686                            ..*c.class
2687                        }),
2688                        ..c
2689                    }
2690                    .into(),
2691                    _ => decl,
2692                })
2693                .map(Some);
2694        }
2695
2696        if p.input().is(&P::Token::CONST) && peek!(p).is_some_and(|peek| peek.is_enum()) {
2697            p.assert_and_bump(&P::Token::CONST);
2698            p.assert_and_bump(&P::Token::ENUM);
2699
2700            return parse_ts_enum_decl(p, start, /* is_const */ true)
2701                .map(|decl| TsEnumDecl {
2702                    declare: true,
2703                    span: Span {
2704                        lo: declare_start,
2705                        ..decl.span
2706                    },
2707                    ..*decl
2708                })
2709                .map(Box::new)
2710                .map(From::from)
2711                .map(Some);
2712        }
2713
2714        let cur = p.input().cur();
2715        if cur.is_const() || cur.is_var() || cur.is_let() {
2716            return parse_var_stmt(p, false)
2717                .map(|decl| VarDecl {
2718                    declare: true,
2719                    span: Span {
2720                        lo: declare_start,
2721                        ..decl.span
2722                    },
2723                    ..*decl
2724                })
2725                .map(Box::new)
2726                .map(From::from)
2727                .map(Some);
2728        }
2729
2730        if p.input().is(&P::Token::GLOBAL) {
2731            return parse_ts_ambient_external_module_decl(p, start)
2732                .map(Decl::from)
2733                .map(make_decl_declare)
2734                .map(Some);
2735        } else if p.input().cur().is_word() {
2736            let value = p
2737                .input_mut()
2738                .cur()
2739                .clone()
2740                .take_word(p.input_mut())
2741                .unwrap();
2742            return parse_ts_decl(p, start, decorators, value, /* next */ true)
2743                .map(|v| v.map(make_decl_declare));
2744        }
2745
2746        Ok(None)
2747    })
2748}
2749
2750/// `tsTryParseExportDeclaration`
2751///
2752/// Note: this won't be called unless the keyword is allowed in
2753/// `shouldParseExportDeclaration`.
2754pub fn try_parse_ts_export_decl<'a, P: Parser<'a>>(
2755    p: &mut P,
2756    decorators: Vec<Decorator>,
2757    value: Atom,
2758) -> Option<Decl> {
2759    if !cfg!(feature = "typescript") {
2760        return None;
2761    }
2762
2763    try_parse_ts(p, |p| {
2764        let start = p.cur_pos();
2765        let opt = parse_ts_decl(p, start, decorators, value, true)?;
2766        Ok(opt)
2767    })
2768}
2769
2770/// Common to tsTryParseDeclare, tsTryParseExportDeclaration, and
2771/// tsParseExpressionStatement.
2772///
2773/// `tsParseDeclaration`
2774fn parse_ts_decl<'a, P: Parser<'a>>(
2775    p: &mut P,
2776    start: BytePos,
2777    decorators: Vec<Decorator>,
2778    value: Atom,
2779    next: bool,
2780) -> PResult<Option<Decl>> {
2781    if !cfg!(feature = "typescript") {
2782        return Ok(Default::default());
2783    }
2784
2785    match &*value {
2786        "abstract" => {
2787            if next || (p.input().is(&P::Token::CLASS) && !p.input().had_line_break_before_cur()) {
2788                if next {
2789                    p.bump();
2790                }
2791                return Ok(Some(parse_class_decl(p, start, start, decorators, true)?));
2792            }
2793        }
2794
2795        "enum" => {
2796            if next || p.is_ident_ref() {
2797                if next {
2798                    p.bump();
2799                }
2800                return parse_ts_enum_decl(p, start, /* is_const */ false)
2801                    .map(From::from)
2802                    .map(Some);
2803            }
2804        }
2805
2806        "interface" => {
2807            if next || (p.is_ident_ref()) {
2808                if next {
2809                    p.bump();
2810                }
2811
2812                return parse_ts_interface_decl(p, start).map(From::from).map(Some);
2813            }
2814        }
2815
2816        "module" if !p.input().had_line_break_before_cur() => {
2817            if next {
2818                p.bump();
2819            }
2820
2821            let cur = p.input().cur();
2822            if cur.is_str() {
2823                return parse_ts_ambient_external_module_decl(p, start)
2824                    .map(From::from)
2825                    .map(Some);
2826            } else if cur.is_error() {
2827                let err = p.input_mut().expect_error_token_and_bump();
2828                return Err(err);
2829            } else if cur.is_eof() {
2830                return Err(eof_error(p));
2831            } else if next || p.is_ident_ref() {
2832                return parse_ts_module_or_ns_decl(p, start, false)
2833                    .map(From::from)
2834                    .map(Some);
2835            }
2836        }
2837
2838        "namespace" => {
2839            if next || p.is_ident_ref() {
2840                if next {
2841                    p.bump();
2842                }
2843                return parse_ts_module_or_ns_decl(p, start, true)
2844                    .map(From::from)
2845                    .map(Some);
2846            }
2847        }
2848
2849        "type" => {
2850            if next || (!p.input().had_line_break_before_cur() && p.is_ident_ref()) {
2851                if next {
2852                    p.bump();
2853                }
2854                return parse_ts_type_alias_decl(p, start).map(From::from).map(Some);
2855            }
2856        }
2857
2858        _ => {}
2859    }
2860
2861    Ok(None)
2862}
2863
2864/// `tsTryParseGenericAsyncArrowFunction`
2865pub fn try_parse_ts_generic_async_arrow_fn<'a, P: Parser<'a>>(
2866    p: &mut P,
2867    start: BytePos,
2868) -> PResult<Option<ArrowExpr>> {
2869    if !cfg!(feature = "typescript") {
2870        return Ok(Default::default());
2871    }
2872
2873    let cur = p.input().cur();
2874    let res = if cur.is_less() || cur.is_jsx_tag_start() {
2875        try_parse_ts(p, |p| {
2876            let type_params = parse_ts_type_params(p, false, false)?;
2877            // Don't use overloaded parseFunctionParams which would look for "<" again.
2878            expect!(p, &P::Token::LPAREN);
2879            let params: Vec<Pat> = parse_formal_params(p)?.into_iter().map(|p| p.pat).collect();
2880            expect!(p, &P::Token::RPAREN);
2881            let return_type = try_parse_ts_type_or_type_predicate_ann(p)?;
2882            expect!(p, &P::Token::ARROW);
2883
2884            Ok(Some((type_params, params, return_type)))
2885        })
2886    } else {
2887        None
2888    };
2889
2890    let (type_params, params, return_type) = match res {
2891        Some(v) => v,
2892        None => return Ok(None),
2893    };
2894
2895    p.do_inside_of_context(Context::InAsync, |p| {
2896        p.do_outside_of_context(Context::InGenerator, |p| {
2897            let is_generator = false;
2898            let is_async = true;
2899            let body = parse_fn_block_or_expr_body(
2900                p,
2901                true,
2902                false,
2903                true,
2904                params.is_simple_parameter_list(),
2905            )?;
2906            Ok(Some(ArrowExpr {
2907                span: p.span(start),
2908                body,
2909                is_async,
2910                is_generator,
2911                type_params: Some(type_params),
2912                params,
2913                return_type,
2914                ..Default::default()
2915            }))
2916        })
2917    })
2918}