1use swc_atoms::atom;
2use swc_common::Span;
3use swc_ecma_ast::*;
4
5use super::{
6 buffer::Buffer,
7 class_and_fn::{parse_default_async_fn, parse_default_fn, parse_fn_decl},
8 expr::parse_assignment_expr,
9 ident::{parse_ident, parse_ident_name, parse_module_export_name},
10 stmt::{parse_block_body, parse_stmt_like, parse_var_stmt},
11 typescript::{parse_ts_import_equals_decl, try_parse_ts_declare, try_parse_ts_export_decl},
12 PResult, Parser,
13};
14use crate::{
15 common::{
16 context::Context,
17 lexer::token::TokenFactory,
18 parser::{
19 class_and_fn::{
20 parse_async_fn_decl, parse_class_decl, parse_decorators, parse_default_class,
21 },
22 eof_error,
23 expr::parse_str_lit,
24 ident::parse_binding_ident,
25 object::parse_object_expr,
26 typescript::{parse_ts_enum_decl, parse_ts_interface_decl},
27 },
28 },
29 error::SyntaxError,
30};
31
32fn handle_import_export<'a, P: Parser<'a>>(
33 p: &mut P,
34 decorators: Vec<Decorator>,
35) -> PResult<ModuleItem> {
36 if !p
37 .ctx()
38 .intersects(Context::TopLevel.union(Context::TsModuleBlock))
39 {
40 syntax_error!(p, SyntaxError::NonTopLevelImportExport);
41 }
42
43 let decl = if p.input().is(&P::Token::IMPORT) {
44 parse_import(p)?
45 } else if p.input().is(&P::Token::EXPORT) {
46 parse_export(p, decorators).map(ModuleItem::from)?
47 } else {
48 unreachable!(
49 "handle_import_export should not be called if current token isn't import nor export"
50 )
51 };
52
53 Ok(decl)
54}
55
56pub fn parse_module_item_block_body<'a, P: Parser<'a>>(
57 p: &mut P,
58 allow_directives: bool,
59 end: Option<&P::Token>,
60) -> PResult<Vec<ModuleItem>> {
61 parse_block_body(p, allow_directives, end, handle_import_export)
62}
63
64fn parse_from_clause_and_semi<'a, P: Parser<'a>>(
66 p: &mut P,
67) -> PResult<(Box<Str>, Option<Box<ObjectLit>>)> {
68 expect!(p, &P::Token::FROM);
69
70 let cur = p.input().cur();
71 let src = if cur.is_str() {
72 Box::new(parse_str_lit(p))
73 } else {
74 unexpected!(p, "a string literal")
75 };
76 let with = if p.input().syntax().import_attributes()
77 && !p.input().had_line_break_before_cur()
78 && (p.input_mut().eat(&P::Token::ASSERT) || p.input_mut().eat(&P::Token::WITH))
79 {
80 match parse_object_expr(p)? {
81 Expr::Object(v) => Some(Box::new(v)),
82 _ => unreachable!(),
83 }
84 } else {
85 None
86 };
87 p.expect_general_semi()?;
88 Ok((src, with))
89}
90
91fn parse_named_export_specifier<'a, P: Parser<'a>>(
92 p: &mut P,
93 type_only: bool,
94) -> PResult<ExportNamedSpecifier> {
95 let start = p.cur_pos();
96
97 let mut is_type_only = false;
98
99 let orig = match parse_module_export_name(p)? {
100 ModuleExportName::Ident(orig_ident) => {
101 if p.syntax().typescript() && orig_ident.sym == "type" && p.input().cur().is_word() {
108 let possibly_orig = parse_ident_name(p).map(Ident::from)?;
109 if possibly_orig.sym == "as" {
110 if !p.input().cur().is_word() {
112 if type_only {
113 p.emit_err(orig_ident.span, SyntaxError::TS2207);
114 }
115
116 return Ok(ExportNamedSpecifier {
117 span: p.span(start),
118 orig: ModuleExportName::Ident(possibly_orig),
119 exported: None,
120 is_type_only: true,
121 });
122 }
123
124 let maybe_as = parse_ident_name(p).map(Ident::from)?;
125 if maybe_as.sym == "as" {
126 if p.input().cur().is_word() {
127 let exported = parse_ident_name(p).map(Ident::from)?;
130
131 if type_only {
132 p.emit_err(orig_ident.span, SyntaxError::TS2207);
133 }
134
135 debug_assert!(start <= orig_ident.span.hi());
136 return Ok(ExportNamedSpecifier {
137 span: Span::new_with_checked(start, orig_ident.span.hi()),
138 orig: ModuleExportName::Ident(possibly_orig),
139 exported: Some(ModuleExportName::Ident(exported)),
140 is_type_only: true,
141 });
142 } else {
143 return Ok(ExportNamedSpecifier {
145 span: Span::new_with_checked(start, orig_ident.span.hi()),
146 orig: ModuleExportName::Ident(orig_ident),
147 exported: Some(ModuleExportName::Ident(maybe_as)),
148 is_type_only: false,
149 });
150 }
151 } else {
152 return Ok(ExportNamedSpecifier {
154 span: Span::new_with_checked(start, orig_ident.span.hi()),
155 orig: ModuleExportName::Ident(orig_ident),
156 exported: Some(ModuleExportName::Ident(maybe_as)),
157 is_type_only: false,
158 });
159 }
160 } else {
161 if type_only {
164 p.emit_err(orig_ident.span, SyntaxError::TS2207);
165 }
166
167 is_type_only = true;
168 ModuleExportName::Ident(possibly_orig)
169 }
170 } else {
171 ModuleExportName::Ident(orig_ident)
172 }
173 }
174 module_export_name => module_export_name,
175 };
176
177 let exported = if p.input_mut().eat(&P::Token::AS) {
178 Some(parse_module_export_name(p)?)
179 } else {
180 None
181 };
182
183 Ok(ExportNamedSpecifier {
184 span: p.span(start),
185 orig,
186 exported,
187 is_type_only,
188 })
189}
190
191fn parse_imported_binding<'a>(p: &mut impl Parser<'a>) -> PResult<Ident> {
192 Ok(
193 p.do_outside_of_context(Context::InAsync.union(Context::InGenerator), |p| {
194 parse_binding_ident(p, false)
195 })?
196 .into(),
197 )
198}
199
200fn parse_imported_default_binding<'a>(p: &mut impl Parser<'a>) -> PResult<Ident> {
201 parse_imported_binding(p)
202}
203
204fn parse_import_specifier<'a, P: Parser<'a>>(
206 p: &mut P,
207 type_only: bool,
208) -> PResult<ImportSpecifier> {
209 let start = p.cur_pos();
210 match parse_module_export_name(p)? {
211 ModuleExportName::Ident(mut orig_name) => {
212 let mut is_type_only = false;
213 if p.syntax().typescript() && orig_name.sym == "type" && p.input().cur().is_word() {
220 let possibly_orig_name = parse_ident_name(p).map(Ident::from)?;
221 if possibly_orig_name.sym == "as" {
222 if !p.input().cur().is_word() {
224 if p.ctx().is_reserved_word(&possibly_orig_name.sym) {
225 syntax_error!(
226 p,
227 possibly_orig_name.span,
228 SyntaxError::ReservedWordInImport
229 )
230 }
231
232 if type_only {
233 p.emit_err(orig_name.span, SyntaxError::TS2206);
234 }
235
236 return Ok(ImportSpecifier::Named(ImportNamedSpecifier {
237 span: p.span(start),
238 local: possibly_orig_name,
239 imported: None,
240 is_type_only: true,
241 }));
242 }
243
244 let maybe_as: Ident = parse_binding_ident(p, false)?.into();
245 if maybe_as.sym == "as" {
246 if p.input().cur().is_word() {
247 let local: Ident = parse_binding_ident(p, false)?.into();
250
251 if type_only {
252 p.emit_err(orig_name.span, SyntaxError::TS2206);
253 }
254
255 return Ok(ImportSpecifier::Named(ImportNamedSpecifier {
256 span: Span::new_with_checked(start, orig_name.span.hi()),
257 local,
258 imported: Some(ModuleExportName::Ident(possibly_orig_name)),
259 is_type_only: true,
260 }));
261 } else {
262 return Ok(ImportSpecifier::Named(ImportNamedSpecifier {
264 span: Span::new_with_checked(start, maybe_as.span.hi()),
265 local: maybe_as,
266 imported: Some(ModuleExportName::Ident(orig_name)),
267 is_type_only: false,
268 }));
269 }
270 } else {
271 return Ok(ImportSpecifier::Named(ImportNamedSpecifier {
273 span: Span::new_with_checked(start, orig_name.span.hi()),
274 local: maybe_as,
275 imported: Some(ModuleExportName::Ident(orig_name)),
276 is_type_only: false,
277 }));
278 }
279 } else {
280 if type_only {
283 p.emit_err(orig_name.span, SyntaxError::TS2206);
284 }
285
286 orig_name = possibly_orig_name;
287 is_type_only = true;
288 }
289 }
290
291 if p.input_mut().eat(&P::Token::AS) {
292 let local: Ident = parse_binding_ident(p, false)?.into();
293 return Ok(ImportSpecifier::Named(ImportNamedSpecifier {
294 span: Span::new_with_checked(start, local.span.hi()),
295 local,
296 imported: Some(ModuleExportName::Ident(orig_name)),
297 is_type_only,
298 }));
299 }
300
301 if p.ctx().is_reserved_word(&orig_name.sym) {
306 syntax_error!(p, orig_name.span, SyntaxError::ReservedWordInImport)
307 }
308
309 let local = orig_name;
310 Ok(ImportSpecifier::Named(ImportNamedSpecifier {
311 span: p.span(start),
312 local,
313 imported: None,
314 is_type_only,
315 }))
316 }
317 ModuleExportName::Str(orig_str) => {
318 if p.input_mut().eat(&P::Token::AS) {
319 let local: Ident = parse_binding_ident(p, false)?.into();
320 Ok(ImportSpecifier::Named(ImportNamedSpecifier {
321 span: Span::new_with_checked(start, local.span.hi()),
322 local,
323 imported: Some(ModuleExportName::Str(orig_str)),
324 is_type_only: false,
325 }))
326 } else {
327 syntax_error!(
328 p,
329 orig_str.span,
330 SyntaxError::ImportBindingIsString(orig_str.value)
331 )
332 }
333 }
334
335 #[cfg(swc_ast_unknown)]
336 _ => unreachable!(),
337 }
338}
339
340fn parse_export<'a, P: Parser<'a>>(
341 p: &mut P,
342 mut decorators: Vec<Decorator>,
343) -> PResult<ModuleDecl> {
344 if !p.ctx().contains(Context::Module) && p.ctx().contains(Context::TopLevel) {
345 let ctx = p.ctx() | Context::Module | Context::Strict;
347 p.set_ctx(ctx);
348 }
349
350 let start = p.cur_pos();
351 p.assert_and_bump(&P::Token::EXPORT);
352
353 let cur = p.input().cur();
354 if cur.is_eof() {
355 return Err(eof_error(p));
356 }
357
358 let after_export_start = p.cur_pos();
359
360 let declare = p.input().syntax().typescript() && p.input_mut().eat(&P::Token::DECLARE);
362
363 if declare {
364 if let Some(decl) = try_parse_ts_declare(p, after_export_start, decorators.clone())? {
366 return Ok(ExportDecl {
367 span: p.span(start),
368 decl,
369 }
370 .into());
371 }
372 }
373
374 if p.input().syntax().typescript() {
375 let cur = p.input().cur();
376 if cur.is_word() {
377 let sym = cur.clone().take_word(p.input()).unwrap();
378 if let Some(decl) = try_parse_ts_export_decl(p, decorators.clone(), sym) {
380 return Ok(ExportDecl {
381 span: p.span(start),
382 decl,
383 }
384 .into());
385 }
386 }
387
388 if p.input_mut().eat(&P::Token::IMPORT) {
389 let is_type_only =
390 p.input().is(&P::Token::TYPE) && peek!(p).is_some_and(|p| p.is_word());
391
392 if is_type_only {
393 p.assert_and_bump(&P::Token::TYPE);
394 }
395
396 let id = parse_ident_name(p)?;
397
398 return parse_ts_import_equals_decl(
400 p,
401 start,
402 id.into(),
403 true,
404 is_type_only,
405 )
406 .map(From::from);
407 }
408
409 if p.input_mut().eat(&P::Token::EQUAL) {
410 let expr = p.parse_expr()?;
412 p.expect_general_semi()?;
413 return Ok(TsExportAssignment {
414 span: p.span(start),
415 expr,
416 }
417 .into());
418 }
419
420 if p.input_mut().eat(&P::Token::AS) {
421 expect!(p, &P::Token::NAMESPACE);
424 let id = parse_ident(p, false, false)?;
425 p.expect_general_semi()?;
426 return Ok(TsNamespaceExportDecl {
427 span: p.span(start),
428 id,
429 }
430 .into());
431 }
432 }
433
434 let ns_export_specifier_start = p.cur_pos();
435
436 let type_only = p.input().syntax().typescript() && p.input_mut().eat(&P::Token::TYPE);
437
438 let mut export_default = None;
440
441 if !type_only && p.input_mut().eat(&P::Token::DEFAULT) {
442 if p.input().is(&P::Token::AT) {
443 let start = p.cur_pos();
444 let after_decorators = parse_decorators(p, false)?;
445
446 if !decorators.is_empty() {
447 syntax_error!(p, p.span(start), SyntaxError::TS8038);
448 }
449
450 decorators = after_decorators;
451 }
452
453 if p.input().syntax().typescript() {
454 if p.input().is(&P::Token::ABSTRACT)
455 && peek!(p).is_some_and(|cur| cur.is_class())
456 && !p.input_mut().has_linebreak_between_cur_and_peeked()
457 {
458 let class_start = p.cur_pos();
459 p.assert_and_bump(&P::Token::ABSTRACT);
460 let cur = p.input().cur();
461 if cur.is_error() {
462 let err = p.input_mut().expect_error_token_and_bump();
463 return Err(err);
464 }
465
466 return parse_default_class(p, start, class_start, decorators, true)
467 .map(ModuleDecl::ExportDefaultDecl);
468 }
469 if p.input().is(&P::Token::ABSTRACT) && peek!(p).is_some_and(|cur| cur.is_interface()) {
470 p.emit_err(p.input().cur_span(), SyntaxError::TS1242);
471 p.assert_and_bump(&P::Token::ABSTRACT);
472 }
473
474 if p.input().is(&P::Token::INTERFACE) {
475 let interface_start = p.cur_pos();
476 p.assert_and_bump(&P::Token::INTERFACE);
477 let decl = parse_ts_interface_decl(p, interface_start).map(DefaultDecl::from)?;
478 return Ok(ExportDefaultDecl {
479 span: p.span(start),
480 decl,
481 }
482 .into());
483 }
484 }
485
486 if p.input().is(&P::Token::CLASS) {
487 let class_start = p.cur_pos();
488 let decl = parse_default_class(p, start, class_start, decorators, false)?;
489 return Ok(decl.into());
490 } else if p.input().is(&P::Token::ASYNC)
491 && peek!(p).is_some_and(|cur| cur.is_function())
492 && !p.input_mut().has_linebreak_between_cur_and_peeked()
493 {
494 let decl = parse_default_async_fn(p, start, decorators)?;
495 return Ok(decl.into());
496 } else if p.input().is(&P::Token::FUNCTION) {
497 let decl = parse_default_fn(p, start, decorators)?;
498 return Ok(decl.into());
499 } else if p.input().syntax().export_default_from()
500 && ((p.input().is(&P::Token::FROM) && peek!(p).is_some_and(|peek| peek.is_str()))
501 || (p.input().is(&P::Token::COMMA)
502 && (peek!(p).is_some_and(|peek| peek.is_star() || peek.is_lbrace()))))
503 {
504 export_default = Some(Ident::new_no_ctxt(atom!("default"), p.input().prev_span()))
505 } else {
506 let expr = p.allow_in_expr(parse_assignment_expr)?;
507 p.expect_general_semi()?;
508 return Ok(ExportDefaultExpr {
509 span: p.span(start),
510 expr,
511 }
512 .into());
513 }
514 }
515
516 if p.input().is(&P::Token::AT) {
517 let start = p.cur_pos();
518 let after_decorators = parse_decorators(p, false)?;
519
520 if !decorators.is_empty() {
521 syntax_error!(p, p.span(start), SyntaxError::TS8038);
522 }
523
524 decorators = after_decorators;
525 }
526
527 let decl = if !type_only && p.input().is(&P::Token::CLASS) {
528 let class_start = p.cur_pos();
529 parse_class_decl(p, start, class_start, decorators, false)?
530 } else if !type_only
531 && p.input().is(&P::Token::ASYNC)
532 && peek!(p).is_some_and(|cur| cur.is_function())
533 && !p.input_mut().has_linebreak_between_cur_and_peeked()
534 {
535 parse_async_fn_decl(p, decorators)?
536 } else if !type_only && p.input().is(&P::Token::FUNCTION) {
537 parse_fn_decl(p, decorators)?
538 } else if !type_only
539 && p.input().syntax().typescript()
540 && p.input().is(&P::Token::CONST)
541 && peek!(p).is_some_and(|cur| cur.is_enum())
542 {
543 let enum_start = p.cur_pos();
544 p.assert_and_bump(&P::Token::CONST);
545 p.assert_and_bump(&P::Token::ENUM);
546 return parse_ts_enum_decl(p, enum_start, true)
547 .map(Decl::from)
548 .map(|decl| {
549 ExportDecl {
550 span: p.span(start),
551 decl,
552 }
553 .into()
554 });
555 } else if !type_only
556 && (p.input().is(&P::Token::VAR)
557 || p.input().is(&P::Token::CONST)
558 || (p.input().is(&P::Token::LET))
559 && peek!(p).map(|t| t.follows_keyword_let()).unwrap_or(false))
560 {
561 parse_var_stmt(p, false).map(Decl::Var)?
562 } else {
563 let default = match export_default {
578 Some(default) => Some(default),
579 None => {
580 if p.input().syntax().export_default_from() && p.input().cur().is_word() {
581 Some(parse_ident(p, false, false)?)
582 } else {
583 None
584 }
585 }
586 };
587
588 if default.is_none()
589 && p.input().is(&P::Token::MUL)
590 && !peek!(p).is_some_and(|cur| cur.is_as())
591 {
592 p.assert_and_bump(&P::Token::MUL);
593
594 let (src, with) = parse_from_clause_and_semi(p)?;
596 return Ok(ExportAll {
597 span: p.span(start),
598 src,
599 type_only,
600 with,
601 }
602 .into());
603 }
604
605 let mut specifiers = Vec::new();
606
607 let mut has_default = false;
608 let mut has_ns = false;
609
610 if let Some(default) = default {
611 has_default = true;
612 specifiers.push(ExportSpecifier::Default(ExportDefaultSpecifier {
613 exported: default,
614 }))
615 }
616
617 if !specifiers.is_empty()
620 && p.input().is(&P::Token::COMMA)
621 && peek!(p).is_some_and(|cur| cur.is_star())
622 {
623 p.assert_and_bump(&P::Token::COMMA);
624
625 has_ns = true;
626 }
627 else if specifiers.is_empty() && p.input().is(&P::Token::MUL) {
630 has_ns = true;
631 }
632
633 if has_ns {
634 p.assert_and_bump(&P::Token::MUL);
635 expect!(p, &P::Token::AS);
636 let name = parse_module_export_name(p)?;
637 specifiers.push(ExportSpecifier::Namespace(ExportNamespaceSpecifier {
638 span: p.span(ns_export_specifier_start),
639 name,
640 }));
641 }
642
643 if has_default || has_ns {
644 if p.input().is(&P::Token::FROM) {
645 let (src, with) = parse_from_clause_and_semi(p)?;
646 return Ok(NamedExport {
647 span: p.span(start),
648 specifiers,
649 src: Some(src),
650 type_only,
651 with,
652 }
653 .into());
654 } else if !p.input().syntax().export_default_from() {
655 expect!(p, &P::Token::FROM);
657 }
658
659 expect!(p, &P::Token::COMMA);
660 }
661
662 expect!(p, &P::Token::LBRACE);
663
664 while !p.input().is(&P::Token::RBRACE) {
665 let specifier = parse_named_export_specifier(p, type_only)?;
666 specifiers.push(ExportSpecifier::Named(specifier));
667
668 if p.input().is(&P::Token::RBRACE) {
669 break;
670 } else {
671 expect!(p, &P::Token::COMMA);
672 }
673 }
674 expect!(p, &P::Token::RBRACE);
675
676 let opt = if p.input().is(&P::Token::FROM) {
677 Some(parse_from_clause_and_semi(p)?)
678 } else {
679 for s in &specifiers {
680 match s {
681 ExportSpecifier::Default(default) => {
682 p.emit_err(
683 default.exported.span,
684 SyntaxError::ExportExpectFrom(default.exported.sym.clone()),
685 );
686 }
687 ExportSpecifier::Namespace(namespace) => {
688 let export_name = match &namespace.name {
689 ModuleExportName::Ident(i) => i.sym.clone(),
690 ModuleExportName::Str(s) => s.value.clone(),
691 #[cfg(swc_ast_unknown)]
692 _ => unreachable!(),
693 };
694 p.emit_err(namespace.span, SyntaxError::ExportExpectFrom(export_name));
695 }
696 ExportSpecifier::Named(named) => match &named.orig {
697 ModuleExportName::Ident(id) if id.is_reserved() => {
698 p.emit_err(id.span, SyntaxError::ExportExpectFrom(id.sym.clone()));
699 }
700 ModuleExportName::Str(s) => {
701 p.emit_err(s.span, SyntaxError::ExportBindingIsString);
702 }
703 _ => {}
704 },
705 #[cfg(swc_ast_unknown)]
706 _ => (),
707 }
708 }
709
710 p.eat_general_semi();
711
712 None
713 };
714 let (src, with) = match opt {
715 Some(v) => (Some(v.0), v.1),
716 None => (None, None),
717 };
718 return Ok(NamedExport {
719 span: p.span(start),
720 specifiers,
721 src,
722 type_only,
723 with,
724 }
725 .into());
726 };
727
728 Ok(ExportDecl {
729 span: p.span(start),
730 decl,
731 }
732 .into())
733}
734
735fn parse_import<'a, P: Parser<'a>>(p: &mut P) -> PResult<ModuleItem> {
736 let start = p.cur_pos();
737
738 if peek!(p).is_some_and(|cur| cur.is_dot()) {
739 let expr = p.parse_expr()?;
740
741 p.eat_general_semi();
742
743 return Ok(ExprStmt {
744 span: p.span(start),
745 expr,
746 }
747 .into());
748 }
749
750 if peek!(p).is_some_and(|cur| cur.is_lparen()) {
751 let expr = p.parse_expr()?;
752
753 p.eat_general_semi();
754
755 return Ok(ExprStmt {
756 span: p.span(start),
757 expr,
758 }
759 .into());
760 }
761
762 if !p.ctx().contains(Context::Module) {
765 let ctx = p.ctx() | Context::Module | Context::Strict;
767 p.set_ctx(ctx);
768 }
769
770 expect!(p, &P::Token::IMPORT);
771
772 if p.input().cur().is_str() {
774 let src = Box::new(parse_str_lit(p));
775 let with = if p.input().syntax().import_attributes()
776 && !p.input().had_line_break_before_cur()
777 && (p.input_mut().eat(&P::Token::ASSERT) || p.input_mut().eat(&P::Token::WITH))
778 {
779 match parse_object_expr(p)? {
780 Expr::Object(v) => Some(Box::new(v)),
781 _ => unreachable!(),
782 }
783 } else {
784 None
785 };
786 p.eat_general_semi();
787 return Ok(ImportDecl {
788 span: p.span(start),
789 src,
790 specifiers: Vec::new(),
791 type_only: false,
792 with,
793 phase: Default::default(),
794 }
795 .into());
796 }
797
798 let mut type_only = false;
799 let mut phase = ImportPhase::Evaluation;
800 let mut specifiers = Vec::with_capacity(4);
801
802 'import_maybe_ident: {
803 if p.is_ident_ref() {
804 let mut local = parse_imported_default_binding(p)?;
805
806 if p.input().syntax().typescript() && local.sym == "type" {
807 let cur = p.input().cur();
808 if cur.is_lbrace() || cur.is_star() {
809 type_only = true;
810 break 'import_maybe_ident;
811 }
812
813 if p.is_ident_ref() {
814 if !p.input().is(&P::Token::FROM) || peek!(p).is_some_and(|cur| cur.is_from()) {
815 type_only = true;
816 local = parse_imported_default_binding(p)?;
817 } else if peek!(p).is_some_and(|cur| cur.is_equal()) {
818 type_only = true;
819 local = parse_ident_name(p).map(From::from)?;
820 }
821 }
822 }
823
824 if p.input().syntax().typescript() && p.input().is(&P::Token::EQUAL) {
825 return parse_ts_import_equals_decl(p, start, local, false, type_only)
826 .map(ModuleDecl::from)
827 .map(ModuleItem::from);
828 }
829
830 if matches!(&*local.sym, "source" | "defer") {
831 let new_phase = match &*local.sym {
832 "source" => ImportPhase::Source,
833 "defer" => ImportPhase::Defer,
834 _ => unreachable!(),
835 };
836
837 let cur = p.input().cur();
838 if cur.is_lbrace() || cur.is_star() {
839 phase = new_phase;
840 break 'import_maybe_ident;
841 }
842
843 if p.is_ident_ref() && !p.input().is(&P::Token::FROM)
844 || peek!(p).is_some_and(|cur| cur.is_from())
845 {
846 if new_phase == ImportPhase::Defer {
849 break 'import_maybe_ident;
850 }
851 phase = new_phase;
852 local = parse_imported_default_binding(p)?;
853 }
854 }
855
856 if !p.input().is(&P::Token::FROM) {
858 expect!(p, &P::Token::COMMA);
859 }
860 specifiers.push(ImportSpecifier::Default(ImportDefaultSpecifier {
861 span: local.span,
862 local,
863 }));
864 }
865 }
866
867 {
868 let import_spec_start = p.cur_pos();
869 if phase != ImportPhase::Source && p.input_mut().eat(&P::Token::MUL) {
871 expect!(p, &P::Token::AS);
872 let local = parse_imported_binding(p)?;
873 specifiers.push(ImportSpecifier::Namespace(ImportStarAsSpecifier {
874 span: p.span(import_spec_start),
875 local,
876 }));
877 } else if phase == ImportPhase::Evaluation && p.input_mut().eat(&P::Token::LBRACE) {
879 while !p.input().is(&P::Token::RBRACE) {
880 specifiers.push(parse_import_specifier(p, type_only)?);
881
882 if p.input().is(&P::Token::RBRACE) {
883 break;
884 } else {
885 expect!(p, &P::Token::COMMA);
886 }
887 }
888 expect!(p, &P::Token::RBRACE);
889 }
890 }
891
892 let src = {
893 expect!(p, &P::Token::FROM);
894 if p.input().cur().is_str() {
895 Box::new(parse_str_lit(p))
896 } else {
897 unexpected!(p, "a string literal")
898 }
899 };
900
901 let with = if p.input().syntax().import_attributes()
902 && !p.input().had_line_break_before_cur()
903 && (p.input_mut().eat(&P::Token::ASSERT) || p.input_mut().eat(&P::Token::WITH))
904 {
905 match parse_object_expr(p)? {
906 Expr::Object(v) => Some(Box::new(v)),
907 _ => unreachable!(),
908 }
909 } else {
910 None
911 };
912
913 p.expect_general_semi()?;
914
915 Ok(ImportDecl {
916 span: p.span(start),
917 specifiers,
918 src,
919 type_only,
920 with,
921 phase,
922 }
923 .into())
924}
925
926pub fn parse_module_item<'a>(p: &mut impl Parser<'a>) -> PResult<ModuleItem> {
927 p.do_inside_of_context(Context::TopLevel, |p| {
928 parse_stmt_like(p, true, handle_import_export)
929 })
930}