@homebound/truss 2.0.3 → 2.0.5

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.
@@ -1238,6 +1238,13 @@ import _generate from "@babel/generator";
1238
1238
  import * as t3 from "@babel/types";
1239
1239
  var generate = _generate.default ?? _generate;
1240
1240
  var traverse = _traverse.default ?? _traverse;
1241
+ function formatDroppedPropertyKey(prop) {
1242
+ if (t3.isObjectProperty(prop)) {
1243
+ if (t3.isIdentifier(prop.key)) return prop.key.name;
1244
+ if (t3.isStringLiteral(prop.key)) return prop.key.value;
1245
+ }
1246
+ return formatNodeSnippet(prop);
1247
+ }
1241
1248
  function rewriteExpressionSites(options) {
1242
1249
  for (const site of options.sites) {
1243
1250
  const propsArgs = buildPropsArgsFromChain(site.resolvedChain, options);
@@ -1259,8 +1266,18 @@ function rewriteExpressionSites(options) {
1259
1266
  }
1260
1267
  site.path.replaceWith(buildStyleArrayExpression(propsArgs, site.path.node.loc?.start.line ?? null, options));
1261
1268
  }
1262
- rewriteCssSpreadCalls(options.ast, options.cssBindingName);
1263
- rewriteStyleObjectExpressions(options.ast);
1269
+ rewriteCssSpreadCalls(
1270
+ options.ast,
1271
+ options.cssBindingName,
1272
+ options.asStyleArrayHelperName,
1273
+ options.needsAsStyleArrayHelper
1274
+ );
1275
+ rewriteStyleObjectExpressions(
1276
+ options.ast,
1277
+ options.skippedCssPropMessages,
1278
+ options.asStyleArrayHelperName,
1279
+ options.needsAsStyleArrayHelper
1280
+ );
1264
1281
  rewriteCssAttributeExpressions(
1265
1282
  options.ast,
1266
1283
  options.filename,
@@ -1451,7 +1468,7 @@ function isCssRewriteableExpression(expr, path) {
1451
1468
  return !!lowerCssExpressionToPropsArgs(expr, path, "asStyleArray", { current: false });
1452
1469
  }
1453
1470
  function lowerCssExpressionToPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1454
- return buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) ?? buildStyleArrayLikePropsArgsFromExpression(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) ?? buildUnknownCssValuePropsArgs(expr, asStyleArrayHelperName, needsAsStyleArrayHelper);
1471
+ return buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) ?? buildStyleArrayLikePropsArgsFromExpression(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1455
1472
  }
1456
1473
  function explainSkippedCssRewrite(expr, path) {
1457
1474
  if (t3.isObjectExpression(expr)) {
@@ -1503,26 +1520,28 @@ function removeExistingClassNameAttribute(path) {
1503
1520
  }
1504
1521
  function buildStyleObjectPropsArgs(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1505
1522
  if (!t3.isObjectExpression(expr) || expr.properties.length === 0) return null;
1506
- const propsArgs = [];
1507
- for (const prop of expr.properties) {
1508
- if (!t3.isSpreadElement(prop)) return null;
1509
- const normalizedArg = normalizeStyleArrayLikeExpression(prop.argument, path, /* @__PURE__ */ new Set());
1510
- if (!normalizedArg) {
1511
- propsArgs.push(
1512
- t3.spreadElement(
1513
- buildUnknownObjectSpreadFallback(prop.argument, asStyleArrayHelperName, needsAsStyleArrayHelper)
1514
- )
1515
- );
1516
- continue;
1517
- }
1518
- const nestedArgs = buildStyleArrayLikePropsArgs(normalizedArg, path, /* @__PURE__ */ new Set());
1519
- if (nestedArgs && t3.isArrayExpression(normalizedArg)) {
1520
- propsArgs.push(...nestedArgs);
1521
- } else {
1522
- propsArgs.push(t3.spreadElement(buildSafeSpreadArgument(normalizedArg)));
1523
+ const result = collectStyleCompositionEntries(expr, path);
1524
+ if (!result) {
1525
+ if (expr.properties.every(function(prop) {
1526
+ return t3.isSpreadElement(prop);
1527
+ })) {
1528
+ return expr.properties.map(function(prop) {
1529
+ const spread = prop;
1530
+ return t3.spreadElement(
1531
+ buildUnknownObjectSpreadFallback(spread.argument, asStyleArrayHelperName, needsAsStyleArrayHelper)
1532
+ // I.e. `css={{ ...css }}` or `css={{ ...xss }}`
1533
+ );
1534
+ });
1523
1535
  }
1536
+ return null;
1524
1537
  }
1525
- return propsArgs.length > 0 ? propsArgs : null;
1538
+ if (result.droppedPropertyKeys.length > 0) return null;
1539
+ return buildPropsArgsFromStyleCompositionEntries(
1540
+ result.entries,
1541
+ path,
1542
+ asStyleArrayHelperName,
1543
+ needsAsStyleArrayHelper
1544
+ );
1526
1545
  }
1527
1546
  function buildStyleArrayLikePropsArgsFromExpression(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1528
1547
  const normalizedExpr = normalizeStyleArrayLikeExpression(expr, path, /* @__PURE__ */ new Set());
@@ -1559,20 +1578,22 @@ function buildStyleArrayLikePropsArgs(expr, path, seen) {
1559
1578
  }
1560
1579
  return null;
1561
1580
  }
1562
- function buildUnknownCssValuePropsArgs(expr, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1563
- if (!(t3.isIdentifier(expr) || t3.isMemberExpression(expr) || t3.isCallExpression(expr))) return null;
1564
- return [t3.spreadElement(buildUnknownObjectSpreadFallback(expr, asStyleArrayHelperName, needsAsStyleArrayHelper))];
1565
- }
1566
- function rewriteStyleObjectExpressions(ast) {
1581
+ function rewriteStyleObjectExpressions(ast, messages, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1567
1582
  traverse(ast, {
1568
1583
  ObjectExpression(path) {
1569
- const rewritten = tryBuildStyleArrayFromObject(path);
1570
- if (!rewritten) return;
1571
- path.replaceWith(rewritten);
1584
+ const result = tryBuildStyleArrayFromObject(path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1585
+ if (!result.rewritten) return;
1586
+ if (result.droppedPropertyKeys.length > 0) {
1587
+ messages.push({
1588
+ message: `[truss] Unsupported pattern: Dropped non-spread properties from style composition object (${result.droppedPropertyKeys.join(", ")})`,
1589
+ line: path.node.loc?.start.line ?? null
1590
+ });
1591
+ }
1592
+ path.replaceWith(result.rewritten);
1572
1593
  }
1573
1594
  });
1574
1595
  }
1575
- function rewriteCssSpreadCalls(ast, cssBindingName) {
1596
+ function rewriteCssSpreadCalls(ast, cssBindingName, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1576
1597
  traverse(ast, {
1577
1598
  CallExpression(path) {
1578
1599
  if (!isCssSpreadCall(path.node, cssBindingName)) return;
@@ -1580,44 +1601,86 @@ function rewriteCssSpreadCalls(ast, cssBindingName) {
1580
1601
  if (!arg || t3.isSpreadElement(arg) || !t3.isExpression(arg) || path.node.arguments.length !== 1) return;
1581
1602
  const styleObject = unwrapStyleObjectExpression(arg);
1582
1603
  if (!styleObject) return;
1583
- const rewritten = tryBuildStyleArrayFromObjectExpression(styleObject, path);
1584
- if (!rewritten) return;
1585
- path.replaceWith(rewritten);
1604
+ const result = tryBuildStyleArrayFromObjectExpression(
1605
+ styleObject,
1606
+ path,
1607
+ asStyleArrayHelperName,
1608
+ needsAsStyleArrayHelper
1609
+ );
1610
+ if (!result.rewritten) return;
1611
+ path.replaceWith(result.rewritten);
1586
1612
  }
1587
1613
  });
1588
1614
  }
1589
- function tryBuildStyleArrayFromObject(path) {
1590
- return tryBuildStyleArrayFromObjectExpression(path.node, path);
1615
+ function tryBuildStyleArrayFromObject(path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1616
+ return tryBuildStyleArrayFromObjectExpression(path.node, path, asStyleArrayHelperName, needsAsStyleArrayHelper);
1617
+ }
1618
+ function tryBuildStyleArrayFromObjectExpression(expr, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1619
+ const result = collectStyleCompositionEntries(expr, path);
1620
+ if (!result) return { rewritten: null, droppedPropertyKeys: [] };
1621
+ const elements = buildArrayElementsFromStyleCompositionEntries(
1622
+ result.entries,
1623
+ path,
1624
+ asStyleArrayHelperName,
1625
+ needsAsStyleArrayHelper
1626
+ );
1627
+ return { rewritten: t3.arrayExpression(elements), droppedPropertyKeys: result.droppedPropertyKeys };
1591
1628
  }
1592
- function tryBuildStyleArrayFromObjectExpression(expr, path) {
1629
+ function collectStyleCompositionEntries(expr, path) {
1593
1630
  if (expr.properties.length === 0) return null;
1594
- let sawStyleArray = false;
1595
- const elements = [];
1631
+ let sawKnownStyle = false;
1632
+ const entries = [];
1633
+ const droppedPropertyKeys = [];
1596
1634
  for (const prop of expr.properties) {
1597
1635
  if (!t3.isSpreadElement(prop)) {
1598
- return null;
1636
+ droppedPropertyKeys.push(formatDroppedPropertyKey(prop));
1637
+ continue;
1599
1638
  }
1600
- const normalizedArg = normalizeStyleArrayLikeExpression(
1601
- prop.argument,
1602
- path,
1603
- /* @__PURE__ */ new Set()
1604
- // I.e. `...Css.df.$`, `...(cond ? Css.df.$ : {})`, or `...styles.wrapper`
1605
- );
1639
+ const normalizedArg = normalizeStyleArrayLikeExpression(prop.argument, path, /* @__PURE__ */ new Set());
1606
1640
  if (!normalizedArg) {
1607
- elements.push(t3.spreadElement(buildInlineAsStyleArrayExpression(prop.argument)));
1641
+ entries.push({ kind: "unknown", expr: prop.argument });
1608
1642
  continue;
1609
1643
  }
1610
1644
  if (isKnownStyleArrayLike(normalizedArg, path, /* @__PURE__ */ new Set())) {
1611
- sawStyleArray = true;
1645
+ sawKnownStyle = true;
1646
+ entries.push({ kind: "known", expr: normalizedArg });
1647
+ } else {
1648
+ entries.push({ kind: "unknown", expr: normalizedArg });
1612
1649
  }
1613
- if (t3.isArrayExpression(normalizedArg)) {
1614
- elements.push(...normalizedArg.elements);
1650
+ }
1651
+ return sawKnownStyle ? { entries, droppedPropertyKeys } : null;
1652
+ }
1653
+ function buildPropsArgsFromStyleCompositionEntries(entries, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1654
+ const propsArgs = [];
1655
+ for (const entry of entries) {
1656
+ const nestedArgs = entry.kind === "known" ? buildStyleArrayLikePropsArgs(entry.expr, path, /* @__PURE__ */ new Set()) : null;
1657
+ if (nestedArgs && t3.isArrayExpression(entry.expr)) {
1658
+ propsArgs.push(...nestedArgs);
1615
1659
  continue;
1616
1660
  }
1617
- elements.push(t3.spreadElement(buildSafeSpreadArgument(normalizedArg)));
1661
+ propsArgs.push(
1662
+ t3.spreadElement(
1663
+ entry.kind === "known" ? buildSafeSpreadArgument(entry.expr) : buildUnknownObjectSpreadFallback(entry.expr, asStyleArrayHelperName, needsAsStyleArrayHelper)
1664
+ )
1665
+ );
1618
1666
  }
1619
- if (!sawStyleArray) return null;
1620
- return t3.arrayExpression(elements);
1667
+ return propsArgs;
1668
+ }
1669
+ function buildArrayElementsFromStyleCompositionEntries(entries, path, asStyleArrayHelperName, needsAsStyleArrayHelper) {
1670
+ const elements = [];
1671
+ for (const entry of entries) {
1672
+ const nestedArgs = entry.kind === "known" ? buildStyleArrayLikePropsArgs(entry.expr, path, /* @__PURE__ */ new Set()) : null;
1673
+ if (nestedArgs && t3.isArrayExpression(entry.expr)) {
1674
+ elements.push(...entry.expr.elements);
1675
+ continue;
1676
+ }
1677
+ elements.push(
1678
+ t3.spreadElement(
1679
+ entry.kind === "known" ? buildSafeSpreadArgument(entry.expr) : asStyleArrayHelperName && needsAsStyleArrayHelper ? buildUnknownObjectSpreadFallback(entry.expr, asStyleArrayHelperName, needsAsStyleArrayHelper) : buildInlineAsStyleArrayExpression(entry.expr)
1680
+ )
1681
+ );
1682
+ }
1683
+ return elements;
1621
1684
  }
1622
1685
  function isCssSpreadCall(expr, cssBindingName) {
1623
1686
  return t3.isMemberExpression(expr.callee) && !expr.callee.computed && t3.isIdentifier(expr.callee.object, { name: cssBindingName }) && t3.isIdentifier(expr.callee.property, { name: "spread" });
@@ -1661,6 +1724,9 @@ function normalizeStyleArrayLikeBranch(expr, path, seen) {
1661
1724
  if (isEmptyObjectExpression(expr)) {
1662
1725
  return t3.arrayExpression([]);
1663
1726
  }
1727
+ if (t3.isObjectExpression(expr)) {
1728
+ return tryBuildStyleArrayFromObjectExpression(expr, path).rewritten;
1729
+ }
1664
1730
  return normalizeStyleArrayLikeExpression(expr, path, seen);
1665
1731
  }
1666
1732
  function isStyleArrayLike(expr, path, seen) {
@@ -1677,6 +1743,12 @@ function isStyleArrayLike(expr, path, seen) {
1677
1743
  return isStyleArrayLikeBranch(expr.consequent, path, seen) && isStyleArrayLikeBranch(expr.alternate, path, seen);
1678
1744
  }
1679
1745
  if (t3.isIdentifier(expr)) {
1746
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1747
+ if (possibleValues) {
1748
+ return possibleValues.every(function(value) {
1749
+ return isStyleArrayLike(value, path, new Set(seen));
1750
+ });
1751
+ }
1680
1752
  const binding = path.scope.getBinding(expr.name);
1681
1753
  const bindingPath = binding?.path;
1682
1754
  if (!bindingPath || !bindingPath.isVariableDeclarator()) return false;
@@ -1684,10 +1756,22 @@ function isStyleArrayLike(expr, path, seen) {
1684
1756
  return !!(init && isStyleArrayLike(init, bindingPath, seen));
1685
1757
  }
1686
1758
  if (t3.isCallExpression(expr)) {
1759
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1760
+ if (possibleValues) {
1761
+ return possibleValues.every(function(value) {
1762
+ return isStyleArrayLike(value, path, new Set(seen));
1763
+ });
1764
+ }
1687
1765
  const returnExpr = getCallStyleArrayLikeExpression(expr, path);
1688
1766
  return returnExpr ? isStyleArrayLike(returnExpr, path, seen) : true;
1689
1767
  }
1690
1768
  if (t3.isMemberExpression(expr)) {
1769
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1770
+ if (possibleValues) {
1771
+ return possibleValues.every(function(value) {
1772
+ return isStyleArrayLike(value, path, new Set(seen));
1773
+ });
1774
+ }
1691
1775
  const object = expr.object;
1692
1776
  if (!t3.isIdentifier(object)) return false;
1693
1777
  const binding = path.scope.getBinding(object.name);
@@ -1720,6 +1804,12 @@ function isKnownStyleArrayLike(expr, path, seen) {
1720
1804
  return isStyleArrayLikeBranch(expr.consequent, path, seen) && isStyleArrayLikeBranch(expr.alternate, path, seen);
1721
1805
  }
1722
1806
  if (t3.isIdentifier(expr)) {
1807
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1808
+ if (possibleValues) {
1809
+ return possibleValues.every(function(value) {
1810
+ return isKnownStyleArrayLike(value, path, new Set(seen));
1811
+ });
1812
+ }
1723
1813
  const binding = path.scope.getBinding(expr.name);
1724
1814
  const bindingPath = binding?.path;
1725
1815
  if (!bindingPath || !bindingPath.isVariableDeclarator()) return false;
@@ -1727,10 +1817,22 @@ function isKnownStyleArrayLike(expr, path, seen) {
1727
1817
  return !!(init && isKnownStyleArrayLike(init, bindingPath, seen));
1728
1818
  }
1729
1819
  if (t3.isCallExpression(expr)) {
1820
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1821
+ if (possibleValues) {
1822
+ return possibleValues.every(function(value) {
1823
+ return isKnownStyleArrayLike(value, path, new Set(seen));
1824
+ });
1825
+ }
1730
1826
  const returnExpr = getCallStyleArrayLikeExpression(expr, path);
1731
1827
  return !!(returnExpr && isKnownStyleArrayLike(returnExpr, path, seen));
1732
1828
  }
1733
1829
  if (t3.isMemberExpression(expr)) {
1830
+ const possibleValues = resolvePossibleStyleValues(expr, path, new Set(seen));
1831
+ if (possibleValues) {
1832
+ return possibleValues.every(function(value) {
1833
+ return isKnownStyleArrayLike(value, path, new Set(seen));
1834
+ });
1835
+ }
1734
1836
  const object = expr.object;
1735
1837
  if (!t3.isIdentifier(object)) return false;
1736
1838
  const binding = path.scope.getBinding(object.name);
@@ -1767,6 +1869,7 @@ function buildInlineAsStyleArrayExpression(expr) {
1767
1869
  t3.callExpression(t3.memberExpression(t3.identifier("Array"), t3.identifier("isArray")), [expr]),
1768
1870
  expr,
1769
1871
  t3.conditionalExpression(expr, t3.arrayExpression([expr]), t3.arrayExpression([]))
1872
+ // I.e. `xss` becomes `[xss]` when truthy
1770
1873
  );
1771
1874
  }
1772
1875
  function buildSafeSpreadArgument(expr) {
@@ -1797,6 +1900,47 @@ function getCallStyleArrayLikeExpression(expr, path) {
1797
1900
  }
1798
1901
  return null;
1799
1902
  }
1903
+ function resolvePossibleStyleValues(expr, path, seen) {
1904
+ if (seen.has(expr)) return null;
1905
+ seen.add(expr);
1906
+ if (t3.isObjectExpression(expr) || t3.isArrayExpression(expr)) {
1907
+ return [expr];
1908
+ }
1909
+ if (t3.isIdentifier(expr)) {
1910
+ const binding = path.scope.getBinding(expr.name);
1911
+ const bindingPath = binding?.path;
1912
+ if (!bindingPath || !bindingPath.isVariableDeclarator()) return null;
1913
+ const init = bindingPath.node.init;
1914
+ return init && t3.isExpression(init) ? resolvePossibleStyleValues(init, bindingPath, seen) : null;
1915
+ }
1916
+ if (t3.isCallExpression(expr)) {
1917
+ const returnExpr = getCallStyleArrayLikeExpression(expr, path);
1918
+ return returnExpr ? resolvePossibleStyleValues(returnExpr, path, seen) : null;
1919
+ }
1920
+ if (t3.isMemberExpression(expr)) {
1921
+ const object = expr.object;
1922
+ if (!t3.isExpression(object)) return null;
1923
+ const objectValues = resolvePossibleStyleValues(object, path, seen);
1924
+ if (!objectValues) return null;
1925
+ const propertyName = getStaticMemberPropertyName(expr, path);
1926
+ const values = [];
1927
+ for (const objectValue of objectValues) {
1928
+ if (!t3.isObjectExpression(objectValue)) continue;
1929
+ for (const prop of objectValue.properties) {
1930
+ if (!t3.isObjectProperty(prop) || prop.computed || !t3.isExpression(prop.value)) continue;
1931
+ if (propertyName) {
1932
+ if (isMatchingPropertyName(prop.key, propertyName)) {
1933
+ values.push(prop.value);
1934
+ }
1935
+ } else {
1936
+ values.push(prop.value);
1937
+ }
1938
+ }
1939
+ }
1940
+ return values.length > 0 ? values : null;
1941
+ }
1942
+ return null;
1943
+ }
1800
1944
  function getLocalFunctionReturnExpression(expr, path) {
1801
1945
  if (!t3.isIdentifier(expr.callee)) return null;
1802
1946
  const binding = path.scope.getBinding(expr.callee.name);