@rayburst/cli 0.4.3 → 0.4.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.
@@ -434,15 +434,15 @@ function createRouterDecisionNode(sourceFilePath, gitHash, routeCount) {
434
434
  };
435
435
  }
436
436
  function extractRoutePathFromFile(routeFilePath) {
437
- let path5 = routeFilePath.replace(/^src\/routes\//, "/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/route$/, "").replace(/\/index$/, "");
438
- if (path5 === "/__root") {
437
+ let path6 = routeFilePath.replace(/^src\/routes\//, "/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/route$/, "").replace(/\/index$/, "");
438
+ if (path6 === "/__root") {
439
439
  return "/";
440
440
  }
441
- path5 = path5.replace(/\/\$([^/]+)/g, (_, param) => `/:${param}`);
442
- if (path5 === "" || path5 === "/") {
441
+ path6 = path6.replace(/\/\$([^/]+)/g, (_, param) => `/:${param}`);
442
+ if (path6 === "" || path6 === "/") {
443
443
  return "/";
444
444
  }
445
- return path5;
445
+ return path6;
446
446
  }
447
447
  function createConfigBasedEdges(sourceNode, targetFilePaths, nodeMap, edges, edgeType = "config", useRoutePathLabels = false) {
448
448
  let edgesCreated = 0;
@@ -650,7 +650,7 @@ function traceConfigToComponentPaths(configObject, propertyName, projectPath, pr
650
650
  }
651
651
  return [];
652
652
  }
653
- function detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectPath, project, gitHash, externalNodeMap) {
653
+ function detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectPath, project, gitHash, externalNodeMap, usedIds, idCounters) {
654
654
  let totalEdgesCreated = 0;
655
655
  try {
656
656
  const jsxElements = sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement);
@@ -747,7 +747,18 @@ function detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectP
747
747
  for (const routeFilePath of componentPaths) {
748
748
  const routePath = extractRoutePathFromFile(routeFilePath);
749
749
  const isDynamic = routePath.includes(":");
750
- const decisionNodeId = `${routerNode.id}::decision::${routePath.replace(/[/:]/g, "_")}`;
750
+ const routePathNormalized = routePath.replace(/[/:]/g, "_");
751
+ const decisionNodeName = `RouterDecision::decision::${routePathNormalized}`;
752
+ const routerIdParts = routerNode.id.split("::");
753
+ const sourceFilePath = routerIdParts[0];
754
+ const gitHash2 = routerIdParts[2];
755
+ const decisionNodeId = getUniqueNodeId(
756
+ sourceFilePath,
757
+ decisionNodeName,
758
+ gitHash2,
759
+ usedIds,
760
+ idCounters
761
+ );
751
762
  const decisionNode = {
752
763
  id: decisionNodeId,
753
764
  type: "conditional",
@@ -879,7 +890,7 @@ async function analyzeProject(projectPath, projectId, onLog) {
879
890
  log(` Analyzing config-based components...`);
880
891
  let totalConfigEdges = 0;
881
892
  for (const sourceFile of sourceFiles) {
882
- const configEdges = detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectPath, project, gitHash, externalNodeMap);
893
+ const configEdges = detectConfigBasedComponents(sourceFile, nodes, nodeMap, edges, projectPath, project, gitHash, externalNodeMap, usedIds, idCounters);
883
894
  totalConfigEdges += configEdges;
884
895
  }
885
896
  if (totalConfigEdges > 0) {
@@ -935,6 +946,19 @@ async function analyzeProject(projectPath, projectId, onLog) {
935
946
  log(" Checking for changed files vs remote...");
936
947
  const changedFiles = getChangedFilesVsRemote(projectPath);
937
948
  log(` Found ${changedFiles.length} changed files`);
949
+ const changedFilesMetadata = [];
950
+ for (const filePath of changedFiles) {
951
+ try {
952
+ const stats = fs.statSync(filePath);
953
+ changedFilesMetadata.push({
954
+ filePath,
955
+ lastModified: stats.mtimeMs
956
+ // Unix timestamp in milliseconds
957
+ });
958
+ } catch (error) {
959
+ log(` Warning: Could not get stats for ${filePath}`);
960
+ }
961
+ }
938
962
  const result = {
939
963
  project: projectMetadata,
940
964
  branches: [branchMetadata],
@@ -945,6 +969,9 @@ async function analyzeProject(projectPath, projectId, onLog) {
945
969
  logs,
946
970
  changedFilesVsRemote: changedFiles.length > 0 ? {
947
971
  [branchId]: changedFiles
972
+ } : void 0,
973
+ changedFilesMetadata: changedFilesMetadata.length > 0 ? {
974
+ [branchId]: changedFilesMetadata
948
975
  } : void 0
949
976
  };
950
977
  return result;
@@ -1217,6 +1244,58 @@ function getReturnDescription(returnAnalysis) {
1217
1244
  }
1218
1245
  return "Returns value";
1219
1246
  }
1247
+ function extractProviderItems(func) {
1248
+ const items = [];
1249
+ try {
1250
+ const variables = func.getVariableDeclarations();
1251
+ for (const variable of variables) {
1252
+ const varName = variable.getName();
1253
+ if (varName === "value" || varName.includes("Value") || varName.includes("Context")) {
1254
+ const initializer = variable.getInitializer();
1255
+ if (initializer && Node.isObjectLiteralExpression(initializer)) {
1256
+ const properties = initializer.getProperties();
1257
+ for (const prop of properties) {
1258
+ if (Node.isPropertyAssignment(prop) || Node.isShorthandPropertyAssignment(prop)) {
1259
+ const propName = prop.getName();
1260
+ const propType = prop.getType().getText();
1261
+ let icon = "Other";
1262
+ if (propType.includes("function") || propType.includes("=>")) {
1263
+ icon = "Function";
1264
+ } else if (propType.includes("boolean")) {
1265
+ icon = "State";
1266
+ } else if (propType.includes("User") || propType.includes("Session")) {
1267
+ icon = "User";
1268
+ } else if (propType.includes("object") || propType.includes("{")) {
1269
+ icon = "State";
1270
+ }
1271
+ items.push({
1272
+ name: propName,
1273
+ type: simplifyType(propType),
1274
+ icon,
1275
+ connections: 0
1276
+ // Will be calculated later based on edges
1277
+ });
1278
+ }
1279
+ }
1280
+ }
1281
+ }
1282
+ }
1283
+ } catch (error) {
1284
+ console.error("Failed to extract provider items:", error);
1285
+ }
1286
+ return items;
1287
+ }
1288
+ function simplifyType(type) {
1289
+ if (type.length > 50) {
1290
+ if (type.includes("function") || type.includes("=>")) return "function";
1291
+ if (type.includes("boolean")) return "boolean";
1292
+ if (type.includes("string")) return "string";
1293
+ if (type.includes("number")) return "number";
1294
+ if (type.includes("null")) return "null";
1295
+ return "object";
1296
+ }
1297
+ return type;
1298
+ }
1220
1299
  function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nodes, nodeMap, usedIds, idCounters) {
1221
1300
  let count = 0;
1222
1301
  let y = startY;
@@ -1230,6 +1309,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
1230
1309
  const propsType = propsParam ? propsParam.getType().getText() : "any";
1231
1310
  const returnAnalysis = analyzeReturnStatements(func);
1232
1311
  const isProvider = name.endsWith("Provider");
1312
+ const providerItems = isProvider ? extractProviderItems(func) : [];
1233
1313
  const node = {
1234
1314
  id,
1235
1315
  type: isProvider ? "provider" : "component",
@@ -1238,7 +1318,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
1238
1318
  providerName: name,
1239
1319
  label: name,
1240
1320
  description: `Provider in ${relativePath}`,
1241
- providerItems: []
1321
+ providerItems
1242
1322
  } : {
1243
1323
  componentName: name,
1244
1324
  props: propsType,
@@ -1270,6 +1350,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
1270
1350
  const propsType = propsParam ? propsParam.getType().getText() : "any";
1271
1351
  const returnAnalysis = analyzeReturnStatements(init);
1272
1352
  const isProvider = name.endsWith("Provider");
1353
+ const providerItems = isProvider ? extractProviderItems(init) : [];
1273
1354
  const node = {
1274
1355
  id,
1275
1356
  type: isProvider ? "provider" : "component",
@@ -1278,7 +1359,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
1278
1359
  providerName: name,
1279
1360
  label: name,
1280
1361
  description: `Provider in ${relativePath}`,
1281
- providerItems: []
1362
+ providerItems
1282
1363
  } : {
1283
1364
  componentName: name,
1284
1365
  props: propsType,
@@ -1839,6 +1920,8 @@ function getEdgeChanges(oldEdge, newEdge) {
1839
1920
 
1840
1921
  // src/vite-plugin.ts
1841
1922
  import chalk2 from "chalk";
1923
+ import * as fs3 from "fs";
1924
+ import * as path5 from "path";
1842
1925
  function rayburstPlugin(options = {}) {
1843
1926
  const {
1844
1927
  enabled = process.env.CI !== "true",
@@ -1848,6 +1931,41 @@ function rayburstPlugin(options = {}) {
1848
1931
  let config;
1849
1932
  let debounceTimer = null;
1850
1933
  let isAnalyzing = false;
1934
+ let lastGitState = null;
1935
+ let gitPollInterval = null;
1936
+ const checkGitState = (projectPath) => {
1937
+ try {
1938
+ const gitDir = path5.join(projectPath, ".git");
1939
+ if (!fs3.existsSync(gitDir)) {
1940
+ return false;
1941
+ }
1942
+ const headPath = path5.join(gitDir, "HEAD");
1943
+ if (!fs3.existsSync(headPath)) {
1944
+ return false;
1945
+ }
1946
+ const headContent = fs3.readFileSync(headPath, "utf-8").trim();
1947
+ let gitState = headContent;
1948
+ if (headContent.startsWith("ref: ")) {
1949
+ const refPath = headContent.substring(5);
1950
+ const fullRefPath = path5.join(gitDir, refPath);
1951
+ if (fs3.existsSync(fullRefPath)) {
1952
+ const refContent = fs3.readFileSync(fullRefPath, "utf-8").trim();
1953
+ gitState = `${headContent}:${refContent}`;
1954
+ }
1955
+ }
1956
+ if (lastGitState === null) {
1957
+ lastGitState = gitState;
1958
+ return false;
1959
+ }
1960
+ if (lastGitState !== gitState) {
1961
+ lastGitState = gitState;
1962
+ return true;
1963
+ }
1964
+ return false;
1965
+ } catch (error) {
1966
+ return false;
1967
+ }
1968
+ };
1851
1969
  const runAnalysis = async (triggerFile) => {
1852
1970
  if (isAnalyzing) return;
1853
1971
  isAnalyzing = true;
@@ -1926,6 +2044,24 @@ function rayburstPlugin(options = {}) {
1926
2044
  server.watcher.on("change", handleFileChange);
1927
2045
  server.watcher.on("add", handleFileChange);
1928
2046
  server.watcher.on("unlink", handleFileChange);
2047
+ const gitHeadPath = path5.join(config.root, ".git", "HEAD");
2048
+ if (fs3.existsSync(gitHeadPath)) {
2049
+ server.watcher.add(gitHeadPath);
2050
+ const handleGitChange = (changedPath) => {
2051
+ if (changedPath === gitHeadPath || changedPath.includes(".git/refs/heads/")) {
2052
+ console.log(chalk2.dim("[Rayburst] Git state changed, re-analyzing..."));
2053
+ runAnalysis("git-event");
2054
+ }
2055
+ };
2056
+ server.watcher.on("change", handleGitChange);
2057
+ checkGitState(config.root);
2058
+ gitPollInterval = setInterval(() => {
2059
+ if (checkGitState(config.root)) {
2060
+ console.log(chalk2.dim("[Rayburst] Git state changed (poll), re-analyzing..."));
2061
+ runAnalysis("git-poll");
2062
+ }
2063
+ }, 5e3);
2064
+ }
1929
2065
  return () => {
1930
2066
  server.watcher.off("change", handleFileChange);
1931
2067
  server.watcher.off("add", handleFileChange);
@@ -1933,6 +2069,9 @@ function rayburstPlugin(options = {}) {
1933
2069
  if (debounceTimer) {
1934
2070
  clearTimeout(debounceTimer);
1935
2071
  }
2072
+ if (gitPollInterval) {
2073
+ clearInterval(gitPollInterval);
2074
+ }
1936
2075
  };
1937
2076
  }
1938
2077
  };
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-76MJ4WFX.js";
12
+ } from "./chunk-5VOUWYVS.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rayburstPlugin
3
- } from "./chunk-76MJ4WFX.js";
3
+ } from "./chunk-5VOUWYVS.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.4.3",
3
+ "version": "0.4.5",
4
4
  "description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -47,7 +47,7 @@
47
47
  "zod": "^4.2.0"
48
48
  },
49
49
  "devDependencies": {
50
- "@rayburst/types": "^0.1.7",
50
+ "@rayburst/types": "^0.1.8",
51
51
  "@types/node": "^25.0.2",
52
52
  "tsup": "^8.5.1",
53
53
  "typescript": "^5.9.3",