diff --git a/CHANGELOG.md b/CHANGELOG.md index 2be85bf37b81..d32a347b0ab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Invalidate context when main CSS changes ([#7626](https://github.com/tailwindlabs/tailwindcss/pull/7626)) - Only add `!` to selector class matching template candidate when using important modifier with mutli-class selectors ([#7664](https://github.com/tailwindlabs/tailwindcss/pull/7664)) - Correctly parse and prefix animation names with dots ([#7163](https://github.com/tailwindlabs/tailwindcss/pull/7163)) +- Fix extraction from template literal/function with array ([#7481](https://github.com/tailwindlabs/tailwindcss/pull/7481)) ### Changed diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index fe720f86780f..e211c598fea7 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -2,16 +2,16 @@ const PATTERNS = [ /(?:\['([^'\s]+[^<>"'`\s:\\])')/.source, // ['text-lg' -> text-lg /(?:\["([^"\s]+[^<>"'`\s:\\])")/.source, // ["text-lg" -> text-lg /(?:\[`([^`\s]+[^<>"'`\s:\\])`)/.source, // [`text-lg` -> text-lg - /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif] - /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] + /([^${(<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif] + /([^${(<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')] /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")] /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')] /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")] /([^<>"'`\s]*\[[^<>"'`\s]*\('[^"`\s]*'\)+\])/.source, // h-[calc(100%-theme('spacing.1'))] /([^<>"'`\s]*\[[^<>"'`\s]*\("[^'`\s]*"\)+\])/.source, // h-[calc(100%-theme("spacing.1"))] - /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']` - /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` + /([^${(<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']` + /([^${(<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` /([^<>"'`\s]*\[[^<>"'`\s]*:[^\]\s]*\])/.source, // `[attr:value]` /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]` /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']` diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 35d06b0551d3..e1bf6b77c3ad 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,9 +1,22 @@ import { html } from './util/run' import { defaultExtractor } from '../src/lib/defaultExtractor' -let jsxExample = "
" -const input = - html` +const jsExamples = ` + document.body.classList.add(["pl-1.5"].join(" ")); + document.body.classList.add(['pl-2.5'].join(" ")); +` +const jsxExamples = ` +
+
+
+
+
+
+
+
+
+` +const htmlExamples = html`
@@ -46,10 +59,21 @@ const input = let classes14 = ["
"] let obj = { - lowercase: true + lowercase: true, + "normal-case": true, + 'ml-0.5': true, + 'ml-0.5': true, + 'h-[106px]': true, + "h-[107px]": true, + } + let obj2 = { + 'h-[108px]': true + } + let obj3 = { + "h-[109px]": true } -` + jsxExample +` const includes = [ `font-['some_font',sans-serif]`, @@ -67,8 +91,28 @@ const includes = [ `fill-[#bada55]`, `fill-[#bada55]/50`, `px-1.5`, + `pl-1.5`, + `pl-2.5`, + `pr-1.5`, + `pr-2.5`, + `pr-3.5`, + `pr-4.5`, + `pr-5.5`, + `pr-6.5`, + `ml-0.5`, + `h-[100px]`, + `h-[101px]`, + `h-[102px]`, + `h-[103px]`, + `h-[104px]`, + `h-[105px]`, + `h-[106px]`, + `h-[107px]`, + `h-[108px]`, + `h-[109px]`, `uppercase`, `lowercase`, + `normal-case`, `hover:font-bold`, `text-sm`, `text-[10px]`, @@ -106,7 +150,7 @@ const excludes = [ ] test('The default extractor works as expected', async () => { - const extractions = defaultExtractor(input.trim()) + const extractions = defaultExtractor([jsExamples, jsxExamples, htmlExamples].join('\n').trim()) for (const str of includes) { expect(extractions).toContain(str) @@ -345,3 +389,31 @@ test('special characters', async () => { expect(extractions).toContain(`:font-bold`) }) + +test('with single quotes array within template literal', async () => { + const extractions = defaultExtractor(`
`) + + expect(extractions).toContain('pr-1.5') + expect(extractions).toContain('pr-1') +}) + +test('with double quotes array within template literal', async () => { + const extractions = defaultExtractor(`
`) + + expect(extractions).toContain('pr-1.5') + expect(extractions).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).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).toContain('pl-1') +})