Repository navigation
fix(regex): escape literal [ inside character classes (#3527) - #3777
Closed
proggeramlug wants to merge 1 commit into
Closed
proggeramlug wants to merge 1 commit into
proggeramlug wants to merge 1 commit into
Conversation
A literal unescaped `[` inside a `[...]` character class is valid in JS (it's a plain `[`), but both Rust engines — the `regex` crate AND the `fancy-regex` fallback — reject it as "invalid character class". `js_regex_to_rust` passed it through unchanged. This mattered more than a lone-bracket quirk: the *same* translated pattern string feeds both engines, so when the `regex` crate bailed on an advanced construct (backreference / lookaround) and the code fell back to `fancy-regex`, the unescaped `[` made fancy-regex reject the pattern too — even though it fully supports the backreferences and lookahead involved. get-intrinsic's path-split pattern `[^%.[\]]+|...(?!\2)...\2...|(?=...)` is exactly this shape, so it threw `SyntaxError: Invalid regular expression: …: invalid pattern` at init while compiling Express (#3527), despite fancy-regex being able to handle it once the `[` is escaped. Fix: track character-class depth in `js_regex_to_rust` and escape a literal `[` encountered inside a class to `\[` (semantics-preserving in both engines). Also gate the `(?<name>...)` named-group rewrite on being outside a class, where `(` is literal. Verified: the get-intrinsic pattern now compiles under fancy-regex and matches correctly; the Express tree advances past it. Unit test covers the class-bracket escaping and the full pattern.
proggeramlug
force-pushed
the
fix/3527-regex-bracket-in-class
branch
from
May 31, 2026 18:23
6d69e55 to
7029680
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A literal unescaped
[inside a[...]character class is valid in JS (a plain[), but both Rust engines — theregexcrate and thefancy-regexfallback — reject it as "invalid character class".js_regex_to_rustpassed it through unchanged.Why this mattered (and why it's NOT an engine limitation)
Perry already has a
fancy-regexfallback that supports backreferences, lookahead, and lookbehind. But the same translated pattern string feeds both engines: when theregexcrate bails on an advanced construct and the code falls back tofancy-regex, an unescaped[makes fancy-regex reject the pattern too — even though it fully supports the rest.get-intrinsic's path-split pattern is exactly this shape:
It has backreferences (
\2) and lookahead ((?=...)) — both fancy-regex-compatible — but the leading[^%.[\]]class with a literal[made it throwSyntaxError: Invalid regular expression: …: invalid patternat init while compiling Express (#3527). Escaping the[→ the whole pattern compiles under fancy-regex and matches correctly.Fix
Track character-class depth in
js_regex_to_rustand escape a literal[found inside a class to\[(semantics-preserving in both engines). Also gate the(?<name>...)named-group rewrite on being outside a class, where(is literal.Verification
%Array.prototype.push%→Array); the Express tree advances past it.js_regex_to_rust_escapes_literal_bracket_in_classcovers the escaping, the named-group interaction, and end-to-end compilation of the full pattern.cargo fmt --checkclean.Part of the #3527 chain (prior: #3537/#3543/#3546, #3551, #3733, #3751, #3764, #3771, #3776). No version bump / changelog — folded in at merge per the worktree-PR convention.