Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/regexp-flags-unicode-escape.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
swc_core: patch
swc_ecma_parser: patch
---

fix(es/parser): reject unicode escapes in RegExp flags
5 changes: 5 additions & 0 deletions crates/swc_ecma_parser/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ pub enum SyntaxError {

DuplicatedRegExpFlags(char),
UnknownRegExpFlags,
/// IdentifierPart in RegExp flags must not contain a UnicodeEscapeSequence.
UnicodeEscapeInRegExpFlags,

TS1003,
TS1005,
Expand Down Expand Up @@ -591,6 +593,9 @@ impl SyntaxError {
format!("Duplicated regular expression flag '{flag}'.").into()
}
SyntaxError::UnknownRegExpFlags => "Unknown regular expression flags.".into(),
SyntaxError::UnicodeEscapeInRegExpFlags => {
"Regular expression flags cannot contain unicode escapes.".into()
}

SyntaxError::TS1003 => "Expected an identifier".into(),
SyntaxError::TS1005 => "Expected a semicolon".into(),
Expand Down
19 changes: 11 additions & 8 deletions crates/swc_ecma_parser/src/lexer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1870,16 +1870,19 @@ impl<'a> Lexer<'a> {
self.bump(1); // '/'

// Spec says "It is a Syntax Error if IdentifierPart contains a Unicode escape
// sequence." TODO: check for escape

// Need to use `read_word` because '\uXXXX' sequences are allowed
// here (don't ask).
// let flags_start = self.cur_pos();
// sequence."
// Need to use `read_word` because '\uXXXX' sequences are accepted by the
// scanner — we still reject them as an early error below.
let flags = {
match self.cur() {
Some(c) if c.is_ident_start() => self
.read_word_as_str_with()
.map(|(s, _)| Some(self.atom(s))),
Some(c) if c == b'\\' || c.is_ident_start() => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep scanning non-ASCII regexp flags

When the first flag is non-ASCII, self.cur() is only the first UTF-8 byte, so c.is_ident_start() is false and this branch is skipped. That leaves inputs such as /a/π\u0067 tokenized as /a/ followed by an identifier, so the new unicode-escape-in-flags diagnostic (and the existing unknown-flag validation) never runs for these regexp flags. Please use the current character/IdentifierPart-aware path before deciding there are no flags.

Useful? React with 👍 / 👎.

let (s, has_escape) = self.read_word_as_str_with()?;
if has_escape {
let span = self.span(start);
self.emit_error_span(span, SyntaxError::UnicodeEscapeInRegExpFlags);
}
Ok(Some(self.atom(s)))
}
_ => Ok(None),
}
}?;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/pattern/g\u0069m;
/pattern/\u0067im;
/pattern/gi\u006d;
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/escaped-among-ascii/input.js:1:1]
1 | /pattern/g\u0069m;
: ^^^^^^^^^^^^^^^^^
2 | /pattern/\u0067im;
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/escaped-among-ascii/input.js:2:1]
1 | /pattern/g\u0069m;
2 | /pattern/\u0067im;
: ^^^^^^^^^^^^^^^^^
3 | /pattern/gi\u006d;
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/escaped-among-ascii/input.js:3:1]
2 | /pattern/\u0067im;
3 | /pattern/gi\u006d;
: ^^^^^^^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/ok/gimuy;
/bad/g\u0069m;
/also/\u0067;
/leading/\u{79};
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/mixed-valid-invalid/input.js:2:1]
1 | /ok/gimuy;
2 | /bad/g\u0069m;
: ^^^^^^^^^^^^^
3 | /also/\u0067;
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/mixed-valid-invalid/input.js:3:1]
2 | /bad/g\u0069m;
3 | /also/\u0067;
: ^^^^^^^^^^^^
4 | /leading/\u{79};
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/mixed-valid-invalid/input.js:4:1]
3 | /also/\u0067;
4 | /leading/\u{79};
: ^^^^^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/x/\u0067;
/x/\u{0069};
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/only-escaped-flag/input.js:1:1]
1 | /x/\u0067;
: ^^^^^^^^^
2 | /x/\u{0069};
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/only-escaped-flag/input.js:2:1]
1 | /x/\u0067;
2 | /x/\u{0069};
: ^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/a/\u{69};
/foo/g\u{0069};
/\w+/\u{006d}\u{0073};
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/u-brace-escape/input.js:1:1]
1 | /a/\u{69};
: ^^^^^^^^^
2 | /foo/g\u{0069};
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/u-brace-escape/input.js:2:1]
1 | /a/\u{69};
2 | /foo/g\u{0069};
: ^^^^^^^^^^^^^^
3 | /\w+/\u{006d}\u{0073};
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/u-brace-escape/input.js:3:1]
2 | /foo/g\u{0069};
3 | /\w+/\u{006d}\u{0073};
: ^^^^^^^^^^^^^^^^^^^^^
`----
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/a/g\u0069;
/\w+/m\u0073;
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/u-escape/input.js:1:1]
1 | /a/g\u0069;
: ^^^^^^^^^^
2 | /\w+/m\u0073;
`----
x Regular expression flags cannot contain unicode escapes.
,-[$DIR/tests/errors/regexp-flags-unicode-escape/u-escape/input.js:2:1]
1 | /a/g\u0069;
2 | /\w+/m\u0073;
: ^^^^^^^^^^^^
`----
Loading