@csszyx/cli 0.9.9 → 0.10.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.
@@ -0,0 +1,3626 @@
1
+ import { resolve, dirname } from 'node:path';
2
+ import { existsSync, writeFileSync } from 'node:fs';
3
+ import { mkdir } from 'node:fs/promises';
4
+ import { pathToFileURL } from 'node:url';
5
+ import resolveConfig from 'tailwindcss/resolveConfig.js';
6
+ import { parse } from '@babel/parser';
7
+ import * as t from '@babel/types';
8
+ import { REMOVED_BOOLEAN_SUGAR, SUGGESTION_MAP } from '@csszyx/compiler';
9
+
10
+ const CONFIG_FILES = [
11
+ "tailwind.config.ts",
12
+ "tailwind.config.js",
13
+ "tailwind.config.cjs",
14
+ "tailwind.config.mjs"
15
+ ];
16
+ function findConfigFile(cwd) {
17
+ for (const fileName of CONFIG_FILES) {
18
+ const configPath = resolve(cwd, fileName);
19
+ if (existsSync(configPath)) {
20
+ return configPath;
21
+ }
22
+ }
23
+ return null;
24
+ }
25
+ async function scanTailwindConfig(configPath) {
26
+ const absolutePath = resolve(configPath);
27
+ if (!existsSync(absolutePath)) {
28
+ throw new Error(`Tailwind config not found: ${absolutePath}`);
29
+ }
30
+ let userConfig;
31
+ try {
32
+ const fileUrl = pathToFileURL(absolutePath).href;
33
+ const module = await import(fileUrl);
34
+ userConfig = module.default || module;
35
+ } catch (error) {
36
+ throw new Error(
37
+ `Failed to load Tailwind config: ${error instanceof Error ? error.message : String(error)}`
38
+ );
39
+ }
40
+ const resolvedConfig = resolveConfig(userConfig);
41
+ const theme = resolvedConfig.theme;
42
+ const hasCustomColors = Boolean(userConfig.theme?.colors || userConfig.theme?.extend?.colors);
43
+ const hasCustomSpacing = Boolean(
44
+ userConfig.theme?.spacing || userConfig.theme?.extend?.spacing
45
+ );
46
+ return {
47
+ theme,
48
+ configPath: absolutePath,
49
+ hasCustomColors,
50
+ hasCustomSpacing
51
+ };
52
+ }
53
+ function flattenColors(colors) {
54
+ const result = [];
55
+ for (const [key, value] of Object.entries(colors)) {
56
+ if (key === "inherit" || key === "current" || key === "transparent") {
57
+ result.push(key);
58
+ continue;
59
+ }
60
+ if (typeof value === "string") {
61
+ result.push(key);
62
+ } else if (typeof value === "object" && value !== null) {
63
+ for (const shade of Object.keys(value)) {
64
+ if (shade === "DEFAULT") {
65
+ result.push(key);
66
+ } else {
67
+ result.push(`${key}-${shade}`);
68
+ }
69
+ }
70
+ }
71
+ }
72
+ return result.sort();
73
+ }
74
+ function extractSpacingKeys(spacing) {
75
+ return Object.keys(spacing).sort((a, b) => {
76
+ const aNum = parseFloat(a);
77
+ const bNum = parseFloat(b);
78
+ if (!Number.isNaN(aNum) && !Number.isNaN(bNum)) {
79
+ return aNum - bNum;
80
+ }
81
+ if (!Number.isNaN(aNum)) {
82
+ return -1;
83
+ }
84
+ if (!Number.isNaN(bNum)) {
85
+ return 1;
86
+ }
87
+ return a.localeCompare(b);
88
+ });
89
+ }
90
+ function extractScreenKeys(screens) {
91
+ return Object.keys(screens);
92
+ }
93
+
94
+ const PROPERTY_MAPPINGS = [
95
+ // Layout
96
+ {
97
+ prop: "display",
98
+ prefix: "",
99
+ valueType: "display",
100
+ description: "CSS display property"
101
+ },
102
+ {
103
+ prop: "position",
104
+ prefix: "",
105
+ valueType: "position",
106
+ description: "CSS position property"
107
+ },
108
+ {
109
+ prop: "overflow",
110
+ prefix: "overflow",
111
+ valueType: "overflow",
112
+ description: "CSS overflow property"
113
+ },
114
+ {
115
+ prop: "z",
116
+ prefix: "z",
117
+ valueType: "zIndex",
118
+ description: "CSS z-index property"
119
+ },
120
+ // Flexbox & Grid
121
+ {
122
+ prop: "flex",
123
+ prefix: "flex",
124
+ valueType: "flex",
125
+ description: "Flex shorthand"
126
+ },
127
+ {
128
+ prop: "flexDir",
129
+ prefix: "flex",
130
+ valueType: "flexDirection",
131
+ description: "Flex direction"
132
+ },
133
+ {
134
+ prop: "justify",
135
+ prefix: "justify",
136
+ valueType: "justify",
137
+ description: "Justify content"
138
+ },
139
+ {
140
+ prop: "items",
141
+ prefix: "items",
142
+ valueType: "items",
143
+ description: "Align items"
144
+ },
145
+ {
146
+ prop: "gap",
147
+ prefix: "gap",
148
+ valueType: "spacing",
149
+ description: "Gap between flex/grid items"
150
+ },
151
+ {
152
+ prop: "gridCols",
153
+ prefix: "grid-cols",
154
+ valueType: "gridCols",
155
+ description: "Grid template columns"
156
+ },
157
+ {
158
+ prop: "gridRows",
159
+ prefix: "grid-rows",
160
+ valueType: "gridRows",
161
+ description: "Grid template rows"
162
+ },
163
+ {
164
+ prop: "col",
165
+ prefix: "col",
166
+ valueType: "col",
167
+ description: "Grid column span"
168
+ },
169
+ {
170
+ prop: "row",
171
+ prefix: "row",
172
+ valueType: "row",
173
+ description: "Grid row span"
174
+ },
175
+ // Spacing
176
+ {
177
+ prop: "p",
178
+ prefix: "p",
179
+ valueType: "spacing",
180
+ responsive: true,
181
+ description: "Padding (all sides)"
182
+ },
183
+ {
184
+ prop: "px",
185
+ prefix: "px",
186
+ valueType: "spacing",
187
+ responsive: true,
188
+ description: "Padding horizontal"
189
+ },
190
+ {
191
+ prop: "py",
192
+ prefix: "py",
193
+ valueType: "spacing",
194
+ responsive: true,
195
+ description: "Padding vertical"
196
+ },
197
+ {
198
+ prop: "pt",
199
+ prefix: "pt",
200
+ valueType: "spacing",
201
+ responsive: true,
202
+ description: "Padding top"
203
+ },
204
+ {
205
+ prop: "pr",
206
+ prefix: "pr",
207
+ valueType: "spacing",
208
+ responsive: true,
209
+ description: "Padding right"
210
+ },
211
+ {
212
+ prop: "pb",
213
+ prefix: "pb",
214
+ valueType: "spacing",
215
+ responsive: true,
216
+ description: "Padding bottom"
217
+ },
218
+ {
219
+ prop: "pl",
220
+ prefix: "pl",
221
+ valueType: "spacing",
222
+ responsive: true,
223
+ description: "Padding left"
224
+ },
225
+ {
226
+ prop: "m",
227
+ prefix: "m",
228
+ valueType: "spacing",
229
+ responsive: true,
230
+ description: "Margin (all sides)"
231
+ },
232
+ {
233
+ prop: "mx",
234
+ prefix: "mx",
235
+ valueType: "spacing",
236
+ responsive: true,
237
+ description: "Margin horizontal"
238
+ },
239
+ {
240
+ prop: "my",
241
+ prefix: "my",
242
+ valueType: "spacing",
243
+ responsive: true,
244
+ description: "Margin vertical"
245
+ },
246
+ {
247
+ prop: "mt",
248
+ prefix: "mt",
249
+ valueType: "spacing",
250
+ responsive: true,
251
+ description: "Margin top"
252
+ },
253
+ {
254
+ prop: "mr",
255
+ prefix: "mr",
256
+ valueType: "spacing",
257
+ responsive: true,
258
+ description: "Margin right"
259
+ },
260
+ {
261
+ prop: "mb",
262
+ prefix: "mb",
263
+ valueType: "spacing",
264
+ responsive: true,
265
+ description: "Margin bottom"
266
+ },
267
+ {
268
+ prop: "ml",
269
+ prefix: "ml",
270
+ valueType: "spacing",
271
+ responsive: true,
272
+ description: "Margin left"
273
+ },
274
+ // Sizing
275
+ {
276
+ prop: "w",
277
+ prefix: "w",
278
+ valueType: "sizing",
279
+ responsive: true,
280
+ description: "Width"
281
+ },
282
+ {
283
+ prop: "h",
284
+ prefix: "h",
285
+ valueType: "sizing",
286
+ responsive: true,
287
+ description: "Height"
288
+ },
289
+ {
290
+ prop: "minW",
291
+ prefix: "min-w",
292
+ valueType: "minWidth",
293
+ description: "Minimum width"
294
+ },
295
+ {
296
+ prop: "maxW",
297
+ prefix: "max-w",
298
+ valueType: "maxWidth",
299
+ description: "Maximum width"
300
+ },
301
+ {
302
+ prop: "minH",
303
+ prefix: "min-h",
304
+ valueType: "minHeight",
305
+ description: "Minimum height"
306
+ },
307
+ {
308
+ prop: "maxH",
309
+ prefix: "max-h",
310
+ valueType: "maxHeight",
311
+ description: "Maximum height"
312
+ },
313
+ // Colors
314
+ {
315
+ prop: "bg",
316
+ prefix: "bg",
317
+ valueType: "colors",
318
+ stateful: true,
319
+ description: "Background color"
320
+ },
321
+ {
322
+ prop: "color",
323
+ prefix: "text",
324
+ valueType: "colors",
325
+ stateful: true,
326
+ description: "Text color"
327
+ },
328
+ {
329
+ prop: "border",
330
+ prefix: "border",
331
+ valueType: "colors",
332
+ stateful: true,
333
+ description: "Border color"
334
+ },
335
+ {
336
+ prop: "ring",
337
+ prefix: "ring",
338
+ valueType: "colors",
339
+ stateful: true,
340
+ description: "Ring color"
341
+ },
342
+ {
343
+ prop: "fill",
344
+ prefix: "fill",
345
+ valueType: "colors",
346
+ description: "SVG fill color"
347
+ },
348
+ {
349
+ prop: "stroke",
350
+ prefix: "stroke",
351
+ valueType: "colors",
352
+ description: "SVG stroke color"
353
+ },
354
+ // Typography
355
+ {
356
+ prop: "weight",
357
+ prefix: "font",
358
+ valueType: "fontWeight",
359
+ description: "Font weight"
360
+ },
361
+ {
362
+ prop: "fontFamily",
363
+ prefix: "font",
364
+ valueType: "fontFamily",
365
+ description: "Font family"
366
+ },
367
+ {
368
+ prop: "text",
369
+ prefix: "text",
370
+ valueType: "fontSize",
371
+ description: "Font size"
372
+ },
373
+ {
374
+ prop: "leading",
375
+ prefix: "leading",
376
+ valueType: "lineHeight",
377
+ description: "Line height"
378
+ },
379
+ {
380
+ prop: "tracking",
381
+ prefix: "tracking",
382
+ valueType: "letterSpacing",
383
+ description: "Letter spacing"
384
+ },
385
+ {
386
+ prop: "textAlign",
387
+ prefix: "text",
388
+ valueType: "textAlign",
389
+ description: "Text alignment"
390
+ },
391
+ // Borders
392
+ {
393
+ prop: "rounded",
394
+ prefix: "rounded",
395
+ valueType: "borderRadius",
396
+ description: "Border radius"
397
+ },
398
+ // Effects
399
+ {
400
+ prop: "shadow",
401
+ prefix: "shadow",
402
+ valueType: "boxShadow",
403
+ description: "Box shadow"
404
+ },
405
+ {
406
+ prop: "opacity",
407
+ prefix: "opacity",
408
+ valueType: "opacity",
409
+ description: "Opacity"
410
+ },
411
+ // Transforms
412
+ {
413
+ prop: "scale",
414
+ prefix: "scale",
415
+ valueType: "scale",
416
+ description: "Scale transform"
417
+ },
418
+ {
419
+ prop: "rotate",
420
+ prefix: "rotate",
421
+ valueType: "rotate",
422
+ description: "Rotate transform"
423
+ },
424
+ {
425
+ prop: "translate",
426
+ prefix: "translate",
427
+ valueType: "translate",
428
+ description: "Translate transform"
429
+ },
430
+ // Transitions
431
+ {
432
+ prop: "transition",
433
+ prefix: "transition",
434
+ valueType: "transition",
435
+ description: "Transition property"
436
+ },
437
+ {
438
+ prop: "duration",
439
+ prefix: "duration",
440
+ valueType: "duration",
441
+ description: "Transition duration"
442
+ },
443
+ {
444
+ prop: "ease",
445
+ prefix: "ease",
446
+ valueType: "ease",
447
+ description: "Transition timing function"
448
+ }
449
+ ];
450
+ const STATIC_VALUE_TYPES = {
451
+ display: [
452
+ "block",
453
+ "inline-block",
454
+ "inline",
455
+ "flex",
456
+ "inline-flex",
457
+ "grid",
458
+ "inline-grid",
459
+ "hidden",
460
+ "contents",
461
+ "flow-root"
462
+ ],
463
+ position: ["static", "fixed", "absolute", "relative", "sticky"],
464
+ overflow: [
465
+ "auto",
466
+ "hidden",
467
+ "clip",
468
+ "visible",
469
+ "scroll",
470
+ "x-auto",
471
+ "y-auto",
472
+ "x-hidden",
473
+ "y-hidden",
474
+ "x-clip",
475
+ "y-clip",
476
+ "x-visible",
477
+ "y-visible",
478
+ "x-scroll",
479
+ "y-scroll"
480
+ ],
481
+ flexDirection: ["row", "row-reverse", "col", "col-reverse"],
482
+ justify: ["normal", "start", "end", "center", "between", "around", "evenly", "stretch"],
483
+ items: ["start", "end", "center", "baseline", "stretch"],
484
+ flex: ["1", "auto", "initial", "none"],
485
+ grid: ["flow-row", "flow-col", "flow-dense", "flow-row-dense", "flow-col-dense"],
486
+ gridCols: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "none", "subgrid"],
487
+ gridRows: ["1", "2", "3", "4", "5", "6", "none", "subgrid"],
488
+ col: [
489
+ "auto",
490
+ "span-1",
491
+ "span-2",
492
+ "span-3",
493
+ "span-4",
494
+ "span-5",
495
+ "span-6",
496
+ "span-7",
497
+ "span-8",
498
+ "span-9",
499
+ "span-10",
500
+ "span-11",
501
+ "span-12",
502
+ "span-full",
503
+ "start-1",
504
+ "start-2",
505
+ "start-3",
506
+ "start-4",
507
+ "start-5",
508
+ "start-6",
509
+ "start-7",
510
+ "start-8",
511
+ "start-9",
512
+ "start-10",
513
+ "start-11",
514
+ "start-12",
515
+ "start-13",
516
+ "start-auto",
517
+ "end-1",
518
+ "end-2",
519
+ "end-3",
520
+ "end-4",
521
+ "end-5",
522
+ "end-6",
523
+ "end-7",
524
+ "end-8",
525
+ "end-9",
526
+ "end-10",
527
+ "end-11",
528
+ "end-12",
529
+ "end-13",
530
+ "end-auto"
531
+ ],
532
+ row: [
533
+ "auto",
534
+ "span-1",
535
+ "span-2",
536
+ "span-3",
537
+ "span-4",
538
+ "span-5",
539
+ "span-6",
540
+ "span-full",
541
+ "start-1",
542
+ "start-2",
543
+ "start-3",
544
+ "start-4",
545
+ "start-5",
546
+ "start-6",
547
+ "start-7",
548
+ "start-auto",
549
+ "end-1",
550
+ "end-2",
551
+ "end-3",
552
+ "end-4",
553
+ "end-5",
554
+ "end-6",
555
+ "end-7",
556
+ "end-auto"
557
+ ],
558
+ textAlign: ["left", "center", "right", "justify", "start", "end"],
559
+ fontWeight: [
560
+ "thin",
561
+ "extralight",
562
+ "light",
563
+ "normal",
564
+ "medium",
565
+ "semibold",
566
+ "bold",
567
+ "extrabold",
568
+ "black"
569
+ ],
570
+ transition: ["none", "all", "colors", "opacity", "shadow", "transform"],
571
+ ease: ["linear", "in", "out", "in-out"]
572
+ };
573
+ function escapeTsString(value) {
574
+ return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\r/g, "\\r").replace(/\n/g, "\\n");
575
+ }
576
+ function generateUnionType(values) {
577
+ if (values.length === 0) {
578
+ return "string";
579
+ }
580
+ return values.map((v) => `'${escapeTsString(v)}'`).join(" | ");
581
+ }
582
+ function generateTypeDeclarations(theme, options = {}) {
583
+ const { includeComments = true } = options;
584
+ const colors = flattenColors(theme.colors || {});
585
+ const spacing = extractSpacingKeys(theme.spacing || {});
586
+ const screens = extractScreenKeys(theme.screens || {});
587
+ const sizing = [
588
+ ...spacing,
589
+ "auto",
590
+ "full",
591
+ "screen",
592
+ "svw",
593
+ "lvw",
594
+ "dvw",
595
+ "min",
596
+ "max",
597
+ "fit",
598
+ "1/2",
599
+ "1/3",
600
+ "2/3",
601
+ "1/4",
602
+ "2/4",
603
+ "3/4",
604
+ "1/5",
605
+ "2/5",
606
+ "3/5",
607
+ "4/5",
608
+ "1/6",
609
+ "5/6"
610
+ ];
611
+ const valueTypeMap = {
612
+ colors,
613
+ spacing,
614
+ sizing,
615
+ screens,
616
+ ...STATIC_VALUE_TYPES,
617
+ // Extract from theme if available
618
+ zIndex: theme.zIndex ? Object.keys(theme.zIndex) : ["0", "10", "20", "30", "40", "50", "auto"],
619
+ borderRadius: theme.borderRadius ? Object.keys(theme.borderRadius) : ["none", "sm", "md", "lg", "xl", "2xl", "3xl", "full"],
620
+ boxShadow: theme.boxShadow ? Object.keys(theme.boxShadow) : ["sm", "md", "lg", "xl", "2xl", "inner", "none"],
621
+ opacity: theme.opacity ? Object.keys(theme.opacity) : [
622
+ "0",
623
+ "5",
624
+ "10",
625
+ "20",
626
+ "25",
627
+ "30",
628
+ "40",
629
+ "50",
630
+ "60",
631
+ "70",
632
+ "75",
633
+ "80",
634
+ "90",
635
+ "95",
636
+ "100"
637
+ ],
638
+ fontSize: theme.fontSize ? Object.keys(theme.fontSize) : [
639
+ "xs",
640
+ "sm",
641
+ "base",
642
+ "lg",
643
+ "xl",
644
+ "2xl",
645
+ "3xl",
646
+ "4xl",
647
+ "5xl",
648
+ "6xl",
649
+ "7xl",
650
+ "8xl",
651
+ "9xl"
652
+ ],
653
+ fontFamily: theme.fontFamily ? Object.keys(theme.fontFamily) : ["sans", "serif", "mono"],
654
+ lineHeight: [
655
+ "none",
656
+ "tight",
657
+ "snug",
658
+ "normal",
659
+ "relaxed",
660
+ "loose",
661
+ "3",
662
+ "4",
663
+ "5",
664
+ "6",
665
+ "7",
666
+ "8",
667
+ "9",
668
+ "10"
669
+ ],
670
+ letterSpacing: ["tighter", "tight", "normal", "wide", "wider", "widest"],
671
+ borderWidth: ["0", "2", "4", "8", ""],
672
+ minWidth: ["0", "full", "min", "max", "fit"],
673
+ maxWidth: [
674
+ "0",
675
+ "none",
676
+ "xs",
677
+ "sm",
678
+ "md",
679
+ "lg",
680
+ "xl",
681
+ "2xl",
682
+ "3xl",
683
+ "4xl",
684
+ "5xl",
685
+ "6xl",
686
+ "7xl",
687
+ "full",
688
+ "min",
689
+ "max",
690
+ "fit",
691
+ "prose",
692
+ "screen-sm",
693
+ "screen-md",
694
+ "screen-lg",
695
+ "screen-xl",
696
+ "screen-2xl"
697
+ ],
698
+ minHeight: ["0", "full", "screen", "svh", "lvh", "dvh", "min", "max", "fit"],
699
+ maxHeight: ["0", "none", "full", "screen", "svh", "lvh", "dvh", "min", "max", "fit"],
700
+ scale: ["0", "50", "75", "90", "95", "100", "105", "110", "125", "150"],
701
+ rotate: ["0", "1", "2", "3", "6", "12", "45", "90", "180"],
702
+ translate: spacing,
703
+ duration: ["0", "75", "100", "150", "200", "300", "500", "700", "1000"]
704
+ };
705
+ const properties = [];
706
+ for (const mapping of PROPERTY_MAPPINGS) {
707
+ const values = valueTypeMap[mapping.valueType] || [];
708
+ const unionType = generateUnionType(values);
709
+ let propDef = "";
710
+ if (includeComments && mapping.description) {
711
+ propDef += ` /** ${mapping.description} */
712
+ `;
713
+ }
714
+ propDef += ` ${mapping.prop}?: ${unionType} | (string & {}) | number;`;
715
+ properties.push(propDef);
716
+ }
717
+ const variants = [
718
+ "hover",
719
+ "focus",
720
+ "active",
721
+ "disabled",
722
+ "visited",
723
+ "first",
724
+ "last",
725
+ "odd",
726
+ "even",
727
+ "group-hover",
728
+ "dark"
729
+ ];
730
+ const variantProps = [];
731
+ for (const variant of variants) {
732
+ if (includeComments) {
733
+ variantProps.push(` /** Styles applied on ${variant} state */`);
734
+ }
735
+ variantProps.push(` ${variant}?: SzVariantObject;`);
736
+ }
737
+ const responsiveProps = [];
738
+ for (const screen of screens) {
739
+ if (includeComments) {
740
+ responsiveProps.push(` /** Styles applied at ${screen} breakpoint and above */`);
741
+ }
742
+ responsiveProps.push(` ${screen}?: SzVariantObject;`);
743
+ }
744
+ const output = `/**
745
+ * Auto-generated TypeScript declarations for csszyx.
746
+ *
747
+ * This file provides strict typing for the sz prop based on your
748
+ * Tailwind CSS configuration.
749
+ *
750
+ * @generated by @csszyx/cli
751
+ * @see https://github.com/nguyennhutien/csszyx
752
+ */
753
+
754
+ import '@csszyx/types';
755
+
756
+ /**
757
+ * Variant object type (used for hover, focus, responsive breakpoints, etc.)
758
+ */
759
+ type SzVariantObject = Partial<StrictSzObject>;
760
+
761
+ /**
762
+ * Strict sz object interface with typed properties.
763
+ */
764
+ interface StrictSzObject {
765
+ ${properties.join("\n")}
766
+
767
+ // State variants
768
+ ${variantProps.join("\n")}
769
+
770
+ // Responsive variants
771
+ ${responsiveProps.join("\n")}
772
+
773
+ // Allow arbitrary properties for escape hatch
774
+ [key: string]: string | number | boolean | SzVariantObject | undefined;
775
+ }
776
+
777
+ declare module '@csszyx/types' {
778
+ /**
779
+ * Override the base SzObject with strict typing.
780
+ */
781
+ interface SzObject extends StrictSzObject {}
782
+ }
783
+
784
+ declare module 'react' {
785
+ interface HTMLAttributes<T> {
786
+ /**
787
+ * csszyx object syntax for Tailwind CSS classes.
788
+ * Provides IntelliSense for all Tailwind utilities.
789
+ */
790
+ sz?: StrictSzObject;
791
+ }
792
+
793
+ interface SVGAttributes<T> {
794
+ /**
795
+ * csszyx object syntax for Tailwind CSS classes.
796
+ */
797
+ sz?: StrictSzObject;
798
+ }
799
+ }
800
+
801
+ export {};
802
+ `;
803
+ return output;
804
+ }
805
+ async function writeDeclarationFile(content, outputPath) {
806
+ const absolutePath = resolve(outputPath);
807
+ const dir = dirname(absolutePath);
808
+ await mkdir(dir, { recursive: true });
809
+ writeFileSync(absolutePath, content, "utf-8");
810
+ }
811
+ async function generateAndWriteTypes(theme, options = {}) {
812
+ const outputPath = options.output || "./csszyx.d.ts";
813
+ const content = generateTypeDeclarations(theme, options);
814
+ await writeDeclarationFile(content, outputPath);
815
+ return resolve(outputPath);
816
+ }
817
+
818
+ async function generateTypes(options = {}) {
819
+ const cwd = options.cwd || process.cwd();
820
+ const log = options.silent ? () => {
821
+ } : console.log;
822
+ const error = options.silent ? () => {
823
+ } : console.error;
824
+ let configPath;
825
+ let scanResult;
826
+ if (options.config) {
827
+ configPath = resolve(cwd, options.config);
828
+ } else {
829
+ log("\u{1F50D} Searching for tailwind.config...");
830
+ const foundConfig = findConfigFile(cwd);
831
+ if (!foundConfig) {
832
+ error("\u274C Could not find tailwind.config.js in current directory");
833
+ error(" Please specify the path with --config flag");
834
+ process.exit(1);
835
+ }
836
+ configPath = foundConfig;
837
+ }
838
+ log(`\u{1F4D6} Reading config from: ${configPath}`);
839
+ try {
840
+ scanResult = await scanTailwindConfig(configPath);
841
+ } catch (err) {
842
+ error(
843
+ `\u274C Failed to read Tailwind config: ${err instanceof Error ? err.message : String(err)}`
844
+ );
845
+ process.exit(1);
846
+ }
847
+ log("\u2705 Config loaded successfully");
848
+ if (scanResult.hasCustomColors) {
849
+ log(" \u2022 Custom colors detected");
850
+ }
851
+ if (scanResult.hasCustomSpacing) {
852
+ log(" \u2022 Custom spacing detected");
853
+ }
854
+ const outputPath = options.output || "./csszyx.d.ts";
855
+ const generatorOptions = {
856
+ output: resolve(cwd, outputPath),
857
+ includeComments: true
858
+ };
859
+ log("\n\u{1F4DD} Generating TypeScript declarations...");
860
+ try {
861
+ const writtenPath = await generateAndWriteTypes(scanResult.theme, generatorOptions);
862
+ log("\n\u2728 Types generated successfully!");
863
+ log(` Output: ${writtenPath}`);
864
+ log('\n\u{1F4A1} Add this to your tsconfig.json "include" array:');
865
+ log(' "include": ["src", "csszyx.d.ts"]');
866
+ } catch (err) {
867
+ error(`\u274C Failed to generate types: ${err instanceof Error ? err.message : String(err)}`);
868
+ process.exit(1);
869
+ }
870
+ }
871
+
872
+ function generateSzExpression(obj) {
873
+ return `{${objectToString(obj)}}`;
874
+ }
875
+ function generateSzHtmlValue(obj, braces = false) {
876
+ const s = objectToString(obj);
877
+ if (braces) {
878
+ return s;
879
+ }
880
+ if (s.startsWith("{ ") && s.endsWith(" }")) {
881
+ return s.slice(2, -2);
882
+ }
883
+ if (s.startsWith("{") && s.endsWith("}")) {
884
+ return s.slice(1, -1).trim();
885
+ }
886
+ return s;
887
+ }
888
+ function generateSzObjectLiteral(obj) {
889
+ return objectToString(obj);
890
+ }
891
+ function objectToString(obj, indent = 0) {
892
+ const entries = Object.entries(obj);
893
+ if (entries.length === 0) {
894
+ return "{}";
895
+ }
896
+ const spaces = " ".repeat(indent);
897
+ const innerSpaces = " ".repeat(indent + 2);
898
+ if (entries.length <= 2 && !hasDeepNesting(obj)) {
899
+ const parts = entries.map(([k, v]) => `${formatKey(k)}: ${formatValue(v, indent)}`);
900
+ return `{ ${parts.join(", ")} }`;
901
+ }
902
+ const lines = entries.map(
903
+ ([k, v]) => `${innerSpaces}${formatKey(k)}: ${formatValue(v, indent + 2)},`
904
+ );
905
+ return `{
906
+ ${lines.join("\n")}
907
+ ${spaces}}`;
908
+ }
909
+ function hasDeepNesting(obj) {
910
+ return Object.values(obj).some(
911
+ (v) => typeof v === "object" && v !== null && !isColorOpacityObj(v) && !isGradientObj(v)
912
+ );
913
+ }
914
+ function isColorOpacityObj(v) {
915
+ return typeof v === "object" && v !== null && "color" in v && "op" in v;
916
+ }
917
+ function isGradientObj(v) {
918
+ return typeof v === "object" && v !== null && "gradient" in v;
919
+ }
920
+ function formatKey(key) {
921
+ if (/^[a-z_$][\w$]*$/i.test(key)) {
922
+ return key;
923
+ }
924
+ return `'${key}'`;
925
+ }
926
+ function formatValue(value, indent) {
927
+ if (value === true) {
928
+ return "true";
929
+ }
930
+ if (value === false) {
931
+ return "false";
932
+ }
933
+ if (value === null) {
934
+ return "null";
935
+ }
936
+ if (typeof value === "number") {
937
+ return String(value);
938
+ }
939
+ if (typeof value === "string") {
940
+ return `'${escapeString(value)}'`;
941
+ }
942
+ if (Array.isArray(value)) {
943
+ const items = value.map((v) => formatValue(v, indent));
944
+ return `[${items.join(", ")}]`;
945
+ }
946
+ if (typeof value === "object") {
947
+ if (isColorOpacityObj(value)) {
948
+ const parts = [`color: '${escapeString(String(value.color))}'`];
949
+ if (typeof value.op === "number") {
950
+ parts.push(`op: ${value.op}`);
951
+ } else {
952
+ parts.push(`op: '${escapeString(String(value.op))}'`);
953
+ }
954
+ return `{ ${parts.join(", ")} }`;
955
+ }
956
+ if (isGradientObj(value)) {
957
+ const grad = value;
958
+ const parts = [`gradient: '${grad.gradient}'`];
959
+ if ("dir" in grad) {
960
+ if (typeof grad.dir === "number") {
961
+ parts.push(`dir: ${grad.dir}`);
962
+ } else {
963
+ parts.push(`dir: '${escapeString(String(grad.dir))}'`);
964
+ }
965
+ }
966
+ if ("in" in grad) {
967
+ parts.push(`in: '${escapeString(String(grad.in))}'`);
968
+ }
969
+ return `{ ${parts.join(", ")} }`;
970
+ }
971
+ return objectToString(value, indent);
972
+ }
973
+ return String(value);
974
+ }
975
+ function escapeString(s) {
976
+ return s.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
977
+ }
978
+
979
+ const REVERSE_PROPERTY_MAP = {
980
+ // Background (ambiguous — disambiguated in class-parser)
981
+ bg: "bg",
982
+ "bg-clip": "bgClip",
983
+ "bg-origin": "bgOrigin",
984
+ "bg-size": "bgSize",
985
+ // Border Radius
986
+ rounded: "rounded",
987
+ "rounded-t": "roundedT",
988
+ "rounded-r": "roundedR",
989
+ "rounded-b": "roundedB",
990
+ "rounded-l": "roundedL",
991
+ "rounded-tl": "roundedTl",
992
+ "rounded-tr": "roundedTr",
993
+ "rounded-bl": "roundedBl",
994
+ "rounded-br": "roundedBr",
995
+ "rounded-s": "roundedS",
996
+ "rounded-e": "roundedE",
997
+ "rounded-ss": "roundedSs",
998
+ "rounded-se": "roundedSe",
999
+ "rounded-es": "roundedEs",
1000
+ "rounded-ee": "roundedEe",
1001
+ // Border (ambiguous — disambiguated)
1002
+ border: "border",
1003
+ "border-t": "borderT",
1004
+ "border-r": "borderR",
1005
+ "border-b": "borderB",
1006
+ "border-l": "borderL",
1007
+ "border-x": "borderX",
1008
+ "border-y": "borderY",
1009
+ "border-s": "borderS",
1010
+ "border-e": "borderE",
1011
+ // Divide
1012
+ "divide-x": "divideX",
1013
+ "divide-y": "divideY",
1014
+ divide: "divideColor",
1015
+ // Outline (ambiguous)
1016
+ outline: "outline",
1017
+ "outline-offset": "outlineOffset",
1018
+ // Ring (v4: outset ring + inset ring)
1019
+ ring: "ring",
1020
+ "ring-offset": "ringOffset",
1021
+ "inset-ring": "insetRing",
1022
+ // Spacing
1023
+ p: "p",
1024
+ pt: "pt",
1025
+ pr: "pr",
1026
+ pb: "pb",
1027
+ pl: "pl",
1028
+ px: "px",
1029
+ py: "py",
1030
+ ps: "ps",
1031
+ pe: "pe",
1032
+ m: "m",
1033
+ mt: "mt",
1034
+ mr: "mr",
1035
+ mb: "mb",
1036
+ ml: "ml",
1037
+ mx: "mx",
1038
+ my: "my",
1039
+ ms: "ms",
1040
+ me: "me",
1041
+ // Space between
1042
+ "space-x": "spaceX",
1043
+ "space-y": "spaceY",
1044
+ // Logical margin / padding (block-start / block-end)
1045
+ mbs: "mbs",
1046
+ mbe: "mbe",
1047
+ pbs: "pbs",
1048
+ pbe: "pbe",
1049
+ // Sizing
1050
+ w: "w",
1051
+ "min-w": "minW",
1052
+ "max-w": "maxW",
1053
+ h: "h",
1054
+ "min-h": "minH",
1055
+ "max-h": "maxH",
1056
+ size: "size",
1057
+ // Logical sizing (block-size / inline-size). The bare `block`/`inline` classes
1058
+ // are display values (BOOLEAN_VALUE_MAP wins via exact match first); only the
1059
+ // `block-*` / `inline-*` value forms route here.
1060
+ block: "blockSize",
1061
+ inline: "inlineSize",
1062
+ "min-block": "minBlockSize",
1063
+ "max-block": "maxBlockSize",
1064
+ "min-inline": "minInlineSize",
1065
+ "max-inline": "maxInlineSize",
1066
+ // Layout
1067
+ aspect: "aspect",
1068
+ columns: "columns",
1069
+ "break-after": "breakAfter",
1070
+ "break-before": "breakBefore",
1071
+ "break-inside": "breakInside",
1072
+ "box-decoration": "boxDecoration",
1073
+ box: "box",
1074
+ float: "float",
1075
+ clear: "clear",
1076
+ object: "objectFit",
1077
+ // ambiguous — objectFit vs objectPos (objectPos for position values)
1078
+ overflow: "overflow",
1079
+ "overflow-x": "overflowX",
1080
+ "overflow-y": "overflowY",
1081
+ overscroll: "overscroll",
1082
+ "overscroll-x": "overscrollX",
1083
+ "overscroll-y": "overscrollY",
1084
+ z: "z",
1085
+ // Inset
1086
+ inset: "inset",
1087
+ "inset-x": "insetX",
1088
+ "inset-y": "insetY",
1089
+ // Logical inset sides (inset-s/e + block-start/block-end)
1090
+ "inset-s": "insetS",
1091
+ "inset-e": "insetE",
1092
+ "inset-bs": "insetBs",
1093
+ "inset-be": "insetBe",
1094
+ top: "top",
1095
+ right: "right",
1096
+ bottom: "bottom",
1097
+ left: "left",
1098
+ // TW v4.2: start/end are deprecated — migrate to inset-s/inset-e
1099
+ start: "insetS",
1100
+ end: "insetE",
1101
+ // Typography (ambiguous — text-*, font-* disambiguated)
1102
+ text: "color",
1103
+ // default for text- prefix
1104
+ font: "weight",
1105
+ // default for font- prefix
1106
+ decoration: "decoration",
1107
+ // ambiguous
1108
+ "underline-offset": "underlineOffset",
1109
+ indent: "indent",
1110
+ align: "align",
1111
+ whitespace: "whitespace",
1112
+ break: "break",
1113
+ // ambiguous with break-after/before/inside (handled by prefix matching)
1114
+ hyphens: "hyphens",
1115
+ content: "content",
1116
+ leading: "leading",
1117
+ tracking: "tracking",
1118
+ list: "list",
1119
+ // ambiguous
1120
+ "list-image": "listImg",
1121
+ // Flex & Grid
1122
+ basis: "basis",
1123
+ flex: "flex",
1124
+ // ambiguous (boolean flex, flexDirection, flexWrap)
1125
+ grow: "grow",
1126
+ shrink: "shrink",
1127
+ order: "order",
1128
+ items: "items",
1129
+ self: "self",
1130
+ justify: "justify",
1131
+ "justify-items": "justifyItems",
1132
+ "justify-self": "justifySelf",
1133
+ "place-content": "placeContent",
1134
+ "place-items": "placeItems",
1135
+ "place-self": "placeSelf",
1136
+ gap: "gap",
1137
+ "gap-x": "gapX",
1138
+ "gap-y": "gapY",
1139
+ // Grid
1140
+ "grid-cols": "gridCols",
1141
+ "grid-rows": "gridRows",
1142
+ col: "col",
1143
+ "col-span": "colSpan",
1144
+ "col-start": "colStart",
1145
+ "col-end": "colEnd",
1146
+ row: "row",
1147
+ "row-span": "rowSpan",
1148
+ "row-start": "rowStart",
1149
+ "row-end": "rowEnd",
1150
+ "grid-flow": "gridFlow",
1151
+ "auto-cols": "autoCols",
1152
+ "auto-rows": "autoRows",
1153
+ // Effects
1154
+ shadow: "shadow",
1155
+ // ambiguous (shadow vs shadowColor)
1156
+ "inset-shadow": "insetShadow",
1157
+ opacity: "opacity",
1158
+ "mix-blend": "mixBlend",
1159
+ "bg-blend": "bgBlend",
1160
+ // Filters
1161
+ filter: "filter",
1162
+ "backdrop-filter": "backdropFilter",
1163
+ blur: "blur",
1164
+ brightness: "brightness",
1165
+ contrast: "contrast",
1166
+ "drop-shadow": "dropShadow",
1167
+ grayscale: "grayscale",
1168
+ "hue-rotate": "hueRotate",
1169
+ invert: "invert",
1170
+ saturate: "saturate",
1171
+ sepia: "sepia",
1172
+ "backdrop-blur": "backdropBlur",
1173
+ "backdrop-brightness": "backdropBrightness",
1174
+ "backdrop-contrast": "backdropContrast",
1175
+ "backdrop-grayscale": "backdropGrayscale",
1176
+ "backdrop-hue-rotate": "backdropHueRotate",
1177
+ "backdrop-invert": "backdropInvert",
1178
+ "backdrop-opacity": "backdropOpacity",
1179
+ "backdrop-saturate": "backdropSaturate",
1180
+ "backdrop-sepia": "backdropSepia",
1181
+ // Transforms
1182
+ scale: "scale",
1183
+ "scale-x": "scaleX",
1184
+ "scale-y": "scaleY",
1185
+ "scale-z": "scaleZ",
1186
+ rotate: "rotate",
1187
+ translate: "translate",
1188
+ "translate-x": "translateX",
1189
+ "translate-y": "translateY",
1190
+ "translate-z": "translateZ",
1191
+ "skew-x": "skewX",
1192
+ "skew-y": "skewY",
1193
+ origin: "origin",
1194
+ // Transitions & Animation
1195
+ transition: "transition",
1196
+ duration: "duration",
1197
+ ease: "ease",
1198
+ delay: "delay",
1199
+ animate: "animate",
1200
+ // Interactivity
1201
+ cursor: "cursor",
1202
+ caret: "caret",
1203
+ "pointer-events": "pointerEvents",
1204
+ scheme: "scheme",
1205
+ tab: "tabSize",
1206
+ zoom: "zoom",
1207
+ scrollbar: "scrollbar",
1208
+ "scrollbar-gutter": "scrollbarGutter",
1209
+ resize: "resize",
1210
+ scroll: "scroll",
1211
+ "scroll-m": "scrollM",
1212
+ "scroll-mt": "scrollMt",
1213
+ "scroll-mr": "scrollMr",
1214
+ "scroll-mb": "scrollMb",
1215
+ "scroll-ml": "scrollMl",
1216
+ "scroll-ms": "scrollMs",
1217
+ "scroll-me": "scrollMe",
1218
+ "scroll-mx": "scrollMx",
1219
+ "scroll-my": "scrollMy",
1220
+ "scroll-p": "scrollP",
1221
+ "scroll-pt": "scrollPt",
1222
+ "scroll-pr": "scrollPr",
1223
+ "scroll-pb": "scrollPb",
1224
+ "scroll-pl": "scrollPl",
1225
+ "scroll-ps": "scrollPs",
1226
+ "scroll-pe": "scrollPe",
1227
+ "scroll-px": "scrollPx",
1228
+ "scroll-py": "scrollPy",
1229
+ snap: "snapType",
1230
+ // ambiguous
1231
+ touch: "touch",
1232
+ select: "select",
1233
+ "will-change": "willChange",
1234
+ accent: "accent",
1235
+ // SVG
1236
+ fill: "fill",
1237
+ stroke: "stroke",
1238
+ // Tables
1239
+ "border-spacing": "borderSpacing",
1240
+ table: "tableLayout",
1241
+ // ambiguous with boolean "table" display
1242
+ caption: "caption",
1243
+ // Line clamp
1244
+ "line-clamp": "lineClamp",
1245
+ wrap: "wrap",
1246
+ // Typography plugin (bare `prose` is boolean; `prose-gray`/`prose-lg` carry a value)
1247
+ prose: "prose",
1248
+ // Text shadow
1249
+ "text-shadow": "textShadow",
1250
+ // Gradient stops
1251
+ from: "from",
1252
+ via: "via",
1253
+ to: "to",
1254
+ // Masks
1255
+ mask: "mask",
1256
+ // Forced colors
1257
+ "forced-color-adjust": "forcedColorAdjust",
1258
+ // Perspective
1259
+ perspective: "perspective",
1260
+ "perspective-origin": "perspectiveOrigin",
1261
+ backface: "backface"
1262
+ };
1263
+ const REVERSE_BOOLEAN_MAP = {
1264
+ // Typography (composite)
1265
+ truncate: "truncate",
1266
+ // Flexbox (default-or-value: bare `grow`/`shrink` mean grow/shrink: true,
1267
+ // while grow-0/shrink-0 carry a value via REVERSE_PROPERTY_MAP).
1268
+ // flexWrap is string-based, not boolean — kept out of this map.
1269
+ grow: "grow",
1270
+ shrink: "shrink",
1271
+ // Filters (defaults)
1272
+ blur: "blur",
1273
+ grayscale: "grayscale",
1274
+ invert: "invert",
1275
+ sepia: "sepia",
1276
+ "backdrop-blur": "backdropBlur",
1277
+ "backdrop-grayscale": "backdropGrayscale",
1278
+ "backdrop-invert": "backdropInvert",
1279
+ "backdrop-sepia": "backdropSepia",
1280
+ // Misc
1281
+ container: "container",
1282
+ prose: "prose",
1283
+ // Bare `resize` (resize: both) and bare `shadow` (default elevation) are
1284
+ // default-or-value toggles, like ring/outline below.
1285
+ resize: "resize",
1286
+ shadow: "shadow",
1287
+ "sr-only": "srOnly",
1288
+ "not-sr-only": "notSrOnly",
1289
+ isolate: "isolate",
1290
+ ordinal: "ordinal",
1291
+ "slashed-zero": "slashedZero",
1292
+ // Bare `transition` (common transition property) and the `group`/`peer`
1293
+ // marker classes round-trip through the compiler as boolean sugar.
1294
+ transition: "transition",
1295
+ group: "group",
1296
+ peer: "peer",
1297
+ // Divide/Space reverse
1298
+ "divide-x-reverse": "divideXReverse",
1299
+ "divide-y-reverse": "divideYReverse",
1300
+ "space-x-reverse": "spaceXReverse",
1301
+ "space-y-reverse": "spaceYReverse",
1302
+ // Ring/Outline/Border-radius (boolean defaults)
1303
+ ring: "ring",
1304
+ "inset-ring": "insetRing",
1305
+ outline: "outline",
1306
+ rounded: "rounded",
1307
+ // Transforms — scale-3d/translate-3d carry the literal '3d' value via
1308
+ // BOOLEAN_VALUE_MAP, and transform-gpu/cpu/none → { transform: 'gpu'/'cpu'/'none' }.
1309
+ // Font numeric
1310
+ "normal-nums": "fontVariant",
1311
+ "lining-nums": "fontVariant",
1312
+ "oldstyle-nums": "fontVariant",
1313
+ "proportional-nums": "fontVariant",
1314
+ "tabular-nums": "fontVariant",
1315
+ "diagonal-fractions": "fontVariant",
1316
+ "stacked-fractions": "fontVariant",
1317
+ // Snap
1318
+ "snap-none": "snapType",
1319
+ "snap-x": "snapType",
1320
+ "snap-y": "snapType",
1321
+ "snap-both": "snapType",
1322
+ "snap-mandatory": "snapStrictness",
1323
+ "snap-proximity": "snapStrictness",
1324
+ "snap-start": "snapAlign",
1325
+ "snap-end": "snapAlign",
1326
+ "snap-center": "snapAlign",
1327
+ "snap-align-none": "snapAlign",
1328
+ "snap-normal": "snapStop",
1329
+ "snap-always": "snapStop",
1330
+ // Divide styles
1331
+ "divide-solid": "divideStyle",
1332
+ "divide-dashed": "divideStyle",
1333
+ "divide-dotted": "divideStyle",
1334
+ "divide-double": "divideStyle",
1335
+ "divide-none": "divideStyle",
1336
+ // Appearance
1337
+ "appearance-none": "appearance",
1338
+ "appearance-auto": "appearance"
1339
+ };
1340
+ const BOOLEAN_VALUE_MAP = {
1341
+ // Snap types
1342
+ "snap-none": { prop: "snapType", value: "none" },
1343
+ "snap-x": { prop: "snapType", value: "x" },
1344
+ "snap-y": { prop: "snapType", value: "y" },
1345
+ "snap-both": { prop: "snapType", value: "both" },
1346
+ "snap-mandatory": { prop: "snapStrictness", value: "mandatory" },
1347
+ "snap-proximity": { prop: "snapStrictness", value: "proximity" },
1348
+ "snap-start": { prop: "snapAlign", value: "start" },
1349
+ "snap-end": { prop: "snapAlign", value: "end" },
1350
+ "snap-center": { prop: "snapAlign", value: "center" },
1351
+ "snap-align-none": { prop: "snapAlign", value: "none" },
1352
+ "snap-normal": { prop: "snapStop", value: "normal" },
1353
+ "snap-always": { prop: "snapStop", value: "always" },
1354
+ // Divide styles
1355
+ "divide-solid": { prop: "divideStyle", value: "solid" },
1356
+ "divide-dashed": { prop: "divideStyle", value: "dashed" },
1357
+ "divide-dotted": { prop: "divideStyle", value: "dotted" },
1358
+ "divide-double": { prop: "divideStyle", value: "double" },
1359
+ "divide-none": { prop: "divideStyle", value: "none" },
1360
+ // Font variants
1361
+ "normal-nums": { prop: "fontVariant", value: "normal-nums" },
1362
+ "lining-nums": { prop: "fontVariant", value: "lining-nums" },
1363
+ "oldstyle-nums": { prop: "fontVariant", value: "oldstyle-nums" },
1364
+ "proportional-nums": { prop: "fontVariant", value: "proportional-nums" },
1365
+ "tabular-nums": { prop: "fontVariant", value: "tabular-nums" },
1366
+ "diagonal-fractions": { prop: "fontVariant", value: "diagonal-fractions" },
1367
+ "stacked-fractions": { prop: "fontVariant", value: "stacked-fractions" },
1368
+ // Appearance
1369
+ "appearance-none": { prop: "appearance", value: "none" },
1370
+ "appearance-auto": { prop: "appearance", value: "auto" },
1371
+ // Isolation (bare `isolate` is in REVERSE_BOOLEAN_MAP; `isolation-auto` carries a value)
1372
+ "isolation-auto": { prop: "isolation", value: "auto", cssProperty: "isolation" },
1373
+ // Field sizing
1374
+ "field-sizing-content": { prop: "fieldSizing", value: "content", cssProperty: "field-sizing" },
1375
+ "field-sizing-fixed": { prop: "fieldSizing", value: "fixed", cssProperty: "field-sizing" },
1376
+ // Transform
1377
+ "transform-none": { prop: "transform", value: "none" },
1378
+ "transform-gpu": { prop: "transform", value: "gpu" },
1379
+ "transform-cpu": { prop: "transform", value: "cpu" },
1380
+ // transform-style (3d / flat) — single CSS property, so fail-closed on conflict.
1381
+ "transform-3d": { prop: "transformStyle", value: "3d", cssProperty: "transform-style" },
1382
+ "transform-flat": { prop: "transformStyle", value: "flat", cssProperty: "transform-style" },
1383
+ // 3D scale/translate keyword shorthands carry the literal '3d' value.
1384
+ "scale-3d": { prop: "scale", value: "3d" },
1385
+ "translate-3d": { prop: "translate", value: "3d" },
1386
+ // Single-property utilities — migrated to their canonical { key: value }
1387
+ // form. The boolean-sugar aliases (flex/absolute/italic/...) were removed,
1388
+ // so these never emit `{ flex: true }`; one key per CSS property.
1389
+ // display
1390
+ block: { prop: "display", value: "block", cssProperty: "display" },
1391
+ inline: { prop: "display", value: "inline", cssProperty: "display" },
1392
+ "inline-block": { prop: "display", value: "inline-block", cssProperty: "display" },
1393
+ flex: { prop: "display", value: "flex", cssProperty: "display" },
1394
+ "inline-flex": { prop: "display", value: "inline-flex", cssProperty: "display" },
1395
+ grid: { prop: "display", value: "grid", cssProperty: "display" },
1396
+ "inline-grid": { prop: "display", value: "inline-grid", cssProperty: "display" },
1397
+ hidden: { prop: "display", value: "none", cssProperty: "display" },
1398
+ contents: { prop: "display", value: "contents", cssProperty: "display" },
1399
+ table: { prop: "display", value: "table", cssProperty: "display" },
1400
+ "inline-table": { prop: "display", value: "inline-table", cssProperty: "display" },
1401
+ "table-row": { prop: "display", value: "table-row", cssProperty: "display" },
1402
+ "table-row-group": { prop: "display", value: "table-row-group", cssProperty: "display" },
1403
+ "table-cell": { prop: "display", value: "table-cell", cssProperty: "display" },
1404
+ "table-caption": { prop: "display", value: "table-caption", cssProperty: "display" },
1405
+ "table-column": { prop: "display", value: "table-column", cssProperty: "display" },
1406
+ "table-column-group": {
1407
+ prop: "display",
1408
+ value: "table-column-group",
1409
+ cssProperty: "display"
1410
+ },
1411
+ "table-footer-group": {
1412
+ prop: "display",
1413
+ value: "table-footer-group",
1414
+ cssProperty: "display"
1415
+ },
1416
+ "table-header-group": {
1417
+ prop: "display",
1418
+ value: "table-header-group",
1419
+ cssProperty: "display"
1420
+ },
1421
+ "flow-root": { prop: "display", value: "flow-root", cssProperty: "display" },
1422
+ "list-item": { prop: "display", value: "list-item", cssProperty: "display" },
1423
+ // position
1424
+ static: { prop: "position", value: "static", cssProperty: "position" },
1425
+ fixed: { prop: "position", value: "fixed", cssProperty: "position" },
1426
+ absolute: { prop: "position", value: "absolute", cssProperty: "position" },
1427
+ relative: { prop: "position", value: "relative", cssProperty: "position" },
1428
+ sticky: { prop: "position", value: "sticky", cssProperty: "position" },
1429
+ // visibility
1430
+ visible: { prop: "visibility", value: "visible", cssProperty: "visibility" },
1431
+ invisible: { prop: "visibility", value: "hidden", cssProperty: "visibility" },
1432
+ collapse: { prop: "visibility", value: "collapse", cssProperty: "visibility" },
1433
+ // isolation
1434
+ isolate: { prop: "isolation", value: "isolate", cssProperty: "isolation" },
1435
+ // text-transform
1436
+ uppercase: { prop: "textTransform", value: "uppercase", cssProperty: "text-transform" },
1437
+ lowercase: { prop: "textTransform", value: "lowercase", cssProperty: "text-transform" },
1438
+ capitalize: { prop: "textTransform", value: "capitalize", cssProperty: "text-transform" },
1439
+ "normal-case": { prop: "textTransform", value: "none", cssProperty: "text-transform" },
1440
+ // font-style
1441
+ italic: { prop: "fontStyle", value: "italic", cssProperty: "font-style" },
1442
+ "not-italic": { prop: "fontStyle", value: "normal", cssProperty: "font-style" },
1443
+ // text-decoration-line
1444
+ underline: { prop: "decoration", value: "underline", cssProperty: "text-decoration-line" },
1445
+ overline: { prop: "decoration", value: "overline", cssProperty: "text-decoration-line" },
1446
+ "line-through": {
1447
+ prop: "decoration",
1448
+ value: "line-through",
1449
+ cssProperty: "text-decoration-line"
1450
+ },
1451
+ "no-underline": { prop: "decoration", value: "none", cssProperty: "text-decoration-line" },
1452
+ // font-smoothing
1453
+ antialiased: { prop: "fontSmoothing", value: "grayscale", cssProperty: "font-smoothing" },
1454
+ "subpixel-antialiased": {
1455
+ prop: "fontSmoothing",
1456
+ value: "subpixel",
1457
+ cssProperty: "font-smoothing"
1458
+ }
1459
+ };
1460
+ const SORTED_PREFIXES = Object.keys(REVERSE_PROPERTY_MAP).sort((a, b) => {
1461
+ if (b.length !== a.length) {
1462
+ return b.length - a.length;
1463
+ }
1464
+ return a.localeCompare(b);
1465
+ });
1466
+ const NEGATIVE_ALLOWED = /* @__PURE__ */ new Set([
1467
+ "m",
1468
+ "mt",
1469
+ "mr",
1470
+ "mb",
1471
+ "ml",
1472
+ "mx",
1473
+ "my",
1474
+ "ms",
1475
+ "me",
1476
+ "top",
1477
+ "right",
1478
+ "bottom",
1479
+ "left",
1480
+ "inset",
1481
+ "inset-x",
1482
+ "inset-y",
1483
+ "start",
1484
+ "end",
1485
+ "inset-s",
1486
+ "inset-e",
1487
+ "inset-bs",
1488
+ "inset-be",
1489
+ "mbs",
1490
+ "mbe",
1491
+ "translate",
1492
+ "z",
1493
+ "order",
1494
+ "col",
1495
+ "col-start",
1496
+ "col-end",
1497
+ "row",
1498
+ "row-start",
1499
+ "row-end",
1500
+ "rotate",
1501
+ "skew-x",
1502
+ "skew-y",
1503
+ "translate-x",
1504
+ "translate-y",
1505
+ "space-x",
1506
+ "space-y",
1507
+ "tracking",
1508
+ "indent",
1509
+ "scroll-m",
1510
+ "scroll-mx",
1511
+ "scroll-my",
1512
+ "scroll-mt",
1513
+ "scroll-mr",
1514
+ "scroll-mb",
1515
+ "scroll-ml",
1516
+ "hue-rotate",
1517
+ "backdrop-hue-rotate",
1518
+ // mask gradient direction carries a leading `-` as part of the value
1519
+ // (e.g. -mask-linear-45 → { mask: '-linear-45' }), not a numeric negation.
1520
+ "mask"
1521
+ ]);
1522
+ const FRACTION_SUPPORTED = /* @__PURE__ */ new Set([
1523
+ "w",
1524
+ "min-w",
1525
+ "max-w",
1526
+ "h",
1527
+ "min-h",
1528
+ "max-h",
1529
+ "size",
1530
+ "basis",
1531
+ "inset",
1532
+ "inset-x",
1533
+ "inset-y",
1534
+ "top",
1535
+ "right",
1536
+ "bottom",
1537
+ "left",
1538
+ "start",
1539
+ "end",
1540
+ "inset-s",
1541
+ "inset-e",
1542
+ "inset-bs",
1543
+ "inset-be",
1544
+ "translate-x",
1545
+ "translate-y",
1546
+ "translate",
1547
+ "aspect"
1548
+ ]);
1549
+ const SPACING_PROPS = /* @__PURE__ */ new Set([
1550
+ "p",
1551
+ "pt",
1552
+ "pr",
1553
+ "pb",
1554
+ "pl",
1555
+ "px",
1556
+ "py",
1557
+ "ps",
1558
+ "pe",
1559
+ "m",
1560
+ "mt",
1561
+ "mr",
1562
+ "mb",
1563
+ "ml",
1564
+ "mx",
1565
+ "my",
1566
+ "ms",
1567
+ "me",
1568
+ "gap",
1569
+ "gap-x",
1570
+ "gap-y",
1571
+ "w",
1572
+ "h",
1573
+ "min-w",
1574
+ "max-w",
1575
+ "min-h",
1576
+ "max-h",
1577
+ "size",
1578
+ "basis",
1579
+ "inset",
1580
+ "inset-x",
1581
+ "inset-y",
1582
+ "top",
1583
+ "right",
1584
+ "bottom",
1585
+ "left",
1586
+ "start",
1587
+ "end",
1588
+ "space-x",
1589
+ "space-y",
1590
+ "indent",
1591
+ "scroll-m",
1592
+ "scroll-mx",
1593
+ "scroll-my",
1594
+ "scroll-mt",
1595
+ "scroll-mr",
1596
+ "scroll-mb",
1597
+ "scroll-ml",
1598
+ "scroll-ms",
1599
+ "scroll-me",
1600
+ "scroll-p",
1601
+ "scroll-px",
1602
+ "scroll-py",
1603
+ "scroll-pt",
1604
+ "scroll-pr",
1605
+ "scroll-pb",
1606
+ "scroll-pl",
1607
+ "scroll-ps",
1608
+ "scroll-pe",
1609
+ "border-spacing",
1610
+ "translate-x",
1611
+ "translate-y",
1612
+ "translate-z",
1613
+ "translate",
1614
+ // Logical sizing accepts the spacing/sizing scale (block-4, inline-full, …)
1615
+ "block",
1616
+ "inline",
1617
+ "min-block",
1618
+ "max-block",
1619
+ "min-inline",
1620
+ "max-inline",
1621
+ // Logical inset sides + block-axis margin/padding
1622
+ "inset-s",
1623
+ "inset-e",
1624
+ "inset-bs",
1625
+ "inset-be",
1626
+ "mbs",
1627
+ "mbe",
1628
+ "pbs",
1629
+ "pbe"
1630
+ ]);
1631
+ const TEXT_SIZE_KEYWORDS = /* @__PURE__ */ new Set([
1632
+ "xs",
1633
+ "sm",
1634
+ "base",
1635
+ "lg",
1636
+ "xl",
1637
+ "2xl",
1638
+ "3xl",
1639
+ "4xl",
1640
+ "5xl",
1641
+ "6xl",
1642
+ "7xl",
1643
+ "8xl",
1644
+ "9xl"
1645
+ ]);
1646
+ const TEXT_ALIGN_KEYWORDS = /* @__PURE__ */ new Set(["left", "center", "right", "justify", "start", "end"]);
1647
+ const TEXT_WRAP_KEYWORDS = /* @__PURE__ */ new Set(["wrap", "nowrap", "balance", "pretty"]);
1648
+ const TEXT_OVERFLOW_KEYWORDS = /* @__PURE__ */ new Set(["ellipsis", "clip"]);
1649
+ const FONT_WEIGHT_KEYWORDS = /* @__PURE__ */ new Set([
1650
+ "thin",
1651
+ "extralight",
1652
+ "light",
1653
+ "normal",
1654
+ "medium",
1655
+ "semibold",
1656
+ "bold",
1657
+ "extrabold",
1658
+ "black"
1659
+ ]);
1660
+ const FONT_FAMILY_KEYWORDS = /* @__PURE__ */ new Set(["sans", "serif", "mono"]);
1661
+ const FONT_STRETCH_KEYWORDS = /* @__PURE__ */ new Set([
1662
+ "ultra-condensed",
1663
+ "extra-condensed",
1664
+ "condensed",
1665
+ "semi-condensed",
1666
+ "semi-expanded",
1667
+ "expanded",
1668
+ "extra-expanded",
1669
+ "ultra-expanded"
1670
+ ]);
1671
+ const BORDER_WIDTH_KEYWORDS = /* @__PURE__ */ new Set(["0", "2", "4", "8"]);
1672
+ const BORDER_STYLE_KEYWORDS = /* @__PURE__ */ new Set([
1673
+ "solid",
1674
+ "dashed",
1675
+ "dotted",
1676
+ "double",
1677
+ "none",
1678
+ "hidden"
1679
+ ]);
1680
+ const BG_POSITION_KEYWORDS = /* @__PURE__ */ new Set([
1681
+ "center",
1682
+ "top",
1683
+ "bottom",
1684
+ "left",
1685
+ "right",
1686
+ "left-top",
1687
+ "left-bottom",
1688
+ "right-top",
1689
+ "right-bottom"
1690
+ ]);
1691
+ const BG_SIZE_KEYWORDS = /* @__PURE__ */ new Set(["cover", "contain", "auto"]);
1692
+ const BG_REPEAT_KEYWORDS = /* @__PURE__ */ new Set([
1693
+ "repeat",
1694
+ "no-repeat",
1695
+ "repeat-x",
1696
+ "repeat-y",
1697
+ "round",
1698
+ "space"
1699
+ ]);
1700
+ const BG_ATTACHMENT_KEYWORDS = /* @__PURE__ */ new Set(["fixed", "local", "scroll"]);
1701
+ const OBJECT_FIT_KEYWORDS = /* @__PURE__ */ new Set(["contain", "cover", "fill", "none", "scale-down"]);
1702
+ const OBJECT_POSITION_KEYWORDS = /* @__PURE__ */ new Set([
1703
+ "center",
1704
+ "top",
1705
+ "bottom",
1706
+ "left",
1707
+ "right",
1708
+ "left-top",
1709
+ "left-bottom",
1710
+ "right-top",
1711
+ "right-bottom"
1712
+ ]);
1713
+ const SHADOW_SIZE_KEYWORDS = /* @__PURE__ */ new Set([
1714
+ "2xs",
1715
+ "xs",
1716
+ "sm",
1717
+ "md",
1718
+ "lg",
1719
+ "xl",
1720
+ "2xl",
1721
+ "inner",
1722
+ "none"
1723
+ ]);
1724
+ const ALIGN_CONTENT_KEYWORDS = /* @__PURE__ */ new Set([
1725
+ "normal",
1726
+ "center",
1727
+ "start",
1728
+ "end",
1729
+ "between",
1730
+ "around",
1731
+ "evenly",
1732
+ "baseline",
1733
+ "stretch"
1734
+ ]);
1735
+ const OUTLINE_STYLE_KEYWORDS = /* @__PURE__ */ new Set(["none", "dashed", "dotted", "double"]);
1736
+ const DECORATION_STYLE_KEYWORDS = /* @__PURE__ */ new Set(["solid", "double", "dotted", "dashed", "wavy"]);
1737
+ const DECORATION_THICKNESS_KEYWORDS = /* @__PURE__ */ new Set([
1738
+ "auto",
1739
+ "from-font",
1740
+ "0",
1741
+ "1",
1742
+ "2",
1743
+ "4",
1744
+ "8"
1745
+ ]);
1746
+ const TRANSITION_PROPERTY_KEYWORDS = /* @__PURE__ */ new Set([
1747
+ "none",
1748
+ "all",
1749
+ "colors",
1750
+ "opacity",
1751
+ "shadow",
1752
+ "transform"
1753
+ ]);
1754
+ const REVERSE_VARIANT_MAP = {
1755
+ "focus-within": "focusWithin",
1756
+ "focus-visible": "focusVisible",
1757
+ "first-of-type": "firstOfType",
1758
+ "last-of-type": "lastOfType",
1759
+ "only-of-type": "onlyOfType",
1760
+ "motion-reduce": "motionReduce",
1761
+ "motion-safe": "motionSafe",
1762
+ "contrast-more": "contrastMore",
1763
+ "contrast-less": "contrastLess",
1764
+ "first-line": "firstLine",
1765
+ "first-letter": "firstLetter",
1766
+ "placeholder-shown": "placeholderShown",
1767
+ "in-range": "inRange",
1768
+ "out-of-range": "outOfRange",
1769
+ "read-only": "readOnly",
1770
+ "pointer-fine": "pointerFine",
1771
+ "pointer-coarse": "pointerCoarse",
1772
+ "pointer-none": "pointerNone",
1773
+ "@max-sm": "@maxSm",
1774
+ "@max-md": "@maxMd",
1775
+ "@max-lg": "@maxLg",
1776
+ "@max-xl": "@maxXl",
1777
+ "@max-2xl": "@max2xl"
1778
+ };
1779
+ const KNOWN_SIMPLE_VARIANTS = /* @__PURE__ */ new Set([
1780
+ "sm",
1781
+ "md",
1782
+ "lg",
1783
+ "xl",
1784
+ "2xl",
1785
+ "@sm",
1786
+ "@md",
1787
+ "@lg",
1788
+ "@xl",
1789
+ "@2xl",
1790
+ "dark",
1791
+ "light",
1792
+ "print",
1793
+ "portrait",
1794
+ "landscape",
1795
+ "hover",
1796
+ "focus",
1797
+ "active",
1798
+ "visited",
1799
+ "target",
1800
+ "disabled",
1801
+ "enabled",
1802
+ "checked",
1803
+ "indeterminate",
1804
+ "default",
1805
+ "required",
1806
+ "valid",
1807
+ "invalid",
1808
+ "autofill",
1809
+ "open",
1810
+ "first",
1811
+ "last",
1812
+ "only",
1813
+ "odd",
1814
+ "even",
1815
+ "empty",
1816
+ "before",
1817
+ "after",
1818
+ "placeholder",
1819
+ "file",
1820
+ "marker",
1821
+ "selection",
1822
+ "backdrop",
1823
+ "ltr",
1824
+ "rtl"
1825
+ ]);
1826
+ /* @__PURE__ */ new Set([
1827
+ ...KNOWN_SIMPLE_VARIANTS,
1828
+ "focus-within",
1829
+ "focus-visible",
1830
+ "first-of-type",
1831
+ "last-of-type",
1832
+ "only-of-type",
1833
+ "first-child",
1834
+ "last-child",
1835
+ "only-child",
1836
+ "motion-reduce",
1837
+ "motion-safe",
1838
+ "contrast-more",
1839
+ "contrast-less",
1840
+ "first-line",
1841
+ "first-letter",
1842
+ "placeholder-shown",
1843
+ "in-range",
1844
+ "out-of-range",
1845
+ "read-only",
1846
+ "pointer-fine",
1847
+ "pointer-coarse",
1848
+ "pointer-none"
1849
+ ]);
1850
+
1851
+ function parseClass(cls, options = {}) {
1852
+ let important = false;
1853
+ let input = cls;
1854
+ if (input.endsWith("!")) {
1855
+ important = true;
1856
+ input = input.slice(0, -1);
1857
+ }
1858
+ let negative = false;
1859
+ let negInput = input;
1860
+ if (input.startsWith("-")) {
1861
+ negative = true;
1862
+ negInput = input.slice(1);
1863
+ }
1864
+ if (input === "@container") {
1865
+ return { prop: "@container", value: true };
1866
+ }
1867
+ if (input.startsWith("@container/")) {
1868
+ return { prop: "@container", value: input.slice("@container/".length) };
1869
+ }
1870
+ const boolResult = tryBooleanMatch(input);
1871
+ if (boolResult) {
1872
+ return applyImportant(boolResult, important);
1873
+ }
1874
+ const gradResult = tryGradient(negInput, negative);
1875
+ if (gradResult) {
1876
+ return applyImportant(gradResult, important);
1877
+ }
1878
+ const source = negative ? negInput : input;
1879
+ for (const prefix of SORTED_PREFIXES) {
1880
+ if (source === prefix) {
1881
+ const prop = REVERSE_PROPERTY_MAP[prefix];
1882
+ if (negative && NEGATIVE_ALLOWED.has(prefix)) {
1883
+ continue;
1884
+ }
1885
+ if (REVERSE_BOOLEAN_MAP[source]) {
1886
+ return applyImportant(
1887
+ { prop: REVERSE_BOOLEAN_MAP[source], value: true },
1888
+ important
1889
+ );
1890
+ }
1891
+ if (prefix === "divide-x" || prefix === "divide-y") {
1892
+ return applyImportant({ prop, value: true }, important);
1893
+ }
1894
+ if (prefix === "border") {
1895
+ return applyImportant({ prop: "border", value: true }, important);
1896
+ }
1897
+ if ([
1898
+ "border-t",
1899
+ "border-r",
1900
+ "border-b",
1901
+ "border-l",
1902
+ "border-x",
1903
+ "border-y",
1904
+ "border-s",
1905
+ "border-e"
1906
+ ].includes(prefix)) {
1907
+ return applyImportant({ prop, value: true }, important);
1908
+ }
1909
+ continue;
1910
+ }
1911
+ if (source.startsWith(`${prefix}-`)) {
1912
+ const rawValue = source.slice(prefix.length + 1);
1913
+ if (!rawValue) {
1914
+ continue;
1915
+ }
1916
+ if (negative && !NEGATIVE_ALLOWED.has(prefix)) {
1917
+ continue;
1918
+ }
1919
+ if (SPACING_PROPS.has(prefix) && !isValidSpacingValue(rawValue)) {
1920
+ continue;
1921
+ }
1922
+ const result = disambiguateAndParse(prefix, rawValue, negative);
1923
+ if (result) {
1924
+ return applyImportant(result, important);
1925
+ }
1926
+ }
1927
+ }
1928
+ if (input.startsWith("[") && input.endsWith("]") && input.includes(":")) {
1929
+ const inner = input.slice(1, -1);
1930
+ if (inner.startsWith("--")) {
1931
+ const colonIdx = inner.indexOf(":");
1932
+ return applyImportant(
1933
+ {
1934
+ prop: inner.slice(0, colonIdx),
1935
+ value: inner.slice(colonIdx + 1)
1936
+ },
1937
+ important
1938
+ );
1939
+ }
1940
+ }
1941
+ return null;
1942
+ }
1943
+ function applyImportant(result, important) {
1944
+ if (!important) {
1945
+ return result;
1946
+ }
1947
+ const base = result.cssProperty ? { cssProperty: result.cssProperty } : {};
1948
+ if (typeof result.value === "string") {
1949
+ return { ...base, prop: result.prop, value: `${result.value}!` };
1950
+ }
1951
+ if (typeof result.value === "boolean") {
1952
+ return { ...base, prop: result.prop, value: "!" };
1953
+ }
1954
+ if (typeof result.value === "number") {
1955
+ return { ...base, prop: result.prop, value: `${String(result.value)}!` };
1956
+ }
1957
+ return result;
1958
+ }
1959
+ function tryBooleanMatch(cls) {
1960
+ if (BOOLEAN_VALUE_MAP[cls]) {
1961
+ const { prop, value, cssProperty } = BOOLEAN_VALUE_MAP[cls];
1962
+ return cssProperty ? { prop, value, cssProperty } : { prop, value };
1963
+ }
1964
+ if (REVERSE_BOOLEAN_MAP[cls]) {
1965
+ return { prop: REVERSE_BOOLEAN_MAP[cls], value: true };
1966
+ }
1967
+ return null;
1968
+ }
1969
+ function tryGradient(cls, negative) {
1970
+ let input = cls;
1971
+ let type = null;
1972
+ if (input.startsWith("bg-linear")) {
1973
+ type = "linear";
1974
+ input = input.slice("bg-linear".length);
1975
+ } else if (input.startsWith("bg-radial")) {
1976
+ type = "radial";
1977
+ input = input.slice("bg-radial".length);
1978
+ } else if (input.startsWith("bg-conic")) {
1979
+ type = "conic";
1980
+ input = input.slice("bg-conic".length);
1981
+ }
1982
+ if (!type) {
1983
+ return null;
1984
+ }
1985
+ let colorInterp;
1986
+ const slashIdx = findTopLevelSlash$1(input);
1987
+ if (slashIdx !== -1) {
1988
+ colorInterp = input.slice(slashIdx + 1);
1989
+ input = input.slice(0, slashIdx);
1990
+ }
1991
+ const grad = { gradient: type };
1992
+ if (input === "" || input === void 0) ; else if (input.startsWith("-")) {
1993
+ const dir = input.slice(1);
1994
+ if (dir.startsWith("[") && dir.endsWith("]")) {
1995
+ grad.dir = dir.slice(1, -1).replace(/_/g, " ");
1996
+ } else if (dir.startsWith("(") && dir.endsWith(")")) {
1997
+ grad.dir = dir.slice(1, -1);
1998
+ } else if (/^\d+$/.test(dir)) {
1999
+ grad.dir = negative ? -parseInt(dir, 10) : parseInt(dir, 10);
2000
+ } else {
2001
+ grad.dir = dir;
2002
+ }
2003
+ }
2004
+ if (colorInterp) {
2005
+ grad.in = colorInterp;
2006
+ }
2007
+ return { prop: "bgImg", value: grad };
2008
+ }
2009
+ function findTopLevelSlash$1(s) {
2010
+ let depth = 0;
2011
+ for (let i = 0; i < s.length; i++) {
2012
+ if (s[i] === "[" || s[i] === "(") {
2013
+ depth++;
2014
+ } else if (s[i] === "]" || s[i] === ")") {
2015
+ depth--;
2016
+ } else if (s[i] === "/" && depth === 0) {
2017
+ return i;
2018
+ }
2019
+ }
2020
+ return -1;
2021
+ }
2022
+ function disambiguateAndParse(prefix, rawValue, negative) {
2023
+ const slashIdx = findTopLevelSlash$1(rawValue);
2024
+ let opacity;
2025
+ let value = rawValue;
2026
+ if (slashIdx !== -1 && !isGradientPrefix(prefix)) {
2027
+ const isFraction = FRACTION_SUPPORTED.has(prefix) && /^\d+\/\d+$/.test(rawValue);
2028
+ if (!isFraction) {
2029
+ opacity = rawValue.slice(slashIdx + 1);
2030
+ value = rawValue.slice(0, slashIdx);
2031
+ if (opacity.startsWith("[") && opacity.endsWith("]")) {
2032
+ opacity = opacity.slice(1, -1);
2033
+ if (!String(opacity).includes("%")) {
2034
+ const opNum = Number(opacity);
2035
+ if (!Number.isNaN(opNum)) {
2036
+ opacity = opNum;
2037
+ }
2038
+ }
2039
+ } else if (opacity.startsWith("(") && opacity.endsWith(")")) {
2040
+ opacity = opacity.slice(1, -1);
2041
+ } else {
2042
+ const opNum = Number(opacity);
2043
+ if (!Number.isNaN(opNum)) {
2044
+ opacity = opNum;
2045
+ }
2046
+ }
2047
+ }
2048
+ }
2049
+ const result = disambiguate(prefix, value, negative);
2050
+ if (!result) {
2051
+ return null;
2052
+ }
2053
+ if (opacity !== void 0 && typeof result.value === "string") {
2054
+ return {
2055
+ prop: result.prop,
2056
+ value: { color: result.value, op: opacity }
2057
+ };
2058
+ }
2059
+ return result;
2060
+ }
2061
+ function isGradientPrefix(prefix) {
2062
+ return prefix === "from" || prefix === "via" || prefix === "to";
2063
+ }
2064
+ function disambiguate(prefix, value, negative) {
2065
+ switch (prefix) {
2066
+ case "text":
2067
+ return disambiguateText(value);
2068
+ case "font":
2069
+ return disambiguateFont(value);
2070
+ case "border":
2071
+ return disambiguateBorder(value);
2072
+ case "bg":
2073
+ return disambiguateBg(value);
2074
+ case "object":
2075
+ return disambiguateObject(value);
2076
+ case "shadow":
2077
+ return disambiguateShadow(value);
2078
+ case "outline":
2079
+ return disambiguateOutline(value);
2080
+ case "decoration":
2081
+ return disambiguateDecoration(value);
2082
+ case "transition":
2083
+ return disambiguateTransition(value);
2084
+ case "ring":
2085
+ return disambiguateRing(value, negative);
2086
+ case "ring-offset":
2087
+ return disambiguateRingOffset(value);
2088
+ case "inset-ring":
2089
+ return disambiguateInsetRing(value, negative);
2090
+ case "inset-shadow":
2091
+ return disambiguateInsetShadow(value);
2092
+ case "stroke":
2093
+ return disambiguateStroke(value);
2094
+ case "from":
2095
+ case "via":
2096
+ case "to":
2097
+ return disambiguateGradientStop(prefix, value);
2098
+ case "list":
2099
+ return disambiguateList(value);
2100
+ case "ease":
2101
+ return { prop: "ease", value: parseValue("ease", value, negative) };
2102
+ case "snap":
2103
+ return disambiguateSnap();
2104
+ case "content":
2105
+ return disambiguateContent(value);
2106
+ case "flex":
2107
+ return disambiguateFlex(value);
2108
+ case "table":
2109
+ return disambiguateTable(value);
2110
+ case "divide":
2111
+ return disambiguateDivide(value);
2112
+ case "break":
2113
+ if (value === "words") {
2114
+ return { prop: "wrap", value: "break-word" };
2115
+ }
2116
+ return { prop: "break", value };
2117
+ case "wrap":
2118
+ return { prop: "wrap", value };
2119
+ default:
2120
+ return {
2121
+ prop: REVERSE_PROPERTY_MAP[prefix] || prefix,
2122
+ value: parseValue(prefix, value, negative)
2123
+ };
2124
+ }
2125
+ }
2126
+ function disambiguateText(value) {
2127
+ if (TEXT_SIZE_KEYWORDS.has(value)) {
2128
+ return { prop: "text", value };
2129
+ }
2130
+ if (TEXT_ALIGN_KEYWORDS.has(value)) {
2131
+ return { prop: "textAlign", value };
2132
+ }
2133
+ if (TEXT_WRAP_KEYWORDS.has(value)) {
2134
+ return { prop: "textWrap", value };
2135
+ }
2136
+ if (TEXT_OVERFLOW_KEYWORDS.has(value)) {
2137
+ return { prop: "textOverflow", value };
2138
+ }
2139
+ if (isArbitraryDimension(value)) {
2140
+ return { prop: "text", value: parseStringValue(value) };
2141
+ }
2142
+ return { prop: "color", value: parseStringValue(value) };
2143
+ }
2144
+ function disambiguateFont(value) {
2145
+ if (FONT_WEIGHT_KEYWORDS.has(value)) {
2146
+ return { prop: "weight", value };
2147
+ }
2148
+ if (/^\d{3}$/.test(value)) {
2149
+ return { prop: "weight", value: parseInt(value, 10) };
2150
+ }
2151
+ if (FONT_FAMILY_KEYWORDS.has(value)) {
2152
+ return { prop: "fontFamily", value };
2153
+ }
2154
+ if (value.startsWith("stretch-")) {
2155
+ const stretchVal = value.slice("stretch-".length);
2156
+ return { prop: "fontStretch", value: parseStringValue(stretchVal) };
2157
+ }
2158
+ if (FONT_STRETCH_KEYWORDS.has(value)) {
2159
+ return { prop: "fontStretch", value };
2160
+ }
2161
+ return { prop: "fontFamily", value: parseStringValue(value) };
2162
+ }
2163
+ function disambiguateBorder(value) {
2164
+ if (BORDER_WIDTH_KEYWORDS.has(value) || value === "px") {
2165
+ return { prop: "border", value: parseNumericOrString("border", value, false) };
2166
+ }
2167
+ if (BORDER_STYLE_KEYWORDS.has(value)) {
2168
+ return { prop: "borderStyle", value };
2169
+ }
2170
+ if (isArbitraryDimension(value)) {
2171
+ return { prop: "border", value: parseStringValue(value) };
2172
+ }
2173
+ return { prop: "borderColor", value: parseStringValue(value) };
2174
+ }
2175
+ function disambiguateBg(value) {
2176
+ if (BG_POSITION_KEYWORDS.has(value)) {
2177
+ return { prop: "bgPos", value };
2178
+ }
2179
+ if (BG_SIZE_KEYWORDS.has(value)) {
2180
+ return { prop: "bgSize", value };
2181
+ }
2182
+ if (BG_REPEAT_KEYWORDS.has(value)) {
2183
+ return { prop: "bgRepeat", value };
2184
+ }
2185
+ if (BG_ATTACHMENT_KEYWORDS.has(value)) {
2186
+ return { prop: "bgAttach", value };
2187
+ }
2188
+ if (value.startsWith("[") && value.endsWith("]")) {
2189
+ const inner = value.slice(1, -1).replace(/_/g, " ");
2190
+ if (inner.includes(" ") && BG_POSITION_KEYWORDS.has(inner.split(" ")[0])) {
2191
+ return { prop: "bgPos", value: inner };
2192
+ }
2193
+ }
2194
+ if (value === "none") {
2195
+ return { prop: "bgImg", value: "none" };
2196
+ }
2197
+ return { prop: "bg", value: parseStringValue(value) };
2198
+ }
2199
+ function disambiguateObject(value) {
2200
+ if (OBJECT_FIT_KEYWORDS.has(value)) {
2201
+ return { prop: "objectFit", value };
2202
+ }
2203
+ if (OBJECT_POSITION_KEYWORDS.has(value)) {
2204
+ return { prop: "objectPos", value };
2205
+ }
2206
+ return { prop: "objectPos", value: parseStringValue(value) };
2207
+ }
2208
+ function disambiguateShadow(value) {
2209
+ if (SHADOW_SIZE_KEYWORDS.has(value)) {
2210
+ return { prop: "shadow", value };
2211
+ }
2212
+ if (value.startsWith("(") && value.endsWith(")")) {
2213
+ const inner = value.slice(1, -1);
2214
+ if (inner.startsWith("color:")) {
2215
+ return { prop: "shadowColor", value: inner.slice("color:".length) };
2216
+ }
2217
+ return { prop: "shadow", value: inner };
2218
+ }
2219
+ return { prop: "shadowColor", value: parseStringValue(value) };
2220
+ }
2221
+ function disambiguateOutline(value) {
2222
+ if (OUTLINE_STYLE_KEYWORDS.has(value)) {
2223
+ return { prop: "outlineStyle", value };
2224
+ }
2225
+ const num = Number(value);
2226
+ if (!Number.isNaN(num) && Number.isInteger(num)) {
2227
+ return { prop: "outline", value: num };
2228
+ }
2229
+ if (isArbitraryDimension(value)) {
2230
+ return { prop: "outline", value: parseStringValue(value) };
2231
+ }
2232
+ return { prop: "outlineColor", value: parseStringValue(value) };
2233
+ }
2234
+ function disambiguateDecoration(value) {
2235
+ if (DECORATION_STYLE_KEYWORDS.has(value)) {
2236
+ return { prop: "decorationStyle", value };
2237
+ }
2238
+ if (DECORATION_THICKNESS_KEYWORDS.has(value)) {
2239
+ return { prop: "decorationThickness", value };
2240
+ }
2241
+ if (isArbitraryDimension(value) || value.startsWith("(") && value.endsWith(")")) {
2242
+ return { prop: "decorationThickness", value: parseStringValue(value) };
2243
+ }
2244
+ return { prop: "decorationColor", value: parseStringValue(value) };
2245
+ }
2246
+ function disambiguateRing(value, negative) {
2247
+ const num = Number(value);
2248
+ if (!Number.isNaN(num) && Number.isInteger(num)) {
2249
+ return { prop: "ring", value: negative ? -num : num };
2250
+ }
2251
+ if (isArbitraryDimension(value)) {
2252
+ return { prop: "ring", value: parseStringValue(value) };
2253
+ }
2254
+ return { prop: "ringColor", value: parseStringValue(value) };
2255
+ }
2256
+ function disambiguateRingOffset(value) {
2257
+ const num = Number(value);
2258
+ if (!Number.isNaN(num) && Number.isInteger(num)) {
2259
+ return { prop: "ringOffset", value: num };
2260
+ }
2261
+ return { prop: "ringOffsetColor", value: parseStringValue(value) };
2262
+ }
2263
+ function disambiguateInsetRing(value, negative) {
2264
+ const num = Number(value);
2265
+ if (!Number.isNaN(num) && Number.isInteger(num)) {
2266
+ return { prop: "insetRing", value: negative ? -num : num };
2267
+ }
2268
+ if (isArbitraryDimension(value)) {
2269
+ return { prop: "insetRing", value: parseStringValue(value) };
2270
+ }
2271
+ return { prop: "insetRingColor", value: parseStringValue(value) };
2272
+ }
2273
+ function disambiguateInsetShadow(value) {
2274
+ const INSET_SHADOW_SIZE_KEYWORDS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl", "none", "inner"]);
2275
+ if (INSET_SHADOW_SIZE_KEYWORDS.has(value)) {
2276
+ return { prop: "insetShadow", value };
2277
+ }
2278
+ if (isArbitraryDimension(value)) {
2279
+ return { prop: "insetShadow", value: parseStringValue(value) };
2280
+ }
2281
+ return { prop: "insetShadowColor", value: parseStringValue(value) };
2282
+ }
2283
+ function disambiguateStroke(value) {
2284
+ const num = Number(value);
2285
+ if (!Number.isNaN(num) && Number.isInteger(num)) {
2286
+ return { prop: "strokeWidth", value: num };
2287
+ }
2288
+ if (isArbitraryDimension(value)) {
2289
+ return { prop: "strokeWidth", value: parseStringValue(value) };
2290
+ }
2291
+ return { prop: "stroke", value: parseStringValue(value) };
2292
+ }
2293
+ function disambiguateGradientStop(prefix, value) {
2294
+ const posKey = prefix === "from" ? "fromPos" : prefix === "via" ? "viaPos" : "toPos";
2295
+ if (/^\d+(\.\d+)?%$/.test(value) || /^\d+$/.test(value) || isArbitraryDimension(value)) {
2296
+ return { prop: posKey, value: parseStringValue(value) };
2297
+ }
2298
+ return { prop: prefix, value: parseStringValue(value) };
2299
+ }
2300
+ function disambiguateTransition(value) {
2301
+ if (TRANSITION_PROPERTY_KEYWORDS.has(value)) {
2302
+ return { prop: "transition", value };
2303
+ }
2304
+ return { prop: "transition", value: parseStringValue(value) };
2305
+ }
2306
+ function disambiguateList(value) {
2307
+ if (value === "inside" || value === "outside") {
2308
+ return { prop: "listPos", value };
2309
+ }
2310
+ return { prop: "list", value: parseStringValue(value) };
2311
+ }
2312
+ function disambiguateSnap(_value) {
2313
+ return null;
2314
+ }
2315
+ function disambiguateContent(value) {
2316
+ if (ALIGN_CONTENT_KEYWORDS.has(value)) {
2317
+ return { prop: "alignContent", value };
2318
+ }
2319
+ return { prop: "content", value: parseValue("content", value, false) };
2320
+ }
2321
+ function disambiguateFlex(value) {
2322
+ const dirValues = /* @__PURE__ */ new Set(["row", "col", "row-reverse", "col-reverse"]);
2323
+ if (dirValues.has(value)) {
2324
+ return { prop: "flexDir", value };
2325
+ }
2326
+ const wrapValues = /* @__PURE__ */ new Set(["wrap", "nowrap", "wrap-reverse"]);
2327
+ if (wrapValues.has(value)) {
2328
+ return { prop: "flexWrap", value };
2329
+ }
2330
+ if (value === "1" || value === "auto" || value === "initial" || value === "none") {
2331
+ return { prop: "flex", value: parseStringValue(value) };
2332
+ }
2333
+ return { prop: "flex", value: parseStringValue(value) };
2334
+ }
2335
+ function disambiguateTable(value) {
2336
+ if (value === "auto" || value === "fixed") {
2337
+ return { prop: "tableLayout", value };
2338
+ }
2339
+ return null;
2340
+ }
2341
+ function disambiguateDivide(value) {
2342
+ return { prop: "divideColor", value: parseStringValue(value) };
2343
+ }
2344
+ const CSS_DIMENSION_RE = /^-?[\d.]+(?:px|r?em|ex|ch|vw|vh|vmin|vmax|svh|svw|dvh|dvw|lvh|lvw|cqw|cqh|cqi|cqb|%|fr|deg|rad|turn|grad|ms|s|pt|pc|cm|mm|in)$/;
2345
+ function isArbitraryDimension(value) {
2346
+ if (!value.startsWith("[") || !value.endsWith("]")) {
2347
+ return false;
2348
+ }
2349
+ return CSS_DIMENSION_RE.test(value.slice(1, -1));
2350
+ }
2351
+ function isValidSpacingValue(value) {
2352
+ if (value.startsWith("[") && value.endsWith("]")) {
2353
+ return true;
2354
+ }
2355
+ if (value.startsWith("(") && value.endsWith(")")) {
2356
+ return true;
2357
+ }
2358
+ if (!Number.isNaN(Number(value))) {
2359
+ return true;
2360
+ }
2361
+ if (/^\d+\/\d+$/.test(value)) {
2362
+ return true;
2363
+ }
2364
+ if ([
2365
+ "auto",
2366
+ "full",
2367
+ "screen",
2368
+ "px",
2369
+ "min",
2370
+ "max",
2371
+ "fit",
2372
+ "none",
2373
+ "dvh",
2374
+ "dvw",
2375
+ "svh",
2376
+ "svw",
2377
+ "lvh",
2378
+ "lvw",
2379
+ // Max-width size keywords
2380
+ "3xs",
2381
+ "2xs",
2382
+ "xs",
2383
+ "sm",
2384
+ "md",
2385
+ "lg",
2386
+ "xl",
2387
+ "2xl",
2388
+ "3xl",
2389
+ "4xl",
2390
+ "5xl",
2391
+ "6xl",
2392
+ "7xl",
2393
+ "prose",
2394
+ "screen-sm",
2395
+ "screen-md",
2396
+ "screen-lg",
2397
+ "screen-xl",
2398
+ "screen-2xl",
2399
+ // Size keywords used in min-h, max-h
2400
+ "content"
2401
+ ].includes(value)) {
2402
+ return true;
2403
+ }
2404
+ if (value.includes("/")) {
2405
+ return true;
2406
+ }
2407
+ return false;
2408
+ }
2409
+ function parseValue(prefix, value, negative) {
2410
+ if (value.startsWith("[") && value.endsWith("]")) {
2411
+ const inner = value.slice(1, -1).replace(/_/g, " ");
2412
+ if (negative) {
2413
+ return `-${inner}`;
2414
+ }
2415
+ if (prefix === "content") {
2416
+ const isQuoted = inner.startsWith("'") && inner.endsWith("'") || inner.startsWith('"') && inner.endsWith('"');
2417
+ if (isQuoted) {
2418
+ return `"${inner.slice(1, -1)}"`;
2419
+ }
2420
+ }
2421
+ return inner;
2422
+ }
2423
+ if (value.startsWith("(") && value.endsWith(")")) {
2424
+ const inner = value.slice(1, -1);
2425
+ if (negative) {
2426
+ return `-${inner}`;
2427
+ }
2428
+ return inner;
2429
+ }
2430
+ if (FRACTION_SUPPORTED.has(prefix) && /^\d+\/\d+$/.test(value)) {
2431
+ return negative ? `-${value}` : value;
2432
+ }
2433
+ if (value === "px") {
2434
+ return negative ? "-px" : "px";
2435
+ }
2436
+ if (value === "auto") {
2437
+ return "auto";
2438
+ }
2439
+ if (value === "full") {
2440
+ return negative ? "-full" : "full";
2441
+ }
2442
+ if (value === "screen") {
2443
+ return "screen";
2444
+ }
2445
+ const num = Number(value);
2446
+ if (!Number.isNaN(num)) {
2447
+ if (negative) {
2448
+ return -num;
2449
+ }
2450
+ return num;
2451
+ }
2452
+ if (negative) {
2453
+ return `-${value}`;
2454
+ }
2455
+ return value;
2456
+ }
2457
+ function parseNumericOrString(prefix, value, negative) {
2458
+ if (value === "px") {
2459
+ return "px";
2460
+ }
2461
+ const num = Number(value);
2462
+ if (!Number.isNaN(num)) {
2463
+ return negative ? -num : num;
2464
+ }
2465
+ return value;
2466
+ }
2467
+ function parseStringValue(value) {
2468
+ if (value.startsWith("[") && value.endsWith("]")) {
2469
+ return value.slice(1, -1).replace(/_/g, " ");
2470
+ }
2471
+ if (value.startsWith("(") && value.endsWith(")")) {
2472
+ return value.slice(1, -1);
2473
+ }
2474
+ return value;
2475
+ }
2476
+
2477
+ function tokenize(className) {
2478
+ return className.trim().split(/\s+/).filter(Boolean);
2479
+ }
2480
+ function extractVariants(token) {
2481
+ const parts = [];
2482
+ let current = "";
2483
+ let depth = 0;
2484
+ for (let i = 0; i < token.length; i++) {
2485
+ const ch = token[i];
2486
+ if (ch === "[" || ch === "(") {
2487
+ depth++;
2488
+ current += ch;
2489
+ } else if (ch === "]" || ch === ")") {
2490
+ depth--;
2491
+ current += ch;
2492
+ } else if (ch === ":" && depth === 0) {
2493
+ parts.push(current);
2494
+ current = "";
2495
+ } else {
2496
+ current += ch;
2497
+ }
2498
+ }
2499
+ if (parts.length === 0) {
2500
+ return { variantParts: [], baseClass: current };
2501
+ }
2502
+ return { variantParts: parts, baseClass: current };
2503
+ }
2504
+ function mapVariant(variant) {
2505
+ if (variant.startsWith("@")) {
2506
+ if (variant === "@container") {
2507
+ return ["@container"];
2508
+ }
2509
+ const slashIdx = variant.indexOf("/");
2510
+ if (slashIdx !== -1) {
2511
+ const queryPart = variant.slice(0, slashIdx);
2512
+ const namePart = variant.slice(slashIdx + 1);
2513
+ return [normalizeVariantKey(queryPart), namePart];
2514
+ }
2515
+ const match = variant.match(/^(@min|@max)-\[(.+)\]$/);
2516
+ if (match) {
2517
+ return [match[1], match[2]];
2518
+ }
2519
+ return [normalizeVariantKey(variant)];
2520
+ }
2521
+ if (variant.startsWith("group-") || variant.startsWith("peer-")) {
2522
+ return parseGroupPeerVariant(variant);
2523
+ }
2524
+ if (variant.startsWith("has-")) {
2525
+ const rest = variant.slice(4);
2526
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2527
+ let selector = rest.slice(1, -1);
2528
+ if (selector.startsWith(":")) {
2529
+ selector = selector.slice(1);
2530
+ }
2531
+ return ["has", selector];
2532
+ }
2533
+ return ["has", rest];
2534
+ }
2535
+ if (variant.startsWith("not-")) {
2536
+ const rest = variant.slice(4);
2537
+ if (rest.startsWith("supports-[") && rest.endsWith("]")) {
2538
+ const cond = rest.slice(10, -1);
2539
+ return ["not", "supports", cond];
2540
+ }
2541
+ return ["not", normalizeVariantKey(rest)];
2542
+ }
2543
+ if (variant.startsWith("data-")) {
2544
+ const rest = variant.slice(5);
2545
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2546
+ return ["data", rest.slice(1, -1)];
2547
+ }
2548
+ return ["data", rest];
2549
+ }
2550
+ if (variant.startsWith("aria-")) {
2551
+ const rest = variant.slice(5);
2552
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2553
+ return ["aria", rest.slice(1, -1)];
2554
+ }
2555
+ return ["aria", rest];
2556
+ }
2557
+ if (variant.startsWith("supports-")) {
2558
+ const rest = variant.slice(9);
2559
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2560
+ return ["supports", rest.slice(1, -1)];
2561
+ }
2562
+ return ["supports", rest];
2563
+ }
2564
+ if (variant.startsWith("min-") || variant.startsWith("max-")) {
2565
+ const prefix = variant.startsWith("min-") ? "min" : "max";
2566
+ const rest = variant.slice(4);
2567
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2568
+ return [prefix, rest.slice(1, -1)];
2569
+ }
2570
+ return [prefix, rest];
2571
+ }
2572
+ if (variant.startsWith("[") && variant.endsWith("]")) {
2573
+ return [variant];
2574
+ }
2575
+ return [normalizeVariantKey(variant)];
2576
+ }
2577
+ function parseGroupPeerVariant(variant) {
2578
+ const isGroup = variant.startsWith("group-");
2579
+ const type = isGroup ? "group" : "peer";
2580
+ let rest = variant.slice(type.length + 1);
2581
+ let name;
2582
+ const slashIdx = findTopLevelSlash(rest);
2583
+ if (slashIdx !== -1) {
2584
+ name = rest.slice(slashIdx + 1);
2585
+ rest = rest.slice(0, slashIdx);
2586
+ }
2587
+ const keys = [type];
2588
+ if (name) {
2589
+ keys.push(name);
2590
+ }
2591
+ if (rest.startsWith("[") && rest.endsWith("]")) {
2592
+ keys.push(rest.slice(1, -1));
2593
+ } else if (rest.startsWith("has-")) {
2594
+ const hasRest = rest.slice(4);
2595
+ if (hasRest.startsWith("[") && hasRest.endsWith("]")) {
2596
+ keys.push("has");
2597
+ keys.push(hasRest.slice(1, -1));
2598
+ } else {
2599
+ keys.push("has");
2600
+ keys.push(hasRest);
2601
+ }
2602
+ } else if (rest.startsWith("data-")) {
2603
+ const dataRest = rest.slice(5);
2604
+ keys.push("data");
2605
+ if (dataRest.startsWith("[") && dataRest.endsWith("]")) {
2606
+ keys.push(dataRest.slice(1, -1));
2607
+ } else if (dataRest.startsWith("(") && dataRest.endsWith(")")) {
2608
+ keys.push(dataRest.slice(1, -1));
2609
+ } else {
2610
+ keys.push(dataRest);
2611
+ }
2612
+ } else if (rest.startsWith("aria-")) {
2613
+ const ariaRest = rest.slice(5);
2614
+ keys.push("aria");
2615
+ if (ariaRest.startsWith("[") && ariaRest.endsWith("]")) {
2616
+ keys.push(ariaRest.slice(1, -1));
2617
+ } else {
2618
+ keys.push(ariaRest);
2619
+ }
2620
+ } else {
2621
+ keys.push(normalizeVariantKey(rest));
2622
+ }
2623
+ return keys;
2624
+ }
2625
+ function findTopLevelSlash(s) {
2626
+ let depth = 0;
2627
+ for (let i = 0; i < s.length; i++) {
2628
+ if (s[i] === "[" || s[i] === "(") {
2629
+ depth++;
2630
+ } else if (s[i] === "]" || s[i] === ")") {
2631
+ depth--;
2632
+ } else if (s[i] === "/" && depth === 0) {
2633
+ return i;
2634
+ }
2635
+ }
2636
+ return -1;
2637
+ }
2638
+ function normalizeVariantKey(variant) {
2639
+ if (REVERSE_VARIANT_MAP[variant]) {
2640
+ return REVERSE_VARIANT_MAP[variant];
2641
+ }
2642
+ if (variant.startsWith("@")) {
2643
+ return variant;
2644
+ }
2645
+ return variant;
2646
+ }
2647
+ const TODO_KEEP = "sz:keep";
2648
+ const TODO_REMOVE = "sz:remove";
2649
+ const TODO_PENDING = "sz:todo";
2650
+ const MAX_TOKEN_CACHE_SIZE = 4096;
2651
+ const parsedTokenCache = /* @__PURE__ */ new Map();
2652
+ function resolveCustomMapEntry(token, customMap, resolveString) {
2653
+ if (!(token in customMap)) {
2654
+ return null;
2655
+ }
2656
+ const val = customMap[token];
2657
+ if (val && typeof val === "object" && !Array.isArray(val)) {
2658
+ return { action: "sz", value: val };
2659
+ }
2660
+ if (typeof val === "string") {
2661
+ if (val === TODO_KEEP) {
2662
+ return { action: "keep" };
2663
+ }
2664
+ if (val === TODO_REMOVE) {
2665
+ return { action: "remove" };
2666
+ }
2667
+ if (val === TODO_PENDING) {
2668
+ return { action: "unresolved" };
2669
+ }
2670
+ const result = resolveString(val);
2671
+ if (result && Object.keys(result.sz).length > 0) {
2672
+ return { action: "sz", value: result.sz, cascade: result.cascade };
2673
+ }
2674
+ return { action: "unresolved" };
2675
+ }
2676
+ return { action: "unresolved" };
2677
+ }
2678
+ function classNameToSzObject(className, customMap) {
2679
+ const tokens = tokenize(className);
2680
+ const szObject = {};
2681
+ const unrecognized = [];
2682
+ const keepInClassName = [];
2683
+ const seenCssPropertiesByPath = /* @__PURE__ */ new Map();
2684
+ const conflictedCssPropertiesByPath = /* @__PURE__ */ new Map();
2685
+ for (const token of tokens) {
2686
+ if (customMap && token in customMap) {
2687
+ const entry = resolveCustomMapEntry(
2688
+ token,
2689
+ customMap,
2690
+ // Inline resolver: parse Tailwind string recursively (no customMap to avoid infinite loop).
2691
+ // Returns both the sz object and any unrecognized tokens from the string value,
2692
+ // so partially-valid strings cascade their unknowns back to the unrecognized list.
2693
+ (twStr) => {
2694
+ const inner = classNameToSzObject(twStr);
2695
+ if (Object.keys(inner.szObject).length === 0) {
2696
+ return null;
2697
+ }
2698
+ return { sz: inner.szObject, cascade: inner.unrecognized };
2699
+ }
2700
+ );
2701
+ if (entry) {
2702
+ if (entry.action === "sz") {
2703
+ Object.assign(szObject, entry.value);
2704
+ if (entry.cascade && entry.cascade.length > 0) {
2705
+ unrecognized.push(...entry.cascade);
2706
+ }
2707
+ continue;
2708
+ }
2709
+ if (entry.action === "keep") {
2710
+ keepInClassName.push(token);
2711
+ continue;
2712
+ }
2713
+ if (entry.action === "remove") {
2714
+ continue;
2715
+ }
2716
+ if (entry.action === "unresolved") {
2717
+ unrecognized.push(token);
2718
+ continue;
2719
+ }
2720
+ }
2721
+ }
2722
+ const parsedToken = parseClassTokenCached(token);
2723
+ if (!parsedToken) {
2724
+ unrecognized.push(token);
2725
+ continue;
2726
+ }
2727
+ if (isCssPropertyConflicted(conflictedCssPropertiesByPath, parsedToken)) {
2728
+ unrecognized.push(token);
2729
+ continue;
2730
+ }
2731
+ const conflict = findCssPropertyConflict(seenCssPropertiesByPath, parsedToken, token);
2732
+ if (conflict) {
2733
+ rememberCssPropertyConflict(conflictedCssPropertiesByPath, parsedToken);
2734
+ unrecognized.push(conflict, token);
2735
+ removeNestedValue(szObject, parsedToken.keyPath, parsedToken.prop);
2736
+ continue;
2737
+ }
2738
+ rememberCssProperty(seenCssPropertiesByPath, parsedToken, token);
2739
+ setNestedValue(
2740
+ szObject,
2741
+ parsedToken.keyPath,
2742
+ parsedToken.prop,
2743
+ cloneParsedValue(parsedToken.value)
2744
+ );
2745
+ }
2746
+ return { szObject, unrecognized, keepInClassName };
2747
+ }
2748
+ function parseClassTokenCached(token) {
2749
+ if (parsedTokenCache.has(token)) {
2750
+ return parsedTokenCache.get(token) ?? null;
2751
+ }
2752
+ const parsed = parseClassToken(token);
2753
+ rememberParsedToken(token, parsed);
2754
+ return parsed;
2755
+ }
2756
+ function parseClassToken(token) {
2757
+ const { variantParts, baseClass } = extractVariants(token);
2758
+ const parsed = parseClass(baseClass, { });
2759
+ if (!parsed) {
2760
+ return null;
2761
+ }
2762
+ const keyPath = [];
2763
+ for (const variant of variantParts) {
2764
+ keyPath.push(...mapVariant(variant));
2765
+ }
2766
+ return {
2767
+ keyPath,
2768
+ prop: parsed.prop,
2769
+ value: parsed.value,
2770
+ cssProperty: parsed.cssProperty
2771
+ };
2772
+ }
2773
+ function rememberParsedToken(token, parsed) {
2774
+ if (parsedTokenCache.size >= MAX_TOKEN_CACHE_SIZE) {
2775
+ const oldest = parsedTokenCache.keys().next().value;
2776
+ if (oldest !== void 0) {
2777
+ parsedTokenCache.delete(oldest);
2778
+ }
2779
+ }
2780
+ parsedTokenCache.set(token, parsed);
2781
+ }
2782
+ function cloneParsedValue(value) {
2783
+ if (Array.isArray(value)) {
2784
+ return value.map(cloneParsedValue);
2785
+ }
2786
+ if (value && typeof value === "object") {
2787
+ const clone = {};
2788
+ for (const [key, nested] of Object.entries(value)) {
2789
+ clone[key] = cloneParsedValue(nested);
2790
+ }
2791
+ return clone;
2792
+ }
2793
+ return value;
2794
+ }
2795
+ function setNestedValue(obj, keyPath, prop, value) {
2796
+ let current = obj;
2797
+ for (const key of keyPath) {
2798
+ if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
2799
+ current[key] = {};
2800
+ }
2801
+ current = current[key];
2802
+ }
2803
+ current[prop] = value;
2804
+ }
2805
+ function findCssPropertyConflict(seen, parsed, token) {
2806
+ if (!parsed.cssProperty) {
2807
+ return null;
2808
+ }
2809
+ const scope = parsed.keyPath.join("\0");
2810
+ const previous = seen.get(scope)?.get(parsed.cssProperty);
2811
+ return previous && previous !== token ? previous : null;
2812
+ }
2813
+ function isCssPropertyConflicted(conflicted, parsed) {
2814
+ if (!parsed.cssProperty) {
2815
+ return false;
2816
+ }
2817
+ return conflicted.get(parsed.keyPath.join("\0"))?.has(parsed.cssProperty) === true;
2818
+ }
2819
+ function rememberCssPropertyConflict(conflicted, parsed) {
2820
+ if (!parsed.cssProperty) {
2821
+ return;
2822
+ }
2823
+ const scope = parsed.keyPath.join("\0");
2824
+ let properties = conflicted.get(scope);
2825
+ if (!properties) {
2826
+ properties = /* @__PURE__ */ new Set();
2827
+ conflicted.set(scope, properties);
2828
+ }
2829
+ properties.add(parsed.cssProperty);
2830
+ }
2831
+ function rememberCssProperty(seen, parsed, token) {
2832
+ if (!parsed.cssProperty) {
2833
+ return;
2834
+ }
2835
+ const scope = parsed.keyPath.join("\0");
2836
+ let properties = seen.get(scope);
2837
+ if (!properties) {
2838
+ properties = /* @__PURE__ */ new Map();
2839
+ seen.set(scope, properties);
2840
+ }
2841
+ properties.set(parsed.cssProperty, token);
2842
+ }
2843
+ function removeNestedValue(obj, keyPath, prop) {
2844
+ let current = obj;
2845
+ const parents = [];
2846
+ for (const key of keyPath) {
2847
+ const next = current[key];
2848
+ if (!next || typeof next !== "object" || Array.isArray(next)) {
2849
+ return;
2850
+ }
2851
+ parents.push([current, key]);
2852
+ current = next;
2853
+ }
2854
+ delete current[prop];
2855
+ for (let index = parents.length - 1; index >= 0; index--) {
2856
+ const [parent, key] = parents[index];
2857
+ const child = parent[key];
2858
+ if (child && typeof child === "object" && Object.keys(child).length === 0) {
2859
+ delete parent[key];
2860
+ }
2861
+ }
2862
+ }
2863
+
2864
+ const CLSX_LIKE_NAMES = /* @__PURE__ */ new Set(["clsx", "cn", "cx", "twMerge", "classNames", "classnames"]);
2865
+ function isClsxLikeName(name) {
2866
+ return CLSX_LIKE_NAMES.has(name);
2867
+ }
2868
+ function handleClsxCall(node, source, t, customMap) {
2869
+ const warnings = [];
2870
+ const allUnrecognized = [];
2871
+ const elements = [];
2872
+ let converted = 0;
2873
+ for (const arg of node.arguments) {
2874
+ if (t.isSpreadElement(arg)) {
2875
+ const argSrc2 = safeSlice(source, arg.start, arg.end);
2876
+ warnings.push(`Cannot migrate spread argument: ${argSrc2}`);
2877
+ return skip(allUnrecognized, warnings);
2878
+ }
2879
+ if (t.isStringLiteral(arg)) {
2880
+ const result = migrateString(arg.value, customMap);
2881
+ if (!result) {
2882
+ return skip(allUnrecognized, warnings);
2883
+ }
2884
+ elements.push(result.objectStr);
2885
+ allUnrecognized.push(...result.unrecognized);
2886
+ converted++;
2887
+ continue;
2888
+ }
2889
+ if (t.isLogicalExpression(arg) && arg.operator === "&&") {
2890
+ const result = handleLogicalAndInner(arg, source, t, customMap);
2891
+ if (!result) {
2892
+ const argSrc2 = safeSlice(source, arg.start, arg.end);
2893
+ warnings.push(`Cannot migrate logical expression: ${argSrc2}`);
2894
+ return skip(allUnrecognized, warnings);
2895
+ }
2896
+ elements.push(result.exprStr);
2897
+ allUnrecognized.push(...result.unrecognized);
2898
+ converted++;
2899
+ continue;
2900
+ }
2901
+ if (t.isConditionalExpression(arg)) {
2902
+ const result = handleTernaryInner(arg, source, t, customMap);
2903
+ if (!result) {
2904
+ const argSrc2 = safeSlice(source, arg.start, arg.end);
2905
+ warnings.push(`Cannot migrate ternary: ${argSrc2}`);
2906
+ return skip(allUnrecognized, warnings);
2907
+ }
2908
+ elements.push(result.exprStr);
2909
+ allUnrecognized.push(...result.unrecognized);
2910
+ converted++;
2911
+ continue;
2912
+ }
2913
+ const argSrc = safeSlice(source, arg.start, arg.end);
2914
+ warnings.push(`Cannot migrate argument: ${argSrc}`);
2915
+ return skip(allUnrecognized, warnings);
2916
+ }
2917
+ if (elements.length === 0) {
2918
+ return skip(allUnrecognized, warnings);
2919
+ }
2920
+ if (elements.length === 1 && !elements[0].includes("&&") && !elements[0].includes("?")) {
2921
+ return {
2922
+ replacement: `sz={${elements[0]}}`,
2923
+ unrecognized: allUnrecognized,
2924
+ warnings,
2925
+ converted,
2926
+ migrated: true
2927
+ };
2928
+ }
2929
+ return {
2930
+ replacement: `sz={[${elements.join(", ")}]}`,
2931
+ unrecognized: allUnrecognized,
2932
+ warnings,
2933
+ converted,
2934
+ migrated: true
2935
+ };
2936
+ }
2937
+ function handleTernary(node, source, t, customMap) {
2938
+ const result = handleTernaryInner(node, source, t, customMap);
2939
+ if (!result) {
2940
+ return {
2941
+ replacement: "",
2942
+ unrecognized: [],
2943
+ warnings: ["Ternary branches must be string literals"],
2944
+ converted: 0,
2945
+ migrated: false
2946
+ };
2947
+ }
2948
+ return {
2949
+ replacement: `sz={${result.exprStr}}`,
2950
+ unrecognized: result.unrecognized,
2951
+ warnings: [],
2952
+ converted: 1,
2953
+ migrated: true
2954
+ };
2955
+ }
2956
+ function handleLogicalAnd(node, source, t, customMap) {
2957
+ if (node.operator !== "&&") {
2958
+ return {
2959
+ replacement: "",
2960
+ unrecognized: [],
2961
+ warnings: [`Unsupported logical operator: ${node.operator}`],
2962
+ converted: 0,
2963
+ migrated: false
2964
+ };
2965
+ }
2966
+ const result = handleLogicalAndInner(node, source, t, customMap);
2967
+ if (!result) {
2968
+ return {
2969
+ replacement: "",
2970
+ unrecognized: [],
2971
+ warnings: ["Right side of && must be a string literal"],
2972
+ converted: 0,
2973
+ migrated: false
2974
+ };
2975
+ }
2976
+ return {
2977
+ replacement: `sz={${result.exprStr}}`,
2978
+ unrecognized: result.unrecognized,
2979
+ warnings: [],
2980
+ converted: 1,
2981
+ migrated: true
2982
+ };
2983
+ }
2984
+ function handleTemplateLiteral(node, source, t, customMap) {
2985
+ const warnings = [];
2986
+ const allUnrecognized = [];
2987
+ const staticText = node.quasis.map((q) => q.value.cooked ?? q.value.raw).join(" ");
2988
+ const trimmedStatic = staticText.replace(/\s+/g, " ").trim();
2989
+ let baseObject = {};
2990
+ if (trimmedStatic) {
2991
+ const { szObject, unrecognized } = classNameToSzObject(trimmedStatic, customMap);
2992
+ baseObject = szObject;
2993
+ allUnrecognized.push(...unrecognized);
2994
+ }
2995
+ const dynamicElements = [];
2996
+ let converted = 0;
2997
+ for (const expr of node.expressions) {
2998
+ if (!isExpression(expr, t)) {
2999
+ const exprSrc2 = safeSlice(
3000
+ source,
3001
+ expr.start,
3002
+ expr.end
3003
+ );
3004
+ warnings.push(`Cannot migrate template expression: ${exprSrc2}`);
3005
+ return skip(allUnrecognized, warnings);
3006
+ }
3007
+ if (t.isStringLiteral(expr)) {
3008
+ const result = migrateString(expr.value, customMap);
3009
+ if (result) {
3010
+ const { szObject } = classNameToSzObject(expr.value, customMap);
3011
+ baseObject = { ...baseObject, ...szObject };
3012
+ allUnrecognized.push(...result.unrecognized);
3013
+ converted++;
3014
+ }
3015
+ continue;
3016
+ }
3017
+ if (t.isConditionalExpression(expr)) {
3018
+ const result = handleTernaryInner(expr, source, t, customMap);
3019
+ if (!result) {
3020
+ const exprSrc2 = safeSlice(source, expr.start, expr.end);
3021
+ warnings.push(`Cannot migrate template ternary: ${exprSrc2}`);
3022
+ return skip(allUnrecognized, warnings);
3023
+ }
3024
+ dynamicElements.push(result.exprStr);
3025
+ allUnrecognized.push(...result.unrecognized);
3026
+ converted++;
3027
+ continue;
3028
+ }
3029
+ if (t.isLogicalExpression(expr) && expr.operator === "&&") {
3030
+ const result = handleLogicalAndInner(expr, source, t, customMap);
3031
+ if (!result) {
3032
+ const exprSrc2 = safeSlice(source, expr.start, expr.end);
3033
+ warnings.push(`Cannot migrate template logical expr: ${exprSrc2}`);
3034
+ return skip(allUnrecognized, warnings);
3035
+ }
3036
+ dynamicElements.push(result.exprStr);
3037
+ allUnrecognized.push(...result.unrecognized);
3038
+ converted++;
3039
+ continue;
3040
+ }
3041
+ const exprSrc = safeSlice(source, expr.start, expr.end);
3042
+ warnings.push(`Cannot migrate template expression: ${exprSrc}`);
3043
+ return skip(allUnrecognized, warnings);
3044
+ }
3045
+ const hasBase = Object.keys(baseObject).length > 0;
3046
+ const hasDynamic = dynamicElements.length > 0;
3047
+ if (!hasBase && !hasDynamic) {
3048
+ return skip(allUnrecognized, warnings);
3049
+ }
3050
+ if (hasBase && !hasDynamic) {
3051
+ return {
3052
+ replacement: `sz=${generateSzExpression(baseObject)}`,
3053
+ unrecognized: allUnrecognized,
3054
+ warnings,
3055
+ converted: converted + 1,
3056
+ migrated: true
3057
+ };
3058
+ }
3059
+ const parts = [];
3060
+ if (hasBase) {
3061
+ parts.push(generateSzObjectLiteral(baseObject));
3062
+ }
3063
+ parts.push(...dynamicElements);
3064
+ return {
3065
+ replacement: `sz={[${parts.join(", ")}]}`,
3066
+ unrecognized: allUnrecognized,
3067
+ warnings,
3068
+ converted: converted + (hasBase ? 1 : 0),
3069
+ migrated: true
3070
+ };
3071
+ }
3072
+ function handleTernaryInner(node, source, t, customMap) {
3073
+ if (!t.isStringLiteral(node.consequent) || !t.isStringLiteral(node.alternate)) {
3074
+ return null;
3075
+ }
3076
+ const condSource = safeSlice(source, node.test.start, node.test.end);
3077
+ const conValue = node.consequent.value.trim();
3078
+ const altValue = node.alternate.value.trim();
3079
+ if (altValue === "") {
3080
+ if (!conValue) {
3081
+ return null;
3082
+ }
3083
+ const conResult2 = migrateString(conValue, customMap);
3084
+ if (!conResult2 || conResult2.unrecognized.length > 0) {
3085
+ return null;
3086
+ }
3087
+ return {
3088
+ exprStr: `${condSource} && ${conResult2.objectStr}`,
3089
+ unrecognized: []
3090
+ };
3091
+ }
3092
+ if (conValue === "") {
3093
+ const altResult2 = migrateString(altValue, customMap);
3094
+ if (!altResult2 || altResult2.unrecognized.length > 0) {
3095
+ return null;
3096
+ }
3097
+ return {
3098
+ exprStr: `!${wrapCondition(condSource)} && ${altResult2.objectStr}`,
3099
+ unrecognized: []
3100
+ };
3101
+ }
3102
+ const conResult = migrateString(conValue, customMap);
3103
+ const altResult = migrateString(altValue, customMap);
3104
+ if (!conResult || !altResult) {
3105
+ return null;
3106
+ }
3107
+ const unrecognized = [...conResult.unrecognized, ...altResult.unrecognized];
3108
+ if (unrecognized.length > 0) {
3109
+ return null;
3110
+ }
3111
+ return {
3112
+ exprStr: `${condSource} ? ${conResult.objectStr} : ${altResult.objectStr}`,
3113
+ unrecognized: []
3114
+ };
3115
+ }
3116
+ function handleLogicalAndInner(node, source, t, customMap) {
3117
+ if (!t.isStringLiteral(node.right)) {
3118
+ return null;
3119
+ }
3120
+ const result = migrateString(node.right.value, customMap);
3121
+ if (!result || result.unrecognized.length > 0) {
3122
+ return null;
3123
+ }
3124
+ const condSource = safeSlice(source, node.left.start, node.left.end);
3125
+ return {
3126
+ exprStr: `${condSource} && ${result.objectStr}`,
3127
+ unrecognized: []
3128
+ };
3129
+ }
3130
+ function migrateString(className, customMap) {
3131
+ const trimmed = className.trim();
3132
+ if (!trimmed) {
3133
+ return null;
3134
+ }
3135
+ const { szObject, unrecognized } = classNameToSzObject(trimmed, customMap);
3136
+ if (Object.keys(szObject).length === 0) {
3137
+ return null;
3138
+ }
3139
+ return {
3140
+ objectStr: generateSzObjectLiteral(szObject),
3141
+ unrecognized
3142
+ };
3143
+ }
3144
+ function skip(unrecognized, warnings) {
3145
+ return {
3146
+ replacement: "",
3147
+ unrecognized,
3148
+ warnings,
3149
+ converted: 0,
3150
+ migrated: false
3151
+ };
3152
+ }
3153
+ function safeSlice(source, start, end) {
3154
+ if (start === null || start === void 0 || end === null || end === void 0) {
3155
+ return "<unknown>";
3156
+ }
3157
+ return source.slice(start, end);
3158
+ }
3159
+ function wrapCondition(cond) {
3160
+ if (cond.includes(" ") || cond.includes("||") || cond.includes("&&")) {
3161
+ return `(${cond})`;
3162
+ }
3163
+ return cond;
3164
+ }
3165
+ function isExpression(node, t) {
3166
+ return t.isExpression(node);
3167
+ }
3168
+
3169
+ const VISITOR_KEYS = t.VISITOR_KEYS;
3170
+ function injectTodoComment(unrecognized, parent, options, replacements) {
3171
+ if (!options.injectTodos || unrecognized.length === 0) {
3172
+ return;
3173
+ }
3174
+ if (!t.isJSXOpeningElement(parent) || parent.start === null || parent.start === void 0) {
3175
+ return;
3176
+ }
3177
+ replacements.push({
3178
+ start: parent.start,
3179
+ end: parent.start,
3180
+ text: `
3181
+ {/* @sz-todo: ${unrecognized.join(", ")} */}
3182
+ `
3183
+ });
3184
+ }
3185
+ function walkAst(node, visitors, ancestors = []) {
3186
+ if (t.isImportDeclaration(node)) {
3187
+ visitors.ImportDeclaration?.(node);
3188
+ } else if (t.isCallExpression(node)) {
3189
+ visitors.CallExpression?.(node, ancestors);
3190
+ } else if (t.isJSXAttribute(node)) {
3191
+ visitors.JSXAttribute?.(node, ancestors[ancestors.length - 1] ?? null);
3192
+ }
3193
+ const keys = VISITOR_KEYS[node.type];
3194
+ if (!keys) {
3195
+ return;
3196
+ }
3197
+ ancestors.push(node);
3198
+ for (const key of keys) {
3199
+ const child = node[key];
3200
+ if (Array.isArray(child)) {
3201
+ for (const item of child) {
3202
+ if (isAstNode(item)) {
3203
+ walkAst(item, visitors, ancestors);
3204
+ }
3205
+ }
3206
+ } else if (isAstNode(child)) {
3207
+ walkAst(child, visitors, ancestors);
3208
+ }
3209
+ }
3210
+ ancestors.pop();
3211
+ }
3212
+ function isAstNode(value) {
3213
+ return Boolean(value && typeof value === "object" && "type" in value);
3214
+ }
3215
+ function isClassNameJsxAttribute(node) {
3216
+ return t.isJSXAttribute(node) && t.isJSXIdentifier(node.name) && node.name.name === "className";
3217
+ }
3218
+ function isCleanCanonicalTarget(target) {
3219
+ return /^[a-z][a-z0-9]*$/i.test(target);
3220
+ }
3221
+ function normalizeSzObject(obj, replacements) {
3222
+ let count = 0;
3223
+ for (const prop of obj.properties) {
3224
+ if (!t.isObjectProperty(prop) || prop.computed) {
3225
+ continue;
3226
+ }
3227
+ const key = prop.key;
3228
+ let keyName = null;
3229
+ if (t.isIdentifier(key)) {
3230
+ keyName = key.name;
3231
+ } else if (t.isStringLiteral(key)) {
3232
+ keyName = key.value;
3233
+ }
3234
+ if (keyName === null) {
3235
+ continue;
3236
+ }
3237
+ const sugar = REMOVED_BOOLEAN_SUGAR[keyName];
3238
+ if (sugar && t.isBooleanLiteral(prop.value) && prop.value.value === true && prop.start != null && prop.end != null) {
3239
+ replacements.push({
3240
+ start: prop.start,
3241
+ end: prop.end,
3242
+ text: `${sugar.key}: '${sugar.value}'`
3243
+ });
3244
+ count++;
3245
+ continue;
3246
+ }
3247
+ const suggestion = SUGGESTION_MAP[keyName];
3248
+ if (suggestion && isCleanCanonicalTarget(suggestion) && suggestion !== keyName && key.start != null && key.end != null) {
3249
+ replacements.push({
3250
+ start: key.start,
3251
+ end: key.end,
3252
+ text: t.isStringLiteral(key) ? `'${suggestion}'` : suggestion
3253
+ });
3254
+ count++;
3255
+ }
3256
+ if (t.isObjectExpression(prop.value)) {
3257
+ count += normalizeSzObject(prop.value, replacements);
3258
+ }
3259
+ }
3260
+ return count;
3261
+ }
3262
+ function transformSource(source, filePath, options = {}) {
3263
+ const warnings = [];
3264
+ let classNamesTransformed = 0;
3265
+ let classNamesSkipped = 0;
3266
+ let classNamesSkippedComponent = 0;
3267
+ let szKeysNormalized = 0;
3268
+ const classesUnrecognized = [];
3269
+ const replacements = [];
3270
+ const clsxImportNames = /* @__PURE__ */ new Set();
3271
+ let clsxUsedOutsideClassName = false;
3272
+ const clsxCallsitesMigrated = /* @__PURE__ */ new Set();
3273
+ let hasCvaImport = false;
3274
+ if (options.keysOnly && source.indexOf("sz=") === -1) {
3275
+ return {
3276
+ code: source,
3277
+ changed: false,
3278
+ warnings: [],
3279
+ stats: {
3280
+ classNamesTransformed: 0,
3281
+ classNamesSkipped: 0,
3282
+ classNamesSkippedComponent: 0,
3283
+ classesUnrecognized: []
3284
+ },
3285
+ potentiallyUnusedImports: []
3286
+ };
3287
+ }
3288
+ if (source.indexOf("className") === -1 && source.indexOf("cva") === -1 && source.indexOf("sz=") === -1) {
3289
+ return {
3290
+ code: source,
3291
+ changed: false,
3292
+ warnings: [],
3293
+ stats: {
3294
+ classNamesTransformed: 0,
3295
+ classNamesSkipped: 0,
3296
+ classNamesSkippedComponent: 0,
3297
+ classesUnrecognized: []
3298
+ },
3299
+ potentiallyUnusedImports: []
3300
+ };
3301
+ }
3302
+ let ast;
3303
+ try {
3304
+ ast = parse(source, {
3305
+ sourceType: "module",
3306
+ plugins: ["jsx", "typescript", "decorators-legacy"],
3307
+ ranges: true
3308
+ });
3309
+ } catch (err) {
3310
+ const msg = err instanceof Error ? err.message : String(err);
3311
+ return {
3312
+ code: source,
3313
+ changed: false,
3314
+ warnings: [`Parse error in ${filePath}: ${msg}`],
3315
+ stats: {
3316
+ classNamesTransformed: 0,
3317
+ classNamesSkipped: 0,
3318
+ classNamesSkippedComponent: 0,
3319
+ classesUnrecognized: []
3320
+ },
3321
+ potentiallyUnusedImports: []
3322
+ };
3323
+ }
3324
+ walkAst(ast, {
3325
+ ImportDeclaration(node) {
3326
+ const src = node.source.value;
3327
+ const clsxPackages = ["clsx", "clsx/lite", "classnames", "tailwind-merge"];
3328
+ const isClsxPkg = clsxPackages.some((p) => src === p || src.startsWith(`${p}/`));
3329
+ const cvaPkgs = ["cva", "class-variance-authority"];
3330
+ if (cvaPkgs.some((p) => src === p || src.startsWith(`${p}/`))) {
3331
+ hasCvaImport = true;
3332
+ }
3333
+ for (const spec of node.specifiers) {
3334
+ const localName = spec.local.name;
3335
+ if (isClsxPkg || isClsxLikeName(localName)) {
3336
+ clsxImportNames.add(localName);
3337
+ }
3338
+ }
3339
+ },
3340
+ CallExpression(node, ancestors) {
3341
+ if (t.isIdentifier(node.callee) && clsxImportNames.has(node.callee.name)) {
3342
+ const inClassName = ancestors.some(isClassNameJsxAttribute);
3343
+ if (!inClassName) {
3344
+ clsxUsedOutsideClassName = true;
3345
+ }
3346
+ }
3347
+ },
3348
+ JSXAttribute(node, parent) {
3349
+ const attrName = node.name;
3350
+ if (t.isJSXIdentifier(attrName) && attrName.name === "sz") {
3351
+ const szValue = node.value;
3352
+ if (t.isJSXExpressionContainer(szValue) && t.isObjectExpression(szValue.expression)) {
3353
+ szKeysNormalized += normalizeSzObject(szValue.expression, replacements);
3354
+ }
3355
+ return;
3356
+ }
3357
+ if (options.keysOnly) {
3358
+ return;
3359
+ }
3360
+ if (!t.isJSXIdentifier(attrName) || attrName.name !== "className") {
3361
+ return;
3362
+ }
3363
+ if (t.isJSXOpeningElement(parent)) {
3364
+ const elementName = parent.name;
3365
+ const isCapitalized = t.isJSXIdentifier(elementName) && /^[A-Z]/.test(elementName.name) || t.isJSXMemberExpression(elementName);
3366
+ if (isCapitalized) {
3367
+ classNamesSkippedComponent++;
3368
+ return;
3369
+ }
3370
+ }
3371
+ if (t.isJSXOpeningElement(parent)) {
3372
+ const hasSz = parent.attributes.some(
3373
+ (attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === "sz"
3374
+ );
3375
+ if (hasSz) {
3376
+ classNamesSkipped++;
3377
+ return;
3378
+ }
3379
+ }
3380
+ const value = node.value;
3381
+ const attrStart = node.start;
3382
+ const attrEnd = node.end;
3383
+ if (attrStart === null || attrStart === void 0 || attrEnd === null || attrEnd === void 0) {
3384
+ return;
3385
+ }
3386
+ if (t.isStringLiteral(value)) {
3387
+ const result = processStaticString(value.value, options.customMap);
3388
+ if (result) {
3389
+ replacements.push({ start: attrStart, end: attrEnd, text: result.replacement });
3390
+ classNamesTransformed++;
3391
+ classesUnrecognized.push(...result.unrecognized);
3392
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3393
+ } else {
3394
+ classNamesSkipped++;
3395
+ }
3396
+ return;
3397
+ }
3398
+ if (t.isJSXExpressionContainer(value)) {
3399
+ const expr = value.expression;
3400
+ if (t.isStringLiteral(expr)) {
3401
+ const result = processStaticString(expr.value, options.customMap);
3402
+ if (result) {
3403
+ replacements.push({
3404
+ start: attrStart,
3405
+ end: attrEnd,
3406
+ text: result.replacement
3407
+ });
3408
+ classNamesTransformed++;
3409
+ classesUnrecognized.push(...result.unrecognized);
3410
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3411
+ } else {
3412
+ classNamesSkipped++;
3413
+ }
3414
+ return;
3415
+ }
3416
+ if (t.isTemplateLiteral(expr)) {
3417
+ const result = handleTemplateLiteral(expr, source, t, options.customMap);
3418
+ if (result.migrated) {
3419
+ replacements.push({
3420
+ start: attrStart,
3421
+ end: attrEnd,
3422
+ text: result.replacement
3423
+ });
3424
+ classNamesTransformed += result.converted;
3425
+ classesUnrecognized.push(...result.unrecognized);
3426
+ } else {
3427
+ classNamesSkipped++;
3428
+ warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
3429
+ classesUnrecognized.push(...result.unrecognized);
3430
+ }
3431
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3432
+ return;
3433
+ }
3434
+ if (t.isCallExpression(expr) && t.isIdentifier(expr.callee) && isClsxLikeName(expr.callee.name)) {
3435
+ const result = handleClsxCall(expr, source, t, options.customMap);
3436
+ if (result.migrated) {
3437
+ replacements.push({
3438
+ start: attrStart,
3439
+ end: attrEnd,
3440
+ text: result.replacement
3441
+ });
3442
+ classNamesTransformed += result.converted;
3443
+ classesUnrecognized.push(...result.unrecognized);
3444
+ if (expr.start !== null && expr.start !== void 0) {
3445
+ clsxCallsitesMigrated.add(expr.start);
3446
+ }
3447
+ } else {
3448
+ classNamesSkipped++;
3449
+ warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
3450
+ classesUnrecognized.push(...result.unrecognized);
3451
+ }
3452
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3453
+ return;
3454
+ }
3455
+ if (t.isConditionalExpression(expr)) {
3456
+ const result = handleTernary(expr, source, t, options.customMap);
3457
+ if (result.migrated) {
3458
+ replacements.push({
3459
+ start: attrStart,
3460
+ end: attrEnd,
3461
+ text: result.replacement
3462
+ });
3463
+ classNamesTransformed += result.converted;
3464
+ classesUnrecognized.push(...result.unrecognized);
3465
+ } else {
3466
+ classNamesSkipped++;
3467
+ warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
3468
+ classesUnrecognized.push(...result.unrecognized);
3469
+ }
3470
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3471
+ return;
3472
+ }
3473
+ if (t.isLogicalExpression(expr) && expr.operator === "&&") {
3474
+ const result = handleLogicalAnd(expr, source, t, options.customMap);
3475
+ if (result.migrated) {
3476
+ replacements.push({
3477
+ start: attrStart,
3478
+ end: attrEnd,
3479
+ text: result.replacement
3480
+ });
3481
+ classNamesTransformed += result.converted;
3482
+ classesUnrecognized.push(...result.unrecognized);
3483
+ } else {
3484
+ classNamesSkipped++;
3485
+ warnings.push(...result.warnings.map((w) => `[${filePath}] ${w}`));
3486
+ classesUnrecognized.push(...result.unrecognized);
3487
+ }
3488
+ injectTodoComment(result.unrecognized, parent, options, replacements);
3489
+ return;
3490
+ }
3491
+ classNamesSkipped++;
3492
+ return;
3493
+ }
3494
+ classNamesSkipped++;
3495
+ }
3496
+ });
3497
+ if (hasCvaImport) {
3498
+ warnings.push(
3499
+ `[${filePath}] File uses cva() \u2014 consider migrating to szv() from @csszyx/runtime for type-safe variant-based styling.`
3500
+ );
3501
+ }
3502
+ let output = source;
3503
+ const sorted = replacements.sort((a, b) => b.start - a.start);
3504
+ for (const r of sorted) {
3505
+ output = output.slice(0, r.start) + r.text + output.slice(r.end);
3506
+ }
3507
+ const potentiallyUnusedImports = [];
3508
+ if (clsxImportNames.size > 0 && !clsxUsedOutsideClassName && replacements.length > 0) {
3509
+ for (const name of clsxImportNames) {
3510
+ const callPattern = new RegExp(`\\b${name}\\s*\\(`, "g");
3511
+ if (!callPattern.test(output)) {
3512
+ potentiallyUnusedImports.push(name);
3513
+ }
3514
+ }
3515
+ }
3516
+ return {
3517
+ code: output,
3518
+ changed: replacements.length > 0,
3519
+ warnings,
3520
+ stats: {
3521
+ classNamesTransformed,
3522
+ classNamesSkipped,
3523
+ classNamesSkippedComponent,
3524
+ classesUnrecognized,
3525
+ szKeysNormalized
3526
+ },
3527
+ potentiallyUnusedImports
3528
+ };
3529
+ }
3530
+ function processStaticString(classNameStr, customMap) {
3531
+ const trimmed = classNameStr.trim();
3532
+ if (!trimmed) {
3533
+ return null;
3534
+ }
3535
+ const { szObject, unrecognized, keepInClassName } = classNameToSzObject(trimmed, customMap);
3536
+ if (Object.keys(szObject).length === 0) {
3537
+ return null;
3538
+ }
3539
+ const szExpr = generateSzExpression(szObject);
3540
+ const remainingClassName = [...keepInClassName, ...unrecognized];
3541
+ if (remainingClassName.length > 0) {
3542
+ return {
3543
+ replacement: `className="${remainingClassName.join(" ")}" sz=${szExpr}`,
3544
+ unrecognized
3545
+ };
3546
+ }
3547
+ return {
3548
+ replacement: `sz=${szExpr}`,
3549
+ unrecognized: []
3550
+ };
3551
+ }
3552
+ const FOUC_CSS = `<style>
3553
+ /* csszyx: hide [sz] elements until runtime processes them */
3554
+ [sz] { visibility: hidden; }
3555
+ body.sz-ready [sz] { visibility: visible; }
3556
+ </style>`;
3557
+ function transformHtmlSourceSimple(source, filePath, options = {}) {
3558
+ const {
3559
+ braces = false,
3560
+ injectFouc = true,
3561
+ injectRuntime = false,
3562
+ cdnUrl = "https://cdn.csszyx.com/runtime.js",
3563
+ localPath = "csszyx-runtime.js"
3564
+ } = options;
3565
+ const warnings = [];
3566
+ let classNamesTransformed = 0;
3567
+ let classNamesSkipped = 0;
3568
+ const classNamesSkippedComponent = 0;
3569
+ const classesUnrecognized = [];
3570
+ let changed = false;
3571
+ let output = source.replace(/\bclass="([^"]*)"/g, (match, classStr) => {
3572
+ return processClassAttr(match, classStr, '"');
3573
+ });
3574
+ output = output.replace(/\bclass='([^']*)'/g, (match, classStr) => {
3575
+ return processClassAttr(match, classStr, "'");
3576
+ });
3577
+ if (injectFouc && output.includes("</head>") && !output.includes("csszyx: hide [sz]")) {
3578
+ output = output.replace("</head>", `${FOUC_CSS}
3579
+ </head>`);
3580
+ changed = true;
3581
+ }
3582
+ if (injectRuntime && output.includes("</body>")) {
3583
+ const scriptSrc = injectRuntime === "cdn" ? cdnUrl : localPath;
3584
+ const scriptTag = `<script src="${scriptSrc}"><\/script>`;
3585
+ if (!output.includes(scriptSrc)) {
3586
+ output = output.replace("</body>", `${scriptTag}
3587
+ </body>`);
3588
+ changed = true;
3589
+ }
3590
+ }
3591
+ function processClassAttr(match, classStr, quote) {
3592
+ const trimmed = classStr.trim();
3593
+ if (!trimmed) {
3594
+ classNamesSkipped++;
3595
+ return match;
3596
+ }
3597
+ const { szObject, unrecognized } = classNameToSzObject(trimmed);
3598
+ if (Object.keys(szObject).length === 0) {
3599
+ classNamesSkipped++;
3600
+ classesUnrecognized.push(...unrecognized);
3601
+ return match;
3602
+ }
3603
+ const szVal = generateSzHtmlValue(szObject, braces);
3604
+ changed = true;
3605
+ classNamesTransformed++;
3606
+ if (unrecognized.length > 0) {
3607
+ classesUnrecognized.push(...unrecognized);
3608
+ return `class=${quote}${unrecognized.join(" ")}${quote} sz="${szVal}"`;
3609
+ }
3610
+ return `sz="${szVal}"`;
3611
+ }
3612
+ return {
3613
+ code: output,
3614
+ changed,
3615
+ warnings,
3616
+ stats: {
3617
+ classNamesTransformed,
3618
+ classNamesSkipped,
3619
+ classNamesSkippedComponent,
3620
+ classesUnrecognized
3621
+ },
3622
+ potentiallyUnusedImports: []
3623
+ };
3624
+ }
3625
+
3626
+ export { extractSpacingKeys as a, flattenColors as b, classNameToSzObject as c, generateTypeDeclarations as d, extractScreenKeys as e, findConfigFile as f, generateAndWriteTypes as g, generateTypes as h, transformHtmlSourceSimple as i, scanTailwindConfig as s, transformSource as t, writeDeclarationFile as w };