@homebound/truss 2.0.13 → 2.1.0-next.10

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.
@@ -1,6 +1,989 @@
1
1
  // src/plugin/index.ts
2
- import { readFileSync, existsSync } from "fs";
3
- import { resolve, dirname, isAbsolute } from "path";
2
+ import { readFileSync, writeFileSync, existsSync } from "fs";
3
+ import { resolve, dirname, isAbsolute, join } from "path";
4
+
5
+ // src/plugin/emit-truss.ts
6
+ import * as t from "@babel/types";
7
+
8
+ // src/plugin/property-priorities.ts
9
+ var longHandPhysical = /* @__PURE__ */ new Set();
10
+ var longHandLogical = /* @__PURE__ */ new Set();
11
+ var shorthandsOfLonghands = /* @__PURE__ */ new Set();
12
+ var shorthandsOfShorthands = /* @__PURE__ */ new Set();
13
+ longHandLogical.add("background-blend-mode");
14
+ longHandLogical.add("isolation");
15
+ longHandLogical.add("mix-blend-mode");
16
+ shorthandsOfShorthands.add("animation");
17
+ longHandLogical.add("animation-composition");
18
+ longHandLogical.add("animation-delay");
19
+ longHandLogical.add("animation-direction");
20
+ longHandLogical.add("animation-duration");
21
+ longHandLogical.add("animation-fill-mode");
22
+ longHandLogical.add("animation-iteration-count");
23
+ longHandLogical.add("animation-name");
24
+ longHandLogical.add("animation-play-state");
25
+ shorthandsOfLonghands.add("animation-range");
26
+ longHandLogical.add("animation-range-end");
27
+ longHandLogical.add("animation-range-start");
28
+ longHandLogical.add("animation-timing-function");
29
+ longHandLogical.add("animation-timeline");
30
+ shorthandsOfLonghands.add("scroll-timeline");
31
+ longHandLogical.add("scroll-timeline-axis");
32
+ longHandLogical.add("scroll-timeline-name");
33
+ longHandLogical.add("timeline-scope");
34
+ shorthandsOfLonghands.add("view-timeline");
35
+ longHandLogical.add("view-timeline-axis");
36
+ longHandLogical.add("view-timeline-inset");
37
+ longHandLogical.add("view-timeline-name");
38
+ shorthandsOfShorthands.add("background");
39
+ longHandLogical.add("background-attachment");
40
+ longHandLogical.add("background-clip");
41
+ longHandLogical.add("background-color");
42
+ longHandLogical.add("background-image");
43
+ longHandLogical.add("background-origin");
44
+ longHandLogical.add("background-repeat");
45
+ longHandLogical.add("background-size");
46
+ shorthandsOfLonghands.add("background-position");
47
+ longHandLogical.add("background-position-x");
48
+ longHandLogical.add("background-position-y");
49
+ shorthandsOfShorthands.add("border");
50
+ shorthandsOfLonghands.add("border-color");
51
+ shorthandsOfLonghands.add("border-style");
52
+ shorthandsOfLonghands.add("border-width");
53
+ shorthandsOfShorthands.add("border-block");
54
+ longHandLogical.add("border-block-color");
55
+ longHandLogical.add("border-block-stylex");
56
+ longHandLogical.add("border-block-width");
57
+ shorthandsOfLonghands.add("border-block-start");
58
+ shorthandsOfLonghands.add("border-top");
59
+ longHandLogical.add("border-block-start-color");
60
+ longHandPhysical.add("border-top-color");
61
+ longHandLogical.add("border-block-start-style");
62
+ longHandPhysical.add("border-top-style");
63
+ longHandLogical.add("border-block-start-width");
64
+ longHandPhysical.add("border-top-width");
65
+ shorthandsOfLonghands.add("border-block-end");
66
+ shorthandsOfLonghands.add("border-bottom");
67
+ longHandLogical.add("border-block-end-color");
68
+ longHandPhysical.add("border-bottom-color");
69
+ longHandLogical.add("border-block-end-style");
70
+ longHandPhysical.add("border-bottom-style");
71
+ longHandLogical.add("border-block-end-width");
72
+ longHandPhysical.add("border-bottom-width");
73
+ shorthandsOfShorthands.add("border-inline");
74
+ shorthandsOfLonghands.add("border-inline-color");
75
+ shorthandsOfLonghands.add("border-inline-style");
76
+ shorthandsOfLonghands.add("border-inline-width");
77
+ shorthandsOfLonghands.add("border-inline-start");
78
+ shorthandsOfLonghands.add("border-left");
79
+ longHandLogical.add("border-inline-start-color");
80
+ longHandPhysical.add("border-left-color");
81
+ longHandLogical.add("border-inline-start-style");
82
+ longHandPhysical.add("border-left-style");
83
+ longHandLogical.add("border-inline-start-width");
84
+ longHandPhysical.add("border-left-width");
85
+ shorthandsOfLonghands.add("border-inline-end");
86
+ shorthandsOfLonghands.add("border-right");
87
+ longHandLogical.add("border-inline-end-color");
88
+ longHandPhysical.add("border-right-color");
89
+ longHandLogical.add("border-inline-end-style");
90
+ longHandPhysical.add("border-right-style");
91
+ longHandLogical.add("border-inline-end-width");
92
+ longHandPhysical.add("border-right-width");
93
+ shorthandsOfLonghands.add("border-image");
94
+ longHandLogical.add("border-image-outset");
95
+ longHandLogical.add("border-image-repeat");
96
+ longHandLogical.add("border-image-slice");
97
+ longHandLogical.add("border-image-source");
98
+ longHandLogical.add("border-image-width");
99
+ shorthandsOfLonghands.add("border-radius");
100
+ longHandLogical.add("border-start-end-radius");
101
+ longHandLogical.add("border-start-start-radius");
102
+ longHandLogical.add("border-end-end-radius");
103
+ longHandLogical.add("border-end-start-radius");
104
+ longHandPhysical.add("border-top-left-radius");
105
+ longHandPhysical.add("border-top-right-radius");
106
+ longHandPhysical.add("border-bottom-left-radius");
107
+ longHandPhysical.add("border-bottom-right-radius");
108
+ shorthandsOfLonghands.add("corner-shape");
109
+ longHandLogical.add("corner-start-start-shape");
110
+ longHandLogical.add("corner-start-end-shape");
111
+ longHandLogical.add("corner-end-start-shape");
112
+ longHandLogical.add("corner-end-end-shape");
113
+ longHandPhysical.add("corner-top-left-shape");
114
+ longHandPhysical.add("corner-top-right-shape");
115
+ longHandPhysical.add("corner-bottom-left-shape");
116
+ longHandPhysical.add("corner-bottom-right-shape");
117
+ longHandLogical.add("box-shadow");
118
+ longHandLogical.add("accent-color");
119
+ longHandLogical.add("appearance");
120
+ longHandLogical.add("aspect-ratio");
121
+ shorthandsOfLonghands.add("caret");
122
+ longHandLogical.add("caret-color");
123
+ longHandLogical.add("caret-shape");
124
+ longHandLogical.add("cursor");
125
+ longHandLogical.add("ime-mode");
126
+ longHandLogical.add("input-security");
127
+ shorthandsOfLonghands.add("outline");
128
+ longHandLogical.add("outline-color");
129
+ longHandLogical.add("outline-offset");
130
+ longHandLogical.add("outline-style");
131
+ longHandLogical.add("outline-width");
132
+ longHandLogical.add("pointer-events");
133
+ longHandLogical.add("resize");
134
+ longHandLogical.add("text-overflow");
135
+ longHandLogical.add("user-select");
136
+ shorthandsOfLonghands.add("grid-gap");
137
+ shorthandsOfLonghands.add("gap");
138
+ longHandLogical.add("grid-row-gap");
139
+ longHandLogical.add("row-gap");
140
+ longHandLogical.add("grid-column-gap");
141
+ longHandLogical.add("column-gap");
142
+ shorthandsOfLonghands.add("place-content");
143
+ longHandLogical.add("align-content");
144
+ longHandLogical.add("justify-content");
145
+ shorthandsOfLonghands.add("place-items");
146
+ longHandLogical.add("align-items");
147
+ longHandLogical.add("justify-items");
148
+ shorthandsOfLonghands.add("place-self");
149
+ longHandLogical.add("align-self");
150
+ longHandLogical.add("justify-self");
151
+ longHandLogical.add("box-sizing");
152
+ longHandLogical.add("block-size");
153
+ longHandPhysical.add("height");
154
+ longHandLogical.add("inline-size");
155
+ longHandPhysical.add("width");
156
+ longHandLogical.add("max-block-size");
157
+ longHandPhysical.add("max-height");
158
+ longHandLogical.add("max-inline-size");
159
+ longHandPhysical.add("max-width");
160
+ longHandLogical.add("min-block-size");
161
+ longHandPhysical.add("min-height");
162
+ longHandLogical.add("min-inline-size");
163
+ longHandPhysical.add("min-width");
164
+ shorthandsOfShorthands.add("margin");
165
+ shorthandsOfLonghands.add("margin-block");
166
+ longHandLogical.add("margin-block-start");
167
+ longHandPhysical.add("margin-top");
168
+ longHandLogical.add("margin-block-end");
169
+ longHandPhysical.add("margin-bottom");
170
+ shorthandsOfLonghands.add("margin-inline");
171
+ longHandLogical.add("margin-inline-start");
172
+ longHandPhysical.add("margin-left");
173
+ longHandLogical.add("margin-inline-end");
174
+ longHandPhysical.add("margin-right");
175
+ longHandLogical.add("margin-trim");
176
+ shorthandsOfLonghands.add("overscroll-behavior");
177
+ longHandLogical.add("overscroll-behavior-block");
178
+ longHandPhysical.add("overscroll-behavior-y");
179
+ longHandLogical.add("overscroll-behavior-inline");
180
+ longHandPhysical.add("overscroll-behavior-x");
181
+ shorthandsOfShorthands.add("padding");
182
+ shorthandsOfLonghands.add("padding-block");
183
+ longHandLogical.add("padding-block-start");
184
+ longHandPhysical.add("padding-top");
185
+ longHandLogical.add("padding-block-end");
186
+ longHandPhysical.add("padding-bottom");
187
+ shorthandsOfLonghands.add("padding-inline");
188
+ longHandLogical.add("padding-inline-start");
189
+ longHandPhysical.add("padding-left");
190
+ longHandLogical.add("padding-inline-end");
191
+ longHandPhysical.add("padding-right");
192
+ longHandLogical.add("visibility");
193
+ longHandLogical.add("color");
194
+ longHandLogical.add("color-scheme");
195
+ longHandLogical.add("forced-color-adjust");
196
+ longHandLogical.add("opacity");
197
+ longHandLogical.add("print-color-adjust");
198
+ shorthandsOfLonghands.add("columns");
199
+ longHandLogical.add("column-count");
200
+ longHandLogical.add("column-width");
201
+ longHandLogical.add("column-fill");
202
+ longHandLogical.add("column-span");
203
+ shorthandsOfLonghands.add("column-rule");
204
+ longHandLogical.add("column-rule-color");
205
+ longHandLogical.add("column-rule-style");
206
+ longHandLogical.add("column-rule-width");
207
+ longHandLogical.add("contain");
208
+ shorthandsOfLonghands.add("contain-intrinsic-size");
209
+ longHandLogical.add("contain-intrinsic-block-size");
210
+ longHandLogical.add("contain-intrinsic-width");
211
+ longHandLogical.add("contain-intrinsic-height");
212
+ longHandLogical.add("contain-intrinsic-inline-size");
213
+ shorthandsOfLonghands.add("container");
214
+ longHandLogical.add("container-name");
215
+ longHandLogical.add("container-type");
216
+ longHandLogical.add("content-visibility");
217
+ longHandLogical.add("counter-increment");
218
+ longHandLogical.add("counter-reset");
219
+ longHandLogical.add("counter-set");
220
+ longHandLogical.add("display");
221
+ shorthandsOfLonghands.add("flex");
222
+ longHandLogical.add("flex-basis");
223
+ longHandLogical.add("flex-grow");
224
+ longHandLogical.add("flex-shrink");
225
+ shorthandsOfLonghands.add("flex-flow");
226
+ longHandLogical.add("flex-direction");
227
+ longHandLogical.add("flex-wrap");
228
+ longHandLogical.add("order");
229
+ shorthandsOfShorthands.add("font");
230
+ longHandLogical.add("font-family");
231
+ longHandLogical.add("font-size");
232
+ longHandLogical.add("font-stretch");
233
+ longHandLogical.add("font-style");
234
+ longHandLogical.add("font-weight");
235
+ longHandLogical.add("line-height");
236
+ shorthandsOfLonghands.add("font-variant");
237
+ longHandLogical.add("font-variant-alternates");
238
+ longHandLogical.add("font-variant-caps");
239
+ longHandLogical.add("font-variant-east-asian");
240
+ longHandLogical.add("font-variant-emoji");
241
+ longHandLogical.add("font-variant-ligatures");
242
+ longHandLogical.add("font-variant-numeric");
243
+ longHandLogical.add("font-variant-position");
244
+ longHandLogical.add("font-feature-settings");
245
+ longHandLogical.add("font-kerning");
246
+ longHandLogical.add("font-language-override");
247
+ longHandLogical.add("font-optical-sizing");
248
+ longHandLogical.add("font-palette");
249
+ longHandLogical.add("font-variation-settings");
250
+ longHandLogical.add("font-size-adjust");
251
+ longHandLogical.add("font-smooth");
252
+ longHandLogical.add("font-synthesis-position");
253
+ longHandLogical.add("font-synthesis-small-caps");
254
+ longHandLogical.add("font-synthesis-style");
255
+ longHandLogical.add("font-synthesis-weight");
256
+ longHandLogical.add("line-height-step");
257
+ longHandLogical.add("box-decoration-break");
258
+ longHandLogical.add("break-after");
259
+ longHandLogical.add("break-before");
260
+ longHandLogical.add("break-inside");
261
+ longHandLogical.add("orphans");
262
+ longHandLogical.add("widows");
263
+ longHandLogical.add("content");
264
+ longHandLogical.add("quotes");
265
+ shorthandsOfShorthands.add("grid");
266
+ longHandLogical.add("grid-auto-flow");
267
+ longHandLogical.add("grid-auto-rows");
268
+ longHandLogical.add("grid-auto-columns");
269
+ shorthandsOfShorthands.add("grid-template");
270
+ shorthandsOfLonghands.add("grid-template-areas");
271
+ longHandLogical.add("grid-template-columns");
272
+ longHandLogical.add("grid-template-rows");
273
+ shorthandsOfShorthands.add("grid-area");
274
+ shorthandsOfLonghands.add("grid-row");
275
+ longHandLogical.add("grid-row-start");
276
+ longHandLogical.add("grid-row-end");
277
+ shorthandsOfLonghands.add("grid-column");
278
+ longHandLogical.add("grid-column-start");
279
+ longHandLogical.add("grid-column-end");
280
+ longHandLogical.add("align-tracks");
281
+ longHandLogical.add("justify-tracks");
282
+ longHandLogical.add("masonry-auto-flow");
283
+ longHandLogical.add("image-orientation");
284
+ longHandLogical.add("image-rendering");
285
+ longHandLogical.add("image-resolution");
286
+ longHandLogical.add("object-fit");
287
+ longHandLogical.add("object-position");
288
+ longHandLogical.add("initial-letter");
289
+ longHandLogical.add("initial-letter-align");
290
+ shorthandsOfLonghands.add("list-style");
291
+ longHandLogical.add("list-style-image");
292
+ longHandLogical.add("list-style-position");
293
+ longHandLogical.add("list-style-type");
294
+ longHandLogical.add("clip");
295
+ longHandLogical.add("clip-path");
296
+ shorthandsOfLonghands.add("mask");
297
+ longHandLogical.add("mask-clip");
298
+ longHandLogical.add("mask-composite");
299
+ longHandLogical.add("mask-image");
300
+ longHandLogical.add("mask-mode");
301
+ longHandLogical.add("mask-origin");
302
+ longHandLogical.add("mask-position");
303
+ longHandLogical.add("mask-repeat");
304
+ longHandLogical.add("mask-size");
305
+ longHandLogical.add("mask-type");
306
+ shorthandsOfLonghands.add("mask-border");
307
+ longHandLogical.add("mask-border-mode");
308
+ longHandLogical.add("mask-border-outset");
309
+ longHandLogical.add("mask-border-repeat");
310
+ longHandLogical.add("mask-border-slice");
311
+ longHandLogical.add("mask-border-source");
312
+ longHandLogical.add("mask-border-width");
313
+ shorthandsOfShorthands.add("all");
314
+ longHandLogical.add("text-rendering");
315
+ shorthandsOfLonghands.add("offset");
316
+ longHandLogical.add("offset-anchor");
317
+ longHandLogical.add("offset-distance");
318
+ longHandLogical.add("offset-path");
319
+ longHandLogical.add("offset-position");
320
+ longHandLogical.add("offset-rotate");
321
+ longHandLogical.add("-webkit-box-orient");
322
+ longHandLogical.add("-webkit-line-clamp");
323
+ shorthandsOfLonghands.add("overflow");
324
+ longHandLogical.add("overflow-block");
325
+ longHandPhysical.add("overflow-y");
326
+ longHandLogical.add("overflow-inline");
327
+ longHandPhysical.add("overflow-x");
328
+ longHandLogical.add("overflow-clip-margin");
329
+ longHandLogical.add("scroll-gutter");
330
+ longHandLogical.add("scroll-behavior");
331
+ longHandLogical.add("page");
332
+ longHandLogical.add("page-break-after");
333
+ longHandLogical.add("page-break-before");
334
+ longHandLogical.add("page-break-inside");
335
+ shorthandsOfShorthands.add("inset");
336
+ shorthandsOfLonghands.add("inset-block");
337
+ longHandLogical.add("inset-block-start");
338
+ longHandPhysical.add("top");
339
+ longHandLogical.add("inset-block-end");
340
+ longHandPhysical.add("bottom");
341
+ shorthandsOfLonghands.add("inset-inline");
342
+ longHandLogical.add("inset-inline-start");
343
+ longHandPhysical.add("left");
344
+ longHandLogical.add("inset-inline-end");
345
+ longHandPhysical.add("right");
346
+ longHandLogical.add("clear");
347
+ longHandLogical.add("float");
348
+ longHandLogical.add("position");
349
+ longHandLogical.add("z-index");
350
+ longHandLogical.add("ruby-align");
351
+ longHandLogical.add("ruby-merge");
352
+ longHandLogical.add("ruby-position");
353
+ longHandLogical.add("overflow-anchor");
354
+ shorthandsOfShorthands.add("scroll-margin");
355
+ shorthandsOfLonghands.add("scroll-margin-block");
356
+ longHandLogical.add("scroll-margin-block-start");
357
+ longHandPhysical.add("scroll-margin-top");
358
+ longHandLogical.add("scroll-margin-block-end");
359
+ longHandPhysical.add("scroll-margin-bottom");
360
+ shorthandsOfLonghands.add("scroll-margin-inline");
361
+ longHandLogical.add("scroll-margin-inline-start");
362
+ longHandPhysical.add("scroll-margin-left");
363
+ longHandLogical.add("scroll-margin-inline-end");
364
+ longHandPhysical.add("scroll-margin-right");
365
+ shorthandsOfShorthands.add("scroll-padding");
366
+ shorthandsOfLonghands.add("scroll-padding-block");
367
+ longHandLogical.add("scroll-padding-block-start");
368
+ longHandPhysical.add("scroll-padding-top");
369
+ longHandLogical.add("scroll-padding-block-end");
370
+ longHandPhysical.add("scroll-padding-bottom");
371
+ shorthandsOfLonghands.add("scroll-padding-inline");
372
+ longHandLogical.add("scroll-padding-inline-start");
373
+ longHandPhysical.add("scroll-padding-left");
374
+ longHandLogical.add("scroll-padding-inline-end");
375
+ longHandPhysical.add("scroll-padding-right");
376
+ longHandLogical.add("scroll-snap-align");
377
+ longHandLogical.add("scroll-snap-stop");
378
+ shorthandsOfLonghands.add("scroll-snap-type");
379
+ longHandLogical.add("scrollbar-color");
380
+ longHandLogical.add("scrollbar-width");
381
+ longHandLogical.add("shape-image-threshold");
382
+ longHandLogical.add("shape-margin");
383
+ longHandLogical.add("shape-outside");
384
+ longHandLogical.add("azimuth");
385
+ longHandLogical.add("border-collapse");
386
+ longHandLogical.add("border-spacing");
387
+ longHandLogical.add("caption-side");
388
+ longHandLogical.add("empty-cells");
389
+ longHandLogical.add("table-layout");
390
+ longHandLogical.add("vertical-align");
391
+ shorthandsOfLonghands.add("text-decoration");
392
+ longHandLogical.add("text-decoration-color");
393
+ longHandLogical.add("text-decoration-line");
394
+ longHandLogical.add("text-decoration-skip");
395
+ longHandLogical.add("text-decoration-skip-ink");
396
+ longHandLogical.add("text-decoration-style");
397
+ longHandLogical.add("text-decoration-thickness");
398
+ shorthandsOfLonghands.add("text-emphasis");
399
+ longHandLogical.add("text-emphasis-color");
400
+ longHandLogical.add("text-emphasis-position");
401
+ longHandLogical.add("text-emphasis-style");
402
+ longHandLogical.add("text-shadow");
403
+ longHandLogical.add("text-underline-offset");
404
+ longHandLogical.add("text-underline-position");
405
+ longHandLogical.add("hanging-punctuation");
406
+ longHandLogical.add("hyphenate-character");
407
+ longHandLogical.add("hyphenate-limit-chars");
408
+ longHandLogical.add("hyphens");
409
+ longHandLogical.add("letter-spacing");
410
+ longHandLogical.add("line-break");
411
+ longHandLogical.add("overflow-wrap");
412
+ longHandLogical.add("paint-order");
413
+ longHandLogical.add("tab-size");
414
+ longHandLogical.add("text-align");
415
+ longHandLogical.add("text-align-last");
416
+ longHandLogical.add("text-indent");
417
+ longHandLogical.add("text-justify");
418
+ longHandLogical.add("text-size-adjust");
419
+ longHandLogical.add("text-transform");
420
+ longHandLogical.add("text-wrap");
421
+ longHandLogical.add("white-space");
422
+ longHandLogical.add("white-space-collapse");
423
+ longHandLogical.add("word-break");
424
+ longHandLogical.add("word-spacing");
425
+ longHandLogical.add("word-wrap");
426
+ longHandLogical.add("backface-visibility");
427
+ longHandLogical.add("perspective");
428
+ longHandLogical.add("perspective-origin");
429
+ longHandLogical.add("rotate");
430
+ longHandLogical.add("scale");
431
+ longHandLogical.add("transform");
432
+ longHandLogical.add("transform-box");
433
+ longHandLogical.add("transform-origin");
434
+ longHandLogical.add("transform-style");
435
+ longHandLogical.add("translate");
436
+ shorthandsOfLonghands.add("transition");
437
+ longHandLogical.add("transition-delay");
438
+ longHandLogical.add("transition-duration");
439
+ longHandLogical.add("transition-property");
440
+ longHandLogical.add("transition-timing-function");
441
+ longHandLogical.add("view-transition-name");
442
+ longHandLogical.add("will-change");
443
+ longHandLogical.add("direction");
444
+ longHandLogical.add("text-combine-upright");
445
+ longHandLogical.add("text-orientation");
446
+ longHandLogical.add("unicode-bidi");
447
+ longHandLogical.add("writing-mode");
448
+ longHandLogical.add("backdrop-filter");
449
+ longHandLogical.add("filter");
450
+ longHandLogical.add("math-depth");
451
+ longHandLogical.add("math-shift");
452
+ longHandLogical.add("math-style");
453
+ longHandLogical.add("touch-action");
454
+ var PSEUDO_CLASS_PRIORITIES = {
455
+ ":is": 40,
456
+ ":where": 40,
457
+ ":not": 40,
458
+ ":has": 45,
459
+ ":dir": 50,
460
+ ":lang": 51,
461
+ ":first-child": 52,
462
+ ":first-of-type": 53,
463
+ ":last-child": 54,
464
+ ":last-of-type": 55,
465
+ ":only-child": 56,
466
+ ":only-of-type": 57,
467
+ ":nth-child": 60,
468
+ ":nth-last-child": 61,
469
+ ":nth-of-type": 62,
470
+ ":nth-last-of-type": 63,
471
+ ":empty": 70,
472
+ ":link": 80,
473
+ ":any-link": 81,
474
+ ":local-link": 82,
475
+ ":target-within": 83,
476
+ ":target": 84,
477
+ ":visited": 85,
478
+ ":enabled": 91,
479
+ ":disabled": 92,
480
+ ":required": 93,
481
+ ":optional": 94,
482
+ ":read-only": 95,
483
+ ":read-write": 96,
484
+ ":placeholder-shown": 97,
485
+ ":in-range": 98,
486
+ ":out-of-range": 99,
487
+ ":default": 100,
488
+ ":checked": 101,
489
+ ":indeterminate": 101,
490
+ ":blank": 102,
491
+ ":valid": 103,
492
+ ":invalid": 104,
493
+ ":user-invalid": 105,
494
+ ":autofill": 110,
495
+ ":picture-in-picture": 120,
496
+ ":modal": 121,
497
+ ":fullscreen": 122,
498
+ ":paused": 123,
499
+ ":playing": 124,
500
+ ":current": 125,
501
+ ":past": 126,
502
+ ":future": 127,
503
+ ":hover": 130,
504
+ ":focusWithin": 140,
505
+ ":focus": 150,
506
+ ":focusVisible": 160,
507
+ ":active": 170
508
+ };
509
+ var AT_RULE_PRIORITIES = {
510
+ "@supports": 30,
511
+ "@media": 200,
512
+ "@container": 300
513
+ };
514
+ var PSEUDO_ELEMENT_PRIORITY = 5e3;
515
+ function getPropertyPriority(property) {
516
+ if (shorthandsOfShorthands.has(property)) return 1e3;
517
+ if (shorthandsOfLonghands.has(property)) return 2e3;
518
+ if (longHandLogical.has(property)) return 3e3;
519
+ if (longHandPhysical.has(property)) return 4e3;
520
+ return 3e3;
521
+ }
522
+ function getPseudoClassPriority(pseudo) {
523
+ const base = pseudo.split("(")[0];
524
+ return PSEUDO_CLASS_PRIORITIES[base] ?? 40;
525
+ }
526
+ function getAtRulePriority(atRule) {
527
+ if (atRule.startsWith("--")) return 1;
528
+ if (atRule.startsWith("@supports")) return AT_RULE_PRIORITIES["@supports"];
529
+ if (atRule.startsWith("@media")) return AT_RULE_PRIORITIES["@media"];
530
+ if (atRule.startsWith("@container")) return AT_RULE_PRIORITIES["@container"];
531
+ return 0;
532
+ }
533
+
534
+ // src/plugin/priority.ts
535
+ var RELATIONSHIP_BASE = {
536
+ ancestor: 10,
537
+ descendant: 15,
538
+ anySibling: 20,
539
+ siblingBefore: 30,
540
+ siblingAfter: 40
541
+ };
542
+ function computeRulePriority(rule) {
543
+ let priority = getPropertyPriority(rule.cssProperty);
544
+ if (rule.pseudoElement) {
545
+ priority += PSEUDO_ELEMENT_PRIORITY;
546
+ }
547
+ if (rule.pseudoClass) {
548
+ priority += getPseudoClassPriority(rule.pseudoClass);
549
+ }
550
+ if (rule.mediaQuery) {
551
+ priority += getAtRulePriority(rule.mediaQuery);
552
+ }
553
+ if (rule.whenSelector) {
554
+ const relBase = RELATIONSHIP_BASE[rule.whenSelector.relationship] ?? 10;
555
+ const pseudoFraction = getPseudoClassPriority(rule.whenSelector.pseudo) / 100;
556
+ priority += relBase + pseudoFraction;
557
+ }
558
+ if (isVariableRule(rule)) {
559
+ priority += 0.5;
560
+ }
561
+ return priority;
562
+ }
563
+ function isVariableRule(rule) {
564
+ if (rule.declarations) {
565
+ return rule.declarations.some(function(d) {
566
+ return d.cssVarName !== void 0;
567
+ });
568
+ }
569
+ return rule.cssVarName !== void 0;
570
+ }
571
+ function sortRulesByPriority(rules) {
572
+ rules.sort(function(a, b) {
573
+ const diff = computeRulePriority(a) - computeRulePriority(b);
574
+ if (diff !== 0) return diff;
575
+ return a.className < b.className ? -1 : a.className > b.className ? 1 : 0;
576
+ });
577
+ }
578
+
579
+ // src/plugin/emit-truss.ts
580
+ var PSEUDO_SUFFIX = {
581
+ ":hover": "_h",
582
+ ":focus": "_f",
583
+ ":focus-visible": "_fv",
584
+ ":active": "_a",
585
+ ":disabled": "_d"
586
+ };
587
+ var RELATIONSHIP_SHORT = {
588
+ ancestor: "anc",
589
+ descendant: "desc",
590
+ siblingAfter: "sibA",
591
+ siblingBefore: "sibB",
592
+ anySibling: "anyS"
593
+ };
594
+ var DEFAULT_MARKER_CLASS = "__truss_m";
595
+ function markerClassName(markerNode) {
596
+ if (!markerNode) return DEFAULT_MARKER_CLASS;
597
+ if (markerNode.type === "Identifier" && markerNode.name) {
598
+ return `__truss_m_${markerNode.name}`;
599
+ }
600
+ return `${DEFAULT_MARKER_CLASS}_marker`;
601
+ }
602
+ function whenPrefix(whenPseudo) {
603
+ const rel = RELATIONSHIP_SHORT[whenPseudo.relationship ?? "ancestor"] ?? "anc";
604
+ const pseudoTag = PSEUDO_SUFFIX[whenPseudo.pseudo]?.replace(/^_/, "") ?? whenPseudo.pseudo.replace(/^:/, "");
605
+ const markerPart = whenPseudo.markerNode?.type === "Identifier" ? `${whenPseudo.markerNode.name}_` : "";
606
+ return `wh_${rel}_${pseudoTag}_${markerPart}`;
607
+ }
608
+ function conditionPrefix(pseudoClass, mediaQuery, pseudoElement, breakpoints) {
609
+ const parts = [];
610
+ if (pseudoElement) {
611
+ parts.push(`${pseudoElement.replace(/^::/, "")}_`);
612
+ }
613
+ if (mediaQuery && breakpoints) {
614
+ const bpKey = Object.entries(breakpoints).find(([, v]) => v === mediaQuery)?.[0];
615
+ if (bpKey) {
616
+ const shortName = bpKey.replace(/^if/, "").toLowerCase();
617
+ parts.push(`${shortName}_`);
618
+ } else {
619
+ parts.push("mq_");
620
+ }
621
+ } else if (mediaQuery) {
622
+ parts.push("mq_");
623
+ }
624
+ if (pseudoClass) {
625
+ const tag = PSEUDO_SUFFIX[pseudoClass];
626
+ if (tag) parts.push(`${tag.replace(/^_/, "")}_`);
627
+ else parts.push(`${pseudoClass.replace(/^:/, "")}_`);
628
+ }
629
+ return parts.join("");
630
+ }
631
+ function camelToKebab(s) {
632
+ return s.replace(/^(Webkit|Moz|Ms|O)/, (m) => `-${m.toLowerCase()}`).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
633
+ }
634
+ function cleanValueForClassName(value) {
635
+ let cleaned = value;
636
+ if (cleaned.startsWith("-")) {
637
+ cleaned = "neg" + cleaned.slice(1);
638
+ }
639
+ return cleaned.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
640
+ }
641
+ function buildLonghandLookup(mapping) {
642
+ const lookup = /* @__PURE__ */ new Map();
643
+ for (const [abbrev, entry] of Object.entries(mapping.abbreviations)) {
644
+ if (entry.kind !== "static") continue;
645
+ const props = Object.keys(entry.defs);
646
+ if (props.length !== 1) continue;
647
+ const prop = props[0];
648
+ const value = String(entry.defs[prop]);
649
+ const key = `${prop}\0${value}`;
650
+ if (!lookup.has(key)) {
651
+ lookup.set(key, abbrev);
652
+ }
653
+ }
654
+ return lookup;
655
+ }
656
+ var cachedMapping = null;
657
+ var cachedLookup = null;
658
+ function getLonghandLookup(mapping) {
659
+ if (cachedMapping !== mapping) {
660
+ cachedMapping = mapping;
661
+ cachedLookup = buildLonghandLookup(mapping);
662
+ }
663
+ return cachedLookup;
664
+ }
665
+ function computeStaticBaseName(seg, cssProp, cssValue, isMultiProp, mapping) {
666
+ const abbr = seg.abbr;
667
+ if (seg.argResolved !== void 0) {
668
+ const valuePart = cleanValueForClassName(seg.argResolved);
669
+ if (isMultiProp) {
670
+ const lookup = getLonghandLookup(mapping);
671
+ const canonical = lookup.get(`${cssProp}\0${cssValue}`);
672
+ if (canonical) return canonical;
673
+ return `${abbr}_${valuePart}_${cssProp}`;
674
+ }
675
+ return `${abbr}_${valuePart}`;
676
+ }
677
+ if (isMultiProp) {
678
+ const lookup = getLonghandLookup(mapping);
679
+ const canonical = lookup.get(`${cssProp}\0${cssValue}`);
680
+ if (canonical) return canonical;
681
+ return `${abbr}_${cssProp}`;
682
+ }
683
+ return abbr;
684
+ }
685
+ function collectAtomicRules(chains, mapping) {
686
+ const rules = /* @__PURE__ */ new Map();
687
+ let needsMaybeInc = false;
688
+ for (const chain of chains) {
689
+ for (const part of chain.parts) {
690
+ const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
691
+ for (const seg of segs) {
692
+ if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
693
+ if (seg.incremented) needsMaybeInc = true;
694
+ if (seg.variableProps) {
695
+ collectVariableRules(rules, seg, mapping);
696
+ } else {
697
+ collectStaticRules(rules, seg, mapping);
698
+ }
699
+ }
700
+ }
701
+ }
702
+ return { rules, needsMaybeInc };
703
+ }
704
+ function segmentContext(seg, mapping) {
705
+ if (seg.whenPseudo) {
706
+ const wp = seg.whenPseudo;
707
+ return {
708
+ prefix: whenPrefix(wp),
709
+ whenSelector: {
710
+ relationship: wp.relationship ?? "ancestor",
711
+ markerClass: markerClassName(wp.markerNode),
712
+ pseudo: wp.pseudo
713
+ }
714
+ };
715
+ }
716
+ return { prefix: conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints) };
717
+ }
718
+ function baseRuleFields(seg) {
719
+ return {
720
+ pseudoClass: seg.pseudoClass ?? void 0,
721
+ mediaQuery: seg.mediaQuery ?? void 0,
722
+ pseudoElement: seg.pseudoElement ?? void 0
723
+ };
724
+ }
725
+ function collectStaticRules(rules, seg, mapping) {
726
+ const { prefix, whenSelector } = segmentContext(seg, mapping);
727
+ const isMultiProp = Object.keys(seg.defs).length > 1;
728
+ for (const [cssProp, value] of Object.entries(seg.defs)) {
729
+ const cssValue = String(value);
730
+ const baseName = computeStaticBaseName(seg, cssProp, cssValue, isMultiProp, mapping);
731
+ const className = prefix ? `${prefix}${baseName}` : baseName;
732
+ if (!rules.has(className)) {
733
+ rules.set(className, {
734
+ className,
735
+ cssProperty: camelToKebab(cssProp),
736
+ cssValue,
737
+ ...!whenSelector && baseRuleFields(seg),
738
+ whenSelector
739
+ });
740
+ }
741
+ }
742
+ }
743
+ function collectVariableRules(rules, seg, mapping) {
744
+ const { prefix, whenSelector } = segmentContext(seg, mapping);
745
+ for (const prop of seg.variableProps) {
746
+ const className = prefix ? `${prefix}${seg.abbr}_var` : `${seg.abbr}_var`;
747
+ const varName = toCssVariableName(className, seg.abbr, prop);
748
+ const declaration = { cssProperty: camelToKebab(prop), cssValue: `var(${varName})`, cssVarName: varName };
749
+ const existingRule = rules.get(className);
750
+ if (!existingRule) {
751
+ rules.set(className, {
752
+ className,
753
+ cssProperty: declaration.cssProperty,
754
+ cssValue: declaration.cssValue,
755
+ declarations: [declaration],
756
+ cssVarName: varName,
757
+ ...!whenSelector && baseRuleFields(seg),
758
+ whenSelector
759
+ });
760
+ continue;
761
+ }
762
+ existingRule.declarations ??= [
763
+ {
764
+ cssProperty: existingRule.cssProperty,
765
+ cssValue: existingRule.cssValue,
766
+ cssVarName: existingRule.cssVarName
767
+ }
768
+ ];
769
+ if (!existingRule.declarations.some(function(entry) {
770
+ return entry.cssProperty === declaration.cssProperty;
771
+ })) {
772
+ existingRule.declarations.push(declaration);
773
+ }
774
+ }
775
+ if (seg.variableExtraDefs) {
776
+ for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
777
+ const extraBase = `${seg.abbr}_${cssProp}`;
778
+ const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
779
+ if (!rules.has(extraName)) {
780
+ rules.set(extraName, {
781
+ className: extraName,
782
+ cssProperty: camelToKebab(cssProp),
783
+ cssValue: String(value),
784
+ ...!whenSelector && baseRuleFields(seg),
785
+ whenSelector
786
+ });
787
+ }
788
+ }
789
+ }
790
+ }
791
+ function generateCssText(rules) {
792
+ const allRules = Array.from(rules.values());
793
+ sortRulesByPriority(allRules);
794
+ const lines = [];
795
+ for (const rule of allRules) {
796
+ lines.push(formatRule(rule));
797
+ }
798
+ for (const rule of allRules) {
799
+ for (const declaration of getRuleDeclarations(rule)) {
800
+ if (declaration.cssVarName) {
801
+ lines.push(`@property ${declaration.cssVarName} {
802
+ syntax: "*";
803
+ inherits: false;
804
+ }`);
805
+ }
806
+ }
807
+ }
808
+ return lines.join("\n");
809
+ }
810
+ function formatRule(rule) {
811
+ if (rule.whenSelector) return formatWhenRule(rule);
812
+ if (rule.mediaQuery && rule.pseudoClass) return formatMediaPseudoRule(rule);
813
+ if (rule.mediaQuery && rule.pseudoElement) return formatMediaPseudoElementRule(rule);
814
+ if (rule.mediaQuery) return formatMediaRule(rule);
815
+ if (rule.pseudoClass && rule.pseudoElement) return formatPseudoRule(rule);
816
+ if (rule.pseudoElement) return formatPseudoElementRule(rule);
817
+ if (rule.pseudoClass) return formatPseudoRule(rule);
818
+ return formatBaseRule(rule);
819
+ }
820
+ function formatBaseRule(rule) {
821
+ return formatRuleBlock(`.${rule.className}`, rule);
822
+ }
823
+ function formatPseudoRule(rule) {
824
+ const pe = rule.pseudoElement ? rule.pseudoElement : "";
825
+ return formatRuleBlock(`.${rule.className}${rule.pseudoClass}${pe}`, rule);
826
+ }
827
+ function formatPseudoElementRule(rule) {
828
+ return formatRuleBlock(`.${rule.className}${rule.pseudoElement}`, rule);
829
+ }
830
+ function formatWhenRule(rule) {
831
+ const whenSelector = rule.whenSelector;
832
+ if (!whenSelector) {
833
+ return formatBaseRule(rule);
834
+ }
835
+ const markerSelector = `.${whenSelector.markerClass}${whenSelector.pseudo}`;
836
+ const targetSelector = `.${rule.className}`;
837
+ if (whenSelector.relationship === "ancestor") {
838
+ return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
839
+ }
840
+ if (whenSelector.relationship === "descendant") {
841
+ return formatRuleBlock(`${targetSelector}:has(${markerSelector})`, rule);
842
+ }
843
+ if (whenSelector.relationship === "siblingAfter") {
844
+ return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector})`, rule);
845
+ }
846
+ if (whenSelector.relationship === "siblingBefore") {
847
+ return formatRuleBlock(`${markerSelector} ~ ${targetSelector}`, rule);
848
+ }
849
+ if (whenSelector.relationship === "anySibling") {
850
+ return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector}), ${markerSelector} ~ ${targetSelector}`, rule);
851
+ }
852
+ return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
853
+ }
854
+ function formatMediaRule(rule) {
855
+ return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}`, rule);
856
+ }
857
+ function formatMediaPseudoRule(rule) {
858
+ return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${rule.pseudoClass}`, rule);
859
+ }
860
+ function formatMediaPseudoElementRule(rule) {
861
+ const pe = rule.pseudoElement ?? "";
862
+ return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${pe}`, rule);
863
+ }
864
+ function getRuleDeclarations(rule) {
865
+ return rule.declarations ?? [{ cssProperty: rule.cssProperty, cssValue: rule.cssValue, cssVarName: rule.cssVarName }];
866
+ }
867
+ function formatRuleBlock(selector, rule) {
868
+ const body = getRuleDeclarations(rule).map(function(declaration) {
869
+ return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
870
+ }).join("\n");
871
+ return `${selector} {
872
+ ${body}
873
+ }`;
874
+ }
875
+ function formatNestedRuleBlock(wrapper, selector, rule) {
876
+ const body = getRuleDeclarations(rule).map(function(declaration) {
877
+ return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
878
+ }).join("\n");
879
+ return `${wrapper} {
880
+ ${selector} {
881
+ ${body}
882
+ }
883
+ }`;
884
+ }
885
+ function buildStyleHashProperties(segments, mapping, maybeIncHelperName) {
886
+ const propGroups = /* @__PURE__ */ new Map();
887
+ for (const seg of segments) {
888
+ if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
889
+ const { prefix } = segmentContext(seg, mapping);
890
+ if (seg.variableProps) {
891
+ for (const prop of seg.variableProps) {
892
+ const className = prefix ? `${prefix}${seg.abbr}_var` : `${seg.abbr}_var`;
893
+ const varName = toCssVariableName(className, seg.abbr, prop);
894
+ if (!propGroups.has(prop)) propGroups.set(prop, []);
895
+ propGroups.get(prop).push({
896
+ className,
897
+ isVariable: true,
898
+ varName,
899
+ argNode: seg.argNode,
900
+ incremented: seg.incremented,
901
+ appendPx: seg.appendPx
902
+ });
903
+ }
904
+ if (seg.variableExtraDefs) {
905
+ for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
906
+ const extraBase = `${seg.abbr}_${cssProp}`;
907
+ const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
908
+ if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
909
+ propGroups.get(cssProp).push({ className: extraName, isVariable: false });
910
+ }
911
+ }
912
+ } else {
913
+ const isMultiProp = Object.keys(seg.defs).length > 1;
914
+ for (const [cssProp, val] of Object.entries(seg.defs)) {
915
+ const baseName = computeStaticBaseName(seg, cssProp, String(val), isMultiProp, mapping);
916
+ const className = prefix ? `${prefix}${baseName}` : baseName;
917
+ if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
918
+ propGroups.get(cssProp).push({ className, isVariable: false });
919
+ }
920
+ }
921
+ }
922
+ const properties = [];
923
+ for (const [cssProp, entries] of Array.from(propGroups.entries())) {
924
+ const classNames = entries.map((e) => e.className).join(" ");
925
+ const variableEntries = entries.filter((e) => e.isVariable);
926
+ if (variableEntries.length > 0) {
927
+ const varsProps = [];
928
+ for (const dyn of variableEntries) {
929
+ let valueExpr = dyn.argNode;
930
+ if (dyn.incremented) {
931
+ valueExpr = t.callExpression(t.identifier(maybeIncHelperName ?? "__maybeInc"), [valueExpr]);
932
+ } else if (dyn.appendPx) {
933
+ valueExpr = t.templateLiteral(
934
+ [t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
935
+ [valueExpr]
936
+ );
937
+ }
938
+ varsProps.push(t.objectProperty(t.stringLiteral(dyn.varName), valueExpr));
939
+ }
940
+ const tuple = t.arrayExpression([t.stringLiteral(classNames), t.objectExpression(varsProps)]);
941
+ properties.push(t.objectProperty(toPropertyKey(cssProp), tuple));
942
+ } else {
943
+ properties.push(t.objectProperty(toPropertyKey(cssProp), t.stringLiteral(classNames)));
944
+ }
945
+ }
946
+ return properties;
947
+ }
948
+ function toCssVariableName(className, baseKey, cssProp) {
949
+ const baseClassName = `${baseKey}_var`;
950
+ const cp = className.endsWith(baseClassName) ? className.slice(0, -baseClassName.length) : "";
951
+ return `--${cp}${cssProp}`;
952
+ }
953
+ function buildMaybeIncDeclaration(helperName, increment) {
954
+ const incParam = t.identifier("inc");
955
+ const body = t.blockStatement([
956
+ t.returnStatement(
957
+ t.conditionalExpression(
958
+ t.binaryExpression("===", t.unaryExpression("typeof", incParam), t.stringLiteral("string")),
959
+ incParam,
960
+ t.templateLiteral(
961
+ [t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
962
+ [t.binaryExpression("*", incParam, t.numericLiteral(increment))]
963
+ )
964
+ )
965
+ )
966
+ ]);
967
+ return t.variableDeclaration("const", [
968
+ t.variableDeclarator(t.identifier(helperName), t.arrowFunctionExpression([incParam], body))
969
+ ]);
970
+ }
971
+ function toPropertyKey(key) {
972
+ return isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);
973
+ }
974
+ function isValidIdentifier(s) {
975
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
976
+ }
977
+ function buildRuntimeLookupDeclaration(lookupName, segmentsByName, mapping) {
978
+ const properties = [];
979
+ for (const [name, segs] of Object.entries(segmentsByName)) {
980
+ const hashProps = buildStyleHashProperties(segs, mapping);
981
+ properties.push(t.objectProperty(t.identifier(name), t.objectExpression(hashProps)));
982
+ }
983
+ return t.variableDeclaration("const", [
984
+ t.variableDeclarator(t.identifier(lookupName), t.objectExpression(properties))
985
+ ]);
986
+ }
4
987
 
5
988
  // src/plugin/transform.ts
6
989
  import { parse } from "@babel/parser";
@@ -33,6 +1016,23 @@ function resolveFullChain(chain, mapping) {
33
1016
  let currentNodes = [];
34
1017
  while (i < filteredChain.length) {
35
1018
  const node = filteredChain[i];
1019
+ const mediaStart = getMediaConditionalStartNode(node, mapping);
1020
+ if (mediaStart) {
1021
+ const elseIndex = findElseIndex(filteredChain, i + 1);
1022
+ if (elseIndex !== -1) {
1023
+ if (currentNodes.length > 0) {
1024
+ parts.push({ type: "unconditional", segments: resolveChain(currentNodes, mapping) });
1025
+ currentNodes = [];
1026
+ }
1027
+ const thenNodes = mediaStart.thenNodes ? [...mediaStart.thenNodes, ...filteredChain.slice(i + 1, elseIndex)] : filteredChain.slice(i, elseIndex);
1028
+ const elseNodes = [makeMediaQueryNode(mediaStart.inverseMediaQuery), ...filteredChain.slice(elseIndex + 1)];
1029
+ const thenSegs = resolveChain(thenNodes, mapping);
1030
+ const elseSegs = resolveChain(elseNodes, mapping);
1031
+ parts.push({ type: "unconditional", segments: [...thenSegs, ...elseSegs] });
1032
+ i = filteredChain.length;
1033
+ break;
1034
+ }
1035
+ }
36
1036
  if (node.type === "if") {
37
1037
  if (node.conditionNode.type === "StringLiteral") {
38
1038
  const mediaQuery = node.conditionNode.value;
@@ -41,10 +1041,7 @@ function resolveFullChain(chain, mapping) {
41
1041
  continue;
42
1042
  }
43
1043
  if (currentNodes.length > 0) {
44
- parts.push({
45
- type: "unconditional",
46
- segments: mergeOverlappingConditions(resolveChain(currentNodes, mapping))
47
- });
1044
+ parts.push({ type: "unconditional", segments: resolveChain(currentNodes, mapping) });
48
1045
  currentNodes = [];
49
1046
  }
50
1047
  const thenNodes = [];
@@ -67,11 +1064,13 @@ function resolveFullChain(chain, mapping) {
67
1064
  }
68
1065
  i++;
69
1066
  }
1067
+ const thenSegs = resolveChain(thenNodes, mapping);
1068
+ const elseSegs = resolveChain(elseNodes, mapping);
70
1069
  parts.push({
71
1070
  type: "conditional",
72
1071
  conditionNode: node.conditionNode,
73
- thenSegments: mergeOverlappingConditions(resolveChain(thenNodes, mapping)),
74
- elseSegments: mergeOverlappingConditions(resolveChain(elseNodes, mapping))
1072
+ thenSegments: thenSegs,
1073
+ elseSegments: elseSegs
75
1074
  });
76
1075
  } else {
77
1076
  currentNodes.push(node);
@@ -79,7 +1078,7 @@ function resolveFullChain(chain, mapping) {
79
1078
  }
80
1079
  }
81
1080
  if (currentNodes.length > 0) {
82
- parts.push({ type: "unconditional", segments: mergeOverlappingConditions(resolveChain(currentNodes, mapping)) });
1081
+ parts.push({ type: "unconditional", segments: resolveChain(currentNodes, mapping) });
83
1082
  }
84
1083
  const segmentErrors = [];
85
1084
  for (const part of parts) {
@@ -92,6 +1091,53 @@ function resolveFullChain(chain, mapping) {
92
1091
  }
93
1092
  return { parts, markers, errors: [...scanErrors, ...segmentErrors] };
94
1093
  }
1094
+ function getMediaConditionalStartNode(node, mapping) {
1095
+ if (node.type === "if" && node.conditionNode.type === "StringLiteral") {
1096
+ return {
1097
+ inverseMediaQuery: invertMediaQuery(node.conditionNode.value),
1098
+ thenNodes: [makeMediaQueryNode(node.conditionNode.value)]
1099
+ };
1100
+ }
1101
+ if (node.type === "getter" && mapping.breakpoints && node.name in mapping.breakpoints) {
1102
+ return { inverseMediaQuery: invertMediaQuery(mapping.breakpoints[node.name]) };
1103
+ }
1104
+ return null;
1105
+ }
1106
+ function findElseIndex(chain, start) {
1107
+ for (let i = start; i < chain.length; i++) {
1108
+ if (chain[i].type === "if") {
1109
+ return -1;
1110
+ }
1111
+ if (chain[i].type === "else") {
1112
+ return i;
1113
+ }
1114
+ }
1115
+ return -1;
1116
+ }
1117
+ function makeMediaQueryNode(mediaQuery) {
1118
+ return { type: "__mediaQuery", mediaQuery };
1119
+ }
1120
+ function invertMediaQuery(query) {
1121
+ const screenPrefix = "@media screen and ";
1122
+ if (query.startsWith(screenPrefix)) {
1123
+ const conditions = query.slice(screenPrefix.length).trim();
1124
+ const rangeMatch = conditions.match(/^\(min-width: (\d+)px\) and \(max-width: (\d+)px\)$/);
1125
+ if (rangeMatch) {
1126
+ const min = Number(rangeMatch[1]);
1127
+ const max = Number(rangeMatch[2]);
1128
+ return `@media screen and (max-width: ${min - 1}px), screen and (min-width: ${max + 1}px)`;
1129
+ }
1130
+ const minMatch = conditions.match(/^\(min-width: (\d+)px\)$/);
1131
+ if (minMatch) {
1132
+ return `@media screen and (max-width: ${Number(minMatch[1]) - 1}px)`;
1133
+ }
1134
+ const maxMatch = conditions.match(/^\(max-width: (\d+)px\)$/);
1135
+ if (maxMatch) {
1136
+ return `@media screen and (min-width: ${Number(maxMatch[1]) + 1}px)`;
1137
+ }
1138
+ }
1139
+ return query.replace("@media", "@media not");
1140
+ }
95
1141
  function resolveChain(chain, mapping) {
96
1142
  const segments = [];
97
1143
  let currentMediaQuery = null;
@@ -139,7 +1185,14 @@ function resolveChain(chain, mapping) {
139
1185
  continue;
140
1186
  }
141
1187
  if (abbr === "add") {
142
- const seg = resolveAddCall(node, mapping, currentMediaQuery, currentPseudoClass, currentPseudoElement);
1188
+ const seg = resolveAddCall(
1189
+ node,
1190
+ mapping,
1191
+ currentMediaQuery,
1192
+ currentPseudoClass,
1193
+ currentPseudoElement,
1194
+ currentWhenPseudo
1195
+ );
143
1196
  segments.push(seg);
144
1197
  continue;
145
1198
  }
@@ -184,15 +1237,16 @@ function resolveChain(chain, mapping) {
184
1237
  if (!entry) {
185
1238
  throw new UnsupportedPatternError(`Unknown abbreviation "${abbr}"`);
186
1239
  }
187
- if (entry.kind === "dynamic") {
188
- const seg = resolveDynamicCall(
1240
+ if (entry.kind === "variable") {
1241
+ const seg = resolveVariableCall(
189
1242
  abbr,
190
1243
  entry,
191
1244
  node,
192
1245
  mapping,
193
1246
  currentMediaQuery,
194
1247
  currentPseudoClass,
195
- currentPseudoElement
1248
+ currentPseudoElement,
1249
+ currentWhenPseudo
196
1250
  );
197
1251
  segments.push(seg);
198
1252
  } else if (entry.kind === "delegate") {
@@ -203,7 +1257,8 @@ function resolveChain(chain, mapping) {
203
1257
  mapping,
204
1258
  currentMediaQuery,
205
1259
  currentPseudoClass,
206
- currentPseudoElement
1260
+ currentPseudoElement,
1261
+ currentWhenPseudo
207
1262
  );
208
1263
  segments.push(seg);
209
1264
  } else {
@@ -212,7 +1267,7 @@ function resolveChain(chain, mapping) {
212
1267
  }
213
1268
  } catch (err) {
214
1269
  if (err instanceof UnsupportedPatternError) {
215
- segments.push({ key: "__error", defs: {}, error: err.message });
1270
+ segments.push({ abbr: "__error", defs: {}, error: err.message });
216
1271
  } else {
217
1272
  throw err;
218
1273
  }
@@ -220,11 +1275,16 @@ function resolveChain(chain, mapping) {
220
1275
  }
221
1276
  return segments;
222
1277
  }
223
- function conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, breakpoints) {
1278
+ function typographyLookupKeySuffix(mediaQuery, pseudoClass, pseudoElement, breakpoints) {
224
1279
  const parts = [];
225
- if (pseudoElement) parts.push(pseudoName(pseudoElement));
226
- if (mediaQuery) parts.push(pseudoName(mediaQuery, breakpoints));
227
- if (pseudoClass) parts.push(pseudoName(pseudoClass));
1280
+ if (pseudoElement) parts.push(pseudoElement.replace(/^::/, ""));
1281
+ if (mediaQuery && breakpoints) {
1282
+ const bp = Object.entries(breakpoints).find(([, v]) => v === mediaQuery)?.[0];
1283
+ parts.push(bp ? bp.replace(/^if/, "").replace(/^./, (c) => c.toLowerCase()) : "mq");
1284
+ } else if (mediaQuery) {
1285
+ parts.push("mq");
1286
+ }
1287
+ if (pseudoClass) parts.push(pseudoClass.replace(/^:+/, "").replace(/-/g, "_"));
228
1288
  return parts.join("_");
229
1289
  }
230
1290
  function resolveTypographyCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
@@ -239,7 +1299,7 @@ function resolveTypographyCall(node, mapping, mediaQuery, pseudoClass, pseudoEle
239
1299
  if (typography.length === 0) {
240
1300
  throw new UnsupportedPatternError(`typography() is unavailable because no typography abbreviations were generated`);
241
1301
  }
242
- const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
1302
+ const suffix = typographyLookupKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
243
1303
  const lookupKey = suffix ? `typography__${suffix}` : "typography";
244
1304
  const segmentsByName = {};
245
1305
  for (const name of typography) {
@@ -247,7 +1307,7 @@ function resolveTypographyCall(node, mapping, mediaQuery, pseudoClass, pseudoEle
247
1307
  }
248
1308
  return [
249
1309
  {
250
- key: lookupKey,
1310
+ abbr: lookupKey,
251
1311
  defs: {},
252
1312
  typographyLookup: {
253
1313
  lookupKey,
@@ -267,38 +1327,19 @@ function resolveTypographyEntry(name, mapping, mediaQuery, pseudoClass, pseudoEl
267
1327
  }
268
1328
  const resolved = resolveEntry(name, entry, mapping, mediaQuery, pseudoClass, pseudoElement, null);
269
1329
  for (const segment of resolved) {
270
- if (segment.dynamicProps || segment.whenPseudo) {
1330
+ if (segment.variableProps || segment.whenPseudo) {
271
1331
  throw new UnsupportedPatternError(`Typography abbreviation "${name}" cannot require runtime arguments`);
272
1332
  }
273
1333
  }
274
1334
  return resolved;
275
1335
  }
276
- function wrapDefsWithConditions(defs, mediaQuery, pseudoClass) {
277
- if (!mediaQuery && !pseudoClass) return defs;
278
- const result = {};
279
- for (const [prop, value] of Object.entries(defs)) {
280
- if (pseudoClass && mediaQuery) {
281
- result[prop] = { default: null, [pseudoClass]: { default: null, [mediaQuery]: value } };
282
- } else if (pseudoClass) {
283
- result[prop] = { default: null, [pseudoClass]: value };
284
- } else {
285
- result[prop] = { default: null, [mediaQuery]: value };
286
- }
287
- }
288
- return result;
289
- }
290
1336
  function resolveEntry(abbr, entry, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
291
1337
  switch (entry.kind) {
292
1338
  case "static": {
293
1339
  if (whenPseudo) {
294
- const suffix2 = whenPseudoKeyName(whenPseudo);
295
- const key2 = `${abbr}__${suffix2}`;
296
- return [{ key: key2, defs: entry.defs, whenPseudo }];
1340
+ return [{ abbr, defs: entry.defs, whenPseudo }];
297
1341
  }
298
- const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
299
- const key = suffix ? `${abbr}__${suffix}` : abbr;
300
- const defs = pseudoElement ? { [pseudoElement]: wrapDefsWithConditions(entry.defs, mediaQuery, pseudoClass) } : wrapDefsWithConditions(entry.defs, mediaQuery, pseudoClass);
301
- return [{ key, defs, mediaQuery, pseudoClass, pseudoElement }];
1342
+ return [{ abbr, defs: entry.defs, mediaQuery, pseudoClass, pseudoElement }];
302
1343
  }
303
1344
  case "alias": {
304
1345
  const result = [];
@@ -311,100 +1352,93 @@ function resolveEntry(abbr, entry, mapping, mediaQuery, pseudoClass, pseudoEleme
311
1352
  }
312
1353
  return result;
313
1354
  }
314
- case "dynamic":
1355
+ case "variable":
315
1356
  case "delegate":
316
1357
  throw new UnsupportedPatternError(`Abbreviation "${abbr}" requires arguments \u2014 use ${abbr}() not .${abbr}`);
317
1358
  default:
318
1359
  throw new UnsupportedPatternError(`Unhandled entry kind for "${abbr}"`);
319
1360
  }
320
1361
  }
321
- function resolveDynamicCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
1362
+ function resolveVariableCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
322
1363
  if (node.args.length !== 1) {
323
1364
  throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
324
1365
  }
325
- const argAst = node.args[0];
326
- const literalValue = tryEvaluateLiteral(argAst, entry.incremented, mapping.increment);
327
- const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
328
- if (literalValue !== null) {
329
- const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
330
- const key = suffix ? `${abbr}__${keySuffix}__${suffix}` : `${abbr}__${keySuffix}`;
331
- const defs = {};
332
- for (const prop of entry.props) {
333
- defs[prop] = literalValue;
334
- }
335
- if (entry.extraDefs) {
336
- Object.assign(defs, entry.extraDefs);
337
- }
338
- const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
339
- return {
340
- key,
341
- defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
342
- mediaQuery,
343
- pseudoClass,
344
- pseudoElement,
345
- argResolved: literalValue
346
- };
347
- } else {
348
- const key = suffix ? `${abbr}__${suffix}` : abbr;
349
- return {
350
- key,
351
- defs: {},
352
- mediaQuery,
353
- pseudoClass,
354
- dynamicProps: entry.props,
355
- incremented: entry.incremented,
356
- dynamicExtraDefs: entry.extraDefs,
357
- argNode: argAst
358
- };
359
- }
1366
+ const literalValue = tryEvaluateLiteral(node.args[0], entry.incremented, mapping.increment);
1367
+ return buildParameterizedSegment({
1368
+ abbr,
1369
+ props: entry.props,
1370
+ incremented: entry.incremented,
1371
+ extraDefs: entry.extraDefs,
1372
+ argAst: node.args[0],
1373
+ literalValue,
1374
+ mediaQuery,
1375
+ pseudoClass,
1376
+ pseudoElement,
1377
+ whenPseudo
1378
+ });
360
1379
  }
361
- function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
1380
+ function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
362
1381
  const targetEntry = mapping.abbreviations[entry.target];
363
- if (!targetEntry || targetEntry.kind !== "dynamic") {
364
- throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a dynamic entry`);
1382
+ if (!targetEntry || targetEntry.kind !== "variable") {
1383
+ throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a variable entry`);
365
1384
  }
366
1385
  if (node.args.length !== 1) {
367
1386
  throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
368
1387
  }
369
- const argAst = node.args[0];
370
- const literalValue = tryEvaluatePxLiteral(argAst);
371
- const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
1388
+ const literalValue = tryEvaluatePxLiteral(node.args[0]);
1389
+ return buildParameterizedSegment({
1390
+ abbr: entry.target,
1391
+ props: targetEntry.props,
1392
+ incremented: false,
1393
+ appendPx: true,
1394
+ extraDefs: targetEntry.extraDefs,
1395
+ argAst: node.args[0],
1396
+ literalValue,
1397
+ mediaQuery,
1398
+ pseudoClass,
1399
+ pseudoElement,
1400
+ whenPseudo
1401
+ });
1402
+ }
1403
+ function buildParameterizedSegment(params) {
1404
+ const { abbr, props, incremented, appendPx, extraDefs, argAst, literalValue, whenPseudo } = params;
372
1405
  if (literalValue !== null) {
373
- const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
374
- const key = suffix ? `${entry.target}__${keySuffix}__${suffix}` : `${entry.target}__${keySuffix}`;
375
1406
  const defs = {};
376
- for (const prop of targetEntry.props) {
1407
+ for (const prop of props) {
377
1408
  defs[prop] = literalValue;
378
1409
  }
379
- if (targetEntry.extraDefs) {
380
- Object.assign(defs, targetEntry.extraDefs);
1410
+ if (extraDefs) Object.assign(defs, extraDefs);
1411
+ if (whenPseudo) {
1412
+ return { abbr, defs, whenPseudo, argResolved: literalValue };
381
1413
  }
382
- const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
383
1414
  return {
384
- key,
385
- defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
386
- mediaQuery,
387
- pseudoClass,
388
- pseudoElement,
1415
+ abbr,
1416
+ defs,
1417
+ mediaQuery: params.mediaQuery,
1418
+ pseudoClass: params.pseudoClass,
1419
+ pseudoElement: params.pseudoElement,
389
1420
  argResolved: literalValue
390
1421
  };
1422
+ }
1423
+ const base = {
1424
+ abbr,
1425
+ defs: {},
1426
+ variableProps: props,
1427
+ incremented,
1428
+ variableExtraDefs: extraDefs,
1429
+ argNode: argAst
1430
+ };
1431
+ if (appendPx) base.appendPx = true;
1432
+ if (whenPseudo) {
1433
+ base.whenPseudo = whenPseudo;
391
1434
  } else {
392
- const key = suffix ? `${entry.target}__${suffix}` : entry.target;
393
- return {
394
- key,
395
- defs: {},
396
- mediaQuery,
397
- pseudoClass,
398
- pseudoElement,
399
- dynamicProps: targetEntry.props,
400
- incremented: false,
401
- appendPx: true,
402
- dynamicExtraDefs: targetEntry.extraDefs,
403
- argNode: argAst
404
- };
1435
+ base.mediaQuery = params.mediaQuery;
1436
+ base.pseudoClass = params.pseudoClass;
1437
+ base.pseudoElement = params.pseudoElement;
405
1438
  }
1439
+ return base;
406
1440
  }
407
- function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
1441
+ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
408
1442
  if (node.args.length === 1) {
409
1443
  const styleArg = node.args[0];
410
1444
  if (styleArg.type === "SpreadElement") {
@@ -416,7 +1450,7 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
416
1450
  );
417
1451
  }
418
1452
  return {
419
- key: "__composed_css_prop",
1453
+ abbr: "__composed_css_prop",
420
1454
  defs: {},
421
1455
  styleArrayArg: styleArg
422
1456
  };
@@ -433,29 +1467,30 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
433
1467
  const propName = propArg.value;
434
1468
  const valueArg = node.args[1];
435
1469
  const literalValue = tryEvaluateAddLiteral(valueArg);
436
- const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
1470
+ if (whenPseudo) {
1471
+ if (literalValue !== null) {
1472
+ return { abbr: propName, defs: { [propName]: literalValue }, whenPseudo, argResolved: literalValue };
1473
+ } else {
1474
+ return { abbr: propName, defs: {}, whenPseudo, variableProps: [propName], incremented: false, argNode: valueArg };
1475
+ }
1476
+ }
437
1477
  if (literalValue !== null) {
438
- const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
439
- const key = suffix ? `add_${propName}__${keySuffix}__${suffix}` : `add_${propName}__${keySuffix}`;
440
- const defs = { [propName]: literalValue };
441
- const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
442
1478
  return {
443
- key,
444
- defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
1479
+ abbr: propName,
1480
+ defs: { [propName]: literalValue },
445
1481
  mediaQuery,
446
1482
  pseudoClass,
447
1483
  pseudoElement,
448
1484
  argResolved: literalValue
449
1485
  };
450
1486
  } else {
451
- const key = suffix ? `add_${propName}__${suffix}` : `add_${propName}`;
452
1487
  return {
453
- key,
1488
+ abbr: propName,
454
1489
  defs: {},
455
1490
  mediaQuery,
456
1491
  pseudoClass,
457
1492
  pseudoElement,
458
- dynamicProps: [propName],
1493
+ variableProps: [propName],
459
1494
  incremented: false,
460
1495
  argNode: valueArg
461
1496
  };
@@ -518,127 +1553,6 @@ function isPseudoMethod(name) {
518
1553
  function pseudoSelector(name) {
519
1554
  return PSEUDO_METHODS[name];
520
1555
  }
521
- function whenPseudoKeyName(ap) {
522
- const rel = ap.relationship ?? "ancestor";
523
- const pn = pseudoName(ap.pseudo);
524
- const base = `${rel}${pn.charAt(0).toUpperCase()}${pn.slice(1)}`;
525
- if (!ap.markerNode) return base;
526
- const suffix = ap.markerNode.type === "Identifier" ? ap.markerNode.name : "marker";
527
- return `${base}_${suffix}`;
528
- }
529
- function mergeOverlappingConditions(segments) {
530
- const propToIndices = /* @__PURE__ */ new Map();
531
- for (let i = 0; i < segments.length; i++) {
532
- const seg = segments[i];
533
- if (seg.dynamicProps || seg.styleArrayArg || seg.whenPseudo || seg.error) continue;
534
- for (const prop of Object.keys(seg.defs)) {
535
- if (!propToIndices.has(prop)) propToIndices.set(prop, []);
536
- propToIndices.get(prop).push(i);
537
- }
538
- }
539
- const mergeableProps = /* @__PURE__ */ new Set();
540
- for (const [prop, indices] of propToIndices) {
541
- if (indices.length < 2) continue;
542
- const hasBase = indices.some((i) => !segments[i].mediaQuery && !segments[i].pseudoClass);
543
- const hasConditional = indices.some((i) => !!(segments[i].mediaQuery || segments[i].pseudoClass));
544
- if (hasBase && hasConditional) {
545
- mergeableProps.add(prop);
546
- }
547
- }
548
- if (mergeableProps.size === 0) return segments;
549
- const consumedProps = /* @__PURE__ */ new Map();
550
- const mergedPropDefs = /* @__PURE__ */ new Map();
551
- for (const prop of mergeableProps) {
552
- const indices = propToIndices.get(prop);
553
- let merged = {};
554
- const keyParts = [];
555
- for (const idx of indices) {
556
- const seg = segments[idx];
557
- const value = seg.defs[prop];
558
- keyParts.push(seg.key);
559
- if (typeof value === "string" || typeof value === "number") {
560
- merged.default = value;
561
- } else if (typeof value === "object" && value !== null) {
562
- for (const [k, v] of Object.entries(value)) {
563
- if (k === "default" && v === null && merged.default !== void 0) {
564
- continue;
565
- }
566
- merged[k] = v;
567
- }
568
- }
569
- if (!consumedProps.has(idx)) consumedProps.set(idx, /* @__PURE__ */ new Set());
570
- consumedProps.get(idx).add(prop);
571
- }
572
- const finalValue = Object.keys(merged).length === 1 && "default" in merged ? merged.default : merged;
573
- const mergedKey = [...new Set(keyParts)].join("_");
574
- mergedPropDefs.set(prop, { defs: { [prop]: finalValue }, key: mergedKey });
575
- }
576
- const groupByIndices = /* @__PURE__ */ new Map();
577
- for (const prop of mergeableProps) {
578
- const indices = propToIndices.get(prop);
579
- const groupKey = indices.join(",");
580
- if (!groupByIndices.has(groupKey)) {
581
- groupByIndices.set(groupKey, { props: [], key: mergedPropDefs.get(prop).key });
582
- }
583
- groupByIndices.get(groupKey).props.push(prop);
584
- }
585
- const mergedSegments = [];
586
- for (const [, group] of groupByIndices) {
587
- const defs = {};
588
- for (const prop of group.props) {
589
- Object.assign(defs, mergedPropDefs.get(prop).defs);
590
- }
591
- mergedSegments.push({ key: group.key, defs });
592
- }
593
- const result = [];
594
- const mergedEmitted = /* @__PURE__ */ new Set();
595
- for (let i = 0; i < segments.length; i++) {
596
- const seg = segments[i];
597
- const consumed = consumedProps.get(i);
598
- if (!consumed) {
599
- result.push(seg);
600
- continue;
601
- }
602
- const remainingDefs = {};
603
- for (const [prop, value] of Object.entries(seg.defs)) {
604
- if (!consumed.has(prop)) {
605
- remainingDefs[prop] = value;
606
- }
607
- }
608
- if (Object.keys(remainingDefs).length > 0) {
609
- result.push({ ...seg, defs: remainingDefs });
610
- }
611
- const indices = [...propToIndices.entries()].filter(([prop]) => consumed.has(prop) && mergeableProps.has(prop)).map(([, idxs]) => idxs.join(","));
612
- for (const groupKey of new Set(indices)) {
613
- if (!mergedEmitted.has(groupKey)) {
614
- const group = groupByIndices.get(groupKey);
615
- if (group) {
616
- const defs = {};
617
- for (const prop of group.props) {
618
- Object.assign(defs, mergedPropDefs.get(prop).defs);
619
- }
620
- result.push({ key: group.key, defs });
621
- mergedEmitted.add(groupKey);
622
- }
623
- }
624
- }
625
- }
626
- return result;
627
- }
628
- function pseudoName(pseudo, breakpoints) {
629
- if (pseudo.startsWith("@media") && breakpoints) {
630
- for (const [getterName, mediaQuery] of Object.entries(breakpoints)) {
631
- if (mediaQuery === pseudo) {
632
- return getterName.replace(/^if/, "").replace(/^./, (c) => c.toLowerCase());
633
- }
634
- }
635
- return pseudo.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
636
- }
637
- if (pseudo.startsWith("@container")) {
638
- return pseudo.replace(/^@container\s*/, "container ").replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
639
- }
640
- return pseudo.replace(/^:+/, "").replace(/-/g, "_");
641
- }
642
1556
  function tryEvaluateLiteral(node, incremented, increment) {
643
1557
  if (node.type === "NumericLiteral") {
644
1558
  if (incremented) {
@@ -746,44 +1660,44 @@ var UnsupportedPatternError = class extends Error {
746
1660
  };
747
1661
 
748
1662
  // src/plugin/ast-utils.ts
749
- import * as t from "@babel/types";
1663
+ import * as t2 from "@babel/types";
750
1664
  function collectTopLevelBindings(ast) {
751
1665
  const used = /* @__PURE__ */ new Set();
752
1666
  for (const node of ast.program.body) {
753
- if (t.isImportDeclaration(node)) {
1667
+ if (t2.isImportDeclaration(node)) {
754
1668
  for (const spec of node.specifiers) {
755
1669
  used.add(spec.local.name);
756
1670
  }
757
1671
  continue;
758
1672
  }
759
- if (t.isVariableDeclaration(node)) {
1673
+ if (t2.isVariableDeclaration(node)) {
760
1674
  for (const decl of node.declarations) {
761
1675
  collectPatternBindings(decl.id, used);
762
1676
  }
763
1677
  continue;
764
1678
  }
765
- if (t.isFunctionDeclaration(node) && node.id) {
1679
+ if (t2.isFunctionDeclaration(node) && node.id) {
766
1680
  used.add(node.id.name);
767
1681
  continue;
768
1682
  }
769
- if (t.isClassDeclaration(node) && node.id) {
1683
+ if (t2.isClassDeclaration(node) && node.id) {
770
1684
  used.add(node.id.name);
771
1685
  continue;
772
1686
  }
773
- if (t.isExportNamedDeclaration(node) && node.declaration) {
1687
+ if (t2.isExportNamedDeclaration(node) && node.declaration) {
774
1688
  const decl = node.declaration;
775
- if (t.isVariableDeclaration(decl)) {
1689
+ if (t2.isVariableDeclaration(decl)) {
776
1690
  for (const varDecl of decl.declarations) {
777
1691
  collectPatternBindings(varDecl.id, used);
778
1692
  }
779
- } else if ((t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) && decl.id) {
1693
+ } else if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
780
1694
  used.add(decl.id.name);
781
1695
  }
782
1696
  continue;
783
1697
  }
784
- if (t.isExportDefaultDeclaration(node)) {
1698
+ if (t2.isExportDefaultDeclaration(node)) {
785
1699
  const decl = node.declaration;
786
- if ((t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) && decl.id) {
1700
+ if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
787
1701
  used.add(decl.id.name);
788
1702
  }
789
1703
  }
@@ -791,37 +1705,37 @@ function collectTopLevelBindings(ast) {
791
1705
  return used;
792
1706
  }
793
1707
  function collectPatternBindings(pattern, used) {
794
- if (t.isVoidPattern(pattern)) {
1708
+ if (t2.isVoidPattern(pattern)) {
795
1709
  return;
796
1710
  }
797
- if (t.isIdentifier(pattern)) {
1711
+ if (t2.isIdentifier(pattern)) {
798
1712
  used.add(pattern.name);
799
1713
  return;
800
1714
  }
801
- if (t.isAssignmentPattern(pattern)) {
1715
+ if (t2.isAssignmentPattern(pattern)) {
802
1716
  collectPatternBindings(pattern.left, used);
803
1717
  return;
804
1718
  }
805
- if (t.isRestElement(pattern)) {
1719
+ if (t2.isRestElement(pattern)) {
806
1720
  collectPatternBindings(pattern.argument, used);
807
1721
  return;
808
1722
  }
809
- if (t.isObjectPattern(pattern)) {
1723
+ if (t2.isObjectPattern(pattern)) {
810
1724
  for (const prop of pattern.properties) {
811
- if (t.isObjectProperty(prop)) {
1725
+ if (t2.isObjectProperty(prop)) {
812
1726
  collectPatternBindings(prop.value, used);
813
- } else if (t.isRestElement(prop)) {
1727
+ } else if (t2.isRestElement(prop)) {
814
1728
  collectPatternBindings(prop.argument, used);
815
1729
  }
816
1730
  }
817
1731
  return;
818
1732
  }
819
- if (t.isArrayPattern(pattern)) {
1733
+ if (t2.isArrayPattern(pattern)) {
820
1734
  for (const el of pattern.elements) {
821
1735
  if (!el) continue;
822
- if (t.isIdentifier(el) || t.isAssignmentPattern(el) || t.isObjectPattern(el) || t.isArrayPattern(el)) {
1736
+ if (t2.isIdentifier(el) || t2.isAssignmentPattern(el) || t2.isObjectPattern(el) || t2.isArrayPattern(el)) {
823
1737
  collectPatternBindings(el, used);
824
- } else if (t.isRestElement(el)) {
1738
+ } else if (t2.isRestElement(el)) {
825
1739
  collectPatternBindings(el.argument, used);
826
1740
  }
827
1741
  }
@@ -848,9 +1762,9 @@ function reservePreferredName(used, preferred, secondary) {
848
1762
  }
849
1763
  function findCssImportBinding(ast) {
850
1764
  for (const node of ast.program.body) {
851
- if (!t.isImportDeclaration(node)) continue;
1765
+ if (!t2.isImportDeclaration(node)) continue;
852
1766
  for (const spec of node.specifiers) {
853
- if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: "Css" })) {
1767
+ if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: "Css" })) {
854
1768
  return spec.local.name;
855
1769
  }
856
1770
  }
@@ -859,9 +1773,9 @@ function findCssImportBinding(ast) {
859
1773
  }
860
1774
  function hasCssMethodCall(ast, binding, method) {
861
1775
  let found = false;
862
- t.traverseFast(ast, (node) => {
1776
+ t2.traverseFast(ast, (node) => {
863
1777
  if (found) return;
864
- if (t.isCallExpression(node) && t.isMemberExpression(node.callee) && !node.callee.computed && t.isIdentifier(node.callee.object, { name: binding }) && t.isIdentifier(node.callee.property, { name: method })) {
1778
+ if (t2.isCallExpression(node) && t2.isMemberExpression(node.callee) && !node.callee.computed && t2.isIdentifier(node.callee.object, { name: binding }) && t2.isIdentifier(node.callee.property, { name: method })) {
865
1779
  found = true;
866
1780
  }
867
1781
  });
@@ -870,8 +1784,8 @@ function hasCssMethodCall(ast, binding, method) {
870
1784
  function removeCssImport(ast, cssBinding) {
871
1785
  for (let i = 0; i < ast.program.body.length; i++) {
872
1786
  const node = ast.program.body[i];
873
- if (!t.isImportDeclaration(node)) continue;
874
- const cssSpecIndex = node.specifiers.findIndex((s) => t.isImportSpecifier(s) && s.local.name === cssBinding);
1787
+ if (!t2.isImportDeclaration(node)) continue;
1788
+ const cssSpecIndex = node.specifiers.findIndex((s) => t2.isImportSpecifier(s) && s.local.name === cssBinding);
875
1789
  if (cssSpecIndex === -1) continue;
876
1790
  if (node.specifiers.length === 1) {
877
1791
  ast.program.body.splice(i, 1);
@@ -881,64 +1795,67 @@ function removeCssImport(ast, cssBinding) {
881
1795
  return;
882
1796
  }
883
1797
  }
884
- function findStylexNamespaceImport(ast) {
885
- for (const node of ast.program.body) {
886
- if (!t.isImportDeclaration(node)) continue;
887
- if (node.source.value !== "@stylexjs/stylex") continue;
888
- for (const spec of node.specifiers) {
889
- if (t.isImportNamespaceSpecifier(spec)) {
890
- return spec.local.name;
891
- }
892
- }
893
- }
894
- return null;
895
- }
896
1798
  function findLastImportIndex(ast) {
897
1799
  let lastImportIndex = -1;
898
1800
  for (let i = 0; i < ast.program.body.length; i++) {
899
- if (t.isImportDeclaration(ast.program.body[i])) {
1801
+ if (t2.isImportDeclaration(ast.program.body[i])) {
900
1802
  lastImportIndex = i;
901
1803
  }
902
1804
  }
903
1805
  return lastImportIndex;
904
1806
  }
905
- function insertStylexNamespaceImport(ast, localName) {
906
- const stylexImport = t.importDeclaration(
907
- [t.importNamespaceSpecifier(t.identifier(localName))],
908
- t.stringLiteral("@stylexjs/stylex")
909
- );
910
- const idx = findLastImportIndex(ast);
911
- ast.program.body.splice(idx + 1, 0, stylexImport);
912
- }
913
1807
  function findNamedImportBinding(ast, source, importedName) {
914
1808
  for (const node of ast.program.body) {
915
- if (!t.isImportDeclaration(node) || node.source.value !== source) continue;
1809
+ if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
916
1810
  for (const spec of node.specifiers) {
917
- if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: importedName })) {
1811
+ if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: importedName })) {
918
1812
  return spec.local.name;
919
1813
  }
920
1814
  }
921
1815
  }
922
1816
  return null;
923
1817
  }
1818
+ function findImportDeclaration(ast, source) {
1819
+ for (const node of ast.program.body) {
1820
+ if (t2.isImportDeclaration(node) && node.source.value === source) {
1821
+ return node;
1822
+ }
1823
+ }
1824
+ return null;
1825
+ }
1826
+ function replaceCssImportWithNamedImports(ast, cssBinding, source, imports) {
1827
+ for (const node of ast.program.body) {
1828
+ if (!t2.isImportDeclaration(node)) continue;
1829
+ const cssSpecIndex = node.specifiers.findIndex(function(spec) {
1830
+ return t2.isImportSpecifier(spec) && spec.local.name === cssBinding;
1831
+ });
1832
+ if (cssSpecIndex === -1 || node.specifiers.length !== 1) continue;
1833
+ node.source = t2.stringLiteral(source);
1834
+ node.specifiers = imports.map(function(entry) {
1835
+ return t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName));
1836
+ });
1837
+ return true;
1838
+ }
1839
+ return false;
1840
+ }
924
1841
  function upsertNamedImports(ast, source, imports) {
925
1842
  if (imports.length === 0) return;
926
1843
  for (const node of ast.program.body) {
927
- if (!t.isImportDeclaration(node) || node.source.value !== source) continue;
1844
+ if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
928
1845
  for (const entry of imports) {
929
1846
  const exists = node.specifiers.some(function(spec) {
930
- return t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: entry.importedName });
1847
+ return t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: entry.importedName });
931
1848
  });
932
1849
  if (exists) continue;
933
- node.specifiers.push(t.importSpecifier(t.identifier(entry.localName), t.identifier(entry.importedName)));
1850
+ node.specifiers.push(t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName)));
934
1851
  }
935
1852
  return;
936
1853
  }
937
- const importDecl = t.importDeclaration(
1854
+ const importDecl = t2.importDeclaration(
938
1855
  imports.map(function(entry) {
939
- return t.importSpecifier(t.identifier(entry.localName), t.identifier(entry.importedName));
1856
+ return t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName));
940
1857
  }),
941
- t.stringLiteral(source)
1858
+ t2.stringLiteral(source)
942
1859
  );
943
1860
  const idx = findLastImportIndex(ast);
944
1861
  ast.program.body.splice(idx + 1, 0, importDecl);
@@ -947,11 +1864,11 @@ function extractChain(node, cssBinding) {
947
1864
  const chain = [];
948
1865
  let current = node;
949
1866
  while (true) {
950
- if (t.isIdentifier(current, { name: cssBinding })) {
1867
+ if (t2.isIdentifier(current, { name: cssBinding })) {
951
1868
  chain.reverse();
952
1869
  return chain;
953
1870
  }
954
- if (t.isMemberExpression(current) && !current.computed && t.isIdentifier(current.property)) {
1871
+ if (t2.isMemberExpression(current) && !current.computed && t2.isIdentifier(current.property)) {
955
1872
  const name = current.property.name;
956
1873
  if (name === "else") {
957
1874
  chain.push({ type: "else" });
@@ -961,7 +1878,7 @@ function extractChain(node, cssBinding) {
961
1878
  current = current.object;
962
1879
  continue;
963
1880
  }
964
- if (t.isCallExpression(current) && t.isMemberExpression(current.callee) && !current.callee.computed && t.isIdentifier(current.callee.property)) {
1881
+ if (t2.isCallExpression(current) && t2.isMemberExpression(current.callee) && !current.callee.computed && t2.isIdentifier(current.callee.property)) {
965
1882
  const name = current.callee.property.name;
966
1883
  if (name === "if") {
967
1884
  chain.push({
@@ -983,328 +1900,28 @@ function extractChain(node, cssBinding) {
983
1900
  }
984
1901
  }
985
1902
 
986
- // src/plugin/emit-stylex.ts
987
- import * as t2 from "@babel/types";
988
- function collectCreateData(chains) {
989
- const createEntries = /* @__PURE__ */ new Map();
990
- const runtimeLookups = /* @__PURE__ */ new Map();
991
- let needsMaybeInc = false;
992
- for (const chain of chains) {
993
- for (const part of chain.parts) {
994
- const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
995
- for (const seg of segs) {
996
- if (seg.error) continue;
997
- if (seg.typographyLookup) {
998
- collectTypographyLookup(createEntries, runtimeLookups, seg);
999
- continue;
1000
- }
1001
- if (seg.styleArrayArg) {
1002
- continue;
1003
- }
1004
- if (seg.dynamicProps) {
1005
- if (!createEntries.has(seg.key)) {
1006
- createEntries.set(seg.key, {
1007
- key: seg.key,
1008
- dynamic: {
1009
- props: seg.dynamicProps,
1010
- extraDefs: seg.dynamicExtraDefs,
1011
- mediaQuery: seg.mediaQuery,
1012
- pseudoClass: seg.pseudoClass,
1013
- pseudoElement: seg.pseudoElement
1014
- }
1015
- });
1016
- }
1017
- } else {
1018
- if (!createEntries.has(seg.key)) {
1019
- createEntries.set(seg.key, {
1020
- key: seg.key,
1021
- defs: seg.defs,
1022
- whenPseudo: seg.whenPseudo
1023
- });
1024
- }
1025
- }
1026
- if (seg.incremented && seg.dynamicProps) {
1027
- needsMaybeInc = true;
1028
- }
1029
- }
1030
- }
1031
- }
1032
- return { createEntries, runtimeLookups, needsMaybeInc };
1033
- }
1034
- function collectTypographyLookup(createEntries, runtimeLookups, seg) {
1035
- const lookup = seg.typographyLookup;
1036
- if (!lookup) return;
1037
- if (!runtimeLookups.has(lookup.lookupKey)) {
1038
- runtimeLookups.set(lookup.lookupKey, {
1039
- lookupKey: lookup.lookupKey,
1040
- refsByName: Object.fromEntries(
1041
- Object.entries(lookup.segmentsByName).map(function([name, segments]) {
1042
- return [
1043
- name,
1044
- segments.map(function(segment) {
1045
- return segment.key;
1046
- })
1047
- ];
1048
- })
1049
- )
1050
- });
1051
- }
1052
- for (const segments of Object.values(lookup.segmentsByName)) {
1053
- for (const segment of segments) {
1054
- if (createEntries.has(segment.key)) continue;
1055
- createEntries.set(segment.key, {
1056
- key: segment.key,
1057
- defs: segment.defs,
1058
- whenPseudo: segment.whenPseudo
1059
- });
1060
- }
1061
- }
1062
- }
1063
- function buildCreateProperties(createEntries, stylexNamespaceName) {
1064
- const createProperties = [];
1065
- for (const [, entry] of createEntries) {
1066
- if (entry.dynamic) {
1067
- const paramId = t2.identifier("v");
1068
- const bodyProps = [];
1069
- const { mediaQuery, pseudoClass } = entry.dynamic;
1070
- for (const prop of entry.dynamic.props) {
1071
- if (pseudoClass && mediaQuery) {
1072
- bodyProps.push(
1073
- t2.objectProperty(
1074
- toPropertyKey(prop),
1075
- t2.objectExpression([
1076
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1077
- t2.objectProperty(
1078
- t2.stringLiteral(pseudoClass),
1079
- t2.objectExpression([
1080
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1081
- t2.objectProperty(t2.stringLiteral(mediaQuery), paramId)
1082
- ])
1083
- )
1084
- ])
1085
- )
1086
- );
1087
- } else if (pseudoClass || mediaQuery) {
1088
- const condition = pseudoClass || mediaQuery;
1089
- bodyProps.push(
1090
- t2.objectProperty(
1091
- toPropertyKey(prop),
1092
- t2.objectExpression([
1093
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1094
- t2.objectProperty(t2.stringLiteral(condition), paramId)
1095
- ])
1096
- )
1097
- );
1098
- } else {
1099
- bodyProps.push(t2.objectProperty(toPropertyKey(prop), paramId));
1100
- }
1101
- }
1102
- if (entry.dynamic.extraDefs) {
1103
- for (const [prop, value] of Object.entries(entry.dynamic.extraDefs)) {
1104
- if (pseudoClass && mediaQuery) {
1105
- bodyProps.push(
1106
- t2.objectProperty(
1107
- toPropertyKey(prop),
1108
- t2.objectExpression([
1109
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1110
- t2.objectProperty(
1111
- t2.stringLiteral(pseudoClass),
1112
- t2.objectExpression([
1113
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1114
- t2.objectProperty(t2.stringLiteral(mediaQuery), valueToAst(value))
1115
- ])
1116
- )
1117
- ])
1118
- )
1119
- );
1120
- } else if (pseudoClass || mediaQuery) {
1121
- const condition = pseudoClass || mediaQuery;
1122
- bodyProps.push(
1123
- t2.objectProperty(
1124
- toPropertyKey(prop),
1125
- t2.objectExpression([
1126
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1127
- t2.objectProperty(t2.stringLiteral(condition), valueToAst(value))
1128
- ])
1129
- )
1130
- );
1131
- } else {
1132
- bodyProps.push(t2.objectProperty(toPropertyKey(prop), valueToAst(value)));
1133
- }
1134
- }
1135
- }
1136
- let bodyExpr = t2.objectExpression(bodyProps);
1137
- if (entry.dynamic.pseudoElement) {
1138
- bodyExpr = t2.objectExpression([t2.objectProperty(t2.stringLiteral(entry.dynamic.pseudoElement), bodyExpr)]);
1139
- }
1140
- const arrowFn = t2.arrowFunctionExpression([paramId], bodyExpr);
1141
- createProperties.push(t2.objectProperty(toPropertyKey(entry.key), arrowFn));
1142
- continue;
1143
- }
1144
- if (entry.whenPseudo && entry.defs) {
1145
- const ap = entry.whenPseudo;
1146
- const props = [];
1147
- for (const [prop, value] of Object.entries(entry.defs)) {
1148
- const whenCallArgs = [t2.stringLiteral(ap.pseudo)];
1149
- if (ap.markerNode) {
1150
- whenCallArgs.push(ap.markerNode);
1151
- }
1152
- const relationship = ap.relationship ?? "ancestor";
1153
- const whenCall = t2.callExpression(
1154
- t2.memberExpression(
1155
- t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("when")),
1156
- t2.identifier(relationship)
1157
- ),
1158
- whenCallArgs
1159
- );
1160
- props.push(
1161
- t2.objectProperty(
1162
- toPropertyKey(prop),
1163
- t2.objectExpression([
1164
- t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1165
- t2.objectProperty(whenCall, valueToAst(value), true)
1166
- ])
1167
- )
1168
- );
1169
- }
1170
- createProperties.push(t2.objectProperty(toPropertyKey(entry.key), t2.objectExpression(props)));
1171
- continue;
1172
- }
1173
- if (entry.defs) {
1174
- createProperties.push(t2.objectProperty(toPropertyKey(entry.key), defsToAst(entry.defs)));
1175
- }
1176
- }
1177
- return createProperties;
1178
- }
1179
- function buildMaybeIncDeclaration(helperName, increment) {
1180
- const incParam = t2.identifier("inc");
1181
- const body = t2.blockStatement([
1182
- t2.returnStatement(
1183
- t2.conditionalExpression(
1184
- t2.binaryExpression("===", t2.unaryExpression("typeof", incParam), t2.stringLiteral("string")),
1185
- incParam,
1186
- t2.templateLiteral(
1187
- [t2.templateElement({ raw: "", cooked: "" }, false), t2.templateElement({ raw: "px", cooked: "px" }, true)],
1188
- [t2.binaryExpression("*", incParam, t2.numericLiteral(increment))]
1189
- )
1190
- )
1191
- )
1192
- ]);
1193
- return t2.variableDeclaration("const", [
1194
- t2.variableDeclarator(t2.identifier(helperName), t2.arrowFunctionExpression([incParam], body))
1195
- ]);
1196
- }
1197
- function buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties) {
1198
- const createCall = t2.callExpression(t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("create")), [
1199
- t2.objectExpression(createProperties)
1200
- ]);
1201
- return t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(createVarName), createCall)]);
1202
- }
1203
- function buildRuntimeLookupDeclaration(lookupName, createVarName, lookup) {
1204
- const properties = [];
1205
- for (const [name, refs] of Object.entries(lookup.refsByName)) {
1206
- const values = refs.map(function(refKey) {
1207
- return t2.memberExpression(t2.identifier(createVarName), t2.identifier(refKey));
1208
- });
1209
- properties.push(t2.objectProperty(toPropertyKey(name), t2.arrayExpression(values)));
1210
- }
1211
- return t2.variableDeclaration("const", [
1212
- t2.variableDeclarator(t2.identifier(lookupName), t2.objectExpression(properties))
1213
- ]);
1214
- }
1215
- function defsToAst(defs) {
1216
- const properties = [];
1217
- for (const [key, value] of Object.entries(defs)) {
1218
- const keyNode = toPropertyKey(key);
1219
- if (value === null) {
1220
- properties.push(t2.objectProperty(keyNode, t2.nullLiteral()));
1221
- } else if (typeof value === "string") {
1222
- properties.push(t2.objectProperty(keyNode, t2.stringLiteral(value)));
1223
- } else if (typeof value === "number") {
1224
- properties.push(t2.objectProperty(keyNode, t2.numericLiteral(value)));
1225
- } else if (typeof value === "object") {
1226
- properties.push(t2.objectProperty(keyNode, defsToAst(value)));
1227
- }
1228
- }
1229
- return t2.objectExpression(properties);
1230
- }
1231
- function valueToAst(value) {
1232
- if (value === null) return t2.nullLiteral();
1233
- if (typeof value === "string") return t2.stringLiteral(value);
1234
- if (typeof value === "number") return t2.numericLiteral(value);
1235
- if (typeof value === "object") return defsToAst(value);
1236
- return t2.stringLiteral(String(value));
1237
- }
1238
- function toPropertyKey(key) {
1239
- return isValidIdentifier(key) ? t2.identifier(key) : t2.stringLiteral(key);
1240
- }
1241
- function isValidIdentifier(s) {
1242
- return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
1243
- }
1244
-
1245
1903
  // src/plugin/rewrite-sites.ts
1246
1904
  import _traverse from "@babel/traverse";
1247
1905
  import _generate from "@babel/generator";
1248
1906
  import * as t3 from "@babel/types";
1249
1907
  var generate = _generate.default ?? _generate;
1250
1908
  var traverse = _traverse.default ?? _traverse;
1251
- function formatDroppedPropertyKey(prop) {
1252
- if (t3.isObjectProperty(prop)) {
1253
- if (t3.isIdentifier(prop.key)) return prop.key.name;
1254
- if (t3.isStringLiteral(prop.key)) return prop.key.value;
1255
- }
1256
- return formatNodeSnippet(prop);
1257
- }
1258
1909
  function rewriteExpressionSites(options) {
1259
1910
  for (const site of options.sites) {
1260
- const propsArgs = buildPropsArgsFromChain(site.resolvedChain, options);
1911
+ const styleHash = buildStyleHashFromChain(site.resolvedChain, options);
1261
1912
  const cssAttrPath = getCssAttributePath(site.path);
1913
+ const line = site.path.node.loc?.start.line ?? null;
1262
1914
  if (cssAttrPath) {
1263
- cssAttrPath.replaceWith(
1264
- t3.jsxSpreadAttribute(
1265
- buildCssSpreadExpression(
1266
- cssAttrPath,
1267
- propsArgs,
1268
- site.path.node.loc?.start.line ?? null,
1269
- options.mergePropsHelperName,
1270
- options.needsMergePropsHelper,
1271
- options
1272
- )
1273
- )
1274
- );
1275
- continue;
1915
+ cssAttrPath.replaceWith(t3.jsxSpreadAttribute(buildCssSpreadExpression(cssAttrPath, styleHash, line, options)));
1916
+ } else {
1917
+ if (options.debug && line !== null) {
1918
+ injectDebugInfo(styleHash, line, options);
1919
+ }
1920
+ site.path.replaceWith(styleHash);
1276
1921
  }
1277
- site.path.replaceWith(buildStyleArrayExpression(propsArgs, site.path.node.loc?.start.line ?? null, options));
1278
1922
  }
1279
1923
  rewriteCssPropsCalls(options);
1280
- rewriteCssSpreadCalls(
1281
- options.ast,
1282
- options.cssBindingName,
1283
- options.asStyleArrayHelperName,
1284
- options.needsAsStyleArrayHelper
1285
- );
1286
- rewriteStyleObjectExpressions(
1287
- options.ast,
1288
- options.skippedCssPropMessages,
1289
- options.asStyleArrayHelperName,
1290
- options.needsAsStyleArrayHelper
1291
- );
1292
- normalizeMixedStyleTernaries(options.ast);
1293
- rewriteCssAttributeExpressions(
1294
- options.ast,
1295
- options.filename,
1296
- options.debug,
1297
- options.stylexNamespaceName,
1298
- options.mergePropsHelperName,
1299
- options.needsMergePropsHelper,
1300
- options.trussPropsHelperName,
1301
- options.needsTrussPropsHelper,
1302
- options.trussDebugInfoName,
1303
- options.needsTrussDebugInfo,
1304
- options.asStyleArrayHelperName,
1305
- options.needsAsStyleArrayHelper,
1306
- options.skippedCssPropMessages
1307
- );
1924
+ rewriteCssAttributeExpressions(options);
1308
1925
  }
1309
1926
  function getCssAttributePath(path) {
1310
1927
  const parentPath = path.parentPath;
@@ -1314,312 +1931,229 @@ function getCssAttributePath(path) {
1314
1931
  if (!t3.isJSXIdentifier(attrPath.node.name, { name: "css" })) return null;
1315
1932
  return attrPath;
1316
1933
  }
1317
- function buildPropsArgsFromChain(chain, options) {
1318
- const args = [];
1319
- for (const marker of chain.markers) {
1320
- if (marker.markerNode) {
1321
- args.push(marker.markerNode);
1322
- } else {
1323
- args.push(
1324
- t3.callExpression(
1325
- t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("defaultMarker")),
1326
- []
1327
- )
1328
- );
1329
- }
1934
+ function buildStyleHashFromChain(chain, options) {
1935
+ const members = [];
1936
+ const previousProperties = /* @__PURE__ */ new Map();
1937
+ if (chain.markers.length > 0) {
1938
+ const markerClasses = chain.markers.map(function(marker) {
1939
+ return markerClassName(marker.markerNode);
1940
+ });
1941
+ members.push(t3.objectProperty(t3.identifier("__marker"), t3.stringLiteral(markerClasses.join(" "))));
1330
1942
  }
1331
1943
  for (const part of chain.parts) {
1332
1944
  if (part.type === "unconditional") {
1333
- args.push(...buildPropsArgs(part.segments, options));
1334
- continue;
1335
- }
1336
- const thenArgs = buildPropsArgs(part.thenSegments, options);
1337
- const elseArgs = buildPropsArgs(part.elseSegments, options);
1338
- if (thenArgs.length === 1 && elseArgs.length === 1 && !t3.isSpreadElement(thenArgs[0]) && !t3.isSpreadElement(elseArgs[0])) {
1339
- args.push(t3.conditionalExpression(part.conditionNode, thenArgs[0], elseArgs[0]));
1340
- } else if (thenArgs.length > 0 || elseArgs.length > 0) {
1341
- args.push(
1945
+ const partMembers = buildStyleHashMembers(part.segments, options);
1946
+ members.push(...partMembers);
1947
+ for (const member of partMembers) {
1948
+ if (t3.isObjectProperty(member)) {
1949
+ previousProperties.set(propertyName(member.key), member);
1950
+ }
1951
+ }
1952
+ } else {
1953
+ const thenMembers = mergeConditionalBranchMembers(
1954
+ buildStyleHashMembers(part.thenSegments, options),
1955
+ previousProperties,
1956
+ collectConditionalOnlyProps(part.thenSegments)
1957
+ );
1958
+ const elseMembers = mergeConditionalBranchMembers(
1959
+ buildStyleHashMembers(part.elseSegments, options),
1960
+ previousProperties,
1961
+ collectConditionalOnlyProps(part.elseSegments)
1962
+ );
1963
+ members.push(
1342
1964
  t3.spreadElement(
1343
- t3.conditionalExpression(part.conditionNode, t3.arrayExpression(thenArgs), t3.arrayExpression(elseArgs))
1965
+ t3.conditionalExpression(part.conditionNode, t3.objectExpression(thenMembers), t3.objectExpression(elseMembers))
1344
1966
  )
1345
1967
  );
1346
1968
  }
1347
1969
  }
1348
- return args;
1970
+ return t3.objectExpression(members);
1349
1971
  }
1350
- function buildPropsArgs(segments, options) {
1351
- const args = [];
1972
+ function buildStyleHashMembers(segments, options) {
1973
+ const members = [];
1974
+ const normalSegs = [];
1975
+ function flushNormal() {
1976
+ if (normalSegs.length > 0) {
1977
+ members.push(...buildStyleHashProperties(normalSegs, options.mapping, options.maybeIncHelperName));
1978
+ normalSegs.length = 0;
1979
+ }
1980
+ }
1352
1981
  for (const seg of segments) {
1353
1982
  if (seg.error) continue;
1354
- if (seg.typographyLookup) {
1355
- const lookupName = options.runtimeLookupNames.get(seg.typographyLookup.lookupKey);
1356
- if (!lookupName) {
1357
- continue;
1358
- }
1359
- const lookupAccess = t3.memberExpression(
1360
- t3.identifier(lookupName),
1361
- seg.typographyLookup.argNode,
1362
- true
1363
- );
1364
- args.push(t3.spreadElement(t3.logicalExpression("??", lookupAccess, t3.arrayExpression([]))));
1365
- continue;
1366
- }
1367
1983
  if (seg.styleArrayArg) {
1368
- args.push(
1369
- t3.spreadElement(
1370
- buildUnknownSpreadFallback(
1371
- seg.styleArrayArg,
1372
- options.asStyleArrayHelperName,
1373
- options.needsAsStyleArrayHelper
1374
- )
1375
- )
1376
- );
1984
+ flushNormal();
1985
+ members.push(t3.spreadElement(seg.styleArrayArg));
1377
1986
  continue;
1378
1987
  }
1379
- const ref = t3.memberExpression(t3.identifier(options.createVarName), t3.identifier(seg.key));
1380
- if (seg.dynamicProps && seg.argNode) {
1381
- let argExpr;
1382
- if (seg.incremented && options.maybeIncHelperName) {
1383
- argExpr = t3.callExpression(t3.identifier(options.maybeIncHelperName), [seg.argNode]);
1384
- } else if (seg.incremented) {
1385
- argExpr = seg.argNode;
1386
- } else if (seg.appendPx) {
1387
- argExpr = t3.binaryExpression(
1388
- "+",
1389
- t3.callExpression(t3.identifier("String"), [seg.argNode]),
1390
- t3.stringLiteral("px")
1988
+ if (seg.typographyLookup) {
1989
+ flushNormal();
1990
+ const lookupName = options.runtimeLookupNames.get(seg.typographyLookup.lookupKey);
1991
+ if (lookupName) {
1992
+ const lookupAccess = t3.memberExpression(
1993
+ t3.identifier(lookupName),
1994
+ seg.typographyLookup.argNode,
1995
+ true
1391
1996
  );
1392
- } else {
1393
- argExpr = t3.callExpression(t3.identifier("String"), [seg.argNode]);
1997
+ members.push(t3.spreadElement(t3.logicalExpression("??", lookupAccess, t3.objectExpression([]))));
1394
1998
  }
1395
- args.push(t3.callExpression(ref, [argExpr]));
1396
- } else {
1397
- args.push(ref);
1999
+ continue;
1398
2000
  }
2001
+ normalSegs.push(seg);
1399
2002
  }
1400
- return args;
2003
+ flushNormal();
2004
+ return members;
1401
2005
  }
1402
- function rewriteCssAttributeExpressions(ast, filename, debug, stylexNamespaceName, mergePropsHelperName, needsMergePropsHelper, trussPropsHelperName, needsTrussPropsHelper, trussDebugInfoName, needsTrussDebugInfo, asStyleArrayHelperName, needsAsStyleArrayHelper, skippedCssPropMessages) {
1403
- traverse(ast, {
1404
- JSXAttribute(path) {
1405
- if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
1406
- const value = path.node.value;
1407
- if (!t3.isJSXExpressionContainer(value)) return;
1408
- if (!t3.isExpression(value.expression)) return;
1409
- const propsArgs = lowerCssExpressionToPropsArgs(
1410
- value.expression,
1411
- path,
1412
- asStyleArrayHelperName,
1413
- needsAsStyleArrayHelper
1414
- );
1415
- if (!propsArgs) {
1416
- skippedCssPropMessages.push({
1417
- message: explainSkippedCssRewrite(value.expression, path),
1418
- line: path.node.loc?.start.line ?? null
1419
- });
1420
- return;
1421
- }
1422
- path.replaceWith(
1423
- t3.jsxSpreadAttribute(
1424
- buildCssSpreadExpression(
1425
- path,
1426
- propsArgs,
1427
- path.node.loc?.start.line ?? null,
1428
- mergePropsHelperName,
1429
- needsMergePropsHelper,
1430
- {
1431
- filename,
1432
- debug,
1433
- stylexNamespaceName,
1434
- trussPropsHelperName,
1435
- needsTrussPropsHelper,
1436
- trussDebugInfoName,
1437
- needsTrussDebugInfo
1438
- }
1439
- )
1440
- )
1441
- );
2006
+ function collectConditionalOnlyProps(segments) {
2007
+ const allProps = /* @__PURE__ */ new Map();
2008
+ for (const seg of segments) {
2009
+ if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
2010
+ const hasCondition = !!(seg.pseudoClass || seg.mediaQuery || seg.pseudoElement || seg.whenPseudo);
2011
+ const props = seg.variableProps ?? Object.keys(seg.defs);
2012
+ for (const prop of props) {
2013
+ const current = allProps.get(prop);
2014
+ allProps.set(prop, current === void 0 ? hasCondition : current && hasCondition);
1442
2015
  }
1443
- });
1444
- }
1445
- function buildStyleArrayExpression(propsArgs, line, options) {
1446
- const elements = buildDebugElements(line, options);
1447
- elements.push(...propsArgs);
1448
- return t3.arrayExpression(elements);
2016
+ }
2017
+ const result = /* @__PURE__ */ new Set();
2018
+ for (const [prop, isConditionalOnly] of allProps) {
2019
+ if (isConditionalOnly) result.add(prop);
2020
+ }
2021
+ return result;
1449
2022
  }
1450
- function buildPropsCall(propsArgs, line, options) {
1451
- if (!options.debug) {
1452
- return t3.callExpression(
1453
- t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("props")),
1454
- propsArgs
2023
+ function mergeConditionalBranchMembers(members, previousProperties, conditionalOnlyProps) {
2024
+ return members.map(function(member) {
2025
+ if (!t3.isObjectProperty(member)) {
2026
+ return member;
2027
+ }
2028
+ const prop = propertyName(member.key);
2029
+ const prior = previousProperties.get(prop);
2030
+ if (!prior || !conditionalOnlyProps.has(prop)) {
2031
+ return member;
2032
+ }
2033
+ return t3.objectProperty(
2034
+ clonePropertyKey(member.key),
2035
+ mergePropertyValues(prior.value, member.value)
1455
2036
  );
2037
+ });
2038
+ }
2039
+ function mergePropertyValues(previousValue, currentValue) {
2040
+ if (t3.isStringLiteral(previousValue) && t3.isStringLiteral(currentValue)) {
2041
+ return t3.stringLiteral(`${previousValue.value} ${currentValue.value}`);
1456
2042
  }
1457
- options.needsTrussPropsHelper.current = true;
1458
- const args = buildDebugElements(line, options);
1459
- args.push(...propsArgs);
1460
- return t3.callExpression(t3.identifier(options.trussPropsHelperName), [
1461
- t3.identifier(options.stylexNamespaceName),
1462
- ...args
2043
+ if (t3.isStringLiteral(previousValue) && t3.isArrayExpression(currentValue)) {
2044
+ return mergeTupleValue(currentValue, previousValue.value, true);
2045
+ }
2046
+ if (t3.isArrayExpression(previousValue) && t3.isStringLiteral(currentValue)) {
2047
+ return mergeTupleValue(previousValue, currentValue.value, false);
2048
+ }
2049
+ if (t3.isArrayExpression(previousValue) && t3.isArrayExpression(currentValue)) {
2050
+ const previousClassNames = tupleClassNames(previousValue);
2051
+ return mergeTupleValue(currentValue, previousClassNames, true, arrayElementExpression(previousValue.elements[1]));
2052
+ }
2053
+ return t3.cloneNode(currentValue, true);
2054
+ }
2055
+ function mergeTupleValue(tuple, classNames, prependClassNames, previousVars) {
2056
+ const currentClassNames = tupleClassNames(tuple);
2057
+ const mergedClassNames = prependClassNames ? `${classNames} ${currentClassNames}` : `${currentClassNames} ${classNames}`;
2058
+ const varsExpr = tuple.elements[1];
2059
+ const mergedVars = previousVars && arrayElementExpression(varsExpr) ? mergeVarsObject(previousVars, arrayElementExpression(varsExpr)) : arrayElementExpression(varsExpr) ?? previousVars ?? null;
2060
+ return t3.arrayExpression([
2061
+ t3.stringLiteral(mergedClassNames),
2062
+ mergedVars ? t3.cloneNode(mergedVars, true) : t3.objectExpression([])
1463
2063
  ]);
1464
2064
  }
1465
- function buildDebugElements(line, options) {
1466
- if (!options.debug || line === null) {
1467
- return [];
2065
+ function tupleClassNames(tuple) {
2066
+ const classNames = tuple.elements[0];
2067
+ return t3.isStringLiteral(classNames) ? classNames.value : "";
2068
+ }
2069
+ function arrayElementExpression(element) {
2070
+ return element && !t3.isSpreadElement(element) ? element : null;
2071
+ }
2072
+ function mergeVarsObject(previousVars, currentVars) {
2073
+ if (t3.isObjectExpression(previousVars) && t3.isObjectExpression(currentVars)) {
2074
+ return t3.objectExpression([
2075
+ ...previousVars.properties.map(function(property) {
2076
+ return t3.cloneNode(property, true);
2077
+ }),
2078
+ ...currentVars.properties.map(function(property) {
2079
+ return t3.cloneNode(property, true);
2080
+ })
2081
+ ]);
1468
2082
  }
1469
- options.needsTrussDebugInfo.current = true;
1470
- return [t3.newExpression(t3.identifier(options.trussDebugInfoName), [t3.stringLiteral(`${options.filename}:${line}`)])];
2083
+ return t3.cloneNode(currentVars, true);
1471
2084
  }
1472
- function lowerCssExpressionToPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1473
- return buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) ?? buildStyleArrayLikePropsArgsFromExpression(expr, path);
2085
+ function propertyName(key) {
2086
+ if (t3.isIdentifier(key)) {
2087
+ return key.name;
2088
+ }
2089
+ if (t3.isStringLiteral(key)) {
2090
+ return key.value;
2091
+ }
2092
+ return generate(key).code;
1474
2093
  }
1475
- function explainSkippedCssRewrite(expr, path) {
1476
- if (t3.isObjectExpression(expr)) {
1477
- for (const prop of expr.properties) {
1478
- if (!t3.isSpreadElement(prop)) {
1479
- return `[truss] Unsupported pattern: Could not rewrite css prop: object contains a non-spread property (${formatNodeSnippet(expr)})`;
1480
- }
1481
- const normalizedArg = normalizeStyleExpression(prop.argument);
1482
- if (!normalizedArg) {
1483
- return `[truss] Unsupported pattern: Could not rewrite css prop: spread argument is not style-array-like (${formatNodeSnippet(prop.argument)})`;
1484
- }
1485
- }
1486
- return `[truss] Unsupported pattern: Could not rewrite css prop: object spread composition was not recognized (${formatNodeSnippet(expr)})`;
2094
+ function clonePropertyKey(key) {
2095
+ if (t3.isPrivateName(key)) {
2096
+ return t3.identifier(key.id.name);
1487
2097
  }
1488
- return `[truss] Unsupported pattern: Could not rewrite css prop: expression is not style-array-like (${formatNodeSnippet(expr)})`;
2098
+ return t3.cloneNode(key, true);
1489
2099
  }
1490
- function formatNodeSnippet(node) {
1491
- return generate(node, { compact: true, comments: true }).code;
2100
+ function injectDebugInfo(expr, line, options) {
2101
+ if (!options.debug) return;
2102
+ const firstProp = expr.properties.find(function(p) {
2103
+ return t3.isObjectProperty(p) && !(t3.isIdentifier(p.key) && p.key.name === "__marker" || t3.isStringLiteral(p.key) && p.key.value === "__marker");
2104
+ });
2105
+ if (!firstProp) return;
2106
+ options.needsTrussDebugInfo.current = true;
2107
+ const debugExpr = t3.newExpression(t3.identifier(options.trussDebugInfoName), [
2108
+ t3.stringLiteral(`${options.filename}:${line}`)
2109
+ ]);
2110
+ if (t3.isStringLiteral(firstProp.value)) {
2111
+ firstProp.value = t3.arrayExpression([firstProp.value, debugExpr]);
2112
+ } else if (t3.isArrayExpression(firstProp.value)) {
2113
+ firstProp.value.elements.push(debugExpr);
2114
+ }
1492
2115
  }
1493
- function buildCssSpreadExpression(path, propsArgs, line, mergePropsHelperName, needsMergePropsHelper, options) {
1494
- const existingClassNameExpr = removeExistingClassNameAttribute(path);
1495
- if (!existingClassNameExpr) return buildPropsCall(propsArgs, line, options);
1496
- needsMergePropsHelper.current = true;
1497
- const args = buildDebugElements(line, options);
1498
- args.push(...propsArgs);
1499
- return t3.callExpression(t3.identifier(mergePropsHelperName), [
1500
- t3.identifier(options.stylexNamespaceName),
1501
- existingClassNameExpr,
1502
- ...args
2116
+ function buildCssSpreadExpression(path, styleHash, line, options) {
2117
+ const existingClassNameExpr = removeExistingAttribute(path, "className");
2118
+ const existingStyleExpr = removeExistingAttribute(path, "style");
2119
+ if (!existingClassNameExpr && !existingStyleExpr) {
2120
+ return buildPropsCall(styleHash, line, options);
2121
+ }
2122
+ options.needsMergePropsHelper.current = true;
2123
+ if (options.debug && line !== null) {
2124
+ injectDebugInfo(styleHash, line, options);
2125
+ }
2126
+ return t3.callExpression(t3.identifier(options.mergePropsHelperName), [
2127
+ existingClassNameExpr ?? t3.identifier("undefined"),
2128
+ existingStyleExpr ?? t3.identifier("undefined"),
2129
+ styleHash
1503
2130
  ]);
1504
2131
  }
1505
- function removeExistingClassNameAttribute(path) {
2132
+ function buildPropsCall(styleHash, line, options) {
2133
+ options.needsTrussPropsHelper.current = true;
2134
+ if (options.debug && line !== null && t3.isObjectExpression(styleHash)) {
2135
+ injectDebugInfo(styleHash, line, options);
2136
+ }
2137
+ return t3.callExpression(t3.identifier(options.trussPropsHelperName), [styleHash]);
2138
+ }
2139
+ function removeExistingAttribute(path, attrName) {
1506
2140
  const openingElement = path.parentPath;
1507
2141
  if (!openingElement || !openingElement.isJSXOpeningElement()) return null;
1508
2142
  const attrs = openingElement.node.attributes;
1509
2143
  for (let i = 0; i < attrs.length; i++) {
1510
2144
  const attr = attrs[i];
1511
- if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name: "className" })) continue;
1512
- let classNameExpr = null;
2145
+ if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name: attrName })) continue;
2146
+ let expr = null;
1513
2147
  if (t3.isStringLiteral(attr.value)) {
1514
- classNameExpr = attr.value;
2148
+ expr = attr.value;
1515
2149
  } else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
1516
- classNameExpr = attr.value.expression;
2150
+ expr = attr.value.expression;
1517
2151
  }
1518
2152
  attrs.splice(i, 1);
1519
- return classNameExpr;
1520
- }
1521
- return null;
1522
- }
1523
- function buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1524
- if (!t3.isObjectExpression(expr) || expr.properties.length === 0) return null;
1525
- const allSpreads = expr.properties.every(function(prop) {
1526
- return t3.isSpreadElement(prop);
1527
- });
1528
- if (!allSpreads) return null;
1529
- if (hasStyleArraySpread(expr, path)) {
1530
- const result = flattenStyleObject(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1531
- return result.elements.filter(Boolean);
1532
- }
1533
- return expr.properties.map(function(prop) {
1534
- const spread = prop;
1535
- return t3.spreadElement(
1536
- buildUnknownSpreadFallback(spread.argument, asStyleArrayHelperName, needsAsStyleArrayHelper)
1537
- // I.e. `css={{ ...css }}` or `css={{ ...xss }}`
1538
- );
1539
- });
1540
- }
1541
- function buildStyleArrayLikePropsArgsFromExpression(expr, path) {
1542
- const normalizedExpr = normalizeStyleExpression(expr);
1543
- if (!normalizedExpr) return null;
1544
- return buildStyleArrayLikePropsArgs(normalizedExpr, path);
1545
- }
1546
- function buildStyleArrayLikePropsArgs(expr, path) {
1547
- if (t3.isArrayExpression(expr)) {
1548
- const propsArgs = [];
1549
- for (const el of expr.elements) {
1550
- if (!el) continue;
1551
- if (t3.isSpreadElement(el)) {
1552
- const normalizedArg = normalizeStyleExpression(el.argument);
1553
- if (!normalizedArg) {
1554
- propsArgs.push(t3.spreadElement(el.argument));
1555
- continue;
1556
- }
1557
- if (t3.isArrayExpression(normalizedArg)) {
1558
- const nestedArgs = buildStyleArrayLikePropsArgs(normalizedArg, path);
1559
- if (nestedArgs) {
1560
- propsArgs.push(...nestedArgs);
1561
- continue;
1562
- }
1563
- }
1564
- propsArgs.push(t3.spreadElement(buildSafeSpreadArgument(normalizedArg)));
1565
- continue;
1566
- }
1567
- propsArgs.push(el);
1568
- }
1569
- return propsArgs;
1570
- }
1571
- if (t3.isIdentifier(expr) || t3.isMemberExpression(expr) || t3.isConditionalExpression(expr) || t3.isLogicalExpression(expr) || t3.isCallExpression(expr)) {
1572
- return [t3.spreadElement(buildSafeSpreadArgument(expr))];
2153
+ return expr;
1573
2154
  }
1574
2155
  return null;
1575
2156
  }
1576
- function rewriteStyleObjectExpressions(ast, messages, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1577
- traverse(ast, {
1578
- ObjectExpression(path) {
1579
- if (!hasStyleArraySpread(path.node, path)) return;
1580
- const result = flattenStyleObject(path.node, path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1581
- if (result.droppedPropertyKeys.length > 0) {
1582
- messages.push({
1583
- message: `[truss] Unsupported pattern: Dropped non-spread properties from style composition object (${result.droppedPropertyKeys.join(", ")})`,
1584
- line: path.node.loc?.start.line ?? null
1585
- });
1586
- }
1587
- path.replaceWith(t3.arrayExpression(result.elements));
1588
- }
1589
- });
1590
- }
1591
- function normalizeMixedStyleTernaries(ast) {
1592
- traverse(ast, {
1593
- ConditionalExpression(path) {
1594
- const consequentHasArray = expressionContainsArray(path.node.consequent, path);
1595
- const alternateHasArray = expressionContainsArray(path.node.alternate, path);
1596
- if (consequentHasArray && isEmptyObjectExpression(path.node.alternate)) {
1597
- path.node.alternate = t3.arrayExpression([]);
1598
- } else if (alternateHasArray && isEmptyObjectExpression(path.node.consequent)) {
1599
- path.node.consequent = t3.arrayExpression([]);
1600
- }
1601
- },
1602
- LogicalExpression(path) {
1603
- if (path.node.operator !== "||" && path.node.operator !== "??") return;
1604
- if (expressionContainsArray(path.node.left, path) && isEmptyObjectExpression(path.node.right)) {
1605
- path.node.right = t3.arrayExpression([]);
1606
- }
1607
- }
1608
- });
1609
- }
1610
- function rewriteCssSpreadCalls(ast, cssBindingName, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1611
- traverse(ast, {
1612
- CallExpression(path) {
1613
- if (!isCssSpreadCall(path.node, cssBindingName)) return;
1614
- const arg = path.node.arguments[0];
1615
- if (!arg || t3.isSpreadElement(arg) || !t3.isExpression(arg) || path.node.arguments.length !== 1) return;
1616
- const styleObject = unwrapStyleObjectExpression(arg);
1617
- if (!styleObject) return;
1618
- const result = flattenStyleObject(styleObject, path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1619
- path.replaceWith(t3.arrayExpression(result.elements));
1620
- }
1621
- });
1622
- }
1623
2157
  function rewriteCssPropsCalls(options) {
1624
2158
  traverse(options.ast, {
1625
2159
  CallExpression(path) {
@@ -1627,28 +2161,51 @@ function rewriteCssPropsCalls(options) {
1627
2161
  const arg = path.node.arguments[0];
1628
2162
  if (!arg || t3.isSpreadElement(arg) || !t3.isExpression(arg) || path.node.arguments.length !== 1) return;
1629
2163
  const line = path.node.loc?.start.line ?? null;
1630
- let propsArgs;
1631
- const styleObject = unwrapStyleObjectExpression(arg);
1632
- if (styleObject) {
1633
- const result = flattenStyleObject(
1634
- styleObject,
1635
- path,
1636
- options.asStyleArrayHelperName,
1637
- options.needsAsStyleArrayHelper
2164
+ options.needsTrussPropsHelper.current = true;
2165
+ const classNameExpr = extractSiblingClassName(path);
2166
+ if (classNameExpr) {
2167
+ options.needsMergePropsHelper.current = true;
2168
+ path.replaceWith(
2169
+ t3.callExpression(t3.identifier(options.mergePropsHelperName), [classNameExpr, t3.identifier("undefined"), arg])
1638
2170
  );
1639
- propsArgs = result.elements.filter((e) => e !== null);
1640
2171
  } else {
1641
- propsArgs = [t3.spreadElement(arg)];
2172
+ path.replaceWith(t3.callExpression(t3.identifier(options.trussPropsHelperName), [arg]));
1642
2173
  }
1643
- const classNameExpr = extractSiblingClassName(path);
1644
- if (classNameExpr) {
1645
- path.replaceWith(buildMergePropsCall(propsArgs, classNameExpr, line, options));
2174
+ }
2175
+ });
2176
+ }
2177
+ function rewriteCssAttributeExpressions(options) {
2178
+ traverse(options.ast, {
2179
+ JSXAttribute(path) {
2180
+ if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
2181
+ const value = path.node.value;
2182
+ if (!t3.isJSXExpressionContainer(value)) return;
2183
+ if (!t3.isExpression(value.expression)) return;
2184
+ const expr = value.expression;
2185
+ const line = path.node.loc?.start.line ?? null;
2186
+ const existingClassNameExpr = removeExistingAttribute(path, "className");
2187
+ const existingStyleExpr = removeExistingAttribute(path, "style");
2188
+ if (existingClassNameExpr || existingStyleExpr) {
2189
+ options.needsMergePropsHelper.current = true;
2190
+ path.replaceWith(
2191
+ t3.jsxSpreadAttribute(
2192
+ t3.callExpression(t3.identifier(options.mergePropsHelperName), [
2193
+ existingClassNameExpr ?? t3.identifier("undefined"),
2194
+ existingStyleExpr ?? t3.identifier("undefined"),
2195
+ expr
2196
+ ])
2197
+ )
2198
+ );
1646
2199
  } else {
1647
- path.replaceWith(buildPropsCall(propsArgs, line, options));
2200
+ options.needsTrussPropsHelper.current = true;
2201
+ path.replaceWith(t3.jsxSpreadAttribute(t3.callExpression(t3.identifier(options.trussPropsHelperName), [expr])));
1648
2202
  }
1649
2203
  }
1650
2204
  });
1651
2205
  }
2206
+ function isCssPropsCall(expr, cssBindingName) {
2207
+ return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "props" });
2208
+ }
1652
2209
  function extractSiblingClassName(callPath) {
1653
2210
  const spreadPath = callPath.parentPath;
1654
2211
  if (!spreadPath || !spreadPath.isSpreadElement()) return null;
@@ -1666,230 +2223,9 @@ function extractSiblingClassName(callPath) {
1666
2223
  }
1667
2224
  return null;
1668
2225
  }
1669
- function buildMergePropsCall(propsArgs, classNameExpr, line, options) {
1670
- options.needsMergePropsHelper.current = true;
1671
- const args = buildDebugElements(line, options);
1672
- args.push(...propsArgs);
1673
- return t3.callExpression(t3.identifier(options.mergePropsHelperName), [
1674
- t3.identifier(options.stylexNamespaceName),
1675
- classNameExpr,
1676
- ...args
1677
- ]);
1678
- }
1679
- function flattenStyleObject(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1680
- const elements = [];
1681
- const droppedPropertyKeys = [];
1682
- for (const prop of expr.properties) {
1683
- if (!t3.isSpreadElement(prop)) {
1684
- droppedPropertyKeys.push(formatDroppedPropertyKey(prop));
1685
- continue;
1686
- }
1687
- const normalized = normalizeStyleExpression(prop.argument);
1688
- if (!normalized) {
1689
- elements.push(
1690
- t3.spreadElement(buildUnknownSpreadFallback(prop.argument, asStyleArrayHelperName, needsAsStyleArrayHelper))
1691
- );
1692
- continue;
1693
- }
1694
- if (t3.isArrayExpression(normalized)) {
1695
- elements.push(...normalized.elements);
1696
- } else if (isProvablyArray(normalized)) {
1697
- elements.push(t3.spreadElement(buildSafeSpreadArgument(normalized)));
1698
- } else {
1699
- elements.push(
1700
- t3.spreadElement(buildUnknownSpreadFallback(normalized, asStyleArrayHelperName, needsAsStyleArrayHelper))
1701
- // I.e. `...borderBottomStyles`
1702
- );
1703
- }
1704
- }
1705
- return { elements, droppedPropertyKeys };
1706
- }
1707
- function hasStyleArraySpread(expr, path) {
1708
- return expr.properties.some(function(prop) {
1709
- return t3.isSpreadElement(prop) && expressionContainsArray(prop.argument, path);
1710
- });
1711
- }
1712
- function expressionContainsArray(expr, path) {
1713
- if (t3.isArrayExpression(expr)) return true;
1714
- if (t3.isConditionalExpression(expr)) {
1715
- return expressionContainsArray(expr.consequent, path) || expressionContainsArray(expr.alternate, path);
1716
- }
1717
- if (t3.isLogicalExpression(expr)) {
1718
- return expressionContainsArray(expr.left, path) || expressionContainsArray(expr.right, path);
1719
- }
1720
- if (t3.isObjectExpression(expr)) {
1721
- return expr.properties.some(function(p) {
1722
- return t3.isSpreadElement(p) && expressionContainsArray(p.argument, path);
1723
- });
1724
- }
1725
- if (t3.isIdentifier(expr)) {
1726
- const binding = path.scope.getBinding(expr.name);
1727
- if (binding?.path.isVariableDeclarator()) {
1728
- const init = binding.path.node.init;
1729
- if (init) return expressionContainsArray(init, binding.path);
1730
- }
1731
- return false;
1732
- }
1733
- if (t3.isMemberExpression(expr) && t3.isIdentifier(expr.object)) {
1734
- const binding = path.scope.getBinding(expr.object.name);
1735
- if (binding?.path.isVariableDeclarator()) {
1736
- const init = binding.path.node.init;
1737
- if (init && t3.isObjectExpression(init)) {
1738
- const propName = getStaticMemberPropertyName(expr, path);
1739
- if (propName) {
1740
- for (const prop of init.properties) {
1741
- if (!t3.isObjectProperty(prop) || prop.computed) continue;
1742
- if (!isMatchingPropertyName(prop.key, propName)) continue;
1743
- if (t3.isExpression(prop.value)) {
1744
- return expressionContainsArray(prop.value, binding.path);
1745
- }
1746
- }
1747
- }
1748
- }
1749
- }
1750
- return false;
1751
- }
1752
- if (t3.isCallExpression(expr)) {
1753
- const returnExpr = getCallReturnExpression(expr, path);
1754
- return returnExpr ? expressionContainsArray(returnExpr, path) : false;
1755
- }
1756
- return false;
1757
- }
1758
- function normalizeStyleExpression(expr) {
1759
- if (t3.isArrayExpression(expr)) return expr;
1760
- if (isEmptyStyleFallbackExpression(expr)) return t3.arrayExpression([]);
1761
- if (t3.isLogicalExpression(expr) && expr.operator === "&&") {
1762
- const consequent = normalizeStyleExpression(expr.right);
1763
- if (!consequent) return null;
1764
- return t3.conditionalExpression(expr.left, consequent, t3.arrayExpression([]));
1765
- }
1766
- if (t3.isLogicalExpression(expr) && (expr.operator === "||" || expr.operator === "??")) {
1767
- const left = normalizeStyleExpression(expr.left);
1768
- const right = normalizeStyleBranch(expr.right);
1769
- if (!left || !right) return null;
1770
- return t3.logicalExpression(expr.operator, left, right);
1771
- }
1772
- if (t3.isConditionalExpression(expr)) {
1773
- const consequent = normalizeStyleBranch(expr.consequent);
1774
- const alternate = normalizeStyleBranch(expr.alternate);
1775
- if (!consequent || !alternate) return null;
1776
- return t3.conditionalExpression(expr.test, consequent, alternate);
1777
- }
1778
- if (t3.isIdentifier(expr) || t3.isMemberExpression(expr) || t3.isCallExpression(expr)) {
1779
- return expr;
1780
- }
1781
- return null;
1782
- }
1783
- function normalizeStyleBranch(expr) {
1784
- if (isEmptyStyleFallbackExpression(expr)) return t3.arrayExpression([]);
1785
- if (t3.isObjectExpression(expr)) {
1786
- if (expr.properties.length === 0) return t3.arrayExpression([]);
1787
- const allSpreads = expr.properties.every(function(p) {
1788
- return t3.isSpreadElement(p);
1789
- });
1790
- if (!allSpreads) return null;
1791
- const elements = [];
1792
- for (const prop of expr.properties) {
1793
- const spread = prop;
1794
- const normalized = normalizeStyleExpression(spread.argument);
1795
- if (!normalized) return null;
1796
- if (t3.isArrayExpression(normalized)) {
1797
- elements.push(...normalized.elements);
1798
- } else {
1799
- elements.push(t3.spreadElement(buildSafeSpreadArgument(normalized)));
1800
- }
1801
- }
1802
- return t3.arrayExpression(elements);
1803
- }
1804
- return normalizeStyleExpression(expr);
1805
- }
1806
- function isCssPropsCall(expr, cssBindingName) {
1807
- return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "props" });
1808
- }
1809
- function isCssSpreadCall(expr, cssBindingName) {
1810
- return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "spread" });
1811
- }
1812
- function unwrapStyleObjectExpression(expr) {
1813
- if (t3.isObjectExpression(expr)) return expr;
1814
- if (t3.isTSAsExpression(expr) || t3.isTSSatisfiesExpression(expr) || t3.isTSNonNullExpression(expr)) {
1815
- return unwrapStyleObjectExpression(expr.expression);
1816
- }
1817
- return null;
1818
- }
1819
2226
  function isMatchingPropertyName(key, name) {
1820
2227
  return t3.isIdentifier(key) && key.name === name || t3.isStringLiteral(key) && key.value === name;
1821
2228
  }
1822
- function isEmptyObjectExpression(expr) {
1823
- return t3.isObjectExpression(expr) && expr.properties.length === 0;
1824
- }
1825
- function isEmptyStyleFallbackExpression(expr) {
1826
- return isEmptyObjectExpression(expr) || t3.isIdentifier(expr, { name: "undefined" }) || t3.isNullLiteral(expr) || t3.isBooleanLiteral(expr) && expr.value === false;
1827
- }
1828
- function isProvablyArray(expr) {
1829
- if (t3.isArrayExpression(expr)) return true;
1830
- if (t3.isParenthesizedExpression(expr)) return isProvablyArray(expr.expression);
1831
- if (t3.isConditionalExpression(expr)) {
1832
- return isProvablyArray(expr.consequent) && isProvablyArray(expr.alternate);
1833
- }
1834
- if (t3.isLogicalExpression(expr)) {
1835
- return isProvablyArray(expr.left) && isProvablyArray(expr.right);
1836
- }
1837
- return false;
1838
- }
1839
- function buildUnknownSpreadFallback(expr, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1840
- needsAsStyleArrayHelper.current = true;
1841
- return t3.callExpression(t3.identifier(asStyleArrayHelperName), [expr]);
1842
- }
1843
- function buildSafeSpreadArgument(expr) {
1844
- return t3.isConditionalExpression(expr) || t3.isLogicalExpression(expr) ? t3.parenthesizedExpression(expr) : expr;
1845
- }
1846
- function getStaticMemberPropertyName(expr, path) {
1847
- if (!expr.computed && t3.isIdentifier(expr.property)) {
1848
- return expr.property.name;
1849
- }
1850
- if (t3.isStringLiteral(expr.property)) {
1851
- return expr.property.value;
1852
- }
1853
- if (t3.isIdentifier(expr.property)) {
1854
- const binding = path.scope.getBinding(expr.property.name);
1855
- if (!binding?.path.isVariableDeclarator()) return null;
1856
- const init = binding.path.node.init;
1857
- return t3.isStringLiteral(init) ? init.value : null;
1858
- }
1859
- return null;
1860
- }
1861
- function getCallReturnExpression(expr, path) {
1862
- const localReturnExpr = getLocalFunctionReturnExpression(expr, path);
1863
- if (localReturnExpr) return localReturnExpr;
1864
- const firstArg = expr.arguments[0];
1865
- if (firstArg && !t3.isSpreadElement(firstArg) && (t3.isArrowFunctionExpression(firstArg) || t3.isFunctionExpression(firstArg))) {
1866
- return getFunctionLikeReturnExpression(firstArg);
1867
- }
1868
- return null;
1869
- }
1870
- function getLocalFunctionReturnExpression(expr, path) {
1871
- if (!t3.isIdentifier(expr.callee)) return null;
1872
- const binding = path.scope.getBinding(expr.callee.name);
1873
- if (!binding) return null;
1874
- if (binding.path.isFunctionDeclaration()) {
1875
- return getFunctionLikeReturnExpression(binding.path.node);
1876
- }
1877
- if (binding.path.isVariableDeclarator()) {
1878
- const init = binding.path.node.init;
1879
- if (init && (t3.isArrowFunctionExpression(init) || t3.isFunctionExpression(init))) {
1880
- return getFunctionLikeReturnExpression(init);
1881
- }
1882
- }
1883
- return null;
1884
- }
1885
- function getFunctionLikeReturnExpression(fn) {
1886
- if (t3.isExpression(fn.body)) {
1887
- return fn.body;
1888
- }
1889
- if (fn.body.body.length !== 1) return null;
1890
- const stmt = fn.body.body[0];
1891
- return t3.isReturnStatement(stmt) && stmt.argument && t3.isExpression(stmt.argument) ? stmt.argument : null;
1892
- }
1893
2229
 
1894
2230
  // src/plugin/transform.ts
1895
2231
  var traverse2 = _traverse2.default ?? _traverse2;
@@ -1925,18 +2261,14 @@ function transformTruss(code, filename, mapping, options = {}) {
1925
2261
  });
1926
2262
  const hasCssPropsCall = hasCssMethodCall(ast, cssBindingName, "props");
1927
2263
  if (sites.length === 0 && !hasCssPropsCall) return null;
1928
- const { createEntries, runtimeLookups, needsMaybeInc } = collectCreateData(sites.map((s) => s.resolvedChain));
2264
+ const chains = sites.map((s) => s.resolvedChain);
2265
+ const { rules, needsMaybeInc } = collectAtomicRules(chains, mapping);
2266
+ const cssText = generateCssText(rules);
1929
2267
  const usedTopLevelNames = collectTopLevelBindings(ast);
1930
- const existingStylexNamespace = findStylexNamespaceImport(ast);
1931
- const stylexNamespaceName = existingStylexNamespace ?? reservePreferredName(usedTopLevelNames, "stylex");
1932
- const createVarName = reservePreferredName(usedTopLevelNames, "css", "css_");
1933
2268
  const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
1934
2269
  const existingMergePropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "mergeProps");
1935
2270
  const mergePropsHelperName = existingMergePropsHelperName ?? reservePreferredName(usedTopLevelNames, "mergeProps");
1936
2271
  const needsMergePropsHelper = { current: false };
1937
- const existingAsStyleArrayHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "asStyleArray");
1938
- const asStyleArrayHelperName = existingAsStyleArrayHelperName ?? reservePreferredName(usedTopLevelNames, "asStyleArray");
1939
- const needsAsStyleArrayHelper = { current: false };
1940
2272
  const existingTrussPropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "trussProps");
1941
2273
  const trussPropsHelperName = existingTrussPropsHelperName ?? reservePreferredName(usedTopLevelNames, "trussProps");
1942
2274
  const needsTrussPropsHelper = { current: false };
@@ -1944,18 +2276,17 @@ function transformTruss(code, filename, mapping, options = {}) {
1944
2276
  const trussDebugInfoName = existingTrussDebugInfoName ?? reservePreferredName(usedTopLevelNames, "TrussDebugInfo");
1945
2277
  const needsTrussDebugInfo = { current: false };
1946
2278
  const runtimeLookupNames = /* @__PURE__ */ new Map();
2279
+ const runtimeLookups = collectRuntimeLookups(chains);
1947
2280
  for (const [lookupKey] of runtimeLookups) {
1948
2281
  runtimeLookupNames.set(lookupKey, reservePreferredName(usedTopLevelNames, `__${lookupKey}`));
1949
2282
  }
1950
- const createProperties = buildCreateProperties(createEntries, stylexNamespaceName);
1951
2283
  rewriteExpressionSites({
1952
2284
  ast,
1953
2285
  sites,
1954
2286
  cssBindingName,
1955
2287
  filename: basename(filename),
1956
2288
  debug: options.debug ?? false,
1957
- createVarName,
1958
- stylexNamespaceName,
2289
+ mapping,
1959
2290
  maybeIncHelperName,
1960
2291
  mergePropsHelperName,
1961
2292
  needsMergePropsHelper,
@@ -1963,55 +2294,54 @@ function transformTruss(code, filename, mapping, options = {}) {
1963
2294
  needsTrussPropsHelper,
1964
2295
  trussDebugInfoName,
1965
2296
  needsTrussDebugInfo,
1966
- asStyleArrayHelperName,
1967
- needsAsStyleArrayHelper,
1968
- skippedCssPropMessages: errorMessages,
1969
2297
  runtimeLookupNames
1970
2298
  });
1971
- removeCssImport(ast, cssBindingName);
1972
- if (!findStylexNamespaceImport(ast)) {
1973
- insertStylexNamespaceImport(ast, stylexNamespaceName);
2299
+ const runtimeImports = [];
2300
+ if (needsTrussPropsHelper.current) {
2301
+ runtimeImports.push({ importedName: "trussProps", localName: trussPropsHelperName });
1974
2302
  }
1975
- if (needsMergePropsHelper.current || needsAsStyleArrayHelper.current || needsTrussPropsHelper.current || needsTrussDebugInfo.current) {
1976
- const runtimeImports = [];
1977
- if (needsMergePropsHelper.current) {
1978
- runtimeImports.push({ importedName: "mergeProps", localName: mergePropsHelperName });
1979
- }
1980
- if (needsAsStyleArrayHelper.current) {
1981
- runtimeImports.push({ importedName: "asStyleArray", localName: asStyleArrayHelperName });
1982
- }
1983
- if (needsTrussPropsHelper.current) {
1984
- runtimeImports.push({ importedName: "trussProps", localName: trussPropsHelperName });
1985
- }
1986
- if (needsTrussDebugInfo.current) {
1987
- runtimeImports.push({ importedName: "TrussDebugInfo", localName: trussDebugInfoName });
2303
+ if (needsMergePropsHelper.current) {
2304
+ runtimeImports.push({ importedName: "mergeProps", localName: mergePropsHelperName });
2305
+ }
2306
+ if (needsTrussDebugInfo.current) {
2307
+ runtimeImports.push({ importedName: "TrussDebugInfo", localName: trussDebugInfoName });
2308
+ }
2309
+ if (options.injectCss) {
2310
+ runtimeImports.push({ importedName: "__injectTrussCSS", localName: "__injectTrussCSS" });
2311
+ }
2312
+ const reusedCssImportLine = runtimeImports.length > 0 && findImportDeclaration(ast, "@homebound/truss/runtime") === null && replaceCssImportWithNamedImports(ast, cssBindingName, "@homebound/truss/runtime", runtimeImports);
2313
+ if (!reusedCssImportLine) {
2314
+ removeCssImport(ast, cssBindingName);
2315
+ }
2316
+ if (runtimeImports.length > 0) {
2317
+ if (!reusedCssImportLine) {
2318
+ upsertNamedImports(ast, "@homebound/truss/runtime", runtimeImports);
1988
2319
  }
1989
- upsertNamedImports(ast, "@homebound/truss/runtime", runtimeImports);
1990
2320
  }
1991
- const markerVarNames = collectReferencedMarkerNames(createEntries);
1992
- const hoistedMarkerDecls = hoistMarkerDeclarations(ast, markerVarNames);
1993
2321
  const declarationsToInsert = [];
1994
2322
  if (maybeIncHelperName) {
1995
2323
  declarationsToInsert.push(buildMaybeIncDeclaration(maybeIncHelperName, mapping.increment));
1996
2324
  }
1997
- declarationsToInsert.push(...hoistedMarkerDecls);
1998
- if (createProperties.length > 0) {
1999
- declarationsToInsert.push(buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties));
2000
- for (const [lookupKey, lookup] of runtimeLookups) {
2001
- const lookupName = runtimeLookupNames.get(lookupKey);
2002
- if (!lookupName) continue;
2003
- declarationsToInsert.push(buildRuntimeLookupDeclaration(lookupName, createVarName, lookup));
2004
- }
2325
+ for (const [lookupKey, lookup] of runtimeLookups) {
2326
+ const lookupName = runtimeLookupNames.get(lookupKey);
2327
+ if (!lookupName) continue;
2328
+ declarationsToInsert.push(buildRuntimeLookupDeclaration(lookupName, lookup.segmentsByName, mapping));
2329
+ }
2330
+ if (options.injectCss && cssText.length > 0) {
2331
+ declarationsToInsert.push(
2332
+ t4.expressionStatement(t4.callExpression(t4.identifier("__injectTrussCSS"), [t4.stringLiteral(cssText)]))
2333
+ );
2005
2334
  }
2006
2335
  for (const { message, line } of errorMessages) {
2007
2336
  const location = line !== null ? `${filename}:${line}` : filename;
2008
2337
  const logMessage = `${message} (${location})`;
2009
- const consoleError = t4.expressionStatement(
2010
- t4.callExpression(t4.memberExpression(t4.identifier("console"), t4.identifier("error")), [
2011
- t4.stringLiteral(logMessage)
2012
- ])
2338
+ declarationsToInsert.push(
2339
+ t4.expressionStatement(
2340
+ t4.callExpression(t4.memberExpression(t4.identifier("console"), t4.identifier("error")), [
2341
+ t4.stringLiteral(logMessage)
2342
+ ])
2343
+ )
2013
2344
  );
2014
- declarationsToInsert.push(consoleError);
2015
2345
  }
2016
2346
  if (declarationsToInsert.length > 0) {
2017
2347
  const insertIndex = ast.program.body.findIndex(function(node) {
@@ -2021,48 +2351,52 @@ function transformTruss(code, filename, mapping, options = {}) {
2021
2351
  }
2022
2352
  const output = generate2(ast, {
2023
2353
  sourceFileName: filename,
2354
+ sourceMaps: true,
2024
2355
  retainLines: false
2025
2356
  });
2026
- return { code: output.code, map: output.map };
2357
+ const outputCode = preserveBlankLineAfterImports(code, output.code);
2358
+ return { code: outputCode, map: output.map, css: cssText, rules };
2027
2359
  }
2028
- function collectReferencedMarkerNames(createEntries) {
2029
- const names = /* @__PURE__ */ new Set();
2030
- for (const [, entry] of createEntries) {
2031
- if (entry.whenPseudo?.markerNode && entry.whenPseudo.markerNode.type === "Identifier") {
2032
- names.add(entry.whenPseudo.markerNode.name);
2360
+ function collectRuntimeLookups(chains) {
2361
+ const lookups = /* @__PURE__ */ new Map();
2362
+ for (const chain of chains) {
2363
+ for (const part of chain.parts) {
2364
+ const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
2365
+ for (const seg of segs) {
2366
+ if (seg.typographyLookup && !lookups.has(seg.typographyLookup.lookupKey)) {
2367
+ lookups.set(seg.typographyLookup.lookupKey, {
2368
+ segmentsByName: seg.typographyLookup.segmentsByName
2369
+ });
2370
+ }
2371
+ }
2033
2372
  }
2034
2373
  }
2035
- return names;
2374
+ return lookups;
2036
2375
  }
2037
- function hoistMarkerDeclarations(ast, names) {
2038
- if (names.size === 0) return [];
2039
- const hoisted = [];
2040
- const remaining = new Set(names);
2041
- for (let i = ast.program.body.length - 1; i >= 0; i--) {
2042
- if (remaining.size === 0) break;
2043
- const node = ast.program.body[i];
2044
- if (!t4.isVariableDeclaration(node)) continue;
2045
- const matchingDeclarators = [];
2046
- const otherDeclarators = [];
2047
- for (const decl of node.declarations) {
2048
- if (t4.isIdentifier(decl.id) && remaining.has(decl.id.name)) {
2049
- matchingDeclarators.push(decl);
2050
- remaining.delete(decl.id.name);
2051
- } else {
2052
- otherDeclarators.push(decl);
2053
- }
2054
- }
2055
- if (matchingDeclarators.length === 0) continue;
2056
- if (otherDeclarators.length === 0) {
2057
- ast.program.body.splice(i, 1);
2058
- hoisted.push(node);
2059
- } else {
2060
- node.declarations = otherDeclarators;
2061
- hoisted.push(t4.variableDeclaration(node.kind, matchingDeclarators));
2376
+ function preserveBlankLineAfterImports(input, output) {
2377
+ const inputLines = input.split("\n");
2378
+ const outputLines = output.split("\n");
2379
+ const lastInputImportLine = findLastImportLine(inputLines);
2380
+ const lastOutputImportLine = findLastImportLine(outputLines);
2381
+ if (lastInputImportLine === -1 || lastOutputImportLine === -1) {
2382
+ return output;
2383
+ }
2384
+ const inputHasBlankLineAfterImports = inputLines[lastInputImportLine + 1]?.trim() === "";
2385
+ const outputHasBlankLineAfterImports = outputLines[lastOutputImportLine + 1]?.trim() === "";
2386
+ if (!inputHasBlankLineAfterImports || outputHasBlankLineAfterImports) {
2387
+ return output;
2388
+ }
2389
+ outputLines.splice(lastOutputImportLine + 1, 0, "");
2390
+ return outputLines.join("\n");
2391
+ }
2392
+ function findLastImportLine(lines) {
2393
+ let lastImportLine = -1;
2394
+ for (let index = 0; index < lines.length; index++) {
2395
+ if (lines[index].trimStart().startsWith("import ")) {
2396
+ lastImportLine = index;
2062
2397
  }
2063
2398
  }
2064
- hoisted.reverse();
2065
- return hoisted;
2399
+ return lastImportLine;
2066
2400
  }
2067
2401
 
2068
2402
  // src/plugin/transform-css.ts
@@ -2231,8 +2565,8 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
2231
2565
  if (seg.error) {
2232
2566
  return { error: seg.error };
2233
2567
  }
2234
- if (seg.dynamicProps && !seg.argResolved) {
2235
- return { error: `dynamic value with variable argument is not supported in .css.ts files` };
2568
+ if (seg.variableProps && !seg.argResolved) {
2569
+ return { error: `variable value with variable argument is not supported in .css.ts files` };
2236
2570
  }
2237
2571
  if (seg.typographyLookup) {
2238
2572
  return { error: `typography() with a runtime key is not supported in .css.ts files` };
@@ -2263,9 +2597,6 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
2263
2597
  }
2264
2598
  return { declarations };
2265
2599
  }
2266
- function camelToKebab(s) {
2267
- return s.replace(/^(Webkit|Moz|Ms|O)/, (m) => `-${m.toLowerCase()}`).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
2268
- }
2269
2600
  function formatCssRule(selector, declarations) {
2270
2601
  if (declarations.length === 0) {
2271
2602
  return `${selector} {}`;
@@ -2331,11 +2662,19 @@ function toVirtualCssSpecifier(source) {
2331
2662
  // src/plugin/index.ts
2332
2663
  var VIRTUAL_CSS_PREFIX = "\0truss-css:";
2333
2664
  var CSS_TS_QUERY = "?truss-css";
2665
+ var VIRTUAL_CSS_ENDPOINT = "/virtual:truss.css";
2666
+ var VIRTUAL_RUNTIME_ID = "virtual:truss:runtime";
2667
+ var RESOLVED_VIRTUAL_RUNTIME_ID = "\0" + VIRTUAL_RUNTIME_ID;
2334
2668
  function trussPlugin(opts) {
2335
2669
  let mapping = null;
2336
2670
  let projectRoot;
2337
2671
  let debug = false;
2672
+ let isTest = false;
2673
+ let isBuild = false;
2338
2674
  const externalPackages = opts.externalPackages ?? [];
2675
+ const cssRegistry = /* @__PURE__ */ new Map();
2676
+ let cssVersion = 0;
2677
+ let lastSentVersion = 0;
2339
2678
  function mappingPath() {
2340
2679
  return resolve(projectRoot || process.cwd(), opts.mapping);
2341
2680
  }
@@ -2345,23 +2684,95 @@ function trussPlugin(opts) {
2345
2684
  }
2346
2685
  return mapping;
2347
2686
  }
2687
+ function collectCss() {
2688
+ return generateCssText(cssRegistry);
2689
+ }
2348
2690
  return {
2349
- name: "truss-stylex",
2691
+ name: "truss",
2350
2692
  enforce: "pre",
2351
2693
  configResolved(config) {
2352
2694
  projectRoot = config.root;
2353
2695
  debug = config.command === "serve" || config.mode === "development" || config.mode === "test";
2696
+ isTest = config.mode === "test";
2697
+ isBuild = config.command === "build";
2354
2698
  },
2355
2699
  buildStart() {
2356
2700
  ensureMapping();
2701
+ cssRegistry.clear();
2702
+ cssVersion = 0;
2703
+ lastSentVersion = 0;
2357
2704
  },
2705
+ // -- Dev mode HMR --
2706
+ configureServer(server) {
2707
+ if (isTest) return;
2708
+ server.middlewares.use(function(req, res, next) {
2709
+ if (req.url !== VIRTUAL_CSS_ENDPOINT) return next();
2710
+ const css = collectCss();
2711
+ res.setHeader("Content-Type", "text/css");
2712
+ res.setHeader("Cache-Control", "no-store");
2713
+ res.end(css);
2714
+ });
2715
+ const interval = setInterval(function() {
2716
+ if (cssVersion !== lastSentVersion && server.ws) {
2717
+ lastSentVersion = cssVersion;
2718
+ server.ws.send({ type: "custom", event: "truss:css-update" });
2719
+ }
2720
+ }, 150);
2721
+ server.httpServer?.on("close", function() {
2722
+ clearInterval(interval);
2723
+ });
2724
+ },
2725
+ transformIndexHtml(html) {
2726
+ if (isBuild) return html;
2727
+ const tag = `<script type="module" src="/${VIRTUAL_RUNTIME_ID}"></script>`;
2728
+ return html.replace("</head>", ` ${tag}
2729
+ </head>`);
2730
+ },
2731
+ handleHotUpdate(ctx) {
2732
+ if (ctx.server?.ws) {
2733
+ ctx.server.ws.send({ type: "custom", event: "truss:css-update" });
2734
+ }
2735
+ },
2736
+ // -- Virtual module resolution --
2358
2737
  resolveId(source, importer) {
2738
+ if (source === VIRTUAL_RUNTIME_ID || source === "/" + VIRTUAL_RUNTIME_ID) {
2739
+ return RESOLVED_VIRTUAL_RUNTIME_ID;
2740
+ }
2359
2741
  if (!source.endsWith(CSS_TS_QUERY)) return null;
2360
2742
  const absolutePath = resolveImportPath(source.slice(0, -CSS_TS_QUERY.length), importer, projectRoot);
2361
2743
  if (!existsSync(absolutePath)) return null;
2362
2744
  return VIRTUAL_CSS_PREFIX + absolutePath.slice(0, -3);
2363
2745
  },
2364
2746
  load(id) {
2747
+ if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {
2748
+ return `
2749
+ // Truss dev HMR runtime \u2014 keeps styles up to date without page reload
2750
+ (function() {
2751
+ let style = document.getElementById("__truss_virtual__");
2752
+ if (!style) {
2753
+ style = document.createElement("style");
2754
+ style.id = "__truss_virtual__";
2755
+ document.head.appendChild(style);
2756
+ }
2757
+
2758
+ function fetchCss() {
2759
+ fetch("${VIRTUAL_CSS_ENDPOINT}")
2760
+ .then(function(r) { return r.text(); })
2761
+ .then(function(css) { style.textContent = css; })
2762
+ .catch(function() {});
2763
+ }
2764
+
2765
+ fetchCss();
2766
+
2767
+ if (import.meta.hot) {
2768
+ import.meta.hot.on("truss:css-update", fetchCss);
2769
+ import.meta.hot.on("vite:afterUpdate", function() {
2770
+ setTimeout(fetchCss, 50);
2771
+ });
2772
+ }
2773
+ })();
2774
+ `;
2775
+ }
2365
2776
  if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
2366
2777
  const sourcePath = id.slice(VIRTUAL_CSS_PREFIX.length) + ".ts";
2367
2778
  const sourceCode = readFileSync(sourcePath, "utf8");
@@ -2383,12 +2794,62 @@ function trussPlugin(opts) {
2383
2794
  if (!hasCssDsl) {
2384
2795
  return { code: rewrittenCode, map: null };
2385
2796
  }
2386
- const result = transformTruss(rewrittenCode, fileId, ensureMapping(), { debug });
2797
+ const result = transformTruss(rewrittenCode, fileId, ensureMapping(), {
2798
+ debug,
2799
+ // In test mode (jsdom), inject CSS directly so document.styleSheets has rules
2800
+ injectCss: isTest
2801
+ });
2387
2802
  if (!result) {
2388
2803
  if (!rewrittenImports.changed) return null;
2389
2804
  return { code: rewrittenCode, map: null };
2390
2805
  }
2806
+ if (result.rules) {
2807
+ let hasNewRules = false;
2808
+ for (const [className, rule] of result.rules) {
2809
+ if (!cssRegistry.has(className)) {
2810
+ cssRegistry.set(className, rule);
2811
+ hasNewRules = true;
2812
+ }
2813
+ }
2814
+ if (hasNewRules) {
2815
+ cssVersion++;
2816
+ }
2817
+ }
2391
2818
  return { code: result.code, map: result.map };
2819
+ },
2820
+ // -- Production CSS emission --
2821
+ generateBundle(_options, bundle) {
2822
+ if (!isBuild) return;
2823
+ const css = collectCss();
2824
+ if (!css) return;
2825
+ for (const key of Object.keys(bundle)) {
2826
+ const asset = bundle[key];
2827
+ if (asset.type === "asset" && key.endsWith(".css")) {
2828
+ asset.source = asset.source + "\n" + css;
2829
+ return;
2830
+ }
2831
+ }
2832
+ this.emitFile({
2833
+ type: "asset",
2834
+ fileName: "truss.css",
2835
+ source: css
2836
+ });
2837
+ },
2838
+ writeBundle(options, bundle) {
2839
+ if (!isBuild) return;
2840
+ const css = collectCss();
2841
+ if (!css) return;
2842
+ const outDir = options.dir || join(projectRoot, "dist");
2843
+ const trussPath = join(outDir, "truss.css");
2844
+ if (!existsSync(trussPath)) {
2845
+ const alreadyEmitted = Object.keys(bundle).some(function(key) {
2846
+ const asset = bundle[key];
2847
+ return asset.type === "asset" && key.endsWith(".css") && typeof asset.source === "string" && asset.source.includes(css);
2848
+ });
2849
+ if (!alreadyEmitted) {
2850
+ writeFileSync(trussPath, css, "utf8");
2851
+ }
2852
+ }
2392
2853
  }
2393
2854
  };
2394
2855
  }