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}
336
337fn parse_export<'a, P: Parser<'a>>(
338 p: &mut P,
339 mut decorators: Vec<Decorator>,
340) -> PResult<ModuleDecl> {
341 if !p.ctx().contains(Context::Module) && p.ctx().contains(Context::TopLevel) {
342 let ctx = p.ctx() | Context::Module | Context::Strict;
344 p.set_ctx(ctx);
345 }
346
347 let start = p.cur_pos();
348 p.assert_and_bump(&P::Token::EXPORT);
349
350 let cur = p.input().cur();
351 if cur.is_eof() {
352 return Err(eof_error(p));
353 }
354
355 let after_export_start = p.cur_pos();
356
357 let declare = p.input().syntax().typescript() && p.input_mut().eat(&P::Token::DECLARE);
359
360 if declare {
361 if let Some(decl) = try_parse_ts_declare(p, after_export_start, decorators.clone())? {
363 return Ok(ExportDecl {
364 span: p.span(start),
365 decl,
366 }
367 .into());
368 }
369 }
370
371 if p.input().syntax().typescript() {
372 let cur = p.input().cur();
373 if cur.is_word() {
374 let sym = cur.clone().take_word(p.input()).unwrap();
375 if let Some(decl) = try_parse_ts_export_decl(p, decorators.clone(), sym) {
377 return Ok(ExportDecl {
378 span: p.span(start),
379 decl,
380 }
381 .into());
382 }
383 }
384
385 if p.input_mut().eat(&P::Token::IMPORT) {
386 let is_type_only =
387 p.input().is(&P::Token::TYPE) && peek!(p).is_some_and(|p| p.is_word());
388
389 if is_type_only {
390 p.assert_and_bump(&P::Token::TYPE);
391 }
392
393 let id = parse_ident_name(p)?;
394
395 return parse_ts_import_equals_decl(
397 p,
398 start,
399 id.into(),
400 true,
401 is_type_only,
402 )
403 .map(From::from);
404 }
405
406 if p.input_mut().eat(&P::Token::EQUAL) {
407 let expr = p.parse_expr()?;
409 p.expect_general_semi()?;
410 return Ok(TsExportAssignment {
411 span: p.span(start),
412 expr,
413 }
414 .into());
415 }
416
417 if p.input_mut().eat(&P::Token::AS) {
418 expect!(p, &P::Token::NAMESPACE);
421 let id = parse_ident(p, false, false)?;
422 p.expect_general_semi()?;
423 return Ok(TsNamespaceExportDecl {
424 span: p.span(start),
425 id,
426 }
427 .into());
428 }
429 }
430
431 let ns_export_specifier_start = p.cur_pos();
432
433 let type_only = p.input().syntax().typescript() && p.input_mut().eat(&P::Token::TYPE);
434
435 let mut export_default = None;
437
438 if !type_only && p.input_mut().eat(&P::Token::DEFAULT) {
439 if p.input().is(&P::Token::AT) {
440 let start = p.cur_pos();
441 let after_decorators = parse_decorators(p, false)?;
442
443 if !decorators.is_empty() {
444 syntax_error!(p, p.span(start), SyntaxError::TS8038);
445 }
446
447 decorators = after_decorators;
448 }
449
450 if p.input().syntax().typescript() {
451 if p.input().is(&P::Token::ABSTRACT)
452 && peek!(p).is_some_and(|cur| cur.is_class())
453 && !p.input_mut().has_linebreak_between_cur_and_peeked()
454 {
455 let class_start = p.cur_pos();
456 p.assert_and_bump(&P::Token::ABSTRACT);
457 let cur = p.input().cur();
458 if cur.is_error() {
459 let err = p.input_mut().expect_error_token_and_bump();
460 return Err(err);
461 }
462
463 return parse_default_class(p, start, class_start, decorators, true)
464 .map(ModuleDecl::ExportDefaultDecl);
465 }
466 if p.input().is(&P::Token::ABSTRACT) && peek!(p).is_some_and(|cur| cur.is_interface()) {
467 p.emit_err(p.input().cur_span(), SyntaxError::TS1242);
468 p.assert_and_bump(&P::Token::ABSTRACT);
469 }
470
471 if p.input().is(&P::Token::INTERFACE) {
472 let interface_start = p.cur_pos();
473 p.assert_and_bump(&P::Token::INTERFACE);
474 let decl = parse_ts_interface_decl(p, interface_start).map(DefaultDecl::from)?;
475 return Ok(ExportDefaultDecl {
476 span: p.span(start),
477 decl,
478 }
479 .into());
480 }
481 }
482
483 if p.input().is(&P::Token::CLASS) {
484 let class_start = p.cur_pos();
485 let decl = parse_default_class(p, start, class_start, decorators, false)?;
486 return Ok(decl.into());
487 } else if p.input().is(&P::Token::ASYNC)
488 && peek!(p).is_some_and(|cur| cur.is_function())
489 && !p.input_mut().has_linebreak_between_cur_and_peeked()
490 {
491 let decl = parse_default_async_fn(p, start, decorators)?;
492 return Ok(decl.into());
493 } else if p.input().is(&P::Token::FUNCTION) {
494 let decl = parse_default_fn(p, start, decorators)?;
495 return Ok(decl.into());
496 } else if p.input().syntax().export_default_from()
497 && ((p.input().is(&P::Token::FROM) && peek!(p).is_some_and(|peek| peek.is_str()))
498 || (p.input().is(&P::Token::COMMA)
499 && (peek!(p).is_some_and(|peek| peek.is_star() || peek.is_lbrace()))))
500 {
501 export_default = Some(Ident::new_no_ctxt(atom!("default"), p.input().prev_span()))
502 } else {
503 let expr = p.allow_in_expr(parse_assignment_expr)?;
504 p.expect_general_semi()?;
505 return Ok(ExportDefaultExpr {
506 span: p.span(start),
507 expr,
508 }
509 .into());
510 }
511 }
512
513 if p.input().is(&P::Token::AT) {
514 let start = p.cur_pos();
515 let after_decorators = parse_decorators(p, false)?;
516
517 if !decorators.is_empty() {
518 syntax_error!(p, p.span(start), SyntaxError::TS8038);
519 }
520
521 decorators = after_decorators;
522 }
523
524 let decl = if !type_only && p.input().is(&P::Token::CLASS) {
525 let class_start = p.cur_pos();
526 parse_class_decl(p, start, class_start, decorators, false)?
527 } else if !type_only
528 && p.input().is(&P::Token::ASYNC)
529 && peek!(p).is_some_and(|cur| cur.is_function())
530 && !p.input_mut().has_linebreak_between_cur_and_peeked()
531 {
532 parse_async_fn_decl(p, decorators)?
533 } else if !type_only && p.input().is(&P::Token::FUNCTION) {
534 parse_fn_decl(p, decorators)?
535 } else if !type_only
536 && p.input().syntax().typescript()
537 && p.input().is(&P::Token::CONST)
538 && peek!(p).is_some_and(|cur| cur.is_enum())
539 {
540 let enum_start = p.cur_pos();
541 p.assert_and_bump(&P::Token::CONST);
542 p.assert_and_bump(&P::Token::ENUM);
543 return parse_ts_enum_decl(p, enum_start, true)
544 .map(Decl::from)
545 .map(|decl| {
546 ExportDecl {
547 span: p.span(start),
548 decl,
549 }
550 .into()
551 });
552 } else if !type_only
553 && (p.input().is(&P::Token::VAR)
554 || p.input().is(&P::Token::CONST)
555 || (p.input().is(&P::Token::LET))
556 && peek!(p).map(|t| t.follows_keyword_let()).unwrap_or(false))
557 {
558 parse_var_stmt(p, false).map(Decl::Var)?
559 } else {
560 let default = match export_default {
575 Some(default) => Some(default),
576 None => {
577 if p.input().syntax().export_default_from() && p.input().cur().is_word() {
578 Some(parse_ident(p, false, false)?)
579 } else {
580 None
581 }
582 }
583 };
584
585 if default.is_none()
586 && p.input().is(&P::Token::MUL)
587 && !peek!(p).is_some_and(|cur| cur.is_as())
588 {
589 p.assert_and_bump(&P::Token::MUL);
590
591 let (src, with) = parse_from_clause_and_semi(p)?;
593 return Ok(ExportAll {
594 span: p.span(start),
595 src,
596 type_only,
597 with,
598 }
599 .into());
600 }
601
602 let mut specifiers = Vec::new();
603
604 let mut has_default = false;
605 let mut has_ns = false;
606
607 if let Some(default) = default {
608 has_default = true;
609 specifiers.push(ExportSpecifier::Default(ExportDefaultSpecifier {
610 exported: default,
611 }))
612 }
613
614 if !specifiers.is_empty()
617 && p.input().is(&P::Token::COMMA)
618 && peek!(p).is_some_and(|cur| cur.is_star())
619 {
620 p.assert_and_bump(&P::Token::COMMA);
621
622 has_ns = true;
623 }
624 else if specifiers.is_empty() && p.input().is(&P::Token::MUL) {
627 has_ns = true;
628 }
629
630 if has_ns {
631 p.assert_and_bump(&P::Token::MUL);
632 expect!(p, &P::Token::AS);
633 let name = parse_module_export_name(p)?;
634 specifiers.push(ExportSpecifier::Namespace(ExportNamespaceSpecifier {
635 span: p.span(ns_export_specifier_start),
636 name,
637 }));
638 }
639
640 if has_default || has_ns {
641 if p.input().is(&P::Token::FROM) {
642 let (src, with) = parse_from_clause_and_semi(p)?;
643 return Ok(NamedExport {
644 span: p.span(start),
645 specifiers,
646 src: Some(src),
647 type_only,
648 with,
649 }
650 .into());
651 } else if !p.input().syntax().export_default_from() {
652 expect!(p, &P::Token::FROM);
654 }
655
656 expect!(p, &P::Token::COMMA);
657 }
658
659 expect!(p, &P::Token::LBRACE);
660
661 while !p.input().is(&P::Token::RBRACE) {
662 let specifier = parse_named_export_specifier(p, type_only)?;
663 specifiers.push(ExportSpecifier::Named(specifier));
664
665 if p.input().is(&P::Token::RBRACE) {
666 break;
667 } else {
668 expect!(p, &P::Token::COMMA);
669 }
670 }
671 expect!(p, &P::Token::RBRACE);
672
673 let opt = if p.input().is(&P::Token::FROM) {
674 Some(parse_from_clause_and_semi(p)?)
675 } else {
676 for s in &specifiers {
677 match s {
678 ExportSpecifier::Default(default) => {
679 p.emit_err(
680 default.exported.span,
681 SyntaxError::ExportExpectFrom(default.exported.sym.clone()),
682 );
683 }
684 ExportSpecifier::Namespace(namespace) => {
685 let export_name = match &namespace.name {
686 ModuleExportName::Ident(i) => i.sym.clone(),
687 ModuleExportName::Str(s) => s.value.clone(),
688 };
689 p.emit_err(namespace.span, SyntaxError::ExportExpectFrom(export_name));
690 }
691 ExportSpecifier::Named(named) => match &named.orig {
692 ModuleExportName::Ident(id) if id.is_reserved() => {
693 p.emit_err(id.span, SyntaxError::ExportExpectFrom(id.sym.clone()));
694 }
695 ModuleExportName::Str(s) => {
696 p.emit_err(s.span, SyntaxError::ExportBindingIsString);
697 }
698 _ => {}
699 },
700 }
701 }
702
703 p.eat_general_semi();
704
705 None
706 };
707 let (src, with) = match opt {
708 Some(v) => (Some(v.0), v.1),
709 None => (None, None),
710 };
711 return Ok(NamedExport {
712 span: p.span(start),
713 specifiers,
714 src,
715 type_only,
716 with,
717 }
718 .into());
719 };
720
721 Ok(ExportDecl {
722 span: p.span(start),
723 decl,
724 }
725 .into())
726}
727
728fn parse_import<'a, P: Parser<'a>>(p: &mut P) -> PResult<ModuleItem> {
729 let start = p.cur_pos();
730
731 if peek!(p).is_some_and(|cur| cur.is_dot()) {
732 let expr = p.parse_expr()?;
733
734 p.eat_general_semi();
735
736 return Ok(ExprStmt {
737 span: p.span(start),
738 expr,
739 }
740 .into());
741 }
742
743 if peek!(p).is_some_and(|cur| cur.is_lparen()) {
744 let expr = p.parse_expr()?;
745
746 p.eat_general_semi();
747
748 return Ok(ExprStmt {
749 span: p.span(start),
750 expr,
751 }
752 .into());
753 }
754
755 if !p.ctx().contains(Context::Module) {
758 let ctx = p.ctx() | Context::Module | Context::Strict;
760 p.set_ctx(ctx);
761 }
762
763 expect!(p, &P::Token::IMPORT);
764
765 if p.input().cur().is_str() {
767 let src = Box::new(parse_str_lit(p));
768 let with = if p.input().syntax().import_attributes()
769 && !p.input().had_line_break_before_cur()
770 && (p.input_mut().eat(&P::Token::ASSERT) || p.input_mut().eat(&P::Token::WITH))
771 {
772 match parse_object_expr(p)? {
773 Expr::Object(v) => Some(Box::new(v)),
774 _ => unreachable!(),
775 }
776 } else {
777 None
778 };
779 p.eat_general_semi();
780 return Ok(ImportDecl {
781 span: p.span(start),
782 src,
783 specifiers: Vec::new(),
784 type_only: false,
785 with,
786 phase: Default::default(),
787 }
788 .into());
789 }
790
791 let mut type_only = false;
792 let mut phase = ImportPhase::Evaluation;
793 let mut specifiers = Vec::with_capacity(4);
794
795 'import_maybe_ident: {
796 if p.is_ident_ref() {
797 let mut local = parse_imported_default_binding(p)?;
798
799 if p.input().syntax().typescript() && local.sym == "type" {
800 let cur = p.input().cur();
801 if cur.is_lbrace() || cur.is_star() {
802 type_only = true;
803 break 'import_maybe_ident;
804 }
805
806 if p.is_ident_ref() {
807 if !p.input().is(&P::Token::FROM) || peek!(p).is_some_and(|cur| cur.is_from()) {
808 type_only = true;
809 local = parse_imported_default_binding(p)?;
810 } else if peek!(p).is_some_and(|cur| cur.is_equal()) {
811 type_only = true;
812 local = parse_ident_name(p).map(From::from)?;
813 }
814 }
815 }
816
817 if p.input().syntax().typescript() && p.input().is(&P::Token::EQUAL) {
818 return parse_ts_import_equals_decl(p, start, local, false, type_only)
819 .map(ModuleDecl::from)
820 .map(ModuleItem::from);
821 }
822
823 if matches!(&*local.sym, "source" | "defer") {
824 let new_phase = match &*local.sym {
825 "source" => ImportPhase::Source,
826 "defer" => ImportPhase::Defer,
827 _ => unreachable!(),
828 };
829
830 let cur = p.input().cur();
831 if cur.is_lbrace() || cur.is_star() {
832 phase = new_phase;
833 break 'import_maybe_ident;
834 }
835
836 if p.is_ident_ref() && !p.input().is(&P::Token::FROM)
837 || peek!(p).is_some_and(|cur| cur.is_from())
838 {
839 if new_phase == ImportPhase::Defer {
842 break 'import_maybe_ident;
843 }
844 phase = new_phase;
845 local = parse_imported_default_binding(p)?;
846 }
847 }
848
849 if !p.input().is(&P::Token::FROM) {
851 expect!(p, &P::Token::COMMA);
852 }
853 specifiers.push(ImportSpecifier::Default(ImportDefaultSpecifier {
854 span: local.span,
855 local,
856 }));
857 }
858 }
859
860 {
861 let import_spec_start = p.cur_pos();
862 if phase != ImportPhase::Source && p.input_mut().eat(&P::Token::MUL) {
864 expect!(p, &P::Token::AS);
865 let local = parse_imported_binding(p)?;
866 specifiers.push(ImportSpecifier::Namespace(ImportStarAsSpecifier {
867 span: p.span(import_spec_start),
868 local,
869 }));
870 } else if phase == ImportPhase::Evaluation && p.input_mut().eat(&P::Token::LBRACE) {
872 while !p.input().is(&P::Token::RBRACE) {
873 specifiers.push(parse_import_specifier(p, type_only)?);
874
875 if p.input().is(&P::Token::RBRACE) {
876 break;
877 } else {
878 expect!(p, &P::Token::COMMA);
879 }
880 }
881 expect!(p, &P::Token::RBRACE);
882 }
883 }
884
885 let src = {
886 expect!(p, &P::Token::FROM);
887 if p.input().cur().is_str() {
888 Box::new(parse_str_lit(p))
889 } else {
890 unexpected!(p, "a string literal")
891 }
892 };
893
894 let with = if p.input().syntax().import_attributes()
895 && !p.input().had_line_break_before_cur()
896 && (p.input_mut().eat(&P::Token::ASSERT) || p.input_mut().eat(&P::Token::WITH))
897 {
898 match parse_object_expr(p)? {
899 Expr::Object(v) => Some(Box::new(v)),
900 _ => unreachable!(),
901 }
902 } else {
903 None
904 };
905
906 p.expect_general_semi()?;
907
908 Ok(ImportDecl {
909 span: p.span(start),
910 specifiers,
911 src,
912 type_only,
913 with,
914 phase,
915 }
916 .into())
917}
918
919pub fn parse_module_item<'a>(p: &mut impl Parser<'a>) -> PResult<ModuleItem> {
920 p.do_inside_of_context(Context::TopLevel, |p| {
921 parse_stmt_like(p, true, handle_import_export)
922 })
923}