@homebound/truss 2.0.13 → 2.1.0-next.2
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 +85 -33
- package/build/index.js.map +1 -1
- package/build/plugin/index.d.ts +11 -10
- package/build/plugin/index.js +1107 -1004
- 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,571 @@
|
|
|
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
|
+
const declaration = { cssProperty: camelToKebab(prop), cssValue: `var(${varName})`, cssVarName: varName };
|
|
169
|
+
const existingRule = rules.get(className);
|
|
170
|
+
if (!existingRule) {
|
|
171
|
+
rules.set(className, {
|
|
172
|
+
className,
|
|
173
|
+
cssProperty: declaration.cssProperty,
|
|
174
|
+
cssValue: declaration.cssValue,
|
|
175
|
+
declarations: [declaration],
|
|
176
|
+
pseudoClass: seg.pseudoClass ?? void 0,
|
|
177
|
+
mediaQuery: seg.mediaQuery ?? void 0,
|
|
178
|
+
pseudoElement: seg.pseudoElement ?? void 0,
|
|
179
|
+
cssVarName: varName
|
|
180
|
+
});
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
existingRule.declarations ??= [
|
|
184
|
+
{
|
|
185
|
+
cssProperty: existingRule.cssProperty,
|
|
186
|
+
cssValue: existingRule.cssValue,
|
|
187
|
+
cssVarName: existingRule.cssVarName
|
|
188
|
+
}
|
|
189
|
+
];
|
|
190
|
+
if (!existingRule.declarations.some(function(entry) {
|
|
191
|
+
return entry.cssProperty === declaration.cssProperty;
|
|
192
|
+
})) {
|
|
193
|
+
existingRule.declarations.push(declaration);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (seg.variableExtraDefs) {
|
|
197
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
198
|
+
const extraBase = `${baseKey}_${cssProp}`;
|
|
199
|
+
const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
|
|
200
|
+
if (!rules.has(extraName)) {
|
|
201
|
+
rules.set(extraName, {
|
|
202
|
+
className: extraName,
|
|
203
|
+
cssProperty: camelToKebab(cssProp),
|
|
204
|
+
cssValue: String(value),
|
|
205
|
+
pseudoClass: seg.pseudoClass ?? void 0,
|
|
206
|
+
mediaQuery: seg.mediaQuery ?? void 0,
|
|
207
|
+
pseudoElement: seg.pseudoElement ?? void 0
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
function collectWhenStaticRules(rules, seg, mapping) {
|
|
214
|
+
const wp = seg.whenPseudo;
|
|
215
|
+
const prefix = whenPrefix(wp);
|
|
216
|
+
const rawDefs = seg.defs;
|
|
217
|
+
const isMultiProp = Object.keys(rawDefs).length > 1;
|
|
218
|
+
const mClass = markerClassName(wp.markerNode);
|
|
219
|
+
for (const [cssProp, value] of Object.entries(rawDefs)) {
|
|
220
|
+
const cssValue = typeof value === "string" || typeof value === "number" ? value : extractLeafValue(value);
|
|
221
|
+
if (cssValue === null) continue;
|
|
222
|
+
const baseName = computeStaticBaseName(seg, cssProp, String(cssValue), isMultiProp, mapping);
|
|
223
|
+
const className = `${prefix}${baseName}`;
|
|
224
|
+
if (!rules.has(className)) {
|
|
225
|
+
rules.set(className, {
|
|
226
|
+
className,
|
|
227
|
+
cssProperty: camelToKebab(cssProp),
|
|
228
|
+
cssValue: String(cssValue),
|
|
229
|
+
whenSelector: {
|
|
230
|
+
relationship: wp.relationship ?? "ancestor",
|
|
231
|
+
markerClass: mClass,
|
|
232
|
+
pseudo: wp.pseudo
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function collectWhenVariableRules(rules, seg, mapping) {
|
|
239
|
+
const wp = seg.whenPseudo;
|
|
240
|
+
const prefix = whenPrefix(wp);
|
|
241
|
+
const baseKey = seg.key.split("__")[0];
|
|
242
|
+
const mClass = markerClassName(wp.markerNode);
|
|
243
|
+
for (const prop of seg.variableProps) {
|
|
244
|
+
const className = `${prefix}${baseKey}_var`;
|
|
245
|
+
const varName = toCssVariableName(className, baseKey, prop);
|
|
246
|
+
const declaration = { cssProperty: camelToKebab(prop), cssValue: `var(${varName})`, cssVarName: varName };
|
|
247
|
+
const existingRule = rules.get(className);
|
|
248
|
+
if (!existingRule) {
|
|
249
|
+
rules.set(className, {
|
|
250
|
+
className,
|
|
251
|
+
cssProperty: declaration.cssProperty,
|
|
252
|
+
cssValue: declaration.cssValue,
|
|
253
|
+
declarations: [declaration],
|
|
254
|
+
cssVarName: varName,
|
|
255
|
+
whenSelector: {
|
|
256
|
+
relationship: wp.relationship ?? "ancestor",
|
|
257
|
+
markerClass: mClass,
|
|
258
|
+
pseudo: wp.pseudo
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
existingRule.declarations ??= [
|
|
264
|
+
{
|
|
265
|
+
cssProperty: existingRule.cssProperty,
|
|
266
|
+
cssValue: existingRule.cssValue,
|
|
267
|
+
cssVarName: existingRule.cssVarName
|
|
268
|
+
}
|
|
269
|
+
];
|
|
270
|
+
if (!existingRule.declarations.some(function(entry) {
|
|
271
|
+
return entry.cssProperty === declaration.cssProperty;
|
|
272
|
+
})) {
|
|
273
|
+
existingRule.declarations.push(declaration);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
if (seg.variableExtraDefs) {
|
|
277
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
278
|
+
const extraName = `${prefix}${baseKey}_${cssProp}`;
|
|
279
|
+
if (!rules.has(extraName)) {
|
|
280
|
+
rules.set(extraName, {
|
|
281
|
+
className: extraName,
|
|
282
|
+
cssProperty: camelToKebab(cssProp),
|
|
283
|
+
cssValue: String(value),
|
|
284
|
+
whenSelector: {
|
|
285
|
+
relationship: wp.relationship ?? "ancestor",
|
|
286
|
+
markerClass: mClass,
|
|
287
|
+
pseudo: wp.pseudo
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
function unwrapDefs(defs, pseudoElement) {
|
|
295
|
+
let result = defs;
|
|
296
|
+
if (pseudoElement && result[pseudoElement] && typeof result[pseudoElement] === "object") {
|
|
297
|
+
result = result[pseudoElement];
|
|
298
|
+
}
|
|
299
|
+
const unwrapped = {};
|
|
300
|
+
for (const [prop, val] of Object.entries(result)) {
|
|
301
|
+
unwrapped[prop] = extractLeafValue(val) ?? val;
|
|
302
|
+
}
|
|
303
|
+
return unwrapped;
|
|
304
|
+
}
|
|
305
|
+
function extractLeafValue(value) {
|
|
306
|
+
if (typeof value === "string" || typeof value === "number") return value;
|
|
307
|
+
if (value === null) return null;
|
|
308
|
+
if (typeof value === "object") {
|
|
309
|
+
const obj = value;
|
|
310
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
311
|
+
if (k === "default") continue;
|
|
312
|
+
if (typeof v === "string" || typeof v === "number") return v;
|
|
313
|
+
if (typeof v === "object" && v !== null) return extractLeafValue(v);
|
|
314
|
+
}
|
|
315
|
+
if ("default" in obj && obj.default !== null) {
|
|
316
|
+
return extractLeafValue(obj.default);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
return null;
|
|
320
|
+
}
|
|
321
|
+
function generateCssText(rules) {
|
|
322
|
+
const allRules = Array.from(rules.values());
|
|
323
|
+
const base = [];
|
|
324
|
+
const pseudo = /* @__PURE__ */ new Map();
|
|
325
|
+
const pseudoElement = [];
|
|
326
|
+
const whenRules = [];
|
|
327
|
+
const media = [];
|
|
328
|
+
const mediaPseudo = [];
|
|
329
|
+
const mediaPseudoElement = [];
|
|
330
|
+
for (const rule of allRules) {
|
|
331
|
+
if (rule.whenSelector) {
|
|
332
|
+
whenRules.push(rule);
|
|
333
|
+
} else if (rule.mediaQuery && rule.pseudoClass) {
|
|
334
|
+
mediaPseudo.push(rule);
|
|
335
|
+
} else if (rule.mediaQuery && rule.pseudoElement) {
|
|
336
|
+
mediaPseudoElement.push(rule);
|
|
337
|
+
} else if (rule.mediaQuery) {
|
|
338
|
+
media.push(rule);
|
|
339
|
+
} else if (rule.pseudoClass && rule.pseudoElement) {
|
|
340
|
+
const tier = pseudo.get(rule.pseudoClass) ?? [];
|
|
341
|
+
tier.push(rule);
|
|
342
|
+
pseudo.set(rule.pseudoClass, tier);
|
|
343
|
+
} else if (rule.pseudoElement) {
|
|
344
|
+
pseudoElement.push(rule);
|
|
345
|
+
} else if (rule.pseudoClass) {
|
|
346
|
+
const tier = pseudo.get(rule.pseudoClass) ?? [];
|
|
347
|
+
tier.push(rule);
|
|
348
|
+
pseudo.set(rule.pseudoClass, tier);
|
|
349
|
+
} else {
|
|
350
|
+
base.push(rule);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const lines = [];
|
|
354
|
+
for (const rule of base) {
|
|
355
|
+
lines.push(formatBaseRule(rule));
|
|
356
|
+
}
|
|
357
|
+
for (const pc of PSEUDO_ORDER) {
|
|
358
|
+
const tier = pseudo.get(pc);
|
|
359
|
+
if (!tier) continue;
|
|
360
|
+
for (const rule of tier) {
|
|
361
|
+
lines.push(formatPseudoRule(rule));
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
for (const [pc, tier] of Array.from(pseudo.entries())) {
|
|
365
|
+
if (PSEUDO_ORDER.includes(pc)) continue;
|
|
366
|
+
for (const rule of tier) {
|
|
367
|
+
lines.push(formatPseudoRule(rule));
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
for (const rule of pseudoElement) {
|
|
371
|
+
lines.push(formatPseudoElementRule(rule));
|
|
372
|
+
}
|
|
373
|
+
for (const rule of whenRules) {
|
|
374
|
+
lines.push(formatWhenRule(rule));
|
|
375
|
+
}
|
|
376
|
+
for (const rule of media) {
|
|
377
|
+
lines.push(formatMediaRule(rule));
|
|
378
|
+
}
|
|
379
|
+
for (const rule of mediaPseudo) {
|
|
380
|
+
lines.push(formatMediaPseudoRule(rule));
|
|
381
|
+
}
|
|
382
|
+
for (const rule of mediaPseudoElement) {
|
|
383
|
+
lines.push(formatMediaPseudoElementRule(rule));
|
|
384
|
+
}
|
|
385
|
+
for (const rule of allRules) {
|
|
386
|
+
for (const declaration of getRuleDeclarations(rule)) {
|
|
387
|
+
if (declaration.cssVarName) {
|
|
388
|
+
lines.push(`@property ${declaration.cssVarName} {
|
|
389
|
+
syntax: "*";
|
|
390
|
+
inherits: false;
|
|
391
|
+
}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
return lines.join("\n");
|
|
396
|
+
}
|
|
397
|
+
function formatBaseRule(rule) {
|
|
398
|
+
return formatRuleBlock(`.${rule.className}`, rule);
|
|
399
|
+
}
|
|
400
|
+
function formatPseudoRule(rule) {
|
|
401
|
+
const pe = rule.pseudoElement ? rule.pseudoElement : "";
|
|
402
|
+
return formatRuleBlock(`.${rule.className}${rule.pseudoClass}${pe}`, rule);
|
|
403
|
+
}
|
|
404
|
+
function formatPseudoElementRule(rule) {
|
|
405
|
+
return formatRuleBlock(`.${rule.className}${rule.pseudoElement}`, rule);
|
|
406
|
+
}
|
|
407
|
+
function formatWhenRule(rule) {
|
|
408
|
+
const whenSelector = rule.whenSelector;
|
|
409
|
+
if (!whenSelector) {
|
|
410
|
+
return formatBaseRule(rule);
|
|
411
|
+
}
|
|
412
|
+
const markerSelector = `.${whenSelector.markerClass}${whenSelector.pseudo}`;
|
|
413
|
+
const targetSelector = `.${rule.className}`;
|
|
414
|
+
if (whenSelector.relationship === "ancestor") {
|
|
415
|
+
return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
|
|
416
|
+
}
|
|
417
|
+
if (whenSelector.relationship === "descendant") {
|
|
418
|
+
return formatRuleBlock(`${targetSelector}:has(${markerSelector})`, rule);
|
|
419
|
+
}
|
|
420
|
+
if (whenSelector.relationship === "siblingAfter") {
|
|
421
|
+
return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector})`, rule);
|
|
422
|
+
}
|
|
423
|
+
if (whenSelector.relationship === "siblingBefore") {
|
|
424
|
+
return formatRuleBlock(`${markerSelector} ~ ${targetSelector}`, rule);
|
|
425
|
+
}
|
|
426
|
+
if (whenSelector.relationship === "anySibling") {
|
|
427
|
+
return formatRuleBlock(`${targetSelector}:has(~ ${markerSelector}), ${markerSelector} ~ ${targetSelector}`, rule);
|
|
428
|
+
}
|
|
429
|
+
return formatRuleBlock(`${markerSelector} ${targetSelector}`, rule);
|
|
430
|
+
}
|
|
431
|
+
function formatMediaRule(rule) {
|
|
432
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}`, rule);
|
|
433
|
+
}
|
|
434
|
+
function formatMediaPseudoRule(rule) {
|
|
435
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${rule.pseudoClass}`, rule);
|
|
436
|
+
}
|
|
437
|
+
function formatMediaPseudoElementRule(rule) {
|
|
438
|
+
const pe = rule.pseudoElement ?? "";
|
|
439
|
+
return formatNestedRuleBlock(rule.mediaQuery, `.${rule.className}.${rule.className}${pe}`, rule);
|
|
440
|
+
}
|
|
441
|
+
function getRuleDeclarations(rule) {
|
|
442
|
+
return rule.declarations ?? [{ cssProperty: rule.cssProperty, cssValue: rule.cssValue, cssVarName: rule.cssVarName }];
|
|
443
|
+
}
|
|
444
|
+
function formatRuleBlock(selector, rule) {
|
|
445
|
+
const body = getRuleDeclarations(rule).map(function(declaration) {
|
|
446
|
+
return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
|
|
447
|
+
}).join("\n");
|
|
448
|
+
return `${selector} {
|
|
449
|
+
${body}
|
|
450
|
+
}`;
|
|
451
|
+
}
|
|
452
|
+
function formatNestedRuleBlock(wrapper, selector, rule) {
|
|
453
|
+
const body = getRuleDeclarations(rule).map(function(declaration) {
|
|
454
|
+
return ` ${declaration.cssProperty}: ${declaration.cssValue};`;
|
|
455
|
+
}).join("\n");
|
|
456
|
+
return `${wrapper} {
|
|
457
|
+
${selector} {
|
|
458
|
+
${body}
|
|
459
|
+
}
|
|
460
|
+
}`;
|
|
461
|
+
}
|
|
462
|
+
function buildStyleHashProperties(segments, mapping, maybeIncHelperName) {
|
|
463
|
+
const propGroups = /* @__PURE__ */ new Map();
|
|
464
|
+
for (const seg of segments) {
|
|
465
|
+
if (seg.error || seg.styleArrayArg || seg.typographyLookup) continue;
|
|
466
|
+
if (seg.variableProps) {
|
|
467
|
+
const prefix = seg.whenPseudo ? whenPrefix(seg.whenPseudo) : conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
468
|
+
const baseKey = seg.key.split("__")[0];
|
|
469
|
+
for (const prop of seg.variableProps) {
|
|
470
|
+
const className = prefix ? `${prefix}${baseKey}_var` : `${baseKey}_var`;
|
|
471
|
+
const varName = toCssVariableName(className, baseKey, prop);
|
|
472
|
+
if (!propGroups.has(prop)) propGroups.set(prop, []);
|
|
473
|
+
propGroups.get(prop).push({
|
|
474
|
+
className,
|
|
475
|
+
isVariable: true,
|
|
476
|
+
varName,
|
|
477
|
+
argNode: seg.argNode,
|
|
478
|
+
incremented: seg.incremented,
|
|
479
|
+
appendPx: seg.appendPx
|
|
480
|
+
});
|
|
481
|
+
}
|
|
482
|
+
if (seg.variableExtraDefs) {
|
|
483
|
+
for (const [cssProp, value] of Object.entries(seg.variableExtraDefs)) {
|
|
484
|
+
const extraBase = `${baseKey}_${cssProp}`;
|
|
485
|
+
const extraName = prefix ? `${prefix}${extraBase}` : extraBase;
|
|
486
|
+
if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
|
|
487
|
+
propGroups.get(cssProp).push({ className: extraName, isVariable: false });
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
} else {
|
|
491
|
+
const rawDefs = seg.whenPseudo ? seg.defs : unwrapDefs(seg.defs, seg.pseudoElement);
|
|
492
|
+
const prefix = seg.whenPseudo ? whenPrefix(seg.whenPseudo) : conditionPrefix(seg.pseudoClass, seg.mediaQuery, seg.pseudoElement, mapping.breakpoints);
|
|
493
|
+
const isMultiProp = Object.keys(rawDefs).length > 1;
|
|
494
|
+
for (const cssProp of Object.keys(rawDefs)) {
|
|
495
|
+
const val = extractLeafValue(rawDefs[cssProp]);
|
|
496
|
+
if (val === null) continue;
|
|
497
|
+
const baseName = computeStaticBaseName(seg, cssProp, String(val), isMultiProp, mapping);
|
|
498
|
+
const className = prefix ? `${prefix}${baseName}` : baseName;
|
|
499
|
+
if (!propGroups.has(cssProp)) propGroups.set(cssProp, []);
|
|
500
|
+
propGroups.get(cssProp).push({ className, isVariable: false });
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
const properties = [];
|
|
505
|
+
for (const [cssProp, entries] of Array.from(propGroups.entries())) {
|
|
506
|
+
const classNames = entries.map((e) => e.className).join(" ");
|
|
507
|
+
const variableEntries = entries.filter((e) => e.isVariable);
|
|
508
|
+
if (variableEntries.length > 0) {
|
|
509
|
+
const varsProps = [];
|
|
510
|
+
for (const dyn of variableEntries) {
|
|
511
|
+
let valueExpr = dyn.argNode;
|
|
512
|
+
if (dyn.incremented) {
|
|
513
|
+
valueExpr = t.callExpression(t.identifier(maybeIncHelperName ?? "__maybeInc"), [valueExpr]);
|
|
514
|
+
} else if (dyn.appendPx) {
|
|
515
|
+
valueExpr = t.templateLiteral(
|
|
516
|
+
[t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
|
|
517
|
+
[valueExpr]
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
varsProps.push(t.objectProperty(t.stringLiteral(dyn.varName), valueExpr));
|
|
521
|
+
}
|
|
522
|
+
const tuple = t.arrayExpression([t.stringLiteral(classNames), t.objectExpression(varsProps)]);
|
|
523
|
+
properties.push(t.objectProperty(toPropertyKey(cssProp), tuple));
|
|
524
|
+
} else {
|
|
525
|
+
properties.push(t.objectProperty(toPropertyKey(cssProp), t.stringLiteral(classNames)));
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return properties;
|
|
529
|
+
}
|
|
530
|
+
function toCssVariableName(className, baseKey, cssProp) {
|
|
531
|
+
const baseClassName = `${baseKey}_var`;
|
|
532
|
+
const conditionPrefix2 = className.endsWith(baseClassName) ? className.slice(0, -baseClassName.length) : "";
|
|
533
|
+
return `--${conditionPrefix2}${cssProp}`;
|
|
534
|
+
}
|
|
535
|
+
function buildMaybeIncDeclaration(helperName, increment) {
|
|
536
|
+
const incParam = t.identifier("inc");
|
|
537
|
+
const body = t.blockStatement([
|
|
538
|
+
t.returnStatement(
|
|
539
|
+
t.conditionalExpression(
|
|
540
|
+
t.binaryExpression("===", t.unaryExpression("typeof", incParam), t.stringLiteral("string")),
|
|
541
|
+
incParam,
|
|
542
|
+
t.templateLiteral(
|
|
543
|
+
[t.templateElement({ raw: "", cooked: "" }, false), t.templateElement({ raw: "px", cooked: "px" }, true)],
|
|
544
|
+
[t.binaryExpression("*", incParam, t.numericLiteral(increment))]
|
|
545
|
+
)
|
|
546
|
+
)
|
|
547
|
+
)
|
|
548
|
+
]);
|
|
549
|
+
return t.variableDeclaration("const", [
|
|
550
|
+
t.variableDeclarator(t.identifier(helperName), t.arrowFunctionExpression([incParam], body))
|
|
551
|
+
]);
|
|
552
|
+
}
|
|
553
|
+
function toPropertyKey(key) {
|
|
554
|
+
return isValidIdentifier(key) ? t.identifier(key) : t.stringLiteral(key);
|
|
555
|
+
}
|
|
556
|
+
function isValidIdentifier(s) {
|
|
557
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s);
|
|
558
|
+
}
|
|
559
|
+
function buildRuntimeLookupDeclaration(lookupName, segmentsByName, mapping) {
|
|
560
|
+
const properties = [];
|
|
561
|
+
for (const [name, segs] of Object.entries(segmentsByName)) {
|
|
562
|
+
const hashProps = buildStyleHashProperties(segs, mapping);
|
|
563
|
+
properties.push(t.objectProperty(t.identifier(name), t.objectExpression(hashProps)));
|
|
564
|
+
}
|
|
565
|
+
return t.variableDeclaration("const", [
|
|
566
|
+
t.variableDeclarator(t.identifier(lookupName), t.objectExpression(properties))
|
|
567
|
+
]);
|
|
568
|
+
}
|
|
4
569
|
|
|
5
570
|
// src/plugin/transform.ts
|
|
6
571
|
import { parse } from "@babel/parser";
|
|
@@ -10,7 +575,7 @@ import * as t4 from "@babel/types";
|
|
|
10
575
|
import { basename } from "path";
|
|
11
576
|
|
|
12
577
|
// src/plugin/resolve-chain.ts
|
|
13
|
-
function resolveFullChain(chain, mapping) {
|
|
578
|
+
function resolveFullChain(chain, mapping, options) {
|
|
14
579
|
const parts = [];
|
|
15
580
|
const markers = [];
|
|
16
581
|
const filteredChain = [];
|
|
@@ -33,6 +598,31 @@ function resolveFullChain(chain, mapping) {
|
|
|
33
598
|
let currentNodes = [];
|
|
34
599
|
while (i < filteredChain.length) {
|
|
35
600
|
const node = filteredChain[i];
|
|
601
|
+
const mediaStart = getMediaConditionalStartNode(node, mapping);
|
|
602
|
+
if (mediaStart) {
|
|
603
|
+
const elseIndex = findElseIndex(filteredChain, i + 1);
|
|
604
|
+
if (elseIndex !== -1) {
|
|
605
|
+
if (currentNodes.length > 0) {
|
|
606
|
+
const unconditionalSegs = resolveChain(currentNodes, mapping);
|
|
607
|
+
parts.push({
|
|
608
|
+
type: "unconditional",
|
|
609
|
+
segments: options?.skipMerge ? unconditionalSegs : mergeOverlappingConditions(unconditionalSegs)
|
|
610
|
+
});
|
|
611
|
+
currentNodes = [];
|
|
612
|
+
}
|
|
613
|
+
const thenNodes = mediaStart.thenNodes ? [...mediaStart.thenNodes, ...filteredChain.slice(i + 1, elseIndex)] : filteredChain.slice(i, elseIndex);
|
|
614
|
+
const elseNodes = [makeMediaQueryNode(mediaStart.inverseMediaQuery), ...filteredChain.slice(elseIndex + 1)];
|
|
615
|
+
const thenSegs = resolveChain(thenNodes, mapping);
|
|
616
|
+
const elseSegs = resolveChain(elseNodes, mapping);
|
|
617
|
+
const combinedSegs = [...thenSegs, ...elseSegs];
|
|
618
|
+
parts.push({
|
|
619
|
+
type: "unconditional",
|
|
620
|
+
segments: options?.skipMerge ? combinedSegs : mergeOverlappingConditions(combinedSegs)
|
|
621
|
+
});
|
|
622
|
+
i = filteredChain.length;
|
|
623
|
+
break;
|
|
624
|
+
}
|
|
625
|
+
}
|
|
36
626
|
if (node.type === "if") {
|
|
37
627
|
if (node.conditionNode.type === "StringLiteral") {
|
|
38
628
|
const mediaQuery = node.conditionNode.value;
|
|
@@ -41,9 +631,10 @@ function resolveFullChain(chain, mapping) {
|
|
|
41
631
|
continue;
|
|
42
632
|
}
|
|
43
633
|
if (currentNodes.length > 0) {
|
|
634
|
+
const unconditionalSegs = resolveChain(currentNodes, mapping);
|
|
44
635
|
parts.push({
|
|
45
636
|
type: "unconditional",
|
|
46
|
-
segments: mergeOverlappingConditions(
|
|
637
|
+
segments: options?.skipMerge ? unconditionalSegs : mergeOverlappingConditions(unconditionalSegs)
|
|
47
638
|
});
|
|
48
639
|
currentNodes = [];
|
|
49
640
|
}
|
|
@@ -67,11 +658,13 @@ function resolveFullChain(chain, mapping) {
|
|
|
67
658
|
}
|
|
68
659
|
i++;
|
|
69
660
|
}
|
|
661
|
+
const thenSegs = resolveChain(thenNodes, mapping);
|
|
662
|
+
const elseSegs = resolveChain(elseNodes, mapping);
|
|
70
663
|
parts.push({
|
|
71
664
|
type: "conditional",
|
|
72
665
|
conditionNode: node.conditionNode,
|
|
73
|
-
thenSegments: mergeOverlappingConditions(
|
|
74
|
-
elseSegments: mergeOverlappingConditions(
|
|
666
|
+
thenSegments: options?.skipMerge ? thenSegs : mergeOverlappingConditions(thenSegs),
|
|
667
|
+
elseSegments: options?.skipMerge ? elseSegs : mergeOverlappingConditions(elseSegs)
|
|
75
668
|
});
|
|
76
669
|
} else {
|
|
77
670
|
currentNodes.push(node);
|
|
@@ -79,7 +672,11 @@ function resolveFullChain(chain, mapping) {
|
|
|
79
672
|
}
|
|
80
673
|
}
|
|
81
674
|
if (currentNodes.length > 0) {
|
|
82
|
-
|
|
675
|
+
const remainingSegs = resolveChain(currentNodes, mapping);
|
|
676
|
+
parts.push({
|
|
677
|
+
type: "unconditional",
|
|
678
|
+
segments: options?.skipMerge ? remainingSegs : mergeOverlappingConditions(remainingSegs)
|
|
679
|
+
});
|
|
83
680
|
}
|
|
84
681
|
const segmentErrors = [];
|
|
85
682
|
for (const part of parts) {
|
|
@@ -92,6 +689,53 @@ function resolveFullChain(chain, mapping) {
|
|
|
92
689
|
}
|
|
93
690
|
return { parts, markers, errors: [...scanErrors, ...segmentErrors] };
|
|
94
691
|
}
|
|
692
|
+
function getMediaConditionalStartNode(node, mapping) {
|
|
693
|
+
if (node.type === "if" && node.conditionNode.type === "StringLiteral") {
|
|
694
|
+
return {
|
|
695
|
+
inverseMediaQuery: invertMediaQuery(node.conditionNode.value),
|
|
696
|
+
thenNodes: [makeMediaQueryNode(node.conditionNode.value)]
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
if (node.type === "getter" && mapping.breakpoints && node.name in mapping.breakpoints) {
|
|
700
|
+
return { inverseMediaQuery: invertMediaQuery(mapping.breakpoints[node.name]) };
|
|
701
|
+
}
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
function findElseIndex(chain, start) {
|
|
705
|
+
for (let i = start; i < chain.length; i++) {
|
|
706
|
+
if (chain[i].type === "if") {
|
|
707
|
+
return -1;
|
|
708
|
+
}
|
|
709
|
+
if (chain[i].type === "else") {
|
|
710
|
+
return i;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return -1;
|
|
714
|
+
}
|
|
715
|
+
function makeMediaQueryNode(mediaQuery) {
|
|
716
|
+
return { type: "__mediaQuery", mediaQuery };
|
|
717
|
+
}
|
|
718
|
+
function invertMediaQuery(query) {
|
|
719
|
+
const screenPrefix = "@media screen and ";
|
|
720
|
+
if (query.startsWith(screenPrefix)) {
|
|
721
|
+
const conditions = query.slice(screenPrefix.length).trim();
|
|
722
|
+
const rangeMatch = conditions.match(/^\(min-width: (\d+)px\) and \(max-width: (\d+)px\)$/);
|
|
723
|
+
if (rangeMatch) {
|
|
724
|
+
const min = Number(rangeMatch[1]);
|
|
725
|
+
const max = Number(rangeMatch[2]);
|
|
726
|
+
return `@media screen and (max-width: ${min - 1}px), screen and (min-width: ${max + 1}px)`;
|
|
727
|
+
}
|
|
728
|
+
const minMatch = conditions.match(/^\(min-width: (\d+)px\)$/);
|
|
729
|
+
if (minMatch) {
|
|
730
|
+
return `@media screen and (max-width: ${Number(minMatch[1]) - 1}px)`;
|
|
731
|
+
}
|
|
732
|
+
const maxMatch = conditions.match(/^\(max-width: (\d+)px\)$/);
|
|
733
|
+
if (maxMatch) {
|
|
734
|
+
return `@media screen and (min-width: ${Number(maxMatch[1]) + 1}px)`;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
return query.replace("@media", "@media not");
|
|
738
|
+
}
|
|
95
739
|
function resolveChain(chain, mapping) {
|
|
96
740
|
const segments = [];
|
|
97
741
|
let currentMediaQuery = null;
|
|
@@ -139,7 +783,14 @@ function resolveChain(chain, mapping) {
|
|
|
139
783
|
continue;
|
|
140
784
|
}
|
|
141
785
|
if (abbr === "add") {
|
|
142
|
-
const seg = resolveAddCall(
|
|
786
|
+
const seg = resolveAddCall(
|
|
787
|
+
node,
|
|
788
|
+
mapping,
|
|
789
|
+
currentMediaQuery,
|
|
790
|
+
currentPseudoClass,
|
|
791
|
+
currentPseudoElement,
|
|
792
|
+
currentWhenPseudo
|
|
793
|
+
);
|
|
143
794
|
segments.push(seg);
|
|
144
795
|
continue;
|
|
145
796
|
}
|
|
@@ -184,15 +835,16 @@ function resolveChain(chain, mapping) {
|
|
|
184
835
|
if (!entry) {
|
|
185
836
|
throw new UnsupportedPatternError(`Unknown abbreviation "${abbr}"`);
|
|
186
837
|
}
|
|
187
|
-
if (entry.kind === "
|
|
188
|
-
const seg =
|
|
838
|
+
if (entry.kind === "variable") {
|
|
839
|
+
const seg = resolveVariableCall(
|
|
189
840
|
abbr,
|
|
190
841
|
entry,
|
|
191
842
|
node,
|
|
192
843
|
mapping,
|
|
193
844
|
currentMediaQuery,
|
|
194
845
|
currentPseudoClass,
|
|
195
|
-
currentPseudoElement
|
|
846
|
+
currentPseudoElement,
|
|
847
|
+
currentWhenPseudo
|
|
196
848
|
);
|
|
197
849
|
segments.push(seg);
|
|
198
850
|
} else if (entry.kind === "delegate") {
|
|
@@ -203,7 +855,8 @@ function resolveChain(chain, mapping) {
|
|
|
203
855
|
mapping,
|
|
204
856
|
currentMediaQuery,
|
|
205
857
|
currentPseudoClass,
|
|
206
|
-
currentPseudoElement
|
|
858
|
+
currentPseudoElement,
|
|
859
|
+
currentWhenPseudo
|
|
207
860
|
);
|
|
208
861
|
segments.push(seg);
|
|
209
862
|
} else {
|
|
@@ -267,7 +920,7 @@ function resolveTypographyEntry(name, mapping, mediaQuery, pseudoClass, pseudoEl
|
|
|
267
920
|
}
|
|
268
921
|
const resolved = resolveEntry(name, entry, mapping, mediaQuery, pseudoClass, pseudoElement, null);
|
|
269
922
|
for (const segment of resolved) {
|
|
270
|
-
if (segment.
|
|
923
|
+
if (segment.variableProps || segment.whenPseudo) {
|
|
271
924
|
throw new UnsupportedPatternError(`Typography abbreviation "${name}" cannot require runtime arguments`);
|
|
272
925
|
}
|
|
273
926
|
}
|
|
@@ -311,19 +964,43 @@ function resolveEntry(abbr, entry, mapping, mediaQuery, pseudoClass, pseudoEleme
|
|
|
311
964
|
}
|
|
312
965
|
return result;
|
|
313
966
|
}
|
|
314
|
-
case "
|
|
967
|
+
case "variable":
|
|
315
968
|
case "delegate":
|
|
316
969
|
throw new UnsupportedPatternError(`Abbreviation "${abbr}" requires arguments \u2014 use ${abbr}() not .${abbr}`);
|
|
317
970
|
default:
|
|
318
971
|
throw new UnsupportedPatternError(`Unhandled entry kind for "${abbr}"`);
|
|
319
972
|
}
|
|
320
973
|
}
|
|
321
|
-
function
|
|
974
|
+
function resolveVariableCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
322
975
|
if (node.args.length !== 1) {
|
|
323
976
|
throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
|
|
324
977
|
}
|
|
325
978
|
const argAst = node.args[0];
|
|
326
979
|
const literalValue = tryEvaluateLiteral(argAst, entry.incremented, mapping.increment);
|
|
980
|
+
if (whenPseudo) {
|
|
981
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
982
|
+
if (literalValue !== null) {
|
|
983
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
984
|
+
const key = `${abbr}__${keySuffix}__${wpSuffix}`;
|
|
985
|
+
const defs = {};
|
|
986
|
+
for (const prop of entry.props) {
|
|
987
|
+
defs[prop] = literalValue;
|
|
988
|
+
}
|
|
989
|
+
if (entry.extraDefs) Object.assign(defs, entry.extraDefs);
|
|
990
|
+
return { key, defs, whenPseudo, argResolved: literalValue };
|
|
991
|
+
} else {
|
|
992
|
+
const key = `${abbr}__${wpSuffix}`;
|
|
993
|
+
return {
|
|
994
|
+
key,
|
|
995
|
+
defs: {},
|
|
996
|
+
whenPseudo,
|
|
997
|
+
variableProps: entry.props,
|
|
998
|
+
incremented: entry.incremented,
|
|
999
|
+
variableExtraDefs: entry.extraDefs,
|
|
1000
|
+
argNode: argAst
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
327
1004
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
328
1005
|
if (literalValue !== null) {
|
|
329
1006
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
@@ -351,23 +1028,48 @@ function resolveDynamicCall(abbr, entry, node, mapping, mediaQuery, pseudoClass,
|
|
|
351
1028
|
defs: {},
|
|
352
1029
|
mediaQuery,
|
|
353
1030
|
pseudoClass,
|
|
354
|
-
|
|
1031
|
+
variableProps: entry.props,
|
|
355
1032
|
incremented: entry.incremented,
|
|
356
|
-
|
|
1033
|
+
variableExtraDefs: entry.extraDefs,
|
|
357
1034
|
argNode: argAst
|
|
358
1035
|
};
|
|
359
1036
|
}
|
|
360
1037
|
}
|
|
361
|
-
function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
1038
|
+
function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
362
1039
|
const targetEntry = mapping.abbreviations[entry.target];
|
|
363
|
-
if (!targetEntry || targetEntry.kind !== "
|
|
364
|
-
throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a
|
|
1040
|
+
if (!targetEntry || targetEntry.kind !== "variable") {
|
|
1041
|
+
throw new UnsupportedPatternError(`Delegate "${abbr}" targets "${entry.target}" which is not a variable entry`);
|
|
365
1042
|
}
|
|
366
1043
|
if (node.args.length !== 1) {
|
|
367
1044
|
throw new UnsupportedPatternError(`${abbr}() expects exactly 1 argument, got ${node.args.length}`);
|
|
368
1045
|
}
|
|
369
1046
|
const argAst = node.args[0];
|
|
370
1047
|
const literalValue = tryEvaluatePxLiteral(argAst);
|
|
1048
|
+
if (whenPseudo) {
|
|
1049
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
1050
|
+
if (literalValue !== null) {
|
|
1051
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1052
|
+
const key = `${entry.target}__${keySuffix}__${wpSuffix}`;
|
|
1053
|
+
const defs = {};
|
|
1054
|
+
for (const prop of targetEntry.props) {
|
|
1055
|
+
defs[prop] = literalValue;
|
|
1056
|
+
}
|
|
1057
|
+
if (targetEntry.extraDefs) Object.assign(defs, targetEntry.extraDefs);
|
|
1058
|
+
return { key, defs, whenPseudo, argResolved: literalValue };
|
|
1059
|
+
} else {
|
|
1060
|
+
const key = `${entry.target}__${wpSuffix}`;
|
|
1061
|
+
return {
|
|
1062
|
+
key,
|
|
1063
|
+
defs: {},
|
|
1064
|
+
whenPseudo,
|
|
1065
|
+
variableProps: targetEntry.props,
|
|
1066
|
+
incremented: false,
|
|
1067
|
+
appendPx: true,
|
|
1068
|
+
variableExtraDefs: targetEntry.extraDefs,
|
|
1069
|
+
argNode: argAst
|
|
1070
|
+
};
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
371
1073
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
372
1074
|
if (literalValue !== null) {
|
|
373
1075
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_");
|
|
@@ -396,15 +1098,15 @@ function resolveDelegateCall(abbr, entry, node, mapping, mediaQuery, pseudoClass
|
|
|
396
1098
|
mediaQuery,
|
|
397
1099
|
pseudoClass,
|
|
398
1100
|
pseudoElement,
|
|
399
|
-
|
|
1101
|
+
variableProps: targetEntry.props,
|
|
400
1102
|
incremented: false,
|
|
401
1103
|
appendPx: true,
|
|
402
|
-
|
|
1104
|
+
variableExtraDefs: targetEntry.extraDefs,
|
|
403
1105
|
argNode: argAst
|
|
404
1106
|
};
|
|
405
1107
|
}
|
|
406
1108
|
}
|
|
407
|
-
function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
1109
|
+
function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement, whenPseudo) {
|
|
408
1110
|
if (node.args.length === 1) {
|
|
409
1111
|
const styleArg = node.args[0];
|
|
410
1112
|
if (styleArg.type === "SpreadElement") {
|
|
@@ -433,6 +1135,17 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
|
433
1135
|
const propName = propArg.value;
|
|
434
1136
|
const valueArg = node.args[1];
|
|
435
1137
|
const literalValue = tryEvaluateAddLiteral(valueArg);
|
|
1138
|
+
if (whenPseudo) {
|
|
1139
|
+
const wpSuffix = whenPseudoKeyName(whenPseudo);
|
|
1140
|
+
if (literalValue !== null) {
|
|
1141
|
+
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
1142
|
+
const key = `add_${propName}__${keySuffix}__${wpSuffix}`;
|
|
1143
|
+
return { key, defs: { [propName]: literalValue }, whenPseudo, argResolved: literalValue };
|
|
1144
|
+
} else {
|
|
1145
|
+
const key = `add_${propName}__${wpSuffix}`;
|
|
1146
|
+
return { key, defs: {}, whenPseudo, variableProps: [propName], incremented: false, argNode: valueArg };
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
436
1149
|
const suffix = conditionKeySuffix(mediaQuery, pseudoClass, pseudoElement, mapping.breakpoints);
|
|
437
1150
|
if (literalValue !== null) {
|
|
438
1151
|
const keySuffix = literalValue.replace(/[^a-zA-Z0-9]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
|
|
@@ -455,7 +1168,7 @@ function resolveAddCall(node, mapping, mediaQuery, pseudoClass, pseudoElement) {
|
|
|
455
1168
|
mediaQuery,
|
|
456
1169
|
pseudoClass,
|
|
457
1170
|
pseudoElement,
|
|
458
|
-
|
|
1171
|
+
variableProps: [propName],
|
|
459
1172
|
incremented: false,
|
|
460
1173
|
argNode: valueArg
|
|
461
1174
|
};
|
|
@@ -530,7 +1243,7 @@ function mergeOverlappingConditions(segments) {
|
|
|
530
1243
|
const propToIndices = /* @__PURE__ */ new Map();
|
|
531
1244
|
for (let i = 0; i < segments.length; i++) {
|
|
532
1245
|
const seg = segments[i];
|
|
533
|
-
if (seg.
|
|
1246
|
+
if (seg.variableProps || seg.styleArrayArg || seg.whenPseudo || seg.error) continue;
|
|
534
1247
|
for (const prop of Object.keys(seg.defs)) {
|
|
535
1248
|
if (!propToIndices.has(prop)) propToIndices.set(prop, []);
|
|
536
1249
|
propToIndices.get(prop).push(i);
|
|
@@ -746,44 +1459,44 @@ var UnsupportedPatternError = class extends Error {
|
|
|
746
1459
|
};
|
|
747
1460
|
|
|
748
1461
|
// src/plugin/ast-utils.ts
|
|
749
|
-
import * as
|
|
1462
|
+
import * as t2 from "@babel/types";
|
|
750
1463
|
function collectTopLevelBindings(ast) {
|
|
751
1464
|
const used = /* @__PURE__ */ new Set();
|
|
752
1465
|
for (const node of ast.program.body) {
|
|
753
|
-
if (
|
|
1466
|
+
if (t2.isImportDeclaration(node)) {
|
|
754
1467
|
for (const spec of node.specifiers) {
|
|
755
1468
|
used.add(spec.local.name);
|
|
756
1469
|
}
|
|
757
1470
|
continue;
|
|
758
1471
|
}
|
|
759
|
-
if (
|
|
1472
|
+
if (t2.isVariableDeclaration(node)) {
|
|
760
1473
|
for (const decl of node.declarations) {
|
|
761
1474
|
collectPatternBindings(decl.id, used);
|
|
762
1475
|
}
|
|
763
1476
|
continue;
|
|
764
1477
|
}
|
|
765
|
-
if (
|
|
1478
|
+
if (t2.isFunctionDeclaration(node) && node.id) {
|
|
766
1479
|
used.add(node.id.name);
|
|
767
1480
|
continue;
|
|
768
1481
|
}
|
|
769
|
-
if (
|
|
1482
|
+
if (t2.isClassDeclaration(node) && node.id) {
|
|
770
1483
|
used.add(node.id.name);
|
|
771
1484
|
continue;
|
|
772
1485
|
}
|
|
773
|
-
if (
|
|
1486
|
+
if (t2.isExportNamedDeclaration(node) && node.declaration) {
|
|
774
1487
|
const decl = node.declaration;
|
|
775
|
-
if (
|
|
1488
|
+
if (t2.isVariableDeclaration(decl)) {
|
|
776
1489
|
for (const varDecl of decl.declarations) {
|
|
777
1490
|
collectPatternBindings(varDecl.id, used);
|
|
778
1491
|
}
|
|
779
|
-
} else if ((
|
|
1492
|
+
} else if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
|
|
780
1493
|
used.add(decl.id.name);
|
|
781
1494
|
}
|
|
782
1495
|
continue;
|
|
783
1496
|
}
|
|
784
|
-
if (
|
|
1497
|
+
if (t2.isExportDefaultDeclaration(node)) {
|
|
785
1498
|
const decl = node.declaration;
|
|
786
|
-
if ((
|
|
1499
|
+
if ((t2.isFunctionDeclaration(decl) || t2.isClassDeclaration(decl)) && decl.id) {
|
|
787
1500
|
used.add(decl.id.name);
|
|
788
1501
|
}
|
|
789
1502
|
}
|
|
@@ -791,37 +1504,37 @@ function collectTopLevelBindings(ast) {
|
|
|
791
1504
|
return used;
|
|
792
1505
|
}
|
|
793
1506
|
function collectPatternBindings(pattern, used) {
|
|
794
|
-
if (
|
|
1507
|
+
if (t2.isVoidPattern(pattern)) {
|
|
795
1508
|
return;
|
|
796
1509
|
}
|
|
797
|
-
if (
|
|
1510
|
+
if (t2.isIdentifier(pattern)) {
|
|
798
1511
|
used.add(pattern.name);
|
|
799
1512
|
return;
|
|
800
1513
|
}
|
|
801
|
-
if (
|
|
1514
|
+
if (t2.isAssignmentPattern(pattern)) {
|
|
802
1515
|
collectPatternBindings(pattern.left, used);
|
|
803
1516
|
return;
|
|
804
1517
|
}
|
|
805
|
-
if (
|
|
1518
|
+
if (t2.isRestElement(pattern)) {
|
|
806
1519
|
collectPatternBindings(pattern.argument, used);
|
|
807
1520
|
return;
|
|
808
1521
|
}
|
|
809
|
-
if (
|
|
1522
|
+
if (t2.isObjectPattern(pattern)) {
|
|
810
1523
|
for (const prop of pattern.properties) {
|
|
811
|
-
if (
|
|
1524
|
+
if (t2.isObjectProperty(prop)) {
|
|
812
1525
|
collectPatternBindings(prop.value, used);
|
|
813
|
-
} else if (
|
|
1526
|
+
} else if (t2.isRestElement(prop)) {
|
|
814
1527
|
collectPatternBindings(prop.argument, used);
|
|
815
1528
|
}
|
|
816
1529
|
}
|
|
817
1530
|
return;
|
|
818
1531
|
}
|
|
819
|
-
if (
|
|
1532
|
+
if (t2.isArrayPattern(pattern)) {
|
|
820
1533
|
for (const el of pattern.elements) {
|
|
821
1534
|
if (!el) continue;
|
|
822
|
-
if (
|
|
1535
|
+
if (t2.isIdentifier(el) || t2.isAssignmentPattern(el) || t2.isObjectPattern(el) || t2.isArrayPattern(el)) {
|
|
823
1536
|
collectPatternBindings(el, used);
|
|
824
|
-
} else if (
|
|
1537
|
+
} else if (t2.isRestElement(el)) {
|
|
825
1538
|
collectPatternBindings(el.argument, used);
|
|
826
1539
|
}
|
|
827
1540
|
}
|
|
@@ -848,9 +1561,9 @@ function reservePreferredName(used, preferred, secondary) {
|
|
|
848
1561
|
}
|
|
849
1562
|
function findCssImportBinding(ast) {
|
|
850
1563
|
for (const node of ast.program.body) {
|
|
851
|
-
if (!
|
|
1564
|
+
if (!t2.isImportDeclaration(node)) continue;
|
|
852
1565
|
for (const spec of node.specifiers) {
|
|
853
|
-
if (
|
|
1566
|
+
if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: "Css" })) {
|
|
854
1567
|
return spec.local.name;
|
|
855
1568
|
}
|
|
856
1569
|
}
|
|
@@ -859,9 +1572,9 @@ function findCssImportBinding(ast) {
|
|
|
859
1572
|
}
|
|
860
1573
|
function hasCssMethodCall(ast, binding, method) {
|
|
861
1574
|
let found = false;
|
|
862
|
-
|
|
1575
|
+
t2.traverseFast(ast, (node) => {
|
|
863
1576
|
if (found) return;
|
|
864
|
-
if (
|
|
1577
|
+
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
1578
|
found = true;
|
|
866
1579
|
}
|
|
867
1580
|
});
|
|
@@ -870,8 +1583,8 @@ function hasCssMethodCall(ast, binding, method) {
|
|
|
870
1583
|
function removeCssImport(ast, cssBinding) {
|
|
871
1584
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
872
1585
|
const node = ast.program.body[i];
|
|
873
|
-
if (!
|
|
874
|
-
const cssSpecIndex = node.specifiers.findIndex((s) =>
|
|
1586
|
+
if (!t2.isImportDeclaration(node)) continue;
|
|
1587
|
+
const cssSpecIndex = node.specifiers.findIndex((s) => t2.isImportSpecifier(s) && s.local.name === cssBinding);
|
|
875
1588
|
if (cssSpecIndex === -1) continue;
|
|
876
1589
|
if (node.specifiers.length === 1) {
|
|
877
1590
|
ast.program.body.splice(i, 1);
|
|
@@ -881,40 +1594,20 @@ function removeCssImport(ast, cssBinding) {
|
|
|
881
1594
|
return;
|
|
882
1595
|
}
|
|
883
1596
|
}
|
|
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
1597
|
function findLastImportIndex(ast) {
|
|
897
1598
|
let lastImportIndex = -1;
|
|
898
1599
|
for (let i = 0; i < ast.program.body.length; i++) {
|
|
899
|
-
if (
|
|
1600
|
+
if (t2.isImportDeclaration(ast.program.body[i])) {
|
|
900
1601
|
lastImportIndex = i;
|
|
901
1602
|
}
|
|
902
1603
|
}
|
|
903
1604
|
return lastImportIndex;
|
|
904
1605
|
}
|
|
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
1606
|
function findNamedImportBinding(ast, source, importedName) {
|
|
914
1607
|
for (const node of ast.program.body) {
|
|
915
|
-
if (!
|
|
1608
|
+
if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
|
|
916
1609
|
for (const spec of node.specifiers) {
|
|
917
|
-
if (
|
|
1610
|
+
if (t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: importedName })) {
|
|
918
1611
|
return spec.local.name;
|
|
919
1612
|
}
|
|
920
1613
|
}
|
|
@@ -924,21 +1617,21 @@ function findNamedImportBinding(ast, source, importedName) {
|
|
|
924
1617
|
function upsertNamedImports(ast, source, imports) {
|
|
925
1618
|
if (imports.length === 0) return;
|
|
926
1619
|
for (const node of ast.program.body) {
|
|
927
|
-
if (!
|
|
1620
|
+
if (!t2.isImportDeclaration(node) || node.source.value !== source) continue;
|
|
928
1621
|
for (const entry of imports) {
|
|
929
1622
|
const exists = node.specifiers.some(function(spec) {
|
|
930
|
-
return
|
|
1623
|
+
return t2.isImportSpecifier(spec) && t2.isIdentifier(spec.imported, { name: entry.importedName });
|
|
931
1624
|
});
|
|
932
1625
|
if (exists) continue;
|
|
933
|
-
node.specifiers.push(
|
|
1626
|
+
node.specifiers.push(t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName)));
|
|
934
1627
|
}
|
|
935
1628
|
return;
|
|
936
1629
|
}
|
|
937
|
-
const importDecl =
|
|
1630
|
+
const importDecl = t2.importDeclaration(
|
|
938
1631
|
imports.map(function(entry) {
|
|
939
|
-
return
|
|
1632
|
+
return t2.importSpecifier(t2.identifier(entry.localName), t2.identifier(entry.importedName));
|
|
940
1633
|
}),
|
|
941
|
-
|
|
1634
|
+
t2.stringLiteral(source)
|
|
942
1635
|
);
|
|
943
1636
|
const idx = findLastImportIndex(ast);
|
|
944
1637
|
ast.program.body.splice(idx + 1, 0, importDecl);
|
|
@@ -947,11 +1640,11 @@ function extractChain(node, cssBinding) {
|
|
|
947
1640
|
const chain = [];
|
|
948
1641
|
let current = node;
|
|
949
1642
|
while (true) {
|
|
950
|
-
if (
|
|
1643
|
+
if (t2.isIdentifier(current, { name: cssBinding })) {
|
|
951
1644
|
chain.reverse();
|
|
952
1645
|
return chain;
|
|
953
1646
|
}
|
|
954
|
-
if (
|
|
1647
|
+
if (t2.isMemberExpression(current) && !current.computed && t2.isIdentifier(current.property)) {
|
|
955
1648
|
const name = current.property.name;
|
|
956
1649
|
if (name === "else") {
|
|
957
1650
|
chain.push({ type: "else" });
|
|
@@ -961,7 +1654,7 @@ function extractChain(node, cssBinding) {
|
|
|
961
1654
|
current = current.object;
|
|
962
1655
|
continue;
|
|
963
1656
|
}
|
|
964
|
-
if (
|
|
1657
|
+
if (t2.isCallExpression(current) && t2.isMemberExpression(current.callee) && !current.callee.computed && t2.isIdentifier(current.callee.property)) {
|
|
965
1658
|
const name = current.callee.property.name;
|
|
966
1659
|
if (name === "if") {
|
|
967
1660
|
chain.push({
|
|
@@ -983,643 +1676,151 @@ function extractChain(node, cssBinding) {
|
|
|
983
1676
|
}
|
|
984
1677
|
}
|
|
985
1678
|
|
|
986
|
-
// src/plugin/
|
|
987
|
-
import
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
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
|
-
}
|
|
1679
|
+
// src/plugin/rewrite-sites.ts
|
|
1680
|
+
import _traverse from "@babel/traverse";
|
|
1681
|
+
import _generate from "@babel/generator";
|
|
1682
|
+
import * as t3 from "@babel/types";
|
|
1683
|
+
var generate = _generate.default ?? _generate;
|
|
1684
|
+
var traverse = _traverse.default ?? _traverse;
|
|
1685
|
+
function rewriteExpressionSites(options) {
|
|
1686
|
+
for (const site of options.sites) {
|
|
1687
|
+
const styleHash = buildStyleHashFromChain(site.resolvedChain, options);
|
|
1688
|
+
const cssAttrPath = getCssAttributePath(site.path);
|
|
1689
|
+
const line = site.path.node.loc?.start.line ?? null;
|
|
1690
|
+
if (cssAttrPath) {
|
|
1691
|
+
cssAttrPath.replaceWith(t3.jsxSpreadAttribute(buildCssSpreadExpression(cssAttrPath, styleHash, line, options)));
|
|
1692
|
+
} else {
|
|
1693
|
+
if (options.debug && line !== null) {
|
|
1694
|
+
injectDebugInfo(styleHash, line, options);
|
|
1029
1695
|
}
|
|
1696
|
+
site.path.replaceWith(styleHash);
|
|
1030
1697
|
}
|
|
1031
1698
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
if (!
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
})
|
|
1049
|
-
)
|
|
1699
|
+
rewriteCssPropsCalls(options);
|
|
1700
|
+
rewriteCssAttributeExpressions(options);
|
|
1701
|
+
}
|
|
1702
|
+
function getCssAttributePath(path) {
|
|
1703
|
+
const parentPath = path.parentPath;
|
|
1704
|
+
if (!parentPath || !parentPath.isJSXExpressionContainer()) return null;
|
|
1705
|
+
const attrPath = parentPath.parentPath;
|
|
1706
|
+
if (!attrPath || !attrPath.isJSXAttribute()) return null;
|
|
1707
|
+
if (!t3.isJSXIdentifier(attrPath.node.name, { name: "css" })) return null;
|
|
1708
|
+
return attrPath;
|
|
1709
|
+
}
|
|
1710
|
+
function buildStyleHashFromChain(chain, options) {
|
|
1711
|
+
const members = [];
|
|
1712
|
+
if (chain.markers.length > 0) {
|
|
1713
|
+
const markerClasses = chain.markers.map(function(marker) {
|
|
1714
|
+
return markerClassName(marker.markerNode);
|
|
1050
1715
|
});
|
|
1716
|
+
members.push(t3.objectProperty(t3.identifier("__marker"), t3.stringLiteral(markerClasses.join(" "))));
|
|
1051
1717
|
}
|
|
1052
|
-
for (const
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1718
|
+
for (const part of chain.parts) {
|
|
1719
|
+
if (part.type === "unconditional") {
|
|
1720
|
+
members.push(...buildStyleHashMembers(part.segments, options));
|
|
1721
|
+
} else {
|
|
1722
|
+
const thenMembers = buildStyleHashMembers(part.thenSegments, options);
|
|
1723
|
+
const elseMembers = buildStyleHashMembers(part.elseSegments, options);
|
|
1724
|
+
members.push(
|
|
1725
|
+
t3.spreadElement(
|
|
1726
|
+
t3.conditionalExpression(part.conditionNode, t3.objectExpression(thenMembers), t3.objectExpression(elseMembers))
|
|
1727
|
+
)
|
|
1728
|
+
);
|
|
1060
1729
|
}
|
|
1061
1730
|
}
|
|
1731
|
+
return t3.objectExpression(members);
|
|
1062
1732
|
}
|
|
1063
|
-
function
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
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));
|
|
1733
|
+
function buildStyleHashMembers(segments, options) {
|
|
1734
|
+
const members = [];
|
|
1735
|
+
const normalSegs = [];
|
|
1736
|
+
function flushNormal() {
|
|
1737
|
+
if (normalSegs.length > 0) {
|
|
1738
|
+
members.push(...buildStyleHashProperties(normalSegs, options.mapping, options.maybeIncHelperName));
|
|
1739
|
+
normalSegs.length = 0;
|
|
1740
|
+
}
|
|
1741
|
+
}
|
|
1742
|
+
for (const seg of segments) {
|
|
1743
|
+
if (seg.error) continue;
|
|
1744
|
+
if (seg.styleArrayArg) {
|
|
1745
|
+
flushNormal();
|
|
1746
|
+
members.push(t3.spreadElement(seg.styleArrayArg));
|
|
1142
1747
|
continue;
|
|
1143
1748
|
}
|
|
1144
|
-
if (
|
|
1145
|
-
|
|
1146
|
-
const
|
|
1147
|
-
|
|
1148
|
-
const
|
|
1149
|
-
|
|
1150
|
-
|
|
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
|
-
)
|
|
1749
|
+
if (seg.typographyLookup) {
|
|
1750
|
+
flushNormal();
|
|
1751
|
+
const lookupName = options.runtimeLookupNames.get(seg.typographyLookup.lookupKey);
|
|
1752
|
+
if (lookupName) {
|
|
1753
|
+
const lookupAccess = t3.memberExpression(
|
|
1754
|
+
t3.identifier(lookupName),
|
|
1755
|
+
seg.typographyLookup.argNode,
|
|
1756
|
+
true
|
|
1168
1757
|
);
|
|
1758
|
+
members.push(t3.spreadElement(t3.logicalExpression("??", lookupAccess, t3.objectExpression([]))));
|
|
1169
1759
|
}
|
|
1170
|
-
createProperties.push(t2.objectProperty(toPropertyKey(entry.key), t2.objectExpression(props)));
|
|
1171
1760
|
continue;
|
|
1172
1761
|
}
|
|
1173
|
-
|
|
1174
|
-
createProperties.push(t2.objectProperty(toPropertyKey(entry.key), defsToAst(entry.defs)));
|
|
1175
|
-
}
|
|
1762
|
+
normalSegs.push(seg);
|
|
1176
1763
|
}
|
|
1177
|
-
|
|
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
|
-
]);
|
|
1764
|
+
flushNormal();
|
|
1765
|
+
return members;
|
|
1196
1766
|
}
|
|
1197
|
-
function
|
|
1198
|
-
|
|
1199
|
-
|
|
1767
|
+
function injectDebugInfo(expr, line, options) {
|
|
1768
|
+
if (!options.debug) return;
|
|
1769
|
+
const firstProp = expr.properties.find(function(p) {
|
|
1770
|
+
return t3.isObjectProperty(p) && !(t3.isIdentifier(p.key) && p.key.name === "__marker" || t3.isStringLiteral(p.key) && p.key.value === "__marker");
|
|
1771
|
+
});
|
|
1772
|
+
if (!firstProp) return;
|
|
1773
|
+
options.needsTrussDebugInfo.current = true;
|
|
1774
|
+
const debugExpr = t3.newExpression(t3.identifier(options.trussDebugInfoName), [
|
|
1775
|
+
t3.stringLiteral(`${options.filename}:${line}`)
|
|
1200
1776
|
]);
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
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)));
|
|
1777
|
+
if (t3.isStringLiteral(firstProp.value)) {
|
|
1778
|
+
firstProp.value = t3.arrayExpression([firstProp.value, debugExpr]);
|
|
1779
|
+
} else if (t3.isArrayExpression(firstProp.value)) {
|
|
1780
|
+
firstProp.value.elements.push(debugExpr);
|
|
1210
1781
|
}
|
|
1211
|
-
return t2.variableDeclaration("const", [
|
|
1212
|
-
t2.variableDeclarator(t2.identifier(lookupName), t2.objectExpression(properties))
|
|
1213
|
-
]);
|
|
1214
1782
|
}
|
|
1215
|
-
function
|
|
1216
|
-
const
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
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
|
-
// src/plugin/rewrite-sites.ts
|
|
1246
|
-
import _traverse from "@babel/traverse";
|
|
1247
|
-
import _generate from "@babel/generator";
|
|
1248
|
-
import * as t3 from "@babel/types";
|
|
1249
|
-
var generate = _generate.default ?? _generate;
|
|
1250
|
-
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
|
-
function rewriteExpressionSites(options) {
|
|
1259
|
-
for (const site of options.sites) {
|
|
1260
|
-
const propsArgs = buildPropsArgsFromChain(site.resolvedChain, options);
|
|
1261
|
-
const cssAttrPath = getCssAttributePath(site.path);
|
|
1262
|
-
if (cssAttrPath) {
|
|
1263
|
-
cssAttrPath.replaceWith(
|
|
1264
|
-
t3.jsxSpreadAttribute(
|
|
1265
|
-
buildCssSpreadExpression(
|
|
1266
|
-
cssAttrPath,
|
|
1267
|
-
propsArgs,
|
|
1268
|
-
site.path.node.loc?.start.line ?? null,
|
|
1269
|
-
options.mergePropsHelperName,
|
|
1270
|
-
options.needsMergePropsHelper,
|
|
1271
|
-
options
|
|
1272
|
-
)
|
|
1273
|
-
)
|
|
1274
|
-
);
|
|
1275
|
-
continue;
|
|
1276
|
-
}
|
|
1277
|
-
site.path.replaceWith(buildStyleArrayExpression(propsArgs, site.path.node.loc?.start.line ?? null, options));
|
|
1278
|
-
}
|
|
1279
|
-
rewriteCssPropsCalls(options);
|
|
1280
|
-
rewriteCssSpreadCalls(
|
|
1281
|
-
options.ast,
|
|
1282
|
-
options.cssBindingName,
|
|
1283
|
-
options.asStyleArrayHelperName,
|
|
1284
|
-
options.needsAsStyleArrayHelper
|
|
1285
|
-
);
|
|
1286
|
-
rewriteStyleObjectExpressions(
|
|
1287
|
-
options.ast,
|
|
1288
|
-
options.skippedCssPropMessages,
|
|
1289
|
-
options.asStyleArrayHelperName,
|
|
1290
|
-
options.needsAsStyleArrayHelper
|
|
1291
|
-
);
|
|
1292
|
-
normalizeMixedStyleTernaries(options.ast);
|
|
1293
|
-
rewriteCssAttributeExpressions(
|
|
1294
|
-
options.ast,
|
|
1295
|
-
options.filename,
|
|
1296
|
-
options.debug,
|
|
1297
|
-
options.stylexNamespaceName,
|
|
1298
|
-
options.mergePropsHelperName,
|
|
1299
|
-
options.needsMergePropsHelper,
|
|
1300
|
-
options.trussPropsHelperName,
|
|
1301
|
-
options.needsTrussPropsHelper,
|
|
1302
|
-
options.trussDebugInfoName,
|
|
1303
|
-
options.needsTrussDebugInfo,
|
|
1304
|
-
options.asStyleArrayHelperName,
|
|
1305
|
-
options.needsAsStyleArrayHelper,
|
|
1306
|
-
options.skippedCssPropMessages
|
|
1307
|
-
);
|
|
1308
|
-
}
|
|
1309
|
-
function getCssAttributePath(path) {
|
|
1310
|
-
const parentPath = path.parentPath;
|
|
1311
|
-
if (!parentPath || !parentPath.isJSXExpressionContainer()) return null;
|
|
1312
|
-
const attrPath = parentPath.parentPath;
|
|
1313
|
-
if (!attrPath || !attrPath.isJSXAttribute()) return null;
|
|
1314
|
-
if (!t3.isJSXIdentifier(attrPath.node.name, { name: "css" })) return null;
|
|
1315
|
-
return attrPath;
|
|
1316
|
-
}
|
|
1317
|
-
function buildPropsArgsFromChain(chain, options) {
|
|
1318
|
-
const args = [];
|
|
1319
|
-
for (const marker of chain.markers) {
|
|
1320
|
-
if (marker.markerNode) {
|
|
1321
|
-
args.push(marker.markerNode);
|
|
1322
|
-
} else {
|
|
1323
|
-
args.push(
|
|
1324
|
-
t3.callExpression(
|
|
1325
|
-
t3.memberExpression(t3.identifier(options.stylexNamespaceName), t3.identifier("defaultMarker")),
|
|
1326
|
-
[]
|
|
1327
|
-
)
|
|
1328
|
-
);
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
for (const part of chain.parts) {
|
|
1332
|
-
if (part.type === "unconditional") {
|
|
1333
|
-
args.push(...buildPropsArgs(part.segments, options));
|
|
1334
|
-
continue;
|
|
1335
|
-
}
|
|
1336
|
-
const thenArgs = buildPropsArgs(part.thenSegments, options);
|
|
1337
|
-
const elseArgs = buildPropsArgs(part.elseSegments, options);
|
|
1338
|
-
if (thenArgs.length === 1 && elseArgs.length === 1 && !t3.isSpreadElement(thenArgs[0]) && !t3.isSpreadElement(elseArgs[0])) {
|
|
1339
|
-
args.push(t3.conditionalExpression(part.conditionNode, thenArgs[0], elseArgs[0]));
|
|
1340
|
-
} else if (thenArgs.length > 0 || elseArgs.length > 0) {
|
|
1341
|
-
args.push(
|
|
1342
|
-
t3.spreadElement(
|
|
1343
|
-
t3.conditionalExpression(part.conditionNode, t3.arrayExpression(thenArgs), t3.arrayExpression(elseArgs))
|
|
1344
|
-
)
|
|
1345
|
-
);
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
return args;
|
|
1349
|
-
}
|
|
1350
|
-
function buildPropsArgs(segments, options) {
|
|
1351
|
-
const args = [];
|
|
1352
|
-
for (const seg of segments) {
|
|
1353
|
-
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
|
-
if (seg.styleArrayArg) {
|
|
1368
|
-
args.push(
|
|
1369
|
-
t3.spreadElement(
|
|
1370
|
-
buildUnknownSpreadFallback(
|
|
1371
|
-
seg.styleArrayArg,
|
|
1372
|
-
options.asStyleArrayHelperName,
|
|
1373
|
-
options.needsAsStyleArrayHelper
|
|
1374
|
-
)
|
|
1375
|
-
)
|
|
1376
|
-
);
|
|
1377
|
-
continue;
|
|
1378
|
-
}
|
|
1379
|
-
const ref = t3.memberExpression(t3.identifier(options.createVarName), t3.identifier(seg.key));
|
|
1380
|
-
if (seg.dynamicProps && seg.argNode) {
|
|
1381
|
-
let argExpr;
|
|
1382
|
-
if (seg.incremented && options.maybeIncHelperName) {
|
|
1383
|
-
argExpr = t3.callExpression(t3.identifier(options.maybeIncHelperName), [seg.argNode]);
|
|
1384
|
-
} else if (seg.incremented) {
|
|
1385
|
-
argExpr = seg.argNode;
|
|
1386
|
-
} else if (seg.appendPx) {
|
|
1387
|
-
argExpr = t3.binaryExpression(
|
|
1388
|
-
"+",
|
|
1389
|
-
t3.callExpression(t3.identifier("String"), [seg.argNode]),
|
|
1390
|
-
t3.stringLiteral("px")
|
|
1391
|
-
);
|
|
1392
|
-
} else {
|
|
1393
|
-
argExpr = t3.callExpression(t3.identifier("String"), [seg.argNode]);
|
|
1394
|
-
}
|
|
1395
|
-
args.push(t3.callExpression(ref, [argExpr]));
|
|
1396
|
-
} else {
|
|
1397
|
-
args.push(ref);
|
|
1398
|
-
}
|
|
1783
|
+
function buildCssSpreadExpression(path, styleHash, line, options) {
|
|
1784
|
+
const existingClassNameExpr = removeExistingAttribute(path, "className");
|
|
1785
|
+
const existingStyleExpr = removeExistingAttribute(path, "style");
|
|
1786
|
+
if (!existingClassNameExpr && !existingStyleExpr) {
|
|
1787
|
+
return buildPropsCall(styleHash, line, options);
|
|
1399
1788
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
traverse(ast, {
|
|
1404
|
-
JSXAttribute(path) {
|
|
1405
|
-
if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
1406
|
-
const value = path.node.value;
|
|
1407
|
-
if (!t3.isJSXExpressionContainer(value)) return;
|
|
1408
|
-
if (!t3.isExpression(value.expression)) return;
|
|
1409
|
-
const propsArgs = lowerCssExpressionToPropsArgs(
|
|
1410
|
-
value.expression,
|
|
1411
|
-
path,
|
|
1412
|
-
asStyleArrayHelperName,
|
|
1413
|
-
needsAsStyleArrayHelper
|
|
1414
|
-
);
|
|
1415
|
-
if (!propsArgs) {
|
|
1416
|
-
skippedCssPropMessages.push({
|
|
1417
|
-
message: explainSkippedCssRewrite(value.expression, path),
|
|
1418
|
-
line: path.node.loc?.start.line ?? null
|
|
1419
|
-
});
|
|
1420
|
-
return;
|
|
1421
|
-
}
|
|
1422
|
-
path.replaceWith(
|
|
1423
|
-
t3.jsxSpreadAttribute(
|
|
1424
|
-
buildCssSpreadExpression(
|
|
1425
|
-
path,
|
|
1426
|
-
propsArgs,
|
|
1427
|
-
path.node.loc?.start.line ?? null,
|
|
1428
|
-
mergePropsHelperName,
|
|
1429
|
-
needsMergePropsHelper,
|
|
1430
|
-
{
|
|
1431
|
-
filename,
|
|
1432
|
-
debug,
|
|
1433
|
-
stylexNamespaceName,
|
|
1434
|
-
trussPropsHelperName,
|
|
1435
|
-
needsTrussPropsHelper,
|
|
1436
|
-
trussDebugInfoName,
|
|
1437
|
-
needsTrussDebugInfo
|
|
1438
|
-
}
|
|
1439
|
-
)
|
|
1440
|
-
)
|
|
1441
|
-
);
|
|
1442
|
-
}
|
|
1443
|
-
});
|
|
1444
|
-
}
|
|
1445
|
-
function buildStyleArrayExpression(propsArgs, line, options) {
|
|
1446
|
-
const elements = buildDebugElements(line, options);
|
|
1447
|
-
elements.push(...propsArgs);
|
|
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
|
-
);
|
|
1789
|
+
options.needsMergePropsHelper.current = true;
|
|
1790
|
+
if (options.debug && line !== null) {
|
|
1791
|
+
injectDebugInfo(styleHash, line, options);
|
|
1456
1792
|
}
|
|
1457
|
-
options.
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
t3.identifier(options.stylexNamespaceName),
|
|
1462
|
-
...args
|
|
1793
|
+
return t3.callExpression(t3.identifier(options.mergePropsHelperName), [
|
|
1794
|
+
existingClassNameExpr ?? t3.identifier("undefined"),
|
|
1795
|
+
existingStyleExpr ?? t3.identifier("undefined"),
|
|
1796
|
+
styleHash
|
|
1463
1797
|
]);
|
|
1464
1798
|
}
|
|
1465
|
-
function
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
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
|
-
}
|
|
1475
|
-
function explainSkippedCssRewrite(expr, path) {
|
|
1476
|
-
if (t3.isObjectExpression(expr)) {
|
|
1477
|
-
for (const prop of expr.properties) {
|
|
1478
|
-
if (!t3.isSpreadElement(prop)) {
|
|
1479
|
-
return `[truss] Unsupported pattern: Could not rewrite css prop: object contains a non-spread property (${formatNodeSnippet(expr)})`;
|
|
1480
|
-
}
|
|
1481
|
-
const normalizedArg = normalizeStyleExpression(prop.argument);
|
|
1482
|
-
if (!normalizedArg) {
|
|
1483
|
-
return `[truss] Unsupported pattern: Could not rewrite css prop: spread argument is not style-array-like (${formatNodeSnippet(prop.argument)})`;
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
return `[truss] Unsupported pattern: Could not rewrite css prop: object spread composition was not recognized (${formatNodeSnippet(expr)})`;
|
|
1799
|
+
function buildPropsCall(styleHash, line, options) {
|
|
1800
|
+
options.needsTrussPropsHelper.current = true;
|
|
1801
|
+
if (options.debug && line !== null && t3.isObjectExpression(styleHash)) {
|
|
1802
|
+
injectDebugInfo(styleHash, line, options);
|
|
1487
1803
|
}
|
|
1488
|
-
return
|
|
1489
|
-
}
|
|
1490
|
-
function formatNodeSnippet(node) {
|
|
1491
|
-
return generate(node, { compact: true, comments: true }).code;
|
|
1492
|
-
}
|
|
1493
|
-
function buildCssSpreadExpression(path, propsArgs, line, mergePropsHelperName, needsMergePropsHelper, options) {
|
|
1494
|
-
const existingClassNameExpr = removeExistingClassNameAttribute(path);
|
|
1495
|
-
if (!existingClassNameExpr) return buildPropsCall(propsArgs, line, options);
|
|
1496
|
-
needsMergePropsHelper.current = true;
|
|
1497
|
-
const args = buildDebugElements(line, options);
|
|
1498
|
-
args.push(...propsArgs);
|
|
1499
|
-
return t3.callExpression(t3.identifier(mergePropsHelperName), [
|
|
1500
|
-
t3.identifier(options.stylexNamespaceName),
|
|
1501
|
-
existingClassNameExpr,
|
|
1502
|
-
...args
|
|
1503
|
-
]);
|
|
1804
|
+
return t3.callExpression(t3.identifier(options.trussPropsHelperName), [styleHash]);
|
|
1504
1805
|
}
|
|
1505
|
-
function
|
|
1806
|
+
function removeExistingAttribute(path, attrName) {
|
|
1506
1807
|
const openingElement = path.parentPath;
|
|
1507
1808
|
if (!openingElement || !openingElement.isJSXOpeningElement()) return null;
|
|
1508
1809
|
const attrs = openingElement.node.attributes;
|
|
1509
1810
|
for (let i = 0; i < attrs.length; i++) {
|
|
1510
1811
|
const attr = attrs[i];
|
|
1511
|
-
if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name:
|
|
1512
|
-
let
|
|
1812
|
+
if (!t3.isJSXAttribute(attr) || !t3.isJSXIdentifier(attr.name, { name: attrName })) continue;
|
|
1813
|
+
let expr = null;
|
|
1513
1814
|
if (t3.isStringLiteral(attr.value)) {
|
|
1514
|
-
|
|
1815
|
+
expr = attr.value;
|
|
1515
1816
|
} else if (t3.isJSXExpressionContainer(attr.value) && t3.isExpression(attr.value.expression)) {
|
|
1516
|
-
|
|
1817
|
+
expr = attr.value.expression;
|
|
1517
1818
|
}
|
|
1518
1819
|
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))];
|
|
1820
|
+
return expr;
|
|
1573
1821
|
}
|
|
1574
1822
|
return null;
|
|
1575
1823
|
}
|
|
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
1824
|
function rewriteCssPropsCalls(options) {
|
|
1624
1825
|
traverse(options.ast, {
|
|
1625
1826
|
CallExpression(path) {
|
|
@@ -1627,28 +1828,51 @@ function rewriteCssPropsCalls(options) {
|
|
|
1627
1828
|
const arg = path.node.arguments[0];
|
|
1628
1829
|
if (!arg || t3.isSpreadElement(arg) || !t3.isExpression(arg) || path.node.arguments.length !== 1) return;
|
|
1629
1830
|
const line = path.node.loc?.start.line ?? null;
|
|
1630
|
-
|
|
1631
|
-
const
|
|
1632
|
-
if (
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
options.asStyleArrayHelperName,
|
|
1637
|
-
options.needsAsStyleArrayHelper
|
|
1831
|
+
options.needsTrussPropsHelper.current = true;
|
|
1832
|
+
const classNameExpr = extractSiblingClassName(path);
|
|
1833
|
+
if (classNameExpr) {
|
|
1834
|
+
options.needsMergePropsHelper.current = true;
|
|
1835
|
+
path.replaceWith(
|
|
1836
|
+
t3.callExpression(t3.identifier(options.mergePropsHelperName), [classNameExpr, t3.identifier("undefined"), arg])
|
|
1638
1837
|
);
|
|
1639
|
-
propsArgs = result.elements.filter((e) => e !== null);
|
|
1640
1838
|
} else {
|
|
1641
|
-
|
|
1839
|
+
path.replaceWith(t3.callExpression(t3.identifier(options.trussPropsHelperName), [arg]));
|
|
1642
1840
|
}
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1841
|
+
}
|
|
1842
|
+
});
|
|
1843
|
+
}
|
|
1844
|
+
function rewriteCssAttributeExpressions(options) {
|
|
1845
|
+
traverse(options.ast, {
|
|
1846
|
+
JSXAttribute(path) {
|
|
1847
|
+
if (!t3.isJSXIdentifier(path.node.name, { name: "css" })) return;
|
|
1848
|
+
const value = path.node.value;
|
|
1849
|
+
if (!t3.isJSXExpressionContainer(value)) return;
|
|
1850
|
+
if (!t3.isExpression(value.expression)) return;
|
|
1851
|
+
const expr = value.expression;
|
|
1852
|
+
const line = path.node.loc?.start.line ?? null;
|
|
1853
|
+
const existingClassNameExpr = removeExistingAttribute(path, "className");
|
|
1854
|
+
const existingStyleExpr = removeExistingAttribute(path, "style");
|
|
1855
|
+
if (existingClassNameExpr || existingStyleExpr) {
|
|
1856
|
+
options.needsMergePropsHelper.current = true;
|
|
1857
|
+
path.replaceWith(
|
|
1858
|
+
t3.jsxSpreadAttribute(
|
|
1859
|
+
t3.callExpression(t3.identifier(options.mergePropsHelperName), [
|
|
1860
|
+
existingClassNameExpr ?? t3.identifier("undefined"),
|
|
1861
|
+
existingStyleExpr ?? t3.identifier("undefined"),
|
|
1862
|
+
expr
|
|
1863
|
+
])
|
|
1864
|
+
)
|
|
1865
|
+
);
|
|
1646
1866
|
} else {
|
|
1647
|
-
|
|
1867
|
+
options.needsTrussPropsHelper.current = true;
|
|
1868
|
+
path.replaceWith(t3.jsxSpreadAttribute(t3.callExpression(t3.identifier(options.trussPropsHelperName), [expr])));
|
|
1648
1869
|
}
|
|
1649
1870
|
}
|
|
1650
1871
|
});
|
|
1651
1872
|
}
|
|
1873
|
+
function isCssPropsCall(expr, cssBindingName) {
|
|
1874
|
+
return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "props" });
|
|
1875
|
+
}
|
|
1652
1876
|
function extractSiblingClassName(callPath) {
|
|
1653
1877
|
const spreadPath = callPath.parentPath;
|
|
1654
1878
|
if (!spreadPath || !spreadPath.isSpreadElement()) return null;
|
|
@@ -1666,230 +1890,9 @@ function extractSiblingClassName(callPath) {
|
|
|
1666
1890
|
}
|
|
1667
1891
|
return null;
|
|
1668
1892
|
}
|
|
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
1893
|
function isMatchingPropertyName(key, name) {
|
|
1820
1894
|
return t3.isIdentifier(key) && key.name === name || t3.isStringLiteral(key) && key.value === name;
|
|
1821
1895
|
}
|
|
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
1896
|
|
|
1894
1897
|
// src/plugin/transform.ts
|
|
1895
1898
|
var traverse2 = _traverse2.default ?? _traverse2;
|
|
@@ -1915,7 +1918,7 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1915
1918
|
if (parentPath && parentPath.isMemberExpression() && t4.isIdentifier(parentPath.node.property, { name: "$" })) {
|
|
1916
1919
|
return;
|
|
1917
1920
|
}
|
|
1918
|
-
const resolvedChain = resolveFullChain(chain, mapping);
|
|
1921
|
+
const resolvedChain = resolveFullChain(chain, mapping, { skipMerge: true });
|
|
1919
1922
|
sites.push({ path, resolvedChain });
|
|
1920
1923
|
const line = path.node.loc?.start.line ?? null;
|
|
1921
1924
|
for (const err of resolvedChain.errors) {
|
|
@@ -1925,18 +1928,14 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1925
1928
|
});
|
|
1926
1929
|
const hasCssPropsCall = hasCssMethodCall(ast, cssBindingName, "props");
|
|
1927
1930
|
if (sites.length === 0 && !hasCssPropsCall) return null;
|
|
1928
|
-
const
|
|
1931
|
+
const chains = sites.map((s) => s.resolvedChain);
|
|
1932
|
+
const { rules, needsMaybeInc } = collectAtomicRules(chains, mapping);
|
|
1933
|
+
const cssText = generateCssText(rules);
|
|
1929
1934
|
const usedTopLevelNames = collectTopLevelBindings(ast);
|
|
1930
|
-
const existingStylexNamespace = findStylexNamespaceImport(ast);
|
|
1931
|
-
const stylexNamespaceName = existingStylexNamespace ?? reservePreferredName(usedTopLevelNames, "stylex");
|
|
1932
|
-
const createVarName = reservePreferredName(usedTopLevelNames, "css", "css_");
|
|
1933
1935
|
const maybeIncHelperName = needsMaybeInc ? reservePreferredName(usedTopLevelNames, "__maybeInc") : null;
|
|
1934
1936
|
const existingMergePropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "mergeProps");
|
|
1935
1937
|
const mergePropsHelperName = existingMergePropsHelperName ?? reservePreferredName(usedTopLevelNames, "mergeProps");
|
|
1936
1938
|
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
1939
|
const existingTrussPropsHelperName = findNamedImportBinding(ast, "@homebound/truss/runtime", "trussProps");
|
|
1941
1940
|
const trussPropsHelperName = existingTrussPropsHelperName ?? reservePreferredName(usedTopLevelNames, "trussProps");
|
|
1942
1941
|
const needsTrussPropsHelper = { current: false };
|
|
@@ -1944,18 +1943,17 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1944
1943
|
const trussDebugInfoName = existingTrussDebugInfoName ?? reservePreferredName(usedTopLevelNames, "TrussDebugInfo");
|
|
1945
1944
|
const needsTrussDebugInfo = { current: false };
|
|
1946
1945
|
const runtimeLookupNames = /* @__PURE__ */ new Map();
|
|
1946
|
+
const runtimeLookups = collectRuntimeLookups(chains);
|
|
1947
1947
|
for (const [lookupKey] of runtimeLookups) {
|
|
1948
1948
|
runtimeLookupNames.set(lookupKey, reservePreferredName(usedTopLevelNames, `__${lookupKey}`));
|
|
1949
1949
|
}
|
|
1950
|
-
const createProperties = buildCreateProperties(createEntries, stylexNamespaceName);
|
|
1951
1950
|
rewriteExpressionSites({
|
|
1952
1951
|
ast,
|
|
1953
1952
|
sites,
|
|
1954
1953
|
cssBindingName,
|
|
1955
1954
|
filename: basename(filename),
|
|
1956
1955
|
debug: options.debug ?? false,
|
|
1957
|
-
|
|
1958
|
-
stylexNamespaceName,
|
|
1956
|
+
mapping,
|
|
1959
1957
|
maybeIncHelperName,
|
|
1960
1958
|
mergePropsHelperName,
|
|
1961
1959
|
needsMergePropsHelper,
|
|
@@ -1963,55 +1961,50 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
1963
1961
|
needsTrussPropsHelper,
|
|
1964
1962
|
trussDebugInfoName,
|
|
1965
1963
|
needsTrussDebugInfo,
|
|
1966
|
-
asStyleArrayHelperName,
|
|
1967
|
-
needsAsStyleArrayHelper,
|
|
1968
1964
|
skippedCssPropMessages: errorMessages,
|
|
1969
1965
|
runtimeLookupNames
|
|
1970
1966
|
});
|
|
1971
1967
|
removeCssImport(ast, cssBindingName);
|
|
1972
|
-
|
|
1973
|
-
|
|
1968
|
+
const runtimeImports = [];
|
|
1969
|
+
if (needsTrussPropsHelper.current) {
|
|
1970
|
+
runtimeImports.push({ importedName: "trussProps", localName: trussPropsHelperName });
|
|
1974
1971
|
}
|
|
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
|
-
}
|
|
1972
|
+
if (needsMergePropsHelper.current) {
|
|
1973
|
+
runtimeImports.push({ importedName: "mergeProps", localName: mergePropsHelperName });
|
|
1974
|
+
}
|
|
1975
|
+
if (needsTrussDebugInfo.current) {
|
|
1976
|
+
runtimeImports.push({ importedName: "TrussDebugInfo", localName: trussDebugInfoName });
|
|
1977
|
+
}
|
|
1978
|
+
if (options.injectCss) {
|
|
1979
|
+
runtimeImports.push({ importedName: "__injectTrussCSS", localName: "__injectTrussCSS" });
|
|
1980
|
+
}
|
|
1981
|
+
if (runtimeImports.length > 0) {
|
|
1989
1982
|
upsertNamedImports(ast, "@homebound/truss/runtime", runtimeImports);
|
|
1990
1983
|
}
|
|
1991
|
-
const markerVarNames = collectReferencedMarkerNames(createEntries);
|
|
1992
|
-
const hoistedMarkerDecls = hoistMarkerDeclarations(ast, markerVarNames);
|
|
1993
1984
|
const declarationsToInsert = [];
|
|
1994
1985
|
if (maybeIncHelperName) {
|
|
1995
1986
|
declarationsToInsert.push(buildMaybeIncDeclaration(maybeIncHelperName, mapping.increment));
|
|
1996
1987
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
1988
|
+
for (const [lookupKey, lookup] of runtimeLookups) {
|
|
1989
|
+
const lookupName = runtimeLookupNames.get(lookupKey);
|
|
1990
|
+
if (!lookupName) continue;
|
|
1991
|
+
declarationsToInsert.push(buildRuntimeLookupDeclaration(lookupName, lookup.segmentsByName, mapping));
|
|
1992
|
+
}
|
|
1993
|
+
if (options.injectCss && cssText.length > 0) {
|
|
1994
|
+
declarationsToInsert.push(
|
|
1995
|
+
t4.expressionStatement(t4.callExpression(t4.identifier("__injectTrussCSS"), [t4.stringLiteral(cssText)]))
|
|
1996
|
+
);
|
|
2005
1997
|
}
|
|
2006
1998
|
for (const { message, line } of errorMessages) {
|
|
2007
1999
|
const location = line !== null ? `${filename}:${line}` : filename;
|
|
2008
2000
|
const logMessage = `${message} (${location})`;
|
|
2009
|
-
|
|
2010
|
-
t4.
|
|
2011
|
-
t4.
|
|
2012
|
-
|
|
2001
|
+
declarationsToInsert.push(
|
|
2002
|
+
t4.expressionStatement(
|
|
2003
|
+
t4.callExpression(t4.memberExpression(t4.identifier("console"), t4.identifier("error")), [
|
|
2004
|
+
t4.stringLiteral(logMessage)
|
|
2005
|
+
])
|
|
2006
|
+
)
|
|
2013
2007
|
);
|
|
2014
|
-
declarationsToInsert.push(consoleError);
|
|
2015
2008
|
}
|
|
2016
2009
|
if (declarationsToInsert.length > 0) {
|
|
2017
2010
|
const insertIndex = ast.program.body.findIndex(function(node) {
|
|
@@ -2023,46 +2016,23 @@ function transformTruss(code, filename, mapping, options = {}) {
|
|
|
2023
2016
|
sourceFileName: filename,
|
|
2024
2017
|
retainLines: false
|
|
2025
2018
|
});
|
|
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;
|
|
2019
|
+
return { code: output.code, map: output.map, css: cssText, rules };
|
|
2036
2020
|
}
|
|
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);
|
|
2021
|
+
function collectRuntimeLookups(chains) {
|
|
2022
|
+
const lookups = /* @__PURE__ */ new Map();
|
|
2023
|
+
for (const chain of chains) {
|
|
2024
|
+
for (const part of chain.parts) {
|
|
2025
|
+
const segs = part.type === "unconditional" ? part.segments : [...part.thenSegments, ...part.elseSegments];
|
|
2026
|
+
for (const seg of segs) {
|
|
2027
|
+
if (seg.typographyLookup && !lookups.has(seg.typographyLookup.lookupKey)) {
|
|
2028
|
+
lookups.set(seg.typographyLookup.lookupKey, {
|
|
2029
|
+
segmentsByName: seg.typographyLookup.segmentsByName
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2053
2032
|
}
|
|
2054
2033
|
}
|
|
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
2034
|
}
|
|
2064
|
-
|
|
2065
|
-
return hoisted;
|
|
2035
|
+
return lookups;
|
|
2066
2036
|
}
|
|
2067
2037
|
|
|
2068
2038
|
// src/plugin/transform-css.ts
|
|
@@ -2231,8 +2201,8 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2231
2201
|
if (seg.error) {
|
|
2232
2202
|
return { error: seg.error };
|
|
2233
2203
|
}
|
|
2234
|
-
if (seg.
|
|
2235
|
-
return { error: `
|
|
2204
|
+
if (seg.variableProps && !seg.argResolved) {
|
|
2205
|
+
return { error: `variable value with variable argument is not supported in .css.ts files` };
|
|
2236
2206
|
}
|
|
2237
2207
|
if (seg.typographyLookup) {
|
|
2238
2208
|
return { error: `typography() with a runtime key is not supported in .css.ts files` };
|
|
@@ -2254,7 +2224,7 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2254
2224
|
}
|
|
2255
2225
|
for (const [prop, value] of Object.entries(seg.defs)) {
|
|
2256
2226
|
if (typeof value === "string" || typeof value === "number") {
|
|
2257
|
-
declarations.push({ property:
|
|
2227
|
+
declarations.push({ property: camelToKebab2(prop), value: String(value) });
|
|
2258
2228
|
} else {
|
|
2259
2229
|
return { error: `unexpected nested value for property "${prop}"` };
|
|
2260
2230
|
}
|
|
@@ -2263,7 +2233,7 @@ function resolveCssExpression(node, cssBindingName, mapping, filename) {
|
|
|
2263
2233
|
}
|
|
2264
2234
|
return { declarations };
|
|
2265
2235
|
}
|
|
2266
|
-
function
|
|
2236
|
+
function camelToKebab2(s) {
|
|
2267
2237
|
return s.replace(/^(Webkit|Moz|Ms|O)/, (m) => `-${m.toLowerCase()}`).replace(/[A-Z]/g, (m) => `-${m.toLowerCase()}`);
|
|
2268
2238
|
}
|
|
2269
2239
|
function formatCssRule(selector, declarations) {
|
|
@@ -2331,11 +2301,19 @@ function toVirtualCssSpecifier(source) {
|
|
|
2331
2301
|
// src/plugin/index.ts
|
|
2332
2302
|
var VIRTUAL_CSS_PREFIX = "\0truss-css:";
|
|
2333
2303
|
var CSS_TS_QUERY = "?truss-css";
|
|
2304
|
+
var VIRTUAL_CSS_ENDPOINT = "/virtual:truss.css";
|
|
2305
|
+
var VIRTUAL_RUNTIME_ID = "virtual:truss:runtime";
|
|
2306
|
+
var RESOLVED_VIRTUAL_RUNTIME_ID = "\0" + VIRTUAL_RUNTIME_ID;
|
|
2334
2307
|
function trussPlugin(opts) {
|
|
2335
2308
|
let mapping = null;
|
|
2336
2309
|
let projectRoot;
|
|
2337
2310
|
let debug = false;
|
|
2311
|
+
let isTest = false;
|
|
2312
|
+
let isBuild = false;
|
|
2338
2313
|
const externalPackages = opts.externalPackages ?? [];
|
|
2314
|
+
const cssRegistry = /* @__PURE__ */ new Map();
|
|
2315
|
+
let cssVersion = 0;
|
|
2316
|
+
let lastSentVersion = 0;
|
|
2339
2317
|
function mappingPath() {
|
|
2340
2318
|
return resolve(projectRoot || process.cwd(), opts.mapping);
|
|
2341
2319
|
}
|
|
@@ -2345,23 +2323,98 @@ function trussPlugin(opts) {
|
|
|
2345
2323
|
}
|
|
2346
2324
|
return mapping;
|
|
2347
2325
|
}
|
|
2326
|
+
function collectCss() {
|
|
2327
|
+
return generateCssText(cssRegistry);
|
|
2328
|
+
}
|
|
2348
2329
|
return {
|
|
2349
|
-
name: "truss
|
|
2330
|
+
name: "truss",
|
|
2350
2331
|
enforce: "pre",
|
|
2351
2332
|
configResolved(config) {
|
|
2352
2333
|
projectRoot = config.root;
|
|
2353
2334
|
debug = config.command === "serve" || config.mode === "development" || config.mode === "test";
|
|
2335
|
+
isTest = config.mode === "test";
|
|
2336
|
+
isBuild = config.command === "build";
|
|
2354
2337
|
},
|
|
2355
2338
|
buildStart() {
|
|
2356
2339
|
ensureMapping();
|
|
2340
|
+
cssRegistry.clear();
|
|
2341
|
+
cssVersion = 0;
|
|
2342
|
+
lastSentVersion = 0;
|
|
2357
2343
|
},
|
|
2344
|
+
// -- Dev mode HMR --
|
|
2345
|
+
configureServer(server) {
|
|
2346
|
+
if (isTest) return;
|
|
2347
|
+
server.middlewares.use(function(req, res, next) {
|
|
2348
|
+
if (req.url !== VIRTUAL_CSS_ENDPOINT) return next();
|
|
2349
|
+
const css = collectCss();
|
|
2350
|
+
res.setHeader("Content-Type", "text/css");
|
|
2351
|
+
res.setHeader("Cache-Control", "no-store");
|
|
2352
|
+
res.end(css);
|
|
2353
|
+
});
|
|
2354
|
+
const interval = setInterval(function() {
|
|
2355
|
+
if (cssVersion !== lastSentVersion && server.ws) {
|
|
2356
|
+
lastSentVersion = cssVersion;
|
|
2357
|
+
server.ws.send({ type: "custom", event: "truss:css-update" });
|
|
2358
|
+
}
|
|
2359
|
+
}, 150);
|
|
2360
|
+
server.httpServer?.on("close", function() {
|
|
2361
|
+
clearInterval(interval);
|
|
2362
|
+
});
|
|
2363
|
+
},
|
|
2364
|
+
transformIndexHtml(html) {
|
|
2365
|
+
if (isBuild) return html;
|
|
2366
|
+
const tags = [
|
|
2367
|
+
`<link rel="stylesheet" href="${VIRTUAL_CSS_ENDPOINT}">`,
|
|
2368
|
+
`<script type="module" src="/${VIRTUAL_RUNTIME_ID}"></script>`
|
|
2369
|
+
].join("\n ");
|
|
2370
|
+
return html.replace("</head>", ` ${tags}
|
|
2371
|
+
</head>`);
|
|
2372
|
+
},
|
|
2373
|
+
handleHotUpdate(ctx) {
|
|
2374
|
+
if (ctx.server?.ws) {
|
|
2375
|
+
ctx.server.ws.send({ type: "custom", event: "truss:css-update" });
|
|
2376
|
+
}
|
|
2377
|
+
},
|
|
2378
|
+
// -- Virtual module resolution --
|
|
2358
2379
|
resolveId(source, importer) {
|
|
2380
|
+
if (source === VIRTUAL_RUNTIME_ID || source === "/" + VIRTUAL_RUNTIME_ID) {
|
|
2381
|
+
return RESOLVED_VIRTUAL_RUNTIME_ID;
|
|
2382
|
+
}
|
|
2359
2383
|
if (!source.endsWith(CSS_TS_QUERY)) return null;
|
|
2360
2384
|
const absolutePath = resolveImportPath(source.slice(0, -CSS_TS_QUERY.length), importer, projectRoot);
|
|
2361
2385
|
if (!existsSync(absolutePath)) return null;
|
|
2362
2386
|
return VIRTUAL_CSS_PREFIX + absolutePath.slice(0, -3);
|
|
2363
2387
|
},
|
|
2364
2388
|
load(id) {
|
|
2389
|
+
if (id === RESOLVED_VIRTUAL_RUNTIME_ID) {
|
|
2390
|
+
return `
|
|
2391
|
+
// Truss dev HMR runtime \u2014 keeps styles up to date without page reload
|
|
2392
|
+
(function() {
|
|
2393
|
+
let style = document.getElementById("__truss_virtual__");
|
|
2394
|
+
if (!style) {
|
|
2395
|
+
style = document.createElement("style");
|
|
2396
|
+
style.id = "__truss_virtual__";
|
|
2397
|
+
document.head.appendChild(style);
|
|
2398
|
+
}
|
|
2399
|
+
|
|
2400
|
+
function fetchCss() {
|
|
2401
|
+
fetch("${VIRTUAL_CSS_ENDPOINT}")
|
|
2402
|
+
.then(function(r) { return r.text(); })
|
|
2403
|
+
.then(function(css) { style.textContent = css; })
|
|
2404
|
+
.catch(function() {});
|
|
2405
|
+
}
|
|
2406
|
+
|
|
2407
|
+
fetchCss();
|
|
2408
|
+
|
|
2409
|
+
if (import.meta.hot) {
|
|
2410
|
+
import.meta.hot.on("truss:css-update", fetchCss);
|
|
2411
|
+
import.meta.hot.on("vite:afterUpdate", function() {
|
|
2412
|
+
setTimeout(fetchCss, 50);
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
})();
|
|
2416
|
+
`;
|
|
2417
|
+
}
|
|
2365
2418
|
if (!id.startsWith(VIRTUAL_CSS_PREFIX)) return null;
|
|
2366
2419
|
const sourcePath = id.slice(VIRTUAL_CSS_PREFIX.length) + ".ts";
|
|
2367
2420
|
const sourceCode = readFileSync(sourcePath, "utf8");
|
|
@@ -2383,12 +2436,62 @@ function trussPlugin(opts) {
|
|
|
2383
2436
|
if (!hasCssDsl) {
|
|
2384
2437
|
return { code: rewrittenCode, map: null };
|
|
2385
2438
|
}
|
|
2386
|
-
const result = transformTruss(rewrittenCode, fileId, ensureMapping(), {
|
|
2439
|
+
const result = transformTruss(rewrittenCode, fileId, ensureMapping(), {
|
|
2440
|
+
debug,
|
|
2441
|
+
// In test mode (jsdom), inject CSS directly so document.styleSheets has rules
|
|
2442
|
+
injectCss: isTest
|
|
2443
|
+
});
|
|
2387
2444
|
if (!result) {
|
|
2388
2445
|
if (!rewrittenImports.changed) return null;
|
|
2389
2446
|
return { code: rewrittenCode, map: null };
|
|
2390
2447
|
}
|
|
2448
|
+
if (result.rules) {
|
|
2449
|
+
let hasNewRules = false;
|
|
2450
|
+
for (const [className, rule] of result.rules) {
|
|
2451
|
+
if (!cssRegistry.has(className)) {
|
|
2452
|
+
cssRegistry.set(className, rule);
|
|
2453
|
+
hasNewRules = true;
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
if (hasNewRules) {
|
|
2457
|
+
cssVersion++;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2391
2460
|
return { code: result.code, map: result.map };
|
|
2461
|
+
},
|
|
2462
|
+
// -- Production CSS emission --
|
|
2463
|
+
generateBundle(_options, bundle) {
|
|
2464
|
+
if (!isBuild) return;
|
|
2465
|
+
const css = collectCss();
|
|
2466
|
+
if (!css) return;
|
|
2467
|
+
for (const key of Object.keys(bundle)) {
|
|
2468
|
+
const asset = bundle[key];
|
|
2469
|
+
if (asset.type === "asset" && key.endsWith(".css")) {
|
|
2470
|
+
asset.source = asset.source + "\n" + css;
|
|
2471
|
+
return;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
this.emitFile({
|
|
2475
|
+
type: "asset",
|
|
2476
|
+
fileName: "truss.css",
|
|
2477
|
+
source: css
|
|
2478
|
+
});
|
|
2479
|
+
},
|
|
2480
|
+
writeBundle(options, bundle) {
|
|
2481
|
+
if (!isBuild) return;
|
|
2482
|
+
const css = collectCss();
|
|
2483
|
+
if (!css) return;
|
|
2484
|
+
const outDir = options.dir || join(projectRoot, "dist");
|
|
2485
|
+
const trussPath = join(outDir, "truss.css");
|
|
2486
|
+
if (!existsSync(trussPath)) {
|
|
2487
|
+
const alreadyEmitted = Object.keys(bundle).some(function(key) {
|
|
2488
|
+
const asset = bundle[key];
|
|
2489
|
+
return asset.type === "asset" && key.endsWith(".css") && typeof asset.source === "string" && asset.source.includes(css);
|
|
2490
|
+
});
|
|
2491
|
+
if (!alreadyEmitted) {
|
|
2492
|
+
writeFileSync(trussPath, css, "utf8");
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2392
2495
|
}
|
|
2393
2496
|
};
|
|
2394
2497
|
}
|