From c5e7857362148aaadfa294f51da7d343c87e1199 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Mon, 20 Jun 2022 09:56:40 -0400 Subject: [PATCH] Detect arbitrary variants with quotes (#8687) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 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 --- CHANGELOG.md | 1 + src/lib/defaultExtractor.js | 60 +++++++++++++++++++------------- tests/arbitrary-variants.test.js | 34 ++++++++++++++++++ 3 files changed, 70 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d0540fa997e3..daa7ced662f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Provide default to `` when using `theme()` ([#8652](https://github.com/tailwindlabs/tailwindcss/pull/8652)) +- Detect arbitrary variants with quotes ([#8687](https://github.com/tailwindlabs/tailwindcss/pull/8687)) ## [3.1.3] - 2022-06-14 diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 4c28d007a047..1d631a48e1a5 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -64,31 +64,41 @@ function* buildRegExps(context) { ]), ]) - yield regex.pattern([ - // Variants - '((?=((', - regex.any( - [ - regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]), - regex.pattern([/[^\s"'`\[\\]+/, separator]), - ], - true - ), - ')+))\\2)?', - - // Important (optional) - /!?/, - - variantGroupingEnabled - ? regex.any([ - // Or any of those things but grouped separated by commas - regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]), - - // Arbitrary properties, constrained utilities, arbitrary values, etc… - utility, - ]) - : utility, - ]) + let variantPatterns = [ + // Without quotes + regex.any([ + regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`]+\]/, separator]), + regex.pattern([/[^\s"'`\[\\]+/, separator]), + ]), + + // With quotes allowed + regex.any([ + regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s`]+\]/, separator]), + regex.pattern([/[^\s`\[\\]+/, separator]), + ]), + ] + + for (const variantPattern of variantPatterns) { + yield regex.pattern([ + // Variants + '((?=((', + variantPattern, + ')+))\\2)?', + + // Important (optional) + /!?/, + + variantGroupingEnabled + ? regex.any([ + // Or any of those things but grouped separated by commas + regex.pattern([/\(/, utility, regex.zeroOrMore([/,/, utility]), /\)/]), + + // Arbitrary properties, constrained utilities, arbitrary values, etc… + utility, + ]) + : utility, + ]) + } // 5. Inner matches yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g diff --git a/tests/arbitrary-variants.test.js b/tests/arbitrary-variants.test.js index d0f7d85b5482..a42300c4c53c 100644 --- a/tests/arbitrary-variants.test.js +++ b/tests/arbitrary-variants.test.js @@ -493,3 +493,37 @@ test('keeps escaped underscores in arbitrary variants mixed with normal variants `) }) }) + +test('allows attribute variants with quotes', () => { + let config = { + content: [ + { + raw: ` +
+
+ `, + }, + ], + corePlugins: { preflight: false }, + } + + let input = ` + @tailwind base; + @tailwind components; + @tailwind utilities; + ` + + return run(input, config).then((result) => { + expect(result.css).toMatchFormattedCss(css` + ${defaults} + + .\[\&\[data-test\=\'2\'\]\]\:underline[data-test="2"] { + text-decoration-line: underline; + } + + .\[\&\[data-test\=\"2\"\]\]\:underline[data-test='2'] { + text-decoration-line: underline; + } + `) + }) +})