@csszyx/compiler 0.6.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -2
- package/dist/color-var.cjs +3 -28
- package/dist/{color-var.js → color-var.mjs} +2 -6
- package/dist/index.cjs +2073 -3202
- package/dist/index.d.cts +12118 -111
- package/dist/index.d.mts +13484 -0
- package/dist/index.mjs +2706 -0
- package/dist/shared/compiler.BIUVmI0H.mjs +2271 -0
- package/dist/{index.js → shared/compiler.C6jT0mcT.cjs} +75 -1609
- package/dist/transform-core.cjs +17 -0
- package/dist/transform-core.d.cts +86 -0
- package/dist/transform-core.d.mts +86 -0
- package/dist/transform-core.mjs +1 -0
- package/package.json +41 -19
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/index.d.ts +0 -1477
- /package/dist/{color-var.d.ts → color-var.d.mts} +0 -0
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
__require
|
|
3
|
-
} from "./chunk-3RG5ZIWI.js";
|
|
1
|
+
'use strict';
|
|
4
2
|
|
|
5
|
-
// src/compiler.ts
|
|
6
|
-
import { init, transform_sz, version as getWasmVersion } from "@csszyx/core";
|
|
7
|
-
|
|
8
|
-
// src/property-types.ts
|
|
9
3
|
var PropertyCategory = /* @__PURE__ */ ((PropertyCategory2) => {
|
|
10
4
|
PropertyCategory2[PropertyCategory2["SPACING"] = 0] = "SPACING";
|
|
11
5
|
PropertyCategory2[PropertyCategory2["COLOR"] = 1] = "COLOR";
|
|
@@ -17,7 +11,7 @@ var PropertyCategory = /* @__PURE__ */ ((PropertyCategory2) => {
|
|
|
17
11
|
PropertyCategory2[PropertyCategory2["PASSTHROUGH"] = 7] = "PASSTHROUGH";
|
|
18
12
|
return PropertyCategory2;
|
|
19
13
|
})(PropertyCategory || {});
|
|
20
|
-
|
|
14
|
+
const PROPERTY_CATEGORY_MAP = {
|
|
21
15
|
// ---- SPACING ----
|
|
22
16
|
p: 0 /* SPACING */,
|
|
23
17
|
pt: 0 /* SPACING */,
|
|
@@ -181,7 +175,7 @@ var PROPERTY_CATEGORY_MAP = {
|
|
|
181
175
|
function getPropertyCategory(property) {
|
|
182
176
|
return PROPERTY_CATEGORY_MAP[property] ?? 7 /* PASSTHROUGH */;
|
|
183
177
|
}
|
|
184
|
-
|
|
178
|
+
const COLOR_PROPERTIES = new Set(
|
|
185
179
|
Object.entries(PROPERTY_CATEGORY_MAP).filter(([, cat]) => cat === 1 /* COLOR */).map(([key]) => key)
|
|
186
180
|
);
|
|
187
181
|
function getCSSVariableName(property, variantPrefix) {
|
|
@@ -192,8 +186,7 @@ function getCSSVariableName(property, variantPrefix) {
|
|
|
192
186
|
return `--_sz-${prop}`;
|
|
193
187
|
}
|
|
194
188
|
|
|
195
|
-
|
|
196
|
-
var COLOR_STRING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
189
|
+
const COLOR_STRING_KEYWORDS = /* @__PURE__ */ new Set([
|
|
197
190
|
"inherit",
|
|
198
191
|
"current",
|
|
199
192
|
"transparent",
|
|
@@ -239,10 +232,10 @@ function stripInvalidColorStrings(sz) {
|
|
|
239
232
|
result[key] = stripInvalidColorStrings(value);
|
|
240
233
|
continue;
|
|
241
234
|
}
|
|
242
|
-
if (typeof value === "string" && PROPERTY_CATEGORY_MAP[key] ===
|
|
235
|
+
if (typeof value === "string" && PROPERTY_CATEGORY_MAP[key] === PropertyCategory.COLOR) {
|
|
243
236
|
const strVal = value.replace(/!$/, "");
|
|
244
237
|
if (hasSlashOpacity(strVal)) {
|
|
245
|
-
if (process.env
|
|
238
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined") {
|
|
246
239
|
const slashIdx = strVal.indexOf("/");
|
|
247
240
|
const colorPart = strVal.slice(0, slashIdx);
|
|
248
241
|
const opPart = strVal.slice(slashIdx + 1);
|
|
@@ -253,7 +246,7 @@ function stripInvalidColorStrings(sz) {
|
|
|
253
246
|
continue;
|
|
254
247
|
}
|
|
255
248
|
if (!isValidColorString(strVal)) {
|
|
256
|
-
if (process.env
|
|
249
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined") {
|
|
257
250
|
console.warn(
|
|
258
251
|
`[csszyx] "${key}: '${strVal}'" is not a recognized color value and will be ignored. Use a Tailwind color ("blue-500"), CSS variable ("--my-color"), hex/rgb/hsl ("#ff0000"), or object form ({ color: "blue-500", op: 50 }).`
|
|
259
252
|
);
|
|
@@ -266,45 +259,7 @@ function stripInvalidColorStrings(sz) {
|
|
|
266
259
|
return result;
|
|
267
260
|
}
|
|
268
261
|
|
|
269
|
-
|
|
270
|
-
import * as babel from "@babel/core";
|
|
271
|
-
import * as t from "@babel/types";
|
|
272
|
-
|
|
273
|
-
// src/ast-budget.ts
|
|
274
|
-
var AST_BUDGET = 5e4;
|
|
275
|
-
var ASTBudgetExceededError = class extends Error {
|
|
276
|
-
/**
|
|
277
|
-
*
|
|
278
|
-
* @param filename Source filename if known, otherwise `undefined`.
|
|
279
|
-
* @param nodeCount Node count at the point traversal was aborted.
|
|
280
|
-
* @param budget Effective budget that was exceeded. Defaults to
|
|
281
|
-
* {@link AST_BUDGET} for backwards compatibility with callers that
|
|
282
|
-
* don't pass an override.
|
|
283
|
-
*/
|
|
284
|
-
constructor(filename, nodeCount, budget = AST_BUDGET) {
|
|
285
|
-
const where = filename ?? "<anonymous>";
|
|
286
|
-
super(
|
|
287
|
-
`[csszyx] AST budget exceeded: ${where} has more than ${budget} nodes (traversal aborted at ${nodeCount}). Files this large are almost always machine-generated and should be excluded from sz transformation. Either exclude the file from the plugin (Vite: \`csszyx({ exclude: [/large-data\\.ts$/] })\`), or raise the limit globally with \`csszyx({ build: { astBudgetLimit: 100_000 } })\`.`
|
|
288
|
-
);
|
|
289
|
-
this.name = "ASTBudgetExceededError";
|
|
290
|
-
this.filename = filename;
|
|
291
|
-
this.nodeCount = nodeCount;
|
|
292
|
-
this.budget = budget;
|
|
293
|
-
}
|
|
294
|
-
};
|
|
295
|
-
|
|
296
|
-
// src/recovery-tokens.ts
|
|
297
|
-
import { createHash } from "crypto";
|
|
298
|
-
function generateInlineRecoveryToken(filename, line, column, elementType) {
|
|
299
|
-
const input = `${filename}:${line}:${column}:${elementType}`;
|
|
300
|
-
return createHash("sha256").update(input).digest("hex").substring(0, 12);
|
|
301
|
-
}
|
|
302
|
-
function isValidInlineRecoveryMode(value) {
|
|
303
|
-
return value === "csr" || value === "dev-only";
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
// src/transform-core.ts
|
|
307
|
-
var PROPERTY_MAP = {
|
|
262
|
+
const PROPERTY_MAP = {
|
|
308
263
|
// Background
|
|
309
264
|
bg: "bg",
|
|
310
265
|
bgAttach: "bg",
|
|
@@ -624,12 +579,12 @@ var PROPERTY_MAP = {
|
|
|
624
579
|
// Overflow
|
|
625
580
|
overflow: "overflow"
|
|
626
581
|
};
|
|
627
|
-
|
|
582
|
+
const CSS_VAR_TYPE_HINTS = {
|
|
628
583
|
fontFamily: "family-name",
|
|
629
584
|
fontWeight: "weight",
|
|
630
585
|
text: "length"
|
|
631
586
|
};
|
|
632
|
-
|
|
587
|
+
const SUGGESTION_MAP = {
|
|
633
588
|
// Background
|
|
634
589
|
backgroundColor: "bg",
|
|
635
590
|
backgroundImage: "bgImg",
|
|
@@ -739,7 +694,7 @@ var SUGGESTION_MAP = {
|
|
|
739
694
|
flexWrapReverse: "flexWrap: 'wrap-reverse'",
|
|
740
695
|
flexNowrap: "flexWrap: 'nowrap'"
|
|
741
696
|
};
|
|
742
|
-
|
|
697
|
+
const VARIANT_MAP = {
|
|
743
698
|
// Focus variants
|
|
744
699
|
focusWithin: "focus-within",
|
|
745
700
|
focusVisible: "focus-visible",
|
|
@@ -778,7 +733,7 @@ var VARIANT_MAP = {
|
|
|
778
733
|
"@maxXl": "@max-xl",
|
|
779
734
|
"@max2xl": "@max-2xl"
|
|
780
735
|
};
|
|
781
|
-
|
|
736
|
+
const KNOWN_VARIANTS = /* @__PURE__ */ new Set([
|
|
782
737
|
// Responsive
|
|
783
738
|
"sm",
|
|
784
739
|
"md",
|
|
@@ -879,7 +834,7 @@ var KNOWN_VARIANTS = /* @__PURE__ */ new Set([
|
|
|
879
834
|
"ltr",
|
|
880
835
|
"rtl"
|
|
881
836
|
]);
|
|
882
|
-
|
|
837
|
+
const ARIA_STATES = /* @__PURE__ */ new Set([
|
|
883
838
|
"checked",
|
|
884
839
|
"disabled",
|
|
885
840
|
"expanded",
|
|
@@ -895,7 +850,7 @@ var ARIA_STATES = /* @__PURE__ */ new Set([
|
|
|
895
850
|
"atomic",
|
|
896
851
|
"modal"
|
|
897
852
|
]);
|
|
898
|
-
|
|
853
|
+
const BOOLEAN_SHORTHANDS = /* @__PURE__ */ new Set([
|
|
899
854
|
// Display
|
|
900
855
|
"block",
|
|
901
856
|
"inline",
|
|
@@ -973,7 +928,7 @@ var BOOLEAN_SHORTHANDS = /* @__PURE__ */ new Set([
|
|
|
973
928
|
// Outline
|
|
974
929
|
"outline"
|
|
975
930
|
]);
|
|
976
|
-
|
|
931
|
+
const BOOLEAN_TO_CLASS = {
|
|
977
932
|
inlineBlock: "inline-block",
|
|
978
933
|
inlineFlex: "inline-flex",
|
|
979
934
|
inlineGrid: "inline-grid",
|
|
@@ -1009,7 +964,7 @@ var BOOLEAN_TO_CLASS = {
|
|
|
1009
964
|
// Misc
|
|
1010
965
|
proseInvert: "prose-invert"
|
|
1011
966
|
};
|
|
1012
|
-
|
|
967
|
+
const SNAP_DIRECT_MAP = {
|
|
1013
968
|
snapAlign: {
|
|
1014
969
|
start: "snap-start",
|
|
1015
970
|
end: "snap-end",
|
|
@@ -1031,7 +986,7 @@ var SNAP_DIRECT_MAP = {
|
|
|
1031
986
|
proximity: "snap-proximity"
|
|
1032
987
|
}
|
|
1033
988
|
};
|
|
1034
|
-
|
|
989
|
+
const NEGATIVE_ALLOWED = /* @__PURE__ */ new Set([
|
|
1035
990
|
"m",
|
|
1036
991
|
"mt",
|
|
1037
992
|
"mr",
|
|
@@ -1120,7 +1075,7 @@ function normalizeArbitraryValue(value) {
|
|
|
1120
1075
|
const stripped = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
1121
1076
|
return stripped.trim().replace(/\s+/g, "_");
|
|
1122
1077
|
}
|
|
1123
|
-
|
|
1078
|
+
const FRACTION_SUPPORTED_PROPS = /* @__PURE__ */ new Set([
|
|
1124
1079
|
// Sizing (both rawKey and resolved key forms)
|
|
1125
1080
|
"w",
|
|
1126
1081
|
"width",
|
|
@@ -1166,8 +1121,12 @@ var FRACTION_SUPPORTED_PROPS = /* @__PURE__ */ new Set([
|
|
|
1166
1121
|
]);
|
|
1167
1122
|
function needsArbitraryBrackets(value) {
|
|
1168
1123
|
const v = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
1169
|
-
return /^\d+(\.\d+)?(px|rem|em|%|vh|vw|ch|dvh|dvw|svh|svw|lvh|lvw|cqw|cqh|deg|rad|turn|grad|ms|s|fr)$/.test(
|
|
1170
|
-
|
|
1124
|
+
return /^\d+(\.\d+)?(px|rem|em|%|vh|vw|ch|dvh|dvw|svh|svw|lvh|lvw|cqw|cqh|deg|rad|turn|grad|ms|s|fr)$/.test(
|
|
1125
|
+
v
|
|
1126
|
+
) || // Positive units
|
|
1127
|
+
/^-\d+(\.\d+)?(px|rem|em|%|vh|vw|ch|dvh|dvw|svh|svw|lvh|lvw|cqw|cqh|deg|rad|turn|grad|ms|s|fr)$/.test(
|
|
1128
|
+
v
|
|
1129
|
+
) || // Negative units like -1px, -2rem
|
|
1171
1130
|
/^\.\d+(px|rem|em|%|vh|vw|ch)?$/.test(v) || // Values starting with . like .25em
|
|
1172
1131
|
/^-\.\d+(px|rem|em|%|vh|vw|ch)?$/.test(v) || // Negative values starting with -. like -.25em
|
|
1173
1132
|
v.startsWith("#") || // Hex colors
|
|
@@ -1182,8 +1141,8 @@ function needsArbitraryBrackets(value) {
|
|
|
1182
1141
|
v.includes("max(") || // Max
|
|
1183
1142
|
v.includes(" ");
|
|
1184
1143
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1144
|
+
const LIST_STYLE_STANDARD = /* @__PURE__ */ new Set(["none", "disc", "decimal"]);
|
|
1145
|
+
const FONT_STRETCH_KEYWORDS = /* @__PURE__ */ new Set([
|
|
1187
1146
|
"ultra-condensed",
|
|
1188
1147
|
"extra-condensed",
|
|
1189
1148
|
"condensed",
|
|
@@ -1514,10 +1473,10 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1514
1473
|
}
|
|
1515
1474
|
continue;
|
|
1516
1475
|
}
|
|
1517
|
-
if (typeof value === "string" && PROPERTY_CATEGORY_MAP[rawKey] ===
|
|
1476
|
+
if (typeof value === "string" && PROPERTY_CATEGORY_MAP[rawKey] === PropertyCategory.COLOR) {
|
|
1518
1477
|
const strVal = value.replace(/!$/, "");
|
|
1519
1478
|
if (hasSlashOpacity(strVal)) {
|
|
1520
|
-
if (process.env
|
|
1479
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined") {
|
|
1521
1480
|
const slashIdx = strVal.indexOf("/");
|
|
1522
1481
|
const colorPart = strVal.slice(0, slashIdx);
|
|
1523
1482
|
const opPart = strVal.slice(slashIdx + 1);
|
|
@@ -1528,7 +1487,7 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1528
1487
|
continue;
|
|
1529
1488
|
}
|
|
1530
1489
|
if (!isValidColorString(strVal)) {
|
|
1531
|
-
if (process.env
|
|
1490
|
+
if (process.env.NODE_ENV !== "production" && typeof window === "undefined") {
|
|
1532
1491
|
console.warn(
|
|
1533
1492
|
`[csszyx] "${rawKey}: '${strVal}'" is not a recognized color value and will be ignored. Use a Tailwind color ("blue-500"), CSS variable ("--my-color"), hex/rgb/hsl ("#ff0000"), or object form ({ color: "blue-500", op: 50 }).`
|
|
1534
1493
|
);
|
|
@@ -1619,7 +1578,10 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1619
1578
|
}
|
|
1620
1579
|
} else if (PROPERTY_MAP[nestedKey] || BOOLEAN_SHORTHANDS.has(nestedKey) || nestedKey.startsWith("@")) {
|
|
1621
1580
|
const nestedPrefix2 = `${prefix}${mappedKey}:`;
|
|
1622
|
-
const result = transform(
|
|
1581
|
+
const result = transform(
|
|
1582
|
+
{ [nestedKey]: nestedValue },
|
|
1583
|
+
nestedPrefix2
|
|
1584
|
+
);
|
|
1623
1585
|
if (result.className) {
|
|
1624
1586
|
classes.push(result.className);
|
|
1625
1587
|
}
|
|
@@ -1631,7 +1593,10 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1631
1593
|
}
|
|
1632
1594
|
} else {
|
|
1633
1595
|
const nestedPrefix2 = `${prefix}${mappedKey}:`;
|
|
1634
|
-
const result = transform(
|
|
1596
|
+
const result = transform(
|
|
1597
|
+
{ [nestedKey]: nestedValue },
|
|
1598
|
+
nestedPrefix2
|
|
1599
|
+
);
|
|
1635
1600
|
if (result.className) {
|
|
1636
1601
|
classes.push(result.className);
|
|
1637
1602
|
}
|
|
@@ -1745,7 +1710,9 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1745
1710
|
}
|
|
1746
1711
|
if (typeof value === "string") {
|
|
1747
1712
|
if (rawKey === "decoration") {
|
|
1748
|
-
if (["underline", "overline", "line-through", "no-underline", "none"].includes(
|
|
1713
|
+
if (["underline", "overline", "line-through", "no-underline", "none"].includes(
|
|
1714
|
+
value
|
|
1715
|
+
)) {
|
|
1749
1716
|
className += value === "none" ? "no-underline" : value;
|
|
1750
1717
|
classes.push(className);
|
|
1751
1718
|
continue;
|
|
@@ -1783,9 +1750,9 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1783
1750
|
}
|
|
1784
1751
|
if (rawKey === "break") {
|
|
1785
1752
|
const wbMap = {
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1753
|
+
normal: "break-normal",
|
|
1754
|
+
all: "break-all",
|
|
1755
|
+
keep: "break-keep",
|
|
1789
1756
|
"break-normal": "break-normal",
|
|
1790
1757
|
"break-all": "break-all",
|
|
1791
1758
|
"break-keep": "break-keep"
|
|
@@ -1796,9 +1763,9 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1796
1763
|
}
|
|
1797
1764
|
if (rawKey === "wrap") {
|
|
1798
1765
|
const owMap = {
|
|
1799
|
-
|
|
1766
|
+
normal: "wrap-normal",
|
|
1800
1767
|
"break-word": "wrap-break-word",
|
|
1801
|
-
|
|
1768
|
+
anywhere: "wrap-anywhere",
|
|
1802
1769
|
"wrap-normal": "wrap-normal",
|
|
1803
1770
|
"wrap-break-word": "wrap-break-word",
|
|
1804
1771
|
"wrap-anywhere": "wrap-anywhere"
|
|
@@ -1821,7 +1788,7 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
1821
1788
|
className += `line-clamp-(${sValue})`;
|
|
1822
1789
|
} else {
|
|
1823
1790
|
const numVal = Number(sValue);
|
|
1824
|
-
if (!isNaN(numVal) && Number.isInteger(numVal)) {
|
|
1791
|
+
if (!Number.isNaN(numVal) && Number.isInteger(numVal)) {
|
|
1825
1792
|
className += `line-clamp-${sValue}`;
|
|
1826
1793
|
} else {
|
|
1827
1794
|
className += `line-clamp-[${sValue}]`;
|
|
@@ -2149,7 +2116,17 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
2149
2116
|
continue;
|
|
2150
2117
|
}
|
|
2151
2118
|
if (rawKey === "perspectiveOrigin") {
|
|
2152
|
-
const STANDARD_ORIGINS = /* @__PURE__ */ new Set([
|
|
2119
|
+
const STANDARD_ORIGINS = /* @__PURE__ */ new Set([
|
|
2120
|
+
"center",
|
|
2121
|
+
"top",
|
|
2122
|
+
"right",
|
|
2123
|
+
"bottom",
|
|
2124
|
+
"left",
|
|
2125
|
+
"top-left",
|
|
2126
|
+
"top-right",
|
|
2127
|
+
"bottom-left",
|
|
2128
|
+
"bottom-right"
|
|
2129
|
+
]);
|
|
2153
2130
|
if (STANDARD_ORIGINS.has(value)) {
|
|
2154
2131
|
className += `perspective-origin-${value}`;
|
|
2155
2132
|
} else {
|
|
@@ -2223,8 +2200,7 @@ function transform(szProp, prefix = "", mangleMap) {
|
|
|
2223
2200
|
finalValue = `[${finalValue}]`;
|
|
2224
2201
|
}
|
|
2225
2202
|
} else if (key === "aspect" && /^[0-9]+(?:\.[0-9]+)?\/[0-9]+(?:\.[0-9]+)?$/.test(finalValue)) {
|
|
2226
|
-
if (finalValue === "auto" || finalValue === "square" || finalValue === "video" || /^\d+\/\d+$/.test(finalValue)) {
|
|
2227
|
-
} else {
|
|
2203
|
+
if (finalValue === "auto" || finalValue === "square" || finalValue === "video" || /^\d+\/\d+$/.test(finalValue)) ; else {
|
|
2228
2204
|
finalValue = `[${finalValue}]`;
|
|
2229
2205
|
}
|
|
2230
2206
|
} else if (needsArbitraryBrackets(finalValue) || /^\d+\.\d+%$/.test(finalValue)) {
|
|
@@ -2294,1530 +2270,20 @@ function normalizeClassName(className) {
|
|
|
2294
2270
|
return className.split(/\s+/).filter(Boolean).join(" ");
|
|
2295
2271
|
}
|
|
2296
2272
|
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
// Enable TS/JSX parsing
|
|
2315
|
-
ast: true,
|
|
2316
|
-
code: true,
|
|
2317
|
-
configFile: false,
|
|
2318
|
-
babelrc: false,
|
|
2319
|
-
parserOpts: {
|
|
2320
|
-
plugins: ["typescript", "jsx"]
|
|
2321
|
-
},
|
|
2322
|
-
plugins: [
|
|
2323
|
-
function() {
|
|
2324
|
-
return {
|
|
2325
|
-
// Budget guard runs in `pre` (before the visitor pass)
|
|
2326
|
-
// so it short-circuits pathologically large files
|
|
2327
|
-
// before any sz transform work begins, and doesn't
|
|
2328
|
-
// interfere with the JSXAttribute handler below.
|
|
2329
|
-
pre(file) {
|
|
2330
|
-
let nodeCount = 0;
|
|
2331
|
-
babel.traverse(file.ast, {
|
|
2332
|
-
enter() {
|
|
2333
|
-
nodeCount++;
|
|
2334
|
-
if (nodeCount > astBudget) {
|
|
2335
|
-
throw new ASTBudgetExceededError(filename, nodeCount, astBudget);
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
});
|
|
2339
|
-
},
|
|
2340
|
-
visitor: {
|
|
2341
|
-
JSXAttribute(path) {
|
|
2342
|
-
const attrName = t.isJSXIdentifier(path.node.name) ? path.node.name.name : "";
|
|
2343
|
-
if (attrName === "className" || attrName === "class") {
|
|
2344
|
-
const val = path.node.value;
|
|
2345
|
-
if (t.isStringLiteral(val)) {
|
|
2346
|
-
for (const c of val.value.split(/\s+/)) {
|
|
2347
|
-
if (c) {
|
|
2348
|
-
rawClassNames.add(c);
|
|
2349
|
-
}
|
|
2350
|
-
}
|
|
2351
|
-
}
|
|
2352
|
-
return;
|
|
2353
|
-
}
|
|
2354
|
-
if (attrName === "szRecover") {
|
|
2355
|
-
const recoverValue = path.node.value;
|
|
2356
|
-
if (!t.isStringLiteral(recoverValue)) {
|
|
2357
|
-
diagnostics.push(
|
|
2358
|
-
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: only string-literal values ("csr" | "dev-only") are supported. Dynamic values disable token emission for this element.`
|
|
2359
|
-
);
|
|
2360
|
-
return;
|
|
2361
|
-
}
|
|
2362
|
-
if (!isValidInlineRecoveryMode(recoverValue.value)) {
|
|
2363
|
-
diagnostics.push(
|
|
2364
|
-
`[csszyx] szRecover at ${filename ?? "<anonymous>"}: unknown mode "${recoverValue.value}" \u2014 expected "csr" or "dev-only". Token emission skipped.`
|
|
2365
|
-
);
|
|
2366
|
-
return;
|
|
2367
|
-
}
|
|
2368
|
-
const opening = path.parentPath;
|
|
2369
|
-
if (!opening?.isJSXOpeningElement()) {
|
|
2370
|
-
return;
|
|
2371
|
-
}
|
|
2372
|
-
const alreadyTagged = opening.node.attributes.some(
|
|
2373
|
-
(attr) => t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name) && attr.name.name === "data-sz-recovery-token"
|
|
2374
|
-
);
|
|
2375
|
-
if (alreadyTagged) {
|
|
2376
|
-
return;
|
|
2377
|
-
}
|
|
2378
|
-
const loc = path.node.loc;
|
|
2379
|
-
const elementType = t.isJSXIdentifier(opening.node.name) ? opening.node.name.name : t.isJSXMemberExpression(opening.node.name) ? "<member>" : "<unknown>";
|
|
2380
|
-
const line = loc?.start.line ?? 0;
|
|
2381
|
-
const column = loc?.start.column ?? 0;
|
|
2382
|
-
const file = filename ?? "file.tsx";
|
|
2383
|
-
const token = generateInlineRecoveryToken(file, line, column, elementType);
|
|
2384
|
-
opening.node.attributes.push(
|
|
2385
|
-
t.jsxAttribute(
|
|
2386
|
-
t.jsxIdentifier("data-sz-recovery-token"),
|
|
2387
|
-
t.stringLiteral(token)
|
|
2388
|
-
)
|
|
2389
|
-
);
|
|
2390
|
-
recoveryTokens.set(token, {
|
|
2391
|
-
mode: recoverValue.value,
|
|
2392
|
-
component: elementType,
|
|
2393
|
-
path: `${file}:${line}:${column}`
|
|
2394
|
-
});
|
|
2395
|
-
transformed = true;
|
|
2396
|
-
return;
|
|
2397
|
-
}
|
|
2398
|
-
if (attrName !== "sz") {
|
|
2399
|
-
return;
|
|
2400
|
-
}
|
|
2401
|
-
const value = path.node.value;
|
|
2402
|
-
let existingClassNameNode = null;
|
|
2403
|
-
let existingClassExpr = null;
|
|
2404
|
-
let existingStyleNode = null;
|
|
2405
|
-
let existingStyleExpr = null;
|
|
2406
|
-
if (path.parentPath?.isJSXOpeningElement()) {
|
|
2407
|
-
for (const attr of path.parentPath.node.attributes) {
|
|
2408
|
-
if (t.isJSXAttribute(attr) && t.isJSXIdentifier(attr.name)) {
|
|
2409
|
-
const aName = attr.name;
|
|
2410
|
-
if (aName.name === "className" || aName.name === "class") {
|
|
2411
|
-
existingClassNameNode = attr;
|
|
2412
|
-
const aVal = attr.value;
|
|
2413
|
-
if (t.isStringLiteral(aVal)) {
|
|
2414
|
-
existingClassExpr = aVal;
|
|
2415
|
-
} else if (t.isJSXExpressionContainer(aVal)) {
|
|
2416
|
-
if (t.isExpression(aVal.expression)) {
|
|
2417
|
-
existingClassExpr = aVal.expression;
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
} else if (aName.name === "style") {
|
|
2421
|
-
existingStyleNode = attr;
|
|
2422
|
-
const aVal = attr.value;
|
|
2423
|
-
if (t.isJSXExpressionContainer(aVal)) {
|
|
2424
|
-
if (t.isExpression(aVal.expression)) {
|
|
2425
|
-
existingStyleExpr = aVal.expression;
|
|
2426
|
-
}
|
|
2427
|
-
} else if (t.isStringLiteral(aVal)) {
|
|
2428
|
-
existingStyleExpr = aVal;
|
|
2429
|
-
}
|
|
2430
|
-
}
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
}
|
|
2434
|
-
const createMergedClassNameValue = (szExpr) => {
|
|
2435
|
-
if (!existingClassExpr) {
|
|
2436
|
-
return t.isStringLiteral(szExpr) ? szExpr : t.jsxExpressionContainer(szExpr);
|
|
2437
|
-
}
|
|
2438
|
-
if (existingClassNameNode && path.parentPath?.isJSXOpeningElement()) {
|
|
2439
|
-
path.parentPath.node.attributes = path.parentPath.node.attributes.filter(
|
|
2440
|
-
(a) => a !== existingClassNameNode
|
|
2441
|
-
);
|
|
2442
|
-
existingClassNameNode = null;
|
|
2443
|
-
}
|
|
2444
|
-
if (t.isStringLiteral(existingClassExpr) && t.isStringLiteral(szExpr)) {
|
|
2445
|
-
const merged = `${existingClassExpr.value} ${szExpr.value}`.trim();
|
|
2446
|
-
return t.stringLiteral(merged);
|
|
2447
|
-
}
|
|
2448
|
-
usesRuntime = true;
|
|
2449
|
-
usesMerge = true;
|
|
2450
|
-
return t.jsxExpressionContainer(
|
|
2451
|
-
t.callExpression(t.identifier("_szMerge"), [existingClassExpr, szExpr])
|
|
2452
|
-
);
|
|
2453
|
-
};
|
|
2454
|
-
const mergeAndInjectStyle = (newStyleProps) => {
|
|
2455
|
-
if (newStyleProps.length === 0) {
|
|
2456
|
-
return;
|
|
2457
|
-
}
|
|
2458
|
-
if (!path.parentPath?.isJSXOpeningElement()) {
|
|
2459
|
-
return;
|
|
2460
|
-
}
|
|
2461
|
-
if (existingStyleNode && existingStyleExpr) {
|
|
2462
|
-
path.parentPath.node.attributes = path.parentPath.node.attributes.filter(
|
|
2463
|
-
(a) => a !== existingStyleNode
|
|
2464
|
-
);
|
|
2465
|
-
existingStyleNode = null;
|
|
2466
|
-
if (t.isObjectExpression(existingStyleExpr)) {
|
|
2467
|
-
existingStyleExpr.properties.push(...newStyleProps);
|
|
2468
|
-
path.parentPath.node.attributes.push(
|
|
2469
|
-
t.jsxAttribute(t.jsxIdentifier("style"), t.jsxExpressionContainer(existingStyleExpr))
|
|
2470
|
-
);
|
|
2471
|
-
} else if (t.isStringLiteral(existingStyleExpr)) {
|
|
2472
|
-
const parsedOldProps = parseStyleStringToObjectExpr(existingStyleExpr.value).properties;
|
|
2473
|
-
path.parentPath.node.attributes.push(
|
|
2474
|
-
t.jsxAttribute(t.jsxIdentifier("style"), t.jsxExpressionContainer(
|
|
2475
|
-
t.objectExpression([...parsedOldProps, ...newStyleProps])
|
|
2476
|
-
))
|
|
2477
|
-
);
|
|
2478
|
-
} else {
|
|
2479
|
-
const mergedStyle = t.objectExpression([
|
|
2480
|
-
t.spreadElement(existingStyleExpr),
|
|
2481
|
-
...newStyleProps
|
|
2482
|
-
]);
|
|
2483
|
-
path.parentPath.node.attributes.push(
|
|
2484
|
-
t.jsxAttribute(t.jsxIdentifier("style"), t.jsxExpressionContainer(mergedStyle))
|
|
2485
|
-
);
|
|
2486
|
-
}
|
|
2487
|
-
} else {
|
|
2488
|
-
path.parentPath.node.attributes.push(
|
|
2489
|
-
t.jsxAttribute(t.jsxIdentifier("style"), t.jsxExpressionContainer(t.objectExpression(newStyleProps)))
|
|
2490
|
-
);
|
|
2491
|
-
existingStyleExpr = t.objectExpression(newStyleProps);
|
|
2492
|
-
existingStyleNode = path.parentPath.node.attributes[path.parentPath.node.attributes.length - 1];
|
|
2493
|
-
}
|
|
2494
|
-
};
|
|
2495
|
-
if (t.isStringLiteral(value)) {
|
|
2496
|
-
path.node.name.name = "className";
|
|
2497
|
-
for (const c of value.value.split(/\s+/)) {
|
|
2498
|
-
if (c) {
|
|
2499
|
-
collectedClasses.add(c);
|
|
2500
|
-
}
|
|
2501
|
-
}
|
|
2502
|
-
path.node.value = createMergedClassNameValue(value);
|
|
2503
|
-
transformed = true;
|
|
2504
|
-
return;
|
|
2505
|
-
}
|
|
2506
|
-
if (t.isJSXExpressionContainer(value)) {
|
|
2507
|
-
const expression = value.expression;
|
|
2508
|
-
if (t.isObjectExpression(expression)) {
|
|
2509
|
-
const getBinding = (name) => path.scope.getBinding(name);
|
|
2510
|
-
const flatExpression = resolveObjectSpreads(expression, getBinding) ?? expression;
|
|
2511
|
-
const staticObject = evaluateStaticObject(flatExpression);
|
|
2512
|
-
if (staticObject !== null) {
|
|
2513
|
-
const { className, attributes } = transform(staticObject);
|
|
2514
|
-
for (const c of className.split(/\s+/)) {
|
|
2515
|
-
if (c) {
|
|
2516
|
-
collectedClasses.add(c);
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
path.node.name.name = "className";
|
|
2520
|
-
path.node.value = createMergedClassNameValue(t.stringLiteral(className));
|
|
2521
|
-
Object.entries(attributes).forEach(([key, val]) => {
|
|
2522
|
-
if (path.parentPath?.isJSXOpeningElement()) {
|
|
2523
|
-
if (key === "style") {
|
|
2524
|
-
const newProps = parseStyleStringToObjectExpr(val).properties;
|
|
2525
|
-
mergeAndInjectStyle(newProps);
|
|
2526
|
-
} else {
|
|
2527
|
-
path.parentPath.node.attributes.push(
|
|
2528
|
-
t.jsxAttribute(
|
|
2529
|
-
t.jsxIdentifier(key),
|
|
2530
|
-
t.stringLiteral(val)
|
|
2531
|
-
)
|
|
2532
|
-
);
|
|
2533
|
-
}
|
|
2534
|
-
}
|
|
2535
|
-
});
|
|
2536
|
-
transformed = true;
|
|
2537
|
-
return;
|
|
2538
|
-
}
|
|
2539
|
-
const hoisted = tryHoistConditionalSpread(expression, getBinding);
|
|
2540
|
-
if (hoisted !== null) {
|
|
2541
|
-
path.node.name.name = "className";
|
|
2542
|
-
path.node.value = createMergedClassNameValue(hoisted);
|
|
2543
|
-
collectFromExpr(hoisted, collectedClasses);
|
|
2544
|
-
transformed = true;
|
|
2545
|
-
return;
|
|
2546
|
-
}
|
|
2547
|
-
const partial = evaluatePartialObject(flatExpression);
|
|
2548
|
-
if (partial !== null && !partial.hasSpread && (partial.dynamicProps.size > 0 || partial.conditionalClasses.length > 0)) {
|
|
2549
|
-
const staticClasses = [];
|
|
2550
|
-
if (Object.keys(partial.staticProps).length > 0) {
|
|
2551
|
-
const { className: sc } = transform(partial.staticProps);
|
|
2552
|
-
if (sc) {
|
|
2553
|
-
staticClasses.push(sc);
|
|
2554
|
-
}
|
|
2555
|
-
}
|
|
2556
|
-
const cssVarClasses = [];
|
|
2557
|
-
const styleProps = [];
|
|
2558
|
-
for (const [, info] of partial.dynamicProps) {
|
|
2559
|
-
if (!info.skipClass) {
|
|
2560
|
-
cssVarClasses.push(buildCSSVarClassName(info));
|
|
2561
|
-
}
|
|
2562
|
-
styleProps.push(
|
|
2563
|
-
t.objectProperty(
|
|
2564
|
-
t.stringLiteral(info.varName),
|
|
2565
|
-
generateStyleValueExpression(info)
|
|
2566
|
-
)
|
|
2567
|
-
);
|
|
2568
|
-
}
|
|
2569
|
-
const baseClasses = [...staticClasses, ...partial.rawClasses, ...cssVarClasses].join(" ");
|
|
2570
|
-
for (const c of baseClasses.split(/\s+/)) {
|
|
2571
|
-
if (c) {
|
|
2572
|
-
collectedClasses.add(c);
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
for (const cc of partial.conditionalClasses) {
|
|
2576
|
-
for (const c of cc.consequent.split(/\s+/)) {
|
|
2577
|
-
if (c) {
|
|
2578
|
-
collectedClasses.add(c);
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
for (const c of cc.alternate.split(/\s+/)) {
|
|
2582
|
-
if (c) {
|
|
2583
|
-
collectedClasses.add(c);
|
|
2584
|
-
}
|
|
2585
|
-
}
|
|
2586
|
-
}
|
|
2587
|
-
const classExpr = partial.conditionalClasses.length > 0 ? buildConditionalClassExpr(baseClasses, partial.conditionalClasses) : t.stringLiteral(baseClasses);
|
|
2588
|
-
path.node.name.name = "className";
|
|
2589
|
-
path.node.value = createMergedClassNameValue(classExpr);
|
|
2590
|
-
mergeAndInjectStyle(styleProps);
|
|
2591
|
-
if (partial.usesColorVar) {
|
|
2592
|
-
usesColorVar = true;
|
|
2593
|
-
}
|
|
2594
|
-
transformed = true;
|
|
2595
|
-
return;
|
|
2596
|
-
}
|
|
2597
|
-
}
|
|
2598
|
-
if (t.isIdentifier(expression) && !t.isJSXEmptyExpression(expression)) {
|
|
2599
|
-
const binding = path.scope.getBinding(expression.name);
|
|
2600
|
-
if (binding && binding.path.isVariableDeclarator()) {
|
|
2601
|
-
const init2 = binding.path.node.init;
|
|
2602
|
-
if (init2) {
|
|
2603
|
-
const gbIdent = (name) => path.scope.getBinding(name);
|
|
2604
|
-
const resolved = tryStaticTransformNode(init2, gbIdent);
|
|
2605
|
-
if (resolved !== null) {
|
|
2606
|
-
path.node.name.name = "className";
|
|
2607
|
-
if (t.isStringLiteral(resolved)) {
|
|
2608
|
-
path.node.value = createMergedClassNameValue(resolved);
|
|
2609
|
-
for (const c of resolved.value.split(/\s+/)) {
|
|
2610
|
-
if (c) {
|
|
2611
|
-
collectedClasses.add(c);
|
|
2612
|
-
}
|
|
2613
|
-
}
|
|
2614
|
-
} else {
|
|
2615
|
-
path.node.value = createMergedClassNameValue(resolved);
|
|
2616
|
-
collectFromExpr(resolved, collectedClasses);
|
|
2617
|
-
}
|
|
2618
|
-
transformed = true;
|
|
2619
|
-
return;
|
|
2620
|
-
}
|
|
2621
|
-
}
|
|
2622
|
-
}
|
|
2623
|
-
}
|
|
2624
|
-
if (t.isConditionalExpression(expression)) {
|
|
2625
|
-
const gbCond = (name) => path.scope.getBinding(name);
|
|
2626
|
-
const resolved = tryStaticTransformNode(expression, gbCond);
|
|
2627
|
-
if (resolved !== null) {
|
|
2628
|
-
path.node.name.name = "className";
|
|
2629
|
-
if (t.isStringLiteral(resolved)) {
|
|
2630
|
-
path.node.value = createMergedClassNameValue(resolved);
|
|
2631
|
-
for (const c of resolved.value.split(/\s+/)) {
|
|
2632
|
-
if (c) {
|
|
2633
|
-
collectedClasses.add(c);
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
} else {
|
|
2637
|
-
path.node.value = createMergedClassNameValue(resolved);
|
|
2638
|
-
collectFromExpr(resolved, collectedClasses);
|
|
2639
|
-
}
|
|
2640
|
-
transformed = true;
|
|
2641
|
-
return;
|
|
2642
|
-
}
|
|
2643
|
-
}
|
|
2644
|
-
if (t.isArrayExpression(expression)) {
|
|
2645
|
-
const parts = [];
|
|
2646
|
-
let hasRuntime = false;
|
|
2647
|
-
const getBindingForArray = (name) => path.scope.getBinding(name);
|
|
2648
|
-
for (const element of expression.elements) {
|
|
2649
|
-
if (element === null) {
|
|
2650
|
-
continue;
|
|
2651
|
-
}
|
|
2652
|
-
if (t.isBooleanLiteral(element) && !element.value) {
|
|
2653
|
-
continue;
|
|
2654
|
-
}
|
|
2655
|
-
if (t.isNullLiteral(element)) {
|
|
2656
|
-
continue;
|
|
2657
|
-
}
|
|
2658
|
-
if (t.isIdentifier(element) && element.name === "undefined") {
|
|
2659
|
-
continue;
|
|
2660
|
-
}
|
|
2661
|
-
if (t.isLogicalExpression(element) && element.operator === "&&") {
|
|
2662
|
-
const resolved2 = tryStaticTransformNode(element.right, getBindingForArray);
|
|
2663
|
-
if (resolved2 !== null && t.isStringLiteral(resolved2)) {
|
|
2664
|
-
if (resolved2.value) {
|
|
2665
|
-
parts.push(t.logicalExpression("&&", element.left, resolved2));
|
|
2666
|
-
for (const c of resolved2.value.split(/\s+/)) {
|
|
2667
|
-
if (c) {
|
|
2668
|
-
collectedClasses.add(c);
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
hasRuntime = true;
|
|
2672
|
-
}
|
|
2673
|
-
continue;
|
|
2674
|
-
}
|
|
2675
|
-
parts.push(element);
|
|
2676
|
-
hasRuntime = true;
|
|
2677
|
-
continue;
|
|
2678
|
-
}
|
|
2679
|
-
const resolved = tryStaticTransformNode(element, getBindingForArray);
|
|
2680
|
-
if (resolved !== null) {
|
|
2681
|
-
if (t.isStringLiteral(resolved)) {
|
|
2682
|
-
if (resolved.value) {
|
|
2683
|
-
parts.push(resolved);
|
|
2684
|
-
for (const c of resolved.value.split(/\s+/)) {
|
|
2685
|
-
if (c) {
|
|
2686
|
-
collectedClasses.add(c);
|
|
2687
|
-
}
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
} else {
|
|
2691
|
-
parts.push(resolved);
|
|
2692
|
-
collectFromExpr(resolved, collectedClasses);
|
|
2693
|
-
hasRuntime = true;
|
|
2694
|
-
}
|
|
2695
|
-
} else {
|
|
2696
|
-
parts.push(element);
|
|
2697
|
-
hasRuntime = true;
|
|
2698
|
-
}
|
|
2699
|
-
}
|
|
2700
|
-
path.node.name.name = "className";
|
|
2701
|
-
if (parts.length === 0) {
|
|
2702
|
-
path.node.value = createMergedClassNameValue(t.stringLiteral(""));
|
|
2703
|
-
} else if (!hasRuntime) {
|
|
2704
|
-
const merged = parts.map((p) => p.value).filter(Boolean).join(" ");
|
|
2705
|
-
path.node.value = createMergedClassNameValue(t.stringLiteral(merged));
|
|
2706
|
-
} else {
|
|
2707
|
-
if (existingClassExpr) {
|
|
2708
|
-
parts.unshift(existingClassExpr);
|
|
2709
|
-
if (existingClassNameNode && path.parentPath?.isJSXOpeningElement()) {
|
|
2710
|
-
path.parentPath.node.attributes = path.parentPath.node.attributes.filter(
|
|
2711
|
-
(a) => a !== existingClassNameNode
|
|
2712
|
-
);
|
|
2713
|
-
existingClassNameNode = null;
|
|
2714
|
-
}
|
|
2715
|
-
}
|
|
2716
|
-
const szCall2 = t.callExpression(
|
|
2717
|
-
t.identifier("_szMerge"),
|
|
2718
|
-
parts
|
|
2719
|
-
);
|
|
2720
|
-
path.node.value = t.jsxExpressionContainer(szCall2);
|
|
2721
|
-
usesMerge = true;
|
|
2722
|
-
usesRuntime = true;
|
|
2723
|
-
}
|
|
2724
|
-
transformed = true;
|
|
2725
|
-
return;
|
|
2726
|
-
}
|
|
2727
|
-
const loc = expression.loc;
|
|
2728
|
-
const lineCol = loc ? `${loc.start.line}:${loc.start.column + 1}` : "?";
|
|
2729
|
-
let reason, suggestion;
|
|
2730
|
-
if (t.isCallExpression(expression)) {
|
|
2731
|
-
const callee = expression.callee;
|
|
2732
|
-
const name = t.isIdentifier(callee) ? callee.name : t.isMemberExpression(callee) && t.isIdentifier(callee.property) ? callee.property.name : "?";
|
|
2733
|
-
reason = `function call \`${name}()\` result is unknown at build time`;
|
|
2734
|
-
suggestion = "If it returns static variants \u2192 convert to szv(). If it depends on runtime data \u2192 use dynamic().";
|
|
2735
|
-
} else if (t.isIdentifier(expression)) {
|
|
2736
|
-
reason = `identifier \`${expression.name}\` could not be resolved to a static value`;
|
|
2737
|
-
suggestion = "Make sure it's a module-level or function-body const with a literal object value. For variant-based styling \u2192 szv(). For true runtime values \u2192 dynamic().";
|
|
2738
|
-
} else if (t.isMemberExpression(expression)) {
|
|
2739
|
-
reason = "member expression is not statically resolvable";
|
|
2740
|
-
suggestion = "Extract the value to a module-level const. For variant-based styling \u2192 szv(). For true runtime values \u2192 dynamic().";
|
|
2741
|
-
} else {
|
|
2742
|
-
reason = `expression of type \`${expression.type}\` is not statically analyzable`;
|
|
2743
|
-
suggestion = "Use a literal sz object or a module-level const. For variant-based styling \u2192 szv(). For true runtime values \u2192 dynamic().";
|
|
2744
|
-
}
|
|
2745
|
-
diagnostics.push(`sz fallback at ${lineCol}: ${reason}.
|
|
2746
|
-
Suggestion: ${suggestion}`);
|
|
2747
|
-
path.node.name.name = "className";
|
|
2748
|
-
const szCall = t.callExpression(
|
|
2749
|
-
t.identifier("_sz"),
|
|
2750
|
-
[expression]
|
|
2751
|
-
);
|
|
2752
|
-
path.node.value = createMergedClassNameValue(szCall);
|
|
2753
|
-
usesRuntime = true;
|
|
2754
|
-
transformed = true;
|
|
2755
|
-
}
|
|
2756
|
-
},
|
|
2757
|
-
// ── szv catalog extraction ────────────────────────────────────────
|
|
2758
|
-
// When the compiler sees `const X = szv({...})` with a static config,
|
|
2759
|
-
// it emits a no-op catalog array so Tailwind JIT can scan all variant
|
|
2760
|
-
// class strings — even when szv is called at runtime with dynamic args.
|
|
2761
|
-
VariableDeclarator(path) {
|
|
2762
|
-
const init2 = path.node.init;
|
|
2763
|
-
if (!t.isCallExpression(init2)) {
|
|
2764
|
-
return;
|
|
2765
|
-
}
|
|
2766
|
-
if (!t.isIdentifier(init2.callee) || init2.callee.name !== "szv") {
|
|
2767
|
-
return;
|
|
2768
|
-
}
|
|
2769
|
-
if (init2.arguments.length === 0) {
|
|
2770
|
-
return;
|
|
2771
|
-
}
|
|
2772
|
-
if (!t.isIdentifier(path.node.id)) {
|
|
2773
|
-
return;
|
|
2774
|
-
}
|
|
2775
|
-
const configArg = init2.arguments[0];
|
|
2776
|
-
if (!t.isObjectExpression(configArg)) {
|
|
2777
|
-
return;
|
|
2778
|
-
}
|
|
2779
|
-
const config = evaluateStaticObject(configArg);
|
|
2780
|
-
if (!config) {
|
|
2781
|
-
return;
|
|
2782
|
-
}
|
|
2783
|
-
const base = config.base ?? {};
|
|
2784
|
-
const variants = config.variants ?? {};
|
|
2785
|
-
const classStrings = [];
|
|
2786
|
-
const baseResult = transform(base);
|
|
2787
|
-
const baseCls = typeof baseResult === "string" ? baseResult : baseResult.className;
|
|
2788
|
-
if (baseCls) {
|
|
2789
|
-
classStrings.push(baseCls);
|
|
2790
|
-
}
|
|
2791
|
-
for (const variantValues of Object.values(variants)) {
|
|
2792
|
-
for (const variantObj of Object.values(variantValues)) {
|
|
2793
|
-
if (!variantObj || typeof variantObj !== "object") {
|
|
2794
|
-
continue;
|
|
2795
|
-
}
|
|
2796
|
-
const merged = { ...base, ...variantObj };
|
|
2797
|
-
const result2 = transform(merged);
|
|
2798
|
-
const cls = typeof result2 === "string" ? result2 : result2.className;
|
|
2799
|
-
if (cls) {
|
|
2800
|
-
classStrings.push(cls);
|
|
2801
|
-
}
|
|
2802
|
-
}
|
|
2803
|
-
}
|
|
2804
|
-
if (classStrings.length === 0) {
|
|
2805
|
-
return;
|
|
2806
|
-
}
|
|
2807
|
-
for (const combined of classStrings) {
|
|
2808
|
-
for (const c of combined.split(/\s+/)) {
|
|
2809
|
-
if (c) {
|
|
2810
|
-
collectedClasses.add(c);
|
|
2811
|
-
}
|
|
2812
|
-
}
|
|
2813
|
-
}
|
|
2814
|
-
const catalogDecl = t.variableDeclaration("const", [
|
|
2815
|
-
t.variableDeclarator(
|
|
2816
|
-
t.identifier(`_szv_catalog_${path.node.id.name}`),
|
|
2817
|
-
t.arrayExpression(classStrings.map((s) => t.stringLiteral(s)))
|
|
2818
|
-
)
|
|
2819
|
-
]);
|
|
2820
|
-
const parentPath = path.parentPath;
|
|
2821
|
-
if (parentPath && t.isVariableDeclaration(parentPath.node)) {
|
|
2822
|
-
parentPath.insertAfter(catalogDecl);
|
|
2823
|
-
transformed = true;
|
|
2824
|
-
}
|
|
2825
|
-
},
|
|
2826
|
-
// ── dynamic() literal extraction ──────────────────────────────────
|
|
2827
|
-
// Detects `dynamic({...})` and `dynamic(CONST_IDENTIFIER)` calls
|
|
2828
|
-
// with statically-analyzable arguments and adds the resulting
|
|
2829
|
-
// class tokens to collectedClasses so prescanAndWriteClasses()
|
|
2830
|
-
// includes them in csszyx-classes.html for Tailwind to scan.
|
|
2831
|
-
// This means dynamic() with static/const args works in Astro SSR
|
|
2832
|
-
// without needing client:* directives.
|
|
2833
|
-
CallExpression(path) {
|
|
2834
|
-
const callee = path.node.callee;
|
|
2835
|
-
if (!t.isIdentifier(callee) || callee.name !== "dynamic") {
|
|
2836
|
-
return;
|
|
2837
|
-
}
|
|
2838
|
-
if (path.node.arguments.length === 0) {
|
|
2839
|
-
return;
|
|
2840
|
-
}
|
|
2841
|
-
const arg = path.node.arguments[0];
|
|
2842
|
-
if (t.isObjectExpression(arg)) {
|
|
2843
|
-
const staticObj = evaluateStaticObject(arg);
|
|
2844
|
-
if (!staticObj) {
|
|
2845
|
-
return;
|
|
2846
|
-
}
|
|
2847
|
-
const { className } = transform(staticObj);
|
|
2848
|
-
for (const c of className.split(/\s+/)) {
|
|
2849
|
-
if (c) {
|
|
2850
|
-
collectedClasses.add(c);
|
|
2851
|
-
}
|
|
2852
|
-
}
|
|
2853
|
-
return;
|
|
2854
|
-
}
|
|
2855
|
-
let argExpr = arg;
|
|
2856
|
-
while (t.isTSAsExpression(argExpr) || t.isTSSatisfiesExpression(argExpr)) {
|
|
2857
|
-
argExpr = argExpr.expression;
|
|
2858
|
-
}
|
|
2859
|
-
if (t.isIdentifier(argExpr)) {
|
|
2860
|
-
const binding = path.scope.getBinding(argExpr.name);
|
|
2861
|
-
if (!binding) {
|
|
2862
|
-
return;
|
|
2863
|
-
}
|
|
2864
|
-
const declarator = binding.path.node;
|
|
2865
|
-
if (!t.isVariableDeclarator(declarator) || !declarator.init) {
|
|
2866
|
-
return;
|
|
2867
|
-
}
|
|
2868
|
-
let initExpr = declarator.init;
|
|
2869
|
-
while (t.isTSAsExpression(initExpr) || t.isTSSatisfiesExpression(initExpr)) {
|
|
2870
|
-
initExpr = initExpr.expression;
|
|
2871
|
-
}
|
|
2872
|
-
if (!t.isObjectExpression(initExpr)) {
|
|
2873
|
-
return;
|
|
2874
|
-
}
|
|
2875
|
-
const staticObj = evaluateStaticObject(initExpr);
|
|
2876
|
-
if (!staticObj) {
|
|
2877
|
-
return;
|
|
2878
|
-
}
|
|
2879
|
-
const { className } = transform(staticObj);
|
|
2880
|
-
for (const c of className.split(/\s+/)) {
|
|
2881
|
-
if (c) {
|
|
2882
|
-
collectedClasses.add(c);
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
}
|
|
2888
|
-
};
|
|
2889
|
-
}
|
|
2890
|
-
]
|
|
2891
|
-
});
|
|
2892
|
-
return {
|
|
2893
|
-
code: result?.code || source,
|
|
2894
|
-
transformed,
|
|
2895
|
-
usesRuntime,
|
|
2896
|
-
usesMerge,
|
|
2897
|
-
usesColorVar,
|
|
2898
|
-
classes: collectedClasses,
|
|
2899
|
-
rawClassNames,
|
|
2900
|
-
diagnostics,
|
|
2901
|
-
recoveryTokens
|
|
2902
|
-
};
|
|
2903
|
-
} catch (e) {
|
|
2904
|
-
if (e instanceof ASTBudgetExceededError) {
|
|
2905
|
-
throw e;
|
|
2906
|
-
}
|
|
2907
|
-
console.warn("[csszyx] AST transform failed, falling back to original code:", e);
|
|
2908
|
-
return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
|
|
2909
|
-
}
|
|
2910
|
-
}
|
|
2911
|
-
function parseStyleStringToObjectExpr(styleStr) {
|
|
2912
|
-
const props = styleStr.split(";").map((s) => s.trim()).filter(Boolean);
|
|
2913
|
-
const objProps = [];
|
|
2914
|
-
for (const prop of props) {
|
|
2915
|
-
const idx = prop.indexOf(":");
|
|
2916
|
-
if (idx > -1) {
|
|
2917
|
-
const k = prop.slice(0, idx).trim();
|
|
2918
|
-
const v = prop.slice(idx + 1).trim();
|
|
2919
|
-
let keyNode;
|
|
2920
|
-
if (k.startsWith("--")) {
|
|
2921
|
-
keyNode = t.stringLiteral(k);
|
|
2922
|
-
} else {
|
|
2923
|
-
const camel = k.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
|
2924
|
-
keyNode = t.identifier(camel);
|
|
2925
|
-
}
|
|
2926
|
-
objProps.push(t.objectProperty(keyNode, t.stringLiteral(v)));
|
|
2927
|
-
}
|
|
2928
|
-
}
|
|
2929
|
-
return t.objectExpression(objProps);
|
|
2930
|
-
}
|
|
2931
|
-
function tryStaticTransformNode(node, getBinding) {
|
|
2932
|
-
if (t.isTSAsExpression(node) || t.isTSSatisfiesExpression(node)) {
|
|
2933
|
-
return tryStaticTransformNode(node.expression, getBinding);
|
|
2934
|
-
}
|
|
2935
|
-
if (t.isObjectExpression(node)) {
|
|
2936
|
-
const resolved = getBinding ? resolveObjectSpreads(node, getBinding) ?? node : node;
|
|
2937
|
-
const staticObj = evaluateStaticObject(resolved);
|
|
2938
|
-
if (staticObj !== null) {
|
|
2939
|
-
const { className } = transform(staticObj);
|
|
2940
|
-
return t.stringLiteral(className);
|
|
2941
|
-
}
|
|
2942
|
-
if (getBinding) {
|
|
2943
|
-
const hoisted = tryHoistConditionalSpread(node, getBinding);
|
|
2944
|
-
if (hoisted !== null) {
|
|
2945
|
-
return hoisted;
|
|
2946
|
-
}
|
|
2947
|
-
}
|
|
2948
|
-
return null;
|
|
2949
|
-
}
|
|
2950
|
-
if (t.isStringLiteral(node)) {
|
|
2951
|
-
return node;
|
|
2952
|
-
}
|
|
2953
|
-
if (t.isIdentifier(node) && getBinding) {
|
|
2954
|
-
const binding = getBinding(node.name);
|
|
2955
|
-
if (binding && binding.path.isVariableDeclarator()) {
|
|
2956
|
-
const init2 = binding.path.node.init;
|
|
2957
|
-
if (init2) {
|
|
2958
|
-
return tryStaticTransformNode(init2, getBinding);
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2961
|
-
return null;
|
|
2962
|
-
}
|
|
2963
|
-
if (t.isConditionalExpression(node)) {
|
|
2964
|
-
const consequent = tryStaticTransformNode(node.consequent, getBinding);
|
|
2965
|
-
const alternate = tryStaticTransformNode(node.alternate, getBinding);
|
|
2966
|
-
if (consequent !== null && alternate !== null) {
|
|
2967
|
-
return t.conditionalExpression(node.test, consequent, alternate);
|
|
2968
|
-
}
|
|
2969
|
-
return null;
|
|
2970
|
-
}
|
|
2971
|
-
return null;
|
|
2972
|
-
}
|
|
2973
|
-
function tryHoistConditionalSpread(node, getBinding) {
|
|
2974
|
-
let conditionalSpreadIdx = -1;
|
|
2975
|
-
let conditionalExpr = null;
|
|
2976
|
-
for (let i = 0; i < node.properties.length; i++) {
|
|
2977
|
-
const prop = node.properties[i];
|
|
2978
|
-
if (!t.isSpreadElement(prop)) {
|
|
2979
|
-
continue;
|
|
2980
|
-
}
|
|
2981
|
-
if (t.isConditionalExpression(prop.argument)) {
|
|
2982
|
-
if (conditionalSpreadIdx !== -1) {
|
|
2983
|
-
return null;
|
|
2984
|
-
}
|
|
2985
|
-
conditionalSpreadIdx = i;
|
|
2986
|
-
conditionalExpr = prop.argument;
|
|
2987
|
-
} else {
|
|
2988
|
-
return null;
|
|
2989
|
-
}
|
|
2990
|
-
}
|
|
2991
|
-
if (conditionalSpreadIdx === -1 || conditionalExpr === null) {
|
|
2992
|
-
return null;
|
|
2993
|
-
}
|
|
2994
|
-
const otherProps = node.properties.filter((_, i) => i !== conditionalSpreadIdx);
|
|
2995
|
-
const mkObj = (branch) => t.objectExpression([t.spreadElement(branch), ...otherProps]);
|
|
2996
|
-
const resolvedA = tryStaticTransformNode(mkObj(conditionalExpr.consequent), getBinding);
|
|
2997
|
-
const resolvedB = tryStaticTransformNode(mkObj(conditionalExpr.alternate), getBinding);
|
|
2998
|
-
if (!resolvedA || !resolvedB) {
|
|
2999
|
-
return null;
|
|
3000
|
-
}
|
|
3001
|
-
if (!t.isStringLiteral(resolvedA) || !t.isStringLiteral(resolvedB)) {
|
|
3002
|
-
return null;
|
|
3003
|
-
}
|
|
3004
|
-
return t.conditionalExpression(conditionalExpr.test, resolvedA, resolvedB);
|
|
3005
|
-
}
|
|
3006
|
-
function evaluateStaticObject(node) {
|
|
3007
|
-
const result = {};
|
|
3008
|
-
for (const prop of node.properties) {
|
|
3009
|
-
if (!t.isObjectProperty(prop)) {
|
|
3010
|
-
return null;
|
|
3011
|
-
}
|
|
3012
|
-
if (prop.computed) {
|
|
3013
|
-
return null;
|
|
3014
|
-
}
|
|
3015
|
-
let key;
|
|
3016
|
-
if (t.isIdentifier(prop.key)) {
|
|
3017
|
-
key = prop.key.name;
|
|
3018
|
-
} else if (t.isStringLiteral(prop.key)) {
|
|
3019
|
-
key = prop.key.value;
|
|
3020
|
-
} else if (t.isNumericLiteral(prop.key)) {
|
|
3021
|
-
key = String(prop.key.value);
|
|
3022
|
-
} else {
|
|
3023
|
-
return null;
|
|
3024
|
-
}
|
|
3025
|
-
const value = prop.value;
|
|
3026
|
-
if (t.isStringLiteral(value)) {
|
|
3027
|
-
result[key] = value.value;
|
|
3028
|
-
} else if (t.isNumericLiteral(value)) {
|
|
3029
|
-
result[key] = value.value;
|
|
3030
|
-
} else if (t.isBooleanLiteral(value)) {
|
|
3031
|
-
result[key] = value.value;
|
|
3032
|
-
} else if (t.isUnaryExpression(value) && value.operator === "-" && t.isNumericLiteral(value.argument)) {
|
|
3033
|
-
result[key] = -value.argument.value;
|
|
3034
|
-
} else if (t.isObjectExpression(value)) {
|
|
3035
|
-
const nested = evaluateStaticObject(value);
|
|
3036
|
-
if (nested === null) {
|
|
3037
|
-
return null;
|
|
3038
|
-
}
|
|
3039
|
-
result[key] = nested;
|
|
3040
|
-
} else {
|
|
3041
|
-
return null;
|
|
3042
|
-
}
|
|
3043
|
-
}
|
|
3044
|
-
return result;
|
|
3045
|
-
}
|
|
3046
|
-
function resolveObjectSpreads(node, getBinding) {
|
|
3047
|
-
const newProps = [];
|
|
3048
|
-
for (const prop of node.properties) {
|
|
3049
|
-
if (!t.isSpreadElement(prop)) {
|
|
3050
|
-
if (t.isObjectProperty(prop) && t.isObjectExpression(prop.value)) {
|
|
3051
|
-
const resolvedValue = resolveObjectSpreads(prop.value, getBinding);
|
|
3052
|
-
if (resolvedValue === null) {
|
|
3053
|
-
return null;
|
|
3054
|
-
}
|
|
3055
|
-
newProps.push(t.objectProperty(prop.key, resolvedValue, prop.computed, prop.shorthand));
|
|
3056
|
-
} else {
|
|
3057
|
-
newProps.push(prop);
|
|
3058
|
-
}
|
|
3059
|
-
continue;
|
|
3060
|
-
}
|
|
3061
|
-
const arg = prop.argument;
|
|
3062
|
-
if (!t.isIdentifier(arg)) {
|
|
3063
|
-
return null;
|
|
3064
|
-
}
|
|
3065
|
-
const binding = getBinding(arg.name);
|
|
3066
|
-
if (!binding || !binding.path.isVariableDeclarator()) {
|
|
3067
|
-
return null;
|
|
3068
|
-
}
|
|
3069
|
-
let init2 = binding.path.node.init;
|
|
3070
|
-
if (t.isTSAsExpression(init2) || t.isTSSatisfiesExpression(init2)) {
|
|
3071
|
-
init2 = init2.expression;
|
|
3072
|
-
}
|
|
3073
|
-
if (!t.isObjectExpression(init2)) {
|
|
3074
|
-
return null;
|
|
3075
|
-
}
|
|
3076
|
-
const inner = resolveObjectSpreads(init2, getBinding);
|
|
3077
|
-
if (inner === null) {
|
|
3078
|
-
return null;
|
|
3079
|
-
}
|
|
3080
|
-
newProps.push(...inner.properties);
|
|
3081
|
-
}
|
|
3082
|
-
return t.objectExpression(newProps);
|
|
3083
|
-
}
|
|
3084
|
-
function extractStaticLiteralValue(node) {
|
|
3085
|
-
if (t.isStringLiteral(node)) {
|
|
3086
|
-
return node.value;
|
|
3087
|
-
}
|
|
3088
|
-
if (t.isNumericLiteral(node)) {
|
|
3089
|
-
return node.value;
|
|
3090
|
-
}
|
|
3091
|
-
if (t.isBooleanLiteral(node)) {
|
|
3092
|
-
return node.value;
|
|
3093
|
-
}
|
|
3094
|
-
if (t.isUnaryExpression(node) && node.operator === "-" && t.isNumericLiteral(node.argument)) {
|
|
3095
|
-
return -node.argument.value;
|
|
3096
|
-
}
|
|
3097
|
-
return null;
|
|
3098
|
-
}
|
|
3099
|
-
function buildConditionalClassExpr(baseClasses, conditionalClasses) {
|
|
3100
|
-
if (conditionalClasses.length === 0) {
|
|
3101
|
-
return t.stringLiteral(baseClasses);
|
|
3102
|
-
}
|
|
3103
|
-
const makeCondExpr = (cc) => t.conditionalExpression(cc.test, t.stringLiteral(cc.consequent), t.stringLiteral(cc.alternate));
|
|
3104
|
-
if (conditionalClasses.length === 1 && !baseClasses) {
|
|
3105
|
-
return makeCondExpr(conditionalClasses[0]);
|
|
3106
|
-
}
|
|
3107
|
-
const quasis = [];
|
|
3108
|
-
const exprs = [];
|
|
3109
|
-
for (let i = 0; i < conditionalClasses.length; i++) {
|
|
3110
|
-
const prefix = i === 0 ? baseClasses ? baseClasses + " " : "" : " ";
|
|
3111
|
-
quasis.push(t.templateElement({ raw: prefix, cooked: prefix }, false));
|
|
3112
|
-
exprs.push(makeCondExpr(conditionalClasses[i]));
|
|
3113
|
-
}
|
|
3114
|
-
quasis.push(t.templateElement({ raw: "", cooked: "" }, true));
|
|
3115
|
-
return t.templateLiteral(quasis, exprs);
|
|
3116
|
-
}
|
|
3117
|
-
function evaluatePartialObject(node, variantChain = "") {
|
|
3118
|
-
const staticProps = {};
|
|
3119
|
-
const dynamicProps = /* @__PURE__ */ new Map();
|
|
3120
|
-
const rawClasses = [];
|
|
3121
|
-
const conditionalClasses = [];
|
|
3122
|
-
let usesColorVar = false;
|
|
3123
|
-
for (const prop of node.properties) {
|
|
3124
|
-
if (t.isSpreadElement(prop)) {
|
|
3125
|
-
return null;
|
|
3126
|
-
}
|
|
3127
|
-
if (!t.isObjectProperty(prop)) {
|
|
3128
|
-
return null;
|
|
3129
|
-
}
|
|
3130
|
-
if (prop.computed) {
|
|
3131
|
-
return null;
|
|
3132
|
-
}
|
|
3133
|
-
let key;
|
|
3134
|
-
if (t.isIdentifier(prop.key)) {
|
|
3135
|
-
key = prop.key.name;
|
|
3136
|
-
} else if (t.isStringLiteral(prop.key)) {
|
|
3137
|
-
key = prop.key.value;
|
|
3138
|
-
} else if (t.isNumericLiteral(prop.key)) {
|
|
3139
|
-
key = String(prop.key.value);
|
|
3140
|
-
} else {
|
|
3141
|
-
return null;
|
|
3142
|
-
}
|
|
3143
|
-
const value = prop.value;
|
|
3144
|
-
if (t.isStringLiteral(value)) {
|
|
3145
|
-
staticProps[key] = value.value;
|
|
3146
|
-
} else if (t.isNumericLiteral(value)) {
|
|
3147
|
-
staticProps[key] = value.value;
|
|
3148
|
-
} else if (t.isBooleanLiteral(value)) {
|
|
3149
|
-
staticProps[key] = value.value;
|
|
3150
|
-
} else if (t.isUnaryExpression(value) && value.operator === "-" && t.isNumericLiteral(value.argument)) {
|
|
3151
|
-
staticProps[key] = -value.argument.value;
|
|
3152
|
-
} else if (t.isObjectExpression(value)) {
|
|
3153
|
-
const nested = evaluateStaticObject(value);
|
|
3154
|
-
if (nested !== null) {
|
|
3155
|
-
staticProps[key] = nested;
|
|
3156
|
-
} else {
|
|
3157
|
-
const colorObjProps = /* @__PURE__ */ new Map();
|
|
3158
|
-
for (const p of value.properties) {
|
|
3159
|
-
if (t.isObjectProperty(p) && !p.computed && t.isIdentifier(p.key)) {
|
|
3160
|
-
colorObjProps.set(p.key.name, p);
|
|
3161
|
-
}
|
|
3162
|
-
}
|
|
3163
|
-
if (colorObjProps.has("color") && COLOR_PROPERTIES.has(key)) {
|
|
3164
|
-
const colorProp = colorObjProps.get("color");
|
|
3165
|
-
if (!colorProp) {
|
|
3166
|
-
continue;
|
|
3167
|
-
}
|
|
3168
|
-
const opProp = colorObjProps.get("op");
|
|
3169
|
-
const twPrefix = PROPERTY_MAP[key] || key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
3170
|
-
let colorStr = null;
|
|
3171
|
-
if (t.isStringLiteral(colorProp.value)) {
|
|
3172
|
-
colorStr = colorProp.value.value;
|
|
3173
|
-
}
|
|
3174
|
-
if (colorStr && opProp) {
|
|
3175
|
-
const opVarName = getCSSVariableName(`${key}-op`, variantChain || void 0);
|
|
3176
|
-
const uniqueKey = variantChain ? `${variantChain}-${key}-op` : `${key}-op`;
|
|
3177
|
-
if (t.isStringLiteral(opProp.value) || t.isNumericLiteral(opProp.value)) {
|
|
3178
|
-
const opVal = t.isStringLiteral(opProp.value) ? opProp.value.value : opProp.value.value;
|
|
3179
|
-
staticProps[key] = { color: colorStr, op: opVal };
|
|
3180
|
-
} else if (t.isExpression(opProp.value)) {
|
|
3181
|
-
const variantPfx = variantChain ? `${variantChain}:` : "";
|
|
3182
|
-
rawClasses.push(`${variantPfx}${twPrefix}-${colorStr}/(${opVarName})`);
|
|
3183
|
-
dynamicProps.set(uniqueKey, {
|
|
3184
|
-
expression: opProp.value,
|
|
3185
|
-
category: 3 /* UNITLESS */,
|
|
3186
|
-
varName: opVarName,
|
|
3187
|
-
twPrefix: `${twPrefix}-op`,
|
|
3188
|
-
variantChain: variantChain || "",
|
|
3189
|
-
skipClass: true
|
|
3190
|
-
});
|
|
3191
|
-
}
|
|
3192
|
-
} else if (!colorStr && opProp) {
|
|
3193
|
-
const varName = getCSSVariableName(key, variantChain || void 0);
|
|
3194
|
-
const uniqueKey = variantChain ? `${variantChain}-${key}` : key;
|
|
3195
|
-
usesColorVar = true;
|
|
3196
|
-
dynamicProps.set(uniqueKey, {
|
|
3197
|
-
expression: t.isExpression(colorProp.value) ? colorProp.value : t.stringLiteral(""),
|
|
3198
|
-
category: 1 /* COLOR */,
|
|
3199
|
-
varName,
|
|
3200
|
-
twPrefix,
|
|
3201
|
-
variantChain: variantChain || ""
|
|
3202
|
-
});
|
|
3203
|
-
} else if (colorStr && !opProp) {
|
|
3204
|
-
staticProps[key] = colorStr;
|
|
3205
|
-
}
|
|
3206
|
-
} else {
|
|
3207
|
-
const isVariant = KNOWN_VARIANTS.has(key) || KNOWN_VARIANTS.has(getVariantPrefix(key));
|
|
3208
|
-
if (isVariant) {
|
|
3209
|
-
const variantKey = variantChain ? `${variantChain}-${key}` : key;
|
|
3210
|
-
const nestedResult = evaluatePartialObject(value, variantKey);
|
|
3211
|
-
if (nestedResult === null) {
|
|
3212
|
-
return null;
|
|
3213
|
-
}
|
|
3214
|
-
if (Object.keys(nestedResult.staticProps).length > 0) {
|
|
3215
|
-
staticProps[key] = nestedResult.staticProps;
|
|
3216
|
-
}
|
|
3217
|
-
for (const [k, v] of nestedResult.dynamicProps) {
|
|
3218
|
-
dynamicProps.set(k, v);
|
|
3219
|
-
}
|
|
3220
|
-
rawClasses.push(...nestedResult.rawClasses);
|
|
3221
|
-
conditionalClasses.push(...nestedResult.conditionalClasses);
|
|
3222
|
-
if (nestedResult.usesColorVar) {
|
|
3223
|
-
usesColorVar = true;
|
|
3224
|
-
}
|
|
3225
|
-
} else {
|
|
3226
|
-
return null;
|
|
3227
|
-
}
|
|
3228
|
-
}
|
|
3229
|
-
}
|
|
3230
|
-
} else if (t.isConditionalExpression(value)) {
|
|
3231
|
-
const consVal = extractStaticLiteralValue(value.consequent);
|
|
3232
|
-
const altVal = extractStaticLiteralValue(value.alternate);
|
|
3233
|
-
if (consVal !== null && altVal !== null) {
|
|
3234
|
-
const { className: classA } = transform({ [key]: consVal });
|
|
3235
|
-
const { className: classB } = transform({ [key]: altVal });
|
|
3236
|
-
const vPfx = variantChain ? getVariantPrefix(variantChain) + ":" : "";
|
|
3237
|
-
const prefixed = (cls) => vPfx ? cls.split(/\s+/).filter(Boolean).map((c) => vPfx + c).join(" ") : cls;
|
|
3238
|
-
conditionalClasses.push({ test: value.test, consequent: prefixed(classA), alternate: prefixed(classB) });
|
|
3239
|
-
} else {
|
|
3240
|
-
const twPrefix = PROPERTY_MAP[key] || key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
3241
|
-
const category = getPropertyCategory(key);
|
|
3242
|
-
const varName = getCSSVariableName(key, variantChain || void 0);
|
|
3243
|
-
const uniqueKey = variantChain ? `${variantChain}-${key}` : key;
|
|
3244
|
-
if (COLOR_PROPERTIES.has(key)) {
|
|
3245
|
-
usesColorVar = true;
|
|
3246
|
-
}
|
|
3247
|
-
dynamicProps.set(uniqueKey, { expression: value, category, varName, twPrefix, variantChain: variantChain || "" });
|
|
3248
|
-
}
|
|
3249
|
-
} else if (t.isExpression(value)) {
|
|
3250
|
-
const twPrefix = PROPERTY_MAP[key] || key.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
3251
|
-
const category = getPropertyCategory(key);
|
|
3252
|
-
const varName = getCSSVariableName(key, variantChain || void 0);
|
|
3253
|
-
const uniqueKey = variantChain ? `${variantChain}-${key}` : key;
|
|
3254
|
-
if (COLOR_PROPERTIES.has(key)) {
|
|
3255
|
-
usesColorVar = true;
|
|
3256
|
-
}
|
|
3257
|
-
dynamicProps.set(uniqueKey, {
|
|
3258
|
-
expression: value,
|
|
3259
|
-
category,
|
|
3260
|
-
varName,
|
|
3261
|
-
twPrefix,
|
|
3262
|
-
variantChain: variantChain || ""
|
|
3263
|
-
});
|
|
3264
|
-
} else {
|
|
3265
|
-
return null;
|
|
3266
|
-
}
|
|
3267
|
-
}
|
|
3268
|
-
return { staticProps, dynamicProps, rawClasses, conditionalClasses, hasSpread: false, usesColorVar };
|
|
3269
|
-
}
|
|
3270
|
-
function generateStyleValueExpression(info) {
|
|
3271
|
-
const { expression, category } = info;
|
|
3272
|
-
switch (category) {
|
|
3273
|
-
case 0 /* SPACING */:
|
|
3274
|
-
return t.templateLiteral(
|
|
3275
|
-
[
|
|
3276
|
-
t.templateElement({ raw: "calc(", cooked: "calc(" }, false),
|
|
3277
|
-
t.templateElement({ raw: " * var(--spacing))", cooked: " * var(--spacing))" }, true)
|
|
3278
|
-
],
|
|
3279
|
-
[expression]
|
|
3280
|
-
);
|
|
3281
|
-
case 1 /* COLOR */:
|
|
3282
|
-
return t.callExpression(
|
|
3283
|
-
t.identifier("__szColorVar"),
|
|
3284
|
-
[expression]
|
|
3285
|
-
);
|
|
3286
|
-
case 4 /* ANGLE */:
|
|
3287
|
-
return t.templateLiteral(
|
|
3288
|
-
[
|
|
3289
|
-
t.templateElement({ raw: "", cooked: "" }, false),
|
|
3290
|
-
t.templateElement({ raw: "deg", cooked: "deg" }, true)
|
|
3291
|
-
],
|
|
3292
|
-
[expression]
|
|
3293
|
-
);
|
|
3294
|
-
case 5 /* DURATION */:
|
|
3295
|
-
return t.templateLiteral(
|
|
3296
|
-
[
|
|
3297
|
-
t.templateElement({ raw: "", cooked: "" }, false),
|
|
3298
|
-
t.templateElement({ raw: "ms", cooked: "ms" }, true)
|
|
3299
|
-
],
|
|
3300
|
-
[expression]
|
|
3301
|
-
);
|
|
3302
|
-
case 3 /* UNITLESS */:
|
|
3303
|
-
case 7 /* PASSTHROUGH */:
|
|
3304
|
-
case 2 /* FRACTION */:
|
|
3305
|
-
case 6 /* ARBITRARY */:
|
|
3306
|
-
default:
|
|
3307
|
-
return t.templateLiteral(
|
|
3308
|
-
[
|
|
3309
|
-
t.templateElement({ raw: "", cooked: "" }, false),
|
|
3310
|
-
t.templateElement({ raw: "", cooked: "" }, true)
|
|
3311
|
-
],
|
|
3312
|
-
[expression]
|
|
3313
|
-
);
|
|
3314
|
-
}
|
|
3315
|
-
}
|
|
3316
|
-
function collectFromExpr(node, classes) {
|
|
3317
|
-
if (t.isStringLiteral(node)) {
|
|
3318
|
-
for (const c of node.value.split(/\s+/)) {
|
|
3319
|
-
if (c) {
|
|
3320
|
-
classes.add(c);
|
|
3321
|
-
}
|
|
3322
|
-
}
|
|
3323
|
-
} else if (t.isConditionalExpression(node)) {
|
|
3324
|
-
collectFromExpr(node.consequent, classes);
|
|
3325
|
-
collectFromExpr(node.alternate, classes);
|
|
3326
|
-
}
|
|
3327
|
-
}
|
|
3328
|
-
function buildCSSVarClassName(info) {
|
|
3329
|
-
const { twPrefix, varName, variantChain } = info;
|
|
3330
|
-
const variantPrefix = variantChain ? `${getVariantPrefix(variantChain)}:` : "";
|
|
3331
|
-
return `${variantPrefix}${twPrefix}-(${varName})`;
|
|
3332
|
-
}
|
|
3333
|
-
|
|
3334
|
-
// src/compiler.ts
|
|
3335
|
-
var CsszyxCompiler = class _CsszyxCompiler {
|
|
3336
|
-
/**
|
|
3337
|
-
* Private constructor to enforce singleton pattern.
|
|
3338
|
-
*/
|
|
3339
|
-
constructor() {
|
|
3340
|
-
this.wasmLoaded = false;
|
|
3341
|
-
}
|
|
3342
|
-
/**
|
|
3343
|
-
* Gets the singleton instance of the compiler.
|
|
3344
|
-
*
|
|
3345
|
-
* @returns {CsszyxCompiler} The compiler instance.
|
|
3346
|
-
*/
|
|
3347
|
-
static getInstance() {
|
|
3348
|
-
if (!_CsszyxCompiler.instance) {
|
|
3349
|
-
_CsszyxCompiler.instance = new _CsszyxCompiler();
|
|
3350
|
-
}
|
|
3351
|
-
return _CsszyxCompiler.instance;
|
|
3352
|
-
}
|
|
3353
|
-
/**
|
|
3354
|
-
* Initializes the WASM core.
|
|
3355
|
-
*
|
|
3356
|
-
* @returns {Promise<void>} Resolves when WASM is ready.
|
|
3357
|
-
*/
|
|
3358
|
-
async init() {
|
|
3359
|
-
if (this.wasmLoaded) {
|
|
3360
|
-
return;
|
|
3361
|
-
}
|
|
3362
|
-
try {
|
|
3363
|
-
init();
|
|
3364
|
-
this.wasmLoaded = true;
|
|
3365
|
-
console.info(`[csszyx] WASM Core initialized (v${getWasmVersion()})`);
|
|
3366
|
-
} catch (error) {
|
|
3367
|
-
console.warn(
|
|
3368
|
-
"[csszyx] Failed to initialize WASM core, falling back to JavaScript transformer",
|
|
3369
|
-
error
|
|
3370
|
-
);
|
|
3371
|
-
this.wasmLoaded = false;
|
|
3372
|
-
}
|
|
3373
|
-
}
|
|
3374
|
-
/**
|
|
3375
|
-
* Transforms an sz object into Tailwind classes.
|
|
3376
|
-
*
|
|
3377
|
-
* @param {SzObject} sz - The object to transform.
|
|
3378
|
-
* @returns {string} The transformed class string.
|
|
3379
|
-
*/
|
|
3380
|
-
transform(sz) {
|
|
3381
|
-
if (this.wasmLoaded) {
|
|
3382
|
-
const cleaned = stripInvalidColorStrings(sz);
|
|
3383
|
-
try {
|
|
3384
|
-
return transform_sz(cleaned);
|
|
3385
|
-
} catch (error) {
|
|
3386
|
-
console.warn(
|
|
3387
|
-
"[csszyx] WASM transformation failed, using JS fallback",
|
|
3388
|
-
error
|
|
3389
|
-
);
|
|
3390
|
-
return transform(sz).className;
|
|
3391
|
-
}
|
|
3392
|
-
}
|
|
3393
|
-
return transform(sz).className;
|
|
3394
|
-
}
|
|
3395
|
-
/**
|
|
3396
|
-
* Checks if the WASM core is currently active.
|
|
3397
|
-
*
|
|
3398
|
-
* @returns {boolean} True if WASM is loaded.
|
|
3399
|
-
*/
|
|
3400
|
-
isWasmActive() {
|
|
3401
|
-
return this.wasmLoaded;
|
|
3402
|
-
}
|
|
3403
|
-
/**
|
|
3404
|
-
* Generates a recovery token using WASM or JS fallback.
|
|
3405
|
-
*
|
|
3406
|
-
* @param {object} metadata - Token metadata
|
|
3407
|
-
* @param metadata.component - Component name
|
|
3408
|
-
* @param metadata.filePath - File path source
|
|
3409
|
-
* @param metadata.line - Line number
|
|
3410
|
-
* @param metadata.column - Column number
|
|
3411
|
-
* @param metadata.mode - Build mode (dev/prod)
|
|
3412
|
-
* @param metadata.buildId - Unique build identifier
|
|
3413
|
-
* @returns {string} The generated token
|
|
3414
|
-
*/
|
|
3415
|
-
generateRecoveryToken(metadata) {
|
|
3416
|
-
if (this.wasmLoaded) {
|
|
3417
|
-
try {
|
|
3418
|
-
const { generate_token } = __require("@csszyx/core");
|
|
3419
|
-
return generate_token(
|
|
3420
|
-
metadata.component,
|
|
3421
|
-
metadata.filePath,
|
|
3422
|
-
metadata.line,
|
|
3423
|
-
metadata.column,
|
|
3424
|
-
metadata.mode,
|
|
3425
|
-
metadata.buildId
|
|
3426
|
-
);
|
|
3427
|
-
} catch (error) {
|
|
3428
|
-
console.warn("[csszyx] WASM token generation failed", error);
|
|
3429
|
-
}
|
|
3430
|
-
}
|
|
3431
|
-
const str = `${metadata.component}:${metadata.filePath}:${metadata.line}:${metadata.column}:${metadata.mode}:${metadata.buildId}`;
|
|
3432
|
-
let hash = 0;
|
|
3433
|
-
for (let i = 0; i < str.length; i++) {
|
|
3434
|
-
hash = (hash << 5) - hash + str.charCodeAt(i) | 0;
|
|
3435
|
-
}
|
|
3436
|
-
return Math.abs(hash).toString(16).padStart(12, "0").slice(0, 12);
|
|
3437
|
-
}
|
|
3438
|
-
};
|
|
3439
|
-
|
|
3440
|
-
// src/recovery.ts
|
|
3441
|
-
function isValidRecoveryMode(value) {
|
|
3442
|
-
return value === "csr" || value === "dev-only";
|
|
3443
|
-
}
|
|
3444
|
-
function generateRecoveryToken(metadata) {
|
|
3445
|
-
return CsszyxCompiler.getInstance().generateRecoveryToken(metadata);
|
|
3446
|
-
}
|
|
3447
|
-
function createRecoveryToken(metadata, buildId) {
|
|
3448
|
-
const fullMetadata = {
|
|
3449
|
-
...metadata,
|
|
3450
|
-
buildId
|
|
3451
|
-
};
|
|
3452
|
-
const token = generateRecoveryToken(fullMetadata);
|
|
3453
|
-
return {
|
|
3454
|
-
token,
|
|
3455
|
-
metadata: fullMetadata
|
|
3456
|
-
};
|
|
3457
|
-
}
|
|
3458
|
-
function validateSzRecover(value, componentName) {
|
|
3459
|
-
if (!isValidRecoveryMode(value)) {
|
|
3460
|
-
return {
|
|
3461
|
-
valid: false,
|
|
3462
|
-
error: `szRecover in ${componentName} must be static literal "csr" or "dev-only", got: ${JSON.stringify(value)}`
|
|
3463
|
-
};
|
|
3464
|
-
}
|
|
3465
|
-
return { valid: true };
|
|
3466
|
-
}
|
|
3467
|
-
function injectRecoveryToken(attributes, token) {
|
|
3468
|
-
return {
|
|
3469
|
-
...attributes,
|
|
3470
|
-
"data-sz-recovery-token": token
|
|
3471
|
-
};
|
|
3472
|
-
}
|
|
3473
|
-
|
|
3474
|
-
// src/manifest.ts
|
|
3475
|
-
import { createHash as createHash2 } from "crypto";
|
|
3476
|
-
var ManifestBuilder = class {
|
|
3477
|
-
/**
|
|
3478
|
-
* Creates a new manifest builder.
|
|
3479
|
-
*
|
|
3480
|
-
* @param {string} buildId - Build ID (git hash or timestamp)
|
|
3481
|
-
*
|
|
3482
|
-
* @example
|
|
3483
|
-
* ```typescript
|
|
3484
|
-
* const builder = new ManifestBuilder('abc123');
|
|
3485
|
-
* ```
|
|
3486
|
-
*/
|
|
3487
|
-
constructor(buildId) {
|
|
3488
|
-
this.tokens = /* @__PURE__ */ new Map();
|
|
3489
|
-
this.buildId = buildId;
|
|
3490
|
-
}
|
|
3491
|
-
/**
|
|
3492
|
-
* Adds a token to the manifest.
|
|
3493
|
-
*
|
|
3494
|
-
* @param {string} token - The recovery token
|
|
3495
|
-
* @param {TokenMetadata} metadata - Token metadata
|
|
3496
|
-
*
|
|
3497
|
-
* @example
|
|
3498
|
-
* ```typescript
|
|
3499
|
-
* builder.addToken('a94f1c2e8b3d', {
|
|
3500
|
-
* mode: 'csr',
|
|
3501
|
-
* component: 'Button',
|
|
3502
|
-
* filePath: '/app/Button.tsx',
|
|
3503
|
-
* line: 10,
|
|
3504
|
-
* column: 5,
|
|
3505
|
-
* buildId: 'abc123'
|
|
3506
|
-
* });
|
|
3507
|
-
* ```
|
|
3508
|
-
*/
|
|
3509
|
-
addToken(token, metadata) {
|
|
3510
|
-
const relativePath = this.toRelativePath(metadata.filePath);
|
|
3511
|
-
this.tokens.set(token, {
|
|
3512
|
-
mode: metadata.mode,
|
|
3513
|
-
component: metadata.component,
|
|
3514
|
-
path: relativePath
|
|
3515
|
-
});
|
|
3516
|
-
}
|
|
3517
|
-
/**
|
|
3518
|
-
* Converts absolute path to relative path.
|
|
3519
|
-
*
|
|
3520
|
-
* @param {string} absolutePath - Absolute file path
|
|
3521
|
-
* @returns {string} Relative path
|
|
3522
|
-
*/
|
|
3523
|
-
toRelativePath(absolutePath) {
|
|
3524
|
-
if (absolutePath.startsWith("/")) {
|
|
3525
|
-
const parts = absolutePath.split("/");
|
|
3526
|
-
const rootIndex = parts.findIndex(
|
|
3527
|
-
(p) => p === "src" || p === "app" || p === "components"
|
|
3528
|
-
);
|
|
3529
|
-
if (rootIndex > 0) {
|
|
3530
|
-
return parts.slice(rootIndex).join("/");
|
|
3531
|
-
}
|
|
3532
|
-
}
|
|
3533
|
-
return absolutePath;
|
|
3534
|
-
}
|
|
3535
|
-
/**
|
|
3536
|
-
* Computes checksum of the tokens object.
|
|
3537
|
-
*
|
|
3538
|
-
* @param {Record<string, TokenData>} tokens - Tokens object
|
|
3539
|
-
* @returns {string} SHA-256 checksum
|
|
3540
|
-
*/
|
|
3541
|
-
computeChecksum(tokens) {
|
|
3542
|
-
const sortedKeys = Object.keys(tokens).sort();
|
|
3543
|
-
const sortedTokens = {};
|
|
3544
|
-
for (const key of sortedKeys) {
|
|
3545
|
-
sortedTokens[key] = tokens[key];
|
|
3546
|
-
}
|
|
3547
|
-
const content = JSON.stringify(sortedTokens);
|
|
3548
|
-
return createHash2("sha256").update(content).digest("hex");
|
|
3549
|
-
}
|
|
3550
|
-
/**
|
|
3551
|
-
* Builds the final recovery manifest.
|
|
3552
|
-
*
|
|
3553
|
-
* @returns {RecoveryManifest} The complete recovery manifest
|
|
3554
|
-
*
|
|
3555
|
-
* @example
|
|
3556
|
-
* ```typescript
|
|
3557
|
-
* const manifest = builder.build();
|
|
3558
|
-
* // Returns: { buildId: 'abc123', checksum: '...', tokens: {...} }
|
|
3559
|
-
* ```
|
|
3560
|
-
*/
|
|
3561
|
-
build() {
|
|
3562
|
-
const tokensObject = {};
|
|
3563
|
-
for (const [token, data] of this.tokens.entries()) {
|
|
3564
|
-
tokensObject[token] = data;
|
|
3565
|
-
}
|
|
3566
|
-
const checksum = this.computeChecksum(tokensObject);
|
|
3567
|
-
return {
|
|
3568
|
-
buildId: this.buildId,
|
|
3569
|
-
checksum,
|
|
3570
|
-
tokens: tokensObject
|
|
3571
|
-
};
|
|
3572
|
-
}
|
|
3573
|
-
/**
|
|
3574
|
-
* Gets the number of tokens in the manifest.
|
|
3575
|
-
*
|
|
3576
|
-
* @returns {number} Token count
|
|
3577
|
-
*/
|
|
3578
|
-
size() {
|
|
3579
|
-
return this.tokens.size;
|
|
3580
|
-
}
|
|
3581
|
-
/**
|
|
3582
|
-
* Checks if a token exists in the manifest.
|
|
3583
|
-
*
|
|
3584
|
-
* @param {string} token - Token to check
|
|
3585
|
-
* @returns {boolean} True if token exists
|
|
3586
|
-
*/
|
|
3587
|
-
hasToken(token) {
|
|
3588
|
-
return this.tokens.has(token);
|
|
3589
|
-
}
|
|
3590
|
-
/**
|
|
3591
|
-
* Clears all tokens from the manifest.
|
|
3592
|
-
*/
|
|
3593
|
-
clear() {
|
|
3594
|
-
this.tokens.clear();
|
|
3595
|
-
}
|
|
3596
|
-
};
|
|
3597
|
-
function serializeManifest(manifest, pretty = false) {
|
|
3598
|
-
return JSON.stringify(manifest, null, pretty ? 2 : 0);
|
|
3599
|
-
}
|
|
3600
|
-
function parseManifest(json) {
|
|
3601
|
-
const parsed = JSON.parse(json);
|
|
3602
|
-
if (!parsed.buildId || !parsed.checksum || !parsed.tokens) {
|
|
3603
|
-
throw new Error("Invalid recovery manifest format");
|
|
3604
|
-
}
|
|
3605
|
-
return parsed;
|
|
3606
|
-
}
|
|
3607
|
-
function validateManifest(manifest) {
|
|
3608
|
-
if (!manifest || typeof manifest !== "object") {
|
|
3609
|
-
return { valid: false, error: "Manifest must be an object" };
|
|
3610
|
-
}
|
|
3611
|
-
const m = manifest;
|
|
3612
|
-
if (typeof m.buildId !== "string") {
|
|
3613
|
-
return { valid: false, error: "buildId must be a string" };
|
|
3614
|
-
}
|
|
3615
|
-
if (typeof m.checksum !== "string") {
|
|
3616
|
-
return { valid: false, error: "checksum must be a string" };
|
|
3617
|
-
}
|
|
3618
|
-
if (!m.tokens || typeof m.tokens !== "object") {
|
|
3619
|
-
return { valid: false, error: "tokens must be an object" };
|
|
3620
|
-
}
|
|
3621
|
-
return { valid: true };
|
|
3622
|
-
}
|
|
3623
|
-
|
|
3624
|
-
// src/hoisting.ts
|
|
3625
|
-
import * as t2 from "@babel/types";
|
|
3626
|
-
function findLCA(nodeA, nodeB, parentMap) {
|
|
3627
|
-
const ancestorsA = /* @__PURE__ */ new Set();
|
|
3628
|
-
let current = nodeA;
|
|
3629
|
-
while (current) {
|
|
3630
|
-
ancestorsA.add(current);
|
|
3631
|
-
current = parentMap.get(current);
|
|
3632
|
-
}
|
|
3633
|
-
current = nodeB;
|
|
3634
|
-
while (current) {
|
|
3635
|
-
if (ancestorsA.has(current) && t2.isJSXOpeningElement(current) && current !== nodeA && current !== nodeB) {
|
|
3636
|
-
return current;
|
|
3637
|
-
}
|
|
3638
|
-
current = parentMap.get(current);
|
|
3639
|
-
}
|
|
3640
|
-
return null;
|
|
3641
|
-
}
|
|
3642
|
-
function isFragment(node) {
|
|
3643
|
-
if (t2.isJSXIdentifier(node.name)) {
|
|
3644
|
-
return node.name.name === "Fragment";
|
|
3645
|
-
}
|
|
3646
|
-
if (t2.isJSXMemberExpression(node.name)) {
|
|
3647
|
-
return t2.isJSXIdentifier(node.name.property) && node.name.property.name === "Fragment";
|
|
3648
|
-
}
|
|
3649
|
-
return false;
|
|
3650
|
-
}
|
|
3651
|
-
function removeStyleVar(element, varName) {
|
|
3652
|
-
for (const attr of element.attributes) {
|
|
3653
|
-
if (!t2.isJSXAttribute(attr)) {
|
|
3654
|
-
continue;
|
|
3655
|
-
}
|
|
3656
|
-
if (!t2.isJSXIdentifier(attr.name) || attr.name.name !== "style") {
|
|
3657
|
-
continue;
|
|
3658
|
-
}
|
|
3659
|
-
if (!t2.isJSXExpressionContainer(attr.value)) {
|
|
3660
|
-
continue;
|
|
3661
|
-
}
|
|
3662
|
-
const styleObj = attr.value.expression;
|
|
3663
|
-
if (!t2.isObjectExpression(styleObj)) {
|
|
3664
|
-
continue;
|
|
3665
|
-
}
|
|
3666
|
-
styleObj.properties = styleObj.properties.filter((prop) => {
|
|
3667
|
-
if (!t2.isObjectProperty(prop)) {
|
|
3668
|
-
return true;
|
|
3669
|
-
}
|
|
3670
|
-
if (t2.isStringLiteral(prop.key)) {
|
|
3671
|
-
return prop.key.value !== varName;
|
|
3672
|
-
}
|
|
3673
|
-
return true;
|
|
3674
|
-
});
|
|
3675
|
-
if (styleObj.properties.length === 0) {
|
|
3676
|
-
const idx = element.attributes.indexOf(attr);
|
|
3677
|
-
if (idx !== -1) {
|
|
3678
|
-
element.attributes.splice(idx, 1);
|
|
3679
|
-
}
|
|
3680
|
-
}
|
|
3681
|
-
break;
|
|
3682
|
-
}
|
|
3683
|
-
}
|
|
3684
|
-
function addStyleVar(element, varName, valueExpr) {
|
|
3685
|
-
for (const attr of element.attributes) {
|
|
3686
|
-
if (!t2.isJSXAttribute(attr)) {
|
|
3687
|
-
continue;
|
|
3688
|
-
}
|
|
3689
|
-
if (!t2.isJSXIdentifier(attr.name) || attr.name.name !== "style") {
|
|
3690
|
-
continue;
|
|
3691
|
-
}
|
|
3692
|
-
if (!t2.isJSXExpressionContainer(attr.value)) {
|
|
3693
|
-
continue;
|
|
3694
|
-
}
|
|
3695
|
-
const styleObj = attr.value.expression;
|
|
3696
|
-
if (!t2.isObjectExpression(styleObj)) {
|
|
3697
|
-
continue;
|
|
3698
|
-
}
|
|
3699
|
-
const existing = styleObj.properties.find(
|
|
3700
|
-
(prop) => t2.isObjectProperty(prop) && t2.isStringLiteral(prop.key) && prop.key.value === varName
|
|
3701
|
-
);
|
|
3702
|
-
if (!existing) {
|
|
3703
|
-
styleObj.properties.push(
|
|
3704
|
-
t2.objectProperty(t2.stringLiteral(varName), valueExpr)
|
|
3705
|
-
);
|
|
3706
|
-
}
|
|
3707
|
-
return;
|
|
3708
|
-
}
|
|
3709
|
-
element.attributes.push(
|
|
3710
|
-
t2.jsxAttribute(
|
|
3711
|
-
t2.jsxIdentifier("style"),
|
|
3712
|
-
t2.jsxExpressionContainer(
|
|
3713
|
-
t2.objectExpression([
|
|
3714
|
-
t2.objectProperty(t2.stringLiteral(varName), valueExpr)
|
|
3715
|
-
])
|
|
3716
|
-
)
|
|
3717
|
-
)
|
|
3718
|
-
);
|
|
3719
|
-
}
|
|
3720
|
-
function hoistCSSVariables(usages, parentMap) {
|
|
3721
|
-
if (usages.length < 2) {
|
|
3722
|
-
return;
|
|
3723
|
-
}
|
|
3724
|
-
const groups = /* @__PURE__ */ new Map();
|
|
3725
|
-
for (const usage of usages) {
|
|
3726
|
-
if (usage.serializedValue === null) {
|
|
3727
|
-
continue;
|
|
3728
|
-
}
|
|
3729
|
-
const groupKey = `${usage.varName}::${usage.serializedValue}`;
|
|
3730
|
-
const group = groups.get(groupKey) || [];
|
|
3731
|
-
group.push(usage);
|
|
3732
|
-
groups.set(groupKey, group);
|
|
3733
|
-
}
|
|
3734
|
-
for (const [, group] of groups) {
|
|
3735
|
-
if (group.length < 2) {
|
|
3736
|
-
continue;
|
|
3737
|
-
}
|
|
3738
|
-
let lca = group[0].element;
|
|
3739
|
-
for (let i = 1; i < group.length; i++) {
|
|
3740
|
-
const newLca = findLCA(lca, group[i].element, parentMap);
|
|
3741
|
-
if (newLca === null || isFragment(newLca)) {
|
|
3742
|
-
lca = null;
|
|
3743
|
-
break;
|
|
3744
|
-
}
|
|
3745
|
-
lca = newLca;
|
|
3746
|
-
}
|
|
3747
|
-
if (!lca) {
|
|
3748
|
-
continue;
|
|
3749
|
-
}
|
|
3750
|
-
addStyleVar(lca, group[0].varName, group[0].valueExpr);
|
|
3751
|
-
for (const usage of group) {
|
|
3752
|
-
removeStyleVar(usage.element, usage.varName);
|
|
3753
|
-
}
|
|
3754
|
-
}
|
|
3755
|
-
}
|
|
3756
|
-
function buildParentMap(ast) {
|
|
3757
|
-
const map = /* @__PURE__ */ new Map();
|
|
3758
|
-
function traverse2(node, parent) {
|
|
3759
|
-
if (parent) {
|
|
3760
|
-
map.set(node, parent);
|
|
3761
|
-
}
|
|
3762
|
-
for (const key of Object.keys(node)) {
|
|
3763
|
-
const value = node[key];
|
|
3764
|
-
if (value && typeof value === "object") {
|
|
3765
|
-
if (Array.isArray(value)) {
|
|
3766
|
-
for (const item of value) {
|
|
3767
|
-
if (item && typeof item === "object" && "type" in item) {
|
|
3768
|
-
traverse2(item, node);
|
|
3769
|
-
}
|
|
3770
|
-
}
|
|
3771
|
-
} else if ("type" in value) {
|
|
3772
|
-
traverse2(value, node);
|
|
3773
|
-
}
|
|
3774
|
-
}
|
|
3775
|
-
}
|
|
3776
|
-
}
|
|
3777
|
-
traverse2(ast);
|
|
3778
|
-
return map;
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
// src/index.ts
|
|
3782
|
-
var VERSION = "0.0.0";
|
|
3783
|
-
var DEFAULT_COMPILER_OPTIONS = {
|
|
3784
|
-
buildId: Date.now().toString(),
|
|
3785
|
-
development: process.env.NODE_ENV !== "production",
|
|
3786
|
-
strictMode: false
|
|
3787
|
-
};
|
|
3788
|
-
function mergeOptions(options = {}) {
|
|
3789
|
-
return {
|
|
3790
|
-
...DEFAULT_COMPILER_OPTIONS,
|
|
3791
|
-
...options
|
|
3792
|
-
};
|
|
3793
|
-
}
|
|
3794
|
-
export {
|
|
3795
|
-
BOOLEAN_SHORTHANDS,
|
|
3796
|
-
COLOR_PROPERTIES,
|
|
3797
|
-
CsszyxCompiler,
|
|
3798
|
-
DEFAULT_COMPILER_OPTIONS,
|
|
3799
|
-
KNOWN_VARIANTS,
|
|
3800
|
-
ManifestBuilder,
|
|
3801
|
-
PROPERTY_CATEGORY_MAP,
|
|
3802
|
-
PROPERTY_MAP,
|
|
3803
|
-
PropertyCategory,
|
|
3804
|
-
SUGGESTION_MAP,
|
|
3805
|
-
VERSION,
|
|
3806
|
-
buildParentMap,
|
|
3807
|
-
createRecoveryToken,
|
|
3808
|
-
generateRecoveryToken,
|
|
3809
|
-
getCSSVariableName,
|
|
3810
|
-
getPropertyCategory,
|
|
3811
|
-
hoistCSSVariables,
|
|
3812
|
-
injectRecoveryToken,
|
|
3813
|
-
isValidRecoveryMode,
|
|
3814
|
-
isValidSzProp,
|
|
3815
|
-
mergeOptions,
|
|
3816
|
-
normalizeClassName,
|
|
3817
|
-
parseManifest,
|
|
3818
|
-
serializeManifest,
|
|
3819
|
-
transform,
|
|
3820
|
-
transformSourceCode,
|
|
3821
|
-
validateManifest,
|
|
3822
|
-
validateSzRecover
|
|
3823
|
-
};
|
|
2273
|
+
exports.BOOLEAN_SHORTHANDS = BOOLEAN_SHORTHANDS;
|
|
2274
|
+
exports.COLOR_PROPERTIES = COLOR_PROPERTIES;
|
|
2275
|
+
exports.KNOWN_VARIANTS = KNOWN_VARIANTS;
|
|
2276
|
+
exports.PROPERTY_CATEGORY_MAP = PROPERTY_CATEGORY_MAP;
|
|
2277
|
+
exports.PROPERTY_MAP = PROPERTY_MAP;
|
|
2278
|
+
exports.PropertyCategory = PropertyCategory;
|
|
2279
|
+
exports.SUGGESTION_MAP = SUGGESTION_MAP;
|
|
2280
|
+
exports.VARIANT_MAP = VARIANT_MAP;
|
|
2281
|
+
exports.getCSSVariableName = getCSSVariableName;
|
|
2282
|
+
exports.getPropertyCategory = getPropertyCategory;
|
|
2283
|
+
exports.getVariantPrefix = getVariantPrefix;
|
|
2284
|
+
exports.isValidSzProp = isValidSzProp;
|
|
2285
|
+
exports.normalizeArbitraryValue = normalizeArbitraryValue;
|
|
2286
|
+
exports.normalizeArbitraryVariant = normalizeArbitraryVariant;
|
|
2287
|
+
exports.normalizeClassName = normalizeClassName;
|
|
2288
|
+
exports.stripInvalidColorStrings = stripInvalidColorStrings;
|
|
2289
|
+
exports.transform = transform;
|