diff --git a/.changeset/devtools-bundler-core-stateful-regex.md b/.changeset/devtools-bundler-core-stateful-regex.md new file mode 100644 index 000000000..5a77b249f --- /dev/null +++ b/.changeset/devtools-bundler-core-stateful-regex.md @@ -0,0 +1,5 @@ +--- +'@tanstack/devtools-bundler-core': patch +--- + +Make `matcher` deterministic when `injectSource.ignore` regexes use the `g` (global) or `y` (sticky) flag. Such regexes are stateful under `.test()`, advancing `lastIndex` on each match; since the user's config regex object is reused across every module/component transform, ignored files and components alternated between being ignored and injected depending on processing order. The matcher now clones `g`/`y`-flagged regexes without those flags per call, so matching is stateless and the user's config object is never mutated. diff --git a/packages/devtools-bundler-core/src/matcher.test.ts b/packages/devtools-bundler-core/src/matcher.test.ts index eced3535e..e5724b608 100644 --- a/packages/devtools-bundler-core/src/matcher.test.ts +++ b/packages/devtools-bundler-core/src/matcher.test.ts @@ -30,4 +30,24 @@ describe('matcher', () => { expect(matcher(patterns, 'src/components/ignored-file.jsx')).toBe(true) expect(matcher(patterns, 'src/components/other.jsx')).toBe(false) }) + + it('is deterministic across repeated calls with a g-flagged regex', () => { + const pattern = /\.test\.tsx$/g + for (let i = 0; i < 5; i++) { + expect(matcher([pattern], 'src/Foo.test.tsx')).toBe(true) + } + }) + + it('is deterministic across repeated calls with a y-flagged regex', () => { + const pattern = /\.test\.tsx$/y + for (let i = 0; i < 5; i++) { + expect(matcher([pattern], 'src/Foo.test.tsx')).toBe(true) + } + }) + + it('does not mutate the user-supplied regex lastIndex', () => { + const pattern = /\.test\.tsx$/g + expect(matcher([pattern], 'src/Foo.test.tsx')).toBe(true) + expect(pattern.lastIndex).toBe(0) + }) }) diff --git a/packages/devtools-bundler-core/src/matcher.ts b/packages/devtools-bundler-core/src/matcher.ts index 0098d7635..402171736 100644 --- a/packages/devtools-bundler-core/src/matcher.ts +++ b/packages/devtools-bundler-core/src/matcher.ts @@ -11,7 +11,10 @@ export const matcher = ( if (typeof pattern === 'string') { return picomatch(pattern) } else { - return (s: string) => pattern.test(s) + const re = /[gy]/.test(pattern.flags) + ? new RegExp(pattern.source, pattern.flags.replace(/[gy]/g, '')) + : pattern + return (s: string) => re.test(s) } })