@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.
@@ -1,11 +1,5 @@
1
- import {
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
- var PROPERTY_CATEGORY_MAP = {
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
- var COLOR_PROPERTIES = new Set(
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
- // src/color-validation.ts
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] === 1 /* COLOR */) {
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["NODE_ENV"] !== "production" && typeof window === "undefined") {
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["NODE_ENV"] !== "production" && typeof window === "undefined") {
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
- // src/transform.ts
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
- var CSS_VAR_TYPE_HINTS = {
582
+ const CSS_VAR_TYPE_HINTS = {
628
583
  fontFamily: "family-name",
629
584
  fontWeight: "weight",
630
585
  text: "length"
631
586
  };
632
- var SUGGESTION_MAP = {
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
- var VARIANT_MAP = {
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
- var KNOWN_VARIANTS = /* @__PURE__ */ new Set([
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
- var ARIA_STATES = /* @__PURE__ */ new Set([
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
- var BOOLEAN_SHORTHANDS = /* @__PURE__ */ new Set([
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
- var BOOLEAN_TO_CLASS = {
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
- var SNAP_DIRECT_MAP = {
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
- var NEGATIVE_ALLOWED = /* @__PURE__ */ new Set([
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
- var FRACTION_SUPPORTED_PROPS = /* @__PURE__ */ new Set([
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(v) || // Positive units
1170
- /^-\d+(\.\d+)?(px|rem|em|%|vh|vw|ch|dvh|dvw|svh|svw|lvh|lvw|cqw|cqh|deg|rad|turn|grad|ms|s|fr)$/.test(v) || // Negative units like -1px, -2rem
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
- var LIST_STYLE_STANDARD = /* @__PURE__ */ new Set(["none", "disc", "decimal"]);
1186
- var FONT_STRETCH_KEYWORDS = /* @__PURE__ */ new Set([
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] === 1 /* COLOR */) {
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["NODE_ENV"] !== "production" && typeof window === "undefined") {
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["NODE_ENV"] !== "production" && typeof window === "undefined") {
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({ [nestedKey]: nestedValue }, nestedPrefix2);
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({ [nestedKey]: nestedValue }, nestedPrefix2);
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(value)) {
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
- "normal": "break-normal",
1787
- "all": "break-all",
1788
- "keep": "break-keep",
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
- "normal": "wrap-normal",
1766
+ normal: "wrap-normal",
1800
1767
  "break-word": "wrap-break-word",
1801
- "anywhere": "wrap-anywhere",
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(["center", "top", "right", "bottom", "left", "top-left", "top-right", "bottom-left", "bottom-right"]);
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
- // src/transform.ts
2298
- function transformSourceCode(source, filename, options) {
2299
- const astBudget = options?.astBudget ?? AST_BUDGET;
2300
- let usesRuntime = false;
2301
- let usesMerge = false;
2302
- let usesColorVar = false;
2303
- let transformed = false;
2304
- const collectedClasses = /* @__PURE__ */ new Set();
2305
- const rawClassNames = /* @__PURE__ */ new Set();
2306
- const diagnostics = [];
2307
- const recoveryTokens = /* @__PURE__ */ new Map();
2308
- if (!source.includes("sz")) {
2309
- return { code: source, transformed: false, usesRuntime: false, usesMerge: false, usesColorVar: false, classes: collectedClasses, rawClassNames, diagnostics, recoveryTokens };
2310
- }
2311
- try {
2312
- const result = babel.transformSync(source, {
2313
- filename: filename ?? "file.tsx",
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;