Repository: tailwindlabs/tailwindcss (TypeScript)

Issue:
Tailwind 3.1 regression: No longer keeps classes mentioned in markdown backticks
**What version of Tailwind CSS are you using?**

For example: v3.1.0

**What build tool (or framework if it abstracts the build tool) are you using?**

- parcel
- tailwindcss play

**What version of Node.js are you using?**

For example: v16.14.2

**What browser are you using?**

For example: Firefox

**What operating system are you using?**

For example: OpenSUSE linux

**Reproduction URL**

https://play.tailwindcss.com/XRYewVE3SL

**Describe your issue**

Check `Generated CSS` -> `Components`. 

The classes `.alert-success` `.alert-info` `.alert-failure` are missing in TailwindCSS 3.1, but are rendered in TailwindCSS 3.0 and earlier. This is a 3.1.0 regression.

Removing the backticks around the class names (but keeping the leading `.`) in the HTML comment makes the classes get rendered in TailwindCSS 3.1 as well.

**Note**

This might have the same root cause as #8557 has.



Hints:

Patch:
diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js
--- a/src/lib/defaultExtractor.js
+++ b/src/lib/defaultExtractor.js
@@ -25,7 +25,7 @@ function* buildRegExps(context) {
 
   let utility = regex.any([
     // Arbitrary properties
-    /\[[^\s:'"]+:[^\s\]]+\]/,
+    /\[[^\s:'"`]+:[^\s\]]+\]/,
 
     // Utilities
     regex.pattern([
@@ -43,7 +43,7 @@ function* buildRegExps(context) {
             /(?![{([]])/,
 
             // optionally followed by an opacity modifier
-            /(?:\/[^\s'"\\><$]*)?/,
+            /(?:\/[^\s'"`\\><$]*)?/,
           ]),
 
           regex.pattern([
@@ -54,11 +54,11 @@ function* buildRegExps(context) {
             /(?![{([]])/,
 
             // optionally followed by an opacity modifier
-            /(?:\/[^\s'"\\$]*)?/,
+            /(?:\/[^\s'"`\\$]*)?/,
           ]),
 
           // Normal values w/o quotes — may include an opacity modifier
-          /[-\/][^\s'"\\$={><]*/,
+          /[-\/][^\s'"`\\$={><]*/,
         ])
       ),
     ]),
@@ -69,8 +69,8 @@ function* buildRegExps(context) {
     '((?=((',
     regex.any(
       [
-        regex.pattern([/([^\s"'\[\\]+-)?\[[^\s"'\\]+\]/, separator]),
-        regex.pattern([/[^\s"'\[\\]+/, separator]),
+        regex.pattern([/([^\s"'`\[\\]+-)?\[[^\s"'`\\]+\]/, separator]),
+        regex.pattern([/[^\s"'`\[\\]+/, separator]),
       ],
       true
     ),
@@ -91,7 +91,7 @@ function* buildRegExps(context) {
   ])
 
   // 5. Inner matches
-  // yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
+  yield /[^<>"'`\s.(){}[\]#=%$]*[^<>"'`\s.(){}[\]#=%:$]/g
 }
 
 // We want to capture any "special" characters


Test patch:
diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js
--- a/tests/default-extractor.test.js
+++ b/tests/default-extractor.test.js
@@ -415,28 +415,24 @@ test('with single quotes array within template literal', async () => {
   const extractions = defaultExtractor(`<div class=\`\${['pr-1.5']}\`></div>`)
 
   expect(extractions).toContain('pr-1.5')
-  expect(extractions).not.toContain('pr-1')
 })
 
 test('with double quotes array within template literal', async () => {
   const extractions = defaultExtractor(`<div class=\`\${["pr-1.5"]}\`></div>`)
 
   expect(extractions).toContain('pr-1.5')
-  expect(extractions).not.toContain('pr-1')
 })
 
 test('with single quotes array within function', async () => {
   const extractions = defaultExtractor(`document.body.classList.add(['pl-1.5'].join(" "));`)
 
   expect(extractions).toContain('pl-1.5')
-  expect(extractions).not.toContain('pl-1')
 })
 
 test('with double quotes array within function', async () => {
   const extractions = defaultExtractor(`document.body.classList.add(["pl-1.5"].join(" "));`)
 
   expect(extractions).toContain('pl-1.5')
-  expect(extractions).not.toContain('pl-1')
 })
 
 test('with angle brackets', async () => {
@@ -449,3 +445,26 @@ test('with angle brackets', async () => {
   expect(extractions).not.toContain('>shadow-xl')
   expect(extractions).not.toContain('shadow-xl<')
 })
+
+test('markdown code fences', async () => {
+  const extractions = defaultExtractor('<!-- this should work: `.font-bold`, `.font-normal` -->')
+
+  expect(extractions).toContain('font-bold')
+  expect(extractions).toContain('font-normal')
+  expect(extractions).not.toContain('.font-bold')
+  expect(extractions).not.toContain('.font-normal')
+})
+
+test('classes in slim templates', async () => {
+  const extractions = defaultExtractor(`
+    p.bg-red-500.text-sm
+      'This is a paragraph
+        small.italic.text-gray-500
+          '(Look mom, no closing tag!)
+  `)
+
+  expect(extractions).toContain('bg-red-500')
+  expect(extractions).toContain('text-sm')
+  expect(extractions).toContain('italic')
+  expect(extractions).toContain('text-gray-500')
+})