Support applying classes that occur multiple times in a single selector

This commit is contained in:
Adam Wathan 2020-08-14 19:12:45 -04:00
parent 6fe745b908
commit e37b665b60
2 changed files with 39 additions and 4 deletions

View File

@ -247,6 +247,38 @@ test('it matches classes that have multiple rules', () => {
})
})
test('applying a class that appears multiple times in one selector', () => {
const input = `
.a + .a > .a {
color: red;
}
.b {
@apply a;
}
`
const output = `
.a + .a > .a {
color: red;
}
.b + .a > .a {
color: red;
}
.a + .b > .a {
color: red;
}
.a + .a > .b {
color: red;
}
`
return run(input).then(result => {
expect(result.css).toMatchCss(output)
expect(result.warnings().length).toBe(0)
})
})
test('you can apply utility classes that do not actually exist as long as they would exist if utilities were being generated', () => {
const input = `
.foo { @apply mt-4; }

View File

@ -20,13 +20,15 @@ function hasAtRule(css, atRule) {
return foundAtRule
}
function applyUtility(rule, className, replaceWith) {
function applyUtility({ rule, utilityName: className, classPosition }, replaceWith) {
const processedSelectors = rule.selectors.map(selector => {
const processor = selectorParser(selectors => {
let i = 0
selectors.walkClasses(c => {
if (c.value === className) {
if (c.value === className && classPosition === i) {
c.replaceWith(selectorParser.attribute({ attribute: '__TAILWIND-APPLY-PLACEHOLDER__' }))
}
i++
})
})
@ -78,7 +80,7 @@ function buildUtilityMap(css) {
css.walkRules(rule => {
const utilityNames = extractUtilityNames(rule.selector)
utilityNames.forEach(utilityName => {
utilityNames.forEach((utilityName, i) => {
if (utilityMap[utilityName] === undefined) {
utilityMap[utilityName] = []
}
@ -86,6 +88,7 @@ function buildUtilityMap(css) {
utilityMap[utilityName].push({
index,
utilityName,
classPosition: i,
rule: rule.clone({ parent: rule.parent }),
containsApply: hasAtRule(rule, 'apply'),
})
@ -205,7 +208,7 @@ function processApplyAtRules(css, lookupTree, config) {
// Get new rules with the utility portion of the selector replaced with the new selector
const rulesToInsert = [
...injects.map(injectUtility => {
return applyUtility(injectUtility.rule, injectUtility.utilityName, rule.selector)
return applyUtility(injectUtility, rule.selector)
}),
afterRule,
]