From da7396cf7759dc68f4c2a4c1b03d46e5718cf915 Mon Sep 17 00:00:00 2001 From: Adam Wathan Date: Fri, 24 Dec 2021 12:56:50 -0500 Subject: [PATCH] Sketching out more specific tests for our default extractor --- src/lib/defaultExtractor.js | 15 +++ tests/default-extractor.test.js | 216 +++++++++++++++++++++++++++++++- 2 files changed, 230 insertions(+), 1 deletion(-) diff --git a/src/lib/defaultExtractor.js b/src/lib/defaultExtractor.js index eccf8efc4..49004e18d 100644 --- a/src/lib/defaultExtractor.js +++ b/src/lib/defaultExtractor.js @@ -14,6 +14,11 @@ const PATTERNS = [ /([^<>"'`\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:` + + // Arbitrary properties + // /([^"\s]*\[[^\s]+?\][^"\s]*)/.source, + // /([^'\s]*\[[^\s]+?\][^'\s]*)/.source, + // /([^`\s]*\[[^\s]+?\][^`\s]*)/.source, ].join('|') const BROAD_MATCH_GLOBAL_REGEXP = new RegExp(PATTERNS, 'g') @@ -29,3 +34,13 @@ export function defaultExtractor(content) { return results } + +// Regular utilities +// {{modifier}:}*{namespace}{-{suffix}}*{/{opacityModifier}}? + +// Arbitrary values +// {{modifier}:}*{namespace}-[{arbitraryValue}]{/{opacityModifier}}? +// arbitraryValue: no whitespace, balanced quotes unless within quotes, balanced brackets unless within quotes + +// Arbitrary properties +// {{modifier}:}*[{validCssPropertyName}:{arbitraryValue}] diff --git a/tests/default-extractor.test.js b/tests/default-extractor.test.js index 5c128f642..e507f8de4 100644 --- a/tests/default-extractor.test.js +++ b/tests/default-extractor.test.js @@ -25,6 +25,7 @@ const input =
+
` + jsxExample @@ -65,6 +66,7 @@ const includes = [ `fill-[#bada55]/50`, `px-1.5`, `uppercase`, + `lowercase`, `hover:font-bold`, `text-sm`, `text-[10px]`, @@ -87,6 +89,7 @@ const includes = [ `content-['>']`, `hover:test`, `overflow-scroll`, + `[--y:theme(colors.blue.500)]`, ] const excludes = [ @@ -109,3 +112,214 @@ test('The default extractor works as expected', async () => { expect(extractions).not.toContain(str) } }) + +// Scenarios: +// - In double quoted class attribute +// - In single quoted class attribute +// - Single-quoted as a variable +// - Double-quoted as a variable +// - Single-quoted as first array item +// - Double-quoted as first array item +// - Single-quoted as middle array item +// - Double-quoted as middle array item +// - Single-quoted as last array item +// - Double-quoted as last array item +// - Bare as an object key (with trailing `:`) +// - Quoted as an object key (with trailing `:`) +// - Within a template literal +// - Within a template literal directly before interpolation +// - Within a template literal directly after interpolation +// - JS: ${...} +// - PHP: {$...} +// - Ruby: #{...} +// - Within a string of HTML wrapped in escaped quotes + +test('basic utility classes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-center') + expect(extractions).toContain('font-bold') + expect(extractions).toContain('px-4') + expect(extractions).toContain('pointer-events-none') +}) + +test('modifiers with basic utilites', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('hover:text-center') + expect(extractions).toContain('hover:focus:font-bold') +}) + +test('utilities with dot characters', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('px-1.5') + expect(extractions).toContain('active:px-2.5') + expect(extractions).toContain('hover:focus:px-3.5') +}) + +test('basic utilities with color opacity modifier', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-red-500/25') + expect(extractions).toContain('hover:text-red-500/50') + expect(extractions).toContain('hover:active:text-red-500/75') +}) + +test('basic arbitrary values', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('px-[25px]') + expect(extractions).toContain('hover:px-[40rem]') + expect(extractions).toContain('hover:focus:px-[23vh]') +}) + +test('arbitrary values with color opacity modifier', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-[#bada55]/25') + expect(extractions).toContain('hover:text-[#bada55]/50') + expect(extractions).toContain('hover:active:text-[#bada55]/75') +}) + +test('arbitrary values with spaces', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('grid-cols-[1fr_200px_3fr]') + expect(extractions).toContain('md:grid-cols-[2fr_100px_1fr]') + expect(extractions).toContain('open:lg:grid-cols-[3fr_300px_1fr]') +}) + +test('arbitrary values with css variables', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('fill-[var(--my-color)]') + expect(extractions).toContain('hover:fill-[var(--my-color-2)]') + expect(extractions).toContain('hover:focus:fill-[var(--my-color-3)]') +}) + +test('arbitrary values with type hints', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-[color:var(--my-color)]') + expect(extractions).toContain('hover:text-[color:var(--my-color-2)]') + expect(extractions).toContain('hover:focus:text-[color:var(--my-color-3)]') +}) + +test('arbitrary values with single quotes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`content-['hello_world']`) + expect(extractions).toContain(`hover:content-['hello_world_2']`) + expect(extractions).toContain(`hover:focus:content-['hello_world_3']`) +}) + +test('arbitrary values with double quotes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`content-["hello_world"]`) + expect(extractions).toContain(`hover:content-["hello_world_2"]`) + expect(extractions).toContain(`hover:focus:content-["hello_world_3"]`) +}) + +test('arbitrary values with some single quoted values', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`font-['Open_Sans',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-['Proxima_Nova',_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-['Inter_var',_system-ui,_sans-serif]`) +}) + +test('arbitrary values with some double quoted values', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`font-["Open_Sans",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:font-["Proxima_Nova",_system-ui,_sans-serif]`) + expect(extractions).toContain(`hover:focus:font-["Inter_var",_system-ui,_sans-serif]`) +}) + +test('arbitrary values with escaped underscores', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`content-['hello\\_world']`) + expect(extractions).toContain(`hover:content-['hello\\_world\\_2']`) + expect(extractions).toContain(`hover:focus:content-['hello\\_world\\_3']`) +}) + +test('basic utilities with arbitrary color opacity modifier', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-red-500/[.25]') + expect(extractions).toContain('hover:text-red-500/[.5]') + expect(extractions).toContain('hover:active:text-red-500/[.75]') +}) + +test('arbitrary values with arbitrary color opacity modifier', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain('text-[#bada55]/[.25]') + expect(extractions).toContain('hover:text-[#bada55]/[.5]') + expect(extractions).toContain('hover:active:text-[#bada55]/[.75]') +}) + +test('arbitrary values with angle brackets', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`content-[>]`) + expect(extractions).toContain(`hover:content-[<]`) + expect(extractions).toContain(`hover:focus:content-[>]`) +}) + +test('arbitrary values with angle brackets in single quotes', async () => { + const extractions = defaultExtractor(` +
+ `) + + expect(extractions).toContain(`content-['>']`) + expect(extractions).toContain(`hover:content-['<']`) + expect(extractions).toContain(`hover:focus:content-['>']`) +}) + +test('arbitrary values with angle brackets in double quotes', async () => { + const extractions = defaultExtractor(` +
"] hover:content-["<"] hover:focus:content-[">"]">
+ `) + + expect(extractions).toContain(`content-[">"]`) + expect(extractions).toContain(`hover:content-["<"]`) + expect(extractions).toContain(`hover:focus:content-[">"]`) +})