1use super::decl::*;
4use super::expr::{assign_expr, identifier_name, lhs_expr, literal};
5use super::stmt::{block_items, semi, var_decl};
6use crate::{SyntaxKind::*, *};
7
8pub const BASE_TS_RECOVERY_SET: TokenSet = token_set![
9 T![void],
10 T![ident],
11 T![ident],
12 T![await],
13 T![null],
14 T![break],
15 T!['['],
16];
17
18#[rustfmt::skip]
19pub const DISALLOWED_TYPE_NAMES: &[&str] = &[
20 "string",
21 "null",
22 "number",
23 "object",
24 "any",
25 "unknown",
26 "boolean",
27 "bigint",
28 "symbol",
29 "void",
30 "never",
31];
32
33macro_rules! no_recover {
35 ($p:expr, $res:expr) => {
36 if $res.is_none() && $p.state.no_recovery {
37 return None;
38 }
39 };
40}
41
42pub(crate) fn abstract_readonly_modifiers(
43 p: &mut Parser,
44) -> (Option<Range<usize>>, Option<Range<usize>>) {
45 let (mut abstract_, mut readonly) = (None, None);
46 for _ in 0..2 {
47 match p.cur_src() {
48 "abstract" if abstract_.is_none() => {
49 abstract_ = ts_modifier(p, &["abstract"]);
50 if abstract_.is_none() {
51 return (abstract_, readonly);
52 }
53 }
54 "readonly" if readonly.is_none() => {
55 readonly = ts_modifier(p, &["readonly"]);
56 if readonly.is_none() {
57 return (abstract_, readonly);
58 }
59 }
60 _ => return (abstract_, readonly),
61 }
62 }
63 (abstract_, readonly)
64}
65
66pub fn ts_modifier(p: &mut Parser, modifiers: &[&'static str]) -> Option<Range<usize>> {
67 if !modifiers.contains(&p.cur_src()) {
68 return None;
69 }
70
71 let range = p.cur_tok().range;
72
73 if p.has_linebreak_before_n(1)
74 || token_set![T!['('], T![')'], T![:], T![=], T![?]].contains(p.nth(1))
75 {
76 return None;
77 }
78
79 let kind = match p.cur_src() {
80 "abstract" => T![abstract],
81 "readonly" => T![readonly],
82 _ => unreachable!("unknown modifier"),
83 };
84 p.bump_remap(kind);
85
86 Some(range)
87}
88
89pub(crate) fn maybe_ts_type_annotation(p: &mut Parser) -> Option<Range<usize>> {
90 if p.at(T![:]) {
91 let maybe_err = p.start();
92 let start = p.cur_tok().range.start;
93 p.bump_any();
94 let compl = ts_type(p);
95 let end = compl
96 .map(|x| usize::from(x.range(p).end()))
97 .unwrap_or_else(|| p.cur_tok().range.start);
98
99 if !p.typescript() {
100 let err = p
101 .err_builder("type annotations can only be used in TypeScript files")
102 .primary(start..end, "");
103
104 p.error(err);
105 maybe_err.complete(p, ERROR);
106 } else {
107 maybe_err.abandon(p);
108 }
109 Some(start..end)
110 } else {
111 None
112 }
113}
114
115pub(crate) fn ts_expr_stmt(p: &mut Parser) -> Option<CompletedMarker> {
116 match p.cur_src() {
117 "declare" => ts_declare(p),
118 "global" => {
119 if p.nth_at(1, T!['{']) {
120 ts_ambient_external_module_decl(p, false)
121 } else {
122 None
123 }
124 }
125 _ => ts_decl(p),
126 }
127}
128
129pub(crate) fn ts_declare(p: &mut Parser) -> Option<CompletedMarker> {
130 debug_assert_eq!(p.cur_src(), "declare");
131 let p = &mut *p.with_state(ParserState {
132 in_declare: true,
133 ..p.state.clone()
134 });
135 Some(match p.nth(1) {
136 T![function] => {
137 p.state.decorators_were_valid = true;
138 let m = p.start();
139 p.bump_remap(T![declare]);
140 function_decl(p, m, false)
141 }
142 T![class] => {
143 p.state.decorators_were_valid = true;
144 let m = p.start();
145 p.bump_remap(T![declare]);
146 class_decl(p, false).undo_completion(p).abandon(p);
147 m.complete(p, CLASS_DECL)
148 }
149 t if (t == T![const] && p.nth_at(2, T![enum])) || t == T![enum] => {
150 let m = p.start();
151 p.bump_remap(T![declare]);
152 ts_enum(p).undo_completion(p).abandon(p);
153 m.complete(p, TS_ENUM)
154 }
155 T![const] | T![var] => {
156 let m = p.start();
157 p.bump_remap(T![declare]);
158 var_decl(p, false).undo_completion(p).abandon(p);
160 m.complete(p, VAR_DECL)
161 }
162 _ if p.nth_src(1) == "let" => {
163 let m = p.start();
164 p.bump_remap(T![declare]);
165 var_decl(p, false).undo_completion(p).abandon(p);
166 m.complete(p, VAR_DECL)
167 }
168 _ if p.nth_src(1) == "global" => {
169 let m = p.start();
170 p.bump_remap(T![declare]);
171 if let Some(complete) = ts_ambient_external_module_decl(p, false) {
172 complete.undo_completion(p).abandon(p);
173 }
174 m.complete(p, TS_MODULE_DECL)
175 }
176 _ => {
177 let checkpoint = p.checkpoint();
178 let m = p.start();
179 p.bump_remap(T![declare]);
180 let res = ts_decl(p);
181 if let Some(res) = res {
182 let kind = res.kind();
183 res.undo_completion(p).abandon(p);
184 return Some(m.complete(p, kind));
185 } else {
186 m.abandon(p);
187 p.rewind(checkpoint);
188 return None;
189 }
190 }
191 })
192}
193
194pub(crate) fn ts_decl(p: &mut Parser) -> Option<CompletedMarker> {
195 if p.cur_src() == "abstract" {
196 p.state.decorators_were_valid = true;
197 let m = p.start();
198 let range = p.cur_tok().range;
199 p.bump_remap(T![abstract]);
200 if !p.at(T![class]) {
201 let err = p.err_builder("abstract modifiers can only be applied to classes, methods, or property definitions")
202 .primary(range, "");
203
204 p.error(err);
205 return None;
206 }
207 class_decl(p, false).undo_completion(p).abandon(p);
208 return Some(m.complete(p, CLASS_DECL));
209 }
210
211 if p.at(T![enum]) {
212 return Some(ts_enum(p));
213 }
214
215 if p.cur_src() == "interface" {
216 return ts_interface(p);
217 }
218
219 if p.cur_src() == "module" {
220 if p.nth_at(1, STRING) {
221 return ts_ambient_external_module_decl(p, true);
222 } else if token_set![T![ident], T![yield], T![await]].contains(p.nth(1)) {
223 p.bump_remap(T![module]);
224 return ts_module_or_namespace_decl(p, false, false);
225 }
226 }
227
228 if p.cur_src() == "namespace" {
229 let m = p.start();
230 p.bump_any();
231 ts_module_or_namespace_decl(p, true, false)?
232 .undo_completion(p)
233 .abandon(p);
234 return Some(m.complete(p, TS_NAMESPACE_DECL));
235 }
236
237 if p.cur_src() == "type" {
238 return ts_type_alias_decl(p);
239 }
240
241 None
242}
243
244pub fn ts_type_alias_decl(p: &mut Parser) -> Option<CompletedMarker> {
245 let m = p.start();
246 let start = p.cur_tok().range.start;
247 p.bump_any();
248 no_recover!(p, identifier_name(p));
249 if p.at(T![<]) {
250 no_recover!(p, ts_type_params(p));
251 }
252 let end = p.cur_tok().range.end;
253 p.expect_no_recover(T![=])?;
254 no_recover!(p, ts_type(p));
255 semi(p, start..end);
256 Some(m.complete(p, TS_TYPE_ALIAS_DECL))
257}
258
259pub(crate) fn ts_module_or_namespace_decl(
260 p: &mut Parser,
261 namespace: bool,
262 eat_dot: bool,
263) -> Option<CompletedMarker> {
264 let m = p.start();
265 if eat_dot {
266 p.eat(T![.]);
267 }
268
269 if identifier_name(p).is_none() && p.state.no_recovery {
270 return None;
271 }
272
273 if p.at(T![.]) {
274 ts_module_or_namespace_decl(p, namespace, true)?;
275 } else {
276 ts_module_block(p);
277 }
278
279 Some(m.complete(
280 p,
281 if namespace {
282 TS_NAMESPACE_DECL
283 } else {
284 TS_MODULE_DECL
285 },
286 ))
287}
288
289pub fn ts_ambient_external_module_decl(
290 p: &mut Parser,
291 check_for_module: bool,
292) -> Option<CompletedMarker> {
293 let m = p.start();
294 let start = p.cur_tok().range.start;
295 if check_for_module && p.cur_src() != "module" {
296 let err = p
297 .err_builder(&format!(
298 "expected keyword `module`, but instead found `{}`",
299 p.cur_src()
300 ))
301 .primary(p.cur_tok().range, "");
302
303 p.error(err);
304 } else if check_for_module {
305 p.bump_remap(T![module]);
306 }
307
308 let end = p.cur_tok().range.end;
309 if p.cur_src() == "global" {
310 p.bump_any();
311 } else {
312 p.expect(STRING);
313 }
314 if p.at(T!['{']) {
315 ts_module_block(p);
316 } else {
317 semi(p, start..end);
318 }
319 Some(m.complete(p, TS_MODULE_DECL))
320}
321
322pub fn ts_module_block(p: &mut Parser) -> Option<CompletedMarker> {
323 let m = p.start();
324 p.expect_no_recover(T!['{'])?;
325 block_items(p, false, true, true, None);
327 p.expect_no_recover(T!['}'])?;
328 Some(m.complete(p, TS_MODULE_BLOCK))
329}
330
331pub fn ts_interface(p: &mut Parser) -> Option<CompletedMarker> {
332 let m = p.start();
333 if p.cur_src() != "interface" {
334 let err = p
335 .err_builder(&format!(
336 "expected keyword `interface`, but instead found `{}`",
337 p.cur_src()
338 ))
339 .primary(p.cur_tok().range, "");
340
341 p.error(err);
342 } else {
343 p.bump_any();
344 }
345
346 if DISALLOWED_TYPE_NAMES.contains(&p.cur_src()) || p.cur_src() == "intrinsic" {
347 let err = p
348 .err_builder(&format!(
349 "`{}` cannot be used as the name of an interface",
350 p.cur_src()
351 ))
352 .primary(p.cur_tok().range, "")
353 .footer_note(format!("`{}` is already reserved as a type", p.cur_src()));
354
355 p.error(err);
356 }
357 identifier_name(p);
358 if p.at(T![<]) {
359 ts_type_params(p);
360 }
361
362 if p.cur_src() == "extends" {
363 p.bump_any();
364 ts_heritage_clause(p, false);
365 };
366
367 while p.cur_src() == "extends" {
368 let m = p.start();
369 p.bump_any();
370 let mut complete = ts_heritage_clause(p, false);
371 for elem in &mut complete {
372 elem.change_kind(p, ERROR);
373 }
374
375 let err = p
376 .err_builder("interfaces cannot contain multiple `extends` clauses")
377 .primary(p.marker_vec_range(&complete), "");
378
379 p.error(err);
380 m.complete(p, ERROR);
381 }
382 p.expect(T!['{']);
383 while !p.at(EOF) && !p.at(T!['}']) {
384 ts_type_member(p);
385 }
386 p.expect(T!['}']);
387 Some(m.complete(p, TS_INTERFACE_DECL))
388}
389
390pub(crate) fn ts_heritage_clause(p: &mut Parser, exprs: bool) -> Vec<CompletedMarker> {
393 let mut elems = Vec::with_capacity(1);
394 let m = p.start();
395 if exprs {
396 lhs_expr(p);
397 } else {
398 ts_entity_name(p, None, false);
399 }
400 if p.at(T![<]) {
401 ts_type_args(p);
402 }
403 elems.push(m.complete(p, TS_EXPR_WITH_TYPE_ARGS));
407
408 while p.eat(T![,]) {
409 let m = p.start();
410 if exprs {
411 lhs_expr(p);
412 } else {
413 ts_entity_name(p, None, false);
414 }
415 if p.at(T![<]) {
416 ts_type_args(p);
417 }
418 elems.push(m.complete(p, TS_EXPR_WITH_TYPE_ARGS));
419 }
420 elems
421}
422
423pub fn ts_type_member(p: &mut Parser) -> Option<CompletedMarker> {
424 if p.at(T!['(']) || p.at(T![<]) {
425 return ts_signature_member(p, false);
426 }
427
428 if p.at(T![new]) && token_set!(T![<], T!['(']).contains(p.nth(1)) {
429 return ts_signature_member(p, true);
430 }
431
432 let (m, readonly) = if p.cur_src() == "readonly" {
433 let m = p.start();
434 p.bump_remap(T![readonly]);
435 (m, true)
436 } else {
437 (p.start(), false)
438 };
439
440 if let Some(idx) = try_parse_index_signature(p, m.clone()) {
441 return Some(idx);
442 }
443
444 ts_property_or_method_sig(p, m, readonly)
445}
446
447fn ts_property_or_method_sig(p: &mut Parser, m: Marker, readonly: bool) -> Option<CompletedMarker> {
448 if p.eat(T!['[']) {
449 assign_expr(p);
450 p.expect_no_recover(T![']'])?;
451 } else {
452 match p.cur() {
453 STRING | NUMBER => {
454 literal(p);
455 }
456 _ => {
457 let mut complete = maybe_private_name(p)?;
458 if complete.kind() == PRIVATE_NAME {
459 let err = p
460 .err_builder("private names are not allowed outside of class bodies")
461 .primary(complete.range(p), "");
462
463 p.error(err);
464 complete.change_kind(p, ERROR);
465 }
466 }
467 }
468 };
469
470 p.eat(T![?]);
471 Some(if !readonly && p.at_ts(token_set![T!['('], T![<]]) {
472 if p.at(T![<]) {
473 no_recover!(p, ts_type_params(p));
474 }
475 formal_parameters(p);
476 if p.at(T![:]) {
477 ts_type_or_type_predicate_ann(p, T![:]);
478 }
479 type_member_semi(p);
480 m.complete(p, TS_METHOD_SIGNATURE)
481 } else {
482 if p.eat(T![:]) {
483 ts_type(p);
484 }
485 type_member_semi(p);
486 m.complete(p, TS_PROPERTY_SIGNATURE)
487 })
488}
489
490pub(crate) fn try_parse_index_signature(p: &mut Parser, m: Marker) -> Option<CompletedMarker> {
491 if !p.at(T!['['])
492 || !(token_set![T![ident], T![await], T![yield]].contains(p.nth(1))
493 || p.nth(1).is_keyword())
494 || !token_set![T![:], T![,]].contains(p.nth(2))
495 {
496 return None;
497 }
498
499 p.expect_no_recover(T!['['])?;
500 let pat_m = p.start();
501 identifier_name(p);
502 p.expect_no_recover(T![:])?;
503 no_recover!(p, ts_type(p));
504 pat_m.complete(p, SINGLE_PATTERN);
505 p.expect_no_recover(T![']'])?;
506
507 if p.eat(T![:]) {
508 no_recover!(p, ts_type(p));
509 }
510 type_member_semi(p);
511 Some(m.complete(p, TS_INDEX_SIGNATURE))
512}
513
514pub fn ts_signature_member(p: &mut Parser, construct_sig: bool) -> Option<CompletedMarker> {
515 let m = p.start();
516 if construct_sig {
517 p.expect(T![new]);
518 }
519
520 if p.at(T![<]) {
521 no_recover!(p, ts_type_params(p));
522 }
523
524 formal_parameters(&mut *p.with_state(ParserState {
525 in_binding_list_for_signature: true,
526 ..p.state.clone()
527 }));
528 if p.at(T![:]) {
529 no_recover!(p, ts_type_or_type_predicate_ann(p, T![:]));
530 }
531 type_member_semi(p);
532
533 Some(m.complete(
534 p,
535 if construct_sig {
536 TS_CONSTRUCT_SIGNATURE_DECL
537 } else {
538 TS_CALL_SIGNATURE_DECL
539 },
540 ))
541}
542
543fn type_member_semi(p: &mut Parser) {
545 if p.at_ts(token_set![T![,], T![;]]) {
546 p.bump_any();
547 }
548}
549
550pub fn ts_enum(p: &mut Parser) -> CompletedMarker {
551 let m = p.start();
552 p.eat(T![const]);
553 p.expect(T![enum]);
554 identifier_name(p);
555 p.expect(T!['{']);
556 let mut first = true;
557
558 while !p.at(EOF) && !p.at(T!['}']) {
559 if first {
560 first = false;
561 } else if p.at(T![,]) && p.nth_at(1, T!['}']) {
562 p.eat(T![,]);
563 break;
564 } else {
565 p.expect(T![,]);
566 }
567
568 let member = p.start();
569 let err_occured = if !p.at_ts(token_set![T![ident], T![yield], T![await]])
570 && !p.cur().is_keyword()
571 && !p.at(STRING)
572 {
573 let err = p
574 .err_builder("expected an identifier or string for an enum variant, but found none")
575 .primary(p.cur_tok().range, "");
576
577 p.err_recover(
578 err,
579 token_set![T!['}'], T![ident], T![yield], T![await], T![=], T![,]],
580 false,
581 );
582 true
583 } else {
584 if !p.eat(STRING) {
585 identifier_name(p).unwrap().undo_completion(p).abandon(p);
586 }
587 false
588 };
589
590 if p.eat(T![=]) {
591 assign_expr(p);
592 member.complete(p, TS_ENUM_MEMBER);
593 } else if err_occured {
594 member.abandon(p);
595 } else {
596 member.complete(p, TS_ENUM_MEMBER);
597 }
598 }
599
600 p.expect(T!['}']);
601 m.complete(p, TS_ENUM)
602}
603
604pub fn try_parse_ts(
605 p: &mut Parser,
606 func: impl FnOnce(&mut Parser) -> Option<CompletedMarker>,
607) -> Option<CompletedMarker> {
608 let old = p.to_owned();
612 let res = func(&mut *p.with_state(ParserState {
613 no_recovery: true,
614 ..p.state.clone()
615 }));
616 if res.is_none() {
617 *p = old;
618 }
619 res
620}
621
622pub fn ts_type(p: &mut Parser) -> Option<CompletedMarker> {
623 let ty = ts_non_conditional_type(p);
624 if p.has_linebreak_before_n(0) || !p.at(T![extends]) {
625 return ty;
626 }
627
628 let m = ty.map(|x| x.precede(p)).unwrap_or_else(|| p.start());
629 if p.at(T![extends]) {
630 let m = p.start();
631 p.bump_any();
632 no_recover!(p, ts_non_conditional_type(p));
633 m.complete(p, TS_EXTENDS);
634 }
635 p.expect_no_recover(T![?])?;
636 no_recover!(p, ts_type(p));
637 p.expect_no_recover(T![:])?;
638 no_recover!(p, ts_type(p));
639 Some(m.complete(p, TS_CONDITIONAL_TYPE))
640}
641
642pub fn ts_fn_or_constructor_type(p: &mut Parser, fn_type: bool) -> Option<CompletedMarker> {
643 let m = p.start();
644 if !fn_type {
645 p.expect_no_recover(T![new])?;
646 }
647
648 if p.at(T![<]) {
649 ts_type_params(p);
650 }
651 formal_parameters(p);
652 no_recover!(p, ts_type_or_type_predicate_ann(p, T![=>]));
653 Some(m.complete(
654 p,
655 if fn_type {
656 TS_FN_TYPE
657 } else {
658 TS_CONSTRUCTOR_TYPE
659 },
660 ))
661}
662
663pub(crate) fn ts_type_or_type_predicate_ann(
664 p: &mut Parser,
665 return_token: SyntaxKind,
666) -> Option<CompletedMarker> {
667 let ident_ref_set = token_set![T![await], T![yield], T![ident]];
668 p.expect_no_recover(return_token)?;
669
670 let type_pred = (p.cur_src() == "asserts" && ident_ref_set.contains(p.nth(1)))
671 || (p.at_ts(ident_ref_set) && p.nth_src(1) == "is" && !p.has_linebreak_before_n(1));
672
673 if type_pred {
674 ts_predicate(p)
675 } else {
676 ts_type(p)
677 }
678}
679
680pub fn ts_non_conditional_type(p: &mut Parser) -> Option<CompletedMarker> {
681 if is_start_of_fn_type(p) {
682 return ts_fn_or_constructor_type(p, true);
683 }
684
685 if p.at(T![new]) {
686 return ts_fn_or_constructor_type(p, false);
687 }
688
689 intersection_or_union(p, false, |p| ts_intersection_type_or_higher(p), T![|])
690}
691
692fn ts_intersection_type_or_higher(p: &mut Parser) -> Option<CompletedMarker> {
693 intersection_or_union(p, true, |p| ts_type_operator_or_higher(p), T![&])
694}
695
696fn look_ahead(p: &mut Parser, func: impl FnOnce(&mut Parser) -> bool) -> bool {
697 let checkpoint = p.checkpoint();
698 let res = func(p);
699 p.rewind(checkpoint);
700 res
701}
702
703fn is_start_of_fn_type(p: &mut Parser) -> bool {
704 p.at(T![<]) || (p.at(T!['(']) && look_ahead(p, is_unambiguously_start_of_fn_type))
705}
706
707fn is_unambiguously_start_of_fn_type(p: &mut Parser) -> bool {
708 p.eat(T!['(']);
709 if p.at(T![')']) || p.at(T![...]) {
710 return true;
711 }
712
713 if skip_parameter_start(p) {
714 if p.at_ts(token_set![T![:], T![,], T![?], T![=]]) {
715 return true;
716 }
717 if p.at(T![')']) && p.nth_at(1, T![=>]) {
718 return true;
719 }
720 }
721 false
722}
723
724fn skip_parameter_start(p: &mut Parser) -> bool {
725 maybe_eat_incorrect_modifier(p);
726 if p.at_ts(token_set![T![this], T![yield], T![ident], T![await]]) {
727 p.bump_any();
728 return true;
729 }
730
731 if p.eat(T!['{']) {
732 let mut counter = 1;
733
734 while counter > 0 {
735 if p.eat(T!['{']) {
736 counter += 1;
737 } else if p.eat(T!['}']) {
738 counter -= 1;
739 } else {
740 p.bump_any();
741 }
742 }
743 return true;
744 }
745
746 if p.eat(T!['[']) {
747 let mut counter = 1;
748
749 while counter > 0 {
750 if p.eat(T!['[']) {
751 counter += 1;
752 } else if p.eat(T![']']) {
753 counter -= 1;
754 } else {
755 p.bump_any();
756 }
757 }
758 return true;
759 }
760 false
761}
762
763fn intersection_or_union(
764 p: &mut Parser,
765 intersection: bool,
766 mut constituent: impl FnMut(&mut Parser) -> Option<CompletedMarker>,
767 op: SyntaxKind,
768) -> Option<CompletedMarker> {
769 let kind = if intersection {
770 TS_INTERSECTION
771 } else {
772 TS_UNION
773 };
774 let m = p.start();
775 let saw_op = p.eat(op);
776 let ty = constituent(p);
777 if p.at(op) {
778 while p.eat(op) {
779 constituent(p);
780 }
781
782 Some(m.complete(p, kind))
783 } else if !saw_op && ty.is_none() {
784 m.abandon(p);
785 None
786 } else if !saw_op {
787 m.abandon(p);
788 ty
789 } else {
790 Some(m.complete(p, kind))
791 }
792}
793
794pub fn ts_type_operator_or_higher(p: &mut Parser) -> Option<CompletedMarker> {
795 if matches!(p.cur_src(), "keyof" | "unique" | "readonly") {
796 let m = p.start();
797 let kind = match p.cur_src() {
798 "keyof" => KEYOF_KW,
799 "unique" => UNIQUE_KW,
800 "readonly" => READONLY_KW,
801 _ => unreachable!(),
802 };
803 p.bump_remap(kind);
804 no_recover!(p, ts_type_operator_or_higher(p));
805 Some(m.complete(p, TS_TYPE_OPERATOR))
806 } else if p.cur_src() == "infer" {
807 let m = p.start();
808 p.bump_remap(T![infer]);
809 identifier_name(p);
810 Some(m.complete(p, TS_INFER))
811 } else {
812 ts_array_type_or_higher(p)
815 }
816}
817
818pub fn ts_array_type_or_higher(p: &mut Parser) -> Option<CompletedMarker> {
819 let mut ty = ts_non_array_type(p);
820
821 while !p.has_linebreak_before_n(0) && p.at(T!['[']) {
822 let m = ty.map(|x| x.precede(p)).unwrap_or_else(|| p.start());
823 p.bump_any();
824 if p.eat(T![']']) {
825 ty = Some(m.complete(p, TS_ARRAY));
826 } else {
827 no_recover!(p, ts_type(p));
828 p.expect_no_recover(T![']'])?;
829 ty = Some(m.complete(p, TS_INDEXED_ARRAY));
830 }
831 }
832 ty
833}
834
835pub fn ts_tuple(p: &mut Parser) -> Option<CompletedMarker> {
836 let m = p.start();
837 p.expect_no_recover(T!['['])?;
838
839 while !p.at(EOF) && !p.at(T![']']) {
840 let m = p.start();
841 let rest_range = p.cur_tok().range;
842 let rest = p.eat(T![...]);
843 let name = if crate::at_ident_name!(p)
844 && !DISALLOWED_TYPE_NAMES.contains(&p.cur_src())
845 && (p.nth_at(1, T![:]) || (p.nth_at(1, T![?]) && p.nth_at(2, T![:])))
846 {
847 identifier_name(p);
848 true
849 } else {
850 false
851 };
852
853 let opt_range = p.cur_tok().range;
854 let is_opt = name && p.eat(T![?]);
855 if name {
856 p.expect(T![:]);
857 }
858 no_recover!(p, ts_type(p));
859 if !name && p.at(T![?]) {
860 p.eat(T![?]);
861 }
862 m.complete(p, TS_TUPLE_ELEMENT);
863 if is_opt && rest {
864 let err = p
865 .err_builder("a tuple element cannot be both rest and optional")
866 .secondary(rest_range, "")
867 .primary(opt_range, "");
868
869 p.error(err);
870 }
871 p.eat(T![,]);
872 }
873
874 p.expect_no_recover(T![']'])?;
875 Some(m.complete(p, TS_TUPLE))
876}
877
878pub fn ts_non_array_type(p: &mut Parser) -> Option<CompletedMarker> {
879 match p.cur() {
880 T![ident] | T![void] | T![yield] | T![null] | T![await] | T![break] => {
881 if p.cur_src() == "asserts" && p.nth_at(1, T![this]) {
882 p.bump_any();
883 return ts_predicate(p);
884 }
885
886 let kind = match p.cur_src() {
887 "void" => TS_VOID,
888 "null" => TS_NULL,
889 "any" => TS_ANY,
890 "boolean" => TS_BOOLEAN,
891 "bigint" => TS_BIGINT,
892 "never" => TS_NEVER,
893 "number" => TS_NUMBER,
894 "object" => TS_OBJECT,
895 "string" => TS_STRING,
896 "symbol" => TS_SYMBOL,
897 "unknown" => TS_UNKNOWN,
898 "undefined" => TS_UNDEFINED,
899 _ =>
900 {
902 ERROR
903 }
904 };
905
906 if kind != ERROR && !p.nth_at(1, T![.]) {
907 let m = p.start();
908 p.bump_any();
909 Some(m.complete(p, kind))
910 } else {
911 ts_type_ref(p, None)
912 }
913 }
914 NUMBER | STRING | TRUE_KW | FALSE_KW | REGEX => {
915 Some(literal(p).unwrap().precede(p).complete(p, TS_LITERAL))
916 }
917 BACKTICK => {
918 let m = p.start();
919 p.bump_any();
920
921 while !p.at(EOF) && !p.at(BACKTICK) {
922 match p.cur() {
923 TEMPLATE_CHUNK => p.bump_any(),
924 DOLLARCURLY => {
925 let e = p.start();
926 p.bump_any();
927 ts_type(p);
928 p.expect(T!['}']);
929 e.complete(p, TS_TEMPLATE_ELEMENT);
930 },
931 t => unreachable!("Anything not template chunk or dollarcurly should have been eaten by the lexer, but {:?} was found", t),
932 }
933 }
934
935 p.eat(BACKTICK);
936 Some(m.complete(p, TS_TEMPLATE))
937 }
938 T![-] => {
939 let m = p.start();
940 p.bump_any();
941 if p.at(NUMBER) {
942 let _m = p.start();
943 p.bump_any();
944 _m.complete(p, LITERAL);
945 } else {
946 p.expect_no_recover(NUMBER)?;
947 }
948 Some(m.complete(p, TS_LITERAL))
949 }
950 T![import] => ts_import(p),
951 T![this] => {
952 if p.nth_src(1) == "is" {
953 ts_predicate(p)
954 } else {
955 let m = p.start();
956 p.bump_any();
957 Some(m.complete(p, TS_THIS))
958 }
959 }
960 T![typeof] => ts_type_query(p),
961 T!['{'] => {
962 if is_mapped_type_start(p) {
963 ts_mapped_type(p)
964 } else {
965 let m = p.start();
966 p.bump_any();
967 while !p.at(EOF) && !p.at(T!['}']) {
968 ts_type_member(p);
969 type_member_semi(p);
970 }
971 p.expect(T!['}']);
972 Some(m.complete(p, TS_OBJECT_TYPE))
973 }
974 }
975 T!['['] => ts_tuple(p),
976 T!['('] => {
977 let m = p.start();
978 p.bump_any();
979 no_recover!(p, ts_type(p));
980 p.expect_no_recover(T![')'])?;
981 Some(m.complete(p, TS_PAREN))
982 }
983 _ => {
984 let err = p
985 .err_builder("expected a type")
986 .primary(p.cur_tok().range, "");
987
988 p.err_recover(
989 err,
990 BASE_TS_RECOVERY_SET.union(token_set![
991 T![typeof],
992 T!['{'],
993 T!['['],
994 T!['('],
995 T![this],
996 T![import],
997 T![-],
998 NUMBER,
999 STRING,
1000 TRUE_KW,
1001 FALSE_KW,
1002 REGEX,
1003 BACKTICK,
1004 T![&],
1005 T![|]
1006 ]),
1007 false,
1008 );
1009 None
1010 }
1011 }
1012}
1013
1014pub fn ts_type_args(p: &mut Parser) -> Option<CompletedMarker> {
1015 let m = p.start();
1016 p.expect_no_recover(T![<])?;
1017 let mut first = true;
1018
1019 while !p.at(EOF) && !p.at(T![>]) {
1020 if first {
1021 first = false;
1022 } else if p.at(T![,]) && p.nth_at(1, T![>]) {
1023 let m = p.start();
1024 let range = p.cur_tok().range;
1025 p.bump_any();
1026 m.complete(p, ERROR);
1027 let err = p
1028 .err_builder("type arguments may not contain trailing commas")
1029 .primary(range, "help: remove this comma");
1030
1031 p.error(err);
1032 } else {
1033 p.expect_no_recover(T![,])?;
1034 }
1035 no_recover!(p, ts_type(p));
1036 }
1037 p.expect_no_recover(T![>])?;
1038 Some(m.complete(p, TS_TYPE_ARGS))
1039}
1040
1041pub fn ts_type_params(p: &mut Parser) -> Option<CompletedMarker> {
1043 let m = p.start();
1044 p.expect_no_recover(T![<])?;
1045 let mut first = true;
1046
1047 while !p.at(EOF) && !p.at(T![>]) {
1048 if first {
1049 first = false;
1050 } else {
1051 if p.at(T![,]) && p.nth_at(1, T![>]) {
1052 p.bump_any();
1053 break;
1054 }
1055 p.expect_no_recover(T![,])?;
1056 }
1057 no_recover!(p, type_param(p));
1058 }
1059 p.expect_no_recover(T![>])?;
1060 Some(m.complete(p, TS_TYPE_PARAMS))
1061}
1062
1063fn type_param(p: &mut Parser) -> Option<CompletedMarker> {
1064 let m = p.start();
1065 let mut should_complete =
1066 if p.at_ts(token_set![T![ident], T![await], T![yield]]) || p.cur().is_keyword() {
1067 p.bump_remap(T![ident]);
1068 true
1069 } else {
1070 false
1071 };
1072 if p.cur_src() == "extends" {
1073 should_complete = true;
1074 let _m = p.start();
1075 p.bump_remap(T![extends]);
1076 no_recover!(p, ts_type(p));
1077 _m.complete(p, TS_CONSTRAINT);
1078 }
1079 if p.at(T![=]) {
1080 should_complete = true;
1081 let _m = p.start();
1082 p.bump_any();
1083 no_recover!(p, ts_type(p));
1084 _m.complete(p, TS_DEFAULT);
1085 }
1086 if should_complete {
1087 Some(m.complete(p, TS_TYPE_PARAM))
1088 } else {
1089 m.abandon(p);
1090 let err = p
1091 .err_builder("expected a type parameter, but found none")
1092 .primary(p.cur_tok().range, "");
1093
1094 p.err_recover(
1095 err,
1096 token_set![T![ident], T![yield], T![await], T![>], T![=]],
1097 false,
1098 );
1099 None
1100 }
1101}
1102
1103pub fn ts_import(p: &mut Parser) -> Option<CompletedMarker> {
1104 let m = p.start();
1105 p.expect_no_recover(T![import])?;
1106 p.expect_no_recover(T!['('])?;
1107 p.expect_no_recover(STRING)?;
1108 p.expect_no_recover(T![')'])?;
1109 if p.eat(T![.]) {
1110 ts_entity_name(p, None, false);
1111 }
1112 if p.at(T![<]) && !p.has_linebreak_before_n(0) {
1113 ts_type_args(p);
1114 }
1115
1116 Some(m.complete(p, TS_IMPORT))
1117}
1118
1119pub fn ts_type_query(p: &mut Parser) -> Option<CompletedMarker> {
1120 let m = p.start();
1121 p.expect_no_recover(T![typeof])?;
1122
1123 if p.at(T![import]) {
1124 no_recover!(p, ts_import(p));
1125 } else {
1126 no_recover!(p, ts_entity_name(p, None, true));
1127 }
1128 Some(m.complete(p, TS_TYPE_QUERY))
1129}
1130
1131pub fn ts_mapped_type(p: &mut Parser) -> Option<CompletedMarker> {
1132 let m = p.start();
1133 p.expect_no_recover(T!['{'])?;
1134 let tok = p.cur_tok().range;
1135 let _m = p.start();
1136 if p.eat(T![+]) || p.eat(T![-]) {
1137 if p.cur_src() != "readonly" {
1138 let err = p
1139 .err_builder("`+` and `-` modifiers in mapped types must be followed by `readonly`")
1140 .primary(tok, "");
1141
1142 p.error(err);
1143 } else {
1144 p.bump_remap(T![readonly]);
1145 }
1146 _m.complete(p, TS_MAPPED_TYPE_READONLY);
1147 } else if p.cur_src() == "readonly" {
1148 p.bump_remap(T![readonly]);
1149 _m.complete(p, TS_MAPPED_TYPE_READONLY);
1150 } else {
1151 _m.abandon(p);
1152 }
1153
1154 let param = p.start();
1155 p.expect_no_recover(T!['['])?;
1156 if let Some(x) = identifier_name(p) {
1158 x.undo_completion(p).abandon(p)
1159 }
1160 if p.cur_src() != "in" {
1161 let err = p
1162 .err_builder("expected `in` after a mapped type parameter name")
1163 .primary(p.cur_tok().range, "");
1164
1165 p.error(err);
1166 } else {
1167 p.bump_any();
1168 }
1169 no_recover!(p, ts_type(p));
1170 if p.cur_src() == "as" {
1171 p.bump_any();
1172 ts_type(p);
1173 }
1174 p.expect_no_recover(T![']'])?;
1175 param.complete(p, TS_MAPPED_TYPE_PARAM);
1176 let tok = p.cur_tok().range;
1177 if p.eat(T![+]) || p.eat(T![-]) {
1178 if !p.at(T![?]) {
1179 let err = p
1181 .err_builder("`+` and `-` modifiers in mapped types must be followed by `?`")
1182 .primary(tok, "");
1183
1184 p.error(err);
1185 } else {
1186 p.bump_any();
1187 }
1188 } else if p.at(T![?]) {
1189 p.bump_any();
1190 }
1191
1192 p.expect_no_recover(T![:])?;
1193 no_recover!(p, ts_type(p));
1194 p.eat(T![;]);
1197 p.expect_no_recover(T!['}'])?;
1198 Some(m.complete(p, TS_MAPPED_TYPE))
1199}
1200
1201fn is_mapped_type_start(p: &Parser) -> bool {
1202 if (p.nth_at(1, T![+]) || p.nth_at(1, T![-])) && p.nth_src(2) == "readonly" {
1203 return true;
1204 }
1205 let mut cur = 1;
1206 if p.cur_src() == "readonly" {
1207 cur += 1;
1208 }
1209 if !p.nth_at(cur, T!['[']) {
1210 return false;
1211 }
1212 cur += 1;
1213 if !matches!(p.nth(cur), T![yield] | T![await] | T![ident]) {
1214 return false;
1215 }
1216 cur += 1;
1217 p.nth_at(cur, T![in])
1218}
1219
1220pub fn ts_predicate(p: &mut Parser) -> Option<CompletedMarker> {
1221 let m = p.start();
1222 let mut advanced = false;
1223
1224 if p.cur_src() == "asserts" {
1225 p.bump_any();
1226 advanced = true;
1227 }
1228
1229 if p.at(T![this]) {
1230 let _m = p.start();
1231 p.bump_any();
1232 _m.complete(p, TS_THIS);
1233 advanced = true;
1234 } else if p.at_ts(token_set![T![await], T![yield], T![ident]]) {
1235 let _m = p.start();
1236 p.bump_any();
1237 _m.complete(p, TS_TYPE_NAME);
1238 advanced = true;
1239 }
1240
1241 if p.cur_src() == "is" {
1242 p.bump_any();
1243 no_recover!(p, ts_type(p));
1244 advanced = true;
1245 }
1246
1247 if !advanced {
1248 m.abandon(p);
1249 None
1250 } else {
1251 Some(m.complete(p, TS_PREDICATE))
1252 }
1253}
1254
1255pub(crate) fn maybe_eat_incorrect_modifier(p: &mut Parser) -> Option<CompletedMarker> {
1256 let maybe_err = p.start();
1257 if matches!(p.cur_src(), "public" | "private" | "protected") {
1258 let m = p.start();
1259 p.bump_any();
1260 Some(m.complete(p, ERROR))
1261 } else if ts_modifier(p, &["readonly"]).is_some() {
1262 Some(maybe_err.complete(p, ERROR))
1263 } else {
1264 None
1265 }
1266}
1267
1268pub fn ts_type_ref(
1269 p: &mut Parser,
1270 recovery_set: impl Into<Option<TokenSet>> + Clone,
1271) -> Option<CompletedMarker> {
1272 let m = p.start();
1273 if let Some(err_m) = maybe_eat_incorrect_modifier(p) {
1274 let err = p
1275 .err_builder("a parameter property is only allowed in a constructor implementation")
1276 .primary(err_m.range(p), "");
1277
1278 p.error(err);
1279 }
1280
1281 ts_entity_name(p, recovery_set, true)?;
1282 if !p.has_linebreak_before_n(0) && p.at(T![<]) {
1283 no_recover!(p, ts_type_args(p));
1284 }
1285
1286 Some(m.complete(p, TS_TYPE_REF))
1287}
1288
1289pub fn ts_entity_name(
1290 p: &mut Parser,
1291 recovery_set: impl Into<Option<TokenSet>> + Clone,
1292 allow_reserved: bool,
1293) -> Option<CompletedMarker> {
1294 let init = ts_type_name(p, recovery_set.clone(), false)?;
1295 let mut lhs = init;
1298 let set = recovery_set
1299 .into()
1300 .unwrap_or(BASE_TS_RECOVERY_SET)
1301 .union(token_set![T![.]]);
1302
1303 while p.at(T![.]) {
1304 let m = lhs.precede(p);
1305 p.bump_any();
1306 no_recover!(p, ts_type_name(p, set, allow_reserved));
1308 lhs = m.complete(p, TS_QUALIFIED_PATH);
1309 }
1310 Some(lhs)
1311}
1312
1313pub fn ts_type_name(
1314 p: &mut Parser,
1315 recovery_set: impl Into<Option<TokenSet>>,
1316 allow_reserved: bool,
1317) -> Option<CompletedMarker> {
1318 if p.at(T![ident]) || (p.cur().is_keyword() && allow_reserved) {
1319 let m = p.start();
1320 p.bump_remap(T![ident]);
1321 return Some(m.complete(p, TS_TYPE_NAME));
1322 }
1323
1324 let set = recovery_set.into().unwrap_or(BASE_TS_RECOVERY_SET);
1326 let err = p
1327 .err_builder(&format!(
1328 "expected a TypeScript type name, but instead found `{}`",
1329 p.cur_src()
1330 ))
1331 .primary(p.cur_tok().range, "");
1332
1333 p.err_recover(err, set, false)?;
1334 None
1335}