@cwcss/crosswind 0.1.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +52 -0
- package/dist/bin/cli.js +14615 -0
- package/dist/build.d.ts +24 -0
- package/dist/config.d.ts +5 -0
- package/dist/generator.d.ts +31 -0
- package/dist/index.d.ts +10 -0
- package/dist/parser.d.ts +42 -0
- package/dist/plugin.d.ts +22 -0
- package/dist/preflight-forms.d.ts +5 -0
- package/dist/preflight.d.ts +2 -0
- package/dist/rules-advanced.d.ts +27 -0
- package/dist/rules-effects.d.ts +25 -0
- package/dist/rules-forms.d.ts +7 -0
- package/dist/rules-grid.d.ts +13 -0
- package/dist/rules-interactivity.d.ts +41 -0
- package/dist/rules-layout.d.ts +26 -0
- package/dist/rules-transforms.d.ts +33 -0
- package/dist/rules-typography.d.ts +41 -0
- package/dist/rules.d.ts +39 -0
- package/dist/scanner.d.ts +18 -0
- package/dist/src/index.js +12848 -0
- package/dist/transformer-compile-class.d.ts +37 -0
- package/{src/types.ts → dist/types.d.ts} +17 -86
- package/package.json +2 -16
- package/PLUGIN.md +0 -235
- package/benchmark/framework-comparison.bench.ts +0 -850
- package/bin/cli.ts +0 -365
- package/bin/crosswind +0 -0
- package/bin/headwind +0 -0
- package/build.ts +0 -8
- package/crosswind.config.ts +0 -9
- package/example/comprehensive.html +0 -70
- package/example/index.html +0 -21
- package/example/output.css +0 -236
- package/examples/plugin/README.md +0 -112
- package/examples/plugin/build.ts +0 -32
- package/examples/plugin/src/index.html +0 -34
- package/examples/plugin/src/index.ts +0 -7
- package/headwind +0 -2
- package/src/build.ts +0 -101
- package/src/config.ts +0 -529
- package/src/generator.ts +0 -2173
- package/src/index.ts +0 -10
- package/src/parser.ts +0 -1471
- package/src/plugin.ts +0 -118
- package/src/preflight-forms.ts +0 -229
- package/src/preflight.ts +0 -388
- package/src/rules-advanced.ts +0 -477
- package/src/rules-effects.ts +0 -461
- package/src/rules-forms.ts +0 -103
- package/src/rules-grid.ts +0 -241
- package/src/rules-interactivity.ts +0 -525
- package/src/rules-layout.ts +0 -385
- package/src/rules-transforms.ts +0 -412
- package/src/rules-typography.ts +0 -486
- package/src/rules.ts +0 -809
- package/src/scanner.ts +0 -84
- package/src/transformer-compile-class.ts +0 -275
- package/test/advanced-features.test.ts +0 -911
- package/test/arbitrary.test.ts +0 -396
- package/test/attributify.test.ts +0 -592
- package/test/bracket-syntax.test.ts +0 -1133
- package/test/build.test.ts +0 -99
- package/test/colors.test.ts +0 -934
- package/test/flexbox.test.ts +0 -669
- package/test/generator.test.ts +0 -597
- package/test/grid.test.ts +0 -584
- package/test/layout.test.ts +0 -404
- package/test/modifiers.test.ts +0 -417
- package/test/parser.test.ts +0 -564
- package/test/performance-regression.test.ts +0 -376
- package/test/performance.test.ts +0 -568
- package/test/plugin.test.ts +0 -160
- package/test/scanner.test.ts +0 -94
- package/test/sizing.test.ts +0 -481
- package/test/spacing.test.ts +0 -394
- package/test/transformer-compile-class.test.ts +0 -287
- package/test/transforms.test.ts +0 -448
- package/test/typography.test.ts +0 -632
- package/test/variants-form-states.test.ts +0 -225
- package/test/variants-group-peer.test.ts +0 -66
- package/test/variants-media.test.ts +0 -213
- package/test/variants-positional.test.ts +0 -58
- package/test/variants-pseudo-elements.test.ts +0 -47
- package/test/variants-state.test.ts +0 -62
- package/tsconfig.json +0 -18
package/test/parser.test.ts
DELETED
|
@@ -1,564 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from 'bun:test'
|
|
2
|
-
import { extractClasses, parseClass } from '../src/parser'
|
|
3
|
-
|
|
4
|
-
describe('parseClass', () => {
|
|
5
|
-
it('should parse simple utility without value', () => {
|
|
6
|
-
const result = parseClass('flex')
|
|
7
|
-
expect(result).toEqual({
|
|
8
|
-
raw: 'flex',
|
|
9
|
-
variants: [],
|
|
10
|
-
utility: 'flex',
|
|
11
|
-
value: undefined,
|
|
12
|
-
important: false,
|
|
13
|
-
arbitrary: false,
|
|
14
|
-
})
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
it('should parse utility with value', () => {
|
|
18
|
-
const result = parseClass('p-4')
|
|
19
|
-
expect(result).toEqual({
|
|
20
|
-
raw: 'p-4',
|
|
21
|
-
variants: [],
|
|
22
|
-
utility: 'p',
|
|
23
|
-
value: '4',
|
|
24
|
-
important: false,
|
|
25
|
-
arbitrary: false,
|
|
26
|
-
})
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
it('should parse important modifier', () => {
|
|
30
|
-
const result = parseClass('!p-4')
|
|
31
|
-
expect(result).toEqual({
|
|
32
|
-
raw: '!p-4',
|
|
33
|
-
variants: [],
|
|
34
|
-
utility: 'p',
|
|
35
|
-
value: '4',
|
|
36
|
-
important: true,
|
|
37
|
-
arbitrary: false,
|
|
38
|
-
})
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should parse arbitrary value', () => {
|
|
42
|
-
const result = parseClass('w-[100px]')
|
|
43
|
-
expect(result).toEqual({
|
|
44
|
-
raw: 'w-[100px]',
|
|
45
|
-
variants: [],
|
|
46
|
-
utility: 'w',
|
|
47
|
-
value: '100px',
|
|
48
|
-
important: false,
|
|
49
|
-
arbitrary: true,
|
|
50
|
-
})
|
|
51
|
-
})
|
|
52
|
-
|
|
53
|
-
it('should parse arbitrary color value', () => {
|
|
54
|
-
const result = parseClass('bg-[#ff0000]')
|
|
55
|
-
expect(result).toEqual({
|
|
56
|
-
raw: 'bg-[#ff0000]',
|
|
57
|
-
variants: [],
|
|
58
|
-
utility: 'bg',
|
|
59
|
-
value: '#ff0000',
|
|
60
|
-
important: false,
|
|
61
|
-
arbitrary: true,
|
|
62
|
-
})
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
it('should parse arbitrary value with important', () => {
|
|
66
|
-
const result = parseClass('!w-[100px]')
|
|
67
|
-
expect(result).toEqual({
|
|
68
|
-
raw: '!w-[100px]',
|
|
69
|
-
variants: [],
|
|
70
|
-
utility: 'w',
|
|
71
|
-
value: '100px',
|
|
72
|
-
important: true,
|
|
73
|
-
arbitrary: true,
|
|
74
|
-
})
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
it('should parse utility with compound value', () => {
|
|
78
|
-
const result = parseClass('bg-blue-500')
|
|
79
|
-
expect(result).toEqual({
|
|
80
|
-
raw: 'bg-blue-500',
|
|
81
|
-
variants: [],
|
|
82
|
-
utility: 'bg',
|
|
83
|
-
value: 'blue-500',
|
|
84
|
-
important: false,
|
|
85
|
-
arbitrary: false,
|
|
86
|
-
})
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
it('should parse utility with single variant', () => {
|
|
90
|
-
const result = parseClass('hover:bg-blue-500')
|
|
91
|
-
expect(result).toEqual({
|
|
92
|
-
raw: 'hover:bg-blue-500',
|
|
93
|
-
variants: ['hover'],
|
|
94
|
-
utility: 'bg',
|
|
95
|
-
value: 'blue-500',
|
|
96
|
-
important: false,
|
|
97
|
-
arbitrary: false,
|
|
98
|
-
})
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
it('should parse utility with multiple variants', () => {
|
|
102
|
-
const result = parseClass('sm:hover:flex')
|
|
103
|
-
expect(result).toEqual({
|
|
104
|
-
raw: 'sm:hover:flex',
|
|
105
|
-
variants: ['sm', 'hover'],
|
|
106
|
-
utility: 'flex',
|
|
107
|
-
value: undefined,
|
|
108
|
-
important: false,
|
|
109
|
-
arbitrary: false,
|
|
110
|
-
})
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
it('should parse responsive variant with value', () => {
|
|
114
|
-
const result = parseClass('md:p-8')
|
|
115
|
-
expect(result).toEqual({
|
|
116
|
-
raw: 'md:p-8',
|
|
117
|
-
variants: ['md'],
|
|
118
|
-
utility: 'p',
|
|
119
|
-
value: '8',
|
|
120
|
-
important: false,
|
|
121
|
-
arbitrary: false,
|
|
122
|
-
})
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
it('should parse complex multi-variant utility', () => {
|
|
126
|
-
const result = parseClass('lg:dark:hover:text-gray-800')
|
|
127
|
-
expect(result).toEqual({
|
|
128
|
-
raw: 'lg:dark:hover:text-gray-800',
|
|
129
|
-
variants: ['lg', 'dark', 'hover'],
|
|
130
|
-
utility: 'text',
|
|
131
|
-
value: 'gray-800',
|
|
132
|
-
important: false,
|
|
133
|
-
arbitrary: false,
|
|
134
|
-
})
|
|
135
|
-
})
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
describe('extractClasses', () => {
|
|
139
|
-
it('should extract classes from class attribute', () => {
|
|
140
|
-
const html = '<div class="flex p-4 bg-blue-500"></div>'
|
|
141
|
-
const result = extractClasses(html)
|
|
142
|
-
expect(result).toEqual(new Set(['flex', 'p-4', 'bg-blue-500']))
|
|
143
|
-
})
|
|
144
|
-
|
|
145
|
-
it('should extract classes from className attribute', () => {
|
|
146
|
-
const jsx = '<div className="flex p-4 bg-blue-500"></div>'
|
|
147
|
-
const result = extractClasses(jsx)
|
|
148
|
-
expect(result).toEqual(new Set(['flex', 'p-4', 'bg-blue-500']))
|
|
149
|
-
})
|
|
150
|
-
|
|
151
|
-
it('should extract classes from className with curly braces', () => {
|
|
152
|
-
const jsx = '<div className={"flex p-4"}></div>'
|
|
153
|
-
const result = extractClasses(jsx)
|
|
154
|
-
expect(result).toEqual(new Set(['flex', 'p-4']))
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
it('should extract classes from template literals', () => {
|
|
158
|
-
const jsx = '<div className={`flex p-4 hover:bg-blue-500`}></div>'
|
|
159
|
-
const result = extractClasses(jsx)
|
|
160
|
-
expect(result).toEqual(new Set(['flex', 'p-4', 'hover:bg-blue-500']))
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
it('should handle multiple elements', () => {
|
|
164
|
-
const html = `
|
|
165
|
-
<div class="flex p-4">
|
|
166
|
-
<span className="text-sm">Text</span>
|
|
167
|
-
</div>
|
|
168
|
-
`
|
|
169
|
-
const result = extractClasses(html)
|
|
170
|
-
expect(result).toEqual(new Set(['flex', 'p-4', 'text-sm']))
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should handle variants', () => {
|
|
174
|
-
const html = '<div class="sm:flex md:p-8 hover:bg-blue-500"></div>'
|
|
175
|
-
const result = extractClasses(html)
|
|
176
|
-
expect(result).toEqual(new Set(['sm:flex', 'md:p-8', 'hover:bg-blue-500']))
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
it('should ignore empty strings', () => {
|
|
180
|
-
const html = '<div class=" flex p-4 "></div>'
|
|
181
|
-
const result = extractClasses(html)
|
|
182
|
-
expect(result).toEqual(new Set(['flex', 'p-4']))
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
it('should return empty set for content without classes', () => {
|
|
186
|
-
const html = '<div><p>No classes here</p></div>'
|
|
187
|
-
const result = extractClasses(html)
|
|
188
|
-
expect(result.size).toBe(0)
|
|
189
|
-
})
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
describe('parseClass - Edge Cases', () => {
|
|
193
|
-
it('should handle empty string', () => {
|
|
194
|
-
const result = parseClass('')
|
|
195
|
-
expect(result.utility).toBe('')
|
|
196
|
-
expect(result.variants).toEqual([])
|
|
197
|
-
})
|
|
198
|
-
|
|
199
|
-
it('should handle very long class name', () => {
|
|
200
|
-
const longClass = 'a'.repeat(1000)
|
|
201
|
-
const result = parseClass(longClass)
|
|
202
|
-
expect(result.utility).toBe(longClass)
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
it('should handle class with only dashes', () => {
|
|
206
|
-
const result = parseClass('---')
|
|
207
|
-
// Parser splits on last dash, so --- becomes -- with no value
|
|
208
|
-
expect(result.utility).toBe('--')
|
|
209
|
-
expect(result.value).toBeUndefined()
|
|
210
|
-
})
|
|
211
|
-
|
|
212
|
-
it('should handle class with trailing colon', () => {
|
|
213
|
-
const result = parseClass('hover:')
|
|
214
|
-
expect(result.variants).toEqual(['hover'])
|
|
215
|
-
expect(result.utility).toBe('')
|
|
216
|
-
})
|
|
217
|
-
|
|
218
|
-
it('should handle class with leading colon', () => {
|
|
219
|
-
const result = parseClass(':flex')
|
|
220
|
-
expect(result.variants).toEqual([''])
|
|
221
|
-
expect(result.utility).toBe('flex')
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
it('should handle multiple consecutive colons', () => {
|
|
225
|
-
const result = parseClass('sm::hover::flex')
|
|
226
|
-
expect(result.variants).toEqual(['sm', '', 'hover', ''])
|
|
227
|
-
expect(result.utility).toBe('flex')
|
|
228
|
-
})
|
|
229
|
-
|
|
230
|
-
it('should handle negative zero value', () => {
|
|
231
|
-
const result = parseClass('-m-0')
|
|
232
|
-
expect(result).toEqual({
|
|
233
|
-
raw: '-m-0',
|
|
234
|
-
variants: [],
|
|
235
|
-
utility: 'm',
|
|
236
|
-
value: '-0',
|
|
237
|
-
important: false,
|
|
238
|
-
arbitrary: false,
|
|
239
|
-
})
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
it('should handle fractional zero', () => {
|
|
243
|
-
const result = parseClass('w-0/0')
|
|
244
|
-
expect(result).toEqual({
|
|
245
|
-
raw: 'w-0/0',
|
|
246
|
-
variants: [],
|
|
247
|
-
utility: 'w',
|
|
248
|
-
value: '0/0',
|
|
249
|
-
important: false,
|
|
250
|
-
arbitrary: false,
|
|
251
|
-
})
|
|
252
|
-
})
|
|
253
|
-
|
|
254
|
-
it('should handle arbitrary value with nested brackets', () => {
|
|
255
|
-
const result = parseClass('w-[calc(100%-20px)]')
|
|
256
|
-
expect(result.arbitrary).toBe(true)
|
|
257
|
-
expect(result.utility).toBe('w')
|
|
258
|
-
expect(result.value).toBe('calc(100%-20px)')
|
|
259
|
-
})
|
|
260
|
-
|
|
261
|
-
it('should handle arbitrary value with special characters', () => {
|
|
262
|
-
const result = parseClass('bg-[rgba(255,0,0,0.5)]')
|
|
263
|
-
expect(result.arbitrary).toBe(true)
|
|
264
|
-
expect(result.value).toContain('rgba')
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
it('should handle multiple important modifiers', () => {
|
|
268
|
-
const result = parseClass('!!p-4')
|
|
269
|
-
// Should only process the first !
|
|
270
|
-
expect(result.important).toBe(true)
|
|
271
|
-
expect(result.raw).toBe('!!p-4')
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
it('should handle important with no utility', () => {
|
|
275
|
-
const result = parseClass('!')
|
|
276
|
-
expect(result.important).toBe(true)
|
|
277
|
-
expect(result.utility).toBe('')
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
it('should handle complex variant chain', () => {
|
|
281
|
-
const result = parseClass('2xl:dark:group-hover:peer-checked:first:focus:bg-red-500')
|
|
282
|
-
expect(result.variants).toEqual(['2xl', 'dark', 'group-hover', 'peer-checked', 'first', 'focus'])
|
|
283
|
-
expect(result.utility).toBe('bg')
|
|
284
|
-
expect(result.value).toBe('red-500')
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
it('should handle compound utility with multiple dashes', () => {
|
|
288
|
-
const result = parseClass('grid-cols-12')
|
|
289
|
-
expect(result.utility).toBe('grid-cols')
|
|
290
|
-
expect(result.value).toBe('12')
|
|
291
|
-
})
|
|
292
|
-
|
|
293
|
-
it('should handle negative compound utility', () => {
|
|
294
|
-
const result = parseClass('-translate-x-full')
|
|
295
|
-
expect(result.utility).toBe('translate-x')
|
|
296
|
-
expect(result.value).toBe('-full')
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
it('should handle arbitrary property with numbers', () => {
|
|
300
|
-
const result = parseClass('[line-height:1.5]')
|
|
301
|
-
expect(result.arbitrary).toBe(true)
|
|
302
|
-
expect(result.utility).toBe('line-height')
|
|
303
|
-
expect(result.value).toBe('1.5')
|
|
304
|
-
})
|
|
305
|
-
|
|
306
|
-
it('should handle arbitrary property with spaces in value', () => {
|
|
307
|
-
const result = parseClass('[font-family:ui-sans-serif]')
|
|
308
|
-
expect(result.arbitrary).toBe(true)
|
|
309
|
-
expect(result.utility).toBe('font-family')
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
it('should handle utility with uppercase letters', () => {
|
|
313
|
-
const result = parseClass('BG-RED-500')
|
|
314
|
-
// Lowercase is expected in utility names
|
|
315
|
-
expect(result.raw).toBe('BG-RED-500')
|
|
316
|
-
})
|
|
317
|
-
|
|
318
|
-
it('should handle fraction with large numbers', () => {
|
|
319
|
-
const result = parseClass('w-999/1000')
|
|
320
|
-
expect(result.utility).toBe('w')
|
|
321
|
-
expect(result.value).toBe('999/1000')
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
it('should handle negative fraction', () => {
|
|
325
|
-
const result = parseClass('-m-1/2')
|
|
326
|
-
expect(result.utility).toBe('m')
|
|
327
|
-
expect(result.value).toBe('-1/2')
|
|
328
|
-
})
|
|
329
|
-
|
|
330
|
-
it('should handle space-x without value', () => {
|
|
331
|
-
const result = parseClass('space-x')
|
|
332
|
-
expect(result.utility).toBe('space')
|
|
333
|
-
expect(result.value).toBe('x')
|
|
334
|
-
})
|
|
335
|
-
|
|
336
|
-
it('should handle divide-x without value', () => {
|
|
337
|
-
const result = parseClass('divide-x')
|
|
338
|
-
expect(result.utility).toBe('divide-x')
|
|
339
|
-
expect(result.value).toBe(undefined)
|
|
340
|
-
})
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
describe('extractClasses - Edge Cases', () => {
|
|
344
|
-
it('should handle empty HTML', () => {
|
|
345
|
-
const result = extractClasses('')
|
|
346
|
-
expect(result.size).toBe(0)
|
|
347
|
-
})
|
|
348
|
-
|
|
349
|
-
it('should handle malformed HTML', () => {
|
|
350
|
-
const html = '<div class="flex p-4'
|
|
351
|
-
const result = extractClasses(html)
|
|
352
|
-
// May not extract properly without closing quote
|
|
353
|
-
expect(result.size).toBeGreaterThanOrEqual(0)
|
|
354
|
-
})
|
|
355
|
-
|
|
356
|
-
it('should handle classes with newlines', () => {
|
|
357
|
-
const html = `<div class="flex
|
|
358
|
-
p-4
|
|
359
|
-
bg-blue-500"></div>`
|
|
360
|
-
const result = extractClasses(html)
|
|
361
|
-
expect(result.has('flex')).toBe(true)
|
|
362
|
-
expect(result.has('p-4')).toBe(true)
|
|
363
|
-
expect(result.has('bg-blue-500')).toBe(true)
|
|
364
|
-
})
|
|
365
|
-
|
|
366
|
-
it('should handle classes with tabs', () => {
|
|
367
|
-
const html = '<div class="flex\tp-4\tbg-blue-500"></div>'
|
|
368
|
-
const result = extractClasses(html)
|
|
369
|
-
expect(result.has('flex')).toBe(true)
|
|
370
|
-
expect(result.has('p-4')).toBe(true)
|
|
371
|
-
})
|
|
372
|
-
|
|
373
|
-
it('should handle duplicate classes', () => {
|
|
374
|
-
const html = '<div class="flex flex p-4 p-4"></div>'
|
|
375
|
-
const result = extractClasses(html)
|
|
376
|
-
expect(result.size).toBe(2) // Set removes duplicates
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
it('should handle classes with special characters in attribute', () => {
|
|
380
|
-
const html = '<div data-test="flex" class="p-4"></div>'
|
|
381
|
-
const result = extractClasses(html)
|
|
382
|
-
expect(result.has('p-4')).toBe(true)
|
|
383
|
-
// Should only extract from class/className attributes
|
|
384
|
-
})
|
|
385
|
-
|
|
386
|
-
it('should handle mixed quotes', () => {
|
|
387
|
-
const html = `<div class='flex "p-4"'></div>`
|
|
388
|
-
const result = extractClasses(html)
|
|
389
|
-
// Should extract from single-quoted attribute
|
|
390
|
-
expect(result.size).toBeGreaterThan(0)
|
|
391
|
-
})
|
|
392
|
-
|
|
393
|
-
it('should handle template literal with expressions', () => {
|
|
394
|
-
// eslint-disable-next-line no-template-curly-in-string
|
|
395
|
-
const jsx = '<div className={`flex ${isActive ? "active" : ""} p-4`}></div>'
|
|
396
|
-
const result = extractClasses(jsx)
|
|
397
|
-
expect(result.has('flex')).toBe(true)
|
|
398
|
-
expect(result.has('p-4')).toBe(true)
|
|
399
|
-
})
|
|
400
|
-
|
|
401
|
-
it('should handle very long class string', () => {
|
|
402
|
-
const classes = Array.from({ length: 1000 }).fill('p-4').join(' ')
|
|
403
|
-
const html = `<div class="${classes}"></div>`
|
|
404
|
-
const result = extractClasses(html)
|
|
405
|
-
expect(result.has('p-4')).toBe(true)
|
|
406
|
-
})
|
|
407
|
-
|
|
408
|
-
it('should ignore invalid class names', () => {
|
|
409
|
-
const html = '<div class="123invalid -flex @media"></div>'
|
|
410
|
-
const result = extractClasses(html)
|
|
411
|
-
// Should filter out invalid patterns
|
|
412
|
-
expect(result.has('123invalid')).toBe(false)
|
|
413
|
-
})
|
|
414
|
-
|
|
415
|
-
it('should handle consecutive spaces', () => {
|
|
416
|
-
const html = '<div class="flex p-4 bg-blue-500"></div>'
|
|
417
|
-
const result = extractClasses(html)
|
|
418
|
-
expect(result.size).toBe(3)
|
|
419
|
-
})
|
|
420
|
-
})
|
|
421
|
-
|
|
422
|
-
describe('parseClass - Extreme Edge Cases', () => {
|
|
423
|
-
it('should handle null-like strings', () => {
|
|
424
|
-
expect(() => parseClass('null')).not.toThrow()
|
|
425
|
-
expect(() => parseClass('undefined')).not.toThrow()
|
|
426
|
-
expect(() => parseClass('NaN')).not.toThrow()
|
|
427
|
-
})
|
|
428
|
-
|
|
429
|
-
it('should handle numbers as class names', () => {
|
|
430
|
-
const result = parseClass('123')
|
|
431
|
-
expect(result.utility).toBe('123')
|
|
432
|
-
expect(result.value).toBeUndefined()
|
|
433
|
-
})
|
|
434
|
-
|
|
435
|
-
it('should handle special characters in class names', () => {
|
|
436
|
-
expect(() => parseClass('@apply')).not.toThrow()
|
|
437
|
-
expect(() => parseClass('$variable')).not.toThrow()
|
|
438
|
-
expect(() => parseClass('#id-like')).not.toThrow()
|
|
439
|
-
})
|
|
440
|
-
|
|
441
|
-
it('should handle unicode characters', () => {
|
|
442
|
-
const result = parseClass('w-[20px]') // Normal
|
|
443
|
-
expect(result.arbitrary).toBe(true)
|
|
444
|
-
|
|
445
|
-
const result2 = parseClass('text-[📝]') // Emoji
|
|
446
|
-
expect(result2.arbitrary).toBe(true)
|
|
447
|
-
})
|
|
448
|
-
|
|
449
|
-
it('should handle extremely nested brackets', () => {
|
|
450
|
-
const result = parseClass('w-[calc(calc(100%-10px)-5px)]')
|
|
451
|
-
expect(result.arbitrary).toBe(true)
|
|
452
|
-
expect(result.value).toContain('calc')
|
|
453
|
-
})
|
|
454
|
-
|
|
455
|
-
it('should handle URL in arbitrary value', () => {
|
|
456
|
-
const result = parseClass('bg-[url(https://example.com/image.jpg)]')
|
|
457
|
-
expect(result.arbitrary).toBe(true)
|
|
458
|
-
expect(result.value).toContain('url')
|
|
459
|
-
})
|
|
460
|
-
|
|
461
|
-
it('should handle data URL in arbitrary value', () => {
|
|
462
|
-
const result = parseClass('bg-[url(data:image/svg+xml;base64,ABC123)]')
|
|
463
|
-
expect(result.arbitrary).toBe(true)
|
|
464
|
-
expect(result.value).toContain('data:')
|
|
465
|
-
})
|
|
466
|
-
|
|
467
|
-
it('should handle CSS variables in arbitrary value', () => {
|
|
468
|
-
const result = parseClass('w-[var(--custom-width)]')
|
|
469
|
-
expect(result.arbitrary).toBe(true)
|
|
470
|
-
expect(result.value).toContain('var(--')
|
|
471
|
-
})
|
|
472
|
-
|
|
473
|
-
it('should handle clamp in arbitrary value', () => {
|
|
474
|
-
const result = parseClass('text-[clamp(1rem,5vw,3rem)]')
|
|
475
|
-
expect(result.arbitrary).toBe(true)
|
|
476
|
-
expect(result.value).toContain('clamp')
|
|
477
|
-
})
|
|
478
|
-
|
|
479
|
-
it('should handle min/max in arbitrary value', () => {
|
|
480
|
-
const result = parseClass('w-[min(100%,500px)]')
|
|
481
|
-
expect(result.arbitrary).toBe(true)
|
|
482
|
-
expect(result.value).toContain('min')
|
|
483
|
-
})
|
|
484
|
-
|
|
485
|
-
it('should handle zero with units', () => {
|
|
486
|
-
expect(() => parseClass('w-[0px]')).not.toThrow()
|
|
487
|
-
expect(() => parseClass('h-[0rem]')).not.toThrow()
|
|
488
|
-
expect(() => parseClass('p-[0em]')).not.toThrow()
|
|
489
|
-
})
|
|
490
|
-
|
|
491
|
-
it('should handle extremely large numbers', () => {
|
|
492
|
-
const result = parseClass('w-[99999999px]')
|
|
493
|
-
expect(result.arbitrary).toBe(true)
|
|
494
|
-
expect(result.value).toBe('99999999px')
|
|
495
|
-
})
|
|
496
|
-
|
|
497
|
-
it('should handle extremely small numbers', () => {
|
|
498
|
-
const result = parseClass('w-[0.0001px]')
|
|
499
|
-
expect(result.arbitrary).toBe(true)
|
|
500
|
-
expect(result.value).toBe('0.0001px')
|
|
501
|
-
})
|
|
502
|
-
|
|
503
|
-
it('should handle scientific notation', () => {
|
|
504
|
-
const result = parseClass('w-[1e10px]')
|
|
505
|
-
expect(result.arbitrary).toBe(true)
|
|
506
|
-
expect(result.value).toBe('1e10px')
|
|
507
|
-
})
|
|
508
|
-
})
|
|
509
|
-
|
|
510
|
-
describe('extractClasses - Arbitrary Values', () => {
|
|
511
|
-
it('should extract arbitrary z-index values', () => {
|
|
512
|
-
const html = '<div class="z-[1] z-[999] z-[-1]"></div>'
|
|
513
|
-
const result = extractClasses(html)
|
|
514
|
-
expect(result).toEqual(new Set(['z-[1]', 'z-[999]', 'z-[-1]']))
|
|
515
|
-
})
|
|
516
|
-
|
|
517
|
-
it('should extract arbitrary width/height values', () => {
|
|
518
|
-
const html = '<div class="w-[100px] h-[50vh] min-w-[200px]"></div>'
|
|
519
|
-
const result = extractClasses(html)
|
|
520
|
-
expect(result).toEqual(new Set(['w-[100px]', 'h-[50vh]', 'min-w-[200px]']))
|
|
521
|
-
})
|
|
522
|
-
|
|
523
|
-
it('should extract arbitrary color values', () => {
|
|
524
|
-
const html = '<div class="bg-[#ff0000] text-[rgb(0,0,0)] border-[hsl(0,100%,50%)]"></div>'
|
|
525
|
-
const result = extractClasses(html)
|
|
526
|
-
expect(result).toEqual(new Set(['bg-[#ff0000]', 'text-[rgb(0,0,0)]', 'border-[hsl(0,100%,50%)]']))
|
|
527
|
-
})
|
|
528
|
-
|
|
529
|
-
it('should extract arbitrary values with variants', () => {
|
|
530
|
-
const html = '<div class="hover:z-[10] sm:w-[50%] focus:bg-[#000]"></div>'
|
|
531
|
-
const result = extractClasses(html)
|
|
532
|
-
expect(result).toEqual(new Set(['hover:z-[10]', 'sm:w-[50%]', 'focus:bg-[#000]']))
|
|
533
|
-
})
|
|
534
|
-
|
|
535
|
-
it('should extract arbitrary properties', () => {
|
|
536
|
-
const html = '<div class="[color:red] [mask-type:luminance] [display:grid]"></div>'
|
|
537
|
-
const result = extractClasses(html)
|
|
538
|
-
expect(result).toEqual(new Set(['[color:red]', '[mask-type:luminance]', '[display:grid]']))
|
|
539
|
-
})
|
|
540
|
-
|
|
541
|
-
it('should extract important arbitrary values', () => {
|
|
542
|
-
const html = '<div class="!z-[9999] !w-[100%]"></div>'
|
|
543
|
-
const result = extractClasses(html)
|
|
544
|
-
expect(result).toEqual(new Set(['!z-[9999]', '!w-[100%]']))
|
|
545
|
-
})
|
|
546
|
-
|
|
547
|
-
it('should extract negative arbitrary values', () => {
|
|
548
|
-
const html = '<div class="-mt-[20px] -translate-x-[50%]"></div>'
|
|
549
|
-
const result = extractClasses(html)
|
|
550
|
-
expect(result).toEqual(new Set(['-mt-[20px]', '-translate-x-[50%]']))
|
|
551
|
-
})
|
|
552
|
-
|
|
553
|
-
it('should extract arbitrary values with calc()', () => {
|
|
554
|
-
const html = '<div class="w-[calc(100%-2rem)] h-[calc(100vh-64px)]"></div>'
|
|
555
|
-
const result = extractClasses(html)
|
|
556
|
-
expect(result).toEqual(new Set(['w-[calc(100%-2rem)]', 'h-[calc(100vh-64px)]']))
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
it('should extract mixed regular and arbitrary classes', () => {
|
|
560
|
-
const html = '<div class="flex p-4 z-[1] w-[100px] bg-blue-500 hover:z-[999]"></div>'
|
|
561
|
-
const result = extractClasses(html)
|
|
562
|
-
expect(result).toEqual(new Set(['flex', 'p-4', 'z-[1]', 'w-[100px]', 'bg-blue-500', 'hover:z-[999]']))
|
|
563
|
-
})
|
|
564
|
-
})
|