Fix wildcard duplication issue (#7478)

This would be better as a symbol but the stringy-ness of class candidates is fairly well baked into assumptions across the codebase. Using `new String` with a well placed check seems to solve the problem.
This commit is contained in:
Jordan Pittman 2022-02-15 13:44:19 -05:00 • committed by GitHub
parent db475be6dd
commit be5d5c9e66
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 5 deletions

View file

@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Remove opacity variables from `:visited` pseudo class ([#7458](https://github.com/tailwindlabs/tailwindcss/pull/7458))
- Support arbitrary values + calc + theme with quotes ([#7462](https://github.com/tailwindlabs/tailwindcss/pull/7462))
- Don't duplicate layer output when scanning content with variants + wildcards ([#7478](https://github.com/tailwindlabs/tailwindcss/pull/7478))
## [3.0.22] - 2022-02-11

View file

@ -158,7 +158,7 @@ export default function expandTailwindAtRules(context) {
// ---
// Find potential rules in changed files
let candidates = new Set(['*'])
let candidates = new Set([sharedState.NOT_ON_DEMAND])
let seen = new Set()
env.DEBUG && console.time('Reading changed files')

View file

@ -5,6 +5,7 @@ import isPlainObject from '../util/isPlainObject'
import prefixSelector from '../util/prefixSelector'
import { updateAllClasses } from '../util/pluginUtils'
import log from '../util/log'
import * as sharedState from './sharedState'
import { formatVariantSelector, finalizeSelector } from '../util/formatVariantSelector'
import { asClass } from '../util/nameClass'
import { normalize } from '../util/dataTypes'
@ -382,6 +383,10 @@ function* resolveMatchedPlugins(classCandidate, context) {
}
function splitWithSeparator(input, separator) {
if (input === sharedState.NOT_ON_DEMAND) {
return [sharedState.NOT_ON_DEMAND]
}
return input.split(new RegExp(`\\${separator}(?![^[]*\\])`, 'g'))
}

View file

@ -138,7 +138,7 @@ function withIdentifiers(styles) {
// If this isn't "on-demandable", assign it a universal candidate to always include it.
if (containsNonOnDemandableSelectors) {
candidates.unshift('*')
candidates.unshift(sharedState.NOT_ON_DEMAND)
}
// However, it could be that it also contains "on-demandable" candidates.
@ -163,8 +163,8 @@ function buildPluginApi(tailwindConfig, context, { variantList, variantMap, offs
}
function prefixIdentifier(identifier, options) {
if (identifier === '*') {
return '*'
if (identifier === sharedState.NOT_ON_DEMAND) {
return sharedState.NOT_ON_DEMAND
}
if (!options.respectPrefix) {

View file

@ -5,6 +5,7 @@ export const env = {
export const contextMap = new Map()
export const configContextMap = new Map()
export const contextSourcesMap = new Map()
export const NOT_ON_DEMAND = new String('*')
export function resolveDebug(debug) {
if (debug === undefined) {

View file

@ -1,7 +1,7 @@
import fs from 'fs'
import path from 'path'
import { html, run, css } from './util/run'
import { html, run, css, defaults } from './util/run'
test('basic usage', () => {
let config = {
@ -188,3 +188,64 @@ it('can scan extremely long classes without crashing', () => {
expect(result.css).toMatchFormattedCss(css``)
})
})
it('does not produce duplicate output when seeing variants preceding a wildcard (*)', () => {
let config = {
content: [{ raw: html`underline focus:*` }],
corePlugins: { preflight: false },
}
let input = css`
@tailwind base;
@tailwind components;
@tailwind utilities;
* {
color: red;
}
.combined,
* {
text-align: center;
}
@layer base {
* {
color: blue;
}
.combined,
* {
color: red;
}
}
`
return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
* {
color: blue;
}
.combined,
* {
color: red;
}
${defaults}
.underline {
text-decoration-line: underline;
}
* {
color: red;
}
.combined,
* {
text-align: center;
}
`)
})
})