From 8dbf876dd2c1aa5ee2e0fa80b8e0cff527e2f344 Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Tue, 15 Feb 2022 20:57:22 +0100 Subject: [PATCH 1/8] fix: allow extraction from template literal with array --- src/lib/defaultExtractor.js | 8 ++++---- tests/default-extractor.test.js | 30 ++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index fe720f86780f..d7ee834509a8 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..f0339a85ea67 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,7 +1,10 @@ import { html } from './util/run' import { defaultExtractor } from '../src/lib/defaultExtractor' -let jsxExample = "
" +let jsxExample = ` +
+
+` const input = html`
@@ -46,7 +49,9 @@ const input = let classes14 = ["
"] let obj = { - lowercase: true + lowercase: true, + "normal-case": true, + 'ml-0.5': true, } ` + jsxExample @@ -67,8 +72,11 @@ const includes = [ `fill-[#bada55]`, `fill-[#bada55]/50`, `px-1.5`, + `pr-1.5`, + `ml-0.5`, `uppercase`, `lowercase`, + `normal-case`, `hover:font-bold`, `text-sm`, `text-[10px]`, @@ -345,3 +353,21 @@ test('special characters', async () => { expect(extractions).toContain(`:font-bold`) }) + +test('arbitrary values with template literal in single quotes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('pr-1.5') + expect(extractions).toContain('pr-1') +}) + +test('arbitrary values with template literal in double quotes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('pr-1.5') + expect(extractions).toContain('pr-1') +}) From 167221c02fba81ad3e16684eb90b603db0692891 Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Tue, 15 Feb 2022 21:05:44 +0100 Subject: [PATCH 2/8] fix: support extraction from array in function --- src/lib/defaultExtractor.js | 8 ++++---- tests/default-extractor.test.js | 13 ++++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index d7ee834509a8..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 f0339a85ea67..8ef39edd85b5 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,12 +1,14 @@ import { html } from './util/run' import { defaultExtractor } from '../src/lib/defaultExtractor' -let jsxExample = ` +const jsExamples = ` + document.body.classList.add(["pl-1.5"].join(" ")); +` +const jsxExamples = `
` -const input = - html` +const htmlExamples = html`
@@ -54,7 +56,7 @@ const input = 'ml-0.5': true, } -` + jsxExample +` const includes = [ `font-['some_font',sans-serif]`, @@ -72,6 +74,7 @@ const includes = [ `fill-[#bada55]`, `fill-[#bada55]/50`, `px-1.5`, + `pl-1.5`, `pr-1.5`, `ml-0.5`, `uppercase`, @@ -114,7 +117,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) From 980b904d5541b98475a2a90a3d749cb119f9ae01 Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Tue, 15 Feb 2022 21:12:13 +0100 Subject: [PATCH 3/8] test: add more tests for function and template --- tests/default-extractor.test.js | 36 +++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 8ef39edd85b5..c018030f430c 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -3,10 +3,14 @@ import { defaultExtractor } from '../src/lib/defaultExtractor' const jsExamples = ` document.body.classList.add(["pl-1.5"].join(" ")); + document.body.classList.add(['pl-2.5'].join(" ")); ` const jsxExamples = `
+
+
+
` const htmlExamples = html`
@@ -75,7 +79,13 @@ const includes = [ `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`, `uppercase`, `lowercase`, @@ -357,20 +367,30 @@ test('special characters', async () => { expect(extractions).toContain(`md>:font-bold`) }) -test('arbitrary values with template literal in single quotes', async () => { - const extractions = defaultExtractor(` -
- `) +test('arbitrary values with single quotes array within template literal', async () => { + const extractions = defaultExtractor(`
`) expect(extractions).toContain('pr-1.5') expect(extractions).toContain('pr-1') }) -test('arbitrary values with template literal in double quotes', async () => { - const extractions = defaultExtractor(` -
- `) +test('arbitrary values with double quotes array within template literal', async () => { + const extractions = defaultExtractor(`
`) expect(extractions).toContain('pr-1.5') expect(extractions).toContain('pr-1') }) + +test('arbitrary values 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('arbitrary values 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') +}) From 86ef80d69b0086719265382064c030d22de9210c Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Thu, 17 Feb 2022 11:20:34 +0100 Subject: [PATCH 4/8] test: add test for dynamic classes --- tests/default-extractor.test.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index c018030f430c..0f406f2939f0 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -11,6 +11,10 @@ const jsxExamples = `
+
+
+
+
` const htmlExamples = html`
@@ -87,6 +91,12 @@ const includes = [ `pr-5.5`, `pr-6.5`, `ml-0.5`, + `h-[100px]`, + `h-[101px]`, + `h-[102px]`, + `h-[103px]`, + `h-[104px]`, + `h-[105px]`, `uppercase`, `lowercase`, `normal-case`, From 39bea5761862a85a57a9aaf7d336fbfe77aab8f5 Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Thu, 17 Feb 2022 11:22:01 +0100 Subject: [PATCH 5/8] test: add dynamic class test in js --- tests/default-extractor.test.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 0f406f2939f0..ef20946f581c 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -62,6 +62,9 @@ const htmlExamples = html` lowercase: true, "normal-case": true, 'ml-0.5': true, + 'ml-0.5': true, + "h-[106px]": true, + "h-[107px]": true } ` @@ -97,6 +100,8 @@ const includes = [ `h-[103px]`, `h-[104px]`, `h-[105px]`, + `h-[106px]`, + `h-[107px]`, `uppercase`, `lowercase`, `normal-case`, From cde27bae2df7925a77d67bb907c9252581a66de8 Mon Sep 17 00:00:00 2001 From: Samuel Alev Date: Thu, 17 Feb 2022 11:23:08 +0100 Subject: [PATCH 6/8] test: add dynamic class test in js single quote --- tests/default-extractor.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index ef20946f581c..ad95f22539ef 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -63,8 +63,10 @@ const htmlExamples = html` "normal-case": true, 'ml-0.5': true, 'ml-0.5': true, - "h-[106px]": true, - "h-[107px]": true + 'h-[106px]': true, + 'h-[107px]': true + "h-[108px]": true, + "h-[109px]": true } ` @@ -102,6 +104,8 @@ const includes = [ `h-[105px]`, `h-[106px]`, `h-[107px]`, + `h-[108px]`, + `h-[109px]`, `uppercase`, `lowercase`, `normal-case`, From 43f37d394d7f1c5e01f20680538a3c184a950a4d Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 1 Mar 2022 14:14:25 -0500 Subject: [PATCH 7/8] Cleanup a bit --- tests/default-extractor.test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index ad95f22539ef..e1bf6b77c3ad 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -64,8 +64,12 @@ const htmlExamples = html` 'ml-0.5': true, 'ml-0.5': true, 'h-[106px]': true, - 'h-[107px]': true - "h-[108px]": true, + "h-[107px]": true, + } + let obj2 = { + 'h-[108px]': true + } + let obj3 = { "h-[109px]": true } @@ -386,28 +390,28 @@ test('special characters', async () => { expect(extractions).toContain(`md>:font-bold`) }) -test('arbitrary values with single quotes array within template literal', async () => { +test('with single quotes array within template literal', async () => { const extractions = defaultExtractor(`
`) expect(extractions).toContain('pr-1.5') expect(extractions).toContain('pr-1') }) -test('arbitrary values with double quotes array within template literal', async () => { +test('with double quotes array within template literal', async () => { const extractions = defaultExtractor(`
`) expect(extractions).toContain('pr-1.5') expect(extractions).toContain('pr-1') }) -test('arbitrary values with single quotes array within function', async () => { +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('arbitrary values with double quotes array within function', async () => { +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') From 677cbaac93261f5cf27cd98096f8d91047289994 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Tue, 1 Mar 2022 14:19:24 -0500 Subject: [PATCH 8/8] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) 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