A utility-first CSS framework for rapid UI development.
fix(canonicalize): prevent collapse cache pollution across calls (#19675)
## Summary
fixes
https://github.com/schoero/eslint-plugin-better-tailwindcss/issues/321
This PR fixes an order-sensitive canonicalization bug. This bug caused
issues when running eslint-plugin-better-tailwindcss as the order in
which files are linted in is not consistent. This caused, in some
scenarios, `canonicalizeCandidates(..., { collapse: true,
logicalToPhysical: true, rem: 16 })` to stop collapsing valid
combinations (for example `h-4 + w-4 -> size-4`) after unrelated prior
calls.
To reproduce this issue:
```
# checkout this branch
$ git checkout c/fix-canonicalizeCandidates
# Revert the fix to the current `main` branch
$ git checkout main ./packages/tailwindcss/src/canonicalize-candidates.ts
# Run the tests
$ pnpm run test
```
This should produce a failure like so:
```
FAIL tailwindcss src/canonicalize-candidates.test.ts > regressions > collapse canonicalization is not affected by previous calls
AssertionError: expected [ 'underline', 'h-4', 'w-4' ] to deeply equal [ 'underline', 'size-4' ]
- Expected
+ Received
[
"underline",
- "size-4",
+ "h-4",
+ "w-4",
]
❯ src/canonicalize-candidates.test.ts:1167:66
1165| designSystem.canonicalizeCandidates(['underline', 'mb-4'], options)
1166|
1167| expect(designSystem.canonicalizeCandidates(target, options)).toEqual(['underline', 'size-4'])
| ^
1168| })
1169| })
```
```
# reset all changes on this branch
git reset --hard
# run the tests again (they should now pass)
pnpm run test
```
The cause of this bug is that the canonicalization caches used
`DefaultMap` in places where lookups were expected to be read-only.
`DefaultMap.get` inserts missing entried, which mutated shared cache
state during intermediate lookups and made later canonicalization
results depend on prior calls.
By replacing the use of `DefaultMap` with a plain `Map`, it avoids
inserting into the map on lookup paths. I've polyfilled
[`Map#getOrInsert`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map/getOrInsert)
as it is not widely available yet, and used that where appropriate.
## Test plan
I wrote a test that fails on `main` branch, I then fixed the issue, and
validated that the test now passes.
---------
Co-authored-by: Robin Malfait <malfait.robin@gmail.com> C
Cameron committed
5a4a7eba3a3db4f4a834f37a3e37624fe9c4daa7
Parent: d520e1f
Committed by GitHub <noreply@github.com>
on 2/18/2026, 12:16:59 PM