Skip to content

Commit c5e7857

Browse files
Detect arbitrary variants with quotes (#8687)
* Refactor * Support variants with quotes in them We have to have two regexes here because this is actually ambiguous in the general case. The regex that generally handles `[&[foo='bar']]` would incorrectly match `['bar':'baz']` for instance. So, instead we’ll use multiple regexes and match both! * Update changelog
1 parent 77c248c commit c5e7857

File tree

3 files changed

+70
-25
lines changed

3 files changed

+70
-25
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Fixed
1111

1212
- Provide default to `<alpha-value>` when using `theme()` ([#8652](https://github.com/tailwindlabs/tailwindcss/pull/8652))
13+
- Detect arbitrary variants with quotes ([#8687](https://github.com/tailwindlabs/tailwindcss/pull/8687))
1314

1415
## [3.1.3] - 2022-06-14
1516

src/lib/defaultExtractor.js

+35-25
Original file line numberDiff line numberDiff line change
@@ -64,31 +64,41 @@ function* buildRegExps(context) {
6464
]),
6565
])
6666

67-
yield regex.pattern([
68-
// Variants
69-
'((?=((',
70-
regex.any(
71-
[
72-
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]),
73-
regex.pattern([/[^\s"'`\[\\]+/, separator]),
74-
],
75-
true
76-
),
77-
')+))\\2)?',
78-
79-
// Important (optional)
80-
/!?/,
81-
82-
variantGroupingEnabled
83-
? regex.any([
84-
// Or any of those things but grouped separated by commas
85-
regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]),
86-
87-
// Arbitrary properties, constrained utilities, arbitrary values, etc…
88-
utility,
89-
])
90-
: utility,
91-
])
67+
let variantPatterns = [
68+
// Without quotes
69+
regex.any([
70+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]),
71+
regex.pattern([/[^\s"'`\[\\]+/, separator]),
72+
]),
73+
74+
// With quotes allowed
75+
regex.any([
76+
regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]),
77+
regex.pattern([/[^\s`\[\\]+/, separator]),
78+
]),
79+
]
80+
81+
for (const variantPattern of variantPatterns) {
82+
yield regex.pattern([
83+
// Variants
84+
'((?=((',
85+
variantPattern,
86+
')+))\\2)?',
87+
88+
// Important (optional)
89+
/!?/,
90+
91+
variantGroupingEnabled
92+
? regex.any([
93+
// Or any of those things but grouped separated by commas
94+
regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]),
95+
96+
// Arbitrary properties, constrained utilities, arbitrary values, etc…
97+
utility,
98+
])
99+
: utility,
100+
])
101+
}
92102

93103
// 5. Inner matches
94104
yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g

tests/arbitrary-variants.test.js

+34
Original file line numberDiff line numberDiff line change
@@ -493,3 +493,37 @@ test('keeps escaped underscores in arbitrary variants mixed with normal variants
493493
`)
494494
})
495495
})
496+
497+
test('allows attribute variants with quotes', () => {
498+
let config = {
499+
content: [
500+
{
501+
raw: `
502+
<div class="[&[data-test='2']]:underline"></div>
503+
<div class='[&[data-test="2"]]:underline'></div>
504+
`,
505+
},
506+
],
507+
corePlugins: { preflight: false },
508+
}
509+
510+
let input = `
511+
@tailwind base;
512+
@tailwind components;
513+
@tailwind utilities;
514+
`
515+
516+
return run(input, config).then((result) => {
517+
expect(result.css).toMatchFormattedCss(css`
518+
${defaults}
519+
520+
.\[\&\[data-test\=\'2\'\]\]\:underline[data-test="2"] {
521+
text-decoration-line: underline;
522+
}
523+
524+
.\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'] {
525+
text-decoration-line: underline;
526+
}
527+
`)
528+
})
529+
})

0 commit comments

Comments
 (0)