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