@rayburst/cli 0.2.0 → 0.2.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.
- package/dist/chunk-NIOHEIF6.js +722 -0
- package/dist/index.d.ts +54 -6
- package/dist/index.js +24 -6
- package/dist/vite-plugin.d.ts +6 -3
- package/dist/vite-plugin.js +6 -109
- package/package.json +4 -3
- package/dist/analysis/analyze-project.d.ts +0 -9
- package/dist/analysis/analyze-project.js +0 -440
- package/dist/git-utils.d.ts +0 -33
- package/dist/git-utils.js +0 -96
- package/dist/incremental-analyzer.d.ts +0 -128
- package/dist/incremental-analyzer.js +0 -259
- package/dist/local-storage.d.ts +0 -39
- package/dist/local-storage.js +0 -117
- package/dist/registry.d.ts +0 -89
- package/dist/registry.js +0 -287
|
@@ -1,440 +0,0 @@
|
|
|
1
|
-
import { Project, SyntaxKind, Node } from 'ts-morph';
|
|
2
|
-
import { execSync } from 'child_process';
|
|
3
|
-
import * as fs from 'fs';
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import crypto from 'crypto';
|
|
6
|
-
/**
|
|
7
|
-
* Analyze a TypeScript/React project and generate nodes/edges data
|
|
8
|
-
* @param {string} projectPath - Absolute path to project root
|
|
9
|
-
* @param {string} projectId - Project ID
|
|
10
|
-
* @param {function} onLog - Callback for logging
|
|
11
|
-
* @returns {Promise<AnalysisResult>} Analysis data with nodes and edges
|
|
12
|
-
*/
|
|
13
|
-
export async function analyzeProject(projectPath, projectId, onLog) {
|
|
14
|
-
const logs = [];
|
|
15
|
-
const log = (message) => {
|
|
16
|
-
console.log(message);
|
|
17
|
-
logs.push(message);
|
|
18
|
-
// Call the callback if provided (for real-time streaming)
|
|
19
|
-
if (onLog) {
|
|
20
|
-
onLog(message);
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
log(`Analyzing project at: ${projectPath}`);
|
|
24
|
-
const gitHash = getGitHash(projectPath);
|
|
25
|
-
const gitInfo = getGitInfo(projectPath);
|
|
26
|
-
log(` Git hash: ${gitHash}`);
|
|
27
|
-
log(` Current branch: ${gitInfo.branch}`);
|
|
28
|
-
// Find tsconfig.json
|
|
29
|
-
const tsconfigPath = path.join(projectPath, 'tsconfig.json');
|
|
30
|
-
if (!fs.existsSync(tsconfigPath)) {
|
|
31
|
-
log(` Warning: No tsconfig.json found, skipping TypeScript analysis`);
|
|
32
|
-
const emptyAnalysis = createEmptyAnalysis(projectPath, gitInfo);
|
|
33
|
-
emptyAnalysis.logs = logs;
|
|
34
|
-
return emptyAnalysis;
|
|
35
|
-
}
|
|
36
|
-
try {
|
|
37
|
-
// Initialize ts-morph project
|
|
38
|
-
const project = new Project({
|
|
39
|
-
tsConfigFilePath: tsconfigPath,
|
|
40
|
-
});
|
|
41
|
-
const nodes = [];
|
|
42
|
-
const edges = [];
|
|
43
|
-
const nodeMap = new Map();
|
|
44
|
-
const usedIds = new Set();
|
|
45
|
-
const idCounters = new Map();
|
|
46
|
-
// Track file positions for layout
|
|
47
|
-
let fileIndex = 0;
|
|
48
|
-
const filePositions = new Map();
|
|
49
|
-
// Get all source files (excluding node_modules, test files)
|
|
50
|
-
const sourceFiles = project.getSourceFiles()
|
|
51
|
-
.filter(sf => {
|
|
52
|
-
const filePath = sf.getFilePath();
|
|
53
|
-
return !filePath.includes('node_modules') &&
|
|
54
|
-
!filePath.includes('.test.') &&
|
|
55
|
-
!filePath.includes('.spec.') &&
|
|
56
|
-
(filePath.endsWith('.ts') || filePath.endsWith('.tsx'));
|
|
57
|
-
});
|
|
58
|
-
log(` Analyzing ${sourceFiles.length} source files...`);
|
|
59
|
-
// Analyze each source file
|
|
60
|
-
for (let i = 0; i < sourceFiles.length; i++) {
|
|
61
|
-
const sourceFile = sourceFiles[i];
|
|
62
|
-
const filePath = sourceFile.getFilePath();
|
|
63
|
-
const relativePath = filePath.replace(projectPath + '/', '');
|
|
64
|
-
if (!filePositions.has(relativePath)) {
|
|
65
|
-
filePositions.set(relativePath, fileIndex++);
|
|
66
|
-
}
|
|
67
|
-
const baseX = (filePositions.get(relativePath) || 0) * 400;
|
|
68
|
-
let nodeY = 100;
|
|
69
|
-
// Extract React components
|
|
70
|
-
const components = extractComponents(sourceFile, relativePath, gitHash, baseX, nodeY, nodes, nodeMap, usedIds, idCounters);
|
|
71
|
-
nodeY += components * 150;
|
|
72
|
-
// Extract functions
|
|
73
|
-
const functions = extractFunctions(sourceFile, relativePath, gitHash, baseX, nodeY, nodes, nodeMap, usedIds, idCounters);
|
|
74
|
-
nodeY += functions * 150;
|
|
75
|
-
// Extract state declarations
|
|
76
|
-
const states = extractState(sourceFile, relativePath, gitHash, baseX, nodeY, nodes, nodeMap, usedIds, idCounters);
|
|
77
|
-
nodeY += states * 150;
|
|
78
|
-
// Yield to event loop every 10 files to allow SSE streaming
|
|
79
|
-
if (i % 10 === 0 && i > 0) {
|
|
80
|
-
await new Promise(resolve => setImmediate(resolve));
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
log(` Extracted ${nodes.length} nodes`);
|
|
84
|
-
// Generate edges by analyzing relationships
|
|
85
|
-
for (const sourceFile of sourceFiles) {
|
|
86
|
-
generateEdges(sourceFile, nodeMap, edges);
|
|
87
|
-
}
|
|
88
|
-
log(` Generated ${edges.length} edges`);
|
|
89
|
-
// Read package.json for project metadata
|
|
90
|
-
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
91
|
-
let packageJson = { name: path.basename(projectPath) };
|
|
92
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
93
|
-
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
94
|
-
}
|
|
95
|
-
const branchId = gitInfo.branch.replace(/[^a-zA-Z0-9]/g, '-');
|
|
96
|
-
const projectMetadata = {
|
|
97
|
-
id: projectId || crypto.createHash('md5').update(projectPath).digest('hex').substring(0, 12),
|
|
98
|
-
title: packageJson.name || path.basename(projectPath),
|
|
99
|
-
subtitle: new Date().toLocaleDateString(),
|
|
100
|
-
value: `${nodes.length} nodes`,
|
|
101
|
-
trend: 0,
|
|
102
|
-
chartData: [30, 40, 35, 50, 45, 60, 55, 70],
|
|
103
|
-
chartColor: '#22c55e',
|
|
104
|
-
};
|
|
105
|
-
const branchMetadata = {
|
|
106
|
-
id: branchId,
|
|
107
|
-
name: gitInfo.branch,
|
|
108
|
-
lastCommit: gitInfo.lastCommit,
|
|
109
|
-
lastCommitDate: 'just now',
|
|
110
|
-
author: gitInfo.author,
|
|
111
|
-
status: 'active',
|
|
112
|
-
commitCount: gitInfo.commitCount,
|
|
113
|
-
pullRequests: 0,
|
|
114
|
-
};
|
|
115
|
-
const planData = {
|
|
116
|
-
nodes,
|
|
117
|
-
edges,
|
|
118
|
-
};
|
|
119
|
-
const result = {
|
|
120
|
-
project: projectMetadata,
|
|
121
|
-
branches: [branchMetadata],
|
|
122
|
-
planData: {
|
|
123
|
-
[branchId]: planData
|
|
124
|
-
},
|
|
125
|
-
analyzedAt: new Date().toISOString(),
|
|
126
|
-
logs,
|
|
127
|
-
};
|
|
128
|
-
return result;
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
console.error(` Error analyzing project:`, error.message);
|
|
132
|
-
log(` Error: ${error.message}`);
|
|
133
|
-
const emptyAnalysis = createEmptyAnalysis(projectPath, gitInfo);
|
|
134
|
-
emptyAnalysis.logs = logs;
|
|
135
|
-
return emptyAnalysis;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
function createEmptyAnalysis(projectPath, gitInfo) {
|
|
139
|
-
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
140
|
-
let packageJson = { name: path.basename(projectPath) };
|
|
141
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
142
|
-
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
143
|
-
}
|
|
144
|
-
const branchId = gitInfo.branch.replace(/[^a-zA-Z0-9]/g, '-');
|
|
145
|
-
return {
|
|
146
|
-
project: {
|
|
147
|
-
id: crypto.createHash('md5').update(projectPath).digest('hex').substring(0, 12),
|
|
148
|
-
title: packageJson.name || path.basename(projectPath),
|
|
149
|
-
subtitle: new Date().toLocaleDateString(),
|
|
150
|
-
value: '0 nodes',
|
|
151
|
-
trend: 0,
|
|
152
|
-
chartData: [],
|
|
153
|
-
chartColor: '#6b7280',
|
|
154
|
-
},
|
|
155
|
-
branches: [{
|
|
156
|
-
id: branchId,
|
|
157
|
-
name: gitInfo.branch,
|
|
158
|
-
lastCommit: gitInfo.lastCommit,
|
|
159
|
-
lastCommitDate: 'just now',
|
|
160
|
-
author: gitInfo.author,
|
|
161
|
-
status: 'active',
|
|
162
|
-
commitCount: gitInfo.commitCount,
|
|
163
|
-
pullRequests: 0,
|
|
164
|
-
}],
|
|
165
|
-
planData: {},
|
|
166
|
-
analyzedAt: new Date().toISOString(),
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
function getGitHash(projectPath) {
|
|
170
|
-
try {
|
|
171
|
-
return execSync('git rev-parse --short HEAD', { cwd: projectPath, encoding: 'utf-8' }).trim();
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return 'nogit';
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
function getGitInfo(projectPath) {
|
|
178
|
-
try {
|
|
179
|
-
const branch = execSync('git branch --show-current', { cwd: projectPath, encoding: 'utf-8' }).trim() || 'main';
|
|
180
|
-
const lastCommit = execSync('git log -1 --pretty=%s', { cwd: projectPath, encoding: 'utf-8' }).trim() || 'No commits';
|
|
181
|
-
const author = execSync('git log -1 --pretty=%an', { cwd: projectPath, encoding: 'utf-8' }).trim() || 'Unknown';
|
|
182
|
-
const commitCount = parseInt(execSync('git rev-list --count HEAD', { cwd: projectPath, encoding: 'utf-8' }).trim() || '0');
|
|
183
|
-
return { branch, lastCommit, author, commitCount };
|
|
184
|
-
}
|
|
185
|
-
catch {
|
|
186
|
-
return {
|
|
187
|
-
branch: 'main',
|
|
188
|
-
lastCommit: 'No commits',
|
|
189
|
-
author: 'Unknown',
|
|
190
|
-
commitCount: 0
|
|
191
|
-
};
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
function createNodeId(filePath, nodeName, gitHash, counter = 0) {
|
|
195
|
-
const suffix = counter > 0 ? `-${counter}` : '';
|
|
196
|
-
return `${filePath}::${nodeName}${suffix}::${gitHash}`;
|
|
197
|
-
}
|
|
198
|
-
function getUniqueNodeId(filePath, nodeName, gitHash, usedIds, idCounters) {
|
|
199
|
-
const baseKey = `${filePath}::${nodeName}`;
|
|
200
|
-
const counter = idCounters.get(baseKey) || 0;
|
|
201
|
-
const id = createNodeId(filePath, nodeName, gitHash, counter);
|
|
202
|
-
if (usedIds.has(id)) {
|
|
203
|
-
idCounters.set(baseKey, counter + 1);
|
|
204
|
-
return getUniqueNodeId(filePath, nodeName, gitHash, usedIds, idCounters);
|
|
205
|
-
}
|
|
206
|
-
usedIds.add(id);
|
|
207
|
-
idCounters.set(baseKey, counter + 1);
|
|
208
|
-
return id;
|
|
209
|
-
}
|
|
210
|
-
function isReactComponent(func) {
|
|
211
|
-
const body = func.getBody();
|
|
212
|
-
if (!body)
|
|
213
|
-
return false;
|
|
214
|
-
const text = body.getText();
|
|
215
|
-
return text.includes('return') && (text.includes('</') || text.includes('<>') || text.includes('jsx'));
|
|
216
|
-
}
|
|
217
|
-
function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nodes, nodeMap, usedIds, idCounters) {
|
|
218
|
-
let count = 0;
|
|
219
|
-
let y = startY;
|
|
220
|
-
// Find function components
|
|
221
|
-
const functions = sourceFile.getFunctions();
|
|
222
|
-
for (const func of functions) {
|
|
223
|
-
if (isReactComponent(func)) {
|
|
224
|
-
const name = func.getName() || 'AnonymousComponent';
|
|
225
|
-
const id = getUniqueNodeId(relativePath, name, gitHash, usedIds, idCounters);
|
|
226
|
-
const params = func.getParameters();
|
|
227
|
-
const propsParam = params[0];
|
|
228
|
-
const propsType = propsParam ? propsParam.getType().getText() : 'any';
|
|
229
|
-
const node = {
|
|
230
|
-
id,
|
|
231
|
-
type: 'component',
|
|
232
|
-
position: { x: baseX, y: y },
|
|
233
|
-
data: {
|
|
234
|
-
componentName: name,
|
|
235
|
-
props: propsType,
|
|
236
|
-
label: name,
|
|
237
|
-
description: `Component in ${relativePath}`,
|
|
238
|
-
}
|
|
239
|
-
};
|
|
240
|
-
nodes.push(node);
|
|
241
|
-
nodeMap.set(id, node);
|
|
242
|
-
nodeMap.set(name, node);
|
|
243
|
-
count++;
|
|
244
|
-
y += 150;
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
// Find arrow function components
|
|
248
|
-
const variables = sourceFile.getVariableDeclarations();
|
|
249
|
-
for (const variable of variables) {
|
|
250
|
-
const init = variable.getInitializer();
|
|
251
|
-
if (init && (Node.isArrowFunction(init) || Node.isFunctionExpression(init))) {
|
|
252
|
-
if (isReactComponent(init)) {
|
|
253
|
-
const name = variable.getName();
|
|
254
|
-
const id = getUniqueNodeId(relativePath, name, gitHash, usedIds, idCounters);
|
|
255
|
-
const params = init.getParameters();
|
|
256
|
-
const propsParam = params[0];
|
|
257
|
-
const propsType = propsParam ? propsParam.getType().getText() : 'any';
|
|
258
|
-
const node = {
|
|
259
|
-
id,
|
|
260
|
-
type: 'component',
|
|
261
|
-
position: { x: baseX, y: y },
|
|
262
|
-
data: {
|
|
263
|
-
componentName: name,
|
|
264
|
-
props: propsType,
|
|
265
|
-
label: name,
|
|
266
|
-
description: `Component in ${relativePath}`,
|
|
267
|
-
}
|
|
268
|
-
};
|
|
269
|
-
nodes.push(node);
|
|
270
|
-
nodeMap.set(id, node);
|
|
271
|
-
nodeMap.set(name, node);
|
|
272
|
-
count++;
|
|
273
|
-
y += 150;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
return count;
|
|
278
|
-
}
|
|
279
|
-
function extractFunctions(sourceFile, relativePath, gitHash, baseX, startY, nodes, nodeMap, usedIds, idCounters) {
|
|
280
|
-
let count = 0;
|
|
281
|
-
let y = startY;
|
|
282
|
-
const functions = sourceFile.getFunctions();
|
|
283
|
-
for (const func of functions) {
|
|
284
|
-
if (!isReactComponent(func)) {
|
|
285
|
-
const name = func.getName() || 'anonymous';
|
|
286
|
-
if (name === 'anonymous')
|
|
287
|
-
continue;
|
|
288
|
-
const id = getUniqueNodeId(relativePath, name, gitHash, usedIds, idCounters);
|
|
289
|
-
const params = func.getParameters().map((p) => {
|
|
290
|
-
const paramName = p.getName();
|
|
291
|
-
const paramType = p.getType().getText();
|
|
292
|
-
return `${paramName}: ${paramType}`;
|
|
293
|
-
}).join(', ');
|
|
294
|
-
const returnType = func.getReturnType().getText();
|
|
295
|
-
const node = {
|
|
296
|
-
id,
|
|
297
|
-
type: 'function',
|
|
298
|
-
position: { x: baseX, y: y },
|
|
299
|
-
data: {
|
|
300
|
-
functionName: name,
|
|
301
|
-
parameters: params,
|
|
302
|
-
returnType: returnType,
|
|
303
|
-
label: name,
|
|
304
|
-
description: `Function in ${relativePath}`,
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
nodes.push(node);
|
|
308
|
-
nodeMap.set(id, node);
|
|
309
|
-
nodeMap.set(name, node);
|
|
310
|
-
count++;
|
|
311
|
-
y += 150;
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return count;
|
|
315
|
-
}
|
|
316
|
-
function extractState(sourceFile, relativePath, gitHash, baseX, startY, nodes, nodeMap, usedIds, idCounters) {
|
|
317
|
-
let count = 0;
|
|
318
|
-
let y = startY;
|
|
319
|
-
sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).forEach((callExpr) => {
|
|
320
|
-
const expr = callExpr.getExpression();
|
|
321
|
-
if (expr.getText() === 'useState') {
|
|
322
|
-
const parent = callExpr.getParent();
|
|
323
|
-
if (Node.isVariableDeclaration(parent)) {
|
|
324
|
-
const nameNode = parent.getNameNode();
|
|
325
|
-
if (Node.isArrayBindingPattern(nameNode)) {
|
|
326
|
-
const elements = nameNode.getElements();
|
|
327
|
-
if (elements.length > 0) {
|
|
328
|
-
const stateName = elements[0].getText();
|
|
329
|
-
const id = getUniqueNodeId(relativePath, stateName, gitHash, usedIds, idCounters);
|
|
330
|
-
const args = callExpr.getArguments();
|
|
331
|
-
const initialValue = args.length > 0 ? args[0].getText() : 'undefined';
|
|
332
|
-
const stateType = parent.getType().getText();
|
|
333
|
-
const node = {
|
|
334
|
-
id,
|
|
335
|
-
type: 'state',
|
|
336
|
-
position: { x: baseX, y: y },
|
|
337
|
-
data: {
|
|
338
|
-
stateName: stateName,
|
|
339
|
-
stateType: stateType,
|
|
340
|
-
initialValue: initialValue,
|
|
341
|
-
label: stateName,
|
|
342
|
-
description: `State in ${relativePath}`,
|
|
343
|
-
}
|
|
344
|
-
};
|
|
345
|
-
nodes.push(node);
|
|
346
|
-
nodeMap.set(id, node);
|
|
347
|
-
nodeMap.set(stateName, node);
|
|
348
|
-
count++;
|
|
349
|
-
y += 150;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
return count;
|
|
356
|
-
}
|
|
357
|
-
function generateEdges(sourceFile, nodeMap, edges) {
|
|
358
|
-
// Find JSX elements (component usage)
|
|
359
|
-
sourceFile.getDescendantsOfKind(SyntaxKind.JsxElement).forEach((jsxElement) => {
|
|
360
|
-
const openingElement = jsxElement.getOpeningElement();
|
|
361
|
-
const tagName = openingElement.getTagNameNode().getText();
|
|
362
|
-
const containingFunc = jsxElement.getFirstAncestorByKind(SyntaxKind.FunctionDeclaration) ||
|
|
363
|
-
jsxElement.getFirstAncestorByKind(SyntaxKind.ArrowFunction);
|
|
364
|
-
if (containingFunc) {
|
|
365
|
-
const parentName = containingFunc.getName?.() ||
|
|
366
|
-
containingFunc.getParent()?.asKind(SyntaxKind.VariableDeclaration)?.getName() ||
|
|
367
|
-
null;
|
|
368
|
-
if (parentName && nodeMap.has(parentName) && nodeMap.has(tagName)) {
|
|
369
|
-
const sourceNode = nodeMap.get(parentName);
|
|
370
|
-
const targetNode = nodeMap.get(tagName);
|
|
371
|
-
if (sourceNode && targetNode) {
|
|
372
|
-
const edgeId = `e-${sourceNode.id}-${targetNode.id}`;
|
|
373
|
-
if (!edges.find(e => e.id === edgeId)) {
|
|
374
|
-
edges.push({
|
|
375
|
-
id: edgeId,
|
|
376
|
-
source: sourceNode.id,
|
|
377
|
-
target: targetNode.id,
|
|
378
|
-
type: 'floating',
|
|
379
|
-
});
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
}
|
|
384
|
-
});
|
|
385
|
-
// Find self-closing JSX elements
|
|
386
|
-
sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement).forEach((jsxElement) => {
|
|
387
|
-
const tagName = jsxElement.getTagNameNode().getText();
|
|
388
|
-
const containingFunc = jsxElement.getFirstAncestorByKind(SyntaxKind.FunctionDeclaration) ||
|
|
389
|
-
jsxElement.getFirstAncestorByKind(SyntaxKind.ArrowFunction);
|
|
390
|
-
if (containingFunc) {
|
|
391
|
-
const parentName = containingFunc.getName?.() ||
|
|
392
|
-
containingFunc.getParent()?.asKind(SyntaxKind.VariableDeclaration)?.getName() ||
|
|
393
|
-
null;
|
|
394
|
-
if (parentName && nodeMap.has(parentName) && nodeMap.has(tagName)) {
|
|
395
|
-
const sourceNode = nodeMap.get(parentName);
|
|
396
|
-
const targetNode = nodeMap.get(tagName);
|
|
397
|
-
if (sourceNode && targetNode) {
|
|
398
|
-
const edgeId = `e-${sourceNode.id}-${targetNode.id}`;
|
|
399
|
-
if (!edges.find(e => e.id === edgeId)) {
|
|
400
|
-
edges.push({
|
|
401
|
-
id: edgeId,
|
|
402
|
-
source: sourceNode.id,
|
|
403
|
-
target: targetNode.id,
|
|
404
|
-
type: 'floating',
|
|
405
|
-
});
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
});
|
|
411
|
-
// Find function calls
|
|
412
|
-
sourceFile.getDescendantsOfKind(SyntaxKind.CallExpression).forEach((callExpr) => {
|
|
413
|
-
const expr = callExpr.getExpression();
|
|
414
|
-
const calledName = expr.getText().split('.').pop();
|
|
415
|
-
if (calledName && nodeMap.has(calledName)) {
|
|
416
|
-
const containingFunc = callExpr.getFirstAncestorByKind(SyntaxKind.FunctionDeclaration) ||
|
|
417
|
-
callExpr.getFirstAncestorByKind(SyntaxKind.ArrowFunction);
|
|
418
|
-
if (containingFunc) {
|
|
419
|
-
const parentName = containingFunc.getName?.() ||
|
|
420
|
-
containingFunc.getParent()?.asKind(SyntaxKind.VariableDeclaration)?.getName() ||
|
|
421
|
-
null;
|
|
422
|
-
if (parentName && nodeMap.has(parentName)) {
|
|
423
|
-
const sourceNode = nodeMap.get(parentName);
|
|
424
|
-
const targetNode = nodeMap.get(calledName);
|
|
425
|
-
if (sourceNode && targetNode && sourceNode.id !== targetNode.id) {
|
|
426
|
-
const edgeId = `e-${sourceNode.id}-${targetNode.id}`;
|
|
427
|
-
if (!edges.find(e => e.id === edgeId)) {
|
|
428
|
-
edges.push({
|
|
429
|
-
id: edgeId,
|
|
430
|
-
source: sourceNode.id,
|
|
431
|
-
target: targetNode.id,
|
|
432
|
-
type: 'floating',
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
});
|
|
440
|
-
}
|
package/dist/git-utils.d.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Git Utilities
|
|
3
|
-
*
|
|
4
|
-
* Helper functions to interact with git repositories
|
|
5
|
-
*/
|
|
6
|
-
/**
|
|
7
|
-
* Get list of uncommitted changed files in a git repository
|
|
8
|
-
*
|
|
9
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
10
|
-
* @returns {string[]} - Array of absolute file paths that have uncommitted changes
|
|
11
|
-
*/
|
|
12
|
-
export declare function getUncommittedChanges(projectPath: any): string[];
|
|
13
|
-
/**
|
|
14
|
-
* Check if a directory is a git repository
|
|
15
|
-
*
|
|
16
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
17
|
-
* @returns {boolean}
|
|
18
|
-
*/
|
|
19
|
-
export declare function isGitRepository(projectPath: any): boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Get list of untracked files in a git repository
|
|
22
|
-
*
|
|
23
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
24
|
-
* @returns {string[]} - Array of absolute file paths that are untracked
|
|
25
|
-
*/
|
|
26
|
-
export declare function getUntrackedFiles(projectPath: any): string[];
|
|
27
|
-
/**
|
|
28
|
-
* Get all files with changes (committed or not)
|
|
29
|
-
*
|
|
30
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
31
|
-
* @returns {string[]} - Array of absolute file paths
|
|
32
|
-
*/
|
|
33
|
-
export declare function getAllChangedFiles(projectPath: any): string[];
|
package/dist/git-utils.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
import { execSync } from 'child_process';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
/**
|
|
4
|
-
* Git Utilities
|
|
5
|
-
*
|
|
6
|
-
* Helper functions to interact with git repositories
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Get list of uncommitted changed files in a git repository
|
|
10
|
-
*
|
|
11
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
12
|
-
* @returns {string[]} - Array of absolute file paths that have uncommitted changes
|
|
13
|
-
*/
|
|
14
|
-
export function getUncommittedChanges(projectPath) {
|
|
15
|
-
try {
|
|
16
|
-
// Check if directory is a git repository
|
|
17
|
-
if (!isGitRepository(projectPath)) {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
// Get modified, added, and deleted files (staged and unstaged)
|
|
21
|
-
const command = 'git diff --name-only HEAD && git diff --name-only --cached';
|
|
22
|
-
const output = execSync(command, {
|
|
23
|
-
cwd: projectPath,
|
|
24
|
-
encoding: 'utf8',
|
|
25
|
-
stdio: ['pipe', 'pipe', 'ignore'], // Ignore stderr
|
|
26
|
-
});
|
|
27
|
-
// Parse output and convert to absolute paths
|
|
28
|
-
const files = output
|
|
29
|
-
.split('\n')
|
|
30
|
-
.filter(Boolean)
|
|
31
|
-
.map(file => path.resolve(projectPath, file.trim()));
|
|
32
|
-
// Remove duplicates
|
|
33
|
-
return [...new Set(files)];
|
|
34
|
-
}
|
|
35
|
-
catch (error) {
|
|
36
|
-
// If git command fails, return empty array
|
|
37
|
-
console.error('Failed to get git diff:', error.message);
|
|
38
|
-
return [];
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* Check if a directory is a git repository
|
|
43
|
-
*
|
|
44
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
45
|
-
* @returns {boolean}
|
|
46
|
-
*/
|
|
47
|
-
export function isGitRepository(projectPath) {
|
|
48
|
-
try {
|
|
49
|
-
execSync('git rev-parse --is-inside-work-tree', {
|
|
50
|
-
cwd: projectPath,
|
|
51
|
-
encoding: 'utf8',
|
|
52
|
-
stdio: ['pipe', 'pipe', 'ignore'],
|
|
53
|
-
});
|
|
54
|
-
return true;
|
|
55
|
-
}
|
|
56
|
-
catch {
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Get list of untracked files in a git repository
|
|
62
|
-
*
|
|
63
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
64
|
-
* @returns {string[]} - Array of absolute file paths that are untracked
|
|
65
|
-
*/
|
|
66
|
-
export function getUntrackedFiles(projectPath) {
|
|
67
|
-
try {
|
|
68
|
-
if (!isGitRepository(projectPath)) {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
const output = execSync('git ls-files --others --exclude-standard', {
|
|
72
|
-
cwd: projectPath,
|
|
73
|
-
encoding: 'utf8',
|
|
74
|
-
stdio: ['pipe', 'pipe', 'ignore'],
|
|
75
|
-
});
|
|
76
|
-
return output
|
|
77
|
-
.split('\n')
|
|
78
|
-
.filter(Boolean)
|
|
79
|
-
.map(file => path.resolve(projectPath, file.trim()));
|
|
80
|
-
}
|
|
81
|
-
catch (error) {
|
|
82
|
-
console.error('Failed to get untracked files:', error.message);
|
|
83
|
-
return [];
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Get all files with changes (committed or not)
|
|
88
|
-
*
|
|
89
|
-
* @param {string} projectPath - Absolute path to project directory
|
|
90
|
-
* @returns {string[]} - Array of absolute file paths
|
|
91
|
-
*/
|
|
92
|
-
export function getAllChangedFiles(projectPath) {
|
|
93
|
-
const uncommitted = getUncommittedChanges(projectPath);
|
|
94
|
-
const untracked = getUntrackedFiles(projectPath);
|
|
95
|
-
return [...new Set([...uncommitted, ...untracked])];
|
|
96
|
-
}
|
|
@@ -1,128 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Incremental Analyzer
|
|
3
|
-
*
|
|
4
|
-
* Performs incremental analysis by comparing new analysis results with
|
|
5
|
-
* previously stored results and generating a diff of changes.
|
|
6
|
-
*/
|
|
7
|
-
/**
|
|
8
|
-
* Perform incremental analysis on a project
|
|
9
|
-
*
|
|
10
|
-
* @param {string} projectId - Project identifier
|
|
11
|
-
* @param {string} projectPath - Absolute path to project
|
|
12
|
-
* @param {string[]} changedFiles - Optional array of changed file paths
|
|
13
|
-
* @returns {Object} - Incremental update with added, removed, and modified nodes/edges
|
|
14
|
-
*/
|
|
15
|
-
export declare function performIncrementalAnalysis(projectId: any, projectPath: any, changedFiles?: any[]): {
|
|
16
|
-
type: string;
|
|
17
|
-
analysis: Promise<{
|
|
18
|
-
project: {
|
|
19
|
-
id: string;
|
|
20
|
-
value: string;
|
|
21
|
-
title: string;
|
|
22
|
-
subtitle: string;
|
|
23
|
-
trend: number;
|
|
24
|
-
chartData: number[];
|
|
25
|
-
chartColor: string;
|
|
26
|
-
};
|
|
27
|
-
branches: {
|
|
28
|
-
id: string;
|
|
29
|
-
status: string;
|
|
30
|
-
name: string;
|
|
31
|
-
lastCommit: string;
|
|
32
|
-
lastCommitDate: string;
|
|
33
|
-
author: string;
|
|
34
|
-
commitCount: number;
|
|
35
|
-
pullRequests: number;
|
|
36
|
-
}[];
|
|
37
|
-
planData: Record<string, {
|
|
38
|
-
nodes: {
|
|
39
|
-
id: string;
|
|
40
|
-
type: "function" | "component" | "state" | "api" | "conditional" | "ternary" | "switch" | "try-catch" | "task";
|
|
41
|
-
position: {
|
|
42
|
-
x: number;
|
|
43
|
-
y: number;
|
|
44
|
-
};
|
|
45
|
-
data: {
|
|
46
|
-
label: string;
|
|
47
|
-
description?: string | undefined;
|
|
48
|
-
componentName?: string | undefined;
|
|
49
|
-
props?: string | undefined;
|
|
50
|
-
functionName?: string | undefined;
|
|
51
|
-
parameters?: string | undefined;
|
|
52
|
-
returnType?: string | undefined;
|
|
53
|
-
stateName?: string | undefined;
|
|
54
|
-
stateType?: string | undefined;
|
|
55
|
-
initialValue?: string | undefined;
|
|
56
|
-
method?: string | undefined;
|
|
57
|
-
endpoint?: string | undefined;
|
|
58
|
-
responseType?: string | undefined;
|
|
59
|
-
condition?: string | undefined;
|
|
60
|
-
trueLabel?: string | undefined;
|
|
61
|
-
falseLabel?: string | undefined;
|
|
62
|
-
ternaryCondition?: string | undefined;
|
|
63
|
-
ternaryTrue?: string | undefined;
|
|
64
|
-
ternaryFalse?: string | undefined;
|
|
65
|
-
trueValue?: string | undefined;
|
|
66
|
-
falseValue?: string | undefined;
|
|
67
|
-
switchExpression?: string | undefined;
|
|
68
|
-
cases?: string | undefined;
|
|
69
|
-
tryBlock?: string | undefined;
|
|
70
|
-
catchBlock?: string | undefined;
|
|
71
|
-
};
|
|
72
|
-
}[];
|
|
73
|
-
edges: {
|
|
74
|
-
id: string;
|
|
75
|
-
type: string;
|
|
76
|
-
source: string;
|
|
77
|
-
target: string;
|
|
78
|
-
label?: string | undefined;
|
|
79
|
-
sourceHandle?: string | undefined;
|
|
80
|
-
targetHandle?: string | undefined;
|
|
81
|
-
}[];
|
|
82
|
-
}>;
|
|
83
|
-
analyzedAt: string;
|
|
84
|
-
logs?: string[] | undefined;
|
|
85
|
-
}>;
|
|
86
|
-
update: {
|
|
87
|
-
added: {
|
|
88
|
-
nodes: any[];
|
|
89
|
-
edges: any[];
|
|
90
|
-
};
|
|
91
|
-
removed: {
|
|
92
|
-
nodeIds: any[];
|
|
93
|
-
edgeIds: any[];
|
|
94
|
-
};
|
|
95
|
-
modified: {
|
|
96
|
-
nodes: any[];
|
|
97
|
-
edges: any[];
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
};
|
|
101
|
-
/**
|
|
102
|
-
* Generate diff between old and new analysis
|
|
103
|
-
*
|
|
104
|
-
* @param {Object} oldAnalysis - Previous analysis data
|
|
105
|
-
* @param {Object} newAnalysis - New analysis data
|
|
106
|
-
* @returns {Object} - Incremental update object
|
|
107
|
-
*/
|
|
108
|
-
export declare function generateDiff(oldAnalysis: any, newAnalysis: any): {
|
|
109
|
-
added: {
|
|
110
|
-
nodes: any[];
|
|
111
|
-
edges: any[];
|
|
112
|
-
};
|
|
113
|
-
removed: {
|
|
114
|
-
nodeIds: any[];
|
|
115
|
-
edgeIds: any[];
|
|
116
|
-
};
|
|
117
|
-
modified: {
|
|
118
|
-
nodes: any[];
|
|
119
|
-
edges: any[];
|
|
120
|
-
};
|
|
121
|
-
};
|
|
122
|
-
/**
|
|
123
|
-
* Check if an update has any changes
|
|
124
|
-
*
|
|
125
|
-
* @param {Object} update - Incremental update object
|
|
126
|
-
* @returns {boolean}
|
|
127
|
-
*/
|
|
128
|
-
export declare function hasChanges(update: any): boolean;
|