From 47e3d09acab011423aecdaa792aca4206916764c Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 15 Dec 2021 15:23:00 -0500 Subject: [PATCH 01/23] Pull default extractor into separate file --- src/lib/defaultExtractor.js | 23 +++++++++++++++++++++++ src/lib/expandTailwindAtRules.js | 25 ++----------------------- 2 files changed, 25 insertions(+), 23 deletions(-) create mode 100644 src/lib/defaultExtractor.js diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js new file mode 100644 index 000000000000..3afe6b7dea53 --- /dev/null +++ b/src/lib/defaultExtractor.js @@ -0,0 +1,23 @@ +const PATTERNS = [ + // /([^<>"'`\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]*'\])/.source, // `content-['hello']` but not `content-['hello']']` + /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` + /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]` + /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']` + /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50` + /([^<>"'`\s]*[^"'`\s:\\])/.source, // `px-1.5`, `uppercase` but not `uppercase:` +].join('|') +const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') +const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g + +export default (content) => { + let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [] + let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [] + + return [...broadMatches, ...innerMatches] +} diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index 087a671ea17a..74ee25c71ae7 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -3,33 +3,12 @@ import * as sharedState from './sharedState' import { generateRules } from './generateRules' import bigSign from '../util/bigSign' import cloneNodes from '../util/cloneNodes' +import defaultExtractor from './defaultExtractor' let env = sharedState.env -const PATTERNS = [ - /([^<>"'`\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]*'\])/.source, // `content-['hello']` but not `content-['hello']']` - /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` - /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]` - /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']` - /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50` - /([^<>"'`\s]*[^"'`\s:])/.source, // `px-1.5`, `uppercase` but not `uppercase:` -].join('|') -const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') -const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g - const builtInExtractors = { - DEFAULT: (content) => { - let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [] - let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [] - - return [...broadMatches, ...innerMatches] - }, + DEFAULT: defaultExtractor, } const builtInTransformers = { From ccbc642544ae23708cffd429611ecf6348130ec4 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 15 Dec 2021 15:23:19 -0500 Subject: [PATCH 02/23] Add unit tests for the extractor --- tests/default-extractor.test.js | 268 ++++++++++++++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 tests/default-extractor.test.js diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js new file mode 100644 index 000000000000..4490ce9fd944 --- /dev/null +++ b/tests/default-extractor.test.js @@ -0,0 +1,268 @@ +import extract from '../src/lib/defaultExtractor' + +const html = String.raw + +const table = [ + { + input: '', + output: [], + }, + { + input: html`text-lg`, + output: ["text-lg"], + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "3px", + "ccc", + "class", + "class=", + "decoration-", + "decoration-[#ccc]", + "decoration-[3px]", + "div", + ], + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "class", + "class=", + "com/tailwindlabs", + "div", + "hover:bg-", + "hover:bg-[url('https://github.com/tailwindlabs.png')]", + "https://github", + "png", + "url", + ] + }, + { + input: html` + +
+
+ + +
+
+ + +
+
+ `, + output: [ + "--", + "-->", + "--bg-color", + "--image-url", + "!--", + "/div", + "/div>", + "/image-1-0", + "<", + ">", + "bg-", + "bg-[#ff0000]", + "bg-[color:var(--bg-color)]", + "bg-[url:var(--image-url)]", + "bg-[url('/image-1-0.png')]", + "bg-gradient-to-r", + "bg-red-500", + "By", + "class", + "class=", + "color:var", + "div", + "explicit", + "ff0000", + "implicit", + "Lookup", + "png", + "type", + "url:var", + "url", + ] + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "class", + "class=", + "div", + "hmm:12px", + "inset-", + "inset-[hmm:12px]", + ] + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "class", + "class=", + "div", + "length:12px", + "w-", + "w-[length:12px]", + ] + }, + { + input: html` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `, + output: [ + "___abc____", + "__hello__world__", + "_300px", + "_hello_world_", + ",100px", + "/div", + "/div>", + "<", + ">", + "0,_1fr", + "0px_0px_4px_black", + "0px_1px_3px_black", + "0px_4px_4px_0px", + "1_1_100", + "8px_4px", + "15", + "200px_repeat", + "auto-cols-", + "auto-cols-[minmax(0,_1fr)]", + "auto-fill,minmax", + "class", + "class=", + "col-", + "col-[span_3_/_span_8]", + "content-", + "content-[___abc____]", + "content-[_hello_world_]", + "content-['__hello__world__']", + "div", + "drop-shadow-", + "drop-shadow-[0px_1px_3px_black]", + "flex-", + "flex-[1_1_100%]", + "grid-cols-", + "grid-cols-[200px_repeat(auto-fill,minmax(15%,100px))_300px]", + "grid-rows-", + "grid-rows-[200px_repeat(auto-fill,minmax(15%,100px))_300px]", + "m-", + "m-[8px_4px]", + "minmax", + "p-", + "p-[8px_4px]", + "rounded-", + "rounded-[0px_4px_4px_0px]", + "row-", + "row-[span_3_/_span_8]", + "shadow-", + "shadow-[0px_0px_4px_black]", + "span_3_/_span_8", + ] + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "class", + "class=", + "content-", + "content-['snake\\\\_case']", + "div", + "snake\\\\_case", + ], + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "200px_100px", + "bg-", + "bg-[200px_100px]", + "class", + "class=", + "div", + ], + }, + { + input: html`
`, + output: [ + "/div", + "/div>", + "<", + ">", + "bg-", + "bg-[url('https://www.spacejam.com/1996/img/bg_stars.gif')]", + "class", + "class=", + "com/1996/img/bg_stars", + "div", + "gif", + "https://www", + "spacejam", + "url", + ], + }, + { + input: html`
`, + output: [ + ",_url", + "/div", + "/div>", + "<", + ">", + "bg-", + "bg-[url('brown_potato.jpg'),_url('red_tomato.png')]", + "brown_potato", + "class", + "class=", + "div", + "jpg", + "png", + "red_tomato", + "url", + ], + }, +] + +test.each(table)('Extract $input', ({ input, output }) => { + expect([...new Set(extract(input))].sort()).toEqual([...new Set(output)].sort()) +}) From f165f7a7e09bee1b58d7b5a66cdfbc3a5e4f40cd Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 15 Dec 2021 15:24:11 -0500 Subject: [PATCH 03/23] default extractor --- src/lib/defaultExtractor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 3afe6b7dea53..c132291b78e6 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,5 +1,5 @@ const PATTERNS = [ - // /([^<>"'`\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("...")] From ac4e63462f758f3dbae3d599e0560a4aa8d78757 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Wed, 15 Dec 2021 15:38:01 -0500 Subject: [PATCH 04/23] Add test --- tests/arbitrary-values.test.extractions.txt | 736 ++++++++++++++++++++ tests/default-extractor.test.js | 271 +------ 2 files changed, 745 insertions(+), 262 deletions(-) create mode 100644 tests/arbitrary-values.test.extractions.txt diff --git a/tests/arbitrary-values.test.extractions.txt b/tests/arbitrary-values.test.extractions.txt new file mode 100644 index 000000000000..d379b2d8feb0 --- /dev/null +++ b/tests/arbitrary-values.test.extractions.txt @@ -0,0 +1,736 @@ +!-- +!DOCTYPE +)_2_2,pointer] ++1rem +, +,0 +,100px +,1fr,auto +,300px +,50 +,conic-gradient +,sans-serif +,sans-serif] +,var +,var(--other-font)] +-- +--10-10px,calc +--> +--accent-color +--angle +--app-duration +--aspect +--basis +--color +--columns +--delay +--flex +--font-size +--font1 +--font2 +--grow +--height +--indent +--leading +--opacity +--other-font +--outline +--placeholder +--placeholder-opacity +--position +--radius +--ring-opacity +--scroll-margin +--scroll-padding +--shrink +--tracking +--url +--value +--value1 +--value2 +--width +--width,calc +--will-change +-1cm +-20px- +-30px--40px +-50px +./path_to_hand.cur +./tailwind.css +/ +/3-1rem*2 +/> +/body +/body> +/div +/div> +/favicon +/favicon.ico +/head +/head> +/html +/html> +/path-to-image +/path_to_hand +/tailwind +/title +/title> +0 +0,0,0 +0,100 +0000ffcc +0f0 +0f0_var +0px_1px_2px_black +1 +100 +10em +10px +10px,auto +10vh,100px +11 +11px +12 +123 +123,123,123 +123,123,123,0 +123,_123,_123 +123,_456,_123 +123_123_123 +123_456_789 +144 +15 +15px +16/9 +180 +19rem +2 +2,1 +20 +200px,repeat +20cm +20px +22 +23 +23deg +23rem +2s +3 +300 +30px,100px +38 +3px +3rad +4 +401grad +42 +5 +50 +50px_50px +55 +57rad +5px +5turn +66 +7 +75 +76ad65 +7px +8 +87 +8turn +< +> +Balancing +Georgia,serif +Gill_Sans +INVALID +Some_Font +Some_Other_Font +Title +Title< +UTF-8 +VALID +\1F44D +] +_2_2,pointer +_black +_infinite +_var +accent- +accent-[#bada55] +accent-[var(--accent-color)] +actual +ad672f +align- +align-[10em] +angle:var +animate- +animate-[pong_1s_cubic-bezier(0,0,0.2,1)_infinite] +animate-[var(--value)] +aspect- +aspect-[16/9] +aspect-[var(--aspect)] +attr +auto-cols- +auto-cols-[minmax(10px,auto)] +auto-fill,minmax +auto-rows- +auto-rows-[minmax(10px,auto)] +backdrop-blur- +backdrop-blur-[11px] +backdrop-brightness- +backdrop-brightness-[1.23] +backdrop-contrast- +backdrop-contrast-[0.87] +backdrop-grayscale- +backdrop-grayscale-[0.42] +backdrop-hue-rotate- +backdrop-hue-rotate-[1.57rad] +backdrop-invert- +backdrop-invert-[0.66] +backdrop-opacity- +backdrop-opacity-[22%] +backdrop-saturate- +backdrop-saturate-[144%] +backdrop-sepia- +backdrop-sepia-[0.38] +bada55 +basis- +basis-[var(--basis)] +bg- +bg-[#0000ffcc] +bg-[#0f0] +bg-[#0f0_var(--value)] +bg-[#ff0000] +bg-[center_top_1rem] +bg-[color:var(--value1)_var(--value2)] +bg-[hsl(0,100%,50%)] +bg-[hsla(0,100%,50%,0.3)] +bg-[image(),var(--value)] +bg-[image:var(--value),var(--value)] +bg-[length:200px_100px] +bg-[length:var(--value)] +bg-[linear-gradient(#eee,#fff),conic-gradient(red,orange,yellow,green,blue)] +bg-[linear-gradient(#eee,#fff)] +bg-[position:200px_100px] +bg-[position:var(--value)] +bg-[rgb(123,123,123)] +bg-[rgb(123,_456,_123)_black] +bg-[rgb(123_456_789)] +bg-[rgba(123,123,123,0.5)] +bg-[url('/path-to-image.png')] +bg-[url:var(--url)] +bg-[var(--value),var(--value)] +bg-[var(--value1)_var(--value2)] +bg-opacity- +bg-opacity-[0.11] +bg-opacity-[var(--value)] +black +blur- +blur-[15px] +body +body> +border- +border-[#f00] +border-[2.5px] +border-[color:var(--value)] +border-[length:var(--value)] +border-[red_black] +border-b- +border-b-[#f00] +border-b-[2.5px] +border-b-[color:var(--value)] +border-b-[length:var(--value)] +border-l- +border-l-[#f00] +border-l-[2.5px] +border-l-[color:var(--value)] +border-l-[length:var(--value)] +border-opacity- +border-opacity-[0.8] +border-opacity-[var(--value)] +border-r- +border-r-[#f00] +border-r-[2.5px] +border-r-[color:var(--value)] +border-r-[length:var(--value)] +border-t- +border-t-[#f00] +border-t-[2.5px] +border-t-[color:var(--value)] +border-t-[length:var(--value)] +bottom- +bottom-[11px] +bottom-[var(--value)] +brightness- +brightness-[300%] +but +calc +caret- +caret-[black] +caret-[var(--value)] +center_top_1rem +charset +charset= +checking +clamp +class +class= +col- +col-[7] +col-end- +col-end-[7] +col-start- +col-start-[7] +color:var +columns- +columns-[20] +columns-[var(--columns)] +content +content- +content-['>'] +content-['hello'] +content-[attr(content-before)] +content-before +content= +contrast- +contrast-[2.4] +css +cur +cursor- +cursor-[pointer] +cursor-[url( +cursor-[url(hand.cur)_2_2,pointer] +cursor-[var(--value)] +da5b66 +decoration- +decoration-[black] +decoration-[color:var(--color)] +decoration-[length:10px] +decoration-[rgb(123,123,123)] +decoration-[rgb(123,_123,_123)] +decoration-[rgb(123_123_123)] +delay- +delay-[var(--delay)] +device-width, +div +divide- +divide-[black] +divide-[var(--value)] +divide-opacity- +divide-opacity-[0.8] +divide-opacity-[var(--value)] +divide-x- +divide-x-[20cm] +divide-x-[calc(20%-1cm)] +divide-y- +divide-y-[20cm] +divide-y-[calc(20%-1cm)] +do-not-generate-this +drop-shadow- +drop-shadow-[0px_1px_2px_black] +duration- +duration-[2s] +duration-[var(--app-duration)] +eee, +en +f00 +family-name:var +ff0000 +fff +fill- +fill-[#da5b66] +fill-[url(#icon-gradient)] +fill-[var(--value)] +flex- +flex-[var(--flex)] +flex-grow- +flex-grow-[var(--grow)] +flex-shrink- +flex-shrink-[var(--shrink)] +font- +font-[ +font-['Gill_Sans'] +font-[300] +font-[Georgia,serif] +font-[family-name:var(--value)] +font-[invalid_font_because_spaces] +font-[number:lighter] +font-[number:var(--value)] +font-[sans-serif,serif] +font-[serif,var(--value)] +font-[var(--font1),var(--font2)] +from- +from-[#da5b66] +from-[var(--color)] +gap- +gap-[20px] +gap-[var(--value)] +gap-x- +gap-x-[20px] +gap-x-[var(--value)] +gap-y- +gap-y-[20px] +gap-y-[var(--value)] +grayscale- +grayscale-[0.55] +grid-cols- +grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px] +grid-cols-[[linename],1fr,auto] +grid-rows- +grid-rows-[200px,repeat(auto-fill,minmax(15%,100px)),300px] +grow- +grow-[var(--grow)] +h- +h-[3.23rem] +h-[calc(100%+1rem)] +h-[var(--height)] +hand +head +head> +hello +href +href= +hsl +hsla +html +html> +hue-rotate- +hue-rotate-[0.8turn] +ico +icon +icon-gradient +image +image:var +indent- +indent-[50%] +indent-[var(--indent)] +initial-scale +initial-scale=1.0 +inset- +inset-[11px] +inset-[var(--value)] +inset-x- +inset-x-[11px] +inset-x-[var(--value)] +inset-y- +inset-y-[11px] +inset-y-[var(--value)] +invalid_font_because_spaces +invert- +invert-[0.75] +is +issues, +it-is-invalid-syntax +lang +lang= +leading- +leading-[var(--leading)] +left- +left-[11px] +left-[var(--value)] +length +length:10px +length:200px_100px +length:var +lg:grid-cols- +lg:grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px] +linear-gradient +linename +link +list- +list-['\1F44D'] +list-[var(--value)] +m- +m-[7px] +max-h- +max-h-[3.23rem] +max-h-[calc(100%+1rem)] +max-h-[var(--height)] +max-w- +max-w-[3.23rem] +max-w-[calc(100%+1rem)] +max-w-[var(--width)] +mb- +mb-[7px] +meta +min +min-h- +min-h-[3.23rem] +min-h-[calc(100%+1rem)] +min-h-[var(--height)] +min-w- +min-w-[3.23rem] +min-w-[calc(100%+1rem)] +min-w-[var(--width)] +minmax +ml- +ml-[7px] +mr- +mr-[7px] +mt- +mt-[7px] +mt-[clamp(30px,100px)] +mx- +mx-[7px] +my- +my-[7px] +name +name= +not +number:lighter +number:var +object- +object-[50%,50%] +object-[top,right] +object-[var(--position)] +of +opacity,width +opacity- +opacity-[0.8] +opacity-[var(--opacity)] +order- +order-[4] +order-[var(--value)] +origin- +origin-[50px_50px] +outline- +outline-[10px] +outline-[black] +outline-[color:var(--outline)] +outline-[length:var(--outline)] +outline-offset- +outline-offset-[10px] +p- +p-[7px] +pb- +pb-[7px] +pl- +pl-[7px] +placeholder- +placeholder-[var(--placeholder)] +placeholder-opacity- +placeholder-opacity-[var(--placeholder-opacity)] +png +pointer +pong_1s_cubic-bezier +position:200px_100px +position:var +pr- +pr-[7px] +pt- +pt-[7px] +pt-[clamp(30px,100px)] +purely +px- +px-[7px] +py- +py-[7px] +red,orange,yellow,green,blue +red_black +rel +rel= +rgb +rgba +right- +right-[11px] +right-[var(--value)] +ring- +ring-[#76ad65] +ring-[10px] +ring-[color:var(--value)] +ring-[length:(var(--value))] +ring-offset- +ring-offset-[#76ad65] +ring-offset-[#ad672f] +ring-offset-[19rem] +ring-offset-[color:var(--value)] +ring-offset-[length:var(--value)] +ring-opacity- +ring-opacity-[var(--ring-opacity)] +rotate- +rotate-[1.5turn] +rotate-[2.3rad] +rotate-[23deg] +rotate-[401grad] +rounded- +rounded-[11px] +rounded-b- +rounded-b-[var(--radius)] +rounded-bl- +rounded-bl-[var(--radius)] +rounded-br- +rounded-br-[var(--radius)] +rounded-l- +rounded-l-[var(--radius)] +rounded-r- +rounded-r-[var(--radius)] +rounded-t- +rounded-t-[var(--radius)] +rounded-tl- +rounded-tl-[var(--radius)] +rounded-tr- +rounded-tr-[var(--radius)] +row- +row-[7] +row-end- +row-end-[7] +row-start- +row-start-[7] +sans-serif,serif +saturate- +saturate-[180%] +scale- +scale-[0.7] +scale-[var(--value)] +scale-x- +scale-x-[0.7] +scale-x-[var(--value)] +scale-y- +scale-y-[0.7] +scale-y-[var(--value)] +scroll-m- +scroll-m-[7px] +scroll-mb- +scroll-mb-[7px] +scroll-ml- +scroll-ml-[7px] +scroll-mr- +scroll-mr-[7px] +scroll-mt- +scroll-mt-[7px] +scroll-mt-[var(--scroll-margin)] +scroll-mx- +scroll-mx-[7px] +scroll-my- +scroll-my-[7px] +scroll-p- +scroll-p-[7px] +scroll-pb- +scroll-pb-[7px] +scroll-pl- +scroll-pl-[7px] +scroll-pr- +scroll-pr-[7px] +scroll-pt- +scroll-pt-[7px] +scroll-pt-[var(--scroll-padding)] +scroll-px- +scroll-px-[7px] +scroll-py- +scroll-py-[7px] +sepia- +sepia-[0.2] +serif,var +shadow- +shadow-[0px_1px_2px_black] +shadow-[shadow:var(--value)] +shadow:var +shrink- +shrink-[var(--shrink)] +skew-x- +skew-x-[3px] +skew-x-[var(--value)] +skew-y- +skew-y-[3px] +skew-y-[var(--value)] +space-x- +space-x-[20cm] +space-x-[calc(20%-1cm)] +space-y- +space-y-[20cm] +space-y-[calc(20%-1cm)] +stroke- +stroke-[#da5b66] +stroke-[20px] +stroke-[color:var(--value)] +stroke-[length:var(--value)] +stroke-[url(#icon-gradient)] +stylesheet +syntax-wise +text- +text-[0] +text-[2.23rem] +text-[angle:var(--angle)] +text-[black] +text-[color:var(--color)] +text-[length:var(--font-size)] +text-[min(10vh,100px)] +text-[rgb(123,123,123)] +text-[rgb(123,_123,_123)] +text-[rgb(123_123_123)] +text-opacity- +text-opacity-[0.8] +text-opacity-[var(--value)] +the +this +title +title> +to- +to-[#da5b66] +to-[var(--color)] +top,left +top,right +top- +top-[11px] +top-[var(--value)] +tracking- +tracking-[var(--tracking)] +transition- +transition-[opacity,width] +translate-x- +translate-x-[12%] +translate-x-[var(--value)] +translate-y- +translate-y-[12%] +translate-y-[var(--value)] +underline-offset- +underline-offset-[10px] +url +url:var +validity +value, +var +via- +via-[#da5b66] +via-[var(--color)] +viewport +w- +w-[')()'] +w-['][]'] +w-['}{}'] +w-[(())] +w-[()] +w-[([)]] +w-[({)}] +w-[)()] +w-[)(] +w-[0] +w-[3.23rem] +w-[[(])] +w-[[[]]] +w-[[]] +w-[[{]}] +w-[][] +w-[][]] +w-[calc(100%+1rem)] +w-[calc(100%/3-1rem*2)] +w-[calc(var(--10-10px,calc(-20px-(-30px--40px)))-50px)] +w-[do-not-generate-this]w-[it-is-invalid-syntax] +w-[var(--width)] +w-[var(--width,calc(100%+1rem))] +w-[{(})] +w-[{[}]] +w-[{{}}] +w-[{}] +w-[}{] +w-[}{}] +width +width=device-width, +will-change- +will-change-[top,left] +will-change-[var(--will-change)] +z- +z-[123] +z-[var(--value)] diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 4490ce9fd944..f4e47e943239 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,268 +1,15 @@ +import { promises as fs } from "fs" import extract from '../src/lib/defaultExtractor' -const html = String.raw +test('Extract $input', async () => { + const [input, output] = await Promise.all([ + fs.readFile(__dirname + '/arbitrary-values.test.html', 'utf8'), + fs.readFile(__dirname + '/arbitrary-values.test.extractions.txt', 'utf8'), + ]) -const table = [ - { - input: '', - output: [], - }, - { - input: html`text-lg`, - output: ["text-lg"], - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "3px", - "ccc", - "class", - "class=", - "decoration-", - "decoration-[#ccc]", - "decoration-[3px]", - "div", - ], - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "class", - "class=", - "com/tailwindlabs", - "div", - "hover:bg-", - "hover:bg-[url('https://github.com/tailwindlabs.png')]", - "https://github", - "png", - "url", - ] - }, - { - input: html` - -
-
+ const expected = output.trim().split('\n') - -
-
+ const extractions = [...new Set(extract(input.trim()))].sort() - -
-
- `, - output: [ - "--", - "-->", - "--bg-color", - "--image-url", - "!--", - "/div", - "/div>", - "/image-1-0", - "<", - ">", - "bg-", - "bg-[#ff0000]", - "bg-[color:var(--bg-color)]", - "bg-[url:var(--image-url)]", - "bg-[url('/image-1-0.png')]", - "bg-gradient-to-r", - "bg-red-500", - "By", - "class", - "class=", - "color:var", - "div", - "explicit", - "ff0000", - "implicit", - "Lookup", - "png", - "type", - "url:var", - "url", - ] - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "class", - "class=", - "div", - "hmm:12px", - "inset-", - "inset-[hmm:12px]", - ] - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "class", - "class=", - "div", - "length:12px", - "w-", - "w-[length:12px]", - ] - }, - { - input: html` -
-
-
-
-
-
-
-
-
-
-
-
-
-
- `, - output: [ - "___abc____", - "__hello__world__", - "_300px", - "_hello_world_", - ",100px", - "/div", - "/div>", - "<", - ">", - "0,_1fr", - "0px_0px_4px_black", - "0px_1px_3px_black", - "0px_4px_4px_0px", - "1_1_100", - "8px_4px", - "15", - "200px_repeat", - "auto-cols-", - "auto-cols-[minmax(0,_1fr)]", - "auto-fill,minmax", - "class", - "class=", - "col-", - "col-[span_3_/_span_8]", - "content-", - "content-[___abc____]", - "content-[_hello_world_]", - "content-['__hello__world__']", - "div", - "drop-shadow-", - "drop-shadow-[0px_1px_3px_black]", - "flex-", - "flex-[1_1_100%]", - "grid-cols-", - "grid-cols-[200px_repeat(auto-fill,minmax(15%,100px))_300px]", - "grid-rows-", - "grid-rows-[200px_repeat(auto-fill,minmax(15%,100px))_300px]", - "m-", - "m-[8px_4px]", - "minmax", - "p-", - "p-[8px_4px]", - "rounded-", - "rounded-[0px_4px_4px_0px]", - "row-", - "row-[span_3_/_span_8]", - "shadow-", - "shadow-[0px_0px_4px_black]", - "span_3_/_span_8", - ] - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "class", - "class=", - "content-", - "content-['snake\\\\_case']", - "div", - "snake\\\\_case", - ], - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "200px_100px", - "bg-", - "bg-[200px_100px]", - "class", - "class=", - "div", - ], - }, - { - input: html`
`, - output: [ - "/div", - "/div>", - "<", - ">", - "bg-", - "bg-[url('https://www.spacejam.com/1996/img/bg_stars.gif')]", - "class", - "class=", - "com/1996/img/bg_stars", - "div", - "gif", - "https://www", - "spacejam", - "url", - ], - }, - { - input: html`
`, - output: [ - ",_url", - "/div", - "/div>", - "<", - ">", - "bg-", - "bg-[url('brown_potato.jpg'),_url('red_tomato.png')]", - "brown_potato", - "class", - "class=", - "div", - "jpg", - "png", - "red_tomato", - "url", - ], - }, -] - -test.each(table)('Extract $input', ({ input, output }) => { - expect([...new Set(extract(input))].sort()).toEqual([...new Set(output)].sort()) + expect(extractions).toEqual(expected) }) From aa1be6bd5ba984f362a76b95fc2018bca7cffc05 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 16 Dec 2021 07:56:00 -0500 Subject: [PATCH 05/23] Work on stuff --- src/lib/defaultExtractor.js | 1 + tests/arbitrary-values.test.extractions.txt | 7 +++++++ tests/arbitrary-values.test.html | 2 ++ tests/default-extractor.test.js | 2 +- 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index c132291b78e6..8312b91e617d 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,4 +1,5 @@ const PATTERNS = [ + /(\["(text-\[10px\]))/.source, // text-[foo] in ["text-[foo] or ['text-[foo] /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif] /([^<>"'`\s]*\[\w*"[^"`\s]*"?\])/.source, // font-["some_font",sans-serif] /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')] diff --git a/tests/arbitrary-values.test.extractions.txt b/tests/arbitrary-values.test.extractions.txt index d379b2d8feb0..bc2c4d97db0f 100644 --- a/tests/arbitrary-values.test.extractions.txt +++ b/tests/arbitrary-values.test.extractions.txt @@ -99,6 +99,7 @@ 123_123_123 123_456_789 144 +14px 15 15px 16/9 @@ -151,8 +152,10 @@ Title Title< UTF-8 VALID +[ \1F44D ] +]< _2_2,pointer _black _infinite @@ -315,6 +318,7 @@ delay- delay-[var(--delay)] device-width, div +div> divide- divide-[black] divide-[var(--value)] @@ -436,6 +440,8 @@ length:200px_100px length:var lg:grid-cols- lg:grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px] +lg:text- +lg:text-[14px] linear-gradient linename link @@ -651,6 +657,7 @@ stylesheet syntax-wise text- text-[0] +text-[10px] text-[2.23rem] text-[angle:var(--angle)] text-[black] diff --git a/tests/arbitrary-values.test.html b/tests/arbitrary-values.test.html index af75a3254c27..7a5675927d7a 100644 --- a/tests/arbitrary-values.test.html +++ b/tests/arbitrary-values.test.html @@ -424,5 +424,7 @@
+
["text-[10px]", "lg:text-[14px]"]
+ diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index f4e47e943239..7643db897f17 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,4 +1,4 @@ -import { promises as fs } from "fs" +import { promises as fs } from 'fs' import extract from '../src/lib/defaultExtractor' test('Extract $input', async () => { From b6cf319aceede4b6bd03586efffc6ae35e5b297a Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 16 Dec 2021 12:16:03 -0500 Subject: [PATCH 06/23] Update extractor test --- src/lib/defaultExtractor.js | 5 +-- src/lib/expandTailwindAtRules.js | 2 +- tests/default-extractor.test.js | 68 +++++++++++++++++++++++++++----- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 8312b91e617d..06fd86f41e0f 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,7 +1,6 @@ const PATTERNS = [ - /(\["(text-\[10px\]))/.source, // text-[foo] in ["text-[foo] or ['text-[foo] /([^<>"'`\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('...')] @@ -16,7 +15,7 @@ const PATTERNS = [ const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g -export default (content) => { +export function defaultExtractor(content) { let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [] let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [] diff --git a/src/lib/expandTailwindAtRules.js b/src/lib/expandTailwindAtRules.js index 74ee25c71ae7..addf2c666169 100644 --- a/src/lib/expandTailwindAtRules.js +++ b/src/lib/expandTailwindAtRules.js @@ -3,7 +3,7 @@ import * as sharedState from './sharedState' import { generateRules } from './generateRules' import bigSign from '../util/bigSign' import cloneNodes from '../util/cloneNodes' -import defaultExtractor from './defaultExtractor' +import { defaultExtractor } from './defaultExtractor' let env = sharedState.env diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 7643db897f17..0f8b8b63e36c 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,15 +1,63 @@ -import { promises as fs } from 'fs' -import extract from '../src/lib/defaultExtractor' +import { defaultExtractor } from '../src/lib/defaultExtractor' -test('Extract $input', async () => { - const [input, output] = await Promise.all([ - fs.readFile(__dirname + '/arbitrary-values.test.html', 'utf8'), - fs.readFile(__dirname + '/arbitrary-values.test.extractions.txt', 'utf8'), - ]) +const input = ` +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+` - const expected = output.trim().split('\n') +const includes = [ + `font-['some_font',sans-serif]`, + `font-["some_font",sans-serif]`, + `bg-[url('...')]`, + `bg-[url("...")]`, + `bg-[url('...'),url('...')]`, + `bg-[url("..."),url("...")]`, + `content-['hello']`, + `content-["hello"]`, + `[content:'hello']`, + `[content:"hello"]`, + `[content:"hello"]`, + `[content:'hello']`, + `fill-[#bada55]`, + `fill-[#bada55]/50`, + `px-1.5`, + `uppercase`, + `hover:font-bold`, +] - const extractions = [...new Set(extract(input.trim()))].sort() +const excludes = [ + `uppercase:`, + `font-bold`, +] - expect(extractions).toEqual(expected) +test('The default extractor works as expected', async () => { + const extractions = defaultExtractor(input.trim()) + + console.log(extractions) + + for (const str of includes) { + expect(extractions).toContain(str) + } + + for (const str of excludes) { + expect(extractions).not.toContain(str) + } }) From 618aee38a8ed7029409f894ab434efedba17b563 Mon Sep 17 00:00:00 2001 From: Robin Malfait Date: Thu, 16 Dec 2021 18:45:05 +0100 Subject: [PATCH 07/23] WIP --- src/lib/defaultExtractor.js | 11 +++++++---- tests/default-extractor.test.js | 17 ++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 06fd86f41e0f..8e0e001e5619 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,18 +1,21 @@ const PATTERNS = [ /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif] - /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] + /* Break 1 */ /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')] - /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")] + /* Break 2 */ /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")] /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')] - /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")] + /* Break 3 */ /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")] /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']` - /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` + /* Break 4*/ /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]` /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']` /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50` + /(?:[^\[]([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)[^\]])/.source, // Stuff /([^<>"'`\s]*[^"'`\s:\\])/.source, // `px-1.5`, `uppercase` but not `uppercase:` ].join('|') + const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') +console.log(BROAD_MATCH_GLOBAL_REGEXP) const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g export function defaultExtractor(content) { diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 0f8b8b63e36c..1701cbfe430e 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -1,6 +1,7 @@ +import { html } from './util/run' import { defaultExtractor } from '../src/lib/defaultExtractor' -const input = ` +const input = html`
@@ -21,6 +22,14 @@ const input = `
+ + ` const includes = [ @@ -41,12 +50,10 @@ const includes = [ `px-1.5`, `uppercase`, `hover:font-bold`, + `text-[10px]`, ] -const excludes = [ - `uppercase:`, - `font-bold`, -] +const excludes = [`uppercase:`, `font-bold`] test('The default extractor works as expected', async () => { const extractions = defaultExtractor(input.trim()) From 5c8596bdb03062aa4b77d4ad388b4e001c02f236 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 16 Dec 2021 14:12:17 -0500 Subject: [PATCH 08/23] Remove unused file --- tests/arbitrary-values.test.extractions.txt | 743 -------------------- 1 file changed, 743 deletions(-) delete mode 100644 tests/arbitrary-values.test.extractions.txt diff --git a/tests/arbitrary-values.test.extractions.txt b/tests/arbitrary-values.test.extractions.txt deleted file mode 100644 index bc2c4d97db0f..000000000000 --- a/tests/arbitrary-values.test.extractions.txt +++ /dev/null @@ -1,743 +0,0 @@ -!-- -!DOCTYPE -)_2_2,pointer] -+1rem -, -,0 -,100px -,1fr,auto -,300px -,50 -,conic-gradient -,sans-serif -,sans-serif] -,var -,var(--other-font)] --- ---10-10px,calc ---> ---accent-color ---angle ---app-duration ---aspect ---basis ---color ---columns ---delay ---flex ---font-size ---font1 ---font2 ---grow ---height ---indent ---leading ---opacity ---other-font ---outline ---placeholder ---placeholder-opacity ---position ---radius ---ring-opacity ---scroll-margin ---scroll-padding ---shrink ---tracking ---url ---value ---value1 ---value2 ---width ---width,calc ---will-change --1cm --20px- --30px--40px --50px -./path_to_hand.cur -./tailwind.css -/ -/3-1rem*2 -/> -/body -/body> -/div -/div> -/favicon -/favicon.ico -/head -/head> -/html -/html> -/path-to-image -/path_to_hand -/tailwind -/title -/title> -0 -0,0,0 -0,100 -0000ffcc -0f0 -0f0_var -0px_1px_2px_black -1 -100 -10em -10px -10px,auto -10vh,100px -11 -11px -12 -123 -123,123,123 -123,123,123,0 -123,_123,_123 -123,_456,_123 -123_123_123 -123_456_789 -144 -14px -15 -15px -16/9 -180 -19rem -2 -2,1 -20 -200px,repeat -20cm -20px -22 -23 -23deg -23rem -2s -3 -300 -30px,100px -38 -3px -3rad -4 -401grad -42 -5 -50 -50px_50px -55 -57rad -5px -5turn -66 -7 -75 -76ad65 -7px -8 -87 -8turn -< -> -Balancing -Georgia,serif -Gill_Sans -INVALID -Some_Font -Some_Other_Font -Title -Title< -UTF-8 -VALID -[ -\1F44D -] -]< -_2_2,pointer -_black -_infinite -_var -accent- -accent-[#bada55] -accent-[var(--accent-color)] -actual -ad672f -align- -align-[10em] -angle:var -animate- -animate-[pong_1s_cubic-bezier(0,0,0.2,1)_infinite] -animate-[var(--value)] -aspect- -aspect-[16/9] -aspect-[var(--aspect)] -attr -auto-cols- -auto-cols-[minmax(10px,auto)] -auto-fill,minmax -auto-rows- -auto-rows-[minmax(10px,auto)] -backdrop-blur- -backdrop-blur-[11px] -backdrop-brightness- -backdrop-brightness-[1.23] -backdrop-contrast- -backdrop-contrast-[0.87] -backdrop-grayscale- -backdrop-grayscale-[0.42] -backdrop-hue-rotate- -backdrop-hue-rotate-[1.57rad] -backdrop-invert- -backdrop-invert-[0.66] -backdrop-opacity- -backdrop-opacity-[22%] -backdrop-saturate- -backdrop-saturate-[144%] -backdrop-sepia- -backdrop-sepia-[0.38] -bada55 -basis- -basis-[var(--basis)] -bg- -bg-[#0000ffcc] -bg-[#0f0] -bg-[#0f0_var(--value)] -bg-[#ff0000] -bg-[center_top_1rem] -bg-[color:var(--value1)_var(--value2)] -bg-[hsl(0,100%,50%)] -bg-[hsla(0,100%,50%,0.3)] -bg-[image(),var(--value)] -bg-[image:var(--value),var(--value)] -bg-[length:200px_100px] -bg-[length:var(--value)] -bg-[linear-gradient(#eee,#fff),conic-gradient(red,orange,yellow,green,blue)] -bg-[linear-gradient(#eee,#fff)] -bg-[position:200px_100px] -bg-[position:var(--value)] -bg-[rgb(123,123,123)] -bg-[rgb(123,_456,_123)_black] -bg-[rgb(123_456_789)] -bg-[rgba(123,123,123,0.5)] -bg-[url('/path-to-image.png')] -bg-[url:var(--url)] -bg-[var(--value),var(--value)] -bg-[var(--value1)_var(--value2)] -bg-opacity- -bg-opacity-[0.11] -bg-opacity-[var(--value)] -black -blur- -blur-[15px] -body -body> -border- -border-[#f00] -border-[2.5px] -border-[color:var(--value)] -border-[length:var(--value)] -border-[red_black] -border-b- -border-b-[#f00] -border-b-[2.5px] -border-b-[color:var(--value)] -border-b-[length:var(--value)] -border-l- -border-l-[#f00] -border-l-[2.5px] -border-l-[color:var(--value)] -border-l-[length:var(--value)] -border-opacity- -border-opacity-[0.8] -border-opacity-[var(--value)] -border-r- -border-r-[#f00] -border-r-[2.5px] -border-r-[color:var(--value)] -border-r-[length:var(--value)] -border-t- -border-t-[#f00] -border-t-[2.5px] -border-t-[color:var(--value)] -border-t-[length:var(--value)] -bottom- -bottom-[11px] -bottom-[var(--value)] -brightness- -brightness-[300%] -but -calc -caret- -caret-[black] -caret-[var(--value)] -center_top_1rem -charset -charset= -checking -clamp -class -class= -col- -col-[7] -col-end- -col-end-[7] -col-start- -col-start-[7] -color:var -columns- -columns-[20] -columns-[var(--columns)] -content -content- -content-['>'] -content-['hello'] -content-[attr(content-before)] -content-before -content= -contrast- -contrast-[2.4] -css -cur -cursor- -cursor-[pointer] -cursor-[url( -cursor-[url(hand.cur)_2_2,pointer] -cursor-[var(--value)] -da5b66 -decoration- -decoration-[black] -decoration-[color:var(--color)] -decoration-[length:10px] -decoration-[rgb(123,123,123)] -decoration-[rgb(123,_123,_123)] -decoration-[rgb(123_123_123)] -delay- -delay-[var(--delay)] -device-width, -div -div> -divide- -divide-[black] -divide-[var(--value)] -divide-opacity- -divide-opacity-[0.8] -divide-opacity-[var(--value)] -divide-x- -divide-x-[20cm] -divide-x-[calc(20%-1cm)] -divide-y- -divide-y-[20cm] -divide-y-[calc(20%-1cm)] -do-not-generate-this -drop-shadow- -drop-shadow-[0px_1px_2px_black] -duration- -duration-[2s] -duration-[var(--app-duration)] -eee, -en -f00 -family-name:var -ff0000 -fff -fill- -fill-[#da5b66] -fill-[url(#icon-gradient)] -fill-[var(--value)] -flex- -flex-[var(--flex)] -flex-grow- -flex-grow-[var(--grow)] -flex-shrink- -flex-shrink-[var(--shrink)] -font- -font-[ -font-['Gill_Sans'] -font-[300] -font-[Georgia,serif] -font-[family-name:var(--value)] -font-[invalid_font_because_spaces] -font-[number:lighter] -font-[number:var(--value)] -font-[sans-serif,serif] -font-[serif,var(--value)] -font-[var(--font1),var(--font2)] -from- -from-[#da5b66] -from-[var(--color)] -gap- -gap-[20px] -gap-[var(--value)] -gap-x- -gap-x-[20px] -gap-x-[var(--value)] -gap-y- -gap-y-[20px] -gap-y-[var(--value)] -grayscale- -grayscale-[0.55] -grid-cols- -grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px] -grid-cols-[[linename],1fr,auto] -grid-rows- -grid-rows-[200px,repeat(auto-fill,minmax(15%,100px)),300px] -grow- -grow-[var(--grow)] -h- -h-[3.23rem] -h-[calc(100%+1rem)] -h-[var(--height)] -hand -head -head> -hello -href -href= -hsl -hsla -html -html> -hue-rotate- -hue-rotate-[0.8turn] -ico -icon -icon-gradient -image -image:var -indent- -indent-[50%] -indent-[var(--indent)] -initial-scale -initial-scale=1.0 -inset- -inset-[11px] -inset-[var(--value)] -inset-x- -inset-x-[11px] -inset-x-[var(--value)] -inset-y- -inset-y-[11px] -inset-y-[var(--value)] -invalid_font_because_spaces -invert- -invert-[0.75] -is -issues, -it-is-invalid-syntax -lang -lang= -leading- -leading-[var(--leading)] -left- -left-[11px] -left-[var(--value)] -length -length:10px -length:200px_100px -length:var -lg:grid-cols- -lg:grid-cols-[200px,repeat(auto-fill,minmax(15%,100px)),300px] -lg:text- -lg:text-[14px] -linear-gradient -linename -link -list- -list-['\1F44D'] -list-[var(--value)] -m- -m-[7px] -max-h- -max-h-[3.23rem] -max-h-[calc(100%+1rem)] -max-h-[var(--height)] -max-w- -max-w-[3.23rem] -max-w-[calc(100%+1rem)] -max-w-[var(--width)] -mb- -mb-[7px] -meta -min -min-h- -min-h-[3.23rem] -min-h-[calc(100%+1rem)] -min-h-[var(--height)] -min-w- -min-w-[3.23rem] -min-w-[calc(100%+1rem)] -min-w-[var(--width)] -minmax -ml- -ml-[7px] -mr- -mr-[7px] -mt- -mt-[7px] -mt-[clamp(30px,100px)] -mx- -mx-[7px] -my- -my-[7px] -name -name= -not -number:lighter -number:var -object- -object-[50%,50%] -object-[top,right] -object-[var(--position)] -of -opacity,width -opacity- -opacity-[0.8] -opacity-[var(--opacity)] -order- -order-[4] -order-[var(--value)] -origin- -origin-[50px_50px] -outline- -outline-[10px] -outline-[black] -outline-[color:var(--outline)] -outline-[length:var(--outline)] -outline-offset- -outline-offset-[10px] -p- -p-[7px] -pb- -pb-[7px] -pl- -pl-[7px] -placeholder- -placeholder-[var(--placeholder)] -placeholder-opacity- -placeholder-opacity-[var(--placeholder-opacity)] -png -pointer -pong_1s_cubic-bezier -position:200px_100px -position:var -pr- -pr-[7px] -pt- -pt-[7px] -pt-[clamp(30px,100px)] -purely -px- -px-[7px] -py- -py-[7px] -red,orange,yellow,green,blue -red_black -rel -rel= -rgb -rgba -right- -right-[11px] -right-[var(--value)] -ring- -ring-[#76ad65] -ring-[10px] -ring-[color:var(--value)] -ring-[length:(var(--value))] -ring-offset- -ring-offset-[#76ad65] -ring-offset-[#ad672f] -ring-offset-[19rem] -ring-offset-[color:var(--value)] -ring-offset-[length:var(--value)] -ring-opacity- -ring-opacity-[var(--ring-opacity)] -rotate- -rotate-[1.5turn] -rotate-[2.3rad] -rotate-[23deg] -rotate-[401grad] -rounded- -rounded-[11px] -rounded-b- -rounded-b-[var(--radius)] -rounded-bl- -rounded-bl-[var(--radius)] -rounded-br- -rounded-br-[var(--radius)] -rounded-l- -rounded-l-[var(--radius)] -rounded-r- -rounded-r-[var(--radius)] -rounded-t- -rounded-t-[var(--radius)] -rounded-tl- -rounded-tl-[var(--radius)] -rounded-tr- -rounded-tr-[var(--radius)] -row- -row-[7] -row-end- -row-end-[7] -row-start- -row-start-[7] -sans-serif,serif -saturate- -saturate-[180%] -scale- -scale-[0.7] -scale-[var(--value)] -scale-x- -scale-x-[0.7] -scale-x-[var(--value)] -scale-y- -scale-y-[0.7] -scale-y-[var(--value)] -scroll-m- -scroll-m-[7px] -scroll-mb- -scroll-mb-[7px] -scroll-ml- -scroll-ml-[7px] -scroll-mr- -scroll-mr-[7px] -scroll-mt- -scroll-mt-[7px] -scroll-mt-[var(--scroll-margin)] -scroll-mx- -scroll-mx-[7px] -scroll-my- -scroll-my-[7px] -scroll-p- -scroll-p-[7px] -scroll-pb- -scroll-pb-[7px] -scroll-pl- -scroll-pl-[7px] -scroll-pr- -scroll-pr-[7px] -scroll-pt- -scroll-pt-[7px] -scroll-pt-[var(--scroll-padding)] -scroll-px- -scroll-px-[7px] -scroll-py- -scroll-py-[7px] -sepia- -sepia-[0.2] -serif,var -shadow- -shadow-[0px_1px_2px_black] -shadow-[shadow:var(--value)] -shadow:var -shrink- -shrink-[var(--shrink)] -skew-x- -skew-x-[3px] -skew-x-[var(--value)] -skew-y- -skew-y-[3px] -skew-y-[var(--value)] -space-x- -space-x-[20cm] -space-x-[calc(20%-1cm)] -space-y- -space-y-[20cm] -space-y-[calc(20%-1cm)] -stroke- -stroke-[#da5b66] -stroke-[20px] -stroke-[color:var(--value)] -stroke-[length:var(--value)] -stroke-[url(#icon-gradient)] -stylesheet -syntax-wise -text- -text-[0] -text-[10px] -text-[2.23rem] -text-[angle:var(--angle)] -text-[black] -text-[color:var(--color)] -text-[length:var(--font-size)] -text-[min(10vh,100px)] -text-[rgb(123,123,123)] -text-[rgb(123,_123,_123)] -text-[rgb(123_123_123)] -text-opacity- -text-opacity-[0.8] -text-opacity-[var(--value)] -the -this -title -title> -to- -to-[#da5b66] -to-[var(--color)] -top,left -top,right -top- -top-[11px] -top-[var(--value)] -tracking- -tracking-[var(--tracking)] -transition- -transition-[opacity,width] -translate-x- -translate-x-[12%] -translate-x-[var(--value)] -translate-y- -translate-y-[12%] -translate-y-[var(--value)] -underline-offset- -underline-offset-[10px] -url -url:var -validity -value, -var -via- -via-[#da5b66] -via-[var(--color)] -viewport -w- -w-[')()'] -w-['][]'] -w-['}{}'] -w-[(())] -w-[()] -w-[([)]] -w-[({)}] -w-[)()] -w-[)(] -w-[0] -w-[3.23rem] -w-[[(])] -w-[[[]]] -w-[[]] -w-[[{]}] -w-[][] -w-[][]] -w-[calc(100%+1rem)] -w-[calc(100%/3-1rem*2)] -w-[calc(var(--10-10px,calc(-20px-(-30px--40px)))-50px)] -w-[do-not-generate-this]w-[it-is-invalid-syntax] -w-[var(--width)] -w-[var(--width,calc(100%+1rem))] -w-[{(})] -w-[{[}]] -w-[{{}}] -w-[{}] -w-[}{] -w-[}{}] -width -width=device-width, -will-change- -will-change-[top,left] -will-change-[var(--will-change)] -z- -z-[123] -z-[var(--value)] From 529434b1d269d20ff97f23701f213d18159c61be Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 16 Dec 2021 13:57:25 -0500 Subject: [PATCH 09/23] Collect all capture groups --- src/lib/defaultExtractor.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 8e0e001e5619..5673fceef74c 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -18,9 +18,13 @@ const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') console.log(BROAD_MATCH_GLOBAL_REGEXP) const INNER_MATCH_GLOBAL_REGEXP = /[^<>"'`\s.(){}[\]#=%]*[^<>"'`\s.(){}[\]#=%:]/g +/** + * @param {string} content + */ export function defaultExtractor(content) { - let broadMatches = content.match(BROAD_MATCH_GLOBAL_REGEXP) || [] + let broadMatches = content.matchAll(BROAD_MATCH_GLOBAL_REGEXP) let innerMatches = content.match(INNER_MATCH_GLOBAL_REGEXP) || [] + let results = [...broadMatches, ...innerMatches].flat().filter(v => v !== undefined) - return [...broadMatches, ...innerMatches] + return results } From ad5f846d3e7bc589ea0fcd9b198a69c622c65993 Mon Sep 17 00:00:00 2001 From: Jordan Pittman Date: Thu, 16 Dec 2021 13:57:33 -0500 Subject: [PATCH 10/23] Capture classes inside quotes --- src/lib/defaultExtractor.js | 13 ++++++++----- tests/default-extractor.test.js | 11 +++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index 5673fceef74c..bdeebfe4b983 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -1,16 +1,19 @@ const PATTERNS = [ + /(?:\['([^'\s]+)')/.source, // ['text-lg' -> text-lg + /(?:\["([^"\s]+)")/.source, // ["text-lg" -> text-lg + /(?:\[`([^`\s]+)`)/.source, // [`text-lg` -> text-lg /([^<>"'`\s]*\[\w*'[^"`\s]*'?\])/.source, // font-['some_font',sans-serif] - /* Break 1 */ /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] + /([^<>"'`\s]*\[\w*"[^'`\s]*"?\])/.source, // font-["some_font",sans-serif] /([^<>"'`\s]*\[\w*\('[^"'`\s]*'\)\])/.source, // bg-[url('...')] - /* Break 2 */ /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")] + /([^<>"'`\s]*\[\w*\("[^"'`\s]*"\)\])/.source, // bg-[url("...")] /([^<>"'`\s]*\[\w*\('[^"`\s]*'\)\])/.source, // bg-[url('...'),url('...')] - /* Break 3 */ /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")] + /([^<>"'`\s]*\[\w*\("[^'`\s]*"\)\])/.source, // bg-[url("..."),url("...")] /([^<>"'`\s]*\['[^"'`\s]*'\])/.source, // `content-['hello']` but not `content-['hello']']` - /* Break 4*/ /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` + /([^<>"'`\s]*\["[^"'`\s]*"\])/.source, // `content-["hello"]` but not `content-["hello"]"]` /([^<>"'`\s]*\[[^<>"'`\s]*:'[^"'`\s]*'\])/.source, // `[content:'hello']` but not `[content:"hello"]` /([^<>"'`\s]*\[[^<>"'`\s]*:"[^"'`\s]*"\])/.source, // `[content:"hello"]` but not `[content:'hello']` /([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)/.source, // `fill-[#bada55]`, `fill-[#bada55]/50` - /(?:[^\[]([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)[^\]])/.source, // Stuff + // /(?:[^\[]([^<>"'`\s]*\[[^"'`\s]+\][^<>"'`\s]*)[^\]])/.source, // Stuff /([^<>"'`\s]*[^"'`\s:\\])/.source, // `px-1.5`, `uppercase` but not `uppercase:` ].join('|') diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 1701cbfe430e..0124df929b0c 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -26,6 +26,11 @@ const input = html`