Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions .changeset/devtools-bundler-core-stateful-regex.md
Original file line number Diff line number Diff line change
@@ -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.
20 changes: 20 additions & 0 deletions packages/devtools-bundler-core/src/matcher.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
})
5 changes: 4 additions & 1 deletion packages/devtools-bundler-core/src/matcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
})

Expand Down