@csszyx/compiler 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,11 +1,12 @@
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.BIUVmI0H.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.BIUVmI0H.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.CIBwOKUt.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.CIBwOKUt.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
+ import { transformBatch, CsszyxNativeUnavailableError } from '@csszyx/core/native';
9
10
 
10
11
  const AST_BUDGET = 5e4;
11
12
  class ASTBudgetExceededError extends Error {
@@ -64,6 +65,7 @@ function transformSourceCode(source, filename, options) {
64
65
  const rawClassNames = /* @__PURE__ */ new Set();
65
66
  const diagnostics = [];
66
67
  const recoveryTokens = /* @__PURE__ */ new Map();
68
+ const cssVariableMap = /* @__PURE__ */ new Map();
67
69
  if (!source.includes("sz")) {
68
70
  return {
69
71
  code: source,
@@ -74,7 +76,8 @@ function transformSourceCode(source, filename, options) {
74
76
  classes: collectedClasses,
75
77
  rawClassNames,
76
78
  diagnostics,
77
- recoveryTokens
79
+ recoveryTokens,
80
+ cssVariableMap
78
81
  };
79
82
  }
80
83
  try {
@@ -736,7 +739,8 @@ function transformSourceCode(source, filename, options) {
736
739
  classes: collectedClasses,
737
740
  rawClassNames,
738
741
  diagnostics,
739
- recoveryTokens
742
+ recoveryTokens,
743
+ cssVariableMap
740
744
  };
741
745
  } catch (e) {
742
746
  if (e instanceof ASTBudgetExceededError) {
@@ -752,7 +756,8 @@ function transformSourceCode(source, filename, options) {
752
756
  classes: collectedClasses,
753
757
  rawClassNames,
754
758
  diagnostics,
755
- recoveryTokens
759
+ recoveryTokens,
760
+ cssVariableMap
756
761
  };
757
762
  }
758
763
  }
@@ -1304,6 +1309,271 @@ class CsszyxCompiler {
1304
1309
  }
1305
1310
  }
1306
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
+
1307
1577
  function findLCA(nodeA, nodeB, parentMap) {
1308
1578
  const ancestorsA = /* @__PURE__ */ new Set();
1309
1579
  let current = nodeA;
@@ -1637,6 +1907,155 @@ function injectRecoveryToken(attributes, token) {
1637
1907
  };
1638
1908
  }
1639
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
+
1640
2059
  class OxcNotImplementedError extends Error {
1641
2060
  /**
1642
2061
  * @param slice The Phase D slice expected to implement this path.
@@ -1652,6 +2071,8 @@ function transformOxc(source, filename, options) {
1652
2071
  const rawClassNames = /* @__PURE__ */ new Set();
1653
2072
  const diagnostics = [];
1654
2073
  const recoveryTokens = /* @__PURE__ */ new Map();
2074
+ const cssVariableMap = /* @__PURE__ */ new Map();
2075
+ const globalVarAliases = normalizeGlobalVarAliases$1(options?.globalVarAliases);
1655
2076
  if (!source.includes("sz")) {
1656
2077
  return {
1657
2078
  code: source,
@@ -1662,7 +2083,8 @@ function transformOxc(source, filename, options) {
1662
2083
  classes,
1663
2084
  rawClassNames,
1664
2085
  diagnostics,
1665
- recoveryTokens
2086
+ recoveryTokens,
2087
+ cssVariableMap
1666
2088
  };
1667
2089
  }
1668
2090
  const effectiveFilename = filename ?? "file.tsx";
@@ -1677,6 +2099,18 @@ function transformOxc(source, filename, options) {
1677
2099
  const edits = new MagicString(source);
1678
2100
  const objectBindings = collectObjectBindings(parsed.program);
1679
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
+ }
1680
2114
  let transformed = false;
1681
2115
  let usesRuntime = false;
1682
2116
  let usesMerge = false;
@@ -1702,6 +2136,24 @@ function transformOxc(source, filename, options) {
1702
2136
  let szRecoverAttr = null;
1703
2137
  let alreadyTagged = false;
1704
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
+ };
1705
2157
  for (const attrRaw of attrs) {
1706
2158
  if (attrRaw.type !== "JSXAttribute") {
1707
2159
  continue;
@@ -1762,6 +2214,7 @@ function transformOxc(source, filename, options) {
1762
2214
  }
1763
2215
  }
1764
2216
  if (szAttrs.length === 0) {
2217
+ applyHoistedStyleProps();
1765
2218
  return;
1766
2219
  }
1767
2220
  const szDerived = [];
@@ -1798,7 +2251,9 @@ function transformOxc(source, filename, options) {
1798
2251
  effectiveFilename,
1799
2252
  objectBindings,
1800
2253
  source,
1801
- classes
2254
+ classes,
2255
+ globalVarAliases,
2256
+ cssVariableMap
1802
2257
  );
1803
2258
  if (conditionalClassExpr) {
1804
2259
  if (classNameAttr || szAttrs.length > 1) {
@@ -1820,7 +2275,11 @@ function transformOxc(source, filename, options) {
1820
2275
  const bound = objectBindings.get(identifierName);
1821
2276
  if (bound) {
1822
2277
  const result2 = transform(
1823
- astObjectToSzObject(bound, effectiveFilename, objectBindings)
2278
+ applyGlobalVarAliasesToSzObject(
2279
+ astObjectToSzObject(bound, effectiveFilename, objectBindings),
2280
+ globalVarAliases,
2281
+ cssVariableMap
2282
+ )
1824
2283
  );
1825
2284
  for (const c of result2.className.split(/\s+/)) {
1826
2285
  if (c) {
@@ -1837,7 +2296,9 @@ function transformOxc(source, filename, options) {
1837
2296
  effectiveFilename,
1838
2297
  objectBindings,
1839
2298
  source,
1840
- classes
2299
+ classes,
2300
+ globalVarAliases,
2301
+ cssVariableMap
1841
2302
  );
1842
2303
  if (conditionalClassExpr) {
1843
2304
  if (classNameAttr || szAttrs.length > 1) {
@@ -1859,7 +2320,9 @@ function transformOxc(source, filename, options) {
1859
2320
  const arrayClasses = astArrayToStaticClasses(
1860
2321
  expression,
1861
2322
  effectiveFilename,
1862
- objectBindings
2323
+ objectBindings,
2324
+ globalVarAliases,
2325
+ cssVariableMap
1863
2326
  );
1864
2327
  if (arrayClasses === null) {
1865
2328
  collectArrayCandidateClasses(
@@ -1897,7 +2360,9 @@ function transformOxc(source, filename, options) {
1897
2360
  effectiveFilename,
1898
2361
  objectBindings,
1899
2362
  source,
1900
- classes
2363
+ classes,
2364
+ globalVarAliases,
2365
+ cssVariableMap
1901
2366
  );
1902
2367
  if (conditionalSpreadClassExpr) {
1903
2368
  if (classNameAttr || szAttrs.length > 1) {
@@ -1917,9 +2382,15 @@ function transformOxc(source, filename, options) {
1917
2382
  expression,
1918
2383
  effectiveFilename,
1919
2384
  objectBindings,
1920
- source
2385
+ source,
2386
+ options,
2387
+ componentHoists?.usageNamesByElement.get(elementId),
2388
+ cssVariableMap,
2389
+ reservedCSSVariableNames,
2390
+ globalVarAliases
1921
2391
  );
1922
2392
  if (partial && szAttrs.length === 1) {
2393
+ const mergedStyleProps = hoistedStyleProps.length > 0 ? [...hoistedStyleProps, ...partial.styleProps] : partial.styleProps;
1923
2394
  if (classNameAttr?.value?.type === "JSXExpressionContainer") {
1924
2395
  const classExpression = classNameAttr.value.expression;
1925
2396
  const classExpressionSource = source.slice(
@@ -1932,7 +2403,15 @@ function transformOxc(source, filename, options) {
1932
2403
  `className={_szMerge(${classExpressionSource}, ${JSON.stringify(partial.className)})}`
1933
2404
  );
1934
2405
  edits.remove(whitespaceStart(source, szAttr.start), szAttr.end);
1935
- 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;
1936
2415
  for (const c of partial.className.split(/\s+/)) {
1937
2416
  if (c) {
1938
2417
  classes.add(c);
@@ -1956,7 +2435,15 @@ function transformOxc(source, filename, options) {
1956
2435
  } else {
1957
2436
  edits.overwrite(szAttr.start, szAttr.end, partial.classNameAttr);
1958
2437
  }
1959
- 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;
1960
2447
  for (const c of partial.className.split(/\s+/)) {
1961
2448
  if (c) {
1962
2449
  classes.add(c);
@@ -1972,7 +2459,9 @@ function transformOxc(source, filename, options) {
1972
2459
  }
1973
2460
  throw err;
1974
2461
  }
1975
- const result = transform(szObj);
2462
+ const result = transform(
2463
+ applyGlobalVarAliasesToSzObject(szObj, globalVarAliases, cssVariableMap)
2464
+ );
1976
2465
  for (const c of result.className.split(/\s+/)) {
1977
2466
  if (c) {
1978
2467
  szDerived.push(c);
@@ -2005,6 +2494,7 @@ function transformOxc(source, filename, options) {
2005
2494
  transformed = true;
2006
2495
  return;
2007
2496
  }
2497
+ applyHoistedStyleProps();
2008
2498
  const existingRaw = classNameAttr ? stringLiteralValue(classNameAttr.value) : null;
2009
2499
  const mergedClasses = [
2010
2500
  ...existingRaw ? existingRaw.split(/\s+/).filter(Boolean) : [],
@@ -2039,7 +2529,8 @@ function transformOxc(source, filename, options) {
2039
2529
  classes,
2040
2530
  rawClassNames,
2041
2531
  diagnostics,
2042
- recoveryTokens
2532
+ recoveryTokens,
2533
+ cssVariableMap
2043
2534
  };
2044
2535
  }
2045
2536
  function stringLiteralValue(value) {
@@ -2148,7 +2639,7 @@ function astObjectToSzObject(node, filename, bindings) {
2148
2639
  }
2149
2640
  return result;
2150
2641
  }
2151
- function astArrayToStaticClasses(node, filename, bindings) {
2642
+ function astArrayToStaticClasses(node, filename, bindings, globalVarAliases, cssVariableMap) {
2152
2643
  const out = [];
2153
2644
  for (const element of node.elements) {
2154
2645
  if (!element || isFalsyLiteral(element)) {
@@ -2165,7 +2656,13 @@ function astArrayToStaticClasses(node, filename, bindings) {
2165
2656
  }
2166
2657
  let result;
2167
2658
  try {
2168
- result = transform(astObjectToSzObject(objectNode, filename, bindings));
2659
+ result = transform(
2660
+ applyGlobalVarAliasesToSzObject(
2661
+ astObjectToSzObject(objectNode, filename, bindings),
2662
+ globalVarAliases,
2663
+ cssVariableMap
2664
+ )
2665
+ );
2169
2666
  } catch (err) {
2170
2667
  if (err instanceof OxcNotImplementedError) {
2171
2668
  return null;
@@ -2262,7 +2759,7 @@ function resolveObjectExpression(node, bindings) {
2262
2759
  }
2263
2760
  return null;
2264
2761
  }
2265
- function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes) {
2762
+ function buildConditionalSpreadClassExpression(node, filename, bindings, source, classes, globalVarAliases, cssVariableMap) {
2266
2763
  let conditionalSpread = null;
2267
2764
  const otherProps = [];
2268
2765
  for (const prop of node.properties) {
@@ -2285,14 +2782,18 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
2285
2782
  otherProps,
2286
2783
  node,
2287
2784
  filename,
2288
- bindings
2785
+ bindings,
2786
+ globalVarAliases,
2787
+ cssVariableMap
2289
2788
  );
2290
2789
  const alternate = compileConditionalSpreadBranch(
2291
2790
  conditionalSpread.alternate,
2292
2791
  otherProps,
2293
2792
  node,
2294
2793
  filename,
2295
- bindings
2794
+ bindings,
2795
+ globalVarAliases,
2796
+ cssVariableMap
2296
2797
  );
2297
2798
  if (consequent === null || alternate === null) {
2298
2799
  return null;
@@ -2305,7 +2806,7 @@ function buildConditionalSpreadClassExpression(node, filename, bindings, source,
2305
2806
  const testSource = source.slice(conditionalSpread.test.start, conditionalSpread.test.end);
2306
2807
  return `${testSource} ? ${JSON.stringify(consequent)} : ${JSON.stringify(alternate)}`;
2307
2808
  }
2308
- function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings) {
2809
+ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename, bindings, globalVarAliases, cssVariableMap) {
2309
2810
  const branchObject = resolveObjectExpression(branch, bindings);
2310
2811
  if (!branchObject) {
2311
2812
  return null;
@@ -2317,7 +2818,13 @@ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename
2317
2818
  filename,
2318
2819
  bindings
2319
2820
  );
2320
- return transform({ ...branchValue, ...overrides }).className;
2821
+ return transform(
2822
+ applyGlobalVarAliasesToSzObject(
2823
+ { ...branchValue, ...overrides },
2824
+ globalVarAliases,
2825
+ cssVariableMap
2826
+ )
2827
+ ).className;
2321
2828
  } catch (err) {
2322
2829
  if (err instanceof OxcNotImplementedError) {
2323
2830
  return null;
@@ -2325,8 +2832,15 @@ function compileConditionalSpreadBranch(branch, otherProps, sourceNode, filename
2325
2832
  throw err;
2326
2833
  }
2327
2834
  }
2328
- function buildPartialObjectTransform(node, filename, bindings, source) {
2329
- 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
+ );
2330
2844
  if (!partial || partial.dynamicProps.size === 0 && partial.conditionalClasses.length === 0) {
2331
2845
  return null;
2332
2846
  }
@@ -2335,11 +2849,17 @@ function buildPartialObjectTransform(node, filename, bindings, source) {
2335
2849
  }
2336
2850
  const classParts = [];
2337
2851
  if (Object.keys(partial.staticProps).length > 0) {
2338
- const { className: className2 } = transform(partial.staticProps);
2852
+ const { className: className2 } = transform(
2853
+ applyGlobalVarAliasesToSzObject(partial.staticProps, globalVarAliases, cssVariableMap)
2854
+ );
2339
2855
  if (className2) {
2340
2856
  classParts.push(className2);
2341
2857
  }
2342
2858
  }
2859
+ if (options?.mangleVars) {
2860
+ applyHoistedVariableNames(partial, hoistedNames, cssVariableMap);
2861
+ applyScopedVariablePlan(partial, hoistedNames, cssVariableMap, reservedNames);
2862
+ }
2343
2863
  for (const [, info] of partial.dynamicProps) {
2344
2864
  classParts.push(buildCSSVarClassName(info));
2345
2865
  }
@@ -2348,12 +2868,351 @@ function buildPartialObjectTransform(node, filename, bindings, source) {
2348
2868
  }
2349
2869
  const className = classParts.filter(Boolean).join(" ");
2350
2870
  const classNameAttr = partial.conditionalClasses.length > 0 ? `className={${buildConditionalClassSource(classParts, partial.conditionalClasses, source)}}` : `className="${className}"`;
2351
- const styleProps = [...partial.dynamicProps.values()].map(
2352
- (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)}`
2353
2873
  );
2354
2874
  return { className, classNameAttr, styleProps, usesColorVar: partial.usesColorVar };
2355
2875
  }
2356
- 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 = "") {
2357
3216
  const staticProps = {};
2358
3217
  const dynamicProps = /* @__PURE__ */ new Map();
2359
3218
  const conditionalClasses = [];
@@ -2410,6 +3269,8 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2410
3269
  filename,
2411
3270
  bindings,
2412
3271
  source,
3272
+ globalVarAliases,
3273
+ cssVariableMap,
2413
3274
  nestedVariant
2414
3275
  );
2415
3276
  if (!nested) {
@@ -2430,8 +3291,20 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2430
3291
  const consequent = extractStaticLiteralValue(conditional.consequent);
2431
3292
  const alternate = extractStaticLiteralValue(conditional.alternate);
2432
3293
  if (consequent !== null && alternate !== null) {
2433
- const { className: consequentClasses } = transform({ [key]: consequent });
2434
- 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
+ );
2435
3308
  conditionalClasses.push({
2436
3309
  test: conditional.test,
2437
3310
  consequent: prefixVariantClasses(consequentClasses, variantChain),
@@ -2460,14 +3333,15 @@ function evaluatePartialObject(node, filename, bindings, source, variantChain =
2460
3333
  }
2461
3334
  return { staticProps, dynamicProps, conditionalClasses, usesColorVar };
2462
3335
  }
2463
- function applyStyleProps(edits, source, styleAttr, lastAttr, styleProps) {
3336
+ function applyStyleProps(edits, source, styleAttr, lastAttr, styleProps, fallbackInsertOffset) {
2464
3337
  if (styleProps.length === 0) {
2465
3338
  return;
2466
3339
  }
2467
3340
  const propsSource = styleProps.join(", ");
2468
3341
  if (!styleAttr) {
2469
- if (lastAttr) {
2470
- edits.appendRight(lastAttr.end, ` style={{${propsSource}}}`);
3342
+ const insertOffset = lastAttr?.end ?? fallbackInsertOffset;
3343
+ if (insertOffset !== void 0) {
3344
+ edits.appendRight(insertOffset, ` style={{${propsSource}}}`);
2471
3345
  }
2472
3346
  return;
2473
3347
  }
@@ -2493,6 +3367,67 @@ function generateStyleValueSource(info, source) {
2493
3367
  return `\`\${${expressionSource}}\``;
2494
3368
  }
2495
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
+ }
2496
3431
  function buildCSSVarClassName(info) {
2497
3432
  const variantPrefix = info.variantChain ? `${getVariantPrefix(info.variantChain)}:` : "";
2498
3433
  return `${variantPrefix}${info.twPrefix}-(${info.varName})`;
@@ -2525,9 +3460,21 @@ function prefixVariantClasses(className, variantChain) {
2525
3460
  function isRuntimeExpression(node) {
2526
3461
  return node.type === "Identifier" || node.type === "MemberExpression" || node.type === "CallExpression" || node.type === "ConditionalExpression" || node.type === "TemplateLiteral" || node.type === "BinaryExpression" || node.type === "LogicalExpression";
2527
3462
  }
2528
- function buildStaticConditionalClassExpression(node, filename, bindings, source, classes) {
2529
- const consequent = resolveStaticClassString(node.consequent, filename, bindings);
2530
- 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
+ );
2531
3478
  if (consequent === null || alternate === null) {
2532
3479
  return null;
2533
3480
  }
@@ -2539,7 +3486,7 @@ function buildStaticConditionalClassExpression(node, filename, bindings, source,
2539
3486
  const testSource = source.slice(node.test.start, node.test.end);
2540
3487
  return `${testSource} ? ${JSON.stringify(consequent)} : ${JSON.stringify(alternate)}`;
2541
3488
  }
2542
- function resolveStaticClassString(node, filename, bindings) {
3489
+ function resolveStaticClassString(node, filename, bindings, globalVarAliases, cssVariableMap) {
2543
3490
  const unwrapped = unwrapExpression(node);
2544
3491
  let objectNode = null;
2545
3492
  if (unwrapped.type === "ObjectExpression") {
@@ -2551,7 +3498,13 @@ function resolveStaticClassString(node, filename, bindings) {
2551
3498
  return null;
2552
3499
  }
2553
3500
  try {
2554
- return transform(astObjectToSzObject(objectNode, filename, bindings)).className;
3501
+ return transform(
3502
+ applyGlobalVarAliasesToSzObject(
3503
+ astObjectToSzObject(objectNode, filename, bindings),
3504
+ globalVarAliases,
3505
+ cssVariableMap
3506
+ )
3507
+ ).className;
2555
3508
  } catch (err) {
2556
3509
  if (err instanceof OxcNotImplementedError) {
2557
3510
  return null;
@@ -2666,17 +3619,22 @@ function unwrapExpression(node) {
2666
3619
  }
2667
3620
  return current;
2668
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
+ }
2669
3630
  function walk(node, visit) {
2670
- if (!node || typeof node !== "object") {
3631
+ if (!isOxcNode(node)) {
2671
3632
  return;
2672
3633
  }
2673
3634
  const typed = node;
2674
- if (typeof typed.type !== "string") {
2675
- return;
2676
- }
2677
3635
  visit(typed);
2678
3636
  for (const key of Object.keys(typed)) {
2679
- if (key === "loc" || key === "range" || key === "start" || key === "end" || key === "type") {
3637
+ if (isAstMetadataKey(key)) {
2680
3638
  continue;
2681
3639
  }
2682
3640
  const child = typed[key];
@@ -2690,6 +3648,108 @@ function walk(node, visit) {
2690
3648
  }
2691
3649
  }
2692
3650
 
3651
+ class OxcRustNotImplementedError extends Error {
3652
+ /**
3653
+ * @param detail Native loader or transform failure detail.
3654
+ */
3655
+ constructor(detail) {
3656
+ super(`transformRust: native engine unavailable - ${detail}`);
3657
+ this.name = "OxcRustNotImplementedError";
3658
+ }
3659
+ }
3660
+ function transformRust(source, filename, options) {
3661
+ const [result] = transformRustBatch([{ filename, source }], options);
3662
+ if (!result) {
3663
+ throw new OxcRustNotImplementedError("native transform returned no result");
3664
+ }
3665
+ return result;
3666
+ }
3667
+ function ensureRustTransformAvailable() {
3668
+ try {
3669
+ transformBatch([]);
3670
+ } catch (err) {
3671
+ if (err instanceof OxcRustNotImplementedError) {
3672
+ throw err;
3673
+ }
3674
+ if (err instanceof CsszyxNativeUnavailableError) {
3675
+ throw new OxcRustNotImplementedError(
3676
+ `${err.message}; native package: ${err.packageName ?? "unsupported platform"}`
3677
+ );
3678
+ }
3679
+ throw err;
3680
+ }
3681
+ }
3682
+ function transformRustBatch(files, options) {
3683
+ try {
3684
+ return transformBatch(
3685
+ files.map((file, index) => ({
3686
+ filename: file.filename ?? `file-${index}.tsx`,
3687
+ source: file.source
3688
+ })),
3689
+ {
3690
+ mangleVars: options?.mangleVars === true,
3691
+ mangleVarHoistMaxDepth: options?.mangleVarHoistMaxDepth,
3692
+ globalVarAliases: normalizeGlobalVarAliases(options?.globalVarAliases)
3693
+ }
3694
+ ).map(fromNativeResult);
3695
+ } catch (err) {
3696
+ if (err instanceof OxcRustNotImplementedError) {
3697
+ throw err;
3698
+ }
3699
+ if (err instanceof CsszyxNativeUnavailableError) {
3700
+ throw new OxcRustNotImplementedError(
3701
+ `${err.message}; native package: ${err.packageName ?? "unsupported platform"}`
3702
+ );
3703
+ }
3704
+ throw err;
3705
+ }
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
+ }
3714
+ function fromNativeResult(result) {
3715
+ return {
3716
+ code: result.code,
3717
+ transformed: result.metadata.transformed,
3718
+ usesRuntime: result.metadata.usesRuntime,
3719
+ usesMerge: result.metadata.usesMerge,
3720
+ usesColorVar: result.metadata.usesColorVar,
3721
+ classes: new Set(result.classes),
3722
+ rawClassNames: new Set(result.rawClassNames),
3723
+ diagnostics: result.diagnostics,
3724
+ recoveryTokens: new Map(
3725
+ result.recoveryTokens.map(({ token, ...data }) => [
3726
+ token,
3727
+ {
3728
+ mode: data.mode,
3729
+ component: data.component,
3730
+ path: data.path
3731
+ }
3732
+ ])
3733
+ ),
3734
+ cssVariableMap: aggregateCssVariableMap(result.cssVariableMap ?? [])
3735
+ };
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
+ }
3752
+
2693
3753
  const VERSION = "0.0.0";
2694
3754
  const DEFAULT_COMPILER_OPTIONS = {
2695
3755
  buildId: Date.now().toString(),
@@ -2703,4 +3763,4 @@ function mergeOptions(options = {}) {
2703
3763
  };
2704
3764
  }
2705
3765
 
2706
- export { COLOR_PROPERTIES, CsszyxCompiler, DEFAULT_COMPILER_OPTIONS, KNOWN_VARIANTS, ManifestBuilder, OxcNotImplementedError, PROPERTY_MAP, PropertyCategory, VERSION, buildParentMap, createRecoveryToken, generateRecoveryToken, getCSSVariableName, getPropertyCategory, hoistCSSVariables, injectRecoveryToken, isValidRecoveryMode, mergeOptions, parseManifest, serializeManifest, transform, transformOxc, 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 };