@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.
- package/dist/{chunk-76MJ4WFX.js → chunk-5VOUWYVS.js} +149 -10
- package/dist/index.js +1 -1
- package/dist/vite-plugin.js +1 -1
- package/package.json +2 -2
|
@@ -434,15 +434,15 @@ function createRouterDecisionNode(sourceFilePath, gitHash, routeCount) {
|
|
|
434
434
|
};
|
|
435
435
|
}
|
|
436
436
|
function extractRoutePathFromFile(routeFilePath) {
|
|
437
|
-
let
|
|
438
|
-
if (
|
|
437
|
+
let path6 = routeFilePath.replace(/^src\/routes\//, "/").replace(/\.(tsx?|jsx?)$/, "").replace(/\/route$/, "").replace(/\/index$/, "");
|
|
438
|
+
if (path6 === "/__root") {
|
|
439
439
|
return "/";
|
|
440
440
|
}
|
|
441
|
-
|
|
442
|
-
if (
|
|
441
|
+
path6 = path6.replace(/\/\$([^/]+)/g, (_, param) => `/:${param}`);
|
|
442
|
+
if (path6 === "" || path6 === "/") {
|
|
443
443
|
return "/";
|
|
444
444
|
}
|
|
445
|
-
return
|
|
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
|
|
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
package/dist/vite-plugin.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rayburst/cli",
|
|
3
|
-
"version": "0.4.
|
|
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.
|
|
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",
|