From e37b665b6094196337a89c1798c2f2aa353053f7 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 14 Aug 2020 19:12:45 -0400 Subject: [PATCH] Support applying classes that occur multiple times in a single selector --- __tests__/applyComplexClasses.test.js | 32 +++++++++++++++++++++++++++ src/flagged/applyComplexClasses.js | 11 +++++---- 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/__tests__/applyComplexClasses.test.js b/__tests__/applyComplexClasses.test.js index 1793ffd84..c4dd5ce48 100644 --- a/__tests__/applyComplexClasses.test.js +++ b/__tests__/applyComplexClasses.test.js @@ -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; } diff --git a/src/flagged/applyComplexClasses.js b/src/flagged/applyComplexClasses.js index 6fe0232e6..d31355dc1 100644 --- a/src/flagged/applyComplexClasses.js +++ b/src/flagged/applyComplexClasses.js @@ -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, ]