Skip to content

Commit b518dc3

Browse files
committed
Test applying classes with a prefix configured
1 parent e03db68 commit b518dc3

File tree

2 files changed

+139
-40
lines changed

2 files changed

+139
-40
lines changed

__tests__/applyComplexClasses.test.js

Lines changed: 123 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -635,49 +635,138 @@ test('you can apply classes to rules within at-rules', () => {
635635
})
636636
})
637637

638-
test.skip('you can apply utility classes without using the given prefix', () => {
639-
const input = `
640-
.foo { @apply .tw-mt-4 .mb-4; }
641-
`
638+
describe('using apply with the prefix option', () => {
639+
test('applying a class including the prefix', () => {
640+
const input = `
641+
.foo { @apply tw-mt-4; }
642+
`
642643

643-
const expected = `
644-
.foo { margin-top: 1rem; margin-bottom: 1rem; }
645-
`
644+
const expected = `
645+
.foo { margin-top: 1rem; }
646+
`
646647

647-
const config = resolveConfig([
648-
{
649-
...defaultConfig,
650-
prefix: 'tw-',
651-
},
652-
])
648+
const config = resolveConfig([
649+
{
650+
...defaultConfig,
651+
prefix: 'tw-',
652+
},
653+
])
653654

654-
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
655-
expect(result.css).toMatchCss(expected)
656-
expect(result.warnings().length).toBe(0)
655+
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
656+
expect(result.css).toMatchCss(expected)
657+
expect(result.warnings().length).toBe(0)
658+
})
657659
})
658-
})
659660

660-
test.skip('you can apply utility classes without using the given prefix when using a function for the prefix', () => {
661-
const input = `
662-
.foo { @apply .tw-mt-4 .mb-4; }
663-
`
661+
test('applying a class including the prefix when using a prefix function', () => {
662+
const input = `
663+
.foo { @apply tw-func-mt-4; }
664+
`
664665

665-
const expected = `
666-
.foo { margin-top: 1rem; margin-bottom: 1rem; }
667-
`
666+
const expected = `
667+
.foo { margin-top: 1rem; }
668+
`
668669

669-
const config = resolveConfig([
670-
{
671-
...defaultConfig,
672-
prefix: () => {
673-
return 'tw-'
670+
const config = resolveConfig([
671+
{
672+
...defaultConfig,
673+
prefix: () => {
674+
return 'tw-func-'
675+
},
674676
},
675-
},
676-
])
677+
])
677678

678-
return run(input, config, processPlugins(corePlugins(config), config).utilities).then(result => {
679-
expect(result.css).toMatchCss(expected)
680-
expect(result.warnings().length).toBe(0)
679+
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
680+
expect(result.css).toMatchCss(expected)
681+
expect(result.warnings().length).toBe(0)
682+
})
683+
})
684+
685+
test('applying a class without the prefix fails', () => {
686+
const input = `
687+
.foo { @apply mt-4; }
688+
`
689+
690+
const config = resolveConfig([
691+
{
692+
...defaultConfig,
693+
prefix: 'tw-',
694+
},
695+
])
696+
697+
return run(input, config, () => processPlugins(corePlugins(config), config)).catch(e => {
698+
expect(e).toMatchObject({ name: 'CssSyntaxError' })
699+
})
700+
})
701+
702+
test('custom classes with no prefix can be applied', () => {
703+
const input = `
704+
.foo { @apply mt-4; }
705+
.mt-4 { color: red; }
706+
`
707+
708+
const expected = `
709+
.foo { color: red; }
710+
.mt-4 { color: red; }
711+
`
712+
713+
const config = resolveConfig([
714+
{
715+
...defaultConfig,
716+
prefix: 'tw-',
717+
},
718+
])
719+
720+
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
721+
expect(result.css).toMatchCss(expected)
722+
expect(result.warnings().length).toBe(0)
723+
})
724+
})
725+
726+
test('built-in prefixed utilities can be extended and applied', () => {
727+
const input = `
728+
.foo { @apply tw-mt-4; }
729+
.tw-mt-4 { color: red; }
730+
`
731+
732+
const expected = `
733+
.foo { margin-top: 1rem; color: red; }
734+
.tw-mt-4 { color: red; }
735+
`
736+
737+
const config = resolveConfig([
738+
{
739+
...defaultConfig,
740+
prefix: 'tw-',
741+
},
742+
])
743+
744+
return run(input, config, () => processPlugins(corePlugins(config), config)).then(result => {
745+
expect(result.css).toMatchCss(expected)
746+
expect(result.warnings().length).toBe(0)
747+
})
748+
})
749+
750+
test('a helpful error message is provided if it appears the user forgot to include their prefix', () => {
751+
const input = `
752+
.foo { @apply mt-4; }
753+
`
754+
755+
const config = resolveConfig([
756+
{
757+
...defaultConfig,
758+
prefix: 'tw-',
759+
},
760+
])
761+
762+
expect.assertions(1)
763+
764+
return run(input, config, () => processPlugins(corePlugins(config), config)).catch(e => {
765+
expect(e).toMatchObject({
766+
name: 'CssSyntaxError',
767+
reason: 'The `mt-4` class does not exist, but `tw-mt-4` does. Did you forget the prefix?',
768+
})
769+
})
681770
})
682771
})
683772

src/flagged/applyComplexClasses.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import substituteVariantsAtRules from '../lib/substituteVariantsAtRules'
77
import substituteResponsiveAtRules from '../lib/substituteResponsiveAtRules'
88
import convertLayerAtRulesToControlComments from '../lib/convertLayerAtRulesToControlComments'
99
import substituteScreenAtRules from '../lib/substituteScreenAtRules'
10+
import prefixSelector from '../util/prefixSelector'
1011

1112
function hasAtRule(css, atRule) {
1213
let foundAtRule = false
@@ -130,7 +131,7 @@ function mergeAdjacentRules(initialRule, rulesToInsert) {
130131
return rulesToInsert.filter(r => r.nodes.length > 0)
131132
}
132133

133-
function makeExtractUtilityRules(css) {
134+
function makeExtractUtilityRules(css, config) {
134135
const utilityMap = buildUtilityMap(css)
135136
const orderUtilityMap = _.fromPairs(
136137
_.flatMap(_.toPairs(utilityMap), ([_utilityName, utilities]) => {
@@ -142,8 +143,17 @@ function makeExtractUtilityRules(css) {
142143
return function(utilityNames, rule) {
143144
return _.flatMap(utilityNames, utilityName => {
144145
if (utilityMap[utilityName] === undefined) {
146+
// Look for prefixed utility in case the user has goofed
147+
const prefixedUtility = prefixSelector(config.prefix, `.${utilityName}`).slice(1)
148+
149+
if (utilityMap[prefixedUtility] !== undefined) {
150+
throw rule.error(
151+
`The \`${utilityName}\` class does not exist, but \`${prefixedUtility}\` does. Did you forget the prefix?`
152+
)
153+
}
154+
145155
throw rule.error(
146-
`The \`${utilityName}\` utility does not exist. If you're sure that \`${utilityName}\` exists, make sure that any \`@import\` statements are being properly processed before Tailwind CSS sees your CSS, as \`@apply\` can only be used for classes in the same CSS tree.`,
156+
`The \`${utilityName}\` class does not exist. If you're sure that \`${utilityName}\` exists, make sure that any \`@import\` statements are being properly processed before Tailwind CSS sees your CSS, as \`@apply\` can only be used for classes in the same CSS tree.`,
147157
{ word: utilityName }
148158
)
149159
}
@@ -154,8 +164,8 @@ function makeExtractUtilityRules(css) {
154164
}
155165
}
156166

157-
function processApplyAtRules(css, lookupTree) {
158-
const extractUtilityRules = makeExtractUtilityRules(lookupTree)
167+
function processApplyAtRules(css, lookupTree, config) {
168+
const extractUtilityRules = makeExtractUtilityRules(lookupTree, config)
159169

160170
while (hasAtRule(css, 'apply')) {
161171
css.walkRules(rule => {
@@ -225,7 +235,7 @@ export default function applyComplexClasses(config, getProcessedPlugins) {
225235
return function(css) {
226236
// Tree already contains @tailwind rules, don't prepend default Tailwind tree
227237
if (hasAtRule(css, 'tailwind')) {
228-
return processApplyAtRules(css, css)
238+
return processApplyAtRules(css, css, config)
229239
}
230240

231241
return postcss([
@@ -248,7 +258,7 @@ export default function applyComplexClasses(config, getProcessedPlugins) {
248258
// if css already contains tailwind, css is the lookup tree
249259
const lookupTree = _.tap(css.clone(), tree => tree.prepend(result.root))
250260

251-
return processApplyAtRules(css, lookupTree)
261+
return processApplyAtRules(css, lookupTree, config)
252262
})
253263
}
254264
}

0 commit comments

Comments
 (0)