Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional safelist regex variations #7674

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
60 changes: 50 additions & 10 deletions src/lib/setupContextUtils.js
Expand Up @@ -638,15 +638,6 @@ function registerPlugins(plugins, context) {
continue
}

if (value instanceof RegExp) {
log.warn('root-regex', [
'Regular expressions in `safelist` work differently in Tailwind CSS v3.0.',
'Update your `safelist` configuration to eliminate this warning.',
'https://tailwindcss.com/docs/content-configuration#safelisting-classes',
])
continue
}

checks.push(value)
}

Expand Down Expand Up @@ -683,7 +674,42 @@ function registerPlugins(plugins, context) {
: [util]

for (let util of utils) {
for (let { pattern, variants = [] } of checks) {
for (let check of checks) {
let [pattern = /(?:)/, variants = [], opacities = []] = (() => {
if (check instanceof RegExp) {
return [check]
}

if (Array.isArray(check)) {
if (check.length == 1) {
return check
}

if (check.length == 2) {
if (check[1] instanceof RegExp) {
let [variants, pattern] = check
return [pattern, variants]
}

let [pattern, opacities] = check
return [pattern, [], opacities]
}

if (check.length == 3) {
let [variants, pattern, opacities] = check
return [pattern, variants, opacities]
}

throw new Error(
`Array values in your Tailwind CSS \`safelist\` must contain 1–3 items, found invalid entry containing ${check.length}.`
)
}

// Check must be an object in the shape of { pattern: ..., variants: ... }
let { pattern, variants = [] } = check
return [pattern, variants]
})()

// RegExp with the /g flag are stateful, so let's reset the last
// index pointer to reset the state.
pattern.lastIndex = 0
Expand All @@ -702,6 +728,20 @@ function registerPlugins(plugins, context) {
content: variant + context.tailwindConfig.separator + util,
extension: 'html',
})

for (let opacity of opacities) {
context.changedContent.push({
content: variant + context.tailwindConfig.separator + util + '/' + opacity,
extension: 'html',
})
}
}

for (let opacity of opacities) {
context.changedContent.push({
content: util + '/' + opacity,
extension: 'html',
})
}
}
}
Expand Down
129 changes: 129 additions & 0 deletions tests/safelist.test.js
Expand Up @@ -86,6 +86,135 @@ it('should safelist based on a pattern regex', () => {
})
})

it('should safelist based on a regex', () => {
let config = {
content: [{ raw: html`<div class="uppercase"></div>` }],
safelist: [/bg-(red)-(100|200)/],
}

return run('@tailwind utilities', config).then((result) => {
return expect(result.css).toMatchCss(css`
.bg-red-100 {
--tw-bg-opacity: 1;
background-color: rgb(254 226 226 / var(--tw-bg-opacity));
}

.bg-red-200 {
--tw-bg-opacity: 1;
background-color: rgb(254 202 202 / var(--tw-bg-opacity));
}

.uppercase {
text-transform: uppercase;
}
`)
})
})

it('should safelist based on a tuple with regex', () => {
let config = {
content: [{ raw: html`<div class="uppercase"></div>` }],
safelist: [
[/bg-(red)-(100|200)/],
[['hover'], /bg-(blue)-(100|200)/],
[/bg-(green)-(100|200)/, ['50']],
[['hover'], /bg-(yellow)-(100|200)/, ['50']],
],
}

return run('@tailwind utilities', config).then((result) => {
return expect(result.css).toMatchCss(css`
.bg-red-100 {
--tw-bg-opacity: 1;
background-color: rgb(254 226 226 / var(--tw-bg-opacity));
}

.bg-red-200 {
--tw-bg-opacity: 1;
background-color: rgb(254 202 202 / var(--tw-bg-opacity));
}

.bg-yellow-100 {
--tw-bg-opacity: 1;
background-color: rgb(254 249 195 / var(--tw-bg-opacity));
}

.bg-yellow-100\/50 {
background-color: rgb(254 249 195 / 0.5);
}

.bg-yellow-200 {
--tw-bg-opacity: 1;
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
}

.bg-yellow-200\/50 {
background-color: rgb(254 240 138 / 0.5);
}

.bg-green-100 {
--tw-bg-opacity: 1;
background-color: rgb(220 252 231 / var(--tw-bg-opacity));
}

.bg-green-100\/50 {
background-color: rgb(220 252 231 / 0.5);
}

.bg-green-200 {
--tw-bg-opacity: 1;
background-color: rgb(187 247 208 / var(--tw-bg-opacity));
}

.bg-green-200\/50 {
background-color: rgb(187 247 208 / 0.5);
}

.bg-blue-100 {
--tw-bg-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
}

.bg-blue-200 {
--tw-bg-opacity: 1;
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
}

.uppercase {
text-transform: uppercase;
}

.hover\:bg-yellow-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(254 249 195 / var(--tw-bg-opacity));
}

.hover\:bg-yellow-100\/50:hover {
background-color: rgb(254 249 195 / 0.5);
}

.hover\:bg-yellow-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(254 240 138 / var(--tw-bg-opacity));
}

.hover\:bg-yellow-200\/50:hover {
background-color: rgb(254 240 138 / 0.5);
}

.hover\:bg-blue-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(219 234 254 / var(--tw-bg-opacity));
}

.hover\:bg-blue-200:hover {
--tw-bg-opacity: 1;
background-color: rgb(191 219 254 / var(--tw-bg-opacity));
}
`)
})
})

it('should not generate duplicates', () => {
let config = {
content: [{ raw: html`<div class="uppercase"></div>` }],
Expand Down