@homebound/truss 1.137.4 → 2.0.0-next.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/build/index.d.ts +264 -5
  2. package/build/index.js +1418 -31
  3. package/build/index.js.map +1 -1
  4. package/build/plugin/index.d.ts +71 -0
  5. package/build/plugin/index.js +1577 -0
  6. package/build/plugin/index.js.map +1 -0
  7. package/cli.js +32 -16
  8. package/package.json +27 -20
  9. package/tsup.config.ts +18 -0
  10. package/vitest.config.ts +13 -0
  11. package/build/breakpoints.d.ts +0 -7
  12. package/build/breakpoints.js +0 -79
  13. package/build/breakpoints.js.map +0 -1
  14. package/build/breakpoints.test.d.ts +0 -1
  15. package/build/breakpoints.test.js +0 -49
  16. package/build/breakpoints.test.js.map +0 -1
  17. package/build/config.d.ts +0 -109
  18. package/build/config.js +0 -15
  19. package/build/config.js.map +0 -1
  20. package/build/generate.d.ts +0 -4
  21. package/build/generate.js +0 -155
  22. package/build/generate.js.map +0 -1
  23. package/build/methods.d.ts +0 -82
  24. package/build/methods.js +0 -190
  25. package/build/methods.js.map +0 -1
  26. package/build/methods.test.d.ts +0 -1
  27. package/build/methods.test.js +0 -69
  28. package/build/methods.test.js.map +0 -1
  29. package/build/sections/tachyons/border.d.ts +0 -2
  30. package/build/sections/tachyons/border.js +0 -45
  31. package/build/sections/tachyons/border.js.map +0 -1
  32. package/build/sections/tachyons/borderColors.d.ts +0 -2
  33. package/build/sections/tachyons/borderColors.js +0 -30
  34. package/build/sections/tachyons/borderColors.js.map +0 -1
  35. package/build/sections/tachyons/borderRadius.d.ts +0 -2
  36. package/build/sections/tachyons/borderRadius.js +0 -17
  37. package/build/sections/tachyons/borderRadius.js.map +0 -1
  38. package/build/sections/tachyons/borderStyles.d.ts +0 -2
  39. package/build/sections/tachyons/borderStyles.js +0 -16
  40. package/build/sections/tachyons/borderStyles.js.map +0 -1
  41. package/build/sections/tachyons/borderWidths.d.ts +0 -2
  42. package/build/sections/tachyons/borderWidths.js +0 -13
  43. package/build/sections/tachyons/borderWidths.js.map +0 -1
  44. package/build/sections/tachyons/boxShadow.d.ts +0 -2
  45. package/build/sections/tachyons/boxShadow.js +0 -10
  46. package/build/sections/tachyons/boxShadow.js.map +0 -1
  47. package/build/sections/tachyons/container.d.ts +0 -2
  48. package/build/sections/tachyons/container.js +0 -36
  49. package/build/sections/tachyons/container.js.map +0 -1
  50. package/build/sections/tachyons/coordinates.d.ts +0 -2
  51. package/build/sections/tachyons/coordinates.js +0 -12
  52. package/build/sections/tachyons/coordinates.js.map +0 -1
  53. package/build/sections/tachyons/cursor.d.ts +0 -2
  54. package/build/sections/tachyons/cursor.js +0 -35
  55. package/build/sections/tachyons/cursor.js.map +0 -1
  56. package/build/sections/tachyons/display.d.ts +0 -2
  57. package/build/sections/tachyons/display.js +0 -25
  58. package/build/sections/tachyons/display.js.map +0 -1
  59. package/build/sections/tachyons/flexbox.d.ts +0 -2
  60. package/build/sections/tachyons/flexbox.js +0 -129
  61. package/build/sections/tachyons/flexbox.js.map +0 -1
  62. package/build/sections/tachyons/floats.d.ts +0 -2
  63. package/build/sections/tachyons/floats.js +0 -13
  64. package/build/sections/tachyons/floats.js.map +0 -1
  65. package/build/sections/tachyons/fontWeight.d.ts +0 -2
  66. package/build/sections/tachyons/fontWeight.js +0 -21
  67. package/build/sections/tachyons/fontWeight.js.map +0 -1
  68. package/build/sections/tachyons/grid.d.ts +0 -2
  69. package/build/sections/tachyons/grid.js +0 -39
  70. package/build/sections/tachyons/grid.js.map +0 -1
  71. package/build/sections/tachyons/heights.d.ts +0 -2
  72. package/build/sections/tachyons/heights.js +0 -62
  73. package/build/sections/tachyons/heights.js.map +0 -1
  74. package/build/sections/tachyons/index.d.ts +0 -37
  75. package/build/sections/tachyons/index.js +0 -76
  76. package/build/sections/tachyons/index.js.map +0 -1
  77. package/build/sections/tachyons/lineClamp.d.ts +0 -2
  78. package/build/sections/tachyons/lineClamp.js +0 -38
  79. package/build/sections/tachyons/lineClamp.js.map +0 -1
  80. package/build/sections/tachyons/objectFit.d.ts +0 -2
  81. package/build/sections/tachyons/objectFit.js +0 -16
  82. package/build/sections/tachyons/objectFit.js.map +0 -1
  83. package/build/sections/tachyons/opacity.d.ts +0 -2
  84. package/build/sections/tachyons/opacity.js +0 -38
  85. package/build/sections/tachyons/opacity.js.map +0 -1
  86. package/build/sections/tachyons/outlines.d.ts +0 -2
  87. package/build/sections/tachyons/outlines.js +0 -13
  88. package/build/sections/tachyons/outlines.js.map +0 -1
  89. package/build/sections/tachyons/overflow.d.ts +0 -2
  90. package/build/sections/tachyons/overflow.js +0 -50
  91. package/build/sections/tachyons/overflow.js.map +0 -1
  92. package/build/sections/tachyons/position.d.ts +0 -2
  93. package/build/sections/tachyons/position.js +0 -17
  94. package/build/sections/tachyons/position.js.map +0 -1
  95. package/build/sections/tachyons/skins.d.ts +0 -2
  96. package/build/sections/tachyons/skins.js +0 -51
  97. package/build/sections/tachyons/skins.js.map +0 -1
  98. package/build/sections/tachyons/spacing.d.ts +0 -2
  99. package/build/sections/tachyons/spacing.js +0 -60
  100. package/build/sections/tachyons/spacing.js.map +0 -1
  101. package/build/sections/tachyons/textAlign.d.ts +0 -2
  102. package/build/sections/tachyons/textAlign.js +0 -15
  103. package/build/sections/tachyons/textAlign.js.map +0 -1
  104. package/build/sections/tachyons/textDecoration.d.ts +0 -2
  105. package/build/sections/tachyons/textDecoration.js +0 -13
  106. package/build/sections/tachyons/textDecoration.js.map +0 -1
  107. package/build/sections/tachyons/textTransform.d.ts +0 -2
  108. package/build/sections/tachyons/textTransform.js +0 -15
  109. package/build/sections/tachyons/textTransform.js.map +0 -1
  110. package/build/sections/tachyons/typeScale.d.ts +0 -3
  111. package/build/sections/tachyons/typeScale.js +0 -42
  112. package/build/sections/tachyons/typeScale.js.map +0 -1
  113. package/build/sections/tachyons/typography.d.ts +0 -2
  114. package/build/sections/tachyons/typography.js +0 -48
  115. package/build/sections/tachyons/typography.js.map +0 -1
  116. package/build/sections/tachyons/userSelect.d.ts +0 -2
  117. package/build/sections/tachyons/userSelect.js +0 -15
  118. package/build/sections/tachyons/userSelect.js.map +0 -1
  119. package/build/sections/tachyons/verticalAlign.d.ts +0 -2
  120. package/build/sections/tachyons/verticalAlign.js +0 -14
  121. package/build/sections/tachyons/verticalAlign.js.map +0 -1
  122. package/build/sections/tachyons/visibility.d.ts +0 -2
  123. package/build/sections/tachyons/visibility.js +0 -13
  124. package/build/sections/tachyons/visibility.js.map +0 -1
  125. package/build/sections/tachyons/whitespace.d.ts +0 -2
  126. package/build/sections/tachyons/whitespace.js +0 -16
  127. package/build/sections/tachyons/whitespace.js.map +0 -1
  128. package/build/sections/tachyons/widths.d.ts +0 -2
  129. package/build/sections/tachyons/widths.js +0 -60
  130. package/build/sections/tachyons/widths.js.map +0 -1
  131. package/build/sections/tachyons/wordBreak.d.ts +0 -2
  132. package/build/sections/tachyons/wordBreak.js +0 -15
  133. package/build/sections/tachyons/wordBreak.js.map +0 -1
  134. package/build/sections/tachyons/zIndex.d.ts +0 -2
  135. package/build/sections/tachyons/zIndex.js +0 -45
  136. package/build/sections/tachyons/zIndex.js.map +0 -1
  137. package/build/sections/tachyons-rn/index.d.ts +0 -3
  138. package/build/sections/tachyons-rn/index.js +0 -8
  139. package/build/sections/tachyons-rn/index.js.map +0 -1
  140. package/build/sections/tachyons-rn/spacing.d.ts +0 -2
  141. package/build/sections/tachyons-rn/spacing.js +0 -60
  142. package/build/sections/tachyons-rn/spacing.js.map +0 -1
  143. package/build/tsconfig.tsbuildinfo +0 -1
  144. package/build/utils.d.ts +0 -2
  145. package/build/utils.js +0 -11
  146. package/build/utils.js.map +0 -1
@@ -0,0 +1,1577 @@
1
+ // src/plugin/index.ts
2
+ import { readFileSync, existsSync } from "fs";
3
+ import { resolve, dirname, isAbsolute } from "path";
4
+
5
+ // src/plugin/transform.ts
6
+ import { parse } from "@babel/parser";
7
+ import _traverse2 from "@babel/traverse";
8
+ import _generate from "@babel/generator";
9
+ import * as t4 from "@babel/types";
10
+
11
+ // src/plugin/resolve-chain.ts
12
+ function resolveFullChain(chain, mapping) {
13
+ const parts = [];
14
+ const markers = [];
15
+ const filteredChain = [];
16
+ const scanErrors = [];
17
+ for (let j = 0; j < chain.length; j++) {
18
+ const node = chain[j];
19
+ if (node.type === "getter" && node.name === "marker") {
20
+ markers.push({ type: "marker" });
21
+ } else if (node.type === "call" && node.name === "markerOf") {
22
+ if (node.args.length !== 1) {
23
+ scanErrors.push("[truss] Unsupported pattern: markerOf() requires exactly one argument (a marker variable)");
24
+ } else {
25
+ markers.push({ type: "marker", markerNode: node.args[0] });
26
+ }
27
+ } else {
28
+ filteredChain.push(node);
29
+ }
30
+ }
31
+ let i = 0;
32
+ let currentNodes = [];
33
+ while (i < filteredChain.length) {
34
+ const node = filteredChain[i];
35
+ if (node.type === "if") {
36
+ if (node.conditionNode.type === "StringLiteral") {
37
+ const mediaQuery = node.conditionNode.value;
38
+ currentNodes.push({ type: "__mediaQuery", mediaQuery });
39
+ i++;
40
+ continue;
41
+ }
42
+ if (currentNodes.length > 0) {
43
+ parts.push({
44
+ type: "unconditional",
45
+ segments: mergeOverlappingConditions(resolveChain(currentNodes, mapping))
46
+ });
47
+ currentNodes = [];
48
+ }
49
+ const thenNodes = [];
50
+ const elseNodes = [];
51
+ i++;
52
+ let inElse = false;
53
+ while (i < filteredChain.length) {
54
+ if (filteredChain[i].type === "else") {
55
+ inElse = true;
56
+ i++;
57
+ continue;
58
+ }
59
+ if (filteredChain[i].type === "if") {
60
+ break;
61
+ }
62
+ if (inElse) {
63
+ elseNodes.push(filteredChain[i]);
64
+ } else {
65
+ thenNodes.push(filteredChain[i]);
66
+ }
67
+ i++;
68
+ }
69
+ parts.push({
70
+ type: "conditional",
71
+ conditionNode: node.conditionNode,
72
+ thenSegments: mergeOverlappingConditions(resolveChain(thenNodes, mapping)),
73
+ elseSegments: mergeOverlappingConditions(resolveChain(elseNodes, mapping))
74
+ });
75
+ } else {
76
+ currentNodes.push(node);
77
+ i++;
78
+ }
79
+ }
80
+ if (currentNodes.length > 0) {
81
+ parts.push({ type: "unconditional", segments: mergeOverlappingConditions(resolveChain(currentNodes, mapping)) });
82
+ }
83
+ const segmentErrors = [];
84
+ for (const part of parts) {
85
+ const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
86
+ for (const seg of segs) {
87
+ if (seg.error) {
88
+ segmentErrors.push(seg.error);
89
+ }
90
+ }
91
+ }
92
+ return { parts, markers, errors: [...scanErrors, ...segmentErrors] };
93
+ }
94
+ function resolveChain(chain, mapping) {
95
+ const segments = [];
96
+ let currentMediaQuery = null;
97
+ let currentPseudoClass = null;
98
+ let currentPseudoElement = null;
99
+ let currentWhenPseudo = null;
100
+ for (const node of chain) {
101
+ try {
102
+ if (node.type === "__mediaQuery") {
103
+ currentMediaQuery = node.mediaQuery;
104
+ currentWhenPseudo = null;
105
+ continue;
106
+ }
107
+ if (node.type === "getter") {
108
+ const abbr = node.name;
109
+ if (isPseudoMethod(abbr)) {
110
+ currentPseudoClass = pseudoSelector(abbr);
111
+ currentWhenPseudo = null;
112
+ continue;
113
+ }
114
+ if (mapping.breakpoints && abbr in mapping.breakpoints) {
115
+ currentMediaQuery = mapping.breakpoints[abbr];
116
+ currentWhenPseudo = null;
117
+ continue;
118
+ }
119
+ const entry = mapping.abbreviations[abbr];
120
+ if (!entry) {
121
+ throw new UnsupportedPatternError(`Unknown abbreviation "${abbr}"`);
122
+ }
123
+ const resolved = resolveEntry(
124
+ abbr,
125
+ entry,
126
+ mapping,
127
+ currentMediaQuery,
128
+ currentPseudoClass,
129
+ currentPseudoElement,
130
+ currentWhenPseudo
131
+ );
132
+ segments.push(...resolved);
133
+ } else if (node.type === "call") {
134
+ const abbr = node.name;
135
+ if (abbr === "ifContainer") {
136
+ currentMediaQuery = containerSelectorFromCall(node);
137
+ currentWhenPseudo = null;
138
+ continue;
139
+ }
140
+ if (abbr === "add") {
141
+ const seg = resolveAddCall(node, mapping, currentMediaQuery, currentPseudoClass, currentPseudoElement);
142
+ segments.push(seg);
143
+ continue;
144
+ }
145
+ if (abbr === "element") {
146
+ if (node.args.length !== 1 || node.args[0].type !== "StringLiteral") {
147
+ throw new UnsupportedPatternError(
148
+ `element() requires exactly one string literal argument (e.g. "::placeholder")`
149
+ );
150
+ }
151
+ currentPseudoElement = node.args[0].value;
152
+ continue;
153
+ }
154
+ if (abbr === "when") {
155
+ const resolved = resolveWhenCall(node);
156
+ currentPseudoClass = null;
157
+ currentMediaQuery = null;
158
+ currentWhenPseudo = resolved;
159
+ continue;
160
+ }
161
+ if (isPseudoMethod(abbr)) {
162
+ currentPseudoClass = pseudoSelector(abbr);
163
+ currentWhenPseudo = null;
164
+ if (node.args.length > 0) {
165
+ throw new UnsupportedPatternError(
166
+ `${abbr}() does not take arguments -- use when("ancestor", ":hover") for relationship pseudos`
167
+ );
168
+ }
169
+ continue;
170
+ }
171
+ const entry = mapping.abbreviations[abbr];
172
+ if (!entry) {
173
+ throw new UnsupportedPatternError(`Unknown abbreviation "${abbr}"`);
174
+ }
175
+ if (entry.kind === "dynamic") {
176
+ const seg = resolveDynamicCall(
177
+ abbr,
178
+ entry,
179
+ node,
180
+ mapping,
181
+ currentMediaQuery,
182
+ currentPseudoClass,
183
+ currentPseudoElement
184
+ );
185
+ segments.push(seg);
186
+ } else if (entry.kind === "delegate") {
187
+ const seg = resolveDelegateCall(
188
+ abbr,
189
+ entry,
190
+ node,
191
+ mapping,
192
+ currentMediaQuery,
193
+ currentPseudoClass,
194
+ currentPseudoElement
195
+ );
196
+ segments.push(seg);
197
+ } else {
198
+ throw new UnsupportedPatternError(`Abbreviation "${abbr}" is ${entry.kind}, cannot be called as a function`);
199
+ }
200
+ }
201
+ } catch (err) {
202
+ if (err instanceof UnsupportedPatternError) {
203
+ segments.push({ key: "__error", defs: {}, error: err.message });
204
+ } else {
205
+ throw err;
206
+ }
207
+ }
208
+ }
209
+ return segments;
210
+ }
211
+ function conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, breakpoints) {
212
+ const parts = [];
213
+ if (pseudoElement) parts.push(pseudoName(pseudoElement));
214
+ if (mediaQuery) parts.push(pseudoName(mediaQuery, breakpoints));
215
+ if (pseudoClass) parts.push(pseudoName(pseudoClass));
216
+ return parts.join("_");
217
+ }
218
+ function wrapDefsWithConditions(defs, mediaQuery, pseudoClass) {
219
+ if (!mediaQuery && !pseudoClass) return defs;
220
+ const result = {};
221
+ for (const [prop, value] of Object.entries(defs)) {
222
+ if (pseudoClass && mediaQuery) {
223
+ result[prop] = { default: null, [pseudoClass]: { default: null, [mediaQuery]: value } };
224
+ } else if (pseudoClass) {
225
+ result[prop] = { default: null, [pseudoClass]: value };
226
+ } else {
227
+ result[prop] = { default: null, [mediaQuery]: value };
228
+ }
229
+ }
230
+ return result;
231
+ }
232
+ function resolveEntry(abbr, entry, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
233
+ switch (entry.kind) {
234
+ case "static": {
235
+ if (whenPseudo) {
236
+ const suffix2 = whenPseudoKeyName(whenPseudo);
237
+ const key2 = `${abbr}__${suffix2}`;
238
+ return [{ key: key2, defs: entry.defs, whenPseudo }];
239
+ }
240
+ const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
241
+ const key = suffix ? `${abbr}__${suffix}` : abbr;
242
+ const defs = pseudoElement ? { [pseudoElement]: wrapDefsWithConditions(entry.defs, mediaQuery, pseudoClass) } : wrapDefsWithConditions(entry.defs, mediaQuery, pseudoClass);
243
+ return [{ key, defs, mediaQuery, pseudoClass, pseudoElement }];
244
+ }
245
+ case "alias": {
246
+ const result = [];
247
+ for (const chainAbbr of entry.chain) {
248
+ const subEntry = mapping.abbreviations[chainAbbr];
249
+ if (!subEntry) {
250
+ throw new UnsupportedPatternError(`Alias "${abbr}" references unknown abbreviation "${chainAbbr}"`);
251
+ }
252
+ result.push(...resolveEntry(chainAbbr, subEntry, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo));
253
+ }
254
+ return result;
255
+ }
256
+ case "dynamic":
257
+ case "delegate":
258
+ throw new UnsupportedPatternError(`Abbreviation "${abbr}" requires arguments \u2014 use ${abbr}() not .${abbr}`);
259
+ default:
260
+ throw new UnsupportedPatternError(`Unhandled entry kind for "${abbr}"`);
261
+ }
262
+ }
263
+ function resolveDynamicCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
264
+ if (node.args.length !== 1) {
265
+ throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
266
+ }
267
+ const argAst = node.args[0];
268
+ const literalValue = tryEvaluateLiteral(argAst, entry.incremented, mapping.increment);
269
+ const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
270
+ if (literalValue !== null) {
271
+ const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
272
+ const key = suffix ? `${abbr}__${keySuffix}__${suffix}` : `${abbr}__${keySuffix}`;
273
+ const defs = {};
274
+ for (const prop of entry.props) {
275
+ defs[prop] = literalValue;
276
+ }
277
+ if (entry.extraDefs) {
278
+ Object.assign(defs, entry.extraDefs);
279
+ }
280
+ const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
281
+ return {
282
+ key,
283
+ defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
284
+ mediaQuery,
285
+ pseudoClass,
286
+ pseudoElement,
287
+ argResolved: literalValue
288
+ };
289
+ } else {
290
+ const key = suffix ? `${abbr}__${suffix}` : abbr;
291
+ return {
292
+ key,
293
+ defs: {},
294
+ mediaQuery,
295
+ pseudoClass,
296
+ dynamicProps: entry.props,
297
+ incremented: entry.incremented,
298
+ dynamicExtraDefs: entry.extraDefs,
299
+ argNode: argAst
300
+ };
301
+ }
302
+ }
303
+ function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
304
+ const targetEntry = mapping.abbreviations[entry.target];
305
+ if (!targetEntry || targetEntry.kind !== "dynamic") {
306
+ throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a dynamic entry`);
307
+ }
308
+ if (node.args.length !== 1) {
309
+ throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
310
+ }
311
+ const argAst = node.args[0];
312
+ const literalValue = tryEvaluatePxLiteral(argAst);
313
+ const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
314
+ if (literalValue !== null) {
315
+ const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
316
+ const key = suffix ? `${entry.target}__${keySuffix}__${suffix}` : `${entry.target}__${keySuffix}`;
317
+ const defs = {};
318
+ for (const prop of targetEntry.props) {
319
+ defs[prop] = literalValue;
320
+ }
321
+ if (targetEntry.extraDefs) {
322
+ Object.assign(defs, targetEntry.extraDefs);
323
+ }
324
+ const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
325
+ return {
326
+ key,
327
+ defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
328
+ mediaQuery,
329
+ pseudoClass,
330
+ pseudoElement,
331
+ argResolved: literalValue
332
+ };
333
+ } else {
334
+ const key = suffix ? `${entry.target}__${suffix}` : entry.target;
335
+ return {
336
+ key,
337
+ defs: {},
338
+ mediaQuery,
339
+ pseudoClass,
340
+ pseudoElement,
341
+ dynamicProps: targetEntry.props,
342
+ incremented: false,
343
+ dynamicExtraDefs: targetEntry.extraDefs,
344
+ argNode: argAst
345
+ };
346
+ }
347
+ }
348
+ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
349
+ if (node.args.length !== 2) {
350
+ throw new UnsupportedPatternError(
351
+ `add() requires exactly 2 arguments (property name and value), got ${node.args.length}. The add({...}) object overload is not supported -- use add("propName", value) instead`
352
+ );
353
+ }
354
+ const propArg = node.args[0];
355
+ if (propArg.type !== "StringLiteral") {
356
+ throw new UnsupportedPatternError(`add() first argument must be a string literal property name`);
357
+ }
358
+ const propName = propArg.value;
359
+ const valueArg = node.args[1];
360
+ const literalValue = tryEvaluateAddLiteral(valueArg);
361
+ const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
362
+ if (literalValue !== null) {
363
+ const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
364
+ const key = suffix ? `add_${propName}__${keySuffix}__${suffix}` : `add_${propName}__${keySuffix}`;
365
+ const defs = { [propName]: literalValue };
366
+ const wrappedDefs = wrapDefsWithConditions(defs, mediaQuery, pseudoClass);
367
+ return {
368
+ key,
369
+ defs: pseudoElement ? { [pseudoElement]: wrappedDefs } : wrappedDefs,
370
+ mediaQuery,
371
+ pseudoClass,
372
+ pseudoElement,
373
+ argResolved: literalValue
374
+ };
375
+ } else {
376
+ const key = suffix ? `add_${propName}__${suffix}` : `add_${propName}`;
377
+ return {
378
+ key,
379
+ defs: {},
380
+ mediaQuery,
381
+ pseudoClass,
382
+ pseudoElement,
383
+ dynamicProps: [propName],
384
+ incremented: false,
385
+ argNode: valueArg
386
+ };
387
+ }
388
+ }
389
+ function tryEvaluateAddLiteral(node) {
390
+ if (node.type === "StringLiteral") {
391
+ return node.value;
392
+ }
393
+ if (node.type === "NumericLiteral") {
394
+ return String(node.value);
395
+ }
396
+ if (node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "NumericLiteral") {
397
+ return String(-node.argument.value);
398
+ }
399
+ return null;
400
+ }
401
+ var WHEN_RELATIONSHIPS = /* @__PURE__ */ new Set(["ancestor", "descendant", "anySibling", "siblingBefore", "siblingAfter"]);
402
+ function resolveWhenCall(node) {
403
+ if (node.args.length < 2 || node.args.length > 3) {
404
+ throw new UnsupportedPatternError(
405
+ `when() expects 2 or 3 arguments (relationship, [marker], pseudo), got ${node.args.length}`
406
+ );
407
+ }
408
+ const relationshipArg = node.args[0];
409
+ if (relationshipArg.type !== "StringLiteral") {
410
+ throw new UnsupportedPatternError(`when() first argument must be a string literal relationship`);
411
+ }
412
+ const relationship = relationshipArg.value;
413
+ if (!WHEN_RELATIONSHIPS.has(relationship)) {
414
+ throw new UnsupportedPatternError(
415
+ `when() relationship must be one of: ${[...WHEN_RELATIONSHIPS].join(", ")} -- got "${relationship}"`
416
+ );
417
+ }
418
+ if (node.args.length === 2) {
419
+ const pseudoArg = node.args[1];
420
+ if (pseudoArg.type !== "StringLiteral") {
421
+ throw new UnsupportedPatternError(`when() pseudo selector must be a string literal`);
422
+ }
423
+ return { pseudo: pseudoArg.value, relationship };
424
+ } else {
425
+ const markerNode = node.args[1];
426
+ const pseudoArg = node.args[2];
427
+ if (pseudoArg.type !== "StringLiteral") {
428
+ throw new UnsupportedPatternError(`when() pseudo selector (3rd argument) must be a string literal`);
429
+ }
430
+ return { pseudo: pseudoArg.value, markerNode, relationship };
431
+ }
432
+ }
433
+ var PSEUDO_METHODS = {
434
+ onHover: ":hover",
435
+ onFocus: ":focus",
436
+ onFocusVisible: ":focus-visible",
437
+ onActive: ":active",
438
+ onDisabled: ":disabled"
439
+ };
440
+ function isPseudoMethod(name) {
441
+ return name in PSEUDO_METHODS;
442
+ }
443
+ function pseudoSelector(name) {
444
+ return PSEUDO_METHODS[name];
445
+ }
446
+ function whenPseudoKeyName(ap) {
447
+ const rel = ap.relationship ?? "ancestor";
448
+ const pn = pseudoName(ap.pseudo);
449
+ const base = `${rel}${pn.charAt(0).toUpperCase()}${pn.slice(1)}`;
450
+ if (!ap.markerNode) return base;
451
+ const suffix = ap.markerNode.type === "Identifier" ? ap.markerNode.name : "marker";
452
+ return `${base}_${suffix}`;
453
+ }
454
+ function mergeOverlappingConditions(segments) {
455
+ const propToIndices = /* @__PURE__ */ new Map();
456
+ for (let i = 0; i < segments.length; i++) {
457
+ const seg = segments[i];
458
+ if (seg.dynamicProps || seg.whenPseudo || seg.error) continue;
459
+ for (const prop of Object.keys(seg.defs)) {
460
+ if (!propToIndices.has(prop)) propToIndices.set(prop, []);
461
+ propToIndices.get(prop).push(i);
462
+ }
463
+ }
464
+ const mergeableProps = /* @__PURE__ */ new Set();
465
+ for (const [prop, indices] of propToIndices) {
466
+ if (indices.length < 2) continue;
467
+ const hasBase = indices.some((i) => !segments[i].mediaQuery && !segments[i].pseudoClass);
468
+ const hasConditional = indices.some((i) => !!(segments[i].mediaQuery || segments[i].pseudoClass));
469
+ if (hasBase && hasConditional) {
470
+ mergeableProps.add(prop);
471
+ }
472
+ }
473
+ if (mergeableProps.size === 0) return segments;
474
+ const consumedProps = /* @__PURE__ */ new Map();
475
+ const mergedPropDefs = /* @__PURE__ */ new Map();
476
+ for (const prop of mergeableProps) {
477
+ const indices = propToIndices.get(prop);
478
+ let merged = {};
479
+ const keyParts = [];
480
+ for (const idx of indices) {
481
+ const seg = segments[idx];
482
+ const value = seg.defs[prop];
483
+ keyParts.push(seg.key);
484
+ if (typeof value === "string" || typeof value === "number") {
485
+ merged.default = value;
486
+ } else if (typeof value === "object" && value !== null) {
487
+ for (const [k, v] of Object.entries(value)) {
488
+ if (k === "default" && v === null && merged.default !== void 0) {
489
+ continue;
490
+ }
491
+ merged[k] = v;
492
+ }
493
+ }
494
+ if (!consumedProps.has(idx)) consumedProps.set(idx, /* @__PURE__ */ new Set());
495
+ consumedProps.get(idx).add(prop);
496
+ }
497
+ const finalValue = Object.keys(merged).length === 1 && "default" in merged ? merged.default : merged;
498
+ const mergedKey = [...new Set(keyParts)].join("_");
499
+ mergedPropDefs.set(prop, { defs: { [prop]: finalValue }, key: mergedKey });
500
+ }
501
+ const groupByIndices = /* @__PURE__ */ new Map();
502
+ for (const prop of mergeableProps) {
503
+ const indices = propToIndices.get(prop);
504
+ const groupKey = indices.join(",");
505
+ if (!groupByIndices.has(groupKey)) {
506
+ groupByIndices.set(groupKey, { props: [], key: mergedPropDefs.get(prop).key });
507
+ }
508
+ groupByIndices.get(groupKey).props.push(prop);
509
+ }
510
+ const mergedSegments = [];
511
+ for (const [, group] of groupByIndices) {
512
+ const defs = {};
513
+ for (const prop of group.props) {
514
+ Object.assign(defs, mergedPropDefs.get(prop).defs);
515
+ }
516
+ mergedSegments.push({ key: group.key, defs });
517
+ }
518
+ const result = [];
519
+ const mergedEmitted = /* @__PURE__ */ new Set();
520
+ for (let i = 0; i < segments.length; i++) {
521
+ const seg = segments[i];
522
+ const consumed = consumedProps.get(i);
523
+ if (!consumed) {
524
+ result.push(seg);
525
+ continue;
526
+ }
527
+ const remainingDefs = {};
528
+ for (const [prop, value] of Object.entries(seg.defs)) {
529
+ if (!consumed.has(prop)) {
530
+ remainingDefs[prop] = value;
531
+ }
532
+ }
533
+ if (Object.keys(remainingDefs).length > 0) {
534
+ result.push({ ...seg, defs: remainingDefs });
535
+ }
536
+ const indices = [...propToIndices.entries()].filter(([prop]) => consumed.has(prop) && mergeableProps.has(prop)).map(([, idxs]) => idxs.join(","));
537
+ for (const groupKey of new Set(indices)) {
538
+ if (!mergedEmitted.has(groupKey)) {
539
+ const group = groupByIndices.get(groupKey);
540
+ if (group) {
541
+ const defs = {};
542
+ for (const prop of group.props) {
543
+ Object.assign(defs, mergedPropDefs.get(prop).defs);
544
+ }
545
+ result.push({ key: group.key, defs });
546
+ mergedEmitted.add(groupKey);
547
+ }
548
+ }
549
+ }
550
+ }
551
+ return result;
552
+ }
553
+ function pseudoName(pseudo, breakpoints) {
554
+ if (pseudo.startsWith("@media") && breakpoints) {
555
+ for (const [getterName, mediaQuery] of Object.entries(breakpoints)) {
556
+ if (mediaQuery === pseudo) {
557
+ return getterName.replace(/^if/, "").replace(/^./, (c) => c.toLowerCase());
558
+ }
559
+ }
560
+ return pseudo.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
561
+ }
562
+ if (pseudo.startsWith("@container")) {
563
+ return pseudo.replace(/^@container\s*/, "container ").replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
564
+ }
565
+ return pseudo.replace(/^:+/, "").replace(/-/g, "_");
566
+ }
567
+ function tryEvaluateLiteral(node, incremented, increment) {
568
+ if (node.type === "NumericLiteral") {
569
+ if (incremented) {
570
+ return `${node.value * increment}px`;
571
+ }
572
+ return String(node.value);
573
+ }
574
+ if (node.type === "StringLiteral") {
575
+ return node.value;
576
+ }
577
+ if (node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "NumericLiteral") {
578
+ const val = -node.argument.value;
579
+ if (incremented) {
580
+ return `${val * increment}px`;
581
+ }
582
+ return String(val);
583
+ }
584
+ return null;
585
+ }
586
+ function tryEvaluatePxLiteral(node) {
587
+ if (node.type === "NumericLiteral") {
588
+ return `${node.value}px`;
589
+ }
590
+ return null;
591
+ }
592
+ function containerSelectorFromCall(node) {
593
+ if (node.args.length !== 1) {
594
+ throw new UnsupportedPatternError(`ifContainer() expects exactly 1 argument, got ${node.args.length}`);
595
+ }
596
+ const arg = node.args[0];
597
+ if (!arg || arg.type !== "ObjectExpression") {
598
+ throw new UnsupportedPatternError("ifContainer() expects an object literal argument");
599
+ }
600
+ let lt;
601
+ let gt;
602
+ let name;
603
+ for (const prop of arg.properties) {
604
+ if (prop.type === "SpreadElement") {
605
+ throw new UnsupportedPatternError("ifContainer() does not support spread properties");
606
+ }
607
+ if (prop.type !== "ObjectProperty" || prop.computed) {
608
+ throw new UnsupportedPatternError("ifContainer() expects plain object properties");
609
+ }
610
+ const key = objectPropertyName(prop.key);
611
+ if (!key) {
612
+ throw new UnsupportedPatternError("ifContainer() only supports identifier/string keys");
613
+ }
614
+ const valueNode = prop.value;
615
+ if (key === "lt") {
616
+ lt = numericLiteralValue(valueNode, "ifContainer().lt must be a numeric literal");
617
+ continue;
618
+ }
619
+ if (key === "gt") {
620
+ gt = numericLiteralValue(valueNode, "ifContainer().gt must be a numeric literal");
621
+ continue;
622
+ }
623
+ if (key === "name") {
624
+ name = stringLiteralValue(valueNode, "ifContainer().name must be a string literal");
625
+ continue;
626
+ }
627
+ throw new UnsupportedPatternError(`ifContainer() does not support property "${key}"`);
628
+ }
629
+ if (lt === void 0 && gt === void 0) {
630
+ throw new UnsupportedPatternError('ifContainer() requires at least one of "lt" or "gt"');
631
+ }
632
+ const parts = [];
633
+ if (gt !== void 0) {
634
+ parts.push(`(min-width: ${gt + 1}px)`);
635
+ }
636
+ if (lt !== void 0) {
637
+ parts.push(`(max-width: ${lt}px)`);
638
+ }
639
+ const query = parts.join(" and ");
640
+ const namePrefix = name ? `${name} ` : "";
641
+ return `@container ${namePrefix}${query}`;
642
+ }
643
+ function objectPropertyName(node) {
644
+ if (node.type === "Identifier") return node.name;
645
+ if (node.type === "StringLiteral") return node.value;
646
+ return null;
647
+ }
648
+ function numericLiteralValue(node, errorMessage) {
649
+ if (node.type === "NumericLiteral") {
650
+ return node.value;
651
+ }
652
+ if (node.type === "UnaryExpression" && node.operator === "-" && node.argument.type === "NumericLiteral") {
653
+ return -node.argument.value;
654
+ }
655
+ throw new UnsupportedPatternError(errorMessage);
656
+ }
657
+ function stringLiteralValue(node, errorMessage) {
658
+ if (node.type === "StringLiteral") {
659
+ return node.value;
660
+ }
661
+ if (node.type === "TemplateLiteral" && node.expressions.length === 0 && node.quasis.length === 1) {
662
+ return node.quasis[0].value.cooked ?? "";
663
+ }
664
+ throw new UnsupportedPatternError(errorMessage);
665
+ }
666
+ var UnsupportedPatternError = class extends Error {
667
+ constructor(message) {
668
+ super(`[truss] Unsupported pattern: ${message}`);
669
+ this.name = "UnsupportedPatternError";
670
+ }
671
+ };
672
+
673
+ // src/plugin/ast-utils.ts
674
+ import * as t from "@babel/types";
675
+ function collectTopLevelBindings(ast) {
676
+ const used = /* @__PURE__ */ new Set();
677
+ for (const node of ast.program.body) {
678
+ if (t.isImportDeclaration(node)) {
679
+ for (const spec of node.specifiers) {
680
+ used.add(spec.local.name);
681
+ }
682
+ continue;
683
+ }
684
+ if (t.isVariableDeclaration(node)) {
685
+ for (const decl of node.declarations) {
686
+ collectPatternBindings(decl.id, used);
687
+ }
688
+ continue;
689
+ }
690
+ if (t.isFunctionDeclaration(node) && node.id) {
691
+ used.add(node.id.name);
692
+ continue;
693
+ }
694
+ if (t.isClassDeclaration(node) && node.id) {
695
+ used.add(node.id.name);
696
+ continue;
697
+ }
698
+ if (t.isExportNamedDeclaration(node) && node.declaration) {
699
+ const decl = node.declaration;
700
+ if (t.isVariableDeclaration(decl)) {
701
+ for (const varDecl of decl.declarations) {
702
+ collectPatternBindings(varDecl.id, used);
703
+ }
704
+ } else if ((t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) && decl.id) {
705
+ used.add(decl.id.name);
706
+ }
707
+ continue;
708
+ }
709
+ if (t.isExportDefaultDeclaration(node)) {
710
+ const decl = node.declaration;
711
+ if ((t.isFunctionDeclaration(decl) || t.isClassDeclaration(decl)) && decl.id) {
712
+ used.add(decl.id.name);
713
+ }
714
+ }
715
+ }
716
+ return used;
717
+ }
718
+ function collectPatternBindings(pattern, used) {
719
+ if (t.isVoidPattern(pattern)) {
720
+ return;
721
+ }
722
+ if (t.isIdentifier(pattern)) {
723
+ used.add(pattern.name);
724
+ return;
725
+ }
726
+ if (t.isAssignmentPattern(pattern)) {
727
+ collectPatternBindings(pattern.left, used);
728
+ return;
729
+ }
730
+ if (t.isRestElement(pattern)) {
731
+ collectPatternBindings(pattern.argument, used);
732
+ return;
733
+ }
734
+ if (t.isObjectPattern(pattern)) {
735
+ for (const prop of pattern.properties) {
736
+ if (t.isObjectProperty(prop)) {
737
+ collectPatternBindings(prop.value, used);
738
+ } else if (t.isRestElement(prop)) {
739
+ collectPatternBindings(prop.argument, used);
740
+ }
741
+ }
742
+ return;
743
+ }
744
+ if (t.isArrayPattern(pattern)) {
745
+ for (const el of pattern.elements) {
746
+ if (!el) continue;
747
+ if (t.isIdentifier(el) || t.isAssignmentPattern(el) || t.isObjectPattern(el) || t.isArrayPattern(el)) {
748
+ collectPatternBindings(el, used);
749
+ } else if (t.isRestElement(el)) {
750
+ collectPatternBindings(el.argument, used);
751
+ }
752
+ }
753
+ }
754
+ }
755
+ function reservePreferredName(used, preferred, secondary) {
756
+ if (!used.has(preferred)) {
757
+ used.add(preferred);
758
+ return preferred;
759
+ }
760
+ if (secondary && !used.has(secondary)) {
761
+ used.add(secondary);
762
+ return secondary;
763
+ }
764
+ const base = secondary ?? preferred;
765
+ let i = 1;
766
+ let candidate = `${base}_${i}`;
767
+ while (used.has(candidate)) {
768
+ i++;
769
+ candidate = `${base}_${i}`;
770
+ }
771
+ used.add(candidate);
772
+ return candidate;
773
+ }
774
+ function findCssImportBinding(ast) {
775
+ for (const node of ast.program.body) {
776
+ if (!t.isImportDeclaration(node)) continue;
777
+ for (const spec of node.specifiers) {
778
+ if (t.isImportSpecifier(spec) && t.isIdentifier(spec.imported, { name: "Css" })) {
779
+ return spec.local.name;
780
+ }
781
+ }
782
+ }
783
+ return null;
784
+ }
785
+ function removeCssImport(ast, cssBinding) {
786
+ for (let i = 0; i < ast.program.body.length; i++) {
787
+ const node = ast.program.body[i];
788
+ if (!t.isImportDeclaration(node)) continue;
789
+ const cssSpecIndex = node.specifiers.findIndex((s) => t.isImportSpecifier(s) && s.local.name === cssBinding);
790
+ if (cssSpecIndex === -1) continue;
791
+ if (node.specifiers.length === 1) {
792
+ ast.program.body.splice(i, 1);
793
+ } else {
794
+ node.specifiers.splice(cssSpecIndex, 1);
795
+ }
796
+ return;
797
+ }
798
+ }
799
+ function findStylexNamespaceImport(ast) {
800
+ for (const node of ast.program.body) {
801
+ if (!t.isImportDeclaration(node)) continue;
802
+ if (node.source.value !== "@stylexjs/stylex") continue;
803
+ for (const spec of node.specifiers) {
804
+ if (t.isImportNamespaceSpecifier(spec)) {
805
+ return spec.local.name;
806
+ }
807
+ }
808
+ }
809
+ return null;
810
+ }
811
+ function findLastImportIndex(ast) {
812
+ let lastImportIndex = -1;
813
+ for (let i = 0; i < ast.program.body.length; i++) {
814
+ if (t.isImportDeclaration(ast.program.body[i])) {
815
+ lastImportIndex = i;
816
+ }
817
+ }
818
+ return lastImportIndex;
819
+ }
820
+ function insertStylexNamespaceImport(ast, localName) {
821
+ const stylexImport = t.importDeclaration(
822
+ [t.importNamespaceSpecifier(t.identifier(localName))],
823
+ t.stringLiteral("@stylexjs/stylex")
824
+ );
825
+ const idx = findLastImportIndex(ast);
826
+ ast.program.body.splice(idx + 1, 0, stylexImport);
827
+ }
828
+ function extractChain(node, cssBinding) {
829
+ const chain = [];
830
+ let current = node;
831
+ while (true) {
832
+ if (t.isIdentifier(current, { name: cssBinding })) {
833
+ chain.reverse();
834
+ return chain;
835
+ }
836
+ if (t.isMemberExpression(current) && !current.computed && t.isIdentifier(current.property)) {
837
+ const name = current.property.name;
838
+ if (name === "else") {
839
+ chain.push({ type: "else" });
840
+ } else {
841
+ chain.push({ type: "getter", name });
842
+ }
843
+ current = current.object;
844
+ continue;
845
+ }
846
+ if (t.isCallExpression(current) && t.isMemberExpression(current.callee) && !current.callee.computed && t.isIdentifier(current.callee.property)) {
847
+ const name = current.callee.property.name;
848
+ if (name === "if") {
849
+ chain.push({
850
+ type: "if",
851
+ conditionNode: current.arguments[0]
852
+ });
853
+ current = current.callee.object;
854
+ continue;
855
+ }
856
+ chain.push({
857
+ type: "call",
858
+ name,
859
+ args: current.arguments
860
+ });
861
+ current = current.callee.object;
862
+ continue;
863
+ }
864
+ return null;
865
+ }
866
+ }
867
+
868
+ // src/plugin/emit-stylex.ts
869
+ import * as t2 from "@babel/types";
870
+ function collectCreateData(chains) {
871
+ const createEntries = /* @__PURE__ */ new Map();
872
+ let needsMaybeInc = false;
873
+ for (const chain of chains) {
874
+ for (const part of chain.parts) {
875
+ const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
876
+ for (const seg of segs) {
877
+ if (seg.error) continue;
878
+ if (seg.dynamicProps) {
879
+ if (!createEntries.has(seg.key)) {
880
+ createEntries.set(seg.key, {
881
+ key: seg.key,
882
+ dynamic: {
883
+ props: seg.dynamicProps,
884
+ extraDefs: seg.dynamicExtraDefs,
885
+ mediaQuery: seg.mediaQuery,
886
+ pseudoClass: seg.pseudoClass,
887
+ pseudoElement: seg.pseudoElement
888
+ }
889
+ });
890
+ }
891
+ } else {
892
+ if (!createEntries.has(seg.key)) {
893
+ createEntries.set(seg.key, {
894
+ key: seg.key,
895
+ defs: seg.defs,
896
+ whenPseudo: seg.whenPseudo
897
+ });
898
+ }
899
+ }
900
+ if (seg.incremented && seg.dynamicProps) {
901
+ needsMaybeInc = true;
902
+ }
903
+ }
904
+ }
905
+ }
906
+ return { createEntries, needsMaybeInc };
907
+ }
908
+ function buildCreateProperties(createEntries, stylexNamespaceName) {
909
+ const createProperties = [];
910
+ for (const [, entry] of createEntries) {
911
+ if (entry.dynamic) {
912
+ const paramId = t2.identifier("v");
913
+ const bodyProps = [];
914
+ const { mediaQuery, pseudoClass } = entry.dynamic;
915
+ for (const prop of entry.dynamic.props) {
916
+ if (pseudoClass && mediaQuery) {
917
+ bodyProps.push(
918
+ t2.objectProperty(
919
+ toPropertyKey(prop),
920
+ t2.objectExpression([
921
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
922
+ t2.objectProperty(
923
+ t2.stringLiteral(pseudoClass),
924
+ t2.objectExpression([
925
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
926
+ t2.objectProperty(t2.stringLiteral(mediaQuery), paramId)
927
+ ])
928
+ )
929
+ ])
930
+ )
931
+ );
932
+ } else if (pseudoClass || mediaQuery) {
933
+ const condition = pseudoClass || mediaQuery;
934
+ bodyProps.push(
935
+ t2.objectProperty(
936
+ toPropertyKey(prop),
937
+ t2.objectExpression([
938
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
939
+ t2.objectProperty(t2.stringLiteral(condition), paramId)
940
+ ])
941
+ )
942
+ );
943
+ } else {
944
+ bodyProps.push(t2.objectProperty(toPropertyKey(prop), paramId));
945
+ }
946
+ }
947
+ if (entry.dynamic.extraDefs) {
948
+ for (const [prop, value] of Object.entries(entry.dynamic.extraDefs)) {
949
+ if (pseudoClass && mediaQuery) {
950
+ bodyProps.push(
951
+ t2.objectProperty(
952
+ toPropertyKey(prop),
953
+ t2.objectExpression([
954
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
955
+ t2.objectProperty(
956
+ t2.stringLiteral(pseudoClass),
957
+ t2.objectExpression([
958
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
959
+ t2.objectProperty(t2.stringLiteral(mediaQuery), valueToAst(value))
960
+ ])
961
+ )
962
+ ])
963
+ )
964
+ );
965
+ } else if (pseudoClass || mediaQuery) {
966
+ const condition = pseudoClass || mediaQuery;
967
+ bodyProps.push(
968
+ t2.objectProperty(
969
+ toPropertyKey(prop),
970
+ t2.objectExpression([
971
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
972
+ t2.objectProperty(t2.stringLiteral(condition), valueToAst(value))
973
+ ])
974
+ )
975
+ );
976
+ } else {
977
+ bodyProps.push(t2.objectProperty(toPropertyKey(prop), valueToAst(value)));
978
+ }
979
+ }
980
+ }
981
+ let bodyExpr = t2.objectExpression(bodyProps);
982
+ if (entry.dynamic.pseudoElement) {
983
+ bodyExpr = t2.objectExpression([t2.objectProperty(t2.stringLiteral(entry.dynamic.pseudoElement), bodyExpr)]);
984
+ }
985
+ const arrowFn = t2.arrowFunctionExpression([paramId], bodyExpr);
986
+ createProperties.push(t2.objectProperty(toPropertyKey(entry.key), arrowFn));
987
+ continue;
988
+ }
989
+ if (entry.whenPseudo && entry.defs) {
990
+ const ap = entry.whenPseudo;
991
+ const props = [];
992
+ for (const [prop, value] of Object.entries(entry.defs)) {
993
+ const whenCallArgs = [t2.stringLiteral(ap.pseudo)];
994
+ if (ap.markerNode) {
995
+ whenCallArgs.push(ap.markerNode);
996
+ }
997
+ const relationship = ap.relationship ?? "ancestor";
998
+ const whenCall = t2.callExpression(
999
+ t2.memberExpression(
1000
+ t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("when")),
1001
+ t2.identifier(relationship)
1002
+ ),
1003
+ whenCallArgs
1004
+ );
1005
+ props.push(
1006
+ t2.objectProperty(
1007
+ toPropertyKey(prop),
1008
+ t2.objectExpression([
1009
+ t2.objectProperty(t2.identifier("default"), t2.nullLiteral()),
1010
+ t2.objectProperty(whenCall, valueToAst(value), true)
1011
+ ])
1012
+ )
1013
+ );
1014
+ }
1015
+ createProperties.push(t2.objectProperty(toPropertyKey(entry.key), t2.objectExpression(props)));
1016
+ continue;
1017
+ }
1018
+ if (entry.defs) {
1019
+ createProperties.push(t2.objectProperty(toPropertyKey(entry.key), defsToAst(entry.defs)));
1020
+ }
1021
+ }
1022
+ return createProperties;
1023
+ }
1024
+ function buildMaybeIncDeclaration(helperName, increment) {
1025
+ const incParam = t2.identifier("inc");
1026
+ const body = t2.blockStatement([
1027
+ t2.returnStatement(
1028
+ t2.conditionalExpression(
1029
+ t2.binaryExpression("===", t2.unaryExpression("typeof", incParam), t2.stringLiteral("string")),
1030
+ incParam,
1031
+ t2.templateLiteral(
1032
+ [t2.templateElement({ raw: "", cooked: "" }, false), t2.templateElement({ raw: "px", cooked: "px" }, true)],
1033
+ [t2.binaryExpression("*", incParam, t2.numericLiteral(increment))]
1034
+ )
1035
+ )
1036
+ )
1037
+ ]);
1038
+ return t2.variableDeclaration("const", [
1039
+ t2.variableDeclarator(t2.identifier(helperName), t2.arrowFunctionExpression([incParam], body))
1040
+ ]);
1041
+ }
1042
+ function buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties) {
1043
+ const createCall = t2.callExpression(t2.memberExpression(t2.identifier(stylexNamespaceName), t2.identifier("create")), [
1044
+ t2.objectExpression(createProperties)
1045
+ ]);
1046
+ return t2.variableDeclaration("const", [t2.variableDeclarator(t2.identifier(createVarName), createCall)]);
1047
+ }
1048
+ function defsToAst(defs) {
1049
+ const properties = [];
1050
+ for (const [key, value] of Object.entries(defs)) {
1051
+ const keyNode = toPropertyKey(key);
1052
+ if (value === null) {
1053
+ properties.push(t2.objectProperty(keyNode, t2.nullLiteral()));
1054
+ } else if (typeof value === "string") {
1055
+ properties.push(t2.objectProperty(keyNode, t2.stringLiteral(value)));
1056
+ } else if (typeof value === "number") {
1057
+ properties.push(t2.objectProperty(keyNode, t2.numericLiteral(value)));
1058
+ } else if (typeof value === "object") {
1059
+ properties.push(t2.objectProperty(keyNode, defsToAst(value)));
1060
+ }
1061
+ }
1062
+ return t2.objectExpression(properties);
1063
+ }
1064
+ function valueToAst(value) {
1065
+ if (value === null) return t2.nullLiteral();
1066
+ if (typeof value === "string") return t2.stringLiteral(value);
1067
+ if (typeof value === "number") return t2.numericLiteral(value);
1068
+ if (typeof value === "object") return defsToAst(value);
1069
+ return t2.stringLiteral(String(value));
1070
+ }
1071
+ function toPropertyKey(key) {
1072
+ return isValidIdentifier(key) ? t2.identifier(key) : t2.stringLiteral(key);
1073
+ }
1074
+ function isValidIdentifier(s) {
1075
+ return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
1076
+ }
1077
+
1078
+ // src/plugin/rewrite-sites.ts
1079
+ import _traverse from "@babel/traverse";
1080
+ import * as t3 from "@babel/types";
1081
+ var traverse = _traverse.default ?? _traverse;
1082
+ function rewriteExpressionSites(options) {
1083
+ for (const site of options.sites) {
1084
+ const propsArgs = buildPropsArgsFromChain(site.resolvedChain, options);
1085
+ const cssAttrPath = getCssAttributePath(site.path);
1086
+ if (cssAttrPath) {
1087
+ const propsCall = t3.callExpression(
1088
+ t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("props")),
1089
+ propsArgs
1090
+ );
1091
+ const openingElement = cssAttrPath.parentPath;
1092
+ let existingClassNameExpr = null;
1093
+ if (openingElement && openingElement.isJSXOpeningElement()) {
1094
+ const attrs = openingElement.node.attributes;
1095
+ for (let i = 0; i < attrs.length; i++) {
1096
+ const attr = attrs[i];
1097
+ if (t3.isJSXAttribute(attr) && t3.isJSXIdentifier(attr.name, { name: "className" })) {
1098
+ if (t3.isStringLiteral(attr.value)) {
1099
+ existingClassNameExpr = attr.value;
1100
+ } else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
1101
+ existingClassNameExpr = attr.value.expression;
1102
+ }
1103
+ attrs.splice(i, 1);
1104
+ break;
1105
+ }
1106
+ }
1107
+ }
1108
+ let spreadExpr;
1109
+ if (existingClassNameExpr) {
1110
+ const rId = t3.identifier("__r");
1111
+ const mergedClassName = t3.callExpression(
1112
+ t3.memberExpression(
1113
+ t3.binaryExpression(
1114
+ "+",
1115
+ t3.binaryExpression("+", existingClassNameExpr, t3.stringLiteral(" ")),
1116
+ t3.logicalExpression("||", t3.memberExpression(rId, t3.identifier("className")), t3.stringLiteral(""))
1117
+ ),
1118
+ t3.identifier("trim")
1119
+ ),
1120
+ []
1121
+ );
1122
+ spreadExpr = t3.callExpression(
1123
+ t3.arrowFunctionExpression(
1124
+ [rId],
1125
+ t3.objectExpression([t3.spreadElement(rId), t3.objectProperty(t3.identifier("className"), mergedClassName)])
1126
+ ),
1127
+ [propsCall]
1128
+ );
1129
+ } else {
1130
+ spreadExpr = propsCall;
1131
+ }
1132
+ cssAttrPath.replaceWith(t3.jsxSpreadAttribute(spreadExpr));
1133
+ continue;
1134
+ }
1135
+ site.path.replaceWith(t3.arrayExpression(propsArgs));
1136
+ }
1137
+ rewriteCssArrayExpressions(options.ast, options.stylexNamespaceName);
1138
+ }
1139
+ function getCssAttributePath(path) {
1140
+ const parentPath = path.parentPath;
1141
+ if (!parentPath || !parentPath.isJSXExpressionContainer()) return null;
1142
+ const attrPath = parentPath.parentPath;
1143
+ if (!attrPath || !attrPath.isJSXAttribute()) return null;
1144
+ if (!t3.isJSXIdentifier(attrPath.node.name, { name: "css" })) return null;
1145
+ return attrPath;
1146
+ }
1147
+ function buildPropsArgsFromChain(chain, options) {
1148
+ const args = [];
1149
+ for (const marker of chain.markers) {
1150
+ if (marker.markerNode) {
1151
+ args.push(marker.markerNode);
1152
+ } else {
1153
+ args.push(
1154
+ t3.callExpression(
1155
+ t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("defaultMarker")),
1156
+ []
1157
+ )
1158
+ );
1159
+ }
1160
+ }
1161
+ for (const part of chain.parts) {
1162
+ if (part.type === "unconditional") {
1163
+ args.push(...buildPropsArgs(part.segments, options));
1164
+ continue;
1165
+ }
1166
+ const thenArgs = buildPropsArgs(part.thenSegments, options);
1167
+ const elseArgs = buildPropsArgs(part.elseSegments, options);
1168
+ if (thenArgs.length === 1 && elseArgs.length === 1) {
1169
+ args.push(t3.conditionalExpression(part.conditionNode, thenArgs[0], elseArgs[0]));
1170
+ } else if (thenArgs.length > 0 || elseArgs.length > 0) {
1171
+ args.push(
1172
+ t3.spreadElement(
1173
+ t3.conditionalExpression(part.conditionNode, t3.arrayExpression(thenArgs), t3.arrayExpression(elseArgs))
1174
+ )
1175
+ );
1176
+ }
1177
+ }
1178
+ return args;
1179
+ }
1180
+ function buildPropsArgs(segments, options) {
1181
+ const args = [];
1182
+ for (const seg of segments) {
1183
+ if (seg.error) continue;
1184
+ const ref = t3.memberExpression(t3.identifier(options.createVarName), t3.identifier(seg.key));
1185
+ if (seg.dynamicProps && seg.argNode) {
1186
+ let argExpr;
1187
+ if (seg.incremented && options.maybeIncHelperName) {
1188
+ argExpr = t3.callExpression(t3.identifier(options.maybeIncHelperName), [seg.argNode]);
1189
+ } else if (seg.incremented) {
1190
+ argExpr = seg.argNode;
1191
+ } else {
1192
+ argExpr = t3.callExpression(t3.identifier("String"), [seg.argNode]);
1193
+ }
1194
+ args.push(t3.callExpression(ref, [argExpr]));
1195
+ } else {
1196
+ args.push(ref);
1197
+ }
1198
+ }
1199
+ return args;
1200
+ }
1201
+ function rewriteCssArrayExpressions(ast, stylexNamespaceName) {
1202
+ traverse(ast, {
1203
+ JSXAttribute(path) {
1204
+ if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
1205
+ const value = path.node.value;
1206
+ if (!t3.isJSXExpressionContainer(value)) return;
1207
+ const expr = value.expression;
1208
+ if (!t3.isArrayExpression(expr)) return;
1209
+ const propsArgs = [];
1210
+ for (const el of expr.elements) {
1211
+ if (t3.isSpreadElement(el)) {
1212
+ const arg = el.argument;
1213
+ if (t3.isArrayExpression(arg)) {
1214
+ for (const inner of arg.elements) {
1215
+ if (!inner) continue;
1216
+ if (t3.isSpreadElement(inner)) {
1217
+ propsArgs.push(t3.spreadElement(inner.argument));
1218
+ } else {
1219
+ propsArgs.push(inner);
1220
+ }
1221
+ }
1222
+ } else {
1223
+ propsArgs.push(t3.spreadElement(arg));
1224
+ }
1225
+ } else if (el) {
1226
+ propsArgs.push(el);
1227
+ }
1228
+ }
1229
+ const propsCall = t3.callExpression(
1230
+ t3.memberExpression(t3.identifier(stylexNamespaceName), t3.identifier("props")),
1231
+ propsArgs
1232
+ );
1233
+ path.replaceWith(t3.jsxSpreadAttribute(propsCall));
1234
+ }
1235
+ });
1236
+ }
1237
+
1238
+ // src/plugin/transform.ts
1239
+ var traverse2 = _traverse2.default ?? _traverse2;
1240
+ var generate = _generate.default ?? _generate;
1241
+ function transformTruss(code, filename, mapping) {
1242
+ if (!code.includes("Css")) return null;
1243
+ const ast = parse(code, {
1244
+ sourceType: "module",
1245
+ plugins: ["typescript", "jsx"],
1246
+ sourceFilename: filename
1247
+ });
1248
+ const cssBindingName = findCssImportBinding(ast);
1249
+ if (!cssBindingName) return null;
1250
+ const sites = [];
1251
+ const errorMessages = [];
1252
+ traverse2(ast, {
1253
+ MemberExpression(path) {
1254
+ if (!t4.isIdentifier(path.node.property, { name: "$" })) return;
1255
+ if (path.node.computed) return;
1256
+ const chain = extractChain(path.node.object, cssBindingName);
1257
+ if (!chain) return;
1258
+ const parentPath = path.parentPath;
1259
+ if (parentPath && parentPath.isMemberExpression() && t4.isIdentifier(parentPath.node.property, { name: "$" })) {
1260
+ return;
1261
+ }
1262
+ const resolvedChain = resolveFullChain(chain, mapping);
1263
+ sites.push({ path, resolvedChain });
1264
+ const line = path.node.loc?.start.line ?? null;
1265
+ for (const err of resolvedChain.errors) {
1266
+ errorMessages.push({ message: err, line });
1267
+ }
1268
+ }
1269
+ });
1270
+ if (sites.length === 0) return null;
1271
+ const { createEntries, needsMaybeInc } = collectCreateData(sites.map((s) => s.resolvedChain));
1272
+ const usedTopLevelNames = collectTopLevelBindings(ast);
1273
+ const existingStylexNamespace = findStylexNamespaceImport(ast);
1274
+ const stylexNamespaceName = existingStylexNamespace ?? reservePreferredName(usedTopLevelNames, "stylex");
1275
+ const createVarName = reservePreferredName(usedTopLevelNames, "css", "css_");
1276
+ const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
1277
+ const createProperties = buildCreateProperties(createEntries, stylexNamespaceName);
1278
+ rewriteExpressionSites({
1279
+ ast,
1280
+ sites,
1281
+ createVarName,
1282
+ stylexNamespaceName,
1283
+ maybeIncHelperName
1284
+ });
1285
+ removeCssImport(ast, cssBindingName);
1286
+ if (!findStylexNamespaceImport(ast)) {
1287
+ insertStylexNamespaceImport(ast, stylexNamespaceName);
1288
+ }
1289
+ const markerVarNames = collectReferencedMarkerNames(createEntries);
1290
+ const hoistedMarkerDecls = hoistMarkerDeclarations(ast, markerVarNames);
1291
+ const declarationsToInsert = [];
1292
+ if (maybeIncHelperName) {
1293
+ declarationsToInsert.push(buildMaybeIncDeclaration(maybeIncHelperName, mapping.increment));
1294
+ }
1295
+ declarationsToInsert.push(...hoistedMarkerDecls);
1296
+ if (createProperties.length > 0) {
1297
+ declarationsToInsert.push(buildCreateDeclaration(createVarName, stylexNamespaceName, createProperties));
1298
+ }
1299
+ for (const { message, line } of errorMessages) {
1300
+ const location = line !== null ? `${filename}:${line}` : filename;
1301
+ const logMessage = `${message} (${location})`;
1302
+ const consoleError = t4.expressionStatement(
1303
+ t4.callExpression(t4.memberExpression(t4.identifier("console"), t4.identifier("error")), [
1304
+ t4.stringLiteral(logMessage)
1305
+ ])
1306
+ );
1307
+ declarationsToInsert.push(consoleError);
1308
+ }
1309
+ if (declarationsToInsert.length > 0) {
1310
+ const insertIndex = findLastImportIndex(ast) + 1;
1311
+ ast.program.body.splice(insertIndex, 0, ...declarationsToInsert);
1312
+ }
1313
+ const output = generate(ast, {
1314
+ sourceFileName: filename,
1315
+ retainLines: false
1316
+ });
1317
+ return { code: output.code, map: output.map };
1318
+ }
1319
+ function collectReferencedMarkerNames(createEntries) {
1320
+ const names = /* @__PURE__ */ new Set();
1321
+ for (const [, entry] of createEntries) {
1322
+ if (entry.whenPseudo?.markerNode && entry.whenPseudo.markerNode.type === "Identifier") {
1323
+ names.add(entry.whenPseudo.markerNode.name);
1324
+ }
1325
+ }
1326
+ return names;
1327
+ }
1328
+ function hoistMarkerDeclarations(ast, names) {
1329
+ if (names.size === 0) return [];
1330
+ const hoisted = [];
1331
+ const remaining = new Set(names);
1332
+ for (let i = ast.program.body.length - 1; i >= 0; i--) {
1333
+ if (remaining.size === 0) break;
1334
+ const node = ast.program.body[i];
1335
+ if (!t4.isVariableDeclaration(node)) continue;
1336
+ const matchingDeclarators = [];
1337
+ const otherDeclarators = [];
1338
+ for (const decl of node.declarations) {
1339
+ if (t4.isIdentifier(decl.id) && remaining.has(decl.id.name)) {
1340
+ matchingDeclarators.push(decl);
1341
+ remaining.delete(decl.id.name);
1342
+ } else {
1343
+ otherDeclarators.push(decl);
1344
+ }
1345
+ }
1346
+ if (matchingDeclarators.length === 0) continue;
1347
+ if (otherDeclarators.length === 0) {
1348
+ ast.program.body.splice(i, 1);
1349
+ hoisted.push(node);
1350
+ } else {
1351
+ node.declarations = otherDeclarators;
1352
+ hoisted.push(t4.variableDeclaration(node.kind, matchingDeclarators));
1353
+ }
1354
+ }
1355
+ hoisted.reverse();
1356
+ return hoisted;
1357
+ }
1358
+
1359
+ // src/plugin/transform-css.ts
1360
+ import { parse as parse2 } from "@babel/parser";
1361
+ import * as t5 from "@babel/types";
1362
+ function transformCssTs(code, filename, mapping) {
1363
+ const ast = parse2(code, {
1364
+ sourceType: "module",
1365
+ plugins: ["typescript", "jsx"],
1366
+ sourceFilename: filename
1367
+ });
1368
+ const cssBindingName = findCssImportBinding(ast);
1369
+ if (!cssBindingName) {
1370
+ return `/* [truss] ${filename}: no Css import found */
1371
+ `;
1372
+ }
1373
+ const defaultExport = findDefaultExportObject(ast);
1374
+ if (!defaultExport) {
1375
+ return `/* [truss] ${filename}: expected \`export default { ... }\` with an object literal */
1376
+ `;
1377
+ }
1378
+ const rules = [];
1379
+ for (const prop of defaultExport.properties) {
1380
+ if (t5.isSpreadElement(prop)) {
1381
+ rules.push(`/* [truss] unsupported: spread elements in css.ts export */`);
1382
+ continue;
1383
+ }
1384
+ if (!t5.isObjectProperty(prop)) {
1385
+ rules.push(`/* [truss] unsupported: non-property in css.ts export */`);
1386
+ continue;
1387
+ }
1388
+ const selector = objectPropertyStringKey(prop);
1389
+ if (selector === null) {
1390
+ rules.push(`/* [truss] unsupported: non-string-literal key in css.ts export */`);
1391
+ continue;
1392
+ }
1393
+ const valueNode = prop.value;
1394
+ if (!t5.isExpression(valueNode)) {
1395
+ rules.push(`/* [truss] unsupported: "${selector}" value is not an expression */`);
1396
+ continue;
1397
+ }
1398
+ const cssResult = resolveCssExpression(valueNode, cssBindingName, mapping, filename);
1399
+ if ("error" in cssResult) {
1400
+ rules.push(`/* [truss] unsupported: "${selector}" \u2014 ${cssResult.error} */`);
1401
+ continue;
1402
+ }
1403
+ rules.push(formatCssRule(selector, cssResult.declarations));
1404
+ }
1405
+ return rules.join("\n\n") + "\n";
1406
+ }
1407
+ function findDefaultExportObject(ast) {
1408
+ for (const node of ast.program.body) {
1409
+ if (!t5.isExportDefaultDeclaration(node)) continue;
1410
+ const decl = node.declaration;
1411
+ if (t5.isObjectExpression(decl)) return decl;
1412
+ if (t5.isTSAsExpression(decl) && t5.isObjectExpression(decl.expression)) return decl.expression;
1413
+ if (t5.isTSSatisfiesExpression(decl) && t5.isObjectExpression(decl.expression)) return decl.expression;
1414
+ }
1415
+ return null;
1416
+ }
1417
+ function objectPropertyStringKey(prop) {
1418
+ if (t5.isStringLiteral(prop.key)) return prop.key.value;
1419
+ if (t5.isIdentifier(prop.key) && !prop.computed) return prop.key.name;
1420
+ return null;
1421
+ }
1422
+ function resolveCssExpression(node, cssBindingName, mapping, filename) {
1423
+ if (!t5.isMemberExpression(node) || node.computed || !t5.isIdentifier(node.property, { name: "$" })) {
1424
+ return { error: "value must be a Css.*.$ expression" };
1425
+ }
1426
+ const chain = extractChain(node.object, cssBindingName);
1427
+ if (!chain) {
1428
+ return { error: "could not extract Css chain from expression" };
1429
+ }
1430
+ for (const n of chain) {
1431
+ if (n.type === "if") return { error: "if() conditionals are not supported in .css.ts files" };
1432
+ if (n.type === "else") return { error: "else is not supported in .css.ts files" };
1433
+ }
1434
+ const resolved = resolveFullChain(chain, mapping);
1435
+ if (resolved.errors.length > 0) {
1436
+ return { error: resolved.errors[0] };
1437
+ }
1438
+ for (const part of resolved.parts) {
1439
+ if (part.type === "conditional") {
1440
+ return { error: "conditional chains are not supported in .css.ts files" };
1441
+ }
1442
+ }
1443
+ const declarations = [];
1444
+ for (const part of resolved.parts) {
1445
+ if (part.type !== "unconditional") continue;
1446
+ for (const seg of part.segments) {
1447
+ if (seg.error) {
1448
+ return { error: seg.error };
1449
+ }
1450
+ if (seg.dynamicProps && !seg.argResolved) {
1451
+ return { error: `dynamic value with variable argument is not supported in .css.ts files` };
1452
+ }
1453
+ if (seg.mediaQuery) {
1454
+ return { error: `media query modifiers (ifSm, ifMd, etc.) are not supported in .css.ts files` };
1455
+ }
1456
+ if (seg.pseudoClass) {
1457
+ return { error: `pseudo-class modifiers (onHover, onFocus, etc.) are not supported in .css.ts files` };
1458
+ }
1459
+ if (seg.pseudoElement) {
1460
+ return { error: `pseudo-element modifiers are not supported in .css.ts files` };
1461
+ }
1462
+ if (seg.whenPseudo) {
1463
+ return { error: `when() modifiers are not supported in .css.ts files` };
1464
+ }
1465
+ for (const [prop, value] of Object.entries(seg.defs)) {
1466
+ if (typeof value === "string" || typeof value === "number") {
1467
+ declarations.push({ property: camelToKebab(prop), value: String(value) });
1468
+ } else {
1469
+ return { error: `unexpected nested value for property "${prop}"` };
1470
+ }
1471
+ }
1472
+ }
1473
+ }
1474
+ return { declarations };
1475
+ }
1476
+ function camelToKebab(s) {
1477
+ return s.replace(/^(Webkit|Moz|Ms|O)/, (m) => `-${m.toLowerCase()}`).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
1478
+ }
1479
+ function formatCssRule(selector, declarations) {
1480
+ if (declarations.length === 0) {
1481
+ return `${selector} {}`;
1482
+ }
1483
+ const body = declarations.map((d) => ` ${d.property}: ${d.value};`).join("\n");
1484
+ return `${selector} {
1485
+ ${body}
1486
+ }`;
1487
+ }
1488
+
1489
+ // src/plugin/index.ts
1490
+ var VIRTUAL_CSS_PREFIX = "\0truss-css:";
1491
+ function trussPlugin(opts) {
1492
+ let mapping = null;
1493
+ let projectRoot;
1494
+ const externalPackages = opts.externalPackages ?? [];
1495
+ function mappingPath() {
1496
+ return resolve(projectRoot || process.cwd(), opts.mapping);
1497
+ }
1498
+ function ensureMapping() {
1499
+ if (!mapping) {
1500
+ mapping = loadMapping(mappingPath());
1501
+ }
1502
+ return mapping;
1503
+ }
1504
+ return {
1505
+ name: "truss-stylex",
1506
+ enforce: "pre",
1507
+ configResolved(config) {
1508
+ projectRoot = config.root;
1509
+ },
1510
+ buildStart() {
1511
+ ensureMapping();
1512
+ },
1513
+ resolveId(source, importer) {
1514
+ if (!source.endsWith(".css.ts")) return null;
1515
+ let absolutePath;
1516
+ if (isAbsolute(source)) {
1517
+ absolutePath = source;
1518
+ } else if (importer) {
1519
+ absolutePath = resolve(dirname(importer), source);
1520
+ } else {
1521
+ absolutePath = resolve(projectRoot || process.cwd(), source);
1522
+ }
1523
+ if (!existsSync(absolutePath)) return null;
1524
+ return VIRTUAL_CSS_PREFIX + absolutePath.slice(0, -3);
1525
+ },
1526
+ load(id) {
1527
+ if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
1528
+ const sourcePath = id.slice(VIRTUAL_CSS_PREFIX.length) + ".ts";
1529
+ const sourceCode = readFileSync(sourcePath, "utf8");
1530
+ return transformCssTs(sourceCode, sourcePath, ensureMapping());
1531
+ },
1532
+ transform(code, id) {
1533
+ if (!/\.[cm]?[jt]sx?(\?|$)/.test(id)) return null;
1534
+ if (!code.includes("Css")) return null;
1535
+ const fileId = stripQueryAndHash(id);
1536
+ if (isNodeModulesFile(fileId) && !isWhitelistedExternalPackageFile(fileId, externalPackages)) {
1537
+ return null;
1538
+ }
1539
+ const result = transformTruss(code, id, ensureMapping());
1540
+ if (!result) return null;
1541
+ return { code: result.code, map: result.map };
1542
+ }
1543
+ };
1544
+ }
1545
+ function stripQueryAndHash(id) {
1546
+ const queryIndex = id.indexOf("?");
1547
+ const hashIndex = id.indexOf("#");
1548
+ let end = id.length;
1549
+ if (queryIndex >= 0) end = Math.min(end, queryIndex);
1550
+ if (hashIndex >= 0) end = Math.min(end, hashIndex);
1551
+ const cleanId = id.slice(0, end);
1552
+ if (cleanId.startsWith("/@fs/")) {
1553
+ return cleanId.slice(4);
1554
+ }
1555
+ return cleanId;
1556
+ }
1557
+ function isNodeModulesFile(filePath) {
1558
+ return normalizePath(filePath).includes("/node_modules/");
1559
+ }
1560
+ function isWhitelistedExternalPackageFile(filePath, externalPackages) {
1561
+ const normalizedPath = normalizePath(filePath);
1562
+ return externalPackages.some(function(pkg) {
1563
+ return normalizedPath.includes(`/node_modules/${pkg}/`);
1564
+ });
1565
+ }
1566
+ function normalizePath(path) {
1567
+ return path.replace(/\\/g, "/");
1568
+ }
1569
+ function loadMapping(path) {
1570
+ const raw = readFileSync(path, "utf8");
1571
+ return JSON.parse(raw);
1572
+ }
1573
+ export {
1574
+ loadMapping,
1575
+ trussPlugin
1576
+ };
1577
+ //# sourceMappingURL=index.js.map