@rayburst/cli 0.3.8 → 0.4.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.
@@ -531,6 +531,33 @@ function analyzeJsxPropsForComponents(jsxElement, propName, projectPath, project
531
531
  }
532
532
  return componentPaths;
533
533
  }
534
+ function extractRouterConfigFromJsx(jsxElement, propName) {
535
+ try {
536
+ const jsxAttributes = jsxElement.getChildrenOfKind(SyntaxKind.JsxAttributes)[0];
537
+ if (!jsxAttributes) return null;
538
+ const attributes = jsxAttributes.getChildrenOfKind(SyntaxKind.JsxAttribute);
539
+ for (const attr of attributes) {
540
+ const attrName = attr.getChildrenOfKind(SyntaxKind.Identifier)[0]?.getText();
541
+ if (attrName !== propName) continue;
542
+ const initializer = attr.getChildrenOfKind(SyntaxKind.JsxExpression)[0];
543
+ if (!initializer) continue;
544
+ const identifier = initializer.getChildrenOfKind(SyntaxKind.Identifier)[0];
545
+ if (!identifier) continue;
546
+ const declaration = traceIdentifierToDeclaration(identifier);
547
+ if (!declaration || !isVariableDeclaration(declaration)) continue;
548
+ const dataFlow = traceVariableDataFlow(declaration);
549
+ if (!dataFlow || !isCallExpression(dataFlow)) continue;
550
+ const args = dataFlow.getChildrenOfKind(SyntaxKind.SyntaxList)[0];
551
+ if (!args) continue;
552
+ const configArg = args.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0];
553
+ if (!configArg) continue;
554
+ return extractRouterConfig(configArg);
555
+ }
556
+ } catch (error) {
557
+ console.error("[extractRouterConfigFromJsx] Error:", error);
558
+ }
559
+ return null;
560
+ }
534
561
  function traceConfigToComponentPaths(configObject, propertyName, projectPath, project) {
535
562
  try {
536
563
  const propertyNode = traceConfigProperty(configObject, propertyName);
@@ -667,12 +694,21 @@ function detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectP
667
694
  if (componentPaths.length > 0) {
668
695
  if (propName === "router") {
669
696
  console.log(`[DEBUG] Creating router decision node for ${componentPaths.length} routes`);
697
+ const routerConfig = extractRouterConfigFromJsx(jsxElement, propName);
698
+ console.log(`[DEBUG] Router config extracted:`, routerConfig);
699
+ if (routerConfig) {
700
+ routerConfig.routeTree = componentPaths.length;
701
+ }
670
702
  const relativePath = sourceFile.getFilePath().replace(projectPath + "/", "");
671
703
  const routerNode = createRouterDecisionNode(relativePath, gitHash, componentPaths.length);
672
704
  nodes.push(routerNode);
673
705
  nodeMap.set(routerNode.id, routerNode);
674
706
  const routerProviderExternalId = "external::@tanstack/react-router::RouterProvider";
675
- const routerProviderNode = externalNodeMap.get(routerProviderExternalId);
707
+ let routerProviderNode = externalNodeMap.get(routerProviderExternalId);
708
+ if (routerProviderNode && routerConfig) {
709
+ console.log(`[DEBUG] Updating RouterProvider node with config`);
710
+ routerProviderNode.data.providerItems = formatRouterConfigAsProviderItems(routerConfig);
711
+ }
676
712
  if (routerProviderNode) {
677
713
  const providerToRouterEdgeId = `e-${routerProviderNode.id}-${routerNode.id}`;
678
714
  if (!edges.find((e) => e.id === providerToRouterEdgeId)) {
@@ -706,16 +742,58 @@ function detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectP
706
742
  totalEdgesCreated++;
707
743
  }
708
744
  }
709
- const routerToRoutesEdges = createConfigBasedEdges(
710
- routerNode,
711
- componentPaths,
712
- nodeMap,
713
- edges,
714
- "route",
715
- true
716
- // Use route path labels
717
- );
718
- totalEdgesCreated += routerToRoutesEdges;
745
+ let decisionNodesCreated = 0;
746
+ let decisionEdgesCreated = 0;
747
+ for (const routeFilePath of componentPaths) {
748
+ const routePath = extractRoutePathFromFile(routeFilePath);
749
+ const isDynamic = routePath.includes(":");
750
+ const decisionNodeId = `${routerNode.id}::decision::${routePath.replace(/[/:]/g, "_")}`;
751
+ const decisionNode = {
752
+ id: decisionNodeId,
753
+ type: "conditional",
754
+ position: { x: 800, y: 400 + decisionNodesCreated * 100 },
755
+ data: {
756
+ label: isDynamic ? `matches "${routePath}"` : `path === "${routePath}"`,
757
+ description: `Route condition for ${routePath}`,
758
+ condition: isDynamic ? `pathname.matches("${routePath}")` : `pathname === "${routePath}"`,
759
+ trueLabel: "render",
760
+ falseLabel: "skip"
761
+ }
762
+ };
763
+ nodes.push(decisionNode);
764
+ nodeMap.set(decisionNode.id, decisionNode);
765
+ decisionNodesCreated++;
766
+ const routerToDecisionEdgeId = `e-${routerNode.id}-${decisionNode.id}`;
767
+ if (!edges.find((e) => e.id === routerToDecisionEdgeId)) {
768
+ edges.push({
769
+ id: routerToDecisionEdgeId,
770
+ source: routerNode.id,
771
+ target: decisionNode.id,
772
+ type: "floating",
773
+ label: routePath
774
+ });
775
+ decisionEdgesCreated++;
776
+ }
777
+ const targetNodes = findNodesInFile(routeFilePath, nodeMap);
778
+ for (const targetNode of targetNodes) {
779
+ if (targetNode.type !== "component") {
780
+ continue;
781
+ }
782
+ const decisionToComponentEdgeId = `e-${decisionNode.id}-${targetNode.id}`;
783
+ if (!edges.find((e) => e.id === decisionToComponentEdgeId)) {
784
+ edges.push({
785
+ id: decisionToComponentEdgeId,
786
+ source: decisionNode.id,
787
+ target: targetNode.id,
788
+ type: "floating",
789
+ label: "true"
790
+ });
791
+ decisionEdgesCreated++;
792
+ }
793
+ }
794
+ }
795
+ console.log(`[ROUTER] Created ${decisionNodesCreated} decision nodes and ${decisionEdgesCreated} edges`);
796
+ totalEdgesCreated += decisionEdgesCreated;
719
797
  } else {
720
798
  console.log(`[DEBUG] Creating edges for ${componentPaths.length} components`);
721
799
  const edgesCreated = createConfigBasedEdges(
@@ -1312,17 +1390,110 @@ function resolveImportSource(sourceFile, identifierName) {
1312
1390
  }
1313
1391
  return null;
1314
1392
  }
1315
- function createExternalComponentNode(componentName, packageName, sourceFilePath, nodes, nodeMap, externalNodeMap) {
1393
+ function formatRouterConfigAsProviderItems(config) {
1394
+ const items = [];
1395
+ if (config.routeTree !== void 0) {
1396
+ items.push({
1397
+ name: "routeTree",
1398
+ type: typeof config.routeTree === "number" ? `RouteTree (${config.routeTree} routes)` : "RouteTree",
1399
+ icon: "Other",
1400
+ connections: typeof config.routeTree === "number" ? config.routeTree : 0
1401
+ });
1402
+ }
1403
+ if (config.context !== void 0) {
1404
+ items.push({
1405
+ name: "context",
1406
+ type: typeof config.context === "string" ? config.context : "object",
1407
+ icon: "State",
1408
+ connections: 0
1409
+ });
1410
+ }
1411
+ if (config.defaultPreload !== void 0) {
1412
+ items.push({
1413
+ name: "defaultPreload",
1414
+ type: `'${config.defaultPreload}'`,
1415
+ icon: "Other",
1416
+ connections: 0
1417
+ });
1418
+ }
1419
+ if (config.scrollRestoration !== void 0) {
1420
+ items.push({
1421
+ name: "scrollRestoration",
1422
+ type: String(config.scrollRestoration),
1423
+ icon: "Other",
1424
+ connections: 0
1425
+ });
1426
+ }
1427
+ if (config.defaultStructuralSharing !== void 0) {
1428
+ items.push({
1429
+ name: "defaultStructuralSharing",
1430
+ type: String(config.defaultStructuralSharing),
1431
+ icon: "Other",
1432
+ connections: 0
1433
+ });
1434
+ }
1435
+ if (config.defaultPreloadStaleTime !== void 0) {
1436
+ items.push({
1437
+ name: "defaultPreloadStaleTime",
1438
+ type: `${config.defaultPreloadStaleTime}ms`,
1439
+ icon: "Other",
1440
+ connections: 0
1441
+ });
1442
+ }
1443
+ return items;
1444
+ }
1445
+ function extractRouterConfig(configArg) {
1446
+ const config = {};
1447
+ try {
1448
+ if (!Node.isObjectLiteralExpression(configArg)) {
1449
+ return config;
1450
+ }
1451
+ const properties = configArg.getProperties();
1452
+ for (const prop of properties) {
1453
+ if (Node.isPropertyAssignment(prop) || Node.isShorthandPropertyAssignment(prop)) {
1454
+ const name = prop.getName();
1455
+ if (Node.isPropertyAssignment(prop)) {
1456
+ const initializer = prop.getInitializer();
1457
+ if (initializer) {
1458
+ if (Node.isStringLiteral(initializer)) {
1459
+ config[name] = initializer.getLiteralValue();
1460
+ } else if (Node.isNumericLiteral(initializer)) {
1461
+ config[name] = initializer.getLiteralValue();
1462
+ } else if (initializer.getKind() === SyntaxKind.TrueKeyword || initializer.getKind() === SyntaxKind.FalseKeyword) {
1463
+ config[name] = initializer.getText() === "true";
1464
+ } else if (Node.isObjectLiteralExpression(initializer)) {
1465
+ config[name] = "{}";
1466
+ } else {
1467
+ config[name] = initializer.getText();
1468
+ }
1469
+ }
1470
+ } else if (Node.isShorthandPropertyAssignment(prop)) {
1471
+ config[name] = prop.getName();
1472
+ }
1473
+ }
1474
+ }
1475
+ } catch (error) {
1476
+ console.error("[extractRouterConfig] Error:", error);
1477
+ }
1478
+ return config;
1479
+ }
1480
+ function createExternalComponentNode(componentName, packageName, sourceFilePath, nodes, nodeMap, externalNodeMap, routerConfig) {
1316
1481
  const externalId = `external::${packageName}::${componentName}`;
1317
1482
  if (externalNodeMap.has(externalId)) {
1318
1483
  return externalNodeMap.get(externalId);
1319
1484
  }
1485
+ const isRouterProvider = componentName === "RouterProvider" && packageName === "@tanstack/react-router";
1320
1486
  const node = {
1321
1487
  id: externalId,
1322
- type: "component",
1488
+ type: isRouterProvider ? "provider" : "component",
1323
1489
  position: { x: 1200, y: nodes.length * 150 },
1324
1490
  // Position externals to the right
1325
- data: {
1491
+ data: isRouterProvider ? {
1492
+ providerName: componentName,
1493
+ label: componentName,
1494
+ description: `External: ${packageName}`,
1495
+ providerItems: routerConfig ? formatRouterConfigAsProviderItems(routerConfig) : []
1496
+ } : {
1326
1497
  componentName,
1327
1498
  props: "external",
1328
1499
  label: componentName,
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-KOAVTHSN.js";
12
+ } from "./chunk-4YULNVZV.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rayburstPlugin
3
- } from "./chunk-KOAVTHSN.js";
3
+ } from "./chunk-4YULNVZV.js";
4
4
  export {
5
5
  rayburstPlugin
6
6
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rayburst/cli",
3
- "version": "0.3.8",
3
+ "version": "0.4.1",
4
4
  "description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",