fix(kernel): find a store exported on a later line in CRLF TS/JS files (#2364)

The kernel's is_exported_later mirrors TreeSitterExtractor.isExportedLater's
multiline regex, but JS's `m` flag treats `\r` as a line end while the regex
crate's `(?m)` sees only `\n`. On a CRLF checkout (Windows, autocrlf) a line
like `export default useStore;\r\n` matched in wasm but not in the kernel, so
`const useStore = create(...)` + `export default useStore;` lost its actions
(e.g. `function inc`) on the default kernel route for TS/TSX/JS/JSX.

Compile it in CRLF mode, `(?mR)`: `^`/`$` then treat `\r` as a line end too,
and the pattern body stays byte-identical to the TS regex. It agrees with the
JS regex on CRLF, trailing whitespace and lone `\r` line ends, where an
optional `\r?$` would still miss a lone `\r`.

This was the only `(?m)` regex in the kernel. The other tsjs regexes are
whole-string anchors, and the minified-bundle check splits lines on `\n`
exactly as the TS does.

Adds a kernel/wasm parity case (ts/tsx/js/jsx, LF and CRLF) that fails on
the unfixed kernel for all four CRLF variants and passes with the fix.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Colby Mchenry
2026-10-06 04:06:24 +00:00
committed by GitHub
co-authored by Claude Opus 5.5
parent f40db4b9cc
commit aeb8f95581
3 changed files with 23 additions and 1 deletions
+4 -1
View File
@@ -363,8 +363,11 @@ impl<'t> Walker<'t> {
return false;
}
let n = regex::escape(name);
// `R` (CRLF mode): JS's multiline `^`/`$` treat `\r` as a line end as
// well as `\n`; `(?m)` alone sees only `\n`, and would miss `export
// default NAME;\r\n` on every Windows autocrlf checkout.
let pattern = format!(
r"(?m)^[ \t]*export\s+(?:default\s+{n}\s*;?[ \t]*$|\{{[^}}]*\b{n}\b[^}}]*\}})",
r"(?mR)^[ \t]*export\s+(?:default\s+{n}\s*;?[ \t]*$|\{{[^}}]*\b{n}\b[^}}]*\}})",
n = n
);
match regex::Regex::new(&pattern) {