What happens
The variable declaration regex in excludeRE:
/\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gs
can backtrack across hundreds of lines when a for (const [...] of ...) destructuring appears. The /s flag makes . match newlines, so when the \[.*?\] alternative fails to match (because ] is followed by of, not =/;/\n), the engine expands .*? across the rest of the file until it finds another ] followed by =.
All identifiers in that span end up in group 1, get split by separatorRE, and are falsely marked as "locally declared" — removing them from auto-import detection.
Reproduction
Given a file like:
// utils/native.ts (auto-imported by Nuxt)
export const PRODUCTION_ORIGIN = 'https://example.com';
And a consumer file:
// some-file.ts
async function doWork() {
const results = await Promise.allSettled([task1(), task2()]);
for (const [i, r] of results.entries()) {
// ^ excludeRE starts matching here: `const [`
// The `]` is followed by ` of`, not `= ; \n`, so backtracking begins
if (r.status === 'rejected') logError(r.reason);
}
}
// ... many lines ...
function patchFetch() {
const targetUrl = `${PRODUCTION_ORIGIN}/api`;
// ^ PRODUCTION_ORIGIN is now inside the excludeRE match span
// and gets falsely excluded from auto-import detection
headers[key] = value;
// ^ backtracking finally stops here: `]` followed by ` =`
}
PRODUCTION_ORIGIN is not auto-imported, causing a runtime ReferenceError: Can't find variable: PRODUCTION_ORIGIN.
Impact
We've hit this in production in a Nuxt + Capacitor app. The silent failure (no build error, just a missing import at runtime) makes it hard to catch. We've worked around it with explicit import { x } from '#imports' in affected files.
Analysis
The eslint-disable-next-line regexp/no-super-linear-backtracking comment on the regex suggests the backtracking concern was known but suppressed. The /s flag is what makes this actively harmful rather than just slow — without it, .*? can't cross line boundaries and the match stays local.
Possible fix
A few approaches come to mind (happy to contribute a PR if one of these looks right):
- Remove the
/s flag — the \n in the terminator set [=;\n] already handles multi-line const declarations, and without /s the backtracking stays within one line
- Make the
\[...\] alternative more specific: \[.*?\]\s*?= to only match array destructuring assignments, not for-of
- Use a negative lookahead after
] to reject of keyword: \[.*?\](?!\s+of\b)
What happens
The variable declaration regex in
excludeRE:/\b(?:const|let|var)\s+?(\[.*?\]|\{.*?\}|.+?)\s*?[=;\n]/gscan backtrack across hundreds of lines when a
for (const [...] of ...)destructuring appears. The/sflag makes.match newlines, so when the\[.*?\]alternative fails to match (because]is followed byof, not=/;/\n), the engine expands.*?across the rest of the file until it finds another]followed by=.All identifiers in that span end up in group 1, get split by
separatorRE, and are falsely marked as "locally declared" — removing them from auto-import detection.Reproduction
Given a file like:
And a consumer file:
PRODUCTION_ORIGINis not auto-imported, causing a runtimeReferenceError: Can't find variable: PRODUCTION_ORIGIN.Impact
We've hit this in production in a Nuxt + Capacitor app. The silent failure (no build error, just a missing import at runtime) makes it hard to catch. We've worked around it with explicit
import { x } from '#imports'in affected files.Analysis
The
eslint-disable-next-line regexp/no-super-linear-backtrackingcomment on the regex suggests the backtracking concern was known but suppressed. The/sflag is what makes this actively harmful rather than just slow — without it,.*?can't cross line boundaries and the match stays local.Possible fix
A few approaches come to mind (happy to contribute a PR if one of these looks right):
/sflag — the\nin the terminator set[=;\n]already handles multi-lineconstdeclarations, and without/sthe backtracking stays within one line\[...\]alternative more specific:\[.*?\]\s*?=to only match array destructuring assignments, notfor-of]to rejectofkeyword:\[.*?\](?!\s+of\b)