@homebound/truss 2.0.13 → 2.1.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.
- package/build/index.js +20 -24
- package/build/index.js.map +1 -1
- package/build/plugin/index.d.ts +11 -10
- package/build/plugin/index.js +987 -981
- package/build/plugin/index.js.map +1 -1
- package/build/runtime.d.ts +20 -10
- package/build/runtime.js +57 -41
- package/build/runtime.js.map +1 -1
- package/cli.js +5 -10
- package/package.json +7 -3
package/build/plugin/index.js
CHANGED
|
@@ -1,6 +1,546 @@
|
|
|
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
|
+
var PSEUDO_SUFFIX = {
|
|
8
|
+
":hover": "_h",
|
|
9
|
+
":focus": "_f",
|
|
10
|
+
":focus-visible": "_fv",
|
|
11
|
+
":active": "_a",
|
|
12
|
+
":disabled": "_d"
|
|
13
|
+
};
|
|
14
|
+
var PSEUDO_ORDER = [":hover", ":focus", ":focus-visible", ":active", ":disabled"];
|
|
15
|
+
var RELATIONSHIP_SHORT = {
|
|
16
|
+
ancestor: "anc",
|
|
17
|
+
descendant: "desc",
|
|
18
|
+
siblingAfter: "sibA",
|
|
19
|
+
siblingBefore: "sibB",
|
|
20
|
+
anySibling: "anyS"
|
|
21
|
+
};
|
|
22
|
+
var DEFAULT_MARKER_CLASS = "__truss_m";
|
|
23
|
+
function markerClassName(markerNode) {
|
|
24
|
+
if (!markerNode) return DEFAULT_MARKER_CLASS;
|
|
25
|
+
if (markerNode.type === "Identifier" && markerNode.name) {
|
|
26
|
+
return `__truss_m_${markerNode.name}`;
|
|
27
|
+
}
|
|
28
|
+
return `${DEFAULT_MARKER_CLASS}_marker`;
|
|
29
|
+
}
|
|
30
|
+
function whenPrefix(whenPseudo) {
|
|
31
|
+
const rel = RELATIONSHIP_SHORT[whenPseudo.relationship ?? "ancestor"] ?? "anc";
|
|
32
|
+
const pseudoTag = PSEUDO_SUFFIX[whenPseudo.pseudo]?.replace(/^_/, "") ?? whenPseudo.pseudo.replace(/^:/, "");
|
|
33
|
+
const markerPart = whenPseudo.markerNode?.type === "Identifier" ? `${whenPseudo.markerNode.name}_` : "";
|
|
34
|
+
return `wh_${rel}_${pseudoTag}_${markerPart}`;
|
|
35
|
+
}
|
|
36
|
+
function conditionPrefix(pseudoClass, mediaQuery, pseudoElement, breakpoints) {
|
|
37
|
+
const parts = [];
|
|
38
|
+
if (pseudoElement) {
|
|
39
|
+
parts.push(`${pseudoElement.replace(/^::/, "")}_`);
|
|
40
|
+
}
|
|
41
|
+
if (mediaQuery && breakpoints) {
|
|
42
|
+
const bpKey = Object.entries(breakpoints).find(([, v]) => v === mediaQuery)?.[0];
|
|
43
|
+
if (bpKey) {
|
|
44
|
+
const shortName = bpKey.replace(/^if/, "").toLowerCase();
|
|
45
|
+
parts.push(`${shortName}_`);
|
|
46
|
+
} else {
|
|
47
|
+
parts.push("mq_");
|
|
48
|
+
}
|
|
49
|
+
} else if (mediaQuery) {
|
|
50
|
+
parts.push("mq_");
|
|
51
|
+
}
|
|
52
|
+
if (pseudoClass) {
|
|
53
|
+
const tag = PSEUDO_SUFFIX[pseudoClass];
|
|
54
|
+
if (tag) parts.push(`${tag.replace(/^_/, "")}_`);
|
|
55
|
+
else parts.push(`${pseudoClass.replace(/^:/, "")}_`);
|
|
56
|
+
}
|
|
57
|
+
return parts.join("");
|
|
58
|
+
}
|
|
59
|
+
function camelToKebab(s) {
|
|
60
|
+
return s.replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`).replace(/^(webkit|moz|ms)-/, "-$1-");
|
|
61
|
+
}
|
|
62
|
+
function cleanValueForClassName(value) {
|
|
63
|
+
let cleaned = value;
|
|
64
|
+
if (cleaned.startsWith("-")) {
|
|
65
|
+
cleaned = "neg" + cleaned.slice(1);
|
|
66
|
+
}
|
|
67
|
+
return cleaned.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
68
|
+
}
|
|
69
|
+
function buildLonghandLookup(mapping) {
|
|
70
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const [abbrev, entry] of Object.entries(mapping.abbreviations)) {
|
|
72
|
+
if (entry.kind !== "static") continue;
|
|
73
|
+
const props = Object.keys(entry.defs);
|
|
74
|
+
if (props.length !== 1) continue;
|
|
75
|
+
const prop = props[0];
|
|
76
|
+
const value = String(entry.defs[prop]);
|
|
77
|
+
const key = `${prop}\0${value}`;
|
|
78
|
+
if (!lookup.has(key)) {
|
|
79
|
+
lookup.set(key, abbrev);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return lookup;
|
|
83
|
+
}
|
|
84
|
+
var cachedMapping = null;
|
|
85
|
+
var cachedLookup = null;
|
|
86
|
+
function getLonghandLookup(mapping) {
|
|
87
|
+
if (cachedMapping !== mapping) {
|
|
88
|
+
cachedMapping = mapping;
|
|
89
|
+
cachedLookup = buildLonghandLookup(mapping);
|
|
90
|
+
}
|
|
91
|
+
return cachedLookup;
|
|
92
|
+
}
|
|
93
|
+
function computeStaticBaseName(seg, cssProp, cssValue, isMultiProp, mapping) {
|
|
94
|
+
const abbrev = seg.key.split("__")[0];
|
|
95
|
+
if (seg.argResolved !== void 0) {
|
|
96
|
+
const valuePart = cleanValueForClassName(seg.argResolved);
|
|
97
|
+
if (isMultiProp) {
|
|
98
|
+
const lookup = getLonghandLookup(mapping);
|
|
99
|
+
const canonical = lookup.get(`${cssProp}\0${cssValue}`);
|
|
100
|
+
if (canonical) return canonical;
|
|
101
|
+
return `${abbrev}_${valuePart}_${cssProp}`;
|
|
102
|
+
}
|
|
103
|
+
return `${abbrev}_${valuePart}`;
|
|
104
|
+
}
|
|
105
|
+
if (isMultiProp) {
|
|
106
|
+
const lookup = getLonghandLookup(mapping);
|
|
107
|
+
const canonical = lookup.get(`${cssProp}\0${cssValue}`);
|
|
108
|
+
if (canonical) return canonical;
|
|
109
|
+
return `${abbrev}_${cssProp}`;
|
|
110
|
+
}
|
|
111
|
+
return abbrev;
|
|
112
|
+
}
|
|
113
|
+
function collectAtomicRules(chains, mapping) {
|
|
114
|
+
const rules = /* @__PURE__ */ new Map();
|
|
115
|
+
let needsMaybeInc = false;
|
|
116
|
+
for (const chain of chains) {
|
|
117
|
+
for (const part of chain.parts) {
|
|
118
|
+
const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
|
|
119
|
+
for (const seg of segs) {
|
|
120
|
+
if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
|
|
121
|
+
if (seg.whenPseudo) {
|
|
122
|
+
if (seg.variableProps) {
|
|
123
|
+
if (seg.incremented) needsMaybeInc = true;
|
|
124
|
+
collectWhenVariableRules(rules, seg, mapping);
|
|
125
|
+
} else {
|
|
126
|
+
collectWhenStaticRules(rules, seg, mapping);
|
|
127
|
+
}
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (seg.variableProps) {
|
|
131
|
+
if (seg.incremented) needsMaybeInc = true;
|
|
132
|
+
collectVariableRules(rules, seg, mapping);
|
|
133
|
+
} else {
|
|
134
|
+
collectStaticRules(rules, seg, mapping);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return { rules, needsMaybeInc };
|
|
140
|
+
}
|
|
141
|
+
function collectStaticRules(rules, seg, mapping) {
|
|
142
|
+
const rawDefs = unwrapDefs(seg.defs, seg.pseudoElement);
|
|
143
|
+
const prefix = conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
144
|
+
const isMultiProp = Object.keys(rawDefs).length > 1;
|
|
145
|
+
for (const [cssProp, value] of Object.entries(rawDefs)) {
|
|
146
|
+
const cssValue = extractLeafValue(value);
|
|
147
|
+
if (cssValue === null) continue;
|
|
148
|
+
const baseName = computeStaticBaseName(seg, cssProp, String(cssValue), isMultiProp, mapping);
|
|
149
|
+
const className = prefix ? `${prefix}${baseName}` : baseName;
|
|
150
|
+
if (!rules.has(className)) {
|
|
151
|
+
rules.set(className, {
|
|
152
|
+
className,
|
|
153
|
+
cssProperty: camelToKebab(cssProp),
|
|
154
|
+
cssValue: String(cssValue),
|
|
155
|
+
pseudoClass: seg.pseudoClass ?? void 0,
|
|
156
|
+
mediaQuery: seg.mediaQuery ?? void 0,
|
|
157
|
+
pseudoElement: seg.pseudoElement ?? void 0
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function collectVariableRules(rules, seg, mapping) {
|
|
163
|
+
const prefix = conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
164
|
+
const baseKey = seg.key.split("__")[0];
|
|
165
|
+
for (const prop of seg.variableProps) {
|
|
166
|
+
const className = prefix ? `${prefix}${baseKey}_var` : `${baseKey}_var`;
|
|
167
|
+
const varName = toCssVariableName(className, baseKey, prop);
|
|
168
|
+
if (!rules.has(className)) {
|
|
169
|
+
rules.set(className, {
|
|
170
|
+
className,
|
|
171
|
+
cssProperty: camelToKebab(prop),
|
|
172
|
+
cssValue: `var(${varName})`,
|
|
173
|
+
pseudoClass: seg.pseudoClass ?? void 0,
|
|
174
|
+
mediaQuery: seg.mediaQuery ?? void 0,
|
|
175
|
+
pseudoElement: seg.pseudoElement ?? void 0,
|
|
176
|
+
cssVarName: varName
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (seg.variableExtraDefs) {
|
|
181
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
182
|
+
const extraBase = `${baseKey}_${cssProp}`;
|
|
183
|
+
const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
|
|
184
|
+
if (!rules.has(extraName)) {
|
|
185
|
+
rules.set(extraName, {
|
|
186
|
+
className: extraName,
|
|
187
|
+
cssProperty: camelToKebab(cssProp),
|
|
188
|
+
cssValue: String(value),
|
|
189
|
+
pseudoClass: seg.pseudoClass ?? void 0,
|
|
190
|
+
mediaQuery: seg.mediaQuery ?? void 0,
|
|
191
|
+
pseudoElement: seg.pseudoElement ?? void 0
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
function collectWhenStaticRules(rules, seg, mapping) {
|
|
198
|
+
const wp = seg.whenPseudo;
|
|
199
|
+
const prefix = whenPrefix(wp);
|
|
200
|
+
const rawDefs = seg.defs;
|
|
201
|
+
const isMultiProp = Object.keys(rawDefs).length > 1;
|
|
202
|
+
const mClass = markerClassName(wp.markerNode);
|
|
203
|
+
for (const [cssProp, value] of Object.entries(rawDefs)) {
|
|
204
|
+
const cssValue = typeof value === "string" || typeof value === "number" ? value : extractLeafValue(value);
|
|
205
|
+
if (cssValue === null) continue;
|
|
206
|
+
const baseName = computeStaticBaseName(seg, cssProp, String(cssValue), isMultiProp, mapping);
|
|
207
|
+
const className = `${prefix}${baseName}`;
|
|
208
|
+
if (!rules.has(className)) {
|
|
209
|
+
rules.set(className, {
|
|
210
|
+
className,
|
|
211
|
+
cssProperty: camelToKebab(cssProp),
|
|
212
|
+
cssValue: String(cssValue),
|
|
213
|
+
whenSelector: {
|
|
214
|
+
relationship: wp.relationship ?? "ancestor",
|
|
215
|
+
markerClass: mClass,
|
|
216
|
+
pseudo: wp.pseudo
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
function collectWhenVariableRules(rules, seg, mapping) {
|
|
223
|
+
const wp = seg.whenPseudo;
|
|
224
|
+
const prefix = whenPrefix(wp);
|
|
225
|
+
const baseKey = seg.key.split("__")[0];
|
|
226
|
+
const mClass = markerClassName(wp.markerNode);
|
|
227
|
+
for (const prop of seg.variableProps) {
|
|
228
|
+
const className = `${prefix}${baseKey}_var`;
|
|
229
|
+
const varName = toCssVariableName(className, baseKey, prop);
|
|
230
|
+
if (!rules.has(className)) {
|
|
231
|
+
rules.set(className, {
|
|
232
|
+
className,
|
|
233
|
+
cssProperty: camelToKebab(prop),
|
|
234
|
+
cssValue: `var(${varName})`,
|
|
235
|
+
cssVarName: varName,
|
|
236
|
+
whenSelector: {
|
|
237
|
+
relationship: wp.relationship ?? "ancestor",
|
|
238
|
+
markerClass: mClass,
|
|
239
|
+
pseudo: wp.pseudo
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (seg.variableExtraDefs) {
|
|
245
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
246
|
+
const extraName = `${prefix}${baseKey}_${cssProp}`;
|
|
247
|
+
if (!rules.has(extraName)) {
|
|
248
|
+
rules.set(extraName, {
|
|
249
|
+
className: extraName,
|
|
250
|
+
cssProperty: camelToKebab(cssProp),
|
|
251
|
+
cssValue: String(value),
|
|
252
|
+
whenSelector: {
|
|
253
|
+
relationship: wp.relationship ?? "ancestor",
|
|
254
|
+
markerClass: mClass,
|
|
255
|
+
pseudo: wp.pseudo
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
function unwrapDefs(defs, pseudoElement) {
|
|
263
|
+
let result = defs;
|
|
264
|
+
if (pseudoElement && result[pseudoElement] && typeof result[pseudoElement] === "object") {
|
|
265
|
+
result = result[pseudoElement];
|
|
266
|
+
}
|
|
267
|
+
const unwrapped = {};
|
|
268
|
+
for (const [prop, val] of Object.entries(result)) {
|
|
269
|
+
unwrapped[prop] = extractLeafValue(val) ?? val;
|
|
270
|
+
}
|
|
271
|
+
return unwrapped;
|
|
272
|
+
}
|
|
273
|
+
function extractLeafValue(value) {
|
|
274
|
+
if (typeof value === "string" || typeof value === "number") return value;
|
|
275
|
+
if (value === null) return null;
|
|
276
|
+
if (typeof value === "object") {
|
|
277
|
+
const obj = value;
|
|
278
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
279
|
+
if (k === "default") continue;
|
|
280
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
281
|
+
if (typeof v === "object" && v !== null) return extractLeafValue(v);
|
|
282
|
+
}
|
|
283
|
+
if ("default" in obj && obj.default !== null) {
|
|
284
|
+
return extractLeafValue(obj.default);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
function generateCssText(rules) {
|
|
290
|
+
const allRules = Array.from(rules.values());
|
|
291
|
+
const base = [];
|
|
292
|
+
const pseudo = /* @__PURE__ */ new Map();
|
|
293
|
+
const pseudoElement = [];
|
|
294
|
+
const whenRules = [];
|
|
295
|
+
const media = [];
|
|
296
|
+
const mediaPseudo = [];
|
|
297
|
+
const mediaPseudoElement = [];
|
|
298
|
+
for (const rule of allRules) {
|
|
299
|
+
if (rule.whenSelector) {
|
|
300
|
+
whenRules.push(rule);
|
|
301
|
+
} else if (rule.mediaQuery && rule.pseudoClass) {
|
|
302
|
+
mediaPseudo.push(rule);
|
|
303
|
+
} else if (rule.mediaQuery && rule.pseudoElement) {
|
|
304
|
+
mediaPseudoElement.push(rule);
|
|
305
|
+
} else if (rule.mediaQuery) {
|
|
306
|
+
media.push(rule);
|
|
307
|
+
} else if (rule.pseudoClass && rule.pseudoElement) {
|
|
308
|
+
const tier = pseudo.get(rule.pseudoClass) ?? [];
|
|
309
|
+
tier.push(rule);
|
|
310
|
+
pseudo.set(rule.pseudoClass, tier);
|
|
311
|
+
} else if (rule.pseudoElement) {
|
|
312
|
+
pseudoElement.push(rule);
|
|
313
|
+
} else if (rule.pseudoClass) {
|
|
314
|
+
const tier = pseudo.get(rule.pseudoClass) ?? [];
|
|
315
|
+
tier.push(rule);
|
|
316
|
+
pseudo.set(rule.pseudoClass, tier);
|
|
317
|
+
} else {
|
|
318
|
+
base.push(rule);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
const lines = [];
|
|
322
|
+
for (const rule of base) {
|
|
323
|
+
lines.push(formatBaseRule(rule));
|
|
324
|
+
}
|
|
325
|
+
for (const pc of PSEUDO_ORDER) {
|
|
326
|
+
const tier = pseudo.get(pc);
|
|
327
|
+
if (!tier) continue;
|
|
328
|
+
for (const rule of tier) {
|
|
329
|
+
lines.push(formatPseudoRule(rule));
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
for (const [pc, tier] of Array.from(pseudo.entries())) {
|
|
333
|
+
if (PSEUDO_ORDER.includes(pc)) continue;
|
|
334
|
+
for (const rule of tier) {
|
|
335
|
+
lines.push(formatPseudoRule(rule));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
for (const rule of pseudoElement) {
|
|
339
|
+
lines.push(formatPseudoElementRule(rule));
|
|
340
|
+
}
|
|
341
|
+
for (const rule of whenRules) {
|
|
342
|
+
lines.push(formatWhenRule(rule));
|
|
343
|
+
}
|
|
344
|
+
for (const rule of media) {
|
|
345
|
+
lines.push(formatMediaRule(rule));
|
|
346
|
+
}
|
|
347
|
+
for (const rule of mediaPseudo) {
|
|
348
|
+
lines.push(formatMediaPseudoRule(rule));
|
|
349
|
+
}
|
|
350
|
+
for (const rule of mediaPseudoElement) {
|
|
351
|
+
lines.push(formatMediaPseudoElementRule(rule));
|
|
352
|
+
}
|
|
353
|
+
for (const rule of allRules) {
|
|
354
|
+
if (rule.cssVarName) {
|
|
355
|
+
lines.push(`@property ${rule.cssVarName} {
|
|
356
|
+
syntax: "*";
|
|
357
|
+
inherits: false;
|
|
358
|
+
}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return lines.join("\n");
|
|
362
|
+
}
|
|
363
|
+
function formatBaseRule(rule) {
|
|
364
|
+
return `.${rule.className} {
|
|
365
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
366
|
+
}`;
|
|
367
|
+
}
|
|
368
|
+
function formatPseudoRule(rule) {
|
|
369
|
+
const pe = rule.pseudoElement ? rule.pseudoElement : "";
|
|
370
|
+
return `.${rule.className}${rule.pseudoClass}${pe} {
|
|
371
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
372
|
+
}`;
|
|
373
|
+
}
|
|
374
|
+
function formatPseudoElementRule(rule) {
|
|
375
|
+
return `.${rule.className}${rule.pseudoElement} {
|
|
376
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
377
|
+
}`;
|
|
378
|
+
}
|
|
379
|
+
function formatWhenRule(rule) {
|
|
380
|
+
const whenSelector = rule.whenSelector;
|
|
381
|
+
if (!whenSelector) {
|
|
382
|
+
return formatBaseRule(rule);
|
|
383
|
+
}
|
|
384
|
+
const markerSelector = `.${whenSelector.markerClass}${whenSelector.pseudo}`;
|
|
385
|
+
const targetSelector = `.${rule.className}`;
|
|
386
|
+
if (whenSelector.relationship === "ancestor") {
|
|
387
|
+
return `${markerSelector} ${targetSelector} {
|
|
388
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
389
|
+
}`;
|
|
390
|
+
}
|
|
391
|
+
if (whenSelector.relationship === "descendant") {
|
|
392
|
+
return `${targetSelector}:has(${markerSelector}) {
|
|
393
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
394
|
+
}`;
|
|
395
|
+
}
|
|
396
|
+
if (whenSelector.relationship === "siblingAfter") {
|
|
397
|
+
return `${targetSelector}:has(~ ${markerSelector}) {
|
|
398
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
399
|
+
}`;
|
|
400
|
+
}
|
|
401
|
+
if (whenSelector.relationship === "siblingBefore") {
|
|
402
|
+
return `${markerSelector} ~ ${targetSelector} {
|
|
403
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
404
|
+
}`;
|
|
405
|
+
}
|
|
406
|
+
if (whenSelector.relationship === "anySibling") {
|
|
407
|
+
return `${targetSelector}:has(~ ${markerSelector}), ${markerSelector} ~ ${targetSelector} {
|
|
408
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
409
|
+
}`;
|
|
410
|
+
}
|
|
411
|
+
return `${markerSelector} ${targetSelector} {
|
|
412
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
413
|
+
}`;
|
|
414
|
+
}
|
|
415
|
+
function formatMediaRule(rule) {
|
|
416
|
+
return `${rule.mediaQuery} {
|
|
417
|
+
.${rule.className}.${rule.className} {
|
|
418
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
419
|
+
}
|
|
420
|
+
}`;
|
|
421
|
+
}
|
|
422
|
+
function formatMediaPseudoRule(rule) {
|
|
423
|
+
return `${rule.mediaQuery} {
|
|
424
|
+
.${rule.className}.${rule.className}${rule.pseudoClass} {
|
|
425
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
426
|
+
}
|
|
427
|
+
}`;
|
|
428
|
+
}
|
|
429
|
+
function formatMediaPseudoElementRule(rule) {
|
|
430
|
+
const pe = rule.pseudoElement ?? "";
|
|
431
|
+
return `${rule.mediaQuery} {
|
|
432
|
+
.${rule.className}.${rule.className}${pe} {
|
|
433
|
+
${rule.cssProperty}: ${rule.cssValue};
|
|
434
|
+
}
|
|
435
|
+
}`;
|
|
436
|
+
}
|
|
437
|
+
function buildStyleHashProperties(segments, mapping, maybeIncHelperName) {
|
|
438
|
+
const propGroups = /* @__PURE__ */ new Map();
|
|
439
|
+
for (const seg of segments) {
|
|
440
|
+
if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
|
|
441
|
+
if (seg.variableProps) {
|
|
442
|
+
const prefix = seg.whenPseudo ? whenPrefix(seg.whenPseudo) : conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
443
|
+
const baseKey = seg.key.split("__")[0];
|
|
444
|
+
for (const prop of seg.variableProps) {
|
|
445
|
+
const className = prefix ? `${prefix}${baseKey}_var` : `${baseKey}_var`;
|
|
446
|
+
const varName = toCssVariableName(className, baseKey, prop);
|
|
447
|
+
if (!propGroups.has(prop)) propGroups.set(prop, []);
|
|
448
|
+
propGroups.get(prop).push({
|
|
449
|
+
className,
|
|
450
|
+
isVariable: true,
|
|
451
|
+
varName,
|
|
452
|
+
argNode: seg.argNode,
|
|
453
|
+
incremented: seg.incremented,
|
|
454
|
+
appendPx: seg.appendPx
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
if (seg.variableExtraDefs) {
|
|
458
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
459
|
+
const extraBase = `${baseKey}_${cssProp}`;
|
|
460
|
+
const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
|
|
461
|
+
if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
|
|
462
|
+
propGroups.get(cssProp).push({ className: extraName, isVariable: false });
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
} else {
|
|
466
|
+
const rawDefs = seg.whenPseudo ? seg.defs : unwrapDefs(seg.defs, seg.pseudoElement);
|
|
467
|
+
const prefix = seg.whenPseudo ? whenPrefix(seg.whenPseudo) : conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
468
|
+
const isMultiProp = Object.keys(rawDefs).length > 1;
|
|
469
|
+
for (const cssProp of Object.keys(rawDefs)) {
|
|
470
|
+
const val = extractLeafValue(rawDefs[cssProp]);
|
|
471
|
+
if (val === null) continue;
|
|
472
|
+
const baseName = computeStaticBaseName(seg, cssProp, String(val), isMultiProp, mapping);
|
|
473
|
+
const className = prefix ? `${prefix}${baseName}` : baseName;
|
|
474
|
+
if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
|
|
475
|
+
propGroups.get(cssProp).push({ className, isVariable: false });
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
const properties = [];
|
|
480
|
+
for (const [cssProp, entries] of Array.from(propGroups.entries())) {
|
|
481
|
+
const classNames = entries.map((e) => e.className).join(" ");
|
|
482
|
+
const variableEntries = entries.filter((e) => e.isVariable);
|
|
483
|
+
if (variableEntries.length > 0) {
|
|
484
|
+
const varsProps = [];
|
|
485
|
+
for (const dyn of variableEntries) {
|
|
486
|
+
let valueExpr = dyn.argNode;
|
|
487
|
+
if (dyn.incremented) {
|
|
488
|
+
valueExpr = t.callExpression(t.identifier(maybeIncHelperName ?? "__maybeInc"), [valueExpr]);
|
|
489
|
+
} else if (dyn.appendPx) {
|
|
490
|
+
valueExpr = t.templateLiteral(
|
|
491
|
+
[t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
|
|
492
|
+
[valueExpr]
|
|
493
|
+
);
|
|
494
|
+
}
|
|
495
|
+
varsProps.push(t.objectProperty(t.stringLiteral(dyn.varName), valueExpr));
|
|
496
|
+
}
|
|
497
|
+
const tuple = t.arrayExpression([t.stringLiteral(classNames), t.objectExpression(varsProps)]);
|
|
498
|
+
properties.push(t.objectProperty(toPropertyKey(cssProp), tuple));
|
|
499
|
+
} else {
|
|
500
|
+
properties.push(t.objectProperty(toPropertyKey(cssProp), t.stringLiteral(classNames)));
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return properties;
|
|
504
|
+
}
|
|
505
|
+
function toCssVariableName(className, baseKey, cssProp) {
|
|
506
|
+
const baseClassName = `${baseKey}_var`;
|
|
507
|
+
const conditionPrefix2 = className.endsWith(baseClassName) ? className.slice(0, -baseClassName.length) : "";
|
|
508
|
+
return `--${conditionPrefix2}${cssProp}`;
|
|
509
|
+
}
|
|
510
|
+
function buildMaybeIncDeclaration(helperName, increment) {
|
|
511
|
+
const incParam = t.identifier("inc");
|
|
512
|
+
const body = t.blockStatement([
|
|
513
|
+
t.returnStatement(
|
|
514
|
+
t.conditionalExpression(
|
|
515
|
+
t.binaryExpression("===", t.unaryExpression("typeof", incParam), t.stringLiteral("string")),
|
|
516
|
+
incParam,
|
|
517
|
+
t.templateLiteral(
|
|
518
|
+
[t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
|
|
519
|
+
[t.binaryExpression("*", incParam, t.numericLiteral(increment))]
|
|
520
|
+
)
|
|
521
|
+
)
|
|
522
|
+
)
|
|
523
|
+
]);
|
|
524
|
+
return t.variableDeclaration("const", [
|
|
525
|
+
t.variableDeclarator(t.identifier(helperName), t.arrowFunctionExpression([incParam], body))
|
|
526
|
+
]);
|
|
527
|
+
}
|
|
528
|
+
function toPropertyKey(key) {
|
|
529
|
+
return isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);
|
|
530
|
+
}
|
|
531
|
+
function isValidIdentifier(s) {
|
|
532
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
|
|
533
|
+
}
|
|
534
|
+
function buildRuntimeLookupDeclaration(lookupName, segmentsByName, mapping) {
|
|
535
|
+
const properties = [];
|
|
536
|
+
for (const [name, segs] of Object.entries(segmentsByName)) {
|
|
537
|
+
const hashProps = buildStyleHashProperties(segs, mapping);
|
|
538
|
+
properties.push(t.objectProperty(t.identifier(name), t.objectExpression(hashProps)));
|
|
539
|
+
}
|
|
540
|
+
return t.variableDeclaration("const", [
|
|
541
|
+
t.variableDeclarator(t.identifier(lookupName), t.objectExpression(properties))
|
|
542
|
+
]);
|
|
543
|
+
}
|
|
4
544
|
|
|
5
545
|
// src/plugin/transform.ts
|
|
6
546
|
import { parse } from "@babel/parser";
|
|
@@ -10,7 +550,7 @@ import * as t4 from "@babel/types";
|
|
|
10
550
|
import { basename } from "path";
|
|
11
551
|
|
|
12
552
|
// src/plugin/resolve-chain.ts
|
|
13
|
-
function resolveFullChain(chain, mapping) {
|
|
553
|
+
function resolveFullChain(chain, mapping, options) {
|
|
14
554
|
const parts = [];
|
|
15
555
|
const markers = [];
|
|
16
556
|
const filteredChain = [];
|
|
@@ -41,9 +581,10 @@ function resolveFullChain(chain, mapping) {
|
|
|
41
581
|
continue;
|
|
42
582
|
}
|
|
43
583
|
if (currentNodes.length > 0) {
|
|
584
|
+
const unconditionalSegs = resolveChain(currentNodes, mapping);
|
|
44
585
|
parts.push({
|
|
45
586
|
type: "unconditional",
|
|
46
|
-
segments: mergeOverlappingConditions(
|
|
587
|
+
segments: options?.skipMerge ? unconditionalSegs : mergeOverlappingConditions(unconditionalSegs)
|
|
47
588
|
});
|
|
48
589
|
currentNodes = [];
|
|
49
590
|
}
|
|
@@ -67,11 +608,13 @@ function resolveFullChain(chain, mapping) {
|
|
|
67
608
|
}
|
|
68
609
|
i++;
|
|
69
610
|
}
|
|
611
|
+
const thenSegs = resolveChain(thenNodes, mapping);
|
|
612
|
+
const elseSegs = resolveChain(elseNodes, mapping);
|
|
70
613
|
parts.push({
|
|
71
614
|
type: "conditional",
|
|
72
615
|
conditionNode: node.conditionNode,
|
|
73
|
-
thenSegments: mergeOverlappingConditions(
|
|
74
|
-
elseSegments: mergeOverlappingConditions(
|
|
616
|
+
thenSegments: options?.skipMerge ? thenSegs : mergeOverlappingConditions(thenSegs),
|
|
617
|
+
elseSegments: options?.skipMerge ? elseSegs : mergeOverlappingConditions(elseSegs)
|
|
75
618
|
});
|
|
76
619
|
} else {
|
|
77
620
|
currentNodes.push(node);
|
|
@@ -79,7 +622,11 @@ function resolveFullChain(chain, mapping) {
|
|
|
79
622
|
}
|
|
80
623
|
}
|
|
81
624
|
if (currentNodes.length > 0) {
|
|
82
|
-
|
|
625
|
+
const remainingSegs = resolveChain(currentNodes, mapping);
|
|
626
|
+
parts.push({
|
|
627
|
+
type: "unconditional",
|
|
628
|
+
segments: options?.skipMerge ? remainingSegs : mergeOverlappingConditions(remainingSegs)
|
|
629
|
+
});
|
|
83
630
|
}
|
|
84
631
|
const segmentErrors = [];
|
|
85
632
|
for (const part of parts) {
|
|
@@ -139,7 +686,14 @@ function resolveChain(chain, mapping) {
|
|
|
139
686
|
continue;
|
|
140
687
|
}
|
|
141
688
|
if (abbr === "add") {
|
|
142
|
-
const seg = resolveAddCall(
|
|
689
|
+
const seg = resolveAddCall(
|
|
690
|
+
node,
|
|
691
|
+
mapping,
|
|
692
|
+
currentMediaQuery,
|
|
693
|
+
currentPseudoClass,
|
|
694
|
+
currentPseudoElement,
|
|
695
|
+
currentWhenPseudo
|
|
696
|
+
);
|
|
143
697
|
segments.push(seg);
|
|
144
698
|
continue;
|
|
145
699
|
}
|
|
@@ -184,15 +738,16 @@ function resolveChain(chain, mapping) {
|
|
|
184
738
|
if (!entry) {
|
|
185
739
|
throw new UnsupportedPatternError(`Unknown abbreviation "${abbr}"`);
|
|
186
740
|
}
|
|
187
|
-
if (entry.kind === "
|
|
188
|
-
const seg =
|
|
741
|
+
if (entry.kind === "variable") {
|
|
742
|
+
const seg = resolveVariableCall(
|
|
189
743
|
abbr,
|
|
190
744
|
entry,
|
|
191
745
|
node,
|
|
192
746
|
mapping,
|
|
193
747
|
currentMediaQuery,
|
|
194
748
|
currentPseudoClass,
|
|
195
|
-
currentPseudoElement
|
|
749
|
+
currentPseudoElement,
|
|
750
|
+
currentWhenPseudo
|
|
196
751
|
);
|
|
197
752
|
segments.push(seg);
|
|
198
753
|
} else if (entry.kind === "delegate") {
|
|
@@ -203,7 +758,8 @@ function resolveChain(chain, mapping) {
|
|
|
203
758
|
mapping,
|
|
204
759
|
currentMediaQuery,
|
|
205
760
|
currentPseudoClass,
|
|
206
|
-
currentPseudoElement
|
|
761
|
+
currentPseudoElement,
|
|
762
|
+
currentWhenPseudo
|
|
207
763
|
);
|
|
208
764
|
segments.push(seg);
|
|
209
765
|
} else {
|
|
@@ -267,7 +823,7 @@ function resolveTypographyEntry(name, mapping, mediaQuery, pseudoClass, pseudoEl
|
|
|
267
823
|
}
|
|
268
824
|
const resolved = resolveEntry(name, entry, mapping, mediaQuery, pseudoClass, pseudoElement, null);
|
|
269
825
|
for (const segment of resolved) {
|
|
270
|
-
if (segment.
|
|
826
|
+
if (segment.variableProps || segment.whenPseudo) {
|
|
271
827
|
throw new UnsupportedPatternError(`Typography abbreviation "${name}" cannot require runtime arguments`);
|
|
272
828
|
}
|
|
273
829
|
}
|
|
@@ -311,19 +867,43 @@ function resolveEntry(abbr, entry, mapping, mediaQuery, pseudoClass, pseudoEleme
|
|
|
311
867
|
}
|
|
312
868
|
return result;
|
|
313
869
|
}
|
|
314
|
-
case "
|
|
870
|
+
case "variable":
|
|
315
871
|
case "delegate":
|
|
316
872
|
throw new UnsupportedPatternError(`Abbreviation "${abbr}" requires arguments \u2014 use ${abbr}() not .${abbr}`);
|
|
317
873
|
default:
|
|
318
874
|
throw new UnsupportedPatternError(`Unhandled entry kind for "${abbr}"`);
|
|
319
875
|
}
|
|
320
876
|
}
|
|
321
|
-
function
|
|
877
|
+
function resolveVariableCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
322
878
|
if (node.args.length !== 1) {
|
|
323
879
|
throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
|
|
324
880
|
}
|
|
325
881
|
const argAst = node.args[0];
|
|
326
882
|
const literalValue = tryEvaluateLiteral(argAst, entry.incremented, mapping.increment);
|
|
883
|
+
if (whenPseudo) {
|
|
884
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
885
|
+
if (literalValue !== null) {
|
|
886
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
887
|
+
const key = `${abbr}__${keySuffix}__${wpSuffix}`;
|
|
888
|
+
const defs = {};
|
|
889
|
+
for (const prop of entry.props) {
|
|
890
|
+
defs[prop] = literalValue;
|
|
891
|
+
}
|
|
892
|
+
if (entry.extraDefs) Object.assign(defs, entry.extraDefs);
|
|
893
|
+
return { key, defs, whenPseudo, argResolved: literalValue };
|
|
894
|
+
} else {
|
|
895
|
+
const key = `${abbr}__${wpSuffix}`;
|
|
896
|
+
return {
|
|
897
|
+
key,
|
|
898
|
+
defs: {},
|
|
899
|
+
whenPseudo,
|
|
900
|
+
variableProps: entry.props,
|
|
901
|
+
incremented: entry.incremented,
|
|
902
|
+
variableExtraDefs: entry.extraDefs,
|
|
903
|
+
argNode: argAst
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
}
|
|
327
907
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
328
908
|
if (literalValue !== null) {
|
|
329
909
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
@@ -351,23 +931,48 @@ function resolveDynamicCall(abbr, entry, node, mapping, mediaQuery, pseudoClass,
|
|
|
351
931
|
defs: {},
|
|
352
932
|
mediaQuery,
|
|
353
933
|
pseudoClass,
|
|
354
|
-
|
|
934
|
+
variableProps: entry.props,
|
|
355
935
|
incremented: entry.incremented,
|
|
356
|
-
|
|
936
|
+
variableExtraDefs: entry.extraDefs,
|
|
357
937
|
argNode: argAst
|
|
358
938
|
};
|
|
359
939
|
}
|
|
360
940
|
}
|
|
361
|
-
function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
941
|
+
function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
362
942
|
const targetEntry = mapping.abbreviations[entry.target];
|
|
363
|
-
if (!targetEntry || targetEntry.kind !== "
|
|
364
|
-
throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a
|
|
943
|
+
if (!targetEntry || targetEntry.kind !== "variable") {
|
|
944
|
+
throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a variable entry`);
|
|
365
945
|
}
|
|
366
946
|
if (node.args.length !== 1) {
|
|
367
947
|
throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
|
|
368
948
|
}
|
|
369
949
|
const argAst = node.args[0];
|
|
370
950
|
const literalValue = tryEvaluatePxLiteral(argAst);
|
|
951
|
+
if (whenPseudo) {
|
|
952
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
953
|
+
if (literalValue !== null) {
|
|
954
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
955
|
+
const key = `${entry.target}__${keySuffix}__${wpSuffix}`;
|
|
956
|
+
const defs = {};
|
|
957
|
+
for (const prop of targetEntry.props) {
|
|
958
|
+
defs[prop] = literalValue;
|
|
959
|
+
}
|
|
960
|
+
if (targetEntry.extraDefs) Object.assign(defs, targetEntry.extraDefs);
|
|
961
|
+
return { key, defs, whenPseudo, argResolved: literalValue };
|
|
962
|
+
} else {
|
|
963
|
+
const key = `${entry.target}__${wpSuffix}`;
|
|
964
|
+
return {
|
|
965
|
+
key,
|
|
966
|
+
defs: {},
|
|
967
|
+
whenPseudo,
|
|
968
|
+
variableProps: targetEntry.props,
|
|
969
|
+
incremented: false,
|
|
970
|
+
appendPx: true,
|
|
971
|
+
variableExtraDefs: targetEntry.extraDefs,
|
|
972
|
+
argNode: argAst
|
|
973
|
+
};
|
|
974
|
+
}
|
|
975
|
+
}
|
|
371
976
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
372
977
|
if (literalValue !== null) {
|
|
373
978
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
@@ -396,15 +1001,15 @@ function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass
|
|
|
396
1001
|
mediaQuery,
|
|
397
1002
|
pseudoClass,
|
|
398
1003
|
pseudoElement,
|
|
399
|
-
|
|
1004
|
+
variableProps: targetEntry.props,
|
|
400
1005
|
incremented: false,
|
|
401
1006
|
appendPx: true,
|
|
402
|
-
|
|
1007
|
+
variableExtraDefs: targetEntry.extraDefs,
|
|
403
1008
|
argNode: argAst
|
|
404
1009
|
};
|
|
405
1010
|
}
|
|
406
1011
|
}
|
|
407
|
-
function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
1012
|
+
function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
408
1013
|
if (node.args.length === 1) {
|
|
409
1014
|
const styleArg = node.args[0];
|
|
410
1015
|
if (styleArg.type === "SpreadElement") {
|
|
@@ -433,6 +1038,17 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
|
433
1038
|
const propName = propArg.value;
|
|
434
1039
|
const valueArg = node.args[1];
|
|
435
1040
|
const literalValue = tryEvaluateAddLiteral(valueArg);
|
|
1041
|
+
if (whenPseudo) {
|
|
1042
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
1043
|
+
if (literalValue !== null) {
|
|
1044
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1045
|
+
const key = `add_${propName}__${keySuffix}__${wpSuffix}`;
|
|
1046
|
+
return { key, defs: { [propName]: literalValue }, whenPseudo, argResolved: literalValue };
|
|
1047
|
+
} else {
|
|
1048
|
+
const key = `add_${propName}__${wpSuffix}`;
|
|
1049
|
+
return { key, defs: {}, whenPseudo, variableProps: [propName], incremented: false, argNode: valueArg };
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
436
1052
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
437
1053
|
if (literalValue !== null) {
|
|
438
1054
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
@@ -455,7 +1071,7 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
|
455
1071
|
mediaQuery,
|
|
456
1072
|
pseudoClass,
|
|
457
1073
|
pseudoElement,
|
|
458
|
-
|
|
1074
|
+
variableProps: [propName],
|
|
459
1075
|
incremented: false,
|
|
460
1076
|
argNode: valueArg
|
|
461
1077
|
};
|
|
@@ -530,7 +1146,7 @@ function mergeOverlappingConditions(segments) {
|
|
|
530
1146
|
const propToIndices = /* @__PURE__ */ new Map();
|
|
531
1147
|
for (let i = 0; i < segments.length; i++) {
|
|
532
1148
|
const seg = segments[i];
|
|
533
|
-
if (seg.
|
|
1149
|
+
if (seg.variableProps || seg.styleArrayArg || seg.whenPseudo || seg.error) continue;
|
|
534
1150
|
for (const prop of Object.keys(seg.defs)) {
|
|
535
1151
|
if (!propToIndices.has(prop)) propToIndices.set(prop, []);
|
|
536
1152
|
propToIndices.get(prop).push(i);
|
|
@@ -746,44 +1362,44 @@ var UnsupportedPatternError = class extends Error {
|
|
|
746
1362
|
};
|
|
747
1363
|
|
|
748
1364
|
// src/plugin/ast-utils.ts
|
|
749
|
-
import * as
|
|
1365
|
+
import * as t2 from "@babel/types";
|
|
750
1366
|
function collectTopLevelBindings(ast) {
|
|
751
1367
|
const used = /* @__PURE__ */ new Set();
|
|
752
1368
|
for (const node of ast.program.body) {
|
|
753
|
-
if (
|
|
1369
|
+
if (t2.isImportDeclaration(node)) {
|
|
754
1370
|
for (const spec of node.specifiers) {
|
|
755
1371
|
used.add(spec.local.name);
|
|
756
1372
|
}
|
|
757
1373
|
continue;
|
|
758
1374
|
}
|
|
759
|
-
if (
|
|
1375
|
+
if (t2.isVariableDeclaration(node)) {
|
|
760
1376
|
for (const decl of node.declarations) {
|
|
761
1377
|
collectPatternBindings(decl.id, used);
|
|
762
1378
|
}
|
|
763
1379
|
continue;
|
|
764
1380
|
}
|
|
765
|
-
if (
|
|
1381
|
+
if (t2.isFunctionDeclaration(node) && node.id) {
|
|
766
1382
|
used.add(node.id.name);
|
|
767
1383
|
continue;
|
|
768
1384
|
}
|
|
769
|
-
if (
|
|
1385
|
+
if (t2.isClassDeclaration(node) && node.id) {
|
|
770
1386
|
used.add(node.id.name);
|
|
771
1387
|
continue;
|
|
772
1388
|
}
|
|
773
|
-
if (
|
|
1389
|
+
if (t2.isExportNamedDeclaration(node) && node.declaration) {
|
|
774
1390
|
const decl = node.declaration;
|
|
775
|
-
if (
|
|
1391
|
+
if (t2.isVariableDeclaration(decl)) {
|
|
776
1392
|
for (const varDecl of decl.declarations) {
|
|
777
1393
|
collectPatternBindings(varDecl.id, used);
|
|
778
1394
|
}
|
|
779
|
-
} else if ((
|
|
1395
|
+
} else if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
|
|
780
1396
|
used.add(decl.id.name);
|
|
781
1397
|
}
|
|
782
1398
|
continue;
|
|
783
1399
|
}
|
|
784
|
-
if (
|
|
1400
|
+
if (t2.isExportDefaultDeclaration(node)) {
|
|
785
1401
|
const decl = node.declaration;
|
|
786
|
-
if ((
|
|
1402
|
+
if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
|
|
787
1403
|
used.add(decl.id.name);
|
|
788
1404
|
}
|
|
789
1405
|
}
|
|
@@ -791,37 +1407,37 @@ function collectTopLevelBindings(ast) {
|
|
|
791
1407
|
return used;
|
|
792
1408
|
}
|
|
793
1409
|
function collectPatternBindings(pattern, used) {
|
|
794
|
-
if (
|
|
1410
|
+
if (t2.isVoidPattern(pattern)) {
|
|
795
1411
|
return;
|
|
796
1412
|
}
|
|
797
|
-
if (
|
|
1413
|
+
if (t2.isIdentifier(pattern)) {
|
|
798
1414
|
used.add(pattern.name);
|
|
799
1415
|
return;
|
|
800
1416
|
}
|
|
801
|
-
if (
|
|
1417
|
+
if (t2.isAssignmentPattern(pattern)) {
|
|
802
1418
|
collectPatternBindings(pattern.left, used);
|
|
803
1419
|
return;
|
|
804
1420
|
}
|
|
805
|
-
if (
|
|
1421
|
+
if (t2.isRestElement(pattern)) {
|
|
806
1422
|
collectPatternBindings(pattern.argument, used);
|
|
807
1423
|
return;
|
|
808
1424
|
}
|
|
809
|
-
if (
|
|
1425
|
+
if (t2.isObjectPattern(pattern)) {
|
|
810
1426
|
for (const prop of pattern.properties) {
|
|
811
|
-
if (
|
|
1427
|
+
if (t2.isObjectProperty(prop)) {
|
|
812
1428
|
collectPatternBindings(prop.value, used);
|
|
813
|
-
} else if (
|
|
1429
|
+
} else if (t2.isRestElement(prop)) {
|
|
814
1430
|
collectPatternBindings(prop.argument, used);
|
|
815
1431
|
}
|
|
816
1432
|
}
|
|
817
1433
|
return;
|
|
818
1434
|
}
|
|
819
|
-
if (
|
|
1435
|
+
if (t2.isArrayPattern(pattern)) {
|
|
820
1436
|
for (const el of pattern.elements) {
|
|
821
1437
|
if (!el) continue;
|
|
822
|
-
if (
|
|
1438
|
+
if (t2.isIdentifier(el) || t2.isAssignmentPattern(el) || t2.isObjectPattern(el) || t2.isArrayPattern(el)) {
|
|
823
1439
|
collectPatternBindings(el, used);
|
|
824
|
-
} else if (
|
|
1440
|
+
} else if (t2.isRestElement(el)) {
|
|
825
1441
|
collectPatternBindings(el.argument, used);
|
|
826
1442
|
}
|
|
827
1443
|
}
|
|
@@ -848,9 +1464,9 @@ function reservePreferredName(used, preferred, secondary) {
|
|
|
848
1464
|
}
|
|
849
1465
|
function findCssImportBinding(ast) {
|
|
850
1466
|
for (const node of ast.program.body) {
|
|
851
|
-
if (!
|
|
1467
|
+
if (!t2.isImportDeclaration(node)) continue;
|
|
852
1468
|
for (const spec of node.specifiers) {
|
|
853
|
-
if (
|
|
1469
|
+
if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: "Css" })) {
|
|
854
1470
|
return spec.local.name;
|
|
855
1471
|
}
|
|
856
1472
|
}
|
|
@@ -859,9 +1475,9 @@ function findCssImportBinding(ast) {
|
|
|
859
1475
|
}
|
|
860
1476
|
function hasCssMethodCall(ast, binding, method) {
|
|
861
1477
|
let found = false;
|
|
862
|
-
|
|
1478
|
+
t2.traverseFast(ast, (node) => {
|
|
863
1479
|
if (found) return;
|
|
864
|
-
if (
|
|
1480
|
+
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
1481
|
found = true;
|
|
866
1482
|
}
|
|
867
1483
|
});
|
|
@@ -870,8 +1486,8 @@ function hasCssMethodCall(ast, binding, method) {
|
|
|
870
1486
|
function removeCssImport(ast, cssBinding) {
|
|
871
1487
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
872
1488
|
const node = ast.program.body[i];
|
|
873
|
-
if (!
|
|
874
|
-
const cssSpecIndex = node.specifiers.findIndex((s) =>
|
|
1489
|
+
if (!t2.isImportDeclaration(node)) continue;
|
|
1490
|
+
const cssSpecIndex = node.specifiers.findIndex((s) => t2.isImportSpecifier(s) && s.local.name === cssBinding);
|
|
875
1491
|
if (cssSpecIndex === -1) continue;
|
|
876
1492
|
if (node.specifiers.length === 1) {
|
|
877
1493
|
ast.program.body.splice(i, 1);
|
|
@@ -881,40 +1497,20 @@ function removeCssImport(ast, cssBinding) {
|
|
|
881
1497
|
return;
|
|
882
1498
|
}
|
|
883
1499
|
}
|
|
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
1500
|
function findLastImportIndex(ast) {
|
|
897
1501
|
let lastImportIndex = -1;
|
|
898
1502
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
899
|
-
if (
|
|
1503
|
+
if (t2.isImportDeclaration(ast.program.body[i])) {
|
|
900
1504
|
lastImportIndex = i;
|
|
901
1505
|
}
|
|
902
1506
|
}
|
|
903
1507
|
return lastImportIndex;
|
|
904
1508
|
}
|
|
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
1509
|
function findNamedImportBinding(ast, source, importedName) {
|
|
914
1510
|
for (const node of ast.program.body) {
|
|
915
|
-
if (!
|
|
1511
|
+
if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
|
|
916
1512
|
for (const spec of node.specifiers) {
|
|
917
|
-
if (
|
|
1513
|
+
if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: importedName })) {
|
|
918
1514
|
return spec.local.name;
|
|
919
1515
|
}
|
|
920
1516
|
}
|
|
@@ -924,21 +1520,21 @@ function findNamedImportBinding(ast, source, importedName) {
|
|
|
924
1520
|
function upsertNamedImports(ast, source, imports) {
|
|
925
1521
|
if (imports.length === 0) return;
|
|
926
1522
|
for (const node of ast.program.body) {
|
|
927
|
-
if (!
|
|
1523
|
+
if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
|
|
928
1524
|
for (const entry of imports) {
|
|
929
1525
|
const exists = node.specifiers.some(function(spec) {
|
|
930
|
-
return
|
|
1526
|
+
return t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: entry.importedName });
|
|
931
1527
|
});
|
|
932
1528
|
if (exists) continue;
|
|
933
|
-
node.specifiers.push(
|
|
1529
|
+
node.specifiers.push(t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName)));
|
|
934
1530
|
}
|
|
935
1531
|
return;
|
|
936
1532
|
}
|
|
937
|
-
const importDecl =
|
|
1533
|
+
const importDecl = t2.importDeclaration(
|
|
938
1534
|
imports.map(function(entry) {
|
|
939
|
-
return
|
|
1535
|
+
return t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName));
|
|
940
1536
|
}),
|
|
941
|
-
|
|
1537
|
+
t2.stringLiteral(source)
|
|
942
1538
|
);
|
|
943
1539
|
const idx = findLastImportIndex(ast);
|
|
944
1540
|
ast.program.body.splice(idx + 1, 0, importDecl);
|
|
@@ -947,11 +1543,11 @@ function extractChain(node, cssBinding) {
|
|
|
947
1543
|
const chain = [];
|
|
948
1544
|
let current = node;
|
|
949
1545
|
while (true) {
|
|
950
|
-
if (
|
|
1546
|
+
if (t2.isIdentifier(current, { name: cssBinding })) {
|
|
951
1547
|
chain.reverse();
|
|
952
1548
|
return chain;
|
|
953
1549
|
}
|
|
954
|
-
if (
|
|
1550
|
+
if (t2.isMemberExpression(current) && !current.computed && t2.isIdentifier(current.property)) {
|
|
955
1551
|
const name = current.property.name;
|
|
956
1552
|
if (name === "else") {
|
|
957
1553
|
chain.push({ type: "else" });
|
|
@@ -961,7 +1557,7 @@ function extractChain(node, cssBinding) {
|
|
|
961
1557
|
current = current.object;
|
|
962
1558
|
continue;
|
|
963
1559
|
}
|
|
964
|
-
if (
|
|
1560
|
+
if (t2.isCallExpression(current) && t2.isMemberExpression(current.callee) && !current.callee.computed && t2.isIdentifier(current.callee.property)) {
|
|
965
1561
|
const name = current.callee.property.name;
|
|
966
1562
|
if (name === "if") {
|
|
967
1563
|
chain.push({
|
|
@@ -983,328 +1579,28 @@ function extractChain(node, cssBinding) {
|
|
|
983
1579
|
}
|
|
984
1580
|
}
|
|
985
1581
|
|
|
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
1582
|
// src/plugin/rewrite-sites.ts
|
|
1246
1583
|
import _traverse from "@babel/traverse";
|
|
1247
1584
|
import _generate from "@babel/generator";
|
|
1248
1585
|
import * as t3 from "@babel/types";
|
|
1249
1586
|
var generate = _generate.default ?? _generate;
|
|
1250
1587
|
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
1588
|
function rewriteExpressionSites(options) {
|
|
1259
1589
|
for (const site of options.sites) {
|
|
1260
|
-
const
|
|
1590
|
+
const styleHash = buildStyleHashFromChain(site.resolvedChain, options);
|
|
1261
1591
|
const cssAttrPath = getCssAttributePath(site.path);
|
|
1592
|
+
const line = site.path.node.loc?.start.line ?? null;
|
|
1262
1593
|
if (cssAttrPath) {
|
|
1263
|
-
cssAttrPath.replaceWith(
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
options.mergePropsHelperName,
|
|
1270
|
-
options.needsMergePropsHelper,
|
|
1271
|
-
options
|
|
1272
|
-
)
|
|
1273
|
-
)
|
|
1274
|
-
);
|
|
1275
|
-
continue;
|
|
1594
|
+
cssAttrPath.replaceWith(t3.jsxSpreadAttribute(buildCssSpreadExpression(cssAttrPath, styleHash, line, options)));
|
|
1595
|
+
} else {
|
|
1596
|
+
if (options.debug && line !== null) {
|
|
1597
|
+
injectDebugInfo(styleHash, line, options);
|
|
1598
|
+
}
|
|
1599
|
+
site.path.replaceWith(styleHash);
|
|
1276
1600
|
}
|
|
1277
|
-
site.path.replaceWith(buildStyleArrayExpression(propsArgs, site.path.node.loc?.start.line ?? null, options));
|
|
1278
1601
|
}
|
|
1279
1602
|
rewriteCssPropsCalls(options);
|
|
1280
|
-
|
|
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
|
-
);
|
|
1603
|
+
rewriteCssAttributeExpressions(options);
|
|
1308
1604
|
}
|
|
1309
1605
|
function getCssAttributePath(path) {
|
|
1310
1606
|
const parentPath = path.parentPath;
|
|
@@ -1314,312 +1610,120 @@ function getCssAttributePath(path) {
|
|
|
1314
1610
|
if (!t3.isJSXIdentifier(attrPath.node.name, { name: "css" })) return null;
|
|
1315
1611
|
return attrPath;
|
|
1316
1612
|
}
|
|
1317
|
-
function
|
|
1318
|
-
const
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
t3.callExpression(
|
|
1325
|
-
t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("defaultMarker")),
|
|
1326
|
-
[]
|
|
1327
|
-
)
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1613
|
+
function buildStyleHashFromChain(chain, options) {
|
|
1614
|
+
const members = [];
|
|
1615
|
+
if (chain.markers.length > 0) {
|
|
1616
|
+
const markerClasses = chain.markers.map(function(marker) {
|
|
1617
|
+
return markerClassName(marker.markerNode);
|
|
1618
|
+
});
|
|
1619
|
+
members.push(t3.objectProperty(t3.identifier("__marker"), t3.stringLiteral(markerClasses.join(" "))));
|
|
1330
1620
|
}
|
|
1331
1621
|
for (const part of chain.parts) {
|
|
1332
1622
|
if (part.type === "unconditional") {
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
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(
|
|
1623
|
+
members.push(...buildStyleHashMembers(part.segments, options));
|
|
1624
|
+
} else {
|
|
1625
|
+
const thenMembers = buildStyleHashMembers(part.thenSegments, options);
|
|
1626
|
+
const elseMembers = buildStyleHashMembers(part.elseSegments, options);
|
|
1627
|
+
members.push(
|
|
1342
1628
|
t3.spreadElement(
|
|
1343
|
-
t3.conditionalExpression(part.conditionNode, t3.
|
|
1629
|
+
t3.conditionalExpression(part.conditionNode, t3.objectExpression(thenMembers), t3.objectExpression(elseMembers))
|
|
1344
1630
|
)
|
|
1345
1631
|
);
|
|
1346
1632
|
}
|
|
1347
1633
|
}
|
|
1348
|
-
return
|
|
1634
|
+
return t3.objectExpression(members);
|
|
1349
1635
|
}
|
|
1350
|
-
function
|
|
1351
|
-
const
|
|
1636
|
+
function buildStyleHashMembers(segments, options) {
|
|
1637
|
+
const members = [];
|
|
1638
|
+
const normalSegs = [];
|
|
1639
|
+
function flushNormal() {
|
|
1640
|
+
if (normalSegs.length > 0) {
|
|
1641
|
+
members.push(...buildStyleHashProperties(normalSegs, options.mapping, options.maybeIncHelperName));
|
|
1642
|
+
normalSegs.length = 0;
|
|
1643
|
+
}
|
|
1644
|
+
}
|
|
1352
1645
|
for (const seg of segments) {
|
|
1353
1646
|
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
1647
|
if (seg.styleArrayArg) {
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
buildUnknownSpreadFallback(
|
|
1371
|
-
seg.styleArrayArg,
|
|
1372
|
-
options.asStyleArrayHelperName,
|
|
1373
|
-
options.needsAsStyleArrayHelper
|
|
1374
|
-
)
|
|
1375
|
-
)
|
|
1376
|
-
);
|
|
1648
|
+
flushNormal();
|
|
1649
|
+
members.push(t3.spreadElement(seg.styleArrayArg));
|
|
1377
1650
|
continue;
|
|
1378
1651
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
if (
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
argExpr = t3.binaryExpression(
|
|
1388
|
-
"+",
|
|
1389
|
-
t3.callExpression(t3.identifier("String"), [seg.argNode]),
|
|
1390
|
-
t3.stringLiteral("px")
|
|
1652
|
+
if (seg.typographyLookup) {
|
|
1653
|
+
flushNormal();
|
|
1654
|
+
const lookupName = options.runtimeLookupNames.get(seg.typographyLookup.lookupKey);
|
|
1655
|
+
if (lookupName) {
|
|
1656
|
+
const lookupAccess = t3.memberExpression(
|
|
1657
|
+
t3.identifier(lookupName),
|
|
1658
|
+
seg.typographyLookup.argNode,
|
|
1659
|
+
true
|
|
1391
1660
|
);
|
|
1392
|
-
|
|
1393
|
-
argExpr = t3.callExpression(t3.identifier("String"), [seg.argNode]);
|
|
1661
|
+
members.push(t3.spreadElement(t3.logicalExpression("??", lookupAccess, t3.objectExpression([]))));
|
|
1394
1662
|
}
|
|
1395
|
-
|
|
1396
|
-
} else {
|
|
1397
|
-
args.push(ref);
|
|
1663
|
+
continue;
|
|
1398
1664
|
}
|
|
1665
|
+
normalSegs.push(seg);
|
|
1399
1666
|
}
|
|
1400
|
-
|
|
1667
|
+
flushNormal();
|
|
1668
|
+
return members;
|
|
1401
1669
|
}
|
|
1402
|
-
function
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
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
|
-
);
|
|
1442
|
-
}
|
|
1670
|
+
function injectDebugInfo(expr, line, options) {
|
|
1671
|
+
if (!options.debug) return;
|
|
1672
|
+
const firstProp = expr.properties.find(function(p) {
|
|
1673
|
+
return t3.isObjectProperty(p) && !(t3.isIdentifier(p.key) && p.key.name === "__marker" || t3.isStringLiteral(p.key) && p.key.value === "__marker");
|
|
1443
1674
|
});
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
const
|
|
1447
|
-
|
|
1448
|
-
return t3.arrayExpression(elements);
|
|
1449
|
-
}
|
|
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
|
|
1455
|
-
);
|
|
1456
|
-
}
|
|
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
|
|
1675
|
+
if (!firstProp) return;
|
|
1676
|
+
options.needsTrussDebugInfo.current = true;
|
|
1677
|
+
const debugExpr = t3.newExpression(t3.identifier(options.trussDebugInfoName), [
|
|
1678
|
+
t3.stringLiteral(`${options.filename}:${line}`)
|
|
1463
1679
|
]);
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
if (
|
|
1467
|
-
|
|
1680
|
+
if (t3.isStringLiteral(firstProp.value)) {
|
|
1681
|
+
firstProp.value = t3.arrayExpression([firstProp.value, debugExpr]);
|
|
1682
|
+
} else if (t3.isArrayExpression(firstProp.value)) {
|
|
1683
|
+
firstProp.value.elements.push(debugExpr);
|
|
1468
1684
|
}
|
|
1469
|
-
options.needsTrussDebugInfo.current = true;
|
|
1470
|
-
return [t3.newExpression(t3.identifier(options.trussDebugInfoName), [t3.stringLiteral(`${options.filename}:${line}`)])];
|
|
1471
|
-
}
|
|
1472
|
-
function lowerCssExpressionToPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
|
|
1473
|
-
return buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) ?? buildStyleArrayLikePropsArgsFromExpression(expr, path);
|
|
1474
1685
|
}
|
|
1475
|
-
function
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
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)})`;
|
|
1686
|
+
function buildCssSpreadExpression(path, styleHash, line, options) {
|
|
1687
|
+
const existingClassNameExpr = removeExistingAttribute(path, "className");
|
|
1688
|
+
const existingStyleExpr = removeExistingAttribute(path, "style");
|
|
1689
|
+
if (!existingClassNameExpr && !existingStyleExpr) {
|
|
1690
|
+
return buildPropsCall(styleHash, line, options);
|
|
1487
1691
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
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
|
|
1692
|
+
options.needsMergePropsHelper.current = true;
|
|
1693
|
+
if (options.debug && line !== null) {
|
|
1694
|
+
injectDebugInfo(styleHash, line, options);
|
|
1695
|
+
}
|
|
1696
|
+
return t3.callExpression(t3.identifier(options.mergePropsHelperName), [
|
|
1697
|
+
existingClassNameExpr ?? t3.identifier("undefined"),
|
|
1698
|
+
existingStyleExpr ?? t3.identifier("undefined"),
|
|
1699
|
+
styleHash
|
|
1503
1700
|
]);
|
|
1504
1701
|
}
|
|
1505
|
-
function
|
|
1702
|
+
function buildPropsCall(styleHash, line, options) {
|
|
1703
|
+
options.needsTrussPropsHelper.current = true;
|
|
1704
|
+
if (options.debug && line !== null && t3.isObjectExpression(styleHash)) {
|
|
1705
|
+
injectDebugInfo(styleHash, line, options);
|
|
1706
|
+
}
|
|
1707
|
+
return t3.callExpression(t3.identifier(options.trussPropsHelperName), [styleHash]);
|
|
1708
|
+
}
|
|
1709
|
+
function removeExistingAttribute(path, attrName) {
|
|
1506
1710
|
const openingElement = path.parentPath;
|
|
1507
1711
|
if (!openingElement || !openingElement.isJSXOpeningElement()) return null;
|
|
1508
1712
|
const attrs = openingElement.node.attributes;
|
|
1509
1713
|
for (let i = 0; i < attrs.length; i++) {
|
|
1510
1714
|
const attr = attrs[i];
|
|
1511
|
-
if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name:
|
|
1512
|
-
let
|
|
1715
|
+
if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name: attrName })) continue;
|
|
1716
|
+
let expr = null;
|
|
1513
1717
|
if (t3.isStringLiteral(attr.value)) {
|
|
1514
|
-
|
|
1718
|
+
expr = attr.value;
|
|
1515
1719
|
} else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
|
|
1516
|
-
|
|
1720
|
+
expr = attr.value.expression;
|
|
1517
1721
|
}
|
|
1518
1722
|
attrs.splice(i, 1);
|
|
1519
|
-
return
|
|
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))];
|
|
1723
|
+
return expr;
|
|
1573
1724
|
}
|
|
1574
1725
|
return null;
|
|
1575
1726
|
}
|
|
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
1727
|
function rewriteCssPropsCalls(options) {
|
|
1624
1728
|
traverse(options.ast, {
|
|
1625
1729
|
CallExpression(path) {
|
|
@@ -1627,28 +1731,51 @@ function rewriteCssPropsCalls(options) {
|
|
|
1627
1731
|
const arg = path.node.arguments[0];
|
|
1628
1732
|
if (!arg || t3.isSpreadElement(arg) || !t3.isExpression(arg) || path.node.arguments.length !== 1) return;
|
|
1629
1733
|
const line = path.node.loc?.start.line ?? null;
|
|
1630
|
-
|
|
1631
|
-
const
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
options.asStyleArrayHelperName,
|
|
1637
|
-
options.needsAsStyleArrayHelper
|
|
1734
|
+
options.needsTrussPropsHelper.current = true;
|
|
1735
|
+
const classNameExpr = extractSiblingClassName(path);
|
|
1736
|
+
if (classNameExpr) {
|
|
1737
|
+
options.needsMergePropsHelper.current = true;
|
|
1738
|
+
path.replaceWith(
|
|
1739
|
+
t3.callExpression(t3.identifier(options.mergePropsHelperName), [classNameExpr, t3.identifier("undefined"), arg])
|
|
1638
1740
|
);
|
|
1639
|
-
propsArgs = result.elements.filter((e) => e !== null);
|
|
1640
1741
|
} else {
|
|
1641
|
-
|
|
1742
|
+
path.replaceWith(t3.callExpression(t3.identifier(options.trussPropsHelperName), [arg]));
|
|
1642
1743
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1744
|
+
}
|
|
1745
|
+
});
|
|
1746
|
+
}
|
|
1747
|
+
function rewriteCssAttributeExpressions(options) {
|
|
1748
|
+
traverse(options.ast, {
|
|
1749
|
+
JSXAttribute(path) {
|
|
1750
|
+
if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
1751
|
+
const value = path.node.value;
|
|
1752
|
+
if (!t3.isJSXExpressionContainer(value)) return;
|
|
1753
|
+
if (!t3.isExpression(value.expression)) return;
|
|
1754
|
+
const expr = value.expression;
|
|
1755
|
+
const line = path.node.loc?.start.line ?? null;
|
|
1756
|
+
const existingClassNameExpr = removeExistingAttribute(path, "className");
|
|
1757
|
+
const existingStyleExpr = removeExistingAttribute(path, "style");
|
|
1758
|
+
if (existingClassNameExpr || existingStyleExpr) {
|
|
1759
|
+
options.needsMergePropsHelper.current = true;
|
|
1760
|
+
path.replaceWith(
|
|
1761
|
+
t3.jsxSpreadAttribute(
|
|
1762
|
+
t3.callExpression(t3.identifier(options.mergePropsHelperName), [
|
|
1763
|
+
existingClassNameExpr ?? t3.identifier("undefined"),
|
|
1764
|
+
existingStyleExpr ?? t3.identifier("undefined"),
|
|
1765
|
+
expr
|
|
1766
|
+
])
|
|
1767
|
+
)
|
|
1768
|
+
);
|
|
1646
1769
|
} else {
|
|
1647
|
-
|
|
1770
|
+
options.needsTrussPropsHelper.current = true;
|
|
1771
|
+
path.replaceWith(t3.jsxSpreadAttribute(t3.callExpression(t3.identifier(options.trussPropsHelperName), [expr])));
|
|
1648
1772
|
}
|
|
1649
1773
|
}
|
|
1650
1774
|
});
|
|
1651
1775
|
}
|
|
1776
|
+
function isCssPropsCall(expr, cssBindingName) {
|
|
1777
|
+
return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "props" });
|
|
1778
|
+
}
|
|
1652
1779
|
function extractSiblingClassName(callPath) {
|
|
1653
1780
|
const spreadPath = callPath.parentPath;
|
|
1654
1781
|
if (!spreadPath || !spreadPath.isSpreadElement()) return null;
|
|
@@ -1666,230 +1793,9 @@ function extractSiblingClassName(callPath) {
|
|
|
1666
1793
|
}
|
|
1667
1794
|
return null;
|
|
1668
1795
|
}
|
|
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
1796
|
function isMatchingPropertyName(key, name) {
|
|
1820
1797
|
return t3.isIdentifier(key) && key.name === name || t3.isStringLiteral(key) && key.value === name;
|
|
1821
1798
|
}
|
|
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
1799
|
|
|
1894
1800
|
// src/plugin/transform.ts
|
|
1895
1801
|
var traverse2 = _traverse2.default ?? _traverse2;
|
|
@@ -1915,7 +1821,7 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1915
1821
|
if (parentPath && parentPath.isMemberExpression() && t4.isIdentifier(parentPath.node.property, { name: "$" })) {
|
|
1916
1822
|
return;
|
|
1917
1823
|
}
|
|
1918
|
-
const resolvedChain = resolveFullChain(chain, mapping);
|
|
1824
|
+
const resolvedChain = resolveFullChain(chain, mapping, { skipMerge: true });
|
|
1919
1825
|
sites.push({ path, resolvedChain });
|
|
1920
1826
|
const line = path.node.loc?.start.line ?? null;
|
|
1921
1827
|
for (const err of resolvedChain.errors) {
|
|
@@ -1925,18 +1831,14 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1925
1831
|
});
|
|
1926
1832
|
const hasCssPropsCall = hasCssMethodCall(ast, cssBindingName, "props");
|
|
1927
1833
|
if (sites.length === 0 && !hasCssPropsCall) return null;
|
|
1928
|
-
const
|
|
1834
|
+
const chains = sites.map((s) => s.resolvedChain);
|
|
1835
|
+
const { rules, needsMaybeInc } = collectAtomicRules(chains, mapping);
|
|
1836
|
+
const cssText = generateCssText(rules);
|
|
1929
1837
|
const usedTopLevelNames = collectTopLevelBindings(ast);
|
|
1930
|
-
const existingStylexNamespace = findStylexNamespaceImport(ast);
|
|
1931
|
-
const stylexNamespaceName = existingStylexNamespace ?? reservePreferredName(usedTopLevelNames, "stylex");
|
|
1932
|
-
const createVarName = reservePreferredName(usedTopLevelNames, "css", "css_");
|
|
1933
1838
|
const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
|
|
1934
1839
|
const existingMergePropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "mergeProps");
|
|
1935
1840
|
const mergePropsHelperName = existingMergePropsHelperName ?? reservePreferredName(usedTopLevelNames, "mergeProps");
|
|
1936
1841
|
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
1842
|
const existingTrussPropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "trussProps");
|
|
1941
1843
|
const trussPropsHelperName = existingTrussPropsHelperName ?? reservePreferredName(usedTopLevelNames, "trussProps");
|
|
1942
1844
|
const needsTrussPropsHelper = { current: false };
|
|
@@ -1944,18 +1846,17 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1944
1846
|
const trussDebugInfoName = existingTrussDebugInfoName ?? reservePreferredName(usedTopLevelNames, "TrussDebugInfo");
|
|
1945
1847
|
const needsTrussDebugInfo = { current: false };
|
|
1946
1848
|
const runtimeLookupNames = /* @__PURE__ */ new Map();
|
|
1849
|
+
const runtimeLookups = collectRuntimeLookups(chains);
|
|
1947
1850
|
for (const [lookupKey] of runtimeLookups) {
|
|
1948
1851
|
runtimeLookupNames.set(lookupKey, reservePreferredName(usedTopLevelNames, `__${lookupKey}`));
|
|
1949
1852
|
}
|
|
1950
|
-
const createProperties = buildCreateProperties(createEntries, stylexNamespaceName);
|
|
1951
1853
|
rewriteExpressionSites({
|
|
1952
1854
|
ast,
|
|
1953
1855
|
sites,
|
|
1954
1856
|
cssBindingName,
|
|
1955
1857
|
filename: basename(filename),
|
|
1956
1858
|
debug: options.debug ?? false,
|
|
1957
|
-
|
|
1958
|
-
stylexNamespaceName,
|
|
1859
|
+
mapping,
|
|
1959
1860
|
maybeIncHelperName,
|
|
1960
1861
|
mergePropsHelperName,
|
|
1961
1862
|
needsMergePropsHelper,
|
|
@@ -1963,55 +1864,50 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1963
1864
|
needsTrussPropsHelper,
|
|
1964
1865
|
trussDebugInfoName,
|
|
1965
1866
|
needsTrussDebugInfo,
|
|
1966
|
-
asStyleArrayHelperName,
|
|
1967
|
-
needsAsStyleArrayHelper,
|
|
1968
1867
|
skippedCssPropMessages: errorMessages,
|
|
1969
1868
|
runtimeLookupNames
|
|
1970
1869
|
});
|
|
1971
1870
|
removeCssImport(ast, cssBindingName);
|
|
1972
|
-
|
|
1973
|
-
|
|
1871
|
+
const runtimeImports = [];
|
|
1872
|
+
if (needsTrussPropsHelper.current) {
|
|
1873
|
+
runtimeImports.push({ importedName: "trussProps", localName: trussPropsHelperName });
|
|
1974
1874
|
}
|
|
1975
|
-
if (needsMergePropsHelper.current
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
}
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
}
|
|
1986
|
-
if (needsTrussDebugInfo.current) {
|
|
1987
|
-
runtimeImports.push({ importedName: "TrussDebugInfo", localName: trussDebugInfoName });
|
|
1988
|
-
}
|
|
1875
|
+
if (needsMergePropsHelper.current) {
|
|
1876
|
+
runtimeImports.push({ importedName: "mergeProps", localName: mergePropsHelperName });
|
|
1877
|
+
}
|
|
1878
|
+
if (needsTrussDebugInfo.current) {
|
|
1879
|
+
runtimeImports.push({ importedName: "TrussDebugInfo", localName: trussDebugInfoName });
|
|
1880
|
+
}
|
|
1881
|
+
if (options.injectCss) {
|
|
1882
|
+
runtimeImports.push({ importedName: "__injectTrussCSS", localName: "__injectTrussCSS" });
|
|
1883
|
+
}
|
|
1884
|
+
if (runtimeImports.length > 0) {
|
|
1989
1885
|
upsertNamedImports(ast, "@homebound/truss/runtime", runtimeImports);
|
|
1990
1886
|
}
|
|
1991
|
-
const markerVarNames = collectReferencedMarkerNames(createEntries);
|
|
1992
|
-
const hoistedMarkerDecls = hoistMarkerDeclarations(ast, markerVarNames);
|
|
1993
1887
|
const declarationsToInsert = [];
|
|
1994
1888
|
if (maybeIncHelperName) {
|
|
1995
1889
|
declarationsToInsert.push(buildMaybeIncDeclaration(maybeIncHelperName, mapping.increment));
|
|
1996
1890
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
1891
|
+
for (const [lookupKey, lookup] of runtimeLookups) {
|
|
1892
|
+
const lookupName = runtimeLookupNames.get(lookupKey);
|
|
1893
|
+
if (!lookupName) continue;
|
|
1894
|
+
declarationsToInsert.push(buildRuntimeLookupDeclaration(lookupName, lookup.segmentsByName, mapping));
|
|
1895
|
+
}
|
|
1896
|
+
if (options.injectCss && cssText.length > 0) {
|
|
1897
|
+
declarationsToInsert.push(
|
|
1898
|
+
t4.expressionStatement(t4.callExpression(t4.identifier("__injectTrussCSS"), [t4.stringLiteral(cssText)]))
|
|
1899
|
+
);
|
|
2005
1900
|
}
|
|
2006
1901
|
for (const { message, line } of errorMessages) {
|
|
2007
1902
|
const location = line !== null ? `${filename}:${line}` : filename;
|
|
2008
1903
|
const logMessage = `${message} (${location})`;
|
|
2009
|
-
|
|
2010
|
-
t4.
|
|
2011
|
-
t4.
|
|
2012
|
-
|
|
1904
|
+
declarationsToInsert.push(
|
|
1905
|
+
t4.expressionStatement(
|
|
1906
|
+
t4.callExpression(t4.memberExpression(t4.identifier("console"), t4.identifier("error")), [
|
|
1907
|
+
t4.stringLiteral(logMessage)
|
|
1908
|
+
])
|
|
1909
|
+
)
|
|
2013
1910
|
);
|
|
2014
|
-
declarationsToInsert.push(consoleError);
|
|
2015
1911
|
}
|
|
2016
1912
|
if (declarationsToInsert.length > 0) {
|
|
2017
1913
|
const insertIndex = ast.program.body.findIndex(function(node) {
|
|
@@ -2023,46 +1919,23 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2023
1919
|
sourceFileName: filename,
|
|
2024
1920
|
retainLines: false
|
|
2025
1921
|
});
|
|
2026
|
-
return { code: output.code, map: output.map };
|
|
2027
|
-
}
|
|
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);
|
|
2033
|
-
}
|
|
2034
|
-
}
|
|
2035
|
-
return names;
|
|
1922
|
+
return { code: output.code, map: output.map, css: cssText, rules };
|
|
2036
1923
|
}
|
|
2037
|
-
function
|
|
2038
|
-
|
|
2039
|
-
const
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
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);
|
|
1924
|
+
function collectRuntimeLookups(chains) {
|
|
1925
|
+
const lookups = /* @__PURE__ */ new Map();
|
|
1926
|
+
for (const chain of chains) {
|
|
1927
|
+
for (const part of chain.parts) {
|
|
1928
|
+
const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
|
|
1929
|
+
for (const seg of segs) {
|
|
1930
|
+
if (seg.typographyLookup && !lookups.has(seg.typographyLookup.lookupKey)) {
|
|
1931
|
+
lookups.set(seg.typographyLookup.lookupKey, {
|
|
1932
|
+
segmentsByName: seg.typographyLookup.segmentsByName
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
2053
1935
|
}
|
|
2054
1936
|
}
|
|
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));
|
|
2062
|
-
}
|
|
2063
1937
|
}
|
|
2064
|
-
|
|
2065
|
-
return hoisted;
|
|
1938
|
+
return lookups;
|
|
2066
1939
|
}
|
|
2067
1940
|
|
|
2068
1941
|
// src/plugin/transform-css.ts
|
|
@@ -2231,8 +2104,8 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2231
2104
|
if (seg.error) {
|
|
2232
2105
|
return { error: seg.error };
|
|
2233
2106
|
}
|
|
2234
|
-
if (seg.
|
|
2235
|
-
return { error: `
|
|
2107
|
+
if (seg.variableProps && !seg.argResolved) {
|
|
2108
|
+
return { error: `variable value with variable argument is not supported in .css.ts files` };
|
|
2236
2109
|
}
|
|
2237
2110
|
if (seg.typographyLookup) {
|
|
2238
2111
|
return { error: `typography() with a runtime key is not supported in .css.ts files` };
|
|
@@ -2254,7 +2127,7 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2254
2127
|
}
|
|
2255
2128
|
for (const [prop, value] of Object.entries(seg.defs)) {
|
|
2256
2129
|
if (typeof value === "string" || typeof value === "number") {
|
|
2257
|
-
declarations.push({ property:
|
|
2130
|
+
declarations.push({ property: camelToKebab2(prop), value: String(value) });
|
|
2258
2131
|
} else {
|
|
2259
2132
|
return { error: `unexpected nested value for property "${prop}"` };
|
|
2260
2133
|
}
|
|
@@ -2263,7 +2136,7 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2263
2136
|
}
|
|
2264
2137
|
return { declarations };
|
|
2265
2138
|
}
|
|
2266
|
-
function
|
|
2139
|
+
function camelToKebab2(s) {
|
|
2267
2140
|
return s.replace(/^(Webkit|Moz|Ms|O)/, (m) => `-${m.toLowerCase()}`).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
2268
2141
|
}
|
|
2269
2142
|
function formatCssRule(selector, declarations) {
|
|
@@ -2331,11 +2204,19 @@ function toVirtualCssSpecifier(source) {
|
|
|
2331
2204
|
// src/plugin/index.ts
|
|
2332
2205
|
var VIRTUAL_CSS_PREFIX = "\0truss-css:";
|
|
2333
2206
|
var CSS_TS_QUERY = "?truss-css";
|
|
2207
|
+
var VIRTUAL_CSS_ENDPOINT = "/virtual:truss.css";
|
|
2208
|
+
var VIRTUAL_RUNTIME_ID = "virtual:truss:runtime";
|
|
2209
|
+
var RESOLVED_VIRTUAL_RUNTIME_ID = "\0" + VIRTUAL_RUNTIME_ID;
|
|
2334
2210
|
function trussPlugin(opts) {
|
|
2335
2211
|
let mapping = null;
|
|
2336
2212
|
let projectRoot;
|
|
2337
2213
|
let debug = false;
|
|
2214
|
+
let isTest = false;
|
|
2215
|
+
let isBuild = false;
|
|
2338
2216
|
const externalPackages = opts.externalPackages ?? [];
|
|
2217
|
+
const cssRegistry = /* @__PURE__ */ new Map();
|
|
2218
|
+
let cssVersion = 0;
|
|
2219
|
+
let lastSentVersion = 0;
|
|
2339
2220
|
function mappingPath() {
|
|
2340
2221
|
return resolve(projectRoot || process.cwd(), opts.mapping);
|
|
2341
2222
|
}
|
|
@@ -2345,23 +2226,98 @@ function trussPlugin(opts) {
|
|
|
2345
2226
|
}
|
|
2346
2227
|
return mapping;
|
|
2347
2228
|
}
|
|
2229
|
+
function collectCss() {
|
|
2230
|
+
return generateCssText(cssRegistry);
|
|
2231
|
+
}
|
|
2348
2232
|
return {
|
|
2349
|
-
name: "truss
|
|
2233
|
+
name: "truss",
|
|
2350
2234
|
enforce: "pre",
|
|
2351
2235
|
configResolved(config) {
|
|
2352
2236
|
projectRoot = config.root;
|
|
2353
2237
|
debug = config.command === "serve" || config.mode === "development" || config.mode === "test";
|
|
2238
|
+
isTest = config.mode === "test";
|
|
2239
|
+
isBuild = config.command === "build";
|
|
2354
2240
|
},
|
|
2355
2241
|
buildStart() {
|
|
2356
2242
|
ensureMapping();
|
|
2243
|
+
cssRegistry.clear();
|
|
2244
|
+
cssVersion = 0;
|
|
2245
|
+
lastSentVersion = 0;
|
|
2246
|
+
},
|
|
2247
|
+
// -- Dev mode HMR --
|
|
2248
|
+
configureServer(server) {
|
|
2249
|
+
if (isTest) return;
|
|
2250
|
+
server.middlewares.use(function(req, res, next) {
|
|
2251
|
+
if (req.url !== VIRTUAL_CSS_ENDPOINT) return next();
|
|
2252
|
+
const css = collectCss();
|
|
2253
|
+
res.setHeader("Content-Type", "text/css");
|
|
2254
|
+
res.setHeader("Cache-Control", "no-store");
|
|
2255
|
+
res.end(css);
|
|
2256
|
+
});
|
|
2257
|
+
const interval = setInterval(function() {
|
|
2258
|
+
if (cssVersion !== lastSentVersion && server.ws) {
|
|
2259
|
+
lastSentVersion = cssVersion;
|
|
2260
|
+
server.ws.send({ type: "custom", event: "truss:css-update" });
|
|
2261
|
+
}
|
|
2262
|
+
}, 150);
|
|
2263
|
+
server.httpServer?.on("close", function() {
|
|
2264
|
+
clearInterval(interval);
|
|
2265
|
+
});
|
|
2266
|
+
},
|
|
2267
|
+
transformIndexHtml(html) {
|
|
2268
|
+
if (isBuild) return html;
|
|
2269
|
+
const tags = [
|
|
2270
|
+
`<link rel="stylesheet" href="${VIRTUAL_CSS_ENDPOINT}">`,
|
|
2271
|
+
`<script type="module" src="/${VIRTUAL_RUNTIME_ID}"></script>`
|
|
2272
|
+
].join("\n ");
|
|
2273
|
+
return html.replace("</head>", ` ${tags}
|
|
2274
|
+
</head>`);
|
|
2275
|
+
},
|
|
2276
|
+
handleHotUpdate(ctx) {
|
|
2277
|
+
if (ctx.server?.ws) {
|
|
2278
|
+
ctx.server.ws.send({ type: "custom", event: "truss:css-update" });
|
|
2279
|
+
}
|
|
2357
2280
|
},
|
|
2281
|
+
// -- Virtual module resolution --
|
|
2358
2282
|
resolveId(source, importer) {
|
|
2283
|
+
if (source === VIRTUAL_RUNTIME_ID || source === "/" + VIRTUAL_RUNTIME_ID) {
|
|
2284
|
+
return RESOLVED_VIRTUAL_RUNTIME_ID;
|
|
2285
|
+
}
|
|
2359
2286
|
if (!source.endsWith(CSS_TS_QUERY)) return null;
|
|
2360
2287
|
const absolutePath = resolveImportPath(source.slice(0, -CSS_TS_QUERY.length), importer, projectRoot);
|
|
2361
2288
|
if (!existsSync(absolutePath)) return null;
|
|
2362
2289
|
return VIRTUAL_CSS_PREFIX + absolutePath.slice(0, -3);
|
|
2363
2290
|
},
|
|
2364
2291
|
load(id) {
|
|
2292
|
+
if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {
|
|
2293
|
+
return `
|
|
2294
|
+
// Truss dev HMR runtime \u2014 keeps styles up to date without page reload
|
|
2295
|
+
(function() {
|
|
2296
|
+
let style = document.getElementById("__truss_virtual__");
|
|
2297
|
+
if (!style) {
|
|
2298
|
+
style = document.createElement("style");
|
|
2299
|
+
style.id = "__truss_virtual__";
|
|
2300
|
+
document.head.appendChild(style);
|
|
2301
|
+
}
|
|
2302
|
+
|
|
2303
|
+
function fetchCss() {
|
|
2304
|
+
fetch("${VIRTUAL_CSS_ENDPOINT}")
|
|
2305
|
+
.then(function(r) { return r.text(); })
|
|
2306
|
+
.then(function(css) { style.textContent = css; })
|
|
2307
|
+
.catch(function() {});
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
fetchCss();
|
|
2311
|
+
|
|
2312
|
+
if (import.meta.hot) {
|
|
2313
|
+
import.meta.hot.on("truss:css-update", fetchCss);
|
|
2314
|
+
import.meta.hot.on("vite:afterUpdate", function() {
|
|
2315
|
+
setTimeout(fetchCss, 50);
|
|
2316
|
+
});
|
|
2317
|
+
}
|
|
2318
|
+
})();
|
|
2319
|
+
`;
|
|
2320
|
+
}
|
|
2365
2321
|
if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
|
|
2366
2322
|
const sourcePath = id.slice(VIRTUAL_CSS_PREFIX.length) + ".ts";
|
|
2367
2323
|
const sourceCode = readFileSync(sourcePath, "utf8");
|
|
@@ -2383,12 +2339,62 @@ function trussPlugin(opts) {
|
|
|
2383
2339
|
if (!hasCssDsl) {
|
|
2384
2340
|
return { code: rewrittenCode, map: null };
|
|
2385
2341
|
}
|
|
2386
|
-
const result = transformTruss(rewrittenCode, fileId, ensureMapping(), {
|
|
2342
|
+
const result = transformTruss(rewrittenCode, fileId, ensureMapping(), {
|
|
2343
|
+
debug,
|
|
2344
|
+
// In test mode (jsdom), inject CSS directly so document.styleSheets has rules
|
|
2345
|
+
injectCss: isTest
|
|
2346
|
+
});
|
|
2387
2347
|
if (!result) {
|
|
2388
2348
|
if (!rewrittenImports.changed) return null;
|
|
2389
2349
|
return { code: rewrittenCode, map: null };
|
|
2390
2350
|
}
|
|
2351
|
+
if (result.rules) {
|
|
2352
|
+
let hasNewRules = false;
|
|
2353
|
+
for (const [className, rule] of result.rules) {
|
|
2354
|
+
if (!cssRegistry.has(className)) {
|
|
2355
|
+
cssRegistry.set(className, rule);
|
|
2356
|
+
hasNewRules = true;
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
if (hasNewRules) {
|
|
2360
|
+
cssVersion++;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2391
2363
|
return { code: result.code, map: result.map };
|
|
2364
|
+
},
|
|
2365
|
+
// -- Production CSS emission --
|
|
2366
|
+
generateBundle(_options, bundle) {
|
|
2367
|
+
if (!isBuild) return;
|
|
2368
|
+
const css = collectCss();
|
|
2369
|
+
if (!css) return;
|
|
2370
|
+
for (const key of Object.keys(bundle)) {
|
|
2371
|
+
const asset = bundle[key];
|
|
2372
|
+
if (asset.type === "asset" && key.endsWith(".css")) {
|
|
2373
|
+
asset.source = asset.source + "\n" + css;
|
|
2374
|
+
return;
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
this.emitFile({
|
|
2378
|
+
type: "asset",
|
|
2379
|
+
fileName: "truss.css",
|
|
2380
|
+
source: css
|
|
2381
|
+
});
|
|
2382
|
+
},
|
|
2383
|
+
writeBundle(options, bundle) {
|
|
2384
|
+
if (!isBuild) return;
|
|
2385
|
+
const css = collectCss();
|
|
2386
|
+
if (!css) return;
|
|
2387
|
+
const outDir = options.dir || join(projectRoot, "dist");
|
|
2388
|
+
const trussPath = join(outDir, "truss.css");
|
|
2389
|
+
if (!existsSync(trussPath)) {
|
|
2390
|
+
const alreadyEmitted = Object.keys(bundle).some(function(key) {
|
|
2391
|
+
const asset = bundle[key];
|
|
2392
|
+
return asset.type === "asset" && key.endsWith(".css") && typeof asset.source === "string" && asset.source.includes(css);
|
|
2393
|
+
});
|
|
2394
|
+
if (!alreadyEmitted) {
|
|
2395
|
+
writeFileSync(trussPath, css, "utf8");
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2392
2398
|
}
|
|
2393
2399
|
};
|
|
2394
2400
|
}
|