@csszyx/compiler 0.9.0 → 0.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,11 +1,11 @@
1
- import { init, version, transform_sz } from '@csszyx/core';
2
- import { t as transform, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, s as stripInvalidColorStrings } from './shared/compiler.CUn8HGmA.mjs';
3
- export { B as BOOLEAN_SHORTHANDS, d as PROPERTY_CATEGORY_MAP, S as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.CUn8HGmA.mjs';
1
+ import { init, version, transform_sz, encode } from '@csszyx/core';
2
+ import { t as transform, C as COLOR_PROPERTIES, P as PROPERTY_MAP, g as getCSSVariableName, a as PropertyCategory, K as KNOWN_VARIANTS, b as getVariantPrefix, c as getPropertyCategory, s as stripInvalidColorStrings } from './shared/compiler.wyFFQW-b.mjs';
3
+ export { B as BOOLEAN_SHORTHANDS, d as PROPERTY_CATEGORY_MAP, S as SPECIAL_VARIANTS, e as SUGGESTION_MAP, i as isValidSzProp, n as normalizeClassName } from './shared/compiler.wyFFQW-b.mjs';
4
+ import { parseSync } from 'oxc-parser';
4
5
  import * as t from '@babel/types';
5
6
  import { createHash } from 'node:crypto';
6
7
  import * as babel from '@babel/core';
7
8
  import MagicString from 'magic-string';
8
- import { parseSync } from 'oxc-parser';
9
9
  import { transformBatch, CsszyxNativeUnavailableError } from '@csszyx/core/native';
10
10
 
11
11
  const AST_BUDGET = 5e4;
@@ -65,6 +65,7 @@ function transformSourceCode(source, filename, options) {
65
65
  const rawClassNames = /* @__PURE__ */ new Set();
66
66
  const diagnostics = [];
67
67
  const recoveryTokens = /* @__PURE__ */ new Map();
68
+ const cssVariableMap = /* @__PURE__ */ new Map();
68
69
  if (!source.includes("sz")) {
69
70
  return {
70
71
  code: source,
@@ -75,7 +76,8 @@ function transformSourceCode(source, filename, options) {
75
76
  classes: collectedClasses,
76
77
  rawClassNames,
77
78
  diagnostics,
78
- recoveryTokens
79
+ recoveryTokens,
80
+ cssVariableMap
79
81
  };
80
82
  }
81
83
  try {
@@ -737,7 +739,8 @@ function transformSourceCode(source, filename, options) {
737
739
  classes: collectedClasses,
738
740
  rawClassNames,
739
741
  diagnostics,
740
- recoveryTokens
742
+ recoveryTokens,
743
+ cssVariableMap
741
744
  };
742
745
  } catch (e) {
743
746
  if (e instanceof ASTBudgetExceededError) {
@@ -753,7 +756,8 @@ function transformSourceCode(source, filename, options) {
753
756
  classes: collectedClasses,
754
757
  rawClassNames,
755
758
  diagnostics,
756
- recoveryTokens
759
+ recoveryTokens,
760
+ cssVariableMap
757
761
  };
758
762
  }
759
763
  }
@@ -1305,6 +1309,271 @@ class CsszyxCompiler {
1305
1309
  }
1306
1310
  }
1307
1311
 
1312
+ const CSS_VAR_REFERENCE_RE = /var\(\s*(--[\w-]+)/g;
1313
+ function scanGlobalVarUsages(source, filename = "file.tsx", options = {}) {
1314
+ if (!source.includes("--") && !source.includes("var(")) {
1315
+ return [];
1316
+ }
1317
+ const parsed = parseSync(filename, source);
1318
+ if (parsed.errors.length > 0) {
1319
+ throw new Error(
1320
+ `oxc-parser errors in ${filename}: ${parsed.errors.map((error) => error.message).join("; ")}`
1321
+ );
1322
+ }
1323
+ const tokenFilter = options.tokens ? new Set(options.tokens) : null;
1324
+ const constantStrings = collectStringConstants(parsed.program);
1325
+ const diagnostics = [];
1326
+ walk$1(parsed.program, (node, ancestors) => {
1327
+ if (node.type === "CallExpression") {
1328
+ collectStyleMethodDiagnostic(
1329
+ node,
1330
+ source,
1331
+ filename,
1332
+ constantStrings,
1333
+ tokenFilter,
1334
+ diagnostics
1335
+ );
1336
+ return;
1337
+ }
1338
+ if (node.type !== "JSXAttribute") {
1339
+ return;
1340
+ }
1341
+ const attrName = jsxAttributeName(node);
1342
+ if (attrName === "style") {
1343
+ collectJsxStyleDiagnostics(
1344
+ node,
1345
+ source,
1346
+ filename,
1347
+ constantStrings,
1348
+ tokenFilter,
1349
+ diagnostics
1350
+ );
1351
+ return;
1352
+ }
1353
+ if (attrName === "className") {
1354
+ collectClassNameDiagnostics(node, source, filename, tokenFilter, diagnostics);
1355
+ return;
1356
+ }
1357
+ if (attrName === "sz" && ancestors.some((parent) => parent.type === "JSXAttribute")) {
1358
+ return;
1359
+ }
1360
+ });
1361
+ return diagnostics;
1362
+ }
1363
+ function collectStringConstants(root) {
1364
+ const constants = /* @__PURE__ */ new Map();
1365
+ walk$1(root, (node) => {
1366
+ if (node.type !== "VariableDeclarator") {
1367
+ return;
1368
+ }
1369
+ const id = node.id;
1370
+ const init = node.init;
1371
+ if (id?.type !== "Identifier" || !init) {
1372
+ return;
1373
+ }
1374
+ const name = id.name;
1375
+ const value = literalStringValue$1(init);
1376
+ if (typeof name === "string" && value !== null) {
1377
+ constants.set(name, value);
1378
+ }
1379
+ });
1380
+ return constants;
1381
+ }
1382
+ function collectStyleMethodDiagnostic(node, source, filename, constants, tokenFilter, diagnostics) {
1383
+ const method = memberMethodName(node.callee);
1384
+ if (!method || !["setProperty", "getPropertyValue", "removeProperty"].includes(method)) {
1385
+ return;
1386
+ }
1387
+ const firstArg = node.arguments?.[0];
1388
+ const name = firstArg ? resolveString(firstArg, constants) : null;
1389
+ if (!name?.startsWith("--") || !shouldReportToken(name, tokenFilter)) {
1390
+ return;
1391
+ }
1392
+ const kind = method === "setProperty" ? "style-set-property" : method === "getPropertyValue" ? "style-get-property" : "style-remove-property";
1393
+ diagnostics.push(createDiagnostic(kind, name, node, source, filename));
1394
+ }
1395
+ function collectJsxStyleDiagnostics(attr, source, filename, constants, tokenFilter, diagnostics) {
1396
+ const expression = jsxExpression(attr);
1397
+ if (expression?.type !== "ObjectExpression") {
1398
+ return;
1399
+ }
1400
+ for (const prop of expression.properties ?? []) {
1401
+ if (prop.type !== "Property") {
1402
+ continue;
1403
+ }
1404
+ const name = propertyKeyString(prop, constants);
1405
+ if (name?.startsWith("--") && shouldReportToken(name, tokenFilter)) {
1406
+ diagnostics.push(createDiagnostic("jsx-style-key", name, prop, source, filename));
1407
+ }
1408
+ }
1409
+ }
1410
+ function collectClassNameDiagnostics(attr, source, filename, tokenFilter, diagnostics) {
1411
+ for (const value of jsxAttributeStringValues(attr)) {
1412
+ for (const name of extractVarReferences(value)) {
1413
+ if (shouldReportToken(name, tokenFilter)) {
1414
+ diagnostics.push(
1415
+ createDiagnostic("class-string-var-reference", name, attr, source, filename)
1416
+ );
1417
+ }
1418
+ }
1419
+ }
1420
+ }
1421
+ function jsxAttributeName(attr) {
1422
+ const name = attr.name;
1423
+ return name?.type === "JSXIdentifier" ? name.name ?? null : null;
1424
+ }
1425
+ function jsxExpression(attr) {
1426
+ const value = attr.value;
1427
+ if (value?.type !== "JSXExpressionContainer") {
1428
+ return null;
1429
+ }
1430
+ return value.expression ?? null;
1431
+ }
1432
+ function jsxAttributeStringValues(attr) {
1433
+ const value = attr.value;
1434
+ if (!value) {
1435
+ return [];
1436
+ }
1437
+ const direct = literalStringValue$1(value);
1438
+ if (direct !== null) {
1439
+ return [direct];
1440
+ }
1441
+ const expression = jsxExpression(attr);
1442
+ if (!expression) {
1443
+ return [];
1444
+ }
1445
+ const exprValue = literalStringValue$1(expression);
1446
+ if (exprValue !== null) {
1447
+ return [exprValue];
1448
+ }
1449
+ if (expression.type === "TemplateLiteral") {
1450
+ return templateStaticParts(expression);
1451
+ }
1452
+ return [];
1453
+ }
1454
+ function resolveString(node, constants) {
1455
+ const literal = literalStringValue$1(node);
1456
+ if (literal !== null) {
1457
+ return literal;
1458
+ }
1459
+ if (node.type === "Identifier") {
1460
+ const name = node.name;
1461
+ return typeof name === "string" ? constants.get(name) ?? null : null;
1462
+ }
1463
+ return null;
1464
+ }
1465
+ function literalStringValue$1(node) {
1466
+ if (node.type !== "Literal") {
1467
+ return null;
1468
+ }
1469
+ const value = node.value;
1470
+ return typeof value === "string" ? value : null;
1471
+ }
1472
+ function propertyKeyString(property, constants) {
1473
+ const key = property.key;
1474
+ const computed = property.computed === true;
1475
+ if (!key) {
1476
+ return null;
1477
+ }
1478
+ if (computed) {
1479
+ return resolveString(key, constants);
1480
+ }
1481
+ if (key.type === "Identifier") {
1482
+ const name = key.name;
1483
+ return typeof name === "string" ? name : null;
1484
+ }
1485
+ return literalStringValue$1(key);
1486
+ }
1487
+ function memberMethodName(callee) {
1488
+ if (callee?.type !== "MemberExpression") {
1489
+ return null;
1490
+ }
1491
+ const property = callee.property;
1492
+ if (!property) {
1493
+ return null;
1494
+ }
1495
+ if (property.type === "Identifier") {
1496
+ const name = property.name;
1497
+ return typeof name === "string" ? name : null;
1498
+ }
1499
+ return literalStringValue$1(property);
1500
+ }
1501
+ function templateStaticParts(node) {
1502
+ const quasis = node.quasis ?? [];
1503
+ const parts = [];
1504
+ for (const quasi of quasis) {
1505
+ const value = quasi.value;
1506
+ const cooked = value?.cooked;
1507
+ const raw = value?.raw;
1508
+ if (typeof cooked === "string") {
1509
+ parts.push(cooked);
1510
+ } else if (typeof raw === "string") {
1511
+ parts.push(raw);
1512
+ }
1513
+ }
1514
+ return parts;
1515
+ }
1516
+ function extractVarReferences(value) {
1517
+ const refs = /* @__PURE__ */ new Set();
1518
+ for (const match of value.matchAll(CSS_VAR_REFERENCE_RE)) {
1519
+ refs.add(match[1]);
1520
+ }
1521
+ return [...refs].sort();
1522
+ }
1523
+ function shouldReportToken(name, tokenFilter) {
1524
+ return tokenFilter === null || tokenFilter.has(name);
1525
+ }
1526
+ function createDiagnostic(kind, name, node, source, filename) {
1527
+ return {
1528
+ kind,
1529
+ name,
1530
+ location: offsetToLocation(source, node.start, filename),
1531
+ message: `${name} is used outside csszyx-owned global variable alias rewrites (${kind}).`
1532
+ };
1533
+ }
1534
+ function offsetToLocation(source, offset, filename) {
1535
+ let line = 1;
1536
+ let column = 1;
1537
+ for (let index = 0; index < offset; index++) {
1538
+ if (source.charCodeAt(index) === 10) {
1539
+ line++;
1540
+ column = 1;
1541
+ } else {
1542
+ column++;
1543
+ }
1544
+ }
1545
+ return { filePath: filename, line, column };
1546
+ }
1547
+ function walk$1(node, visit, ancestors = []) {
1548
+ if (!isOxcNode$1(node)) {
1549
+ return;
1550
+ }
1551
+ visit(node, ancestors);
1552
+ ancestors.push(node);
1553
+ for (const key of Object.keys(node)) {
1554
+ if (isAstMetadataKey$1(key)) {
1555
+ continue;
1556
+ }
1557
+ const child = node[key];
1558
+ if (Array.isArray(child)) {
1559
+ for (const item of child) {
1560
+ walk$1(item, visit, ancestors);
1561
+ }
1562
+ } else if (child && typeof child === "object") {
1563
+ walk$1(child, visit, ancestors);
1564
+ }
1565
+ }
1566
+ ancestors.pop();
1567
+ }
1568
+ function isOxcNode$1(value) {
1569
+ return Boolean(
1570
+ value && typeof value === "object" && typeof value.type === "string"
1571
+ );
1572
+ }
1573
+ function isAstMetadataKey$1(key) {
1574
+ return key === "loc" || key === "range" || key === "start" || key === "end" || key === "type";
1575
+ }
1576
+
1308
1577
  function findLCA(nodeA, nodeB, parentMap) {
1309
1578
  const ancestorsA = /* @__PURE__ */ new Set();
1310
1579
  let current = nodeA;
@@ -1638,6 +1907,155 @@ function injectRecoveryToken(attributes, token) {
1638
1907
  };
1639
1908
  }
1640
1909
 
1910
+ const DEFAULT_MAX_DEPTH = 5;
1911
+ function planComponentVariableHoistsWithDiagnostics(nodes, usages, options = {}) {
1912
+ const maxDepth = options.maxDepth ?? DEFAULT_MAX_DEPTH;
1913
+ const nodeById = new Map(nodes.map((node) => [node.id, node]));
1914
+ const groups = /* @__PURE__ */ new Map();
1915
+ for (const usage of usages) {
1916
+ const groupKey = `${usage.name}\0${usage.valueKey}`;
1917
+ const group = groups.get(groupKey);
1918
+ if (group) {
1919
+ group.push(usage);
1920
+ } else {
1921
+ groups.set(groupKey, [usage]);
1922
+ }
1923
+ }
1924
+ const plans = [];
1925
+ const diagnostics = [];
1926
+ for (const group of groups.values()) {
1927
+ if (group.length < 2) {
1928
+ continue;
1929
+ }
1930
+ const targetElementId = findLowestCommonAncestor(
1931
+ group.map((usage) => usage.elementId),
1932
+ nodeById
1933
+ );
1934
+ if (!targetElementId) {
1935
+ diagnostics.push(buildHoistDiagnostic(group, "no-lca"));
1936
+ continue;
1937
+ }
1938
+ const target = nodeById.get(targetElementId);
1939
+ if (!target || target.canHost === false) {
1940
+ diagnostics.push(buildHoistDiagnostic(group, "non-host-ancestor"));
1941
+ continue;
1942
+ }
1943
+ if (group.some(
1944
+ (usage) => distanceToAncestor(usage.elementId, targetElementId, nodeById) > maxDepth
1945
+ )) {
1946
+ diagnostics.push(buildHoistDiagnostic(group, "max-depth", maxDepth));
1947
+ continue;
1948
+ }
1949
+ plans.push({
1950
+ name: group[0].name,
1951
+ valueKey: group[0].valueKey,
1952
+ targetElementId,
1953
+ usageIds: group.map((usage) => usage.id)
1954
+ });
1955
+ }
1956
+ return { plans, diagnostics };
1957
+ }
1958
+ function buildHoistDiagnostic(group, reason, maxDepth) {
1959
+ return {
1960
+ name: group[0]?.name ?? "",
1961
+ reason,
1962
+ usageCount: group.length,
1963
+ ...maxDepth === void 0 ? {} : { maxDepth }
1964
+ };
1965
+ }
1966
+ function findLowestCommonAncestor(elementIds, nodeById) {
1967
+ const [first, ...rest] = elementIds;
1968
+ if (!first) {
1969
+ return null;
1970
+ }
1971
+ let currentAncestors = ancestorChain(first, nodeById);
1972
+ for (const elementId of rest) {
1973
+ const nextAncestors = new Set(ancestorChain(elementId, nodeById));
1974
+ currentAncestors = currentAncestors.filter((id) => nextAncestors.has(id));
1975
+ if (currentAncestors.length === 0) {
1976
+ return null;
1977
+ }
1978
+ }
1979
+ return currentAncestors[0] ?? null;
1980
+ }
1981
+ function ancestorChain(elementId, nodeById) {
1982
+ const chain = [];
1983
+ let current = elementId;
1984
+ while (current) {
1985
+ const node = nodeById.get(current);
1986
+ if (!node) {
1987
+ break;
1988
+ }
1989
+ chain.push(current);
1990
+ current = node.parentId;
1991
+ }
1992
+ return chain;
1993
+ }
1994
+ function distanceToAncestor(elementId, ancestorId, nodeById) {
1995
+ let distance = 0;
1996
+ let current = elementId;
1997
+ while (current) {
1998
+ if (current === ancestorId) {
1999
+ return distance;
2000
+ }
2001
+ const node = nodeById.get(current);
2002
+ if (!node) {
2003
+ break;
2004
+ }
2005
+ current = node.parentId;
2006
+ distance++;
2007
+ }
2008
+ return Number.POSITIVE_INFINITY;
2009
+ }
2010
+
2011
+ function planCSSVariableNames(usages, options = {}) {
2012
+ const componentNames = /* @__PURE__ */ new Map();
2013
+ const scopedNamesByElement = /* @__PURE__ */ new Map();
2014
+ const reservedNames = options.reservedNames ?? /* @__PURE__ */ new Set();
2015
+ return usages.map((usage) => {
2016
+ if (usage.tier === "component") {
2017
+ const key2 = canonicalUsageKey(usage);
2018
+ let name2 = componentNames.get(key2);
2019
+ if (!name2) {
2020
+ name2 = allocateVariableName("--c", componentNames.size, reservedNames);
2021
+ componentNames.set(key2, name2);
2022
+ }
2023
+ return { ...usage, name: name2 };
2024
+ }
2025
+ const elementId = usage.elementId ?? "";
2026
+ const elementNames = getOrCreate(scopedNamesByElement, elementId, () => /* @__PURE__ */ new Map());
2027
+ const key = canonicalUsageKey(usage);
2028
+ let name = elementNames.get(key);
2029
+ if (!name) {
2030
+ name = allocateVariableName("--s", elementNames.size, reservedNames);
2031
+ elementNames.set(key, name);
2032
+ }
2033
+ return { ...usage, name };
2034
+ });
2035
+ }
2036
+ function allocateVariableName(prefix, startIndex, reservedNames) {
2037
+ let index = startIndex;
2038
+ while (true) {
2039
+ const name = `${prefix}${encode(index)}`;
2040
+ if (!reservedNames.has(name)) {
2041
+ return name;
2042
+ }
2043
+ index++;
2044
+ }
2045
+ }
2046
+ function canonicalUsageKey(usage) {
2047
+ return `${usage.variantChain ?? ""}\0${usage.propertyKey}`;
2048
+ }
2049
+ function getOrCreate(map, key, create) {
2050
+ const existing = map.get(key);
2051
+ if (existing) {
2052
+ return existing;
2053
+ }
2054
+ const value = create();
2055
+ map.set(key, value);
2056
+ return value;
2057
+ }
2058
+
1641
2059
  class OxcNotImplementedError extends Error {
1642
2060
  /**
1643
2061
  * @param slice The Phase D slice expected to implement this path.
@@ -1653,6 +2071,8 @@ function transformOxc(source, filename, options) {
1653
2071
  const rawClassNames = /* @__PURE__ */ new Set();
1654
2072
  const diagnostics = [];
1655
2073
  const recoveryTokens = /* @__PURE__ */ new Map();
2074
+ const cssVariableMap = /* @__PURE__ */ new Map();
2075
+ const globalVarAliases = normalizeGlobalVarAliases$1(options?.globalVarAliases);
1656
2076
  if (!source.includes("sz")) {
1657
2077
  return {
1658
2078
  code: source,
@@ -1663,7 +2083,8 @@ function transformOxc(source, filename, options) {
1663
2083
  classes,
1664
2084
  rawClassNames,
1665
2085
  diagnostics,
1666
- recoveryTokens
2086
+ recoveryTokens,
2087
+ cssVariableMap
1667
2088
  };
1668
2089
  }
1669
2090
  const effectiveFilename = filename ?? "file.tsx";
@@ -1678,6 +2099,18 @@ function transformOxc(source, filename, options) {
1678
2099
  const edits = new MagicString(source);
1679
2100
  const objectBindings = collectObjectBindings(parsed.program);
1680
2101
  const conditionalBindings = collectConditionalBindings(parsed.program);
2102
+ const reservedCSSVariableNames = options?.mangleVars ? collectStaticStyleCustomPropertyNames(parsed.program) : void 0;
2103
+ const componentHoists = options?.mangleVars ? planOxcComponentVariableHoists(
2104
+ parsed.program,
2105
+ effectiveFilename,
2106
+ objectBindings,
2107
+ source,
2108
+ options.mangleVarHoistMaxDepth,
2109
+ reservedCSSVariableNames
2110
+ ) : null;
2111
+ if (componentHoists) {
2112
+ diagnostics.push(...componentHoists.diagnostics);
2113
+ }
1681
2114
  let transformed = false;
1682
2115
  let usesRuntime = false;
1683
2116
  let usesMerge = false;
@@ -1703,6 +2136,24 @@ function transformOxc(source, filename, options) {
1703
2136
  let szRecoverAttr = null;
1704
2137
  let alreadyTagged = false;
1705
2138
  let lastAttr = null;
2139
+ let appliedHoistedStyleProps = false;
2140
+ const elementId = elementIdForOpening(openingNode);
2141
+ const hoistedStyleProps = componentHoists?.stylePropsByTarget.get(elementId) ?? [];
2142
+ const applyHoistedStyleProps = () => {
2143
+ if (appliedHoistedStyleProps || hoistedStyleProps.length === 0) {
2144
+ return;
2145
+ }
2146
+ applyStyleProps(
2147
+ edits,
2148
+ source,
2149
+ styleAttr,
2150
+ lastAttr,
2151
+ hoistedStyleProps,
2152
+ openingNode.name.end
2153
+ );
2154
+ appliedHoistedStyleProps = true;
2155
+ transformed = true;
2156
+ };
1706
2157
  for (const attrRaw of attrs) {
1707
2158
  if (attrRaw.type !== "JSXAttribute") {
1708
2159
  continue;
@@ -1763,6 +2214,7 @@ function transformOxc(source, filename, options) {
1763
2214
  }
1764
2215
  }
1765
2216
  if (szAttrs.length === 0) {
2217
+ applyHoistedStyleProps();
1766
2218
  return;
1767
2219
  }
1768
2220
  const szDerived = [];
@@ -1799,7 +2251,9 @@ function transformOxc(source, filename, options) {
1799
2251
  effectiveFilename,
1800
2252
  objectBindings,
1801
2253
  source,
1802
- classes
2254
+ classes,
2255
+ globalVarAliases,
2256
+ cssVariableMap
1803
2257
  );
1804
2258
  if (conditionalClassExpr) {
1805
2259
  if (classNameAttr || szAttrs.length > 1) {
@@ -1821,7 +2275,11 @@ function transformOxc(source, filename, options) {
1821
2275
  const bound = objectBindings.get(identifierName);
1822
2276
  if (bound) {
1823
2277
  const result2 = transform(
1824
- astObjectToSzObject(bound, effectiveFilename, objectBindings)
2278
+ applyGlobalVarAliasesToSzObject(
2279
+ astObjectToSzObject(bound, effectiveFilename, objectBindings),
2280
+ globalVarAliases,
2281
+ cssVariableMap
2282
+ )
1825
2283
  );
1826
2284
  for (const c of result2.className.split(/\s+/)) {
1827
2285
  if (c) {
@@ -1838,7 +2296,9 @@ function transformOxc(source, filename, options) {
1838
2296
  effectiveFilename,
1839
2297
  objectBindings,
1840
2298
  source,
1841
- classes
2299
+ classes,
2300
+ globalVarAliases,
2301
+ cssVariableMap
1842
2302
  );
1843
2303
  if (conditionalClassExpr) {
1844
2304
  if (classNameAttr || szAttrs.length > 1) {
@@ -1860,7 +2320,9 @@ function transformOxc(source, filename, options) {
1860
2320
  const arrayClasses = astArrayToStaticClasses(
1861
2321
  expression,
1862
2322
  effectiveFilename,
1863
- objectBindings
2323
+ objectBindings,
2324
+ globalVarAliases,
2325
+ cssVariableMap
1864
2326
  );
1865
2327
  if (arrayClasses === null) {
1866
2328
  collectArrayCandidateClasses(
@@ -1898,7 +2360,9 @@ function transformOxc(source, filename, options) {
1898
2360
  effectiveFilename,
1899
2361
  objectBindings,
1900
2362
  source,
1901
- classes
2363
+ classes,
2364
+ globalVarAliases,
2365
+ cssVariableMap
1902
2366
  );
1903
2367
  if (conditionalSpreadClassExpr) {
1904
2368
  if (classNameAttr || szAttrs.length > 1) {
@@ -1918,9 +2382,15 @@ function transformOxc(source, filename, options) {
1918
2382
  expression,
1919
2383
  effectiveFilename,
1920
2384
  objectBindings,
1921
- source
2385
+ source,
2386
+ options,
2387
+ componentHoists?.usageNamesByElement.get(elementId),
2388
+ cssVariableMap,
2389
+ reservedCSSVariableNames,
2390
+ globalVarAliases
1922
2391
  );
1923
2392
  if (partial && szAttrs.length === 1) {
2393
+ const mergedStyleProps = hoistedStyleProps.length > 0 ? [...hoistedStyleProps, ...partial.styleProps] : partial.styleProps;
1924
2394
  if (classNameAttr?.value?.type === "JSXExpressionContainer") {
1925
2395
  const classExpression = classNameAttr.value.expression;
1926
2396
  const classExpressionSource = source.slice(
@@ -1933,7 +2403,15 @@ function transformOxc(source, filename, options) {
1933
2403
  `className={_szMerge(${classExpressionSource}, ${JSON.stringify(partial.className)})}`
1934
2404
  );
1935
2405
  edits.remove(whitespaceStart(source, szAttr.start), szAttr.end);
1936
- applyStyleProps(edits, source, styleAttr, lastAttr, partial.styleProps);
2406
+ applyStyleProps(
2407
+ edits,
2408
+ source,
2409
+ styleAttr,
2410
+ lastAttr,
2411
+ mergedStyleProps,
2412
+ openingNode.name.end
2413
+ );
2414
+ appliedHoistedStyleProps = true;
1937
2415
  for (const c of partial.className.split(/\s+/)) {
1938
2416
  if (c) {
1939
2417
  classes.add(c);
@@ -1957,7 +2435,15 @@ function transformOxc(source, filename, options) {
1957
2435
  } else {
1958
2436
  edits.overwrite(szAttr.start, szAttr.end, partial.classNameAttr);
1959
2437
  }
1960
- applyStyleProps(edits, source, styleAttr, lastAttr, partial.styleProps);
2438
+ applyStyleProps(
2439
+ edits,
2440
+ source,
2441
+ styleAttr,
2442
+ lastAttr,
2443
+ mergedStyleProps,
2444
+ openingNode.name.end
2445
+ );
2446
+ appliedHoistedStyleProps = true;
1961
2447
  for (const c of partial.className.split(/\s+/)) {
1962
2448
  if (c) {
1963
2449
  classes.add(c);
@@ -1973,7 +2459,9 @@ function transformOxc(source, filename, options) {
1973
2459
  }
1974
2460
  throw err;
1975
2461
  }
1976
- const result = transform(szObj);
2462
+ const result = transform(
2463
+ applyGlobalVarAliasesToSzObject(szObj, globalVarAliases, cssVariableMap)
2464
+ );
1977
2465
  for (const c of result.className.split(/\s+/)) {
1978
2466
  if (c) {
1979
2467
  szDerived.push(c);
@@ -2006,6 +2494,7 @@ function transformOxc(source, filename, options) {
2006
2494
  transformed = true;
2007
2495
  return;
2008
2496
  }
2497
+ applyHoistedStyleProps();
2009
2498
  const existingRaw = classNameAttr ? stringLiteralValue(classNameAttr.value) : null;
2010
2499
  const mergedClasses = [
2011
2500
  ...existingRaw ? existingRaw.split(/\s+/).filter(Boolean) : [],
@@ -2040,7 +2529,8 @@ function transformOxc(source, filename, options) {
2040
2529
  classes,
2041
2530
  rawClassNames,
2042
2531
  diagnostics,
2043
- recoveryTokens
2532
+ recoveryTokens,
2533
+ cssVariableMap
2044
2534
  };
2045
2535
  }
2046
2536
  function stringLiteralValue(value) {
@@ -2149,7 +2639,7 @@ function astObjectToSzObject(node, filename, bindings) {
2149
2639
  }
2150
2640
  return result;
2151
2641
  }
2152
- function astArrayToStaticClasses(node, filename, bindings) {
2642
+ function astArrayToStaticClasses(node, filename, bindings, globalVarAliases, cssVariableMap) {
2153
2643
  const out = [];
2154
2644
  for (const element of node.elements) {
2155
2645
  if (!element || isFalsyLiteral(element)) {
@@ -2166,7 +2656,13 @@ function astArrayToStaticClasses(node, filename, bindings) {
2166
2656
  }
2167
2657
  let result;
2168
2658
  try {
2169
- result = transform(astObjectToSzObject(objectNode, filename, bindings));
2659
+ result = transform(
2660
+ applyGlobalVarAliasesToSzObject(
2661
+ astObjectToSzObject(objectNode, filename, bindings),
2662
+ globalVarAliases,
2663
+ cssVariableMap
2664
+ )
2665
+ );
2170
2666
  } catch (err) {
2171
2667
  if (err instanceof OxcNotImplementedError) {
2172
2668
  return null;
@@ -2263,7 +2759,7 @@ function resolveObjectExpression(node, bindings) {
2263
2759
  }
2264
2760
  return null;
2265
2761
  }
2266
- function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes) {
2762
+ function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
2267
2763
  let conditionalSpread = null;
2268
2764
  const otherProps = [];
2269
2765
  for (const prop of node.properties) {
@@ -2286,14 +2782,18 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
2286
2782
  otherProps,
2287
2783
  node,
2288
2784
  filename,
2289
- bindings
2785
+ bindings,
2786
+ globalVarAliases,
2787
+ cssVariableMap
2290
2788
  );
2291
2789
  const alternate = compileConditionalSpreadBranch(
2292
2790
  conditionalSpread.alternate,
2293
2791
  otherProps,
2294
2792
  node,
2295
2793
  filename,
2296
- bindings
2794
+ bindings,
2795
+ globalVarAliases,
2796
+ cssVariableMap
2297
2797
  );
2298
2798
  if (consequent === null || alternate === null) {
2299
2799
  return null;
@@ -2306,7 +2806,7 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
2306
2806
  const testSource = source.slice(conditionalSpread.test.start, conditionalSpread.test.end);
2307
2807
  return `${testSource} ? ${JSON.stringify(consequent)} : ${JSON.stringify(alternate)}`;
2308
2808
  }
2309
- function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings) {
2809
+ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings, globalVarAliases, cssVariableMap) {
2310
2810
  const branchObject = resolveObjectExpression(branch, bindings);
2311
2811
  if (!branchObject) {
2312
2812
  return null;
@@ -2318,7 +2818,13 @@ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename
2318
2818
  filename,
2319
2819
  bindings
2320
2820
  );
2321
- return transform({ ...branchValue, ...overrides }).className;
2821
+ return transform(
2822
+ applyGlobalVarAliasesToSzObject(
2823
+ { ...branchValue, ...overrides },
2824
+ globalVarAliases,
2825
+ cssVariableMap
2826
+ )
2827
+ ).className;
2322
2828
  } catch (err) {
2323
2829
  if (err instanceof OxcNotImplementedError) {
2324
2830
  return null;
@@ -2326,8 +2832,15 @@ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename
2326
2832
  throw err;
2327
2833
  }
2328
2834
  }
2329
- function buildPartialObjectTransform(node, filename, bindings, source) {
2330
- const partial = evaluatePartialObject(node, filename, bindings, source);
2835
+ function buildPartialObjectTransform(node, filename, bindings, source, options, hoistedNames, cssVariableMap, reservedNames, globalVarAliases = /* @__PURE__ */ new Map()) {
2836
+ const partial = evaluatePartialObject(
2837
+ node,
2838
+ filename,
2839
+ bindings,
2840
+ source,
2841
+ globalVarAliases,
2842
+ cssVariableMap
2843
+ );
2331
2844
  if (!partial || partial.dynamicProps.size === 0 && partial.conditionalClasses.length === 0) {
2332
2845
  return null;
2333
2846
  }
@@ -2336,11 +2849,17 @@ function buildPartialObjectTransform(node, filename, bindings, source) {
2336
2849
  }
2337
2850
  const classParts = [];
2338
2851
  if (Object.keys(partial.staticProps).length > 0) {
2339
- const { className: className2 } = transform(partial.staticProps);
2852
+ const { className: className2 } = transform(
2853
+ applyGlobalVarAliasesToSzObject(partial.staticProps, globalVarAliases, cssVariableMap)
2854
+ );
2340
2855
  if (className2) {
2341
2856
  classParts.push(className2);
2342
2857
  }
2343
2858
  }
2859
+ if (options?.mangleVars) {
2860
+ applyHoistedVariableNames(partial, hoistedNames, cssVariableMap);
2861
+ applyScopedVariablePlan(partial, hoistedNames, cssVariableMap, reservedNames);
2862
+ }
2344
2863
  for (const [, info] of partial.dynamicProps) {
2345
2864
  classParts.push(buildCSSVarClassName(info));
2346
2865
  }
@@ -2349,12 +2868,351 @@ function buildPartialObjectTransform(node, filename, bindings, source) {
2349
2868
  }
2350
2869
  const className = classParts.filter(Boolean).join(" ");
2351
2870
  const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` : `className="${className}"`;
2352
- const styleProps = [...partial.dynamicProps.values()].map(
2353
- (info) => `${JSON.stringify(info.varName)}: ${generateStyleValueSource(info, source)}`
2871
+ const styleProps = [...partial.dynamicProps.entries()].filter(([id]) => !hoistedNames?.has(id)).map(
2872
+ ([, info]) => `${JSON.stringify(info.varName)}: ${generateStyleValueSource(info, source)}`
2354
2873
  );
2355
2874
  return { className, classNameAttr, styleProps, usesColorVar: partial.usesColorVar };
2356
2875
  }
2357
- function evaluatePartialObject(node, filename, bindings, source, variantChain = "") {
2876
+ function applyHoistedVariableNames(partial, hoistedNames, cssVariableMap) {
2877
+ if (!hoistedNames) {
2878
+ return;
2879
+ }
2880
+ for (const [id, name] of hoistedNames) {
2881
+ const info = partial.dynamicProps.get(id);
2882
+ if (info) {
2883
+ addCssVariableMapping(cssVariableMap, info.varName, name);
2884
+ info.varName = name;
2885
+ }
2886
+ }
2887
+ }
2888
+ function applyScopedVariablePlan(partial, hoistedNames, cssVariableMap, reservedNames) {
2889
+ const entries = [...partial.dynamicProps.entries()].filter(([id]) => !hoistedNames?.has(id));
2890
+ const plan = planCSSVariableNames(
2891
+ entries.map(([id]) => ({
2892
+ id,
2893
+ tier: "scoped",
2894
+ elementId: "self",
2895
+ propertyKey: id
2896
+ })),
2897
+ { reservedNames }
2898
+ );
2899
+ for (const planned of plan) {
2900
+ const info = partial.dynamicProps.get(planned.id);
2901
+ if (info) {
2902
+ addCssVariableMapping(cssVariableMap, info.varName, planned.name);
2903
+ info.varName = planned.name;
2904
+ }
2905
+ }
2906
+ }
2907
+ function addCssVariableMapping(cssVariableMap, original, mangled) {
2908
+ if (!cssVariableMap) {
2909
+ return;
2910
+ }
2911
+ const existing = cssVariableMap.get(original);
2912
+ if (!existing) {
2913
+ cssVariableMap.set(original, mangled);
2914
+ return;
2915
+ }
2916
+ const values = Array.isArray(existing) ? existing : [existing];
2917
+ if (!values.includes(mangled)) {
2918
+ cssVariableMap.set(original, [...values, mangled]);
2919
+ }
2920
+ }
2921
+ function normalizeGlobalVarAliases$1(input) {
2922
+ if (!input) {
2923
+ return /* @__PURE__ */ new Map();
2924
+ }
2925
+ const entries = input instanceof Map ? input.entries() : Array.isArray(input) ? input : Object.entries(input);
2926
+ const aliases = /* @__PURE__ */ new Map();
2927
+ for (const [original, alias] of entries) {
2928
+ if (original.startsWith("--") && alias.startsWith("--")) {
2929
+ aliases.set(original, alias);
2930
+ }
2931
+ }
2932
+ return aliases;
2933
+ }
2934
+ function applyGlobalVarAliasesToSzObject(object, globalVarAliases, cssVariableMap) {
2935
+ if (globalVarAliases.size === 0) {
2936
+ return object;
2937
+ }
2938
+ const rewritten = {};
2939
+ for (const [key, value] of Object.entries(object)) {
2940
+ rewritten[key] = applyGlobalVarAliasesToSzValue(value, globalVarAliases, cssVariableMap);
2941
+ }
2942
+ return rewritten;
2943
+ }
2944
+ function applyGlobalVarAliasesToSzValue(value, globalVarAliases, cssVariableMap) {
2945
+ if (typeof value === "string") {
2946
+ const alias = globalVarAliases.get(value);
2947
+ if (alias) {
2948
+ addCssVariableMapping(cssVariableMap, value, alias);
2949
+ return alias;
2950
+ }
2951
+ return value;
2952
+ }
2953
+ if (typeof value === "object") {
2954
+ return applyGlobalVarAliasesToSzObject(value, globalVarAliases, cssVariableMap);
2955
+ }
2956
+ return value;
2957
+ }
2958
+ function planOxcComponentVariableHoists(root, filename, bindings, source, maxDepth, reservedNames) {
2959
+ const nodes = [];
2960
+ const candidates = [];
2961
+ collectOxcHoistCandidates(root, null, nodes, candidates, filename, bindings, source);
2962
+ if (candidates.length < 2) {
2963
+ return {
2964
+ stylePropsByTarget: /* @__PURE__ */ new Map(),
2965
+ usageNamesByElement: /* @__PURE__ */ new Map(),
2966
+ diagnostics: []
2967
+ };
2968
+ }
2969
+ const plannedNames = planCSSVariableNames(
2970
+ candidates.map((candidate) => ({
2971
+ id: candidate.id,
2972
+ tier: "component",
2973
+ elementId: candidate.elementId,
2974
+ propertyKey: candidate.propertyKey,
2975
+ variantChain: candidate.variantChain || void 0
2976
+ })),
2977
+ { reservedNames }
2978
+ );
2979
+ const nameByUsage = new Map(plannedNames.map((entry) => [entry.id, entry.name]));
2980
+ const candidateById = new Map(candidates.map((candidate) => [candidate.id, candidate]));
2981
+ const hoistUsages = candidates.map((candidate) => ({
2982
+ id: candidate.id,
2983
+ elementId: candidate.elementId,
2984
+ name: nameByUsage.get(candidate.id) ?? candidate.info.varName,
2985
+ valueKey: candidate.valueKey
2986
+ }));
2987
+ const analysis = planComponentVariableHoistsWithDiagnostics(nodes, hoistUsages, {
2988
+ maxDepth
2989
+ });
2990
+ const plans = analysis.plans;
2991
+ const stylePropsByTarget = /* @__PURE__ */ new Map();
2992
+ const usageNamesByElement = /* @__PURE__ */ new Map();
2993
+ for (const plan of plans) {
2994
+ const [firstUsageId] = plan.usageIds;
2995
+ const firstCandidate = firstUsageId ? candidateById.get(firstUsageId) : void 0;
2996
+ if (!firstCandidate) {
2997
+ continue;
2998
+ }
2999
+ appendMapArray(
3000
+ stylePropsByTarget,
3001
+ plan.targetElementId,
3002
+ `${JSON.stringify(plan.name)}: ${firstCandidate.valueSource}`
3003
+ );
3004
+ for (const usageId of plan.usageIds) {
3005
+ const candidate = candidateById.get(usageId);
3006
+ if (!candidate) {
3007
+ continue;
3008
+ }
3009
+ getOrCreateMap(usageNamesByElement, candidate.elementId).set(
3010
+ candidate.dynamicKey,
3011
+ plan.name
3012
+ );
3013
+ }
3014
+ }
3015
+ return {
3016
+ stylePropsByTarget,
3017
+ usageNamesByElement,
3018
+ diagnostics: analysis.diagnostics.map(formatHoistSkipDiagnostic)
3019
+ };
3020
+ }
3021
+ function formatHoistSkipDiagnostic(diagnostic) {
3022
+ const suffix = diagnostic.reason === "max-depth" && diagnostic.maxDepth !== void 0 ? ` (maxDepth ${diagnostic.maxDepth})` : "";
3023
+ return `[csszyx] mangleVars skipped component CSS variable hoist for ${diagnostic.name} across ${diagnostic.usageCount} usages: ${diagnostic.reason}${suffix}`;
3024
+ }
3025
+ function collectOxcHoistCandidates(node, parentElementId, nodes, candidates, filename, bindings, source) {
3026
+ if (node.type === "JSXElement") {
3027
+ const element = node;
3028
+ const opening = element.openingElement;
3029
+ const elementId = elementIdForOpening(opening);
3030
+ nodes.push({
3031
+ id: elementId,
3032
+ parentId: parentElementId,
3033
+ canHost: canHostHoistedStyleProps(opening)
3034
+ });
3035
+ collectOpeningHoistCandidates(opening, elementId, candidates, filename, bindings, source);
3036
+ for (const child of element.children) {
3037
+ collectOxcHoistCandidates(
3038
+ child,
3039
+ elementId,
3040
+ nodes,
3041
+ candidates,
3042
+ filename,
3043
+ bindings,
3044
+ source
3045
+ );
3046
+ }
3047
+ return;
3048
+ }
3049
+ if (node.type === "JSXFragment") {
3050
+ const fragment = node;
3051
+ const elementId = `f${node.start}`;
3052
+ nodes.push({ id: elementId, parentId: parentElementId, canHost: false });
3053
+ for (const child of fragment.children) {
3054
+ collectOxcHoistCandidates(
3055
+ child,
3056
+ elementId,
3057
+ nodes,
3058
+ candidates,
3059
+ filename,
3060
+ bindings,
3061
+ source
3062
+ );
3063
+ }
3064
+ return;
3065
+ }
3066
+ for (const key of Object.keys(node)) {
3067
+ if (isAstMetadataKey(key)) {
3068
+ continue;
3069
+ }
3070
+ const child = node[key];
3071
+ if (Array.isArray(child)) {
3072
+ for (const item of child) {
3073
+ if (isOxcNode(item)) {
3074
+ collectOxcHoistCandidates(
3075
+ item,
3076
+ parentElementId,
3077
+ nodes,
3078
+ candidates,
3079
+ filename,
3080
+ bindings,
3081
+ source
3082
+ );
3083
+ }
3084
+ }
3085
+ } else if (isOxcNode(child)) {
3086
+ collectOxcHoistCandidates(
3087
+ child,
3088
+ parentElementId,
3089
+ nodes,
3090
+ candidates,
3091
+ filename,
3092
+ bindings,
3093
+ source
3094
+ );
3095
+ }
3096
+ }
3097
+ }
3098
+ function collectOpeningHoistCandidates(opening, elementId, candidates, filename, bindings, source) {
3099
+ for (const attrRaw of opening.attributes ?? []) {
3100
+ if (attrRaw.type !== "JSXAttribute") {
3101
+ continue;
3102
+ }
3103
+ const attr = attrRaw;
3104
+ if (attr.name?.name !== "sz" || attr.value?.type !== "JSXExpressionContainer") {
3105
+ continue;
3106
+ }
3107
+ const expression = attr.value.expression;
3108
+ if (expression.type !== "ObjectExpression") {
3109
+ continue;
3110
+ }
3111
+ const partial = evaluatePartialObject(
3112
+ expression,
3113
+ filename,
3114
+ bindings,
3115
+ source,
3116
+ /* @__PURE__ */ new Map(),
3117
+ void 0
3118
+ );
3119
+ if (!partial || partial.conditionalClasses.length > 0) {
3120
+ continue;
3121
+ }
3122
+ for (const [dynamicKey, info] of partial.dynamicProps) {
3123
+ candidates.push({
3124
+ id: `${elementId}:${dynamicKey}`,
3125
+ elementId,
3126
+ dynamicKey,
3127
+ propertyKey: dynamicKey,
3128
+ variantChain: info.variantChain,
3129
+ valueSource: generateStyleValueSource(info, source),
3130
+ valueKey: buildDynamicValueKey(info, source),
3131
+ info
3132
+ });
3133
+ }
3134
+ }
3135
+ }
3136
+ function elementIdForOpening(opening) {
3137
+ return `e${opening.start}`;
3138
+ }
3139
+ function canHostHoistedStyleProps(opening) {
3140
+ if (!isDomJsxOpening(opening)) {
3141
+ return false;
3142
+ }
3143
+ const styleAttr = findJsxAttribute(opening, "style");
3144
+ return !styleAttr || styleAttr.value?.type === "JSXExpressionContainer";
3145
+ }
3146
+ function isDomJsxOpening(opening) {
3147
+ if (opening.name.type !== "JSXIdentifier") {
3148
+ return false;
3149
+ }
3150
+ const name = String(opening.name.name);
3151
+ return name.length > 0 && name.charAt(0) === name.charAt(0).toLowerCase();
3152
+ }
3153
+ function findJsxAttribute(opening, name) {
3154
+ for (const attrRaw of opening.attributes ?? []) {
3155
+ if (attrRaw.type === "JSXAttribute") {
3156
+ const attr = attrRaw;
3157
+ if (attr.name?.name === name) {
3158
+ return attr;
3159
+ }
3160
+ }
3161
+ }
3162
+ return null;
3163
+ }
3164
+ function collectStaticStyleCustomPropertyNames(node) {
3165
+ const names = /* @__PURE__ */ new Set();
3166
+ walk(node, (child) => {
3167
+ if (child.type !== "JSXOpeningElement") {
3168
+ return;
3169
+ }
3170
+ const styleAttr = findJsxAttribute(child, "style");
3171
+ if (styleAttr?.value?.type !== "JSXExpressionContainer") {
3172
+ return;
3173
+ }
3174
+ const expression = styleAttr.value.expression;
3175
+ if (expression.type !== "ObjectExpression") {
3176
+ return;
3177
+ }
3178
+ for (const propRaw of expression.properties ?? []) {
3179
+ if (propRaw.type !== "Property") {
3180
+ continue;
3181
+ }
3182
+ const key = propRaw.key;
3183
+ const name = literalStringValue(key);
3184
+ if (name?.startsWith("--")) {
3185
+ names.add(name);
3186
+ }
3187
+ }
3188
+ });
3189
+ return names;
3190
+ }
3191
+ function literalStringValue(node) {
3192
+ if (node.type !== "Literal") {
3193
+ return null;
3194
+ }
3195
+ const value = node.value;
3196
+ return typeof value === "string" ? value : null;
3197
+ }
3198
+ function appendMapArray(map, key, value) {
3199
+ const existing = map.get(key);
3200
+ if (existing) {
3201
+ existing.push(value);
3202
+ } else {
3203
+ map.set(key, [value]);
3204
+ }
3205
+ }
3206
+ function getOrCreateMap(map, key) {
3207
+ const existing = map.get(key);
3208
+ if (existing) {
3209
+ return existing;
3210
+ }
3211
+ const value = /* @__PURE__ */ new Map();
3212
+ map.set(key, value);
3213
+ return value;
3214
+ }
3215
+ function evaluatePartialObject(node, filename, bindings, source, globalVarAliases, cssVariableMap, variantChain = "") {
2358
3216
  const staticProps = {};
2359
3217
  const dynamicProps = /* @__PURE__ */ new Map();
2360
3218
  const conditionalClasses = [];
@@ -2411,6 +3269,8 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2411
3269
  filename,
2412
3270
  bindings,
2413
3271
  source,
3272
+ globalVarAliases,
3273
+ cssVariableMap,
2414
3274
  nestedVariant
2415
3275
  );
2416
3276
  if (!nested) {
@@ -2431,8 +3291,20 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2431
3291
  const consequent = extractStaticLiteralValue(conditional.consequent);
2432
3292
  const alternate = extractStaticLiteralValue(conditional.alternate);
2433
3293
  if (consequent !== null && alternate !== null) {
2434
- const { className: consequentClasses } = transform({ [key]: consequent });
2435
- const { className: alternateClasses } = transform({ [key]: alternate });
3294
+ const { className: consequentClasses } = transform(
3295
+ applyGlobalVarAliasesToSzObject(
3296
+ { [key]: consequent },
3297
+ globalVarAliases,
3298
+ cssVariableMap
3299
+ )
3300
+ );
3301
+ const { className: alternateClasses } = transform(
3302
+ applyGlobalVarAliasesToSzObject(
3303
+ { [key]: alternate },
3304
+ globalVarAliases,
3305
+ cssVariableMap
3306
+ )
3307
+ );
2436
3308
  conditionalClasses.push({
2437
3309
  test: conditional.test,
2438
3310
  consequent: prefixVariantClasses(consequentClasses, variantChain),
@@ -2461,14 +3333,15 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2461
3333
  }
2462
3334
  return { staticProps, dynamicProps, conditionalClasses, usesColorVar };
2463
3335
  }
2464
- function applyStyleProps(edits, source, styleAttr, lastAttr, styleProps) {
3336
+ function applyStyleProps(edits, source, styleAttr, lastAttr, styleProps, fallbackInsertOffset) {
2465
3337
  if (styleProps.length === 0) {
2466
3338
  return;
2467
3339
  }
2468
3340
  const propsSource = styleProps.join(", ");
2469
3341
  if (!styleAttr) {
2470
- if (lastAttr) {
2471
- edits.appendRight(lastAttr.end, ` style={{${propsSource}}}`);
3342
+ const insertOffset = lastAttr?.end ?? fallbackInsertOffset;
3343
+ if (insertOffset !== void 0) {
3344
+ edits.appendRight(insertOffset, ` style={{${propsSource}}}`);
2472
3345
  }
2473
3346
  return;
2474
3347
  }
@@ -2494,6 +3367,67 @@ function generateStyleValueSource(info, source) {
2494
3367
  return `\`\${${expressionSource}}\``;
2495
3368
  }
2496
3369
  }
3370
+ function buildDynamicValueKey(info, source) {
3371
+ const expressionSource = normalizeDynamicExpressionKey(
3372
+ source.slice(info.expression.start, info.expression.end)
3373
+ );
3374
+ switch (info.category) {
3375
+ case PropertyCategory.SPACING:
3376
+ return `spacing:${expressionSource}`;
3377
+ case PropertyCategory.COLOR:
3378
+ return `color:${expressionSource}`;
3379
+ case PropertyCategory.ANGLE:
3380
+ return `angle:${expressionSource}`;
3381
+ case PropertyCategory.DURATION:
3382
+ return `duration:${expressionSource}`;
3383
+ default:
3384
+ return `pass:${expressionSource}`;
3385
+ }
3386
+ }
3387
+ function normalizeDynamicExpressionKey(expressionSource) {
3388
+ let normalized = expressionSource.trim();
3389
+ while (hasRedundantOuterParens(normalized)) {
3390
+ normalized = normalized.slice(1, -1).trim();
3391
+ }
3392
+ return normalized;
3393
+ }
3394
+ function hasRedundantOuterParens(expressionSource) {
3395
+ if (!expressionSource.startsWith("(") || !expressionSource.endsWith(")")) {
3396
+ return false;
3397
+ }
3398
+ let depth = 0;
3399
+ let quote = null;
3400
+ let escaped = false;
3401
+ for (let index = 0; index < expressionSource.length; index++) {
3402
+ const char = expressionSource[index];
3403
+ if (quote) {
3404
+ if (escaped) {
3405
+ escaped = false;
3406
+ } else if (char === "\\") {
3407
+ escaped = true;
3408
+ } else if (char === quote) {
3409
+ quote = null;
3410
+ }
3411
+ continue;
3412
+ }
3413
+ if (char === '"' || char === "'" || char === "`") {
3414
+ quote = char;
3415
+ continue;
3416
+ }
3417
+ if (char === "(") {
3418
+ depth++;
3419
+ } else if (char === ")") {
3420
+ depth--;
3421
+ if (depth === 0 && index !== expressionSource.length - 1) {
3422
+ return false;
3423
+ }
3424
+ }
3425
+ if (depth < 0) {
3426
+ return false;
3427
+ }
3428
+ }
3429
+ return depth === 0;
3430
+ }
2497
3431
  function buildCSSVarClassName(info) {
2498
3432
  const variantPrefix = info.variantChain ? `${getVariantPrefix(info.variantChain)}:` : "";
2499
3433
  return `${variantPrefix}${info.twPrefix}-(${info.varName})`;
@@ -2526,9 +3460,21 @@ function prefixVariantClasses(className, variantChain) {
2526
3460
  function isRuntimeExpression(node) {
2527
3461
  return node.type === "Identifier" || node.type === "MemberExpression" || node.type === "CallExpression" || node.type === "ConditionalExpression" || node.type === "TemplateLiteral" || node.type === "BinaryExpression" || node.type === "LogicalExpression";
2528
3462
  }
2529
- function buildStaticConditionalClassExpression(node, filename, bindings, source, classes) {
2530
- const consequent = resolveStaticClassString(node.consequent, filename, bindings);
2531
- const alternate = resolveStaticClassString(node.alternate, filename, bindings);
3463
+ function buildStaticConditionalClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
3464
+ const consequent = resolveStaticClassString(
3465
+ node.consequent,
3466
+ filename,
3467
+ bindings,
3468
+ globalVarAliases,
3469
+ cssVariableMap
3470
+ );
3471
+ const alternate = resolveStaticClassString(
3472
+ node.alternate,
3473
+ filename,
3474
+ bindings,
3475
+ globalVarAliases,
3476
+ cssVariableMap
3477
+ );
2532
3478
  if (consequent === null || alternate === null) {
2533
3479
  return null;
2534
3480
  }
@@ -2540,7 +3486,7 @@ function buildStaticConditionalClassExpression(node, filename, bindings, source,
2540
3486
  const testSource = source.slice(node.test.start, node.test.end);
2541
3487
  return `${testSource} ? ${JSON.stringify(consequent)} : ${JSON.stringify(alternate)}`;
2542
3488
  }
2543
- function resolveStaticClassString(node, filename, bindings) {
3489
+ function resolveStaticClassString(node, filename, bindings, globalVarAliases, cssVariableMap) {
2544
3490
  const unwrapped = unwrapExpression(node);
2545
3491
  let objectNode = null;
2546
3492
  if (unwrapped.type === "ObjectExpression") {
@@ -2552,7 +3498,13 @@ function resolveStaticClassString(node, filename, bindings) {
2552
3498
  return null;
2553
3499
  }
2554
3500
  try {
2555
- return transform(astObjectToSzObject(objectNode, filename, bindings)).className;
3501
+ return transform(
3502
+ applyGlobalVarAliasesToSzObject(
3503
+ astObjectToSzObject(objectNode, filename, bindings),
3504
+ globalVarAliases,
3505
+ cssVariableMap
3506
+ )
3507
+ ).className;
2556
3508
  } catch (err) {
2557
3509
  if (err instanceof OxcNotImplementedError) {
2558
3510
  return null;
@@ -2667,17 +3619,22 @@ function unwrapExpression(node) {
2667
3619
  }
2668
3620
  return current;
2669
3621
  }
3622
+ function isOxcNode(value) {
3623
+ return Boolean(
3624
+ value && typeof value === "object" && typeof value.type === "string"
3625
+ );
3626
+ }
3627
+ function isAstMetadataKey(key) {
3628
+ return key === "loc" || key === "range" || key === "start" || key === "end" || key === "type";
3629
+ }
2670
3630
  function walk(node, visit) {
2671
- if (!node || typeof node !== "object") {
3631
+ if (!isOxcNode(node)) {
2672
3632
  return;
2673
3633
  }
2674
3634
  const typed = node;
2675
- if (typeof typed.type !== "string") {
2676
- return;
2677
- }
2678
3635
  visit(typed);
2679
3636
  for (const key of Object.keys(typed)) {
2680
- if (key === "loc" || key === "range" || key === "start" || key === "end" || key === "type") {
3637
+ if (isAstMetadataKey(key)) {
2681
3638
  continue;
2682
3639
  }
2683
3640
  const child = typed[key];
@@ -2701,7 +3658,7 @@ class OxcRustNotImplementedError extends Error {
2701
3658
  }
2702
3659
  }
2703
3660
  function transformRust(source, filename, options) {
2704
- const [result] = transformRustBatch([{ filename, source }]);
3661
+ const [result] = transformRustBatch([{ filename, source }], options);
2705
3662
  if (!result) {
2706
3663
  throw new OxcRustNotImplementedError("native transform returned no result");
2707
3664
  }
@@ -2728,7 +3685,12 @@ function transformRustBatch(files, options) {
2728
3685
  files.map((file, index) => ({
2729
3686
  filename: file.filename ?? `file-${index}.tsx`,
2730
3687
  source: file.source
2731
- }))
3688
+ })),
3689
+ {
3690
+ mangleVars: options?.mangleVars === true,
3691
+ mangleVarHoistMaxDepth: options?.mangleVarHoistMaxDepth,
3692
+ globalVarAliases: normalizeGlobalVarAliases(options?.globalVarAliases)
3693
+ }
2732
3694
  ).map(fromNativeResult);
2733
3695
  } catch (err) {
2734
3696
  if (err instanceof OxcRustNotImplementedError) {
@@ -2742,6 +3704,13 @@ function transformRustBatch(files, options) {
2742
3704
  throw err;
2743
3705
  }
2744
3706
  }
3707
+ function normalizeGlobalVarAliases(input) {
3708
+ if (!input) {
3709
+ return [];
3710
+ }
3711
+ const entries = input instanceof Map ? input.entries() : Array.isArray(input) ? input : Object.entries(input);
3712
+ return [...entries].filter(([original, alias]) => original.startsWith("--") && alias.startsWith("--")).map(([original, alias]) => ({ original, alias }));
3713
+ }
2745
3714
  function fromNativeResult(result) {
2746
3715
  return {
2747
3716
  code: result.code,
@@ -2761,9 +3730,25 @@ function fromNativeResult(result) {
2761
3730
  path: data.path
2762
3731
  }
2763
3732
  ])
2764
- )
3733
+ ),
3734
+ cssVariableMap: aggregateCssVariableMap(result.cssVariableMap ?? [])
2765
3735
  };
2766
3736
  }
3737
+ function aggregateCssVariableMap(entries) {
3738
+ const map = /* @__PURE__ */ new Map();
3739
+ for (const entry of entries) {
3740
+ const existing = map.get(entry.original);
3741
+ if (!existing) {
3742
+ map.set(entry.original, entry.mangled);
3743
+ continue;
3744
+ }
3745
+ const values = Array.isArray(existing) ? existing : [existing];
3746
+ if (!values.includes(entry.mangled)) {
3747
+ map.set(entry.original, [...values, entry.mangled]);
3748
+ }
3749
+ }
3750
+ return map;
3751
+ }
2767
3752
 
2768
3753
  const VERSION = "0.0.0";
2769
3754
  const DEFAULT_COMPILER_OPTIONS = {
@@ -2778,4 +3763,4 @@ function mergeOptions(options = {}) {
2778
3763
  };
2779
3764
  }
2780
3765
 
2781
- export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, KNOWN_VARIANTS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_MAP, PropertyCategory, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isValidRecoveryMode, mergeOptions, parseManifest, serializeManifest, transform, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };
3766
+ export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, KNOWN_VARIANTS, ManifestBuilder, OxcNotImplementedError, OxcRustNotImplementedError, PROPERTY_MAP, PropertyCategory, VERSION, buildParentMap, createRecoveryToken, ensureRustTransformAvailable, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isValidRecoveryMode, mergeOptions, parseManifest, scanGlobalVarUsages, serializeManifest, transform, transformOxc, transformRust, transformRustBatch, transformSourceCode, validateManifest, validateSzRecover };