@bamboocss/vite 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1575,6 +1575,58 @@ const foldSource = (options) => {
1575
1575
  }
1576
1576
  return names;
1577
1577
  };
1578
+ /**
1579
+ * Is this binding the variant half of `<recipe>.splitVariantProps(...)`?
1580
+ *
1581
+ * Read off the declaration rather than the type, so it is the same recipe and the same
1582
+ * destructuring position the source actually wrote.
1583
+ */
1584
+ const isSplitVariantPropsOf = (binding, recipe) => {
1585
+ for (const declaration of binding.getSourceFile().getDescendantsOfKind(ts_morph.SyntaxKind.VariableDeclaration)) {
1586
+ const nameNode = declaration.getNameNode();
1587
+ if (!ts_morph.Node.isArrayBindingPattern(nameNode)) continue;
1588
+ const first = nameNode.getElements()[0];
1589
+ if (!first || !ts_morph.Node.isBindingElement(first)) continue;
1590
+ if (first.getNameNode().getText() !== binding.getText()) continue;
1591
+ const initializer = declaration.getInitializer();
1592
+ if (!initializer || !ts_morph.Node.isCallExpression(initializer)) return false;
1593
+ const callee = initializer.getExpression();
1594
+ if (!ts_morph.Node.isPropertyAccessExpression(callee)) return false;
1595
+ return callee.getName() === "splitVariantProps" && callee.getExpression().getText() === recipe;
1596
+ }
1597
+ return false;
1598
+ };
1599
+ /**
1600
+ * Lower a config recipe call the same way an inline one lowers.
1601
+ *
1602
+ * The config lives in `ctx.recipes` rather than in the module, and the classes are named
1603
+ * from it identically — so this is the same `lowerRecipeCall`, handed the config from a
1604
+ * different place. Slot recipes are excluded by the caller: they resolve to one class per
1605
+ * slot rather than to a string.
1606
+ */
1607
+ const lowerConfigRecipeCall = (call, name) => {
1608
+ const config = ctx.recipes.getConfig(name);
1609
+ if (!config || config.slots !== void 0) return void 0;
1610
+ const className = config.className;
1611
+ if (!className) return void 0;
1612
+ if (!ts_morph.Node.isCallExpression(call)) return void 0;
1613
+ const argument = call.getArguments()[0];
1614
+ if (!argument || !ts_morph.Node.isIdentifier(argument) || !isSplitVariantPropsOf(argument, name)) return void 0;
1615
+ const lowered = lowerRecipeCall(call, {
1616
+ config,
1617
+ name: className,
1618
+ box: void 0
1619
+ }, ctx, isInertExpression);
1620
+ if (lowered.kind !== "expression") return void 0;
1621
+ const helper = ensureRecipeHelperImport(RECIPE_PICK_HELPER, call, isBambooCssModule, isGeneratedCssModule, isShadowed);
1622
+ if (!helper) return void 0;
1623
+ return {
1624
+ replacement: helper.name === "cvaPick" ? lowered.expression : lowered.expression.replaceAll(`${RECIPE_PICK_HELPER}(`, `${helper.name}(`),
1625
+ className: lowered.staticClasses,
1626
+ classNames: lowered.classNames,
1627
+ insert: helper.insert
1628
+ };
1629
+ };
1578
1630
  for (const item of parserResult.toArray()) {
1579
1631
  const type = item.type ?? "";
1580
1632
  const name = item.name ?? type;
@@ -1829,6 +1881,18 @@ const foldSource = (options) => {
1829
1881
  });
1830
1882
  continue;
1831
1883
  }
1884
+ const lowered = type === "recipe" && !slot ? lowerConfigRecipeCall(call, name) : void 0;
1885
+ if (lowered) {
1886
+ candidates.push({
1887
+ item,
1888
+ call,
1889
+ node: call,
1890
+ start,
1891
+ end,
1892
+ ...lowered
1893
+ });
1894
+ continue;
1895
+ }
1832
1896
  skipped.push({
1833
1897
  name,
1834
1898
  reason: "dynamic",
@@ -1956,14 +2020,20 @@ const foldSource = (options) => {
1956
2020
  });
1957
2021
  collectSourceFiles(item.box, dependencyScan);
1958
2022
  }
1959
- const recipeSourceFile = recipeConfigs?.size ? [...recipeConfigs.values()].find((entry) => entry.box)?.box?.getNode?.()?.getSourceFile() : void 0;
2023
+ const recipeSourceFile = [...recipeConfigs?.values() ?? []].find((entry) => entry.box)?.box?.getNode?.()?.getSourceFile() ?? candidates[0]?.node.getSourceFile();
1960
2024
  if (recipeSourceFile) for (const access of recipeSourceFile.getDescendantsOfKind(ts_morph.SyntaxKind.PropertyAccessExpression)) {
1961
2025
  if (access.getName() !== "splitVariantProps") continue;
1962
2026
  const target = access.getExpression();
1963
2027
  if (!ts_morph.Node.isIdentifier(target)) continue;
1964
- const entry = recipeConfigs?.get(target.getText());
1965
- if (!entry || entry === AMBIGUOUS) continue;
1966
2028
  if (isShadowed(access, target.getText())) continue;
2029
+ const local = recipeConfigs?.get(target.getText());
2030
+ const importedConfig = !local && importsFor(recipeSourceFile).has(target.getText()) ? ctx.recipes.getConfig(target.getText()) : void 0;
2031
+ const entry = local && local !== AMBIGUOUS ? local : importedConfig ? {
2032
+ config: importedConfig,
2033
+ name: "",
2034
+ box: void 0
2035
+ } : void 0;
2036
+ if (!entry) continue;
1967
2037
  const call = access.getParent();
1968
2038
  if (!ts_morph.Node.isCallExpression(call) || call.getExpression() !== access) continue;
1969
2039
  const args = call.getArguments();
package/dist/index.mjs CHANGED
@@ -1548,6 +1548,58 @@ const foldSource = (options) => {
1548
1548
  }
1549
1549
  return names;
1550
1550
  };
1551
+ /**
1552
+ * Is this binding the variant half of `<recipe>.splitVariantProps(...)`?
1553
+ *
1554
+ * Read off the declaration rather than the type, so it is the same recipe and the same
1555
+ * destructuring position the source actually wrote.
1556
+ */
1557
+ const isSplitVariantPropsOf = (binding, recipe) => {
1558
+ for (const declaration of binding.getSourceFile().getDescendantsOfKind(SyntaxKind.VariableDeclaration)) {
1559
+ const nameNode = declaration.getNameNode();
1560
+ if (!Node.isArrayBindingPattern(nameNode)) continue;
1561
+ const first = nameNode.getElements()[0];
1562
+ if (!first || !Node.isBindingElement(first)) continue;
1563
+ if (first.getNameNode().getText() !== binding.getText()) continue;
1564
+ const initializer = declaration.getInitializer();
1565
+ if (!initializer || !Node.isCallExpression(initializer)) return false;
1566
+ const callee = initializer.getExpression();
1567
+ if (!Node.isPropertyAccessExpression(callee)) return false;
1568
+ return callee.getName() === "splitVariantProps" && callee.getExpression().getText() === recipe;
1569
+ }
1570
+ return false;
1571
+ };
1572
+ /**
1573
+ * Lower a config recipe call the same way an inline one lowers.
1574
+ *
1575
+ * The config lives in `ctx.recipes` rather than in the module, and the classes are named
1576
+ * from it identically — so this is the same `lowerRecipeCall`, handed the config from a
1577
+ * different place. Slot recipes are excluded by the caller: they resolve to one class per
1578
+ * slot rather than to a string.
1579
+ */
1580
+ const lowerConfigRecipeCall = (call, name) => {
1581
+ const config = ctx.recipes.getConfig(name);
1582
+ if (!config || config.slots !== void 0) return void 0;
1583
+ const className = config.className;
1584
+ if (!className) return void 0;
1585
+ if (!Node.isCallExpression(call)) return void 0;
1586
+ const argument = call.getArguments()[0];
1587
+ if (!argument || !Node.isIdentifier(argument) || !isSplitVariantPropsOf(argument, name)) return void 0;
1588
+ const lowered = lowerRecipeCall(call, {
1589
+ config,
1590
+ name: className,
1591
+ box: void 0
1592
+ }, ctx, isInertExpression);
1593
+ if (lowered.kind !== "expression") return void 0;
1594
+ const helper = ensureRecipeHelperImport(RECIPE_PICK_HELPER, call, isBambooCssModule, isGeneratedCssModule, isShadowed);
1595
+ if (!helper) return void 0;
1596
+ return {
1597
+ replacement: helper.name === "cvaPick" ? lowered.expression : lowered.expression.replaceAll(`${RECIPE_PICK_HELPER}(`, `${helper.name}(`),
1598
+ className: lowered.staticClasses,
1599
+ classNames: lowered.classNames,
1600
+ insert: helper.insert
1601
+ };
1602
+ };
1551
1603
  for (const item of parserResult.toArray()) {
1552
1604
  const type = item.type ?? "";
1553
1605
  const name = item.name ?? type;
@@ -1802,6 +1854,18 @@ const foldSource = (options) => {
1802
1854
  });
1803
1855
  continue;
1804
1856
  }
1857
+ const lowered = type === "recipe" && !slot ? lowerConfigRecipeCall(call, name) : void 0;
1858
+ if (lowered) {
1859
+ candidates.push({
1860
+ item,
1861
+ call,
1862
+ node: call,
1863
+ start,
1864
+ end,
1865
+ ...lowered
1866
+ });
1867
+ continue;
1868
+ }
1805
1869
  skipped.push({
1806
1870
  name,
1807
1871
  reason: "dynamic",
@@ -1929,14 +1993,20 @@ const foldSource = (options) => {
1929
1993
  });
1930
1994
  collectSourceFiles(item.box, dependencyScan);
1931
1995
  }
1932
- const recipeSourceFile = recipeConfigs?.size ? [...recipeConfigs.values()].find((entry) => entry.box)?.box?.getNode?.()?.getSourceFile() : void 0;
1996
+ const recipeSourceFile = [...recipeConfigs?.values() ?? []].find((entry) => entry.box)?.box?.getNode?.()?.getSourceFile() ?? candidates[0]?.node.getSourceFile();
1933
1997
  if (recipeSourceFile) for (const access of recipeSourceFile.getDescendantsOfKind(SyntaxKind.PropertyAccessExpression)) {
1934
1998
  if (access.getName() !== "splitVariantProps") continue;
1935
1999
  const target = access.getExpression();
1936
2000
  if (!Node.isIdentifier(target)) continue;
1937
- const entry = recipeConfigs?.get(target.getText());
1938
- if (!entry || entry === AMBIGUOUS) continue;
1939
2001
  if (isShadowed(access, target.getText())) continue;
2002
+ const local = recipeConfigs?.get(target.getText());
2003
+ const importedConfig = !local && importsFor(recipeSourceFile).has(target.getText()) ? ctx.recipes.getConfig(target.getText()) : void 0;
2004
+ const entry = local && local !== AMBIGUOUS ? local : importedConfig ? {
2005
+ config: importedConfig,
2006
+ name: "",
2007
+ box: void 0
2008
+ } : void 0;
2009
+ if (!entry) continue;
1940
2010
  const call = access.getParent();
1941
2011
  if (!Node.isCallExpression(call) || call.getExpression() !== access) continue;
1942
2012
  const args = call.getArguments();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bamboocss/vite",
3
- "version": "1.25.0",
3
+ "version": "1.26.0",
4
4
  "description": "Vite integration for Bamboo CSS",
5
5
  "homepage": "https://bamboocss.com",
6
6
  "license": "MIT",
@@ -37,18 +37,18 @@
37
37
  "dependencies": {
38
38
  "magic-string": "0.30.21",
39
39
  "ts-morph": "28.0.0",
40
- "@bamboocss/config": "1.25.0",
41
- "@bamboocss/core": "1.25.0",
42
- "@bamboocss/extractor": "1.25.0",
43
- "@bamboocss/logger": "1.25.0",
44
- "@bamboocss/node": "1.25.0",
45
- "@bamboocss/types": "1.25.0",
46
- "@bamboocss/shared": "1.25.0"
40
+ "@bamboocss/config": "1.26.0",
41
+ "@bamboocss/extractor": "1.26.0",
42
+ "@bamboocss/core": "1.26.0",
43
+ "@bamboocss/node": "1.26.0",
44
+ "@bamboocss/logger": "1.26.0",
45
+ "@bamboocss/shared": "1.26.0",
46
+ "@bamboocss/types": "1.26.0"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@jridgewell/trace-mapping": "^0.3.31",
50
50
  "vite": "7.2.6",
51
- "@bamboocss/fixture": "1.25.0"
51
+ "@bamboocss/fixture": "1.26.0"
52
52
  },
53
53
  "peerDependencies": {
54
54
  "vite": ">=5"