Skip to content
This repository was archived by the owner on Apr 6, 2021. It is now read-only.

Commit 63a0e75

Browse files
committed
Fix bug where exact match in user CSS prevented generated utility match
1 parent 2cff200 commit 63a0e75

File tree

5 files changed

+48
-40
lines changed

5 files changed

+48
-40
lines changed

src/index.test.css

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,9 @@ div {
225225
* {
226226
padding: 5px;
227227
}
228+
.foo .bg-black {
229+
appearance: none;
230+
}
228231
.mt-6 {
229232
margin-top: 1.5rem;
230233
}
@@ -247,6 +250,10 @@ div {
247250
.grid-cols-\[200px\,repeat\(auto-fill\,minmax\(15\%\,100px\)\)\,300px\] {
248251
grid-template-columns: 200px repeat(auto-fill, minmax(15%, 100px)) 300px;
249252
}
253+
.bg-black {
254+
--tw-bg-opacity: 1;
255+
background-color: rgba(0, 0, 0, var(--tw-bg-opacity));
256+
}
250257
.bg-green-500 {
251258
--tw-bg-opacity: 1;
252259
background-color: rgba(16, 185, 129, var(--tw-bg-opacity));

src/index.test.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
></div>
1515
<div class="grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px]"></div>
1616
<div class="mt-6"></div>
17+
<div class="bg-black"></div>
1718
<div class="custom-util"></div>
1819
<div class="hover:custom-util"></div>
1920
<div class="group-hover:custom-util"></div>

src/index.test.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ test('it works', () => {
8080
* {
8181
padding: 5px;
8282
}
83+
.foo .bg-black {
84+
appearance: none;
85+
}
8386
}
8487
@layer base {
8588
div {

src/lib/expandApplyAtRules.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ function buildApplyCache(applyCandidates, context) {
1414
continue
1515
}
1616

17-
let matches = resolveMatches(candidate, context)
17+
let matches = Array.from(resolveMatches(candidate, context))
1818

1919
if (matches.length === 0) {
2020
context.notClassCache.add(candidate)

src/lib/generateRules.js

Lines changed: 36 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,17 @@ function getClassNameFromSelector(selector) {
1717
// ['ring-offset', 'blue-100']
1818
// ['ring', 'offset-blue-100']
1919
function* candidatePermutations(prefix, modifier = '') {
20-
yield [prefix, modifier]
21-
2220
let dashIdx = prefix.lastIndexOf('-')
2321
if (dashIdx === -1) {
2422
return
2523
}
2624

27-
yield* candidatePermutations(
28-
prefix.slice(0, dashIdx),
29-
[prefix.slice(dashIdx + 1), modifier].filter(Boolean).join('-')
30-
)
25+
modifier = [prefix.slice(dashIdx + 1), modifier].filter(Boolean).join('-')
26+
prefix = prefix.slice(0, dashIdx)
27+
28+
yield [prefix, modifier]
29+
30+
yield* candidatePermutations(prefix, modifier)
3131
}
3232

3333
// Takes a list of rule tuples and applies a variant like `hover`, sm`,
@@ -109,9 +109,9 @@ function parseRules(rule, cache, options = {}) {
109109
return [cache.get(rule), options]
110110
}
111111

112-
function resolveMatchedPlugins(classCandidate, context) {
112+
function* resolveMatchedPlugins(classCandidate, context) {
113113
if (context.candidateRuleMap.has(classCandidate)) {
114-
return [context.candidateRuleMap.get(classCandidate), 'DEFAULT']
114+
yield [context.candidateRuleMap.get(classCandidate), 'DEFAULT']
115115
}
116116

117117
let candidatePrefix = classCandidate
@@ -124,11 +124,10 @@ function resolveMatchedPlugins(classCandidate, context) {
124124

125125
for (let [prefix, modifier] of candidatePermutations(candidatePrefix)) {
126126
if (context.candidateRuleMap.has(prefix)) {
127-
return [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
127+
yield [context.candidateRuleMap.get(prefix), negative ? `-${modifier}` : modifier]
128+
return
128129
}
129130
}
130-
131-
return null
132131
}
133132

134133
function sortAgainst(toSort, against) {
@@ -137,55 +136,53 @@ function sortAgainst(toSort, against) {
137136
})
138137
}
139138

140-
function resolveMatches(candidate, context) {
139+
function* resolveMatches(candidate, context) {
141140
let [classCandidate, ...variants] = candidate.split(':').reverse()
142141

143142
// Strip prefix
144143
// md:hover:tw-bg-black
145144

146-
let matchedPlugins = resolveMatchedPlugins(classCandidate, context)
147-
148145
// TODO: Reintroduce this in ways that doesn't break on false positives
149146
// let sorted = sortAgainst(variants, context.variantMap)
150147
// if (sorted.toString() !== variants.toString()) {
151148
// let corrected = sorted.reverse().concat(classCandidate).join(':')
152149
// throw new Error(`Class ${candidate} should be written as ${corrected}`)
153150
// }
154151

155-
if (matchedPlugins === null) {
156-
return []
157-
}
158-
159-
let pluginHelpers = {
160-
candidate: classCandidate,
161-
theme: context.tailwindConfig.theme,
162-
}
152+
for (let matchedPlugins of resolveMatchedPlugins(classCandidate, context)) {
153+
let pluginHelpers = {
154+
candidate: classCandidate,
155+
theme: context.tailwindConfig.theme,
156+
}
163157

164-
let matches = []
165-
let [plugins, modifier] = matchedPlugins
158+
let matches = []
159+
let [plugins, modifier] = matchedPlugins
166160

167-
for (let [sort, plugin] of plugins) {
168-
if (typeof plugin === 'function') {
169-
for (let ruleSet of [].concat(plugin(modifier, pluginHelpers))) {
161+
for (let [sort, plugin] of plugins) {
162+
if (typeof plugin === 'function') {
163+
for (let ruleSet of [].concat(plugin(modifier, pluginHelpers))) {
164+
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
165+
for (let rule of rules) {
166+
matches.push([{ ...sort, options }, rule])
167+
}
168+
}
169+
} else {
170+
let ruleSet = plugin
170171
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
171172
for (let rule of rules) {
172173
matches.push([{ ...sort, options }, rule])
173174
}
174175
}
175-
} else {
176-
let ruleSet = plugin
177-
let [rules, options] = parseRules(ruleSet, context.postCssNodeCache)
178-
for (let rule of rules) {
179-
matches.push([{ ...sort, options }, rule])
180-
}
181176
}
182-
}
183177

184-
for (let variant of variants) {
185-
matches = applyVariant(variant, matches, context)
186-
}
178+
for (let variant of variants) {
179+
matches = applyVariant(variant, matches, context)
180+
}
187181

188-
return matches
182+
for (let match of matches) {
183+
yield match
184+
}
185+
}
189186
}
190187

191188
function generateRules(candidates, context) {
@@ -201,7 +198,7 @@ function generateRules(candidates, context) {
201198
continue
202199
}
203200

204-
let matches = resolveMatches(candidate, context)
201+
let matches = Array.from(resolveMatches(candidate, context))
205202

206203
// apply prefix and important here?
207204

0 commit comments

Comments
 (0)