dispersa 0.1.3 → 0.3.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.
Files changed (53) hide show
  1. package/README.md +65 -23
  2. package/dist/builders.cjs +1923 -47
  3. package/dist/builders.cjs.map +1 -1
  4. package/dist/builders.d.cts +155 -6
  5. package/dist/builders.d.ts +155 -6
  6. package/dist/builders.js +1922 -49
  7. package/dist/builders.js.map +1 -1
  8. package/dist/cli/cli.d.ts +11 -0
  9. package/dist/cli/cli.js +201 -0
  10. package/dist/cli/cli.js.map +1 -0
  11. package/dist/cli/config.d.ts +8 -0
  12. package/dist/cli/config.js +8 -0
  13. package/dist/cli/config.js.map +1 -0
  14. package/dist/cli/index.d.ts +1 -0
  15. package/dist/cli/index.js +203 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/filters.cjs +8 -7
  18. package/dist/filters.cjs.map +1 -1
  19. package/dist/filters.d.cts +13 -16
  20. package/dist/filters.d.ts +13 -16
  21. package/dist/filters.js +8 -7
  22. package/dist/filters.js.map +1 -1
  23. package/dist/{index-CPB9Ea9U.d.ts → index-BkvV7Z54.d.cts} +183 -60
  24. package/dist/{index-DKf9WMQG.d.cts → index-DJ_UHSQG.d.ts} +183 -60
  25. package/dist/index.cjs +2121 -226
  26. package/dist/index.cjs.map +1 -1
  27. package/dist/index.d.cts +8 -8
  28. package/dist/index.d.ts +8 -8
  29. package/dist/index.js +2120 -228
  30. package/dist/index.js.map +1 -1
  31. package/dist/preprocessors.cjs.map +1 -1
  32. package/dist/preprocessors.d.cts +2 -2
  33. package/dist/preprocessors.d.ts +2 -2
  34. package/dist/preprocessors.js.map +1 -1
  35. package/dist/renderers.cjs.map +1 -1
  36. package/dist/renderers.d.cts +6 -6
  37. package/dist/renderers.d.ts +6 -6
  38. package/dist/renderers.js.map +1 -1
  39. package/dist/transforms.cjs +5 -5
  40. package/dist/transforms.cjs.map +1 -1
  41. package/dist/transforms.d.cts +2 -2
  42. package/dist/transforms.d.ts +2 -2
  43. package/dist/transforms.js +5 -5
  44. package/dist/transforms.js.map +1 -1
  45. package/dist/{types-DM5faYUn.d.cts → types-BAv39mum.d.cts} +1 -1
  46. package/dist/{types-C1GpiJ6q.d.ts → types-Bc0kA7De.d.cts} +10 -10
  47. package/dist/{types-C1GpiJ6q.d.cts → types-Bc0kA7De.d.ts} +10 -10
  48. package/dist/{types-Cl-1UYGD.d.ts → types-BzNcG-rI.d.ts} +1 -1
  49. package/dist/{types-DJH6_4U9.d.ts → types-CZb19kiq.d.ts} +1 -1
  50. package/dist/{types-DbufGPrb.d.cts → types-CussyWwe.d.cts} +1 -1
  51. package/dist/{types-DdPWYkgh.d.ts → types-CzHa7YkW.d.ts} +1 -1
  52. package/dist/{types-BDY1xBmD.d.cts → types-DWKq-eJj.d.cts} +1 -1
  53. package/package.json +18 -1
package/dist/index.cjs CHANGED
@@ -186,10 +186,55 @@ var init_errors = __esm({
186
186
  }
187
187
  });
188
188
 
189
- // src/lib/validation/dtcg-schemas/2025.10/format/group.json
189
+ // src/shared/utils/validation-handler.ts
190
+ var ValidationHandler;
191
+ var init_validation_handler = __esm({
192
+ "src/shared/utils/validation-handler.ts"() {
193
+ ValidationHandler = class {
194
+ mode;
195
+ constructor(options) {
196
+ this.mode = options?.mode ?? "error";
197
+ }
198
+ /**
199
+ * Whether validation checks should run (mode is not 'off')
200
+ */
201
+ shouldValidate() {
202
+ return this.mode !== "off";
203
+ }
204
+ /**
205
+ * Whether the current mode is 'error' (strictest)
206
+ */
207
+ isStrict() {
208
+ return this.mode === "error";
209
+ }
210
+ /**
211
+ * Handle a validation issue: throw in 'error' mode, warn in 'warn' mode, ignore in 'off' mode
212
+ */
213
+ handleIssue(error) {
214
+ if (this.mode === "error") {
215
+ throw error;
216
+ }
217
+ if (this.mode === "warn") {
218
+ console.warn(error.message);
219
+ }
220
+ }
221
+ /**
222
+ * Emit a warning (in 'error' and 'warn' modes, skip in 'off')
223
+ */
224
+ warn(message) {
225
+ if (this.mode === "off") {
226
+ return;
227
+ }
228
+ console.warn(message);
229
+ }
230
+ };
231
+ }
232
+ });
233
+
234
+ // src/validation/dtcg-schemas/2025.10/format/group.json
190
235
  var group_default;
191
236
  var init_group = __esm({
192
- "src/lib/validation/dtcg-schemas/2025.10/format/group.json"() {
237
+ "src/validation/dtcg-schemas/2025.10/format/group.json"() {
193
238
  group_default = {
194
239
  $schema: "http://json-schema.org/draft-07/schema#",
195
240
  $id: "https://www.designtokens.org/schemas/2025.10/format/group.json",
@@ -247,10 +292,10 @@ var init_group = __esm({
247
292
  }
248
293
  });
249
294
 
250
- // src/lib/validation/dtcg-schemas/2025.10/format/groupOrToken.json
295
+ // src/validation/dtcg-schemas/2025.10/format/groupOrToken.json
251
296
  var groupOrToken_default;
252
297
  var init_groupOrToken = __esm({
253
- "src/lib/validation/dtcg-schemas/2025.10/format/groupOrToken.json"() {
298
+ "src/validation/dtcg-schemas/2025.10/format/groupOrToken.json"() {
254
299
  groupOrToken_default = {
255
300
  $schema: "http://json-schema.org/draft-07/schema#",
256
301
  $id: "https://www.designtokens.org/schemas/2025.10/format/groupOrToken.json",
@@ -268,10 +313,10 @@ var init_groupOrToken = __esm({
268
313
  }
269
314
  });
270
315
 
271
- // src/lib/validation/dtcg-schemas/2025.10/format/token.json
316
+ // src/validation/dtcg-schemas/2025.10/format/token.json
272
317
  var token_default;
273
318
  var init_token = __esm({
274
- "src/lib/validation/dtcg-schemas/2025.10/format/token.json"() {
319
+ "src/validation/dtcg-schemas/2025.10/format/token.json"() {
275
320
  token_default = {
276
321
  $schema: "http://json-schema.org/draft-07/schema#",
277
322
  $id: "https://www.designtokens.org/schemas/2025.10/format/token.json",
@@ -699,10 +744,10 @@ var init_token = __esm({
699
744
  }
700
745
  });
701
746
 
702
- // src/lib/validation/dtcg-schemas/2025.10/format/tokenType.json
747
+ // src/validation/dtcg-schemas/2025.10/format/tokenType.json
703
748
  var tokenType_default;
704
749
  var init_tokenType = __esm({
705
- "src/lib/validation/dtcg-schemas/2025.10/format/tokenType.json"() {
750
+ "src/validation/dtcg-schemas/2025.10/format/tokenType.json"() {
706
751
  tokenType_default = {
707
752
  $schema: "http://json-schema.org/draft-07/schema#",
708
753
  $id: "https://www.designtokens.org/schemas/2025.10/format/tokenType.json",
@@ -728,10 +773,10 @@ var init_tokenType = __esm({
728
773
  }
729
774
  });
730
775
 
731
- // src/lib/validation/dtcg-schemas/2025.10/format/values/border.json
776
+ // src/validation/dtcg-schemas/2025.10/format/values/border.json
732
777
  var border_default;
733
778
  var init_border = __esm({
734
- "src/lib/validation/dtcg-schemas/2025.10/format/values/border.json"() {
779
+ "src/validation/dtcg-schemas/2025.10/format/values/border.json"() {
735
780
  border_default = {
736
781
  $schema: "http://json-schema.org/draft-07/schema#",
737
782
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/border.json",
@@ -779,10 +824,10 @@ var init_border = __esm({
779
824
  }
780
825
  });
781
826
 
782
- // src/lib/validation/dtcg-schemas/2025.10/format/values/color.json
827
+ // src/validation/dtcg-schemas/2025.10/format/values/color.json
783
828
  var color_default;
784
829
  var init_color = __esm({
785
- "src/lib/validation/dtcg-schemas/2025.10/format/values/color.json"() {
830
+ "src/validation/dtcg-schemas/2025.10/format/values/color.json"() {
786
831
  color_default = {
787
832
  $schema: "http://json-schema.org/draft-07/schema#",
788
833
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/color.json",
@@ -1300,10 +1345,10 @@ var init_color = __esm({
1300
1345
  }
1301
1346
  });
1302
1347
 
1303
- // src/lib/validation/dtcg-schemas/2025.10/format/values/cubicBezier.json
1348
+ // src/validation/dtcg-schemas/2025.10/format/values/cubicBezier.json
1304
1349
  var cubicBezier_default;
1305
1350
  var init_cubicBezier = __esm({
1306
- "src/lib/validation/dtcg-schemas/2025.10/format/values/cubicBezier.json"() {
1351
+ "src/validation/dtcg-schemas/2025.10/format/values/cubicBezier.json"() {
1307
1352
  cubicBezier_default = {
1308
1353
  $schema: "http://json-schema.org/draft-07/schema#",
1309
1354
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/cubicBezier.json",
@@ -1363,10 +1408,10 @@ var init_cubicBezier = __esm({
1363
1408
  }
1364
1409
  });
1365
1410
 
1366
- // src/lib/validation/dtcg-schemas/2025.10/format/values/dimension.json
1411
+ // src/validation/dtcg-schemas/2025.10/format/values/dimension.json
1367
1412
  var dimension_default;
1368
1413
  var init_dimension = __esm({
1369
- "src/lib/validation/dtcg-schemas/2025.10/format/values/dimension.json"() {
1414
+ "src/validation/dtcg-schemas/2025.10/format/values/dimension.json"() {
1370
1415
  dimension_default = {
1371
1416
  $schema: "http://json-schema.org/draft-07/schema#",
1372
1417
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/dimension.json",
@@ -1404,10 +1449,10 @@ var init_dimension = __esm({
1404
1449
  }
1405
1450
  });
1406
1451
 
1407
- // src/lib/validation/dtcg-schemas/2025.10/format/values/duration.json
1452
+ // src/validation/dtcg-schemas/2025.10/format/values/duration.json
1408
1453
  var duration_default;
1409
1454
  var init_duration = __esm({
1410
- "src/lib/validation/dtcg-schemas/2025.10/format/values/duration.json"() {
1455
+ "src/validation/dtcg-schemas/2025.10/format/values/duration.json"() {
1411
1456
  duration_default = {
1412
1457
  $schema: "http://json-schema.org/draft-07/schema#",
1413
1458
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/duration.json",
@@ -1445,10 +1490,10 @@ var init_duration = __esm({
1445
1490
  }
1446
1491
  });
1447
1492
 
1448
- // src/lib/validation/dtcg-schemas/2025.10/format/values/fontFamily.json
1493
+ // src/validation/dtcg-schemas/2025.10/format/values/fontFamily.json
1449
1494
  var fontFamily_default;
1450
1495
  var init_fontFamily = __esm({
1451
- "src/lib/validation/dtcg-schemas/2025.10/format/values/fontFamily.json"() {
1496
+ "src/validation/dtcg-schemas/2025.10/format/values/fontFamily.json"() {
1452
1497
  fontFamily_default = {
1453
1498
  $schema: "http://json-schema.org/draft-07/schema#",
1454
1499
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/fontFamily.json",
@@ -1485,10 +1530,10 @@ var init_fontFamily = __esm({
1485
1530
  }
1486
1531
  });
1487
1532
 
1488
- // src/lib/validation/dtcg-schemas/2025.10/format/values/fontWeight.json
1533
+ // src/validation/dtcg-schemas/2025.10/format/values/fontWeight.json
1489
1534
  var fontWeight_default;
1490
1535
  var init_fontWeight = __esm({
1491
- "src/lib/validation/dtcg-schemas/2025.10/format/values/fontWeight.json"() {
1536
+ "src/validation/dtcg-schemas/2025.10/format/values/fontWeight.json"() {
1492
1537
  fontWeight_default = {
1493
1538
  $schema: "http://json-schema.org/draft-07/schema#",
1494
1539
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/fontWeight.json",
@@ -1530,10 +1575,10 @@ var init_fontWeight = __esm({
1530
1575
  }
1531
1576
  });
1532
1577
 
1533
- // src/lib/validation/dtcg-schemas/2025.10/format/values/gradient.json
1578
+ // src/validation/dtcg-schemas/2025.10/format/values/gradient.json
1534
1579
  var gradient_default;
1535
1580
  var init_gradient = __esm({
1536
- "src/lib/validation/dtcg-schemas/2025.10/format/values/gradient.json"() {
1581
+ "src/validation/dtcg-schemas/2025.10/format/values/gradient.json"() {
1537
1582
  gradient_default = {
1538
1583
  $schema: "http://json-schema.org/draft-07/schema#",
1539
1584
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/gradient.json",
@@ -1589,10 +1634,10 @@ var init_gradient = __esm({
1589
1634
  }
1590
1635
  });
1591
1636
 
1592
- // src/lib/validation/dtcg-schemas/2025.10/format/values/number.json
1637
+ // src/validation/dtcg-schemas/2025.10/format/values/number.json
1593
1638
  var number_default;
1594
1639
  var init_number = __esm({
1595
- "src/lib/validation/dtcg-schemas/2025.10/format/values/number.json"() {
1640
+ "src/validation/dtcg-schemas/2025.10/format/values/number.json"() {
1596
1641
  number_default = {
1597
1642
  $schema: "http://json-schema.org/draft-07/schema#",
1598
1643
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/number.json",
@@ -1603,10 +1648,10 @@ var init_number = __esm({
1603
1648
  }
1604
1649
  });
1605
1650
 
1606
- // src/lib/validation/dtcg-schemas/2025.10/format/values/shadow.json
1651
+ // src/validation/dtcg-schemas/2025.10/format/values/shadow.json
1607
1652
  var shadow_default;
1608
1653
  var init_shadow = __esm({
1609
- "src/lib/validation/dtcg-schemas/2025.10/format/values/shadow.json"() {
1654
+ "src/validation/dtcg-schemas/2025.10/format/values/shadow.json"() {
1610
1655
  shadow_default = {
1611
1656
  $schema: "http://json-schema.org/draft-07/schema#",
1612
1657
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/shadow.json",
@@ -1712,10 +1757,10 @@ var init_shadow = __esm({
1712
1757
  }
1713
1758
  });
1714
1759
 
1715
- // src/lib/validation/dtcg-schemas/2025.10/format/values/strokeStyle.json
1760
+ // src/validation/dtcg-schemas/2025.10/format/values/strokeStyle.json
1716
1761
  var strokeStyle_default;
1717
1762
  var init_strokeStyle = __esm({
1718
- "src/lib/validation/dtcg-schemas/2025.10/format/values/strokeStyle.json"() {
1763
+ "src/validation/dtcg-schemas/2025.10/format/values/strokeStyle.json"() {
1719
1764
  strokeStyle_default = {
1720
1765
  $schema: "http://json-schema.org/draft-07/schema#",
1721
1766
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/strokeStyle.json",
@@ -1773,10 +1818,10 @@ var init_strokeStyle = __esm({
1773
1818
  }
1774
1819
  });
1775
1820
 
1776
- // src/lib/validation/dtcg-schemas/2025.10/format/values/transition.json
1821
+ // src/validation/dtcg-schemas/2025.10/format/values/transition.json
1777
1822
  var transition_default;
1778
1823
  var init_transition = __esm({
1779
- "src/lib/validation/dtcg-schemas/2025.10/format/values/transition.json"() {
1824
+ "src/validation/dtcg-schemas/2025.10/format/values/transition.json"() {
1780
1825
  transition_default = {
1781
1826
  $schema: "http://json-schema.org/draft-07/schema#",
1782
1827
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/transition.json",
@@ -1824,10 +1869,10 @@ var init_transition = __esm({
1824
1869
  }
1825
1870
  });
1826
1871
 
1827
- // src/lib/validation/dtcg-schemas/2025.10/format/values/typography.json
1872
+ // src/validation/dtcg-schemas/2025.10/format/values/typography.json
1828
1873
  var typography_default;
1829
1874
  var init_typography = __esm({
1830
- "src/lib/validation/dtcg-schemas/2025.10/format/values/typography.json"() {
1875
+ "src/validation/dtcg-schemas/2025.10/format/values/typography.json"() {
1831
1876
  typography_default = {
1832
1877
  $schema: "http://json-schema.org/draft-07/schema#",
1833
1878
  $id: "https://www.designtokens.org/schemas/2025.10/format/values/typography.json",
@@ -1897,10 +1942,10 @@ var init_typography = __esm({
1897
1942
  }
1898
1943
  });
1899
1944
 
1900
- // src/lib/validation/dtcg-schemas/2025.10/format.json
1945
+ // src/validation/dtcg-schemas/2025.10/format.json
1901
1946
  var format_default;
1902
1947
  var init_format = __esm({
1903
- "src/lib/validation/dtcg-schemas/2025.10/format.json"() {
1948
+ "src/validation/dtcg-schemas/2025.10/format.json"() {
1904
1949
  format_default = {
1905
1950
  $schema: "http://json-schema.org/draft-07/schema#",
1906
1951
  $id: "https://www.designtokens.org/schemas/2025.10/format.json",
@@ -2009,10 +2054,10 @@ var init_format = __esm({
2009
2054
  }
2010
2055
  });
2011
2056
 
2012
- // src/lib/validation/dtcg-schemas/2025.10/resolver/modifier.json
2057
+ // src/validation/dtcg-schemas/2025.10/resolver/modifier.json
2013
2058
  var modifier_default;
2014
2059
  var init_modifier = __esm({
2015
- "src/lib/validation/dtcg-schemas/2025.10/resolver/modifier.json"() {
2060
+ "src/validation/dtcg-schemas/2025.10/resolver/modifier.json"() {
2016
2061
  modifier_default = {
2017
2062
  $schema: "http://json-schema.org/draft-07/schema#",
2018
2063
  $id: "https://www.designtokens.org/schemas/2025.10/resolver/modifier.json",
@@ -2100,10 +2145,10 @@ var init_modifier = __esm({
2100
2145
  }
2101
2146
  });
2102
2147
 
2103
- // src/lib/validation/dtcg-schemas/2025.10/resolver/resolutionOrder.json
2148
+ // src/validation/dtcg-schemas/2025.10/resolver/resolutionOrder.json
2104
2149
  var resolutionOrder_default;
2105
2150
  var init_resolutionOrder = __esm({
2106
- "src/lib/validation/dtcg-schemas/2025.10/resolver/resolutionOrder.json"() {
2151
+ "src/validation/dtcg-schemas/2025.10/resolver/resolutionOrder.json"() {
2107
2152
  resolutionOrder_default = {
2108
2153
  $schema: "http://json-schema.org/draft-07/schema#",
2109
2154
  $id: "https://www.designtokens.org/schemas/2025.10/resolver/resolutionOrder.json",
@@ -2223,10 +2268,10 @@ var init_resolutionOrder = __esm({
2223
2268
  }
2224
2269
  });
2225
2270
 
2226
- // src/lib/validation/dtcg-schemas/2025.10/resolver/set.json
2271
+ // src/validation/dtcg-schemas/2025.10/resolver/set.json
2227
2272
  var set_default;
2228
2273
  var init_set = __esm({
2229
- "src/lib/validation/dtcg-schemas/2025.10/resolver/set.json"() {
2274
+ "src/validation/dtcg-schemas/2025.10/resolver/set.json"() {
2230
2275
  set_default = {
2231
2276
  $schema: "http://json-schema.org/draft-07/schema#",
2232
2277
  $id: "https://www.designtokens.org/schemas/2025.10/resolver/set.json",
@@ -2300,10 +2345,10 @@ var init_set = __esm({
2300
2345
  }
2301
2346
  });
2302
2347
 
2303
- // src/lib/validation/dtcg-schemas/2025.10/resolver.json
2348
+ // src/validation/dtcg-schemas/2025.10/resolver.json
2304
2349
  var resolver_default;
2305
2350
  var init_resolver = __esm({
2306
- "src/lib/validation/dtcg-schemas/2025.10/resolver.json"() {
2351
+ "src/validation/dtcg-schemas/2025.10/resolver.json"() {
2307
2352
  resolver_default = {
2308
2353
  $schema: "http://json-schema.org/draft-07/schema#",
2309
2354
  $id: "https://www.designtokens.org/schemas/2025.10/resolver.json",
@@ -2368,10 +2413,10 @@ var init_resolver = __esm({
2368
2413
  }
2369
2414
  });
2370
2415
 
2371
- // src/lib/validation/schemas.ts
2416
+ // src/validation/schemas.ts
2372
2417
  var formatSchema, tokenSchema, tokenTypeSchema, groupSchema, groupOrTokenSchema, colorValueSchema, dimensionValueSchema, fontFamilyValueSchema, fontWeightValueSchema, durationValueSchema, cubicBezierValueSchema, numberValueSchema, strokeStyleValueSchema, borderValueSchema, transitionValueSchema, shadowValueSchema, gradientValueSchema, typographyValueSchema, resolverSchema, resolverSetSchema, resolverModifierSchema, resolverResolutionOrderSchema, dtcgSchemaRegistry;
2373
2418
  var init_schemas = __esm({
2374
- "src/lib/validation/schemas.ts"() {
2419
+ "src/validation/schemas.ts"() {
2375
2420
  init_group();
2376
2421
  init_groupOrToken();
2377
2422
  init_token();
@@ -2443,10 +2488,10 @@ var init_schemas = __esm({
2443
2488
  }
2444
2489
  });
2445
2490
 
2446
- // src/lib/validation/config-schemas.ts
2491
+ // src/validation/config-schemas.ts
2447
2492
  var resolverSchemaRef, basePluginProperties, commonRendererOptionsProperties, transformPluginSchema, rendererPluginSchema, filterPluginSchema, preprocessorPluginSchema, outputConfigSchema, dispersaOptionsSchema, buildConfigSchema;
2448
2493
  var init_config_schemas = __esm({
2449
- "src/lib/validation/config-schemas.ts"() {
2494
+ "src/validation/config-schemas.ts"() {
2450
2495
  init_schemas();
2451
2496
  resolverSchemaRef = resolverSchema;
2452
2497
  basePluginProperties = {
@@ -2500,6 +2545,25 @@ var init_config_schemas = __esm({
2500
2545
  additionalProperties: true
2501
2546
  // Allow custom properties for extended renderers
2502
2547
  });
2548
+ ({
2549
+ $schema: "http://json-schema.org/draft-07/schema#",
2550
+ type: "object",
2551
+ properties: {
2552
+ preset: { type: "string", enum: ["bundle", "standalone"] },
2553
+ includeImport: {
2554
+ type: "boolean",
2555
+ description: 'Prepend @import "tailwindcss" to the output'
2556
+ },
2557
+ namespace: {
2558
+ type: "string",
2559
+ description: "Optional Tailwind namespace prefix for @theme"
2560
+ },
2561
+ selector: { type: "string" },
2562
+ mediaQuery: { type: "string" },
2563
+ ...commonRendererOptionsProperties
2564
+ },
2565
+ additionalProperties: true
2566
+ });
2503
2567
  transformPluginSchema = {
2504
2568
  $schema: "http://json-schema.org/draft-07/schema#",
2505
2569
  type: "object",
@@ -2705,7 +2769,7 @@ var init_config_schemas = __esm({
2705
2769
  });
2706
2770
  var SchemaValidator;
2707
2771
  var init_validator = __esm({
2708
- "src/lib/validation/validator.ts"() {
2772
+ "src/validation/validator.ts"() {
2709
2773
  init_errors();
2710
2774
  init_token_utils();
2711
2775
  init_config_schemas();
@@ -2957,63 +3021,18 @@ var init_validator = __esm({
2957
3021
  }
2958
3022
  });
2959
3023
 
2960
- // src/lib/validation/index.ts
3024
+ // src/validation/index.ts
2961
3025
  var init_validation = __esm({
2962
- "src/lib/validation/index.ts"() {
3026
+ "src/validation/index.ts"() {
2963
3027
  init_validator();
2964
3028
  }
2965
3029
  });
2966
-
2967
- // src/shared/utils/validation-handler.ts
2968
- var ValidationHandler;
2969
- var init_validation_handler = __esm({
2970
- "src/shared/utils/validation-handler.ts"() {
2971
- ValidationHandler = class {
2972
- mode;
2973
- constructor(options) {
2974
- this.mode = options?.mode ?? "error";
2975
- }
2976
- /**
2977
- * Whether validation checks should run (mode is not 'off')
2978
- */
2979
- shouldValidate() {
2980
- return this.mode !== "off";
2981
- }
2982
- /**
2983
- * Whether the current mode is 'error' (strictest)
2984
- */
2985
- isStrict() {
2986
- return this.mode === "error";
2987
- }
2988
- /**
2989
- * Handle a validation issue: throw in 'error' mode, warn in 'warn' mode, ignore in 'off' mode
2990
- */
2991
- handleIssue(error) {
2992
- if (this.mode === "error") {
2993
- throw error;
2994
- }
2995
- if (this.mode === "warn") {
2996
- console.warn(error.message);
2997
- }
2998
- }
2999
- /**
3000
- * Emit a warning (in 'error' and 'warn' modes, skip in 'off')
3001
- */
3002
- warn(message) {
3003
- if (this.mode === "off") {
3004
- return;
3005
- }
3006
- console.warn(message);
3007
- }
3008
- };
3009
- }
3010
- });
3011
3030
  var ResolverParser;
3012
3031
  var init_resolver_parser = __esm({
3013
3032
  "src/adapters/filesystem/resolver-parser.ts"() {
3014
- init_validation();
3015
3033
  init_errors();
3016
3034
  init_validation_handler();
3035
+ init_validation();
3017
3036
  ResolverParser = class {
3018
3037
  validator;
3019
3038
  options;
@@ -3401,32 +3420,55 @@ function filterTokensBySource(tokens, expectedSource) {
3401
3420
  }
3402
3421
  return filtered;
3403
3422
  }
3404
- function interpolatePattern(pattern, modifierInputs, modifierName, context) {
3405
- let result = pattern;
3406
- if (modifierName !== void 0) {
3407
- result = result.replace(/\{modifierName\}/g, modifierName);
3423
+ function filterTokensFromSets(tokens) {
3424
+ const filtered = {};
3425
+ for (const [name, token] of Object.entries(tokens)) {
3426
+ const hasModifierSource = typeof token._sourceModifier === "string" && token._sourceModifier !== "";
3427
+ if (!hasModifierSource) {
3428
+ filtered[name] = token;
3429
+ }
3408
3430
  }
3409
- if (context !== void 0) {
3410
- result = result.replace(/\{context\}/g, context);
3431
+ return filtered;
3432
+ }
3433
+ function resolveBaseFileName(fileName, defaults) {
3434
+ if (typeof fileName === "function") {
3435
+ return fileName({ ...defaults, _base: "true" });
3436
+ }
3437
+ if (/\{.+?\}/.test(fileName)) {
3438
+ const baseInputs = Object.fromEntries(Object.keys(defaults).map((k) => [k, "base"]));
3439
+ return collapseBaseSegments(interpolatePattern(fileName, baseInputs));
3440
+ }
3441
+ const extMatch = fileName.match(/(\.[^.]+)$/);
3442
+ const extension = extMatch ? extMatch[1] : "";
3443
+ const baseName = extension ? fileName.slice(0, -extension.length) : fileName;
3444
+ return `${baseName}-base${extension}`;
3445
+ }
3446
+ function collapseBaseSegments(value) {
3447
+ let result = value;
3448
+ let previous = "";
3449
+ while (result !== previous) {
3450
+ previous = result;
3451
+ result = result.replace(/\bbase([/-])base\b/, "base");
3411
3452
  }
3453
+ return result;
3454
+ }
3455
+ function interpolatePattern(pattern, modifierInputs) {
3456
+ let result = pattern;
3412
3457
  for (const [key, value] of Object.entries(modifierInputs)) {
3413
3458
  result = result.replaceAll(`{${key}}`, value);
3414
3459
  }
3415
3460
  return result;
3416
3461
  }
3417
- function resolveFileName(fileName, modifierInputs, modifierName, context) {
3462
+ function resolveFileName(fileName, modifierInputs) {
3418
3463
  if (typeof fileName === "function") {
3419
3464
  return fileName(modifierInputs);
3420
3465
  }
3421
3466
  if (/\{.+?\}/.test(fileName)) {
3422
- return interpolatePattern(fileName, modifierInputs, modifierName, context);
3467
+ return interpolatePattern(fileName, modifierInputs);
3423
3468
  }
3424
3469
  const extMatch = fileName.match(/(\.[^.]+)$/);
3425
3470
  const extension = extMatch ? extMatch[1] : "";
3426
3471
  const baseName = extension ? fileName.slice(0, -extension.length) : fileName;
3427
- if (modifierName !== void 0 && context !== void 0) {
3428
- return `${baseName}-${modifierName}-${context}${extension}`;
3429
- }
3430
3472
  const modifierSuffix = Object.entries(modifierInputs).sort(([keyA], [keyB]) => keyA.localeCompare(keyB)).map(([key, value]) => `${key}-${value}`).join("-");
3431
3473
  if (modifierSuffix) {
3432
3474
  return `${baseName}-${modifierSuffix}${extension}`;
@@ -3595,7 +3637,7 @@ var init_json = __esm({
3595
3637
  }
3596
3638
  });
3597
3639
 
3598
- // src/lib/codegen/type-generator.ts
3640
+ // src/codegen/type-generator.ts
3599
3641
  var TypeGenerator = class {
3600
3642
  /**
3601
3643
  * Generates complete TypeScript type definitions from resolved tokens
@@ -3727,8 +3769,8 @@ var TypeGenerator = class {
3727
3769
  /**
3728
3770
  * Add structure properties to lines
3729
3771
  */
3730
- addStructureProperties(lines, structure, indent) {
3731
- const indentStr = " ".repeat(indent);
3772
+ addStructureProperties(lines, structure, indent2) {
3773
+ const indentStr = " ".repeat(indent2);
3732
3774
  for (const [key, value] of Object.entries(structure)) {
3733
3775
  if (this.isToken(value)) {
3734
3776
  const token = value;
@@ -3739,7 +3781,7 @@ var TypeGenerator = class {
3739
3781
  lines.push(`${indentStr}${this.quoteKey(key)}: ${valueType}`);
3740
3782
  } else {
3741
3783
  lines.push(`${indentStr}${this.quoteKey(key)}: {`);
3742
- this.addStructureProperties(lines, value, indent + 1);
3784
+ this.addStructureProperties(lines, value, indent2 + 1);
3743
3785
  lines.push(`${indentStr}}`);
3744
3786
  }
3745
3787
  }
@@ -4084,7 +4126,7 @@ async function writeOutputFile(fileName, content, encoding = "utf-8") {
4084
4126
  }
4085
4127
  }
4086
4128
 
4087
- // src/lib/processing/token-modifier.ts
4129
+ // src/processing/token-modifier.ts
4088
4130
  function applyTransforms(tokens, transformList) {
4089
4131
  const result = {};
4090
4132
  for (const [name, token] of Object.entries(tokens)) {
@@ -4216,7 +4258,7 @@ init_validation_handler();
4216
4258
  // src/shared/constants.ts
4217
4259
  var DEFAULT_MAX_ALIAS_DEPTH = 10;
4218
4260
 
4219
- // src/lib/resolution/alias-resolver.ts
4261
+ // src/resolution/alias-resolver.ts
4220
4262
  init_errors();
4221
4263
 
4222
4264
  // src/shared/utils/string-similarity.ts
@@ -4267,7 +4309,7 @@ function findSimilar(target, candidates, maxDistance, maxResults = 3) {
4267
4309
  return scored.slice(0, maxResults).map((entry) => entry.value);
4268
4310
  }
4269
4311
 
4270
- // src/lib/resolution/alias-resolver.ts
4312
+ // src/resolution/alias-resolver.ts
4271
4313
  init_token_utils();
4272
4314
  init_validation_handler();
4273
4315
  var AliasResolver = class _AliasResolver {
@@ -4525,7 +4567,7 @@ var AliasResolver = class _AliasResolver {
4525
4567
  }
4526
4568
  };
4527
4569
 
4528
- // src/lib/resolution/reference-resolver.ts
4570
+ // src/resolution/reference-resolver.ts
4529
4571
  init_errors();
4530
4572
  init_validation_handler();
4531
4573
  var ReferenceResolver = class _ReferenceResolver {
@@ -4832,7 +4874,7 @@ var ReferenceResolver = class _ReferenceResolver {
4832
4874
  }
4833
4875
  };
4834
4876
 
4835
- // src/lib/resolution/resolution-engine.ts
4877
+ // src/resolution/resolution-engine.ts
4836
4878
  init_errors();
4837
4879
 
4838
4880
  // src/shared/utils/case-insensitive-map.ts
@@ -4934,10 +4976,10 @@ var CaseInsensitiveMap = class {
4934
4976
  }
4935
4977
  };
4936
4978
 
4937
- // src/lib/resolution/resolution-engine.ts
4979
+ // src/resolution/resolution-engine.ts
4938
4980
  init_validation_handler();
4939
4981
 
4940
- // src/lib/resolution/modifier-input-processor.ts
4982
+ // src/resolution/modifier-input-processor.ts
4941
4983
  init_errors();
4942
4984
  var ModifierInputProcessor = class {
4943
4985
  modifiers;
@@ -5120,7 +5162,7 @@ var ModifierInputProcessor = class {
5120
5162
  }
5121
5163
  };
5122
5164
 
5123
- // src/lib/resolution/resolution-engine.ts
5165
+ // src/resolution/resolution-engine.ts
5124
5166
  var JSON_POINTER_SETS_PREFIX = "#/sets/";
5125
5167
  var JSON_POINTER_MODIFIERS_PREFIX = "#/modifiers/";
5126
5168
  var ResolutionEngine = class {
@@ -5405,7 +5447,6 @@ var ResolutionEngine = class {
5405
5447
  return typeof obj === "object" && obj !== null && "contexts" in obj && typeof obj.contexts === "object";
5406
5448
  }
5407
5449
  };
5408
- init_validator();
5409
5450
  init_errors();
5410
5451
 
5411
5452
  // src/shared/utils/path-utils.ts
@@ -5416,11 +5457,12 @@ function formatTokenPath(parentPath, name) {
5416
5457
  return parentPath.length > 0 ? `${parentPath.join(".")}.${name}` : name;
5417
5458
  }
5418
5459
 
5419
- // src/lib/tokens/token-parser.ts
5460
+ // src/tokens/token-parser.ts
5420
5461
  init_token_utils();
5421
5462
  init_validation_handler();
5463
+ init_validator();
5422
5464
 
5423
- // src/lib/tokens/group-extension-resolver.ts
5465
+ // src/tokens/group-extension-resolver.ts
5424
5466
  init_errors();
5425
5467
  init_token_utils();
5426
5468
  var GroupExtensionResolver = class {
@@ -5582,7 +5624,7 @@ var GroupExtensionResolver = class {
5582
5624
  }
5583
5625
  };
5584
5626
 
5585
- // src/lib/tokens/token-parser.ts
5627
+ // src/tokens/token-parser.ts
5586
5628
  var INVALID_NAME_CHARS_REGEX = /[{}.]/;
5587
5629
  var TokenParser = class {
5588
5630
  validator;
@@ -6095,9 +6137,9 @@ var TokenPipeline = class {
6095
6137
  };
6096
6138
 
6097
6139
  // src/dispersa.ts
6098
- init_validator();
6099
6140
  init_errors();
6100
6141
  init_token_utils();
6142
+ init_validator();
6101
6143
  var Dispersa = class {
6102
6144
  validator;
6103
6145
  pipeline;
@@ -6379,7 +6421,7 @@ var Dispersa = class {
6379
6421
  }
6380
6422
  };
6381
6423
 
6382
- // src/lib/tokens/types.ts
6424
+ // src/tokens/types.ts
6383
6425
  function isColorToken(token) {
6384
6426
  return token.$type === "color";
6385
6427
  }
@@ -6461,7 +6503,7 @@ function colorObjectToHex(color) {
6461
6503
  return culori.formatHex(culoriColor);
6462
6504
  }
6463
6505
 
6464
- // src/lib/processing/processors/transforms/built-in/dimension-converter.ts
6506
+ // src/processing/processors/transforms/built-in/dimension-converter.ts
6465
6507
  function isDimensionObject(value) {
6466
6508
  return typeof value === "object" && value !== null && "value" in value && "unit" in value;
6467
6509
  }
@@ -6469,98 +6511,839 @@ function dimensionObjectToString(dimension) {
6469
6511
  return `${dimension.value}${dimension.unit}`;
6470
6512
  }
6471
6513
 
6472
- // src/renderers/css.ts
6514
+ // src/renderers/android.ts
6473
6515
  init_errors();
6474
6516
  init_token_utils();
6475
-
6476
- // src/renderers/bundlers/css.ts
6477
- init_errors();
6478
6517
  init_utils();
6479
- var getSourceSet = (token) => {
6480
- if (typeof token !== "object" || token === null) {
6481
- return void 0;
6482
- }
6483
- const maybe = token;
6484
- return typeof maybe._sourceSet === "string" ? maybe._sourceSet : void 0;
6518
+ var toSRGB = culori.converter("rgb");
6519
+ var toP3 = culori.converter("p3");
6520
+ var KOTLIN_KEYWORDS = /* @__PURE__ */ new Set([
6521
+ "val",
6522
+ "var",
6523
+ "fun",
6524
+ "class",
6525
+ "object",
6526
+ "when",
6527
+ "is",
6528
+ "in",
6529
+ "return",
6530
+ "break",
6531
+ "continue",
6532
+ "do",
6533
+ "while",
6534
+ "for",
6535
+ "if",
6536
+ "else",
6537
+ "try",
6538
+ "catch",
6539
+ "throw",
6540
+ "as",
6541
+ "this",
6542
+ "super",
6543
+ "null",
6544
+ "true",
6545
+ "false"
6546
+ ]);
6547
+ var KOTLIN_TYPE_GROUP_MAP = {
6548
+ color: "Colors",
6549
+ dimension: "Spacing",
6550
+ fontFamily: "Fonts",
6551
+ fontWeight: "FontWeights",
6552
+ duration: "Durations",
6553
+ shadow: "Shadows",
6554
+ typography: "Typography",
6555
+ number: "Numbers",
6556
+ cubicBezier: "Animations",
6557
+ border: "Borders"
6485
6558
  };
6486
- var getSourceModifier = (token) => {
6487
- if (typeof token !== "object" || token === null) {
6488
- return void 0;
6559
+ function resolveColorFormat(format) {
6560
+ if (format === "argb_floats" || format === "argb_float") {
6561
+ return "argb_float";
6489
6562
  }
6490
- const maybe = token;
6491
- return typeof maybe._sourceModifier === "string" ? maybe._sourceModifier : void 0;
6492
- };
6493
- async function bundleAsCss(bundleData, resolver, options, formatTokens) {
6494
- const baseItem = bundleData.find((item) => item.isBase);
6495
- if (!baseItem) {
6496
- throw new exports.BasePermutationError("Base permutation not found in bundle data");
6563
+ return "argb_hex";
6564
+ }
6565
+ function indent(width, level) {
6566
+ return " ".repeat(width * level);
6567
+ }
6568
+ function escapeKotlinString(str) {
6569
+ return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\$/g, "\\$");
6570
+ }
6571
+ function escapeKDoc(str) {
6572
+ return str.replace(/\*\//g, "* /").replace(/\r?\n/g, " ").trim();
6573
+ }
6574
+ function formatKotlinNumber(value) {
6575
+ return Number.isInteger(value) ? `${value}.0` : String(value);
6576
+ }
6577
+ function roundComponent(value) {
6578
+ return Math.round(value * 1e3) / 1e3;
6579
+ }
6580
+ function toResourceName(family) {
6581
+ return family.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_|_$/g, "");
6582
+ }
6583
+ function toPascalCase(name) {
6584
+ const pascal = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
6585
+ const result = pascal.charAt(0).toUpperCase() + pascal.slice(1);
6586
+ if (/^\d/.test(result)) {
6587
+ return `_${result}`;
6497
6588
  }
6498
- if (!formatTokens) {
6499
- throw new exports.ConfigurationError("CSS formatter was not provided");
6589
+ return KOTLIN_KEYWORDS.has(result.charAt(0).toLowerCase() + result.slice(1)) ? `\`${result}\`` : result;
6590
+ }
6591
+ function toKotlinIdentifier(name) {
6592
+ const camel = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
6593
+ const identifier = camel.charAt(0).toLowerCase() + camel.slice(1);
6594
+ if (/^\d/.test(identifier)) {
6595
+ return `_${identifier}`;
6500
6596
  }
6501
- const orderedBundleData = orderBundleData(bundleData, resolver, baseItem);
6502
- const cssBlocks = [];
6503
- for (const item of orderedBundleData) {
6504
- if (item.isBase) {
6505
- const blocks = await formatBasePermutation(item, resolver, options, formatTokens);
6506
- cssBlocks.push(...blocks);
6507
- continue;
6597
+ return KOTLIN_KEYWORDS.has(identifier) ? `\`${identifier}\`` : identifier;
6598
+ }
6599
+ var AndroidRenderer = class {
6600
+ async format(context, options) {
6601
+ if (!options?.packageName) {
6602
+ throw new exports.ConfigurationError(
6603
+ `Output "${context.output.name}": packageName is required for Android output`
6604
+ );
6508
6605
  }
6509
- const block = await formatModifierPermutation(item, baseItem, options, formatTokens);
6510
- if (block) {
6511
- cssBlocks.push(block);
6606
+ const opts = {
6607
+ preset: options?.preset ?? "standalone",
6608
+ packageName: options.packageName,
6609
+ objectName: options?.objectName ?? "DesignTokens",
6610
+ colorFormat: resolveColorFormat(options?.colorFormat),
6611
+ colorSpace: options?.colorSpace ?? "sRGB",
6612
+ structure: options?.structure ?? "nested",
6613
+ visibility: options?.visibility,
6614
+ indent: options?.indent ?? 4
6615
+ };
6616
+ if (opts.preset === "bundle") {
6617
+ return await this.formatBundle(context, opts);
6512
6618
  }
6619
+ return await this.formatStandalone(context, opts);
6513
6620
  }
6514
- return cssBlocks.join("\n\n");
6515
- }
6516
- async function formatBasePermutation({ tokens, modifierInputs }, resolver, options, formatTokens) {
6517
- const firstModifierName = resolver.modifiers ? Object.keys(resolver.modifiers)[0] : "";
6518
- const modifier = firstModifierName ?? "";
6519
- const context = modifierInputs[modifier] ?? "";
6520
- const selector = resolveSelector(options?.selector, modifier, context, true, modifierInputs);
6521
- const mediaQuery = resolveMediaQuery(options?.mediaQuery, modifier, context, true, modifierInputs);
6522
- const referenceTokens = stripInternalMetadata(tokens);
6523
- const defaultBlocks = buildDefaultLayerBlocks(tokens, modifierInputs, resolver);
6524
- const cssBlocks = [];
6525
- for (const block of defaultBlocks) {
6526
- const cleanTokens = stripInternalMetadata(block.tokens);
6527
- const css2 = await formatTokens(cleanTokens, {
6528
- selector,
6529
- mediaQuery,
6530
- minify: options?.minify,
6531
- referenceTokens
6621
+ // -----------------------------------------------------------------------
6622
+ // Token tree (nested mode)
6623
+ // -----------------------------------------------------------------------
6624
+ buildTokenTree(tokens) {
6625
+ const root = { children: /* @__PURE__ */ new Map() };
6626
+ for (const [, token] of getSortedTokenEntries(tokens)) {
6627
+ let current = root;
6628
+ const segments = token.path;
6629
+ for (let i = 0; i < segments.length - 1; i++) {
6630
+ const seg = segments[i];
6631
+ if (!current.children.has(seg)) {
6632
+ current.children.set(seg, { children: /* @__PURE__ */ new Map() });
6633
+ }
6634
+ current = current.children.get(seg);
6635
+ }
6636
+ const leafName = segments[segments.length - 1] ?? token.name;
6637
+ const leaf = current.children.get(leafName) ?? { children: /* @__PURE__ */ new Map() };
6638
+ leaf.token = token;
6639
+ current.children.set(leafName, leaf);
6640
+ }
6641
+ return root;
6642
+ }
6643
+ // -----------------------------------------------------------------------
6644
+ // Flat structure grouping
6645
+ // -----------------------------------------------------------------------
6646
+ groupTokensByType(tokens) {
6647
+ const groupMap = /* @__PURE__ */ new Map();
6648
+ for (const [, token] of getSortedTokenEntries(tokens)) {
6649
+ const groupName = KOTLIN_TYPE_GROUP_MAP[token.$type ?? ""] ?? "Other";
6650
+ const existing = groupMap.get(groupName) ?? [];
6651
+ existing.push(token);
6652
+ groupMap.set(groupName, existing);
6653
+ }
6654
+ return Array.from(groupMap.entries()).map(([name, groupTokens]) => ({
6655
+ name,
6656
+ tokens: groupTokens
6657
+ }));
6658
+ }
6659
+ /**
6660
+ * Builds a flattened camelCase name from a token's path, stripping the
6661
+ * type prefix segment (which is already represented by the group object).
6662
+ */
6663
+ buildFlatKotlinName(token) {
6664
+ const path7 = token.path;
6665
+ const withoutTypePrefix = path7.length > 1 ? path7.slice(1) : path7;
6666
+ const joined = withoutTypePrefix.join("_");
6667
+ return toKotlinIdentifier(joined);
6668
+ }
6669
+ // -----------------------------------------------------------------------
6670
+ // Rendering
6671
+ // -----------------------------------------------------------------------
6672
+ formatTokens(tokens, options) {
6673
+ if (options.structure === "flat") {
6674
+ return this.formatAsFlat(tokens, options);
6675
+ }
6676
+ return this.formatAsNested(tokens, options);
6677
+ }
6678
+ formatAsNested(tokens, options) {
6679
+ const tree = this.buildTokenTree(tokens);
6680
+ const tokenTypes = /* @__PURE__ */ new Set();
6681
+ this.collectTokenTypes(tree, tokenTypes);
6682
+ return this.buildFile(tokenTypes, options, (lines, vis) => {
6683
+ lines.push(`@Suppress("unused")`);
6684
+ lines.push(`${vis}object ${options.objectName} {`);
6685
+ this.renderTreeChildren(lines, tree, 1, options);
6686
+ lines.push("}");
6532
6687
  });
6533
- const header = block.description ? `/* ${block.key} */
6534
- /* ${block.description} */` : `/* ${block.key} */`;
6535
- cssBlocks.push(`${header}
6536
- ${css2}`);
6537
6688
  }
6538
- return cssBlocks;
6539
- }
6540
- async function formatModifierPermutation({ tokens, modifierInputs }, baseItem, options, formatTokens) {
6541
- const differenceCount = countModifierDifferences(modifierInputs, baseItem.modifierInputs);
6542
- if (differenceCount > 1) {
6543
- return void 0;
6689
+ formatAsFlat(tokens, options) {
6690
+ const groups = this.groupTokensByType(tokens);
6691
+ const tokenTypes = this.collectTokenTypesFromEntries(tokens);
6692
+ return this.buildFile(tokenTypes, options, (lines, vis) => {
6693
+ lines.push(`@Suppress("unused")`);
6694
+ lines.push(`${vis}object ${options.objectName} {`);
6695
+ this.renderFlatGroups(lines, groups, 1, options);
6696
+ lines.push("}");
6697
+ });
6544
6698
  }
6545
- const expectedSource = getExpectedSource(modifierInputs, baseItem.modifierInputs);
6546
- let tokensToInclude = filterTokensBySource(tokens, expectedSource);
6547
- const hasSourceMetadata = Object.values(tokens).some(
6548
- (token) => token != null && getSourceModifier(token) !== void 0
6549
- );
6550
- if (Object.keys(tokensToInclude).length === 0 && !hasSourceMetadata) {
6551
- tokensToInclude = tokens;
6699
+ /**
6700
+ * Shared file preamble: header, package, imports, optional ShadowToken class.
6701
+ * The `renderBody` callback appends the main object(s) to `lines`.
6702
+ */
6703
+ buildFile(tokenTypes, options, renderBody) {
6704
+ const imports = this.collectImports(tokenTypes, options);
6705
+ const vis = options.visibility ? `${options.visibility} ` : "";
6706
+ const lines = [];
6707
+ lines.push(this.buildFileHeader());
6708
+ lines.push("");
6709
+ lines.push(`package ${options.packageName}`);
6710
+ lines.push("");
6711
+ for (const imp of imports) {
6712
+ lines.push(`import ${imp}`);
6713
+ }
6714
+ if (imports.length > 0) {
6715
+ lines.push("");
6716
+ }
6717
+ if (tokenTypes.has("shadow")) {
6718
+ lines.push(...this.buildShadowTokenClass(vis, options));
6719
+ lines.push("");
6720
+ }
6721
+ renderBody(lines, vis);
6722
+ lines.push("");
6723
+ return lines.join("\n");
6552
6724
  }
6553
- if (Object.keys(tokensToInclude).length === 0) {
6554
- return void 0;
6725
+ renderFlatGroups(lines, groups, baseDepth, options) {
6726
+ const vis = options.visibility ? `${options.visibility} ` : "";
6727
+ const groupIndent = indent(options.indent, baseDepth);
6728
+ const valIndent = indent(options.indent, baseDepth + 1);
6729
+ for (const group of groups) {
6730
+ lines.push(`${groupIndent}${vis}object ${group.name} {`);
6731
+ for (const token of group.tokens) {
6732
+ const kotlinName = this.buildFlatKotlinName(token);
6733
+ const kotlinValue = this.formatKotlinValue(token, options, baseDepth + 1);
6734
+ const annotation = this.typeAnnotationSuffix(token);
6735
+ if (token.$description) {
6736
+ lines.push(`${valIndent}/** ${escapeKDoc(token.$description)} */`);
6737
+ }
6738
+ lines.push(`${valIndent}${vis}val ${kotlinName}${annotation} = ${kotlinValue}`);
6739
+ }
6740
+ lines.push(`${groupIndent}}`);
6741
+ lines.push("");
6742
+ }
6555
6743
  }
6556
- const [modifier, context] = parseModifierSource(expectedSource);
6557
- const cleanTokens = stripInternalMetadata(tokensToInclude);
6558
- const referenceTokens = stripInternalMetadata(tokens);
6559
- const selector = resolveSelector(options?.selector, modifier, context, false, modifierInputs);
6560
- const mediaQuery = resolveMediaQuery(
6561
- options?.mediaQuery,
6562
- modifier,
6563
- context,
6744
+ renderTreeChildren(lines, node, depth, options) {
6745
+ const vis = options.visibility ? `${options.visibility} ` : "";
6746
+ const pad = indent(options.indent, depth);
6747
+ const entries = Array.from(node.children.entries());
6748
+ for (let idx = 0; idx < entries.length; idx++) {
6749
+ const [key, child] = entries[idx];
6750
+ if (child.token && child.children.size === 0) {
6751
+ this.renderLeaf(lines, key, child.token, depth, options);
6752
+ } else if (child.children.size > 0 && !child.token) {
6753
+ const objectName = toPascalCase(key);
6754
+ lines.push(`${pad}${vis}object ${objectName} {`);
6755
+ this.renderTreeChildren(lines, child, depth + 1, options);
6756
+ lines.push(`${pad}}`);
6757
+ if (idx < entries.length - 1) {
6758
+ lines.push("");
6759
+ }
6760
+ } else {
6761
+ this.renderLeaf(lines, key, child.token, depth, options);
6762
+ this.renderTreeChildren(lines, child, depth, options);
6763
+ }
6764
+ }
6765
+ }
6766
+ renderLeaf(lines, key, token, depth, options) {
6767
+ const vis = options.visibility ? `${options.visibility} ` : "";
6768
+ const pad = indent(options.indent, depth);
6769
+ const kotlinName = toKotlinIdentifier(key);
6770
+ const kotlinValue = this.formatKotlinValue(token, options, depth);
6771
+ const annotation = this.typeAnnotationSuffix(token);
6772
+ if (token.$description) {
6773
+ lines.push(`${pad}/** ${escapeKDoc(token.$description)} */`);
6774
+ }
6775
+ lines.push(`${pad}${vis}val ${kotlinName}${annotation} = ${kotlinValue}`);
6776
+ }
6777
+ buildFileHeader() {
6778
+ return [
6779
+ "// Generated by Dispersa - do not edit manually",
6780
+ "// https://github.com/timges/dispersa"
6781
+ ].join("\n");
6782
+ }
6783
+ // -----------------------------------------------------------------------
6784
+ // Shadow data class
6785
+ // -----------------------------------------------------------------------
6786
+ buildShadowTokenClass(vis, options) {
6787
+ const i1 = indent(options.indent, 1);
6788
+ return [
6789
+ "@Immutable",
6790
+ `${vis}data class ShadowToken(`,
6791
+ `${i1}val color: Color,`,
6792
+ `${i1}val elevation: Dp,`,
6793
+ `${i1}val offsetX: Dp,`,
6794
+ `${i1}val offsetY: Dp,`,
6795
+ ")"
6796
+ ];
6797
+ }
6798
+ // -----------------------------------------------------------------------
6799
+ // Imports (tree-shaken)
6800
+ // -----------------------------------------------------------------------
6801
+ collectImports(tokenTypes, options) {
6802
+ const imports = /* @__PURE__ */ new Set();
6803
+ const ns = "androidx.compose";
6804
+ const hasColors = tokenTypes.has("color") || tokenTypes.has("shadow") || tokenTypes.has("border");
6805
+ if (hasColors) {
6806
+ imports.add(`${ns}.ui.graphics.Color`);
6807
+ }
6808
+ if (tokenTypes.has("dimension") || tokenTypes.has("shadow") || tokenTypes.has("border")) {
6809
+ imports.add(`${ns}.ui.unit.Dp`);
6810
+ imports.add(`${ns}.ui.unit.dp`);
6811
+ }
6812
+ if (tokenTypes.has("typography") || tokenTypes.has("fontFamily")) {
6813
+ imports.add(`${ns}.ui.text.TextStyle`);
6814
+ imports.add(`${ns}.ui.unit.sp`);
6815
+ }
6816
+ if (tokenTypes.has("typography") || tokenTypes.has("fontWeight")) {
6817
+ imports.add(`${ns}.ui.text.font.FontWeight`);
6818
+ }
6819
+ if (tokenTypes.has("fontFamily")) {
6820
+ imports.add(`${ns}.ui.text.font.FontFamily`);
6821
+ }
6822
+ if (tokenTypes.has("duration")) {
6823
+ imports.add("kotlin.time.Duration");
6824
+ imports.add("kotlin.time.Duration.Companion.milliseconds");
6825
+ imports.add("kotlin.time.Duration.Companion.seconds");
6826
+ }
6827
+ if (tokenTypes.has("cubicBezier")) {
6828
+ imports.add(`${ns}.animation.core.CubicBezierEasing`);
6829
+ }
6830
+ if (tokenTypes.has("shadow")) {
6831
+ imports.add(`${ns}.runtime.Immutable`);
6832
+ }
6833
+ if (tokenTypes.has("border")) {
6834
+ imports.add(`${ns}.foundation.BorderStroke`);
6835
+ }
6836
+ if (options.colorSpace === "displayP3" && hasColors) {
6837
+ imports.add(`${ns}.ui.graphics.colorspace.ColorSpaces`);
6838
+ }
6839
+ return Array.from(imports).sort();
6840
+ }
6841
+ collectTokenTypes(node, types) {
6842
+ if (node.token?.$type) {
6843
+ types.add(node.token.$type);
6844
+ }
6845
+ for (const child of node.children.values()) {
6846
+ this.collectTokenTypes(child, types);
6847
+ }
6848
+ }
6849
+ collectTokenTypesFromEntries(tokens) {
6850
+ const types = /* @__PURE__ */ new Set();
6851
+ for (const [, token] of Object.entries(tokens)) {
6852
+ if (token.$type) {
6853
+ types.add(token.$type);
6854
+ }
6855
+ }
6856
+ return types;
6857
+ }
6858
+ // -----------------------------------------------------------------------
6859
+ // Type annotations
6860
+ // -----------------------------------------------------------------------
6861
+ getTypeAnnotation(token) {
6862
+ switch (token.$type) {
6863
+ case "color":
6864
+ return "Color";
6865
+ case "dimension":
6866
+ return "Dp";
6867
+ case "fontFamily":
6868
+ return "FontFamily";
6869
+ case "fontWeight":
6870
+ return "FontWeight";
6871
+ case "duration":
6872
+ return "Duration";
6873
+ case "shadow":
6874
+ return "ShadowToken";
6875
+ case "cubicBezier":
6876
+ return "CubicBezierEasing";
6877
+ case "number":
6878
+ return "Double";
6879
+ case "typography":
6880
+ return "TextStyle";
6881
+ case "border":
6882
+ return "BorderStroke";
6883
+ default: {
6884
+ const value = token.$value;
6885
+ if (typeof value === "string") {
6886
+ return "String";
6887
+ }
6888
+ if (typeof value === "boolean") {
6889
+ return "Boolean";
6890
+ }
6891
+ if (typeof value === "number") {
6892
+ return "Double";
6893
+ }
6894
+ return void 0;
6895
+ }
6896
+ }
6897
+ }
6898
+ typeAnnotationSuffix(token) {
6899
+ const type = this.getTypeAnnotation(token);
6900
+ return type ? `: ${type}` : "";
6901
+ }
6902
+ // -----------------------------------------------------------------------
6903
+ // Value formatting
6904
+ // -----------------------------------------------------------------------
6905
+ formatKotlinValue(token, options, depth) {
6906
+ const value = token.$value;
6907
+ if (token.$type === "color") {
6908
+ return this.formatColorValue(value, options);
6909
+ }
6910
+ if (token.$type === "dimension") {
6911
+ return this.formatDimensionValue(value);
6912
+ }
6913
+ if (token.$type === "fontFamily") {
6914
+ return this.formatFontFamilyValue(value);
6915
+ }
6916
+ if (token.$type === "fontWeight") {
6917
+ return this.formatFontWeightValue(value);
6918
+ }
6919
+ if (token.$type === "duration") {
6920
+ return this.formatDurationValue(value);
6921
+ }
6922
+ if (token.$type === "shadow") {
6923
+ return this.formatShadowValue(value, options, depth);
6924
+ }
6925
+ if (token.$type === "typography") {
6926
+ return this.formatTypographyValue(value, options, depth);
6927
+ }
6928
+ if (token.$type === "border") {
6929
+ return this.formatBorderValue(value, options);
6930
+ }
6931
+ if (token.$type === "number") {
6932
+ return typeof value === "number" ? formatKotlinNumber(value) : String(value);
6933
+ }
6934
+ if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
6935
+ return `CubicBezierEasing(${value[0]}f, ${value[1]}f, ${value[2]}f, ${value[3]}f)`;
6936
+ }
6937
+ if (typeof value === "string") {
6938
+ return `"${escapeKotlinString(value)}"`;
6939
+ }
6940
+ if (typeof value === "number") {
6941
+ return formatKotlinNumber(value);
6942
+ }
6943
+ if (typeof value === "boolean") {
6944
+ return value ? "true" : "false";
6945
+ }
6946
+ return `"${escapeKotlinString(String(value))}"`;
6947
+ }
6948
+ formatColorValue(value, options) {
6949
+ if (!isColorObject(value)) {
6950
+ if (typeof value === "string") {
6951
+ const hex = value.replace("#", "");
6952
+ if (/^[0-9a-fA-F]{6,8}$/.test(hex)) {
6953
+ const argb = hex.length === 8 ? hex : `FF${hex}`;
6954
+ return `Color(0x${argb.toUpperCase()})`;
6955
+ }
6956
+ }
6957
+ return "Color.Unspecified";
6958
+ }
6959
+ const colorObj = value;
6960
+ const alpha = colorObj.alpha ?? 1;
6961
+ if (options.colorFormat === "argb_float" || options.colorSpace === "displayP3") {
6962
+ return this.formatFloatColor(colorObj, alpha, options);
6963
+ }
6964
+ return this.formatHexColor(colorObj, alpha);
6965
+ }
6966
+ formatFloatColor(colorObj, alpha, options) {
6967
+ if (options.colorSpace === "displayP3") {
6968
+ const p3 = toP3(dtcgObjectToCulori(colorObj));
6969
+ const r2 = roundComponent(p3?.r ?? 0);
6970
+ const g2 = roundComponent(p3?.g ?? 0);
6971
+ const b2 = roundComponent(p3?.b ?? 0);
6972
+ return `Color(${r2}f, ${g2}f, ${b2}f, ${roundComponent(alpha)}f, ColorSpaces.DisplayP3)`;
6973
+ }
6974
+ const rgb = toSRGB(dtcgObjectToCulori(colorObj));
6975
+ const r = roundComponent(rgb?.r ?? 0);
6976
+ const g = roundComponent(rgb?.g ?? 0);
6977
+ const b = roundComponent(rgb?.b ?? 0);
6978
+ return `Color(${r}f, ${g}f, ${b}f, ${roundComponent(alpha)}f)`;
6979
+ }
6980
+ formatHexColor(colorObj, alpha) {
6981
+ const hex = colorObjectToHex(colorObj);
6982
+ const hexClean = hex.replace("#", "");
6983
+ if (hexClean.length === 8) {
6984
+ const rrggbb = hexClean.slice(0, 6);
6985
+ const aa = hexClean.slice(6, 8);
6986
+ return `Color(0x${aa.toUpperCase()}${rrggbb.toUpperCase()})`;
6987
+ }
6988
+ const alphaHex = alpha < 1 ? Math.round(alpha * 255).toString(16).padStart(2, "0").toUpperCase() : "FF";
6989
+ return `Color(0x${alphaHex}${hexClean.toUpperCase()})`;
6990
+ }
6991
+ formatDimensionValue(value) {
6992
+ if (isDimensionObject(value)) {
6993
+ const dim = value;
6994
+ const dpValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
6995
+ return `${dpValue}.dp`;
6996
+ }
6997
+ return typeof value === "number" ? `${value}.dp` : `0.dp`;
6998
+ }
6999
+ formatFontFamilyValue(value) {
7000
+ if (Array.isArray(value)) {
7001
+ const primary = value[0];
7002
+ if (typeof primary === "string") {
7003
+ return this.mapKotlinFontFamily(primary);
7004
+ }
7005
+ return "FontFamily.Default";
7006
+ }
7007
+ return typeof value === "string" ? this.mapKotlinFontFamily(value) : "FontFamily.Default";
7008
+ }
7009
+ mapKotlinFontFamily(family) {
7010
+ const normalized = family.toLowerCase().replace(/['"]/g, "").trim();
7011
+ const builtIn = {
7012
+ "sans-serif": "FontFamily.SansSerif",
7013
+ serif: "FontFamily.Serif",
7014
+ monospace: "FontFamily.Monospace",
7015
+ cursive: "FontFamily.Cursive"
7016
+ };
7017
+ return builtIn[normalized] ?? `FontFamily.Default // TODO: load "${family}" via Font(R.font.${toResourceName(family)})`;
7018
+ }
7019
+ formatFontWeightValue(value) {
7020
+ if (typeof value === "number") {
7021
+ return this.numericFontWeight(value);
7022
+ }
7023
+ if (typeof value === "string") {
7024
+ return this.namedFontWeight(value) ?? "FontWeight.Normal";
7025
+ }
7026
+ return "FontWeight.Normal";
7027
+ }
7028
+ numericFontWeight(weight) {
7029
+ if (weight <= 100) {
7030
+ return "FontWeight.Thin";
7031
+ }
7032
+ if (weight <= 200) {
7033
+ return "FontWeight.ExtraLight";
7034
+ }
7035
+ if (weight <= 300) {
7036
+ return "FontWeight.Light";
7037
+ }
7038
+ if (weight <= 400) {
7039
+ return "FontWeight.Normal";
7040
+ }
7041
+ if (weight <= 500) {
7042
+ return "FontWeight.Medium";
7043
+ }
7044
+ if (weight <= 600) {
7045
+ return "FontWeight.SemiBold";
7046
+ }
7047
+ if (weight <= 700) {
7048
+ return "FontWeight.Bold";
7049
+ }
7050
+ if (weight <= 800) {
7051
+ return "FontWeight.ExtraBold";
7052
+ }
7053
+ return "FontWeight.Black";
7054
+ }
7055
+ namedFontWeight(name) {
7056
+ const map = {
7057
+ thin: "FontWeight.Thin",
7058
+ extralight: "FontWeight.ExtraLight",
7059
+ ultralight: "FontWeight.ExtraLight",
7060
+ light: "FontWeight.Light",
7061
+ regular: "FontWeight.Normal",
7062
+ normal: "FontWeight.Normal",
7063
+ medium: "FontWeight.Medium",
7064
+ semibold: "FontWeight.SemiBold",
7065
+ demibold: "FontWeight.SemiBold",
7066
+ bold: "FontWeight.Bold",
7067
+ extrabold: "FontWeight.ExtraBold",
7068
+ heavy: "FontWeight.ExtraBold",
7069
+ black: "FontWeight.Black",
7070
+ ultrabold: "FontWeight.Black"
7071
+ };
7072
+ return map[name.toLowerCase()];
7073
+ }
7074
+ formatDurationValue(value) {
7075
+ if (typeof value === "object" && value !== null && "value" in value && "unit" in value) {
7076
+ const dur = value;
7077
+ return dur.unit === "ms" ? `${dur.value}.milliseconds` : `${dur.value}.seconds`;
7078
+ }
7079
+ return typeof value === "number" ? `${value}.milliseconds` : "0.milliseconds";
7080
+ }
7081
+ formatShadowValue(value, options, depth) {
7082
+ if (Array.isArray(value) && value.length > 0) {
7083
+ return this.formatSingleShadow(value[0], options, depth);
7084
+ }
7085
+ if (typeof value === "object" && value !== null) {
7086
+ return this.formatSingleShadow(value, options, depth);
7087
+ }
7088
+ return "ShadowToken(color = Color.Unspecified, elevation = 0.dp, offsetX = 0.dp, offsetY = 0.dp)";
7089
+ }
7090
+ formatSingleShadow(shadow, options, depth) {
7091
+ const color = isColorObject(shadow.color) ? this.formatColorValue(shadow.color, options) : "Color.Black";
7092
+ const elevation = isDimensionObject(shadow.blur) ? this.formatDimensionValue(shadow.blur) : "0.dp";
7093
+ const offsetX = isDimensionObject(shadow.offsetX) ? this.formatDimensionValue(shadow.offsetX) : "0.dp";
7094
+ const offsetY = isDimensionObject(shadow.offsetY) ? this.formatDimensionValue(shadow.offsetY) : "0.dp";
7095
+ const propIndent = indent(options.indent, depth + 1);
7096
+ const closeIndent = indent(options.indent, depth);
7097
+ return [
7098
+ "ShadowToken(",
7099
+ `${propIndent}color = ${color},`,
7100
+ `${propIndent}elevation = ${elevation},`,
7101
+ `${propIndent}offsetX = ${offsetX},`,
7102
+ `${propIndent}offsetY = ${offsetY},`,
7103
+ `${closeIndent})`
7104
+ ].join("\n");
7105
+ }
7106
+ formatBorderValue(value, options) {
7107
+ if (typeof value !== "object" || value === null) {
7108
+ return "BorderStroke(0.dp, Color.Unspecified)";
7109
+ }
7110
+ const border = value;
7111
+ const width = isDimensionObject(border.width) ? this.formatDimensionValue(border.width) : "0.dp";
7112
+ const color = isColorObject(border.color) ? this.formatColorValue(border.color, options) : "Color.Unspecified";
7113
+ return `BorderStroke(${width}, ${color})`;
7114
+ }
7115
+ formatTypographyValue(value, options, depth) {
7116
+ if (typeof value !== "object" || value === null) {
7117
+ return "TextStyle()";
7118
+ }
7119
+ const typo = value;
7120
+ const parts = [];
7121
+ if (isDimensionObject(typo.fontSize)) {
7122
+ const dim = typo.fontSize;
7123
+ const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
7124
+ parts.push(`fontSize = ${spValue}.sp`);
7125
+ }
7126
+ if (typo.fontWeight != null) {
7127
+ parts.push(`fontWeight = ${this.formatFontWeightValue(typo.fontWeight)}`);
7128
+ }
7129
+ if (typo.lineHeight != null && typeof typo.lineHeight === "number") {
7130
+ if (isDimensionObject(typo.fontSize)) {
7131
+ const dim = typo.fontSize;
7132
+ const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
7133
+ const lineHeightSp = Math.round(spValue * typo.lineHeight * 100) / 100;
7134
+ parts.push(`lineHeight = ${lineHeightSp}.sp`);
7135
+ }
7136
+ }
7137
+ if (isDimensionObject(typo.letterSpacing)) {
7138
+ const dim = typo.letterSpacing;
7139
+ const spValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
7140
+ parts.push(`letterSpacing = ${spValue}.sp`);
7141
+ }
7142
+ if (parts.length === 0) {
7143
+ return "TextStyle()";
7144
+ }
7145
+ const propIndent = indent(options.indent, depth + 1);
7146
+ const closeIndent = indent(options.indent, depth);
7147
+ return `TextStyle(
7148
+ ${parts.map((p) => `${propIndent}${p}`).join(",\n")},
7149
+ ${closeIndent})`;
7150
+ }
7151
+ // -----------------------------------------------------------------------
7152
+ // Output: standalone
7153
+ // -----------------------------------------------------------------------
7154
+ async formatStandalone(context, options) {
7155
+ const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
7156
+ if (!context.output.file && requiresFile) {
7157
+ throw new exports.ConfigurationError(
7158
+ `Output "${context.output.name}": file is required for standalone Android output`
7159
+ );
7160
+ }
7161
+ const files = {};
7162
+ for (const { tokens, modifierInputs } of context.permutations) {
7163
+ const processedTokens = stripInternalMetadata(tokens);
7164
+ const content = this.formatTokens(processedTokens, options);
7165
+ const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
7166
+ outputName: context.output.name,
7167
+ extension: "kt",
7168
+ modifierInputs,
7169
+ resolver: context.resolver,
7170
+ defaults: context.meta.defaults
7171
+ });
7172
+ files[fileName] = content;
7173
+ }
7174
+ return outputTree(files);
7175
+ }
7176
+ // -----------------------------------------------------------------------
7177
+ // Output: bundle
7178
+ // -----------------------------------------------------------------------
7179
+ async formatBundle(context, options) {
7180
+ const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
7181
+ if (!context.output.file && requiresFile) {
7182
+ throw new exports.ConfigurationError(
7183
+ `Output "${context.output.name}": file is required for bundle Android output`
7184
+ );
7185
+ }
7186
+ const content = this.formatBundleContent(context, options);
7187
+ const fileName = context.output.file ? resolveFileName(context.output.file, context.meta.basePermutation) : buildInMemoryOutputKey({
7188
+ outputName: context.output.name,
7189
+ extension: "kt",
7190
+ modifierInputs: context.meta.basePermutation,
7191
+ resolver: context.resolver,
7192
+ defaults: context.meta.defaults
7193
+ });
7194
+ return outputTree({ [fileName]: content });
7195
+ }
7196
+ formatBundleContent(context, options) {
7197
+ const allTokenTypes = this.collectAllPermutationTypes(context);
7198
+ return this.buildFile(allTokenTypes, options, (lines, vis) => {
7199
+ const i1 = indent(options.indent, 1);
7200
+ lines.push(`@Suppress("unused")`);
7201
+ lines.push(`${vis}object ${options.objectName} {`);
7202
+ for (let idx = 0; idx < context.permutations.length; idx++) {
7203
+ const { tokens, modifierInputs } = context.permutations[idx];
7204
+ const processedTokens = stripInternalMetadata(tokens);
7205
+ const permName = this.buildPermutationName(modifierInputs);
7206
+ lines.push(`${i1}${vis}object ${permName} {`);
7207
+ this.renderBundleTokens(lines, processedTokens, options, 2);
7208
+ lines.push(`${i1}}`);
7209
+ if (idx < context.permutations.length - 1) {
7210
+ lines.push("");
7211
+ }
7212
+ }
7213
+ lines.push("}");
7214
+ });
7215
+ }
7216
+ collectAllPermutationTypes(context) {
7217
+ const allTokenTypes = /* @__PURE__ */ new Set();
7218
+ for (const { tokens } of context.permutations) {
7219
+ const processed = stripInternalMetadata(tokens);
7220
+ for (const [, token] of Object.entries(processed)) {
7221
+ if (token.$type) {
7222
+ allTokenTypes.add(token.$type);
7223
+ }
7224
+ }
7225
+ }
7226
+ return allTokenTypes;
7227
+ }
7228
+ renderBundleTokens(lines, tokens, options, baseDepth) {
7229
+ if (options.structure === "flat") {
7230
+ const groups = this.groupTokensByType(tokens);
7231
+ this.renderFlatGroups(lines, groups, baseDepth, options);
7232
+ return;
7233
+ }
7234
+ const tree = this.buildTokenTree(tokens);
7235
+ this.renderTreeChildren(lines, tree, baseDepth, options);
7236
+ }
7237
+ buildPermutationName(modifierInputs) {
7238
+ const values = Object.values(modifierInputs);
7239
+ if (values.length === 0) {
7240
+ return "Default";
7241
+ }
7242
+ return values.map((v) => toPascalCase(v)).join("");
7243
+ }
7244
+ };
7245
+ function androidRenderer() {
7246
+ const rendererInstance = new AndroidRenderer();
7247
+ return {
7248
+ format: (context, options) => rendererInstance.format(
7249
+ context,
7250
+ options ?? context.output.options
7251
+ )
7252
+ };
7253
+ }
7254
+
7255
+ // src/renderers/css.ts
7256
+ init_errors();
7257
+ init_token_utils();
7258
+
7259
+ // src/renderers/bundlers/css.ts
7260
+ init_errors();
7261
+ init_utils();
7262
+ var getSourceSet = (token) => {
7263
+ if (typeof token !== "object" || token === null) {
7264
+ return void 0;
7265
+ }
7266
+ const maybe = token;
7267
+ return typeof maybe._sourceSet === "string" ? maybe._sourceSet : void 0;
7268
+ };
7269
+ var getSourceModifier = (token) => {
7270
+ if (typeof token !== "object" || token === null) {
7271
+ return void 0;
7272
+ }
7273
+ const maybe = token;
7274
+ return typeof maybe._sourceModifier === "string" ? maybe._sourceModifier : void 0;
7275
+ };
7276
+ async function bundleAsCss(bundleData, resolver, options, formatTokens) {
7277
+ const baseItem = bundleData.find((item) => item.isBase);
7278
+ if (!baseItem) {
7279
+ throw new exports.BasePermutationError("Base permutation not found in bundle data");
7280
+ }
7281
+ if (!formatTokens) {
7282
+ throw new exports.ConfigurationError("CSS formatter was not provided");
7283
+ }
7284
+ const orderedBundleData = orderBundleData(bundleData, resolver, baseItem);
7285
+ const cssBlocks = [];
7286
+ for (const item of orderedBundleData) {
7287
+ if (item.isBase) {
7288
+ const blocks = await formatBasePermutation(item, resolver, options, formatTokens);
7289
+ cssBlocks.push(...blocks);
7290
+ continue;
7291
+ }
7292
+ const block = await formatModifierPermutation(item, baseItem, options, formatTokens);
7293
+ if (block) {
7294
+ cssBlocks.push(block);
7295
+ }
7296
+ }
7297
+ return cssBlocks.join("\n\n");
7298
+ }
7299
+ async function formatBasePermutation({ tokens, modifierInputs }, resolver, options, formatTokens) {
7300
+ const firstModifierName = resolver.modifiers ? Object.keys(resolver.modifiers)[0] : "";
7301
+ const modifier = firstModifierName ?? "";
7302
+ const context = modifierInputs[modifier] ?? "";
7303
+ const selector = resolveSelector(options?.selector, modifier, context, true, modifierInputs);
7304
+ const mediaQuery = resolveMediaQuery(options?.mediaQuery, modifier, context, true, modifierInputs);
7305
+ const referenceTokens = stripInternalMetadata(tokens);
7306
+ const defaultBlocks = buildDefaultLayerBlocks(tokens, modifierInputs, resolver);
7307
+ const cssBlocks = [];
7308
+ for (const block of defaultBlocks) {
7309
+ const cleanTokens = stripInternalMetadata(block.tokens);
7310
+ const css2 = await formatTokens(cleanTokens, {
7311
+ selector,
7312
+ mediaQuery,
7313
+ minify: options?.minify,
7314
+ referenceTokens
7315
+ });
7316
+ const header = block.description ? `/* ${block.key} */
7317
+ /* ${block.description} */` : `/* ${block.key} */`;
7318
+ cssBlocks.push(`${header}
7319
+ ${css2}`);
7320
+ }
7321
+ return cssBlocks;
7322
+ }
7323
+ async function formatModifierPermutation({ tokens, modifierInputs }, baseItem, options, formatTokens) {
7324
+ const differenceCount = countModifierDifferences(modifierInputs, baseItem.modifierInputs);
7325
+ if (differenceCount > 1) {
7326
+ return void 0;
7327
+ }
7328
+ const expectedSource = getExpectedSource(modifierInputs, baseItem.modifierInputs);
7329
+ let tokensToInclude = filterTokensBySource(tokens, expectedSource);
7330
+ const hasSourceMetadata = Object.values(tokens).some(
7331
+ (token) => token != null && getSourceModifier(token) !== void 0
7332
+ );
7333
+ if (Object.keys(tokensToInclude).length === 0 && !hasSourceMetadata) {
7334
+ tokensToInclude = tokens;
7335
+ }
7336
+ if (Object.keys(tokensToInclude).length === 0) {
7337
+ return void 0;
7338
+ }
7339
+ const [modifier, context] = parseModifierSource(expectedSource);
7340
+ const cleanTokens = stripInternalMetadata(tokensToInclude);
7341
+ const referenceTokens = stripInternalMetadata(tokens);
7342
+ const selector = resolveSelector(options?.selector, modifier, context, false, modifierInputs);
7343
+ const mediaQuery = resolveMediaQuery(
7344
+ options?.mediaQuery,
7345
+ modifier,
7346
+ context,
6564
7347
  false,
6565
7348
  modifierInputs
6566
7349
  );
@@ -6600,6 +7383,33 @@ function collectRemainder(tokens, included) {
6600
7383
  }
6601
7384
  return result;
6602
7385
  }
7386
+ function buildSetLayerBlocks(tokens, resolver) {
7387
+ const blocks = [];
7388
+ const included = /* @__PURE__ */ new Set();
7389
+ const addBlock = (key, blockTokens, description) => {
7390
+ if (Object.keys(blockTokens).length === 0) {
7391
+ return;
7392
+ }
7393
+ for (const k of Object.keys(blockTokens)) {
7394
+ included.add(k);
7395
+ }
7396
+ blocks.push({ key, description, tokens: blockTokens });
7397
+ };
7398
+ for (const item of resolver.resolutionOrder) {
7399
+ const ref = item.$ref;
7400
+ if (typeof ref !== "string" || !ref.startsWith("#/sets/")) {
7401
+ continue;
7402
+ }
7403
+ const setName = ref.slice("#/sets/".length);
7404
+ addBlock(
7405
+ `Set: ${setName}`,
7406
+ collectSetTokens(tokens, setName, included),
7407
+ resolver.sets?.[setName]?.description
7408
+ );
7409
+ }
7410
+ addBlock("Unattributed", collectRemainder(tokens, included));
7411
+ return blocks;
7412
+ }
6603
7413
  function buildDefaultLayerBlocks(tokens, baseModifierInputs, resolver) {
6604
7414
  const blocks = [];
6605
7415
  const included = /* @__PURE__ */ new Set();
@@ -6795,14 +7605,14 @@ var CssRenderer = class _CssRenderer {
6795
7605
  return opts.minify ? cssString : await this.formatWithPrettier(cssString);
6796
7606
  }
6797
7607
  buildCssBlock(lines, groupTokens, selector, tokens, referenceTokens, opts) {
6798
- const indent = opts.minify ? "" : " ";
7608
+ const indent2 = opts.minify ? "" : " ";
6799
7609
  const newline = opts.minify ? "" : "\n";
6800
7610
  const space = opts.minify ? "" : " ";
6801
7611
  const hasMediaQuery = opts.mediaQuery != null && opts.mediaQuery !== "";
6802
- const tokenIndent = hasMediaQuery ? indent + indent : indent;
7612
+ const tokenIndent = hasMediaQuery ? indent2 + indent2 : indent2;
6803
7613
  if (hasMediaQuery) {
6804
7614
  lines.push(`@media ${opts.mediaQuery}${space}{${newline}`);
6805
- lines.push(`${indent}${selector}${space}{${newline}`);
7615
+ lines.push(`${indent2}${selector}${space}{${newline}`);
6806
7616
  } else {
6807
7617
  lines.push(`${selector}${space}{${newline}`);
6808
7618
  }
@@ -6819,21 +7629,21 @@ var CssRenderer = class _CssRenderer {
6819
7629
  );
6820
7630
  }
6821
7631
  if (hasMediaQuery) {
6822
- lines.push(`${indent}}${newline}`);
7632
+ lines.push(`${indent2}}${newline}`);
6823
7633
  }
6824
7634
  lines.push(`}${newline}${newline}`);
6825
7635
  }
6826
- pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences, indent, newline, space) {
7636
+ pushTokenLines(lines, token, tokens, referenceTokens, preserveReferences, indent2, newline, space) {
6827
7637
  const entries = this.buildCssEntries(token, tokens, referenceTokens, preserveReferences);
6828
7638
  if (token.$deprecated != null && token.$deprecated !== false) {
6829
7639
  const deprecationMsg = formatDeprecationMessage(token, "", "comment");
6830
- lines.push(`${indent}/* ${this.sanitizeCssCommentText(deprecationMsg)} */${newline}`);
7640
+ lines.push(`${indent2}/* ${this.sanitizeCssCommentText(deprecationMsg)} */${newline}`);
6831
7641
  }
6832
7642
  if (token.$description && token.$description !== "") {
6833
- lines.push(`${indent}/* ${this.sanitizeCssCommentText(token.$description)} */${newline}`);
7643
+ lines.push(`${indent2}/* ${this.sanitizeCssCommentText(token.$description)} */${newline}`);
6834
7644
  }
6835
7645
  for (const entry of entries) {
6836
- lines.push(`${indent}--${entry.name}:${space}${entry.value};${newline}`);
7646
+ lines.push(`${indent2}--${entry.name}:${space}${entry.value};${newline}`);
6837
7647
  }
6838
7648
  }
6839
7649
  async formatWithPrettier(css2) {
@@ -7320,6 +8130,10 @@ var CssRenderer = class _CssRenderer {
7320
8130
  throw new exports.ConfigurationError("Modifier preset requires modifiers to be defined in resolver");
7321
8131
  }
7322
8132
  const files = {};
8133
+ const baseResult = await this.buildModifierBaseFile(context, options);
8134
+ if (baseResult) {
8135
+ files[baseResult.fileName] = baseResult.content;
8136
+ }
7323
8137
  for (const [modifierName, modifierDef] of Object.entries(context.resolver.modifiers)) {
7324
8138
  for (const contextValue of Object.keys(modifierDef.contexts)) {
7325
8139
  const result = await this.buildModifierContextFile(
@@ -7335,6 +8149,59 @@ var CssRenderer = class _CssRenderer {
7335
8149
  }
7336
8150
  return { kind: "outputTree", files };
7337
8151
  }
8152
+ async buildModifierBaseFile(context, options) {
8153
+ const basePermutation = context.permutations.find(
8154
+ ({ modifierInputs }) => this.isBasePermutation(modifierInputs, context.meta.defaults)
8155
+ );
8156
+ if (!basePermutation) {
8157
+ return void 0;
8158
+ }
8159
+ const setTokens = filterTokensFromSets(basePermutation.tokens);
8160
+ if (Object.keys(setTokens).length === 0) {
8161
+ return void 0;
8162
+ }
8163
+ const setBlocks = buildSetLayerBlocks(setTokens, context.resolver);
8164
+ if (setBlocks.length === 0) {
8165
+ return void 0;
8166
+ }
8167
+ const modifiers = context.resolver.modifiers;
8168
+ const firstModifierName = Object.keys(modifiers)[0] ?? "";
8169
+ const firstModifierContext = context.meta.defaults[firstModifierName] ?? "";
8170
+ const baseModifierInputs = { ...context.meta.defaults };
8171
+ const selector = resolveSelector(
8172
+ options.selector,
8173
+ firstModifierName,
8174
+ firstModifierContext,
8175
+ true,
8176
+ baseModifierInputs
8177
+ );
8178
+ const mediaQuery = resolveMediaQuery(
8179
+ options.mediaQuery,
8180
+ firstModifierName,
8181
+ firstModifierContext,
8182
+ true,
8183
+ baseModifierInputs
8184
+ );
8185
+ const referenceTokens = basePermutation.tokens;
8186
+ const cssBlocks = [];
8187
+ for (const block of setBlocks) {
8188
+ const cleanTokens = stripInternalMetadata(block.tokens);
8189
+ const css2 = await this.formatTokens(cleanTokens, {
8190
+ selector,
8191
+ mediaQuery,
8192
+ minify: options.minify ?? false,
8193
+ preserveReferences: options.preserveReferences ?? false,
8194
+ referenceTokens
8195
+ });
8196
+ const header = block.description ? `/* ${block.key} */
8197
+ /* ${block.description} */` : `/* ${block.key} */`;
8198
+ cssBlocks.push(`${header}
8199
+ ${css2}`);
8200
+ }
8201
+ const content = cssBlocks.join("\n");
8202
+ const fileName = context.output.file ? resolveBaseFileName(context.output.file, context.meta.defaults) : `${context.output.name}-base.css`;
8203
+ return { fileName, content };
8204
+ }
7338
8205
  collectTokensForModifierContext(modifierName, contextValue, permutations) {
7339
8206
  const expectedSource = `${modifierName}-${contextValue}`;
7340
8207
  let tokensFromSource = {};
@@ -7381,7 +8248,7 @@ var CssRenderer = class _CssRenderer {
7381
8248
  preserveReferences: options.preserveReferences ?? false,
7382
8249
  referenceTokens
7383
8250
  });
7384
- const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs, modifierName, contextValue) : buildInMemoryOutputKey({
8251
+ const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
7385
8252
  outputName: context.output.name,
7386
8253
  extension: "css",
7387
8254
  modifierInputs,
@@ -7408,18 +8275,641 @@ var CssRenderer = class _CssRenderer {
7408
8275
  return { modifierName: name, modifierContext: value };
7409
8276
  }
7410
8277
  }
7411
- return { modifierName: "", modifierContext: "" };
7412
- }
7413
- isBasePermutation(modifierInputs, defaults) {
7414
- const normalizedInputs = normalizeModifierInputs(modifierInputs);
7415
- const normalizedDefaults = normalizeModifierInputs(defaults);
7416
- return Object.entries(normalizedDefaults).every(
7417
- ([key, value]) => normalizedInputs[key] === value
7418
- );
8278
+ return { modifierName: "", modifierContext: "" };
8279
+ }
8280
+ isBasePermutation(modifierInputs, defaults) {
8281
+ const normalizedInputs = normalizeModifierInputs(modifierInputs);
8282
+ const normalizedDefaults = normalizeModifierInputs(defaults);
8283
+ return Object.entries(normalizedDefaults).every(
8284
+ ([key, value]) => normalizedInputs[key] === value
8285
+ );
8286
+ }
8287
+ };
8288
+ function cssRenderer() {
8289
+ const rendererInstance = new CssRenderer();
8290
+ return {
8291
+ format: (context, options) => rendererInstance.format(
8292
+ context,
8293
+ options ?? context.output.options
8294
+ )
8295
+ };
8296
+ }
8297
+
8298
+ // src/renderers/ios.ts
8299
+ init_errors();
8300
+ init_token_utils();
8301
+ init_utils();
8302
+ var toSRGB2 = culori.converter("rgb");
8303
+ var toP32 = culori.converter("p3");
8304
+ var SWIFT_TYPE_GROUP_MAP = {
8305
+ color: "Colors",
8306
+ dimension: "Spacing",
8307
+ fontFamily: "Fonts",
8308
+ fontWeight: "FontWeights",
8309
+ duration: "Durations",
8310
+ shadow: "Shadows",
8311
+ typography: "Typography",
8312
+ number: "Numbers",
8313
+ cubicBezier: "Animations",
8314
+ border: "Borders",
8315
+ gradient: "Gradients"
8316
+ };
8317
+ var SWIFT_KEYWORDS = /* @__PURE__ */ new Set([
8318
+ "associatedtype",
8319
+ "class",
8320
+ "deinit",
8321
+ "enum",
8322
+ "extension",
8323
+ "fileprivate",
8324
+ "func",
8325
+ "import",
8326
+ "init",
8327
+ "inout",
8328
+ "internal",
8329
+ "let",
8330
+ "open",
8331
+ "operator",
8332
+ "private",
8333
+ "protocol",
8334
+ "public",
8335
+ "rethrows",
8336
+ "static",
8337
+ "struct",
8338
+ "subscript",
8339
+ "typealias",
8340
+ "var",
8341
+ "break",
8342
+ "case",
8343
+ "continue",
8344
+ "default",
8345
+ "defer",
8346
+ "do",
8347
+ "else",
8348
+ "fallthrough",
8349
+ "for",
8350
+ "guard",
8351
+ "if",
8352
+ "in",
8353
+ "repeat",
8354
+ "return",
8355
+ "switch",
8356
+ "where",
8357
+ "while",
8358
+ "as",
8359
+ "catch",
8360
+ "false",
8361
+ "is",
8362
+ "nil",
8363
+ "super",
8364
+ "self",
8365
+ "Self",
8366
+ "throw",
8367
+ "throws",
8368
+ "true",
8369
+ "try",
8370
+ "Type",
8371
+ "Protocol"
8372
+ ]);
8373
+ var IosRenderer = class {
8374
+ async format(context, options) {
8375
+ const opts = {
8376
+ preset: options?.preset ?? "standalone",
8377
+ accessLevel: options?.accessLevel ?? "public",
8378
+ structure: options?.structure ?? "enum",
8379
+ enumName: options?.enumName ?? "DesignTokens",
8380
+ extensionNamespace: options?.extensionNamespace ?? "DesignTokens",
8381
+ colorSpace: options?.colorSpace ?? "sRGB",
8382
+ swiftVersion: options?.swiftVersion ?? "5.9",
8383
+ indent: options?.indent ?? 4,
8384
+ frozen: options?.frozen ?? false
8385
+ };
8386
+ return await this.formatStandalone(context, opts);
8387
+ }
8388
+ formatTokens(tokens, options) {
8389
+ if (options.structure === "grouped") {
8390
+ return this.formatAsGrouped(tokens, options);
8391
+ }
8392
+ return this.formatAsEnum(tokens, options);
8393
+ }
8394
+ formatAsEnum(tokens, options) {
8395
+ const access3 = options.accessLevel;
8396
+ const groups = this.groupTokensByType(tokens);
8397
+ const imports = this.collectImports(tokens);
8398
+ const i1 = this.indentStr(options.indent, 1);
8399
+ const i2 = this.indentStr(options.indent, 2);
8400
+ const staticPrefix = this.staticLetPrefix(options);
8401
+ const frozen = this.frozenPrefix(options);
8402
+ const lines = [];
8403
+ lines.push(this.buildFileHeader());
8404
+ lines.push("");
8405
+ for (const imp of imports) {
8406
+ lines.push(`import ${imp}`);
8407
+ }
8408
+ lines.push(...this.buildStructDefinitions(tokens, access3, options));
8409
+ lines.push("");
8410
+ lines.push(`${frozen}${access3} enum ${options.enumName} {`);
8411
+ for (const group of groups) {
8412
+ lines.push(`${i1}${frozen}${access3} enum ${group.name} {`);
8413
+ for (const token of group.tokens) {
8414
+ const swiftName = this.buildQualifiedSwiftName(token);
8415
+ const swiftValue = this.formatSwiftValue(token, options);
8416
+ const typeAnnotation = this.getTypeAnnotation(token);
8417
+ const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
8418
+ const docComment = this.buildDocComment(token, i2);
8419
+ if (docComment) {
8420
+ lines.push(docComment);
8421
+ }
8422
+ lines.push(`${i2}${access3} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
8423
+ }
8424
+ lines.push(`${i1}}`);
8425
+ lines.push("");
8426
+ }
8427
+ lines.push("}");
8428
+ lines.push(...this.buildViewExtensions(tokens, access3, options));
8429
+ lines.push("");
8430
+ return lines.join("\n");
8431
+ }
8432
+ formatAsGrouped(tokens, options) {
8433
+ const access3 = options.accessLevel;
8434
+ const namespace = options.extensionNamespace;
8435
+ const groups = this.groupTokensByType(tokens);
8436
+ const imports = this.collectImports(tokens);
8437
+ const i1 = this.indentStr(options.indent, 1);
8438
+ const i2 = this.indentStr(options.indent, 2);
8439
+ const staticPrefix = this.staticLetPrefix(options);
8440
+ const frozen = this.frozenPrefix(options);
8441
+ const lines = [];
8442
+ lines.push(this.buildFileHeader());
8443
+ lines.push("");
8444
+ for (const imp of imports) {
8445
+ lines.push(`import ${imp}`);
8446
+ }
8447
+ lines.push(...this.buildStructDefinitions(tokens, access3, options));
8448
+ lines.push("");
8449
+ lines.push(`${frozen}${access3} enum ${namespace} {}`);
8450
+ lines.push("");
8451
+ for (const group of groups) {
8452
+ lines.push(`${access3} extension ${namespace} {`);
8453
+ lines.push(`${i1}${frozen}enum ${group.name} {`);
8454
+ for (const token of group.tokens) {
8455
+ const swiftName = this.buildQualifiedSwiftName(token);
8456
+ const swiftValue = this.formatSwiftValue(token, options);
8457
+ const typeAnnotation = this.getTypeAnnotation(token);
8458
+ const annotation = typeAnnotation ? `: ${typeAnnotation}` : "";
8459
+ const docComment = this.buildDocComment(token, i2);
8460
+ if (docComment) {
8461
+ lines.push(docComment);
8462
+ }
8463
+ lines.push(`${i2}${access3} ${staticPrefix}${swiftName}${annotation} = ${swiftValue}`);
8464
+ }
8465
+ lines.push(`${i1}}`);
8466
+ lines.push("}");
8467
+ lines.push("");
8468
+ }
8469
+ lines.push(...this.buildViewExtensions(tokens, access3, options));
8470
+ return lines.join("\n");
8471
+ }
8472
+ buildFileHeader() {
8473
+ return [
8474
+ "// Generated by Dispersa - do not edit manually",
8475
+ "// https://github.com/timges/dispersa"
8476
+ ].join("\n");
8477
+ }
8478
+ collectImports(tokens) {
8479
+ const imports = /* @__PURE__ */ new Set();
8480
+ imports.add("SwiftUI");
8481
+ for (const [, token] of Object.entries(tokens)) {
8482
+ if (token.$type === "duration") {
8483
+ imports.add("Foundation");
8484
+ }
8485
+ }
8486
+ return Array.from(imports).sort();
8487
+ }
8488
+ /**
8489
+ * Builds a `///` doc comment from a token's `$description`, if present.
8490
+ */
8491
+ buildDocComment(token, indent2) {
8492
+ if (!token.$description) {
8493
+ return void 0;
8494
+ }
8495
+ return `${indent2}/// ${token.$description}`;
8496
+ }
8497
+ groupTokensByType(tokens) {
8498
+ const groupMap = /* @__PURE__ */ new Map();
8499
+ for (const [, token] of getSortedTokenEntries(tokens)) {
8500
+ const groupName = SWIFT_TYPE_GROUP_MAP[token.$type ?? ""] ?? "Other";
8501
+ const existing = groupMap.get(groupName) ?? [];
8502
+ existing.push(token);
8503
+ groupMap.set(groupName, existing);
8504
+ }
8505
+ return Array.from(groupMap.entries()).map(([name, groupTokens]) => ({
8506
+ name,
8507
+ tokens: groupTokens
8508
+ }));
8509
+ }
8510
+ /**
8511
+ * Builds a qualified Swift name from a token's path, preserving parent
8512
+ * hierarchy segments to avoid duplicate identifiers.
8513
+ *
8514
+ * For example, `color.blue.400` in the `Colors` group becomes `blue400`
8515
+ * instead of just `_400`.
8516
+ */
8517
+ buildQualifiedSwiftName(token) {
8518
+ const path7 = token.path;
8519
+ const withoutTypePrefix = path7.length > 1 ? path7.slice(1) : path7;
8520
+ const joined = withoutTypePrefix.join("_");
8521
+ return this.toSwiftIdentifier(joined);
8522
+ }
8523
+ formatSwiftValue(token, options) {
8524
+ const value = token.$value;
8525
+ if (token.$type === "color") {
8526
+ return this.formatColorValue(value, options);
8527
+ }
8528
+ if (token.$type === "dimension") {
8529
+ return this.formatDimensionValue(value);
8530
+ }
8531
+ if (token.$type === "fontFamily") {
8532
+ return this.formatFontFamilyValue(value);
8533
+ }
8534
+ if (token.$type === "fontWeight") {
8535
+ return this.formatFontWeightValue(value);
8536
+ }
8537
+ if (token.$type === "duration") {
8538
+ return this.formatDurationValue(value);
8539
+ }
8540
+ if (token.$type === "shadow") {
8541
+ return this.formatShadowValue(value, options);
8542
+ }
8543
+ if (token.$type === "typography") {
8544
+ return this.formatTypographyValue(value);
8545
+ }
8546
+ if (token.$type === "border") {
8547
+ return this.formatBorderValue(value, options);
8548
+ }
8549
+ if (token.$type === "gradient") {
8550
+ return this.formatGradientValue(value, options);
8551
+ }
8552
+ if (token.$type === "number") {
8553
+ return String(value);
8554
+ }
8555
+ if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
8556
+ return `UnitCurve.bezier(startControlPoint: UnitPoint(x: ${value[0]}, y: ${value[1]}), endControlPoint: UnitPoint(x: ${value[2]}, y: ${value[3]}))`;
8557
+ }
8558
+ if (typeof value === "string") {
8559
+ return `"${this.escapeSwiftString(value)}"`;
8560
+ }
8561
+ if (typeof value === "number") {
8562
+ return String(value);
8563
+ }
8564
+ if (typeof value === "boolean") {
8565
+ return value ? "true" : "false";
8566
+ }
8567
+ return `"${this.escapeSwiftString(String(value))}"`;
8568
+ }
8569
+ formatColorValue(value, options) {
8570
+ if (!isColorObject(value)) {
8571
+ return typeof value === "string" ? `Color("${this.escapeSwiftString(value)}")` : "Color.clear";
8572
+ }
8573
+ const colorObj = value;
8574
+ const alpha = colorObj.alpha ?? 1;
8575
+ if (options.colorSpace === "displayP3") {
8576
+ const p3 = toP32(dtcgObjectToCulori(colorObj));
8577
+ const r2 = this.roundComponent(p3?.r ?? 0);
8578
+ const g2 = this.roundComponent(p3?.g ?? 0);
8579
+ const b2 = this.roundComponent(p3?.b ?? 0);
8580
+ return alpha < 1 ? `Color(.displayP3, red: ${r2}, green: ${g2}, blue: ${b2}, opacity: ${this.roundComponent(alpha)})` : `Color(.displayP3, red: ${r2}, green: ${g2}, blue: ${b2})`;
8581
+ }
8582
+ const rgb = toSRGB2(dtcgObjectToCulori(colorObj));
8583
+ const r = this.roundComponent(rgb?.r ?? 0);
8584
+ const g = this.roundComponent(rgb?.g ?? 0);
8585
+ const b = this.roundComponent(rgb?.b ?? 0);
8586
+ return alpha < 1 ? `Color(red: ${r}, green: ${g}, blue: ${b}, opacity: ${this.roundComponent(alpha)})` : `Color(red: ${r}, green: ${g}, blue: ${b})`;
8587
+ }
8588
+ formatDimensionValue(value) {
8589
+ if (isDimensionObject(value)) {
8590
+ const dim = value;
8591
+ const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
8592
+ return String(ptValue);
8593
+ }
8594
+ return String(value);
8595
+ }
8596
+ formatFontFamilyValue(value) {
8597
+ if (Array.isArray(value)) {
8598
+ const primary = value[0];
8599
+ return typeof primary === "string" ? `"${this.escapeSwiftString(primary)}"` : '"system"';
8600
+ }
8601
+ return typeof value === "string" ? `"${this.escapeSwiftString(value)}"` : '"system"';
8602
+ }
8603
+ formatFontWeightValue(value) {
8604
+ if (typeof value === "number") {
8605
+ return this.numericFontWeight(value);
8606
+ }
8607
+ if (typeof value === "string") {
8608
+ return this.namedFontWeight(value) ?? "Font.Weight.regular";
8609
+ }
8610
+ return "Font.Weight.regular";
8611
+ }
8612
+ numericFontWeight(weight) {
8613
+ if (weight <= 100) {
8614
+ return "Font.Weight.ultraLight";
8615
+ }
8616
+ if (weight <= 200) {
8617
+ return "Font.Weight.thin";
8618
+ }
8619
+ if (weight <= 300) {
8620
+ return "Font.Weight.light";
8621
+ }
8622
+ if (weight <= 400) {
8623
+ return "Font.Weight.regular";
8624
+ }
8625
+ if (weight <= 500) {
8626
+ return "Font.Weight.medium";
8627
+ }
8628
+ if (weight <= 600) {
8629
+ return "Font.Weight.semibold";
8630
+ }
8631
+ if (weight <= 700) {
8632
+ return "Font.Weight.bold";
8633
+ }
8634
+ if (weight <= 800) {
8635
+ return "Font.Weight.heavy";
8636
+ }
8637
+ return "Font.Weight.black";
8638
+ }
8639
+ namedFontWeight(name) {
8640
+ const map = {
8641
+ thin: "Font.Weight.thin",
8642
+ ultralight: "Font.Weight.ultraLight",
8643
+ extralight: "Font.Weight.ultraLight",
8644
+ light: "Font.Weight.light",
8645
+ regular: "Font.Weight.regular",
8646
+ normal: "Font.Weight.regular",
8647
+ medium: "Font.Weight.medium",
8648
+ semibold: "Font.Weight.semibold",
8649
+ demibold: "Font.Weight.semibold",
8650
+ bold: "Font.Weight.bold",
8651
+ heavy: "Font.Weight.heavy",
8652
+ extrabold: "Font.Weight.heavy",
8653
+ black: "Font.Weight.black",
8654
+ ultrabold: "Font.Weight.black"
8655
+ };
8656
+ return map[name.toLowerCase()];
8657
+ }
8658
+ formatDurationValue(value) {
8659
+ if (typeof value === "object" && value !== null && "value" in value && "unit" in value) {
8660
+ const dur = value;
8661
+ const seconds = dur.unit === "ms" ? dur.value / 1e3 : dur.value;
8662
+ return String(seconds);
8663
+ }
8664
+ return typeof value === "number" ? String(value) : "0";
8665
+ }
8666
+ formatShadowValue(value, options) {
8667
+ if (Array.isArray(value) && value.length > 0) {
8668
+ return this.formatSingleShadow(value[0], options);
8669
+ }
8670
+ if (typeof value === "object" && value !== null) {
8671
+ return this.formatSingleShadow(value, options);
8672
+ }
8673
+ return "ShadowStyle(color: .clear, radius: 0, x: 0, y: 0, spread: 0)";
8674
+ }
8675
+ formatSingleShadow(shadow, options) {
8676
+ const color = isColorObject(shadow.color) ? this.formatColorValue(shadow.color, options) : "Color.black.opacity(0.25)";
8677
+ const radius = isDimensionObject(shadow.blur) ? this.dimensionToCGFloat(shadow.blur) : "8";
8678
+ const x = isDimensionObject(shadow.offsetX) ? this.dimensionToCGFloat(shadow.offsetX) : "0";
8679
+ const y = isDimensionObject(shadow.offsetY) ? this.dimensionToCGFloat(shadow.offsetY) : "0";
8680
+ const spread = isDimensionObject(shadow.spread) ? this.dimensionToCGFloat(shadow.spread) : "0";
8681
+ return `ShadowStyle(color: ${color}, radius: ${radius}, x: ${x}, y: ${y}, spread: ${spread})`;
8682
+ }
8683
+ formatTypographyValue(value) {
8684
+ if (typeof value !== "object" || value === null) {
8685
+ return "TypographyStyle(font: Font.body, tracking: 0, lineSpacing: 0)";
8686
+ }
8687
+ const typo = value;
8688
+ const size = isDimensionObject(typo.fontSize) ? this.dimensionToPoints(typo.fontSize) : "16";
8689
+ const weight = typo.fontWeight != null ? this.formatFontWeightValue(typo.fontWeight) : "Font.Weight.regular";
8690
+ const fontExpr = this.buildFontExpression(typo, size, weight);
8691
+ const tracking = this.extractTracking(typo);
8692
+ const lineSpacing = this.extractLineSpacing(typo);
8693
+ return `TypographyStyle(font: ${fontExpr}, tracking: ${tracking}, lineSpacing: ${lineSpacing})`;
8694
+ }
8695
+ buildFontExpression(typo, size, weight) {
8696
+ if (typo.fontFamily != null) {
8697
+ const family = Array.isArray(typo.fontFamily) ? typo.fontFamily[0] : typo.fontFamily;
8698
+ if (typeof family === "string") {
8699
+ return `Font.custom("${this.escapeSwiftString(family)}", size: ${size}).weight(${weight})`;
8700
+ }
8701
+ }
8702
+ return `Font.system(size: ${size}, weight: ${weight})`;
8703
+ }
8704
+ extractTracking(typo) {
8705
+ if (!isDimensionObject(typo.letterSpacing)) {
8706
+ return "0";
8707
+ }
8708
+ const dim = typo.letterSpacing;
8709
+ const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
8710
+ return String(ptValue);
8711
+ }
8712
+ extractLineSpacing(typo) {
8713
+ if (typo.lineHeight == null || typeof typo.lineHeight !== "number") {
8714
+ return "0";
8715
+ }
8716
+ if (!isDimensionObject(typo.fontSize)) {
8717
+ return "0";
8718
+ }
8719
+ const dim = typo.fontSize;
8720
+ const basePt = dim.unit === "rem" ? dim.value * 16 : dim.value;
8721
+ const lineHeightPt = Math.round(basePt * typo.lineHeight * 100) / 100;
8722
+ return String(lineHeightPt - basePt);
8723
+ }
8724
+ dimensionToPoints(dim) {
8725
+ const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
8726
+ return String(ptValue);
8727
+ }
8728
+ /** Formats a dimension as a CGFloat literal (appends `.0` for integers). */
8729
+ dimensionToCGFloat(dim) {
8730
+ const ptValue = dim.unit === "rem" ? dim.value * 16 : dim.value;
8731
+ return Number.isInteger(ptValue) ? `${ptValue}.0` : String(ptValue);
8732
+ }
8733
+ getTypeAnnotation(token) {
8734
+ switch (token.$type) {
8735
+ case "dimension":
8736
+ return "CGFloat";
8737
+ case "duration":
8738
+ return "TimeInterval";
8739
+ case "number":
8740
+ return "Double";
8741
+ case "fontWeight":
8742
+ return "Font.Weight";
8743
+ case "fontFamily":
8744
+ return "String";
8745
+ default:
8746
+ return void 0;
8747
+ }
8748
+ }
8749
+ toSwiftIdentifier(name) {
8750
+ const camel = name.replace(/[-._]+(.)/g, (_, c) => c.toUpperCase()).replace(/[-._]+$/g, "").replace(/^[-._]+/g, "");
8751
+ const identifier = camel.charAt(0).toLowerCase() + camel.slice(1);
8752
+ const safe = /^\d/.test(identifier) ? `_${identifier}` : identifier;
8753
+ return SWIFT_KEYWORDS.has(safe) ? `\`${safe}\`` : safe;
8754
+ }
8755
+ escapeSwiftString(str) {
8756
+ return str.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n");
8757
+ }
8758
+ roundComponent(value) {
8759
+ return Math.round(value * 1e4) / 1e4;
8760
+ }
8761
+ indentStr(width, level) {
8762
+ return " ".repeat(width * level);
8763
+ }
8764
+ /**
8765
+ * Returns the prefix for `static let` declarations.
8766
+ * Swift 6 requires `nonisolated(unsafe)` on global stored properties.
8767
+ */
8768
+ staticLetPrefix(options) {
8769
+ return options.swiftVersion === "6.0" ? "nonisolated(unsafe) static let " : "static let ";
8770
+ }
8771
+ /** Returns `@frozen ` when the frozen option is enabled, empty string otherwise. */
8772
+ frozenPrefix(options) {
8773
+ return options.frozen ? "@frozen " : "";
8774
+ }
8775
+ /** Returns `: Sendable` when targeting Swift 6, empty string otherwise. */
8776
+ structConformances(options) {
8777
+ return options.swiftVersion === "6.0" ? ": Sendable" : "";
8778
+ }
8779
+ hasShadowTokens(tokens) {
8780
+ return Object.values(tokens).some((t) => t.$type === "shadow");
8781
+ }
8782
+ hasTypographyTokens(tokens) {
8783
+ return Object.values(tokens).some((t) => t.$type === "typography");
8784
+ }
8785
+ hasBorderTokens(tokens) {
8786
+ return Object.values(tokens).some((t) => t.$type === "border");
8787
+ }
8788
+ /** Emits all struct definitions needed by the token set. */
8789
+ buildStructDefinitions(tokens, access3, options) {
8790
+ const lines = [];
8791
+ if (this.hasShadowTokens(tokens)) {
8792
+ lines.push("");
8793
+ lines.push(...this.buildShadowStyleStruct(access3, options));
8794
+ }
8795
+ if (this.hasTypographyTokens(tokens)) {
8796
+ lines.push("");
8797
+ lines.push(...this.buildTypographyStyleStruct(access3, options));
8798
+ }
8799
+ if (this.hasBorderTokens(tokens)) {
8800
+ lines.push("");
8801
+ lines.push(...this.buildBorderStyleStruct(access3, options));
8802
+ }
8803
+ return lines;
8804
+ }
8805
+ buildShadowStyleStruct(access3, options) {
8806
+ const i1 = this.indentStr(options.indent, 1);
8807
+ const conformances = this.structConformances(options);
8808
+ const frozen = this.frozenPrefix(options);
8809
+ return [
8810
+ `${frozen}${access3} struct ShadowStyle${conformances} {`,
8811
+ `${i1}${access3} let color: Color`,
8812
+ `${i1}${access3} let radius: CGFloat`,
8813
+ `${i1}${access3} let x: CGFloat`,
8814
+ `${i1}${access3} let y: CGFloat`,
8815
+ `${i1}${access3} let spread: CGFloat`,
8816
+ "}"
8817
+ ];
8818
+ }
8819
+ buildTypographyStyleStruct(access3, options) {
8820
+ const i1 = this.indentStr(options.indent, 1);
8821
+ const conformances = this.structConformances(options);
8822
+ const frozen = this.frozenPrefix(options);
8823
+ return [
8824
+ `${frozen}${access3} struct TypographyStyle${conformances} {`,
8825
+ `${i1}${access3} let font: Font`,
8826
+ `${i1}${access3} let tracking: CGFloat`,
8827
+ `${i1}${access3} let lineSpacing: CGFloat`,
8828
+ "}"
8829
+ ];
8830
+ }
8831
+ buildBorderStyleStruct(access3, options) {
8832
+ const i1 = this.indentStr(options.indent, 1);
8833
+ const conformances = this.structConformances(options);
8834
+ const frozen = this.frozenPrefix(options);
8835
+ return [
8836
+ `${frozen}${access3} struct BorderStyle${conformances} {`,
8837
+ `${i1}${access3} let color: Color`,
8838
+ `${i1}${access3} let width: CGFloat`,
8839
+ "}"
8840
+ ];
8841
+ }
8842
+ /** Emits convenience View extensions for shadow and typography application. */
8843
+ buildViewExtensions(tokens, access3, options) {
8844
+ const lines = [];
8845
+ const i1 = this.indentStr(options.indent, 1);
8846
+ const i2 = this.indentStr(options.indent, 2);
8847
+ if (this.hasShadowTokens(tokens)) {
8848
+ lines.push("");
8849
+ lines.push(`${access3} extension View {`);
8850
+ lines.push(`${i1}func shadowStyle(_ style: ShadowStyle) -> some View {`);
8851
+ lines.push(
8852
+ `${i2}self.shadow(color: style.color, radius: style.radius, x: style.x, y: style.y)`
8853
+ );
8854
+ lines.push(`${i1}}`);
8855
+ lines.push("}");
8856
+ }
8857
+ if (this.hasTypographyTokens(tokens)) {
8858
+ lines.push("");
8859
+ lines.push(`${access3} extension View {`);
8860
+ lines.push(`${i1}func typographyStyle(_ style: TypographyStyle) -> some View {`);
8861
+ lines.push(
8862
+ `${i2}self.font(style.font).tracking(style.tracking).lineSpacing(style.lineSpacing)`
8863
+ );
8864
+ lines.push(`${i1}}`);
8865
+ lines.push("}");
8866
+ }
8867
+ return lines;
8868
+ }
8869
+ formatBorderValue(value, options) {
8870
+ if (typeof value !== "object" || value === null) {
8871
+ return "BorderStyle(color: .clear, width: 0)";
8872
+ }
8873
+ const border = value;
8874
+ const color = isColorObject(border.color) ? this.formatColorValue(border.color, options) : "Color.clear";
8875
+ const width = isDimensionObject(border.width) ? this.dimensionToCGFloat(border.width) : "1.0";
8876
+ return `BorderStyle(color: ${color}, width: ${width})`;
8877
+ }
8878
+ formatGradientValue(value, options) {
8879
+ if (!Array.isArray(value) || value.length === 0) {
8880
+ return "Gradient(stops: [])";
8881
+ }
8882
+ const stops = value.map((stop) => {
8883
+ const color = isColorObject(stop.color) ? this.formatColorValue(stop.color, options) : "Color.clear";
8884
+ return `.init(color: ${color}, location: ${stop.position})`;
8885
+ });
8886
+ return `Gradient(stops: [${stops.join(", ")}])`;
8887
+ }
8888
+ async formatStandalone(context, options) {
8889
+ const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
8890
+ if (!context.output.file && requiresFile) {
8891
+ throw new exports.ConfigurationError(
8892
+ `Output "${context.output.name}": file is required for standalone iOS output`
8893
+ );
8894
+ }
8895
+ const files = {};
8896
+ for (const { tokens, modifierInputs } of context.permutations) {
8897
+ const processedTokens = stripInternalMetadata(tokens);
8898
+ const content = this.formatTokens(processedTokens, options);
8899
+ const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
8900
+ outputName: context.output.name,
8901
+ extension: "swift",
8902
+ modifierInputs,
8903
+ resolver: context.resolver,
8904
+ defaults: context.meta.defaults
8905
+ });
8906
+ files[fileName] = content;
8907
+ }
8908
+ return outputTree(files);
7419
8909
  }
7420
8910
  };
7421
- function cssRenderer() {
7422
- const rendererInstance = new CssRenderer();
8911
+ function iosRenderer() {
8912
+ const rendererInstance = new IosRenderer();
7423
8913
  return {
7424
8914
  format: (context, options) => rendererInstance.format(
7425
8915
  context,
@@ -7545,8 +9035,8 @@ var JsModuleRenderer = class {
7545
9035
  /**
7546
9036
  * Add object properties to lines
7547
9037
  */
7548
- addObjectProperties(lines, obj, indent) {
7549
- const indentStr = " ".repeat(indent);
9038
+ addObjectProperties(lines, obj, indent2) {
9039
+ const indentStr = " ".repeat(indent2);
7550
9040
  const entries = Object.entries(obj).sort(([keyA], [keyB]) => keyA.localeCompare(keyB));
7551
9041
  for (let i = 0; i < entries.length; i++) {
7552
9042
  const entry = entries[i];
@@ -7557,7 +9047,7 @@ var JsModuleRenderer = class {
7557
9047
  const isLast = i === entries.length - 1;
7558
9048
  if (typeof value === "object" && value !== null && !Array.isArray(value)) {
7559
9049
  lines.push(`${indentStr}${this.quoteKey(key)}: {`);
7560
- this.addObjectProperties(lines, value, indent + 1);
9050
+ this.addObjectProperties(lines, value, indent2 + 1);
7561
9051
  lines.push(`${indentStr}}${isLast ? "" : ","}`);
7562
9052
  } else {
7563
9053
  const valueStr = JSON.stringify(value);
@@ -7749,6 +9239,349 @@ function jsonRenderer() {
7749
9239
  };
7750
9240
  }
7751
9241
 
9242
+ // src/renderers/tailwind.ts
9243
+ init_errors();
9244
+ init_token_utils();
9245
+
9246
+ // src/renderers/bundlers/tailwind.ts
9247
+ init_errors();
9248
+ init_utils();
9249
+ async function bundleAsTailwind(bundleData, options, formatThemeTokens, formatOverrideBlock) {
9250
+ const baseItem = bundleData.find((item) => item.isBase);
9251
+ if (!baseItem) {
9252
+ throw new exports.BasePermutationError("Base permutation not found in bundle data");
9253
+ }
9254
+ const resolvedOpts = resolveOptions(options);
9255
+ const cssBlocks = [];
9256
+ const variantDeclarations = collectVariantDeclarations(bundleData, baseItem, resolvedOpts);
9257
+ const themeOpts = { ...resolvedOpts, variantDeclarations };
9258
+ const baseTokens = stripInternalMetadata(baseItem.tokens);
9259
+ const themeBlock = await formatThemeTokens(baseTokens, themeOpts);
9260
+ cssBlocks.push(themeBlock);
9261
+ for (const item of bundleData) {
9262
+ if (item.isBase) {
9263
+ continue;
9264
+ }
9265
+ const block = await formatModifierOverride(item, baseItem, resolvedOpts, formatOverrideBlock);
9266
+ if (block) {
9267
+ cssBlocks.push(block);
9268
+ }
9269
+ }
9270
+ return cssBlocks.join("\n");
9271
+ }
9272
+ async function formatModifierOverride({ tokens, modifierInputs }, baseItem, options, formatOverrideBlock) {
9273
+ const differenceCount = countModifierDifferences(modifierInputs, baseItem.modifierInputs);
9274
+ if (differenceCount > 1) {
9275
+ return void 0;
9276
+ }
9277
+ const tokensToInclude = filterTokensByValueChange(tokens, baseItem.tokens);
9278
+ if (Object.keys(tokensToInclude).length === 0) {
9279
+ return void 0;
9280
+ }
9281
+ const expectedSource = getExpectedSource(modifierInputs, baseItem.modifierInputs);
9282
+ const [modifier, context] = parseModifierSource(expectedSource);
9283
+ const cleanTokens = stripInternalMetadata(tokensToInclude);
9284
+ const selector = resolveSelector(
9285
+ options.selector,
9286
+ modifier,
9287
+ context,
9288
+ false,
9289
+ normalizeModifierInputs(modifierInputs)
9290
+ );
9291
+ const mediaQuery = resolveMediaQuery(
9292
+ options.mediaQuery,
9293
+ modifier,
9294
+ context,
9295
+ false,
9296
+ normalizeModifierInputs(modifierInputs)
9297
+ );
9298
+ const css2 = await formatOverrideBlock(cleanTokens, selector, mediaQuery, options.minify);
9299
+ return `/* Modifier: ${modifier}=${context} */
9300
+ ${css2}`;
9301
+ }
9302
+ function filterTokensByValueChange(currentTokens, baseTokens) {
9303
+ const changed = {};
9304
+ for (const [name, token] of Object.entries(currentTokens)) {
9305
+ const baseToken = baseTokens[name];
9306
+ if (!baseToken) {
9307
+ changed[name] = token;
9308
+ continue;
9309
+ }
9310
+ if (JSON.stringify(token.$value) !== JSON.stringify(baseToken.$value)) {
9311
+ changed[name] = token;
9312
+ }
9313
+ }
9314
+ return changed;
9315
+ }
9316
+ function collectVariantDeclarations(bundleData, baseItem, options) {
9317
+ const declarations = [];
9318
+ for (const item of bundleData) {
9319
+ if (item.isBase) {
9320
+ continue;
9321
+ }
9322
+ const differenceCount = countModifierDifferences(item.modifierInputs, baseItem.modifierInputs);
9323
+ if (differenceCount > 1) {
9324
+ continue;
9325
+ }
9326
+ const expectedSource = getExpectedSource(item.modifierInputs, baseItem.modifierInputs);
9327
+ const [modifier, context] = parseModifierSource(expectedSource);
9328
+ const variantName = `${modifier}-${context}`;
9329
+ const normalized = normalizeModifierInputs(item.modifierInputs);
9330
+ const mediaQuery = resolveMediaQuery(options.mediaQuery, modifier, context, false, normalized);
9331
+ if (mediaQuery !== "") {
9332
+ declarations.push(`@custom-variant ${variantName} (@media ${mediaQuery});`);
9333
+ continue;
9334
+ }
9335
+ const selector = resolveSelector(options.selector, modifier, context, false, normalized);
9336
+ declarations.push(`@custom-variant ${variantName} (&:where(${selector}, ${selector} *));`);
9337
+ }
9338
+ return declarations;
9339
+ }
9340
+ function resolveOptions(options) {
9341
+ return {
9342
+ preset: options.preset ?? "bundle",
9343
+ includeImport: options.includeImport ?? true,
9344
+ namespace: options.namespace ?? "",
9345
+ minify: options.minify ?? false,
9346
+ selector: options.selector,
9347
+ mediaQuery: options.mediaQuery,
9348
+ variantDeclarations: []
9349
+ };
9350
+ }
9351
+
9352
+ // src/renderers/tailwind.ts
9353
+ init_utils();
9354
+ var TAILWIND_NAMESPACE_MAP = {
9355
+ color: "color",
9356
+ dimension: "spacing",
9357
+ fontFamily: "font",
9358
+ fontWeight: "font-weight",
9359
+ duration: "duration",
9360
+ shadow: "shadow",
9361
+ number: "number",
9362
+ cubicBezier: "ease"
9363
+ };
9364
+ var TailwindRenderer = class {
9365
+ async format(context, options) {
9366
+ const opts = {
9367
+ preset: options?.preset ?? "bundle",
9368
+ includeImport: options?.includeImport ?? true,
9369
+ namespace: options?.namespace ?? "",
9370
+ minify: options?.minify ?? false,
9371
+ selector: options?.selector,
9372
+ mediaQuery: options?.mediaQuery,
9373
+ variantDeclarations: []
9374
+ };
9375
+ if (opts.preset === "bundle") {
9376
+ return await this.formatBundle(context, opts);
9377
+ }
9378
+ return await this.formatStandalone(context, opts);
9379
+ }
9380
+ /**
9381
+ * Format tokens as Tailwind v4 @theme CSS variables
9382
+ */
9383
+ async formatTokens(tokens, options) {
9384
+ const lines = [];
9385
+ const indent2 = options.minify ? "" : " ";
9386
+ const newline = options.minify ? "" : "\n";
9387
+ const space = options.minify ? "" : " ";
9388
+ if (options.includeImport) {
9389
+ lines.push(`@import "tailwindcss";${newline}`);
9390
+ }
9391
+ if (options.variantDeclarations.length > 0) {
9392
+ if (options.includeImport) {
9393
+ lines.push(newline);
9394
+ }
9395
+ for (const declaration of options.variantDeclarations) {
9396
+ lines.push(`${declaration}${newline}`);
9397
+ }
9398
+ }
9399
+ if (options.includeImport || options.variantDeclarations.length > 0) {
9400
+ lines.push(newline);
9401
+ }
9402
+ const themeDirective = options.namespace ? `@theme namespace(${options.namespace})` : "@theme";
9403
+ lines.push(`${themeDirective}${space}{${newline}`);
9404
+ for (const [, token] of getSortedTokenEntries(tokens)) {
9405
+ const varName = this.buildVariableName(token);
9406
+ const varValue = this.formatValue(token);
9407
+ lines.push(`${indent2}--${varName}:${space}${varValue};${newline}`);
9408
+ }
9409
+ lines.push(`}${newline}`);
9410
+ const cssString = lines.join("");
9411
+ return options.minify ? cssString : await this.formatWithPrettier(cssString);
9412
+ }
9413
+ /**
9414
+ * Format tokens as plain CSS custom property overrides inside a selector block.
9415
+ * Used for modifier overrides (e.g., dark mode) appended after the @theme block.
9416
+ */
9417
+ async formatOverrideBlock(tokens, selector, mediaQuery, minify) {
9418
+ const indent2 = minify ? "" : " ";
9419
+ const newline = minify ? "" : "\n";
9420
+ const space = minify ? "" : " ";
9421
+ const hasMediaQuery = mediaQuery !== "";
9422
+ const tokenIndent = hasMediaQuery ? indent2 + indent2 : indent2;
9423
+ const lines = [];
9424
+ if (hasMediaQuery) {
9425
+ lines.push(`@media ${mediaQuery}${space}{${newline}`);
9426
+ lines.push(`${indent2}${selector}${space}{${newline}`);
9427
+ } else {
9428
+ lines.push(`${selector}${space}{${newline}`);
9429
+ }
9430
+ for (const [, token] of getSortedTokenEntries(tokens)) {
9431
+ const varName = this.buildVariableName(token);
9432
+ const varValue = this.formatValue(token);
9433
+ lines.push(`${tokenIndent}--${varName}:${space}${varValue};${newline}`);
9434
+ }
9435
+ if (hasMediaQuery) {
9436
+ lines.push(`${indent2}}${newline}`);
9437
+ lines.push(`}${newline}`);
9438
+ } else {
9439
+ lines.push(`}${newline}`);
9440
+ }
9441
+ return lines.join("");
9442
+ }
9443
+ buildVariableName(token) {
9444
+ const prefix = TAILWIND_NAMESPACE_MAP[token.$type ?? ""];
9445
+ if (!prefix) {
9446
+ return token.name;
9447
+ }
9448
+ const nameLower = token.name.toLowerCase();
9449
+ const prefixLower = prefix.toLowerCase();
9450
+ if (nameLower.startsWith(`${prefixLower}-`) || nameLower.startsWith(`${prefixLower}.`)) {
9451
+ return token.name;
9452
+ }
9453
+ return `${prefix}-${token.name}`;
9454
+ }
9455
+ formatValue(token) {
9456
+ const value = token.$value;
9457
+ if (token.$type === "color" && isColorObject(value)) {
9458
+ return colorObjectToHex(value);
9459
+ }
9460
+ if (token.$type === "dimension" && isDimensionObject(value)) {
9461
+ return dimensionObjectToString(value);
9462
+ }
9463
+ if (token.$type === "duration" && this.isDurationObject(value)) {
9464
+ return `${value.value}${value.unit}`;
9465
+ }
9466
+ if (token.$type === "fontFamily") {
9467
+ if (Array.isArray(value)) {
9468
+ return value.map((v) => typeof v === "string" && v.includes(" ") ? `"${v}"` : v).join(", ");
9469
+ }
9470
+ return typeof value === "string" ? value : String(value);
9471
+ }
9472
+ if (token.$type === "shadow") {
9473
+ return this.formatShadowValue(value);
9474
+ }
9475
+ if (token.$type === "cubicBezier" && Array.isArray(value) && value.length === 4) {
9476
+ return `cubic-bezier(${value.join(", ")})`;
9477
+ }
9478
+ if (typeof value === "string") {
9479
+ return value;
9480
+ }
9481
+ if (typeof value === "number") {
9482
+ return String(value);
9483
+ }
9484
+ return String(value);
9485
+ }
9486
+ formatShadowValue(value) {
9487
+ if (Array.isArray(value) && value.length > 0 && typeof value[0] === "object") {
9488
+ return value.map((s) => this.formatSingleShadow(s)).join(", ");
9489
+ }
9490
+ if (typeof value === "object" && value !== null) {
9491
+ return this.formatSingleShadow(value);
9492
+ }
9493
+ return String(value);
9494
+ }
9495
+ formatSingleShadow(shadow) {
9496
+ const parts = [];
9497
+ if (shadow.inset === true) {
9498
+ parts.push("inset");
9499
+ }
9500
+ if (isDimensionObject(shadow.offsetX)) {
9501
+ parts.push(dimensionObjectToString(shadow.offsetX));
9502
+ }
9503
+ if (isDimensionObject(shadow.offsetY)) {
9504
+ parts.push(dimensionObjectToString(shadow.offsetY));
9505
+ }
9506
+ if (isDimensionObject(shadow.blur)) {
9507
+ parts.push(dimensionObjectToString(shadow.blur));
9508
+ }
9509
+ if (shadow.spread != null && isDimensionObject(shadow.spread)) {
9510
+ parts.push(dimensionObjectToString(shadow.spread));
9511
+ }
9512
+ if (isColorObject(shadow.color)) {
9513
+ parts.push(colorObjectToHex(shadow.color));
9514
+ } else if (shadow.color != null) {
9515
+ parts.push(String(shadow.color));
9516
+ }
9517
+ return parts.join(" ");
9518
+ }
9519
+ isDurationObject(value) {
9520
+ return typeof value === "object" && value !== null && "value" in value && "unit" in value && value.unit !== void 0;
9521
+ }
9522
+ async formatWithPrettier(css2) {
9523
+ try {
9524
+ return await prettier__default.default.format(css2, {
9525
+ parser: "css",
9526
+ printWidth: 80,
9527
+ tabWidth: 2,
9528
+ useTabs: false
9529
+ });
9530
+ } catch {
9531
+ return css2;
9532
+ }
9533
+ }
9534
+ async formatBundle(context, options) {
9535
+ const bundleData = context.permutations.map(({ tokens, modifierInputs }) => ({
9536
+ tokens,
9537
+ modifierInputs,
9538
+ isBase: this.isBasePermutation(modifierInputs, context.meta.defaults)
9539
+ }));
9540
+ return await bundleAsTailwind(
9541
+ bundleData,
9542
+ options,
9543
+ async (tokens, opts) => await this.formatTokens(tokens, opts),
9544
+ async (tokens, selector, mediaQuery, minify) => await this.formatOverrideBlock(tokens, selector, mediaQuery, minify)
9545
+ );
9546
+ }
9547
+ async formatStandalone(context, options) {
9548
+ const requiresFile = context.buildPath !== void 0 && context.buildPath !== "";
9549
+ if (!context.output.file && requiresFile) {
9550
+ throw new exports.ConfigurationError(
9551
+ `Output "${context.output.name}": file is required for standalone Tailwind output`
9552
+ );
9553
+ }
9554
+ const files = {};
9555
+ for (const { tokens, modifierInputs } of context.permutations) {
9556
+ const processedTokens = stripInternalMetadata(tokens);
9557
+ const content = await this.formatTokens(processedTokens, options);
9558
+ const fileName = context.output.file ? resolveFileName(context.output.file, modifierInputs) : buildInMemoryOutputKey({
9559
+ outputName: context.output.name,
9560
+ extension: "css",
9561
+ modifierInputs,
9562
+ resolver: context.resolver,
9563
+ defaults: context.meta.defaults
9564
+ });
9565
+ files[fileName] = content;
9566
+ }
9567
+ return outputTree(files);
9568
+ }
9569
+ isBasePermutation(modifierInputs, defaults) {
9570
+ return Object.entries(defaults).every(
9571
+ ([key, value]) => modifierInputs[key]?.toLowerCase() === value.toLowerCase()
9572
+ );
9573
+ }
9574
+ };
9575
+ function tailwindRenderer() {
9576
+ const rendererInstance = new TailwindRenderer();
9577
+ return {
9578
+ format: (context, options) => rendererInstance.format(
9579
+ context,
9580
+ options ?? context.output.options
9581
+ )
9582
+ };
9583
+ }
9584
+
7752
9585
  // src/builders.ts
7753
9586
  function css(config) {
7754
9587
  const {
@@ -7810,6 +9643,58 @@ function js(config) {
7810
9643
  hooks
7811
9644
  };
7812
9645
  }
9646
+ function tailwind(config) {
9647
+ const { name, file, transforms, filters, hooks, preset = "bundle", ...rendererOptions } = config;
9648
+ return {
9649
+ name,
9650
+ file,
9651
+ renderer: tailwindRenderer(),
9652
+ options: { preset, ...rendererOptions },
9653
+ transforms,
9654
+ filters,
9655
+ hooks
9656
+ };
9657
+ }
9658
+ function ios(config) {
9659
+ const {
9660
+ name,
9661
+ file,
9662
+ transforms,
9663
+ filters,
9664
+ hooks,
9665
+ preset = "standalone",
9666
+ ...rendererOptions
9667
+ } = config;
9668
+ return {
9669
+ name,
9670
+ file,
9671
+ renderer: iosRenderer(),
9672
+ options: { preset, ...rendererOptions },
9673
+ transforms,
9674
+ filters,
9675
+ hooks
9676
+ };
9677
+ }
9678
+ function android(config) {
9679
+ const {
9680
+ name,
9681
+ file,
9682
+ transforms,
9683
+ filters,
9684
+ hooks,
9685
+ preset = "standalone",
9686
+ ...rendererOptions
9687
+ } = config;
9688
+ return {
9689
+ name,
9690
+ file,
9691
+ renderer: androidRenderer(),
9692
+ options: { preset, ...rendererOptions },
9693
+ transforms,
9694
+ filters,
9695
+ hooks
9696
+ };
9697
+ }
7813
9698
 
7814
9699
  // src/renderers/types.ts
7815
9700
  function defineRenderer(renderer) {
@@ -7823,10 +9708,19 @@ init_errors();
7823
9708
  * Copyright (c) 2025 Dispersa Contributors
7824
9709
  * SPDX-License-Identifier: MIT
7825
9710
  */
9711
+ /**
9712
+ * @license MIT
9713
+ * Copyright (c) 2025-present Dispersa Contributors
9714
+ *
9715
+ * This source code is licensed under the MIT license found in the
9716
+ * LICENSE file in the root directory of this source tree.
9717
+ */
7826
9718
 
7827
9719
  exports.Dispersa = Dispersa;
9720
+ exports.android = android;
7828
9721
  exports.css = css;
7829
9722
  exports.defineRenderer = defineRenderer;
9723
+ exports.ios = ios;
7830
9724
  exports.isBorderToken = isBorderToken;
7831
9725
  exports.isColorToken = isColorToken;
7832
9726
  exports.isDimensionToken = isDimensionToken;
@@ -7839,5 +9733,6 @@ exports.isTypographyToken = isTypographyToken;
7839
9733
  exports.js = js;
7840
9734
  exports.json = json;
7841
9735
  exports.outputTree = outputTree;
9736
+ exports.tailwind = tailwind;
7842
9737
  //# sourceMappingURL=index.cjs.map
7843
9738
  //# sourceMappingURL=index.cjs.map