Fix generation of div:not(.foo) if .foo is never defined (#7815)

* fix little typo

* ensure that `div:not(.unknown-class)` gets generated

* update changelog
This commit is contained in:
Robin Malfait 2022-03-17 16:35:40 +01:00 committed by GitHub
parent 7b4cc36f5e
commit 48728ed5d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 48 additions and 6 deletions

View File

@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Correctly parse and prefix animation names with dots ([#7163](https://github.com/tailwindlabs/tailwindcss/pull/7163))
- Fix extraction from template literal/function with array ([#7481](https://github.com/tailwindlabs/tailwindcss/pull/7481))
- Don't output unparsable arbitrary values ([#7789](https://github.com/tailwindlabs/tailwindcss/pull/7789))
- Fix generation of `div:not(.foo)` if `.foo` is never defined ([#7815](https://github.com/tailwindlabs/tailwindcss/pull/7815))
### Changed

View File

@ -85,12 +85,18 @@ function parseStyles(styles) {
})
}
function getClasses(selector) {
function getClasses(selector, mutate) {
let parser = selectorParser((selectors) => {
let allClasses = []
if (mutate) {
mutate(selectors)
}
selectors.walkClasses((classNode) => {
allClasses.push(classNode.value)
})
return allClasses
})
return parser.transformSync(selector)
@ -101,8 +107,20 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
// Handle normal rules
if (node.type === 'rule') {
// Ignore everything inside a :not(...). This allows you to write code like
// `div:not(.foo)`. If `.foo` is never found in your code, then we used to
// not generated it. But now we will ignore everything inside a `:not`, so
// that it still gets generated.
function ignoreNot(selectors) {
selectors.walkPseudos((pseudo) => {
if (pseudo.value === ':not') {
pseudo.remove()
}
})
}
for (let selector of node.selectors) {
let classCandidates = getClasses(selector)
let classCandidates = getClasses(selector, ignoreNot)
// At least one of the selectors contains non-"on-demandable" candidates.
if (classCandidates.length === 0) {
state.containsNonOnDemandable = true
@ -117,9 +135,7 @@ function extractCandidates(node, state = { containsNonOnDemandable: false }, dep
// Handle at-rules (which contains nested rules)
else if (node.type === 'atrule') {
node.walkRules((rule) => {
for (let classCandidate of rule.selectors.flatMap((selector) =>
getClasses(selector, state, depth + 1)
)) {
for (let classCandidate of rule.selectors.flatMap((selector) => getClasses(selector))) {
classes.push(classCandidate)
}
})

View File

@ -349,7 +349,7 @@ it('does not produce duplicate output when seeing variants preceding a wildcard
})
})
it('it can parse box shadows with variables', () => {
it('can parse box shadows with variables', () => {
let config = {
content: [{ raw: html`<div class="shadow-lg"></div>` }],
theme: {
@ -376,3 +376,28 @@ it('it can parse box shadows with variables', () => {
`)
})
})
it('should generate styles using :not(.unknown-class) even if `.unknown-class` does not exist', () => {
let config = {
content: [{ raw: html`<div></div>` }],
corePlugins: { preflight: false },
}
let input = css`
@tailwind components;
@layer components {
div:not(.unknown-class) {
color: red;
}
}
`
return run(input, config).then((result) => {
expect(result.css).toMatchFormattedCss(css`
div:not(.unknown-class) {
color: red;
}
`)
})
})