Skip to content

Commit 7cc2d89

Browse files
thecrypticaceRobinMalfaitadamwathan
authored
Fix non-deterministic variant sorting (#14835)
Right now our variant sorting is sensitive to the authoring order of classes or the order in which we scan files because we weren't comparing variant values when sorting. This PR addresses this by: - "default" values in variants appear first - Then any named values - Then any arbitrary values - Finally, compare the values themselves when all else is equal --------- Co-authored-by: Robin Malfait <malfait.robin@gmail.com> Co-authored-by: Adam Wathan <4323180+adamwathan@users.noreply.github.com> Co-authored-by: Adam Wathan <adam.wathan@gmail.com>
1 parent 0b5736f commit 7cc2d89

File tree

5 files changed

+248
-83
lines changed

5 files changed

+248
-83
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Detect classes in new files when using `@tailwindcss/postcss` ([#14829](https://github.com/tailwindlabs/tailwindcss/pull/14829))
1313
- Fix crash when using `@source` containing `..` ([#14831](https://github.com/tailwindlabs/tailwindcss/pull/14831))
14+
- Ensure instances of the same variant with different values are always sorted deterministically (e.g. `data-focus:flex` and `data-active:flex`) ([#14835](https://github.com/tailwindlabs/tailwindcss/pull/14835))
1415
- _Upgrade (experimental)_: Install `@tailwindcss/postcss` next to `tailwindcss` ([#14830](https://github.com/tailwindlabs/tailwindcss/pull/14830))
1516
- _Upgrade (experimental)_: Remove whitespace around `,` separator when print arbitrary values ([#14838](https://github.com/tailwindlabs/tailwindcss/pull/14838))
1617

packages/tailwindcss/src/compat/config.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1109,16 +1109,16 @@ test('creates variants for `data`, `supports`, and `aria` theme options at the s
11091109
'print:flex',
11101110
]),
11111111
).toMatchInlineSnapshot(`
1112-
".aria-polite\\:underline {
1113-
&[aria-live="polite"] {
1114-
text-decoration-line: underline;
1115-
}
1116-
}
1117-
.aria-hidden\\:flex {
1112+
".aria-hidden\\:flex {
11181113
&[aria-hidden="true"] {
11191114
display: flex;
11201115
}
11211116
}
1117+
.aria-polite\\:underline {
1118+
&[aria-live="polite"] {
1119+
text-decoration-line: underline;
1120+
}
1121+
}
11221122
.data-checked\\:underline {
11231123
&[data-ui~="checked"] {
11241124
text-decoration-line: underline;

packages/tailwindcss/src/compat/plugin-api.ts

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,12 @@ export function buildPluginApi(
156156
if (a.kind !== 'functional' || z.kind !== 'functional') {
157157
return 0
158158
}
159-
if (!a.value || !z.value) {
160-
return 0
161-
}
162159

163-
let aValue = options?.values?.[a.value.value] ?? a.value.value
164-
let zValue = options?.values?.[z.value.value] ?? z.value.value
160+
let aValueKey = a.value ? a.value.value : 'DEFAULT'
161+
let zValueKey = z.value ? z.value.value : 'DEFAULT'
162+
163+
let aValue = options?.values?.[aValueKey] ?? aValueKey
164+
let zValue = options?.values?.[zValueKey] ?? zValueKey
165165

166166
if (options && typeof options.sort === 'function') {
167167
return options.sort(
@@ -170,11 +170,19 @@ export function buildPluginApi(
170170
)
171171
}
172172

173-
let aOrder = defaultOptionKeys.indexOf(a.value.value)
174-
let zOrder = defaultOptionKeys.indexOf(z.value.value)
173+
let aOrder = defaultOptionKeys.indexOf(aValueKey)
174+
let zOrder = defaultOptionKeys.indexOf(zValueKey)
175+
176+
// Sort arbitrary values after configured values
177+
aOrder = aOrder === -1 ? defaultOptionKeys.length : aOrder
178+
zOrder = zOrder === -1 ? defaultOptionKeys.length : zOrder
179+
180+
if (aOrder !== zOrder) return aOrder - zOrder
175181

176-
if (aOrder - zOrder === 0) return aValue < zValue ? -1 : 1
177-
return aOrder - zOrder
182+
// SAFETY: The values don't need to be checked for equality as they
183+
// are guaranteed to be unique since we sort a list of de-duped
184+
// variants and different (valid) variants cannot produce the same AST.
185+
return aValue < zValue ? -1 : 1
178186
},
179187
)
180188
},

0 commit comments

Comments
 (0)