Skip to content

Commit ae22033

Browse files
authored
fix(es/parser): Make export in NS to not affect file type (#10799)
Fixes #10797
1 parent 41d507f commit ae22033

File tree

6 files changed

+84
-38
lines changed

6 files changed

+84
-38
lines changed

.changeset/olive-carrots-work.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
swc_ecma_lexer: patch
3+
swc_ecma_parser: patch
4+
swc_core: patch
5+
---
6+
7+
fix(es/parser): export in ns not affect file type

crates/swc_ecma_lexer/src/common/context.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,5 +65,7 @@ bitflags::bitflags! {
6565
const AllowUsingDecl = 1 << 28;
6666

6767
const TopLevel = 1 << 29;
68+
69+
const TsModuleBlock = 1 << 30;
6870
}
6971
}

crates/swc_ecma_lexer/src/common/parser/module_item.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ fn handle_import_export<'a, P: Parser<'a>>(
3333
p: &mut P,
3434
decorators: Vec<Decorator>,
3535
) -> PResult<ModuleItem> {
36-
if !p.ctx().contains(Context::TopLevel) {
36+
if !p
37+
.ctx()
38+
.intersects(Context::TopLevel.union(Context::TsModuleBlock))
39+
{
3740
syntax_error!(p, SyntaxError::NonTopLevelImportExport);
3841
}
3942

@@ -343,7 +346,7 @@ fn parse_export<'a, P: Parser<'a>>(
343346
p: &mut P,
344347
mut decorators: Vec<Decorator>,
345348
) -> PResult<ModuleDecl> {
346-
if !p.ctx().contains(Context::Module) {
349+
if !p.ctx().contains(Context::Module) && p.ctx().contains(Context::TopLevel) {
347350
// Switch to module mode
348351
let ctx = p.ctx() | Context::Module | Context::Strict;
349352
p.set_ctx(ctx);

crates/swc_ecma_lexer/src/common/parser/stmt.rs

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,53 +1384,61 @@ pub fn parse_stmt_block_body<'a, P: Parser<'a>>(
13841384

13851385
pub(super) fn parse_block_body<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>>(
13861386
p: &mut P,
1387-
mut allow_directives: bool,
1387+
allow_directives: bool,
13881388
end: Option<&P::Token>,
13891389
handle_import_export: impl Fn(&mut P, Vec<Decorator>) -> PResult<Type>,
13901390
) -> PResult<Vec<Type>> {
13911391
trace_cur!(p, parse_block_body);
13921392

1393-
let old_ctx = p.ctx();
1394-
13951393
let mut stmts = Vec::with_capacity(8);
1396-
while {
1397-
match (p.input_mut().cur(), end) {
1398-
(Some(cur), Some(end)) => cur != end,
1399-
(Some(_), None) => true,
1400-
(None, None) => false,
1401-
(None, Some(_)) => {
1402-
let eof_text = p.input_mut().dump_cur();
1403-
p.emit_err(
1404-
p.input().cur_span(),
1405-
SyntaxError::Expected(format!("{:?}", end.unwrap()), eof_text),
1406-
);
1407-
false
1408-
}
1394+
1395+
let is_stmt_start = |p: &mut P| match (p.input_mut().cur(), end) {
1396+
(Some(cur), Some(end)) => cur != end,
1397+
(Some(_), None) => true,
1398+
(None, None) => false,
1399+
(None, Some(_)) => {
1400+
let eof_text = p.input_mut().dump_cur();
1401+
p.emit_err(
1402+
p.input().cur_span(),
1403+
SyntaxError::Expected(format!("{:?}", end.unwrap()), eof_text),
1404+
);
1405+
false
14091406
}
1410-
} {
1407+
};
1408+
1409+
let mut has_strict_directive = false;
1410+
if is_stmt_start(p) {
14111411
let stmt = parse_stmt_like(p, true, &handle_import_export)?;
1412-
if allow_directives {
1413-
allow_directives = false;
1414-
if stmt.is_use_strict() {
1415-
p.set_ctx(old_ctx | Context::Strict);
1416-
if p.input().knows_cur() && !p.is_general_semi() {
1417-
unreachable!(
1418-
"'use strict'; directive requires parser.input.cur to be empty or '}}', \
1419-
but current token was: {:?}",
1420-
p.input_mut().cur()
1421-
)
1422-
}
1412+
if allow_directives && stmt.is_use_strict() {
1413+
has_strict_directive = true;
1414+
if p.input().knows_cur() && !p.is_general_semi() {
1415+
unreachable!(
1416+
"'use strict'; directive requires parser.input.cur to be empty or '}}', but \
1417+
current token was: {:?}",
1418+
p.input_mut().cur()
1419+
)
14231420
}
14241421
}
1425-
14261422
stmts.push(stmt);
14271423
}
14281424

1425+
let parse_rest_stmts = |p: &mut P, stmts: &mut Vec<Type>| -> PResult<()> {
1426+
while is_stmt_start(p) {
1427+
let stmt = parse_stmt_like(p, true, &handle_import_export)?;
1428+
stmts.push(stmt);
1429+
}
1430+
Ok(())
1431+
};
1432+
1433+
if has_strict_directive {
1434+
p.do_inside_of_context(Context::Strict, |p| parse_rest_stmts(p, &mut stmts))?;
1435+
} else {
1436+
parse_rest_stmts(p, &mut stmts)?;
1437+
};
1438+
14291439
if p.input_mut().cur().is_some() && end.is_some() {
14301440
p.bump();
14311441
}
14321442

1433-
p.set_ctx(old_ctx);
1434-
14351443
Ok(stmts)
14361444
}

crates/swc_ecma_lexer/src/common/parser/typescript.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2345,10 +2345,10 @@ fn parse_ts_module_block<'a, P: Parser<'a>>(p: &mut P) -> PResult<TsModuleBlock>
23452345

23462346
let start = p.cur_pos();
23472347
expect!(p, &P::Token::LBRACE);
2348-
// Inside of a module block is considered "top-level", meaning it can have
2349-
// imports and exports.
2350-
let body = p.do_inside_of_context(Context::TopLevel, |p| {
2351-
parse_module_item_block_body(p, false, Some(&P::Token::RBRACE))
2348+
let body = p.do_inside_of_context(Context::TsModuleBlock, |p| {
2349+
p.do_outside_of_context(Context::TopLevel, |p| {
2350+
parse_module_item_block_body(p, false, Some(&P::Token::RBRACE))
2351+
})
23522352
})?;
23532353

23542354
Ok(TsModuleBlock {

crates/swc_ecma_parser/src/parser/stmt.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ impl<I: Tokens> Parser<I> {
2828
mod tests {
2929
use swc_atoms::atom;
3030
use swc_common::{comments::SingleThreadedComments, DUMMY_SP as span};
31-
use swc_ecma_lexer::common::parser::stmt::TempForHead;
31+
use swc_ecma_lexer::{common::parser::stmt::TempForHead, TsSyntax};
3232
use swc_ecma_visit::assert_eq_ignore_span;
3333

3434
use super::*;
@@ -1181,4 +1181,30 @@ const foo;"#;
11811181

11821182
test_parser(src, Default::default(), |p| p.parse_script());
11831183
}
1184+
1185+
#[test]
1186+
fn issue_10797_0() {
1187+
let src = "
1188+
var b = delete ANY1;
1189+
1190+
module A {
1191+
export const a = 1
1192+
}";
1193+
test_parser(src, Syntax::Typescript(TsSyntax::default()), |p| {
1194+
p.parse_script()
1195+
});
1196+
}
1197+
1198+
#[test]
1199+
fn issue_10797_1() {
1200+
let src = "
1201+
module A {
1202+
export const a = 1
1203+
}
1204+
1205+
var b = delete ANY1;";
1206+
test_parser(src, Syntax::Typescript(TsSyntax::default()), |p| {
1207+
p.parse_script()
1208+
});
1209+
}
11841210
}

0 commit comments

Comments
 (0)