@rayburst/cli 0.2.6 → 0.2.7

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.
@@ -124,6 +124,315 @@ function getChangedFilesVsRemote(projectPath, remoteBranch = void 0) {
124
124
  }
125
125
 
126
126
  // src/analysis/analyze-project.ts
127
+ function isIdentifier(node) {
128
+ return node?.getKind() === SyntaxKind.Identifier;
129
+ }
130
+ function isVariableDeclaration(node) {
131
+ return node?.getKind() === SyntaxKind.VariableDeclaration;
132
+ }
133
+ function isCallExpression(node) {
134
+ return node?.getKind() === SyntaxKind.CallExpression;
135
+ }
136
+ function isObjectLiteralExpression(node) {
137
+ return node?.getKind() === SyntaxKind.ObjectLiteralExpression;
138
+ }
139
+ function isImportDeclaration(node) {
140
+ return node?.getKind() === SyntaxKind.ImportDeclaration;
141
+ }
142
+ function traceIdentifierToDeclaration(node) {
143
+ if (!isIdentifier(node)) {
144
+ return null;
145
+ }
146
+ try {
147
+ const symbol = node.getSymbol();
148
+ if (!symbol) {
149
+ return null;
150
+ }
151
+ const declarations = symbol.getDeclarations();
152
+ if (declarations.length === 0) {
153
+ return null;
154
+ }
155
+ return declarations[0];
156
+ } catch (error) {
157
+ console.error(`[traceIdentifierToDeclaration] Error tracing identifier "${node.getText()}":`, error);
158
+ return null;
159
+ }
160
+ }
161
+ function getImportSourceFile(importDeclaration) {
162
+ if (!isImportDeclaration(importDeclaration)) {
163
+ return null;
164
+ }
165
+ try {
166
+ const moduleSpecifier = importDeclaration.getChildrenOfKind(SyntaxKind.StringLiteral)[0];
167
+ if (!moduleSpecifier) {
168
+ return null;
169
+ }
170
+ const symbol = moduleSpecifier.getSymbol();
171
+ if (!symbol) {
172
+ return null;
173
+ }
174
+ const declarations = symbol.getDeclarations();
175
+ if (declarations.length === 0) {
176
+ return null;
177
+ }
178
+ return declarations[0].getSourceFile();
179
+ } catch (error) {
180
+ console.error(`[getImportSourceFile] Error getting import source:`, error);
181
+ return null;
182
+ }
183
+ }
184
+ function traceVariableDataFlow(variableNode, maxDepth = 5) {
185
+ if (maxDepth <= 0) {
186
+ console.log("[traceVariableDataFlow] Max depth reached, stopping recursion");
187
+ return null;
188
+ }
189
+ if (!isVariableDeclaration(variableNode)) {
190
+ return null;
191
+ }
192
+ try {
193
+ const initializer = variableNode.getChildrenOfKind(SyntaxKind.CallExpression)[0] || variableNode.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0] || variableNode.getChildrenOfKind(SyntaxKind.Identifier)[0];
194
+ if (!initializer) {
195
+ return null;
196
+ }
197
+ if (isCallExpression(initializer) || isObjectLiteralExpression(initializer)) {
198
+ return initializer;
199
+ }
200
+ if (isIdentifier(initializer)) {
201
+ const declaration = traceIdentifierToDeclaration(initializer);
202
+ if (declaration && isVariableDeclaration(declaration)) {
203
+ return traceVariableDataFlow(declaration, maxDepth - 1);
204
+ }
205
+ return declaration;
206
+ }
207
+ return initializer;
208
+ } catch (error) {
209
+ console.error("[traceVariableDataFlow] Error tracing variable:", error);
210
+ return null;
211
+ }
212
+ }
213
+ function extractObjectLiteralProperties(objectLiteral) {
214
+ const properties = /* @__PURE__ */ new Map();
215
+ if (!isObjectLiteralExpression(objectLiteral)) {
216
+ return properties;
217
+ }
218
+ try {
219
+ const propertyAssignments = objectLiteral.getChildrenOfKind(SyntaxKind.PropertyAssignment);
220
+ for (const prop of propertyAssignments) {
221
+ const nameNode = prop.getChildrenOfKind(SyntaxKind.Identifier)[0];
222
+ if (!nameNode) continue;
223
+ const propName = nameNode.getText();
224
+ const children = prop.getChildren();
225
+ const valueNode = children[children.length - 1];
226
+ if (valueNode) {
227
+ properties.set(propName, valueNode);
228
+ }
229
+ }
230
+ const shorthandProperties = objectLiteral.getChildrenOfKind(SyntaxKind.ShorthandPropertyAssignment);
231
+ for (const prop of shorthandProperties) {
232
+ const nameNode = prop.getChildrenOfKind(SyntaxKind.Identifier)[0];
233
+ if (nameNode) {
234
+ const propName = nameNode.getText();
235
+ properties.set(propName, nameNode);
236
+ }
237
+ }
238
+ } catch (error) {
239
+ console.error("[extractObjectLiteralProperties] Error extracting properties:", error);
240
+ }
241
+ return properties;
242
+ }
243
+ function traceConfigProperty(configObject, propertyName) {
244
+ if (!isObjectLiteralExpression(configObject)) {
245
+ return null;
246
+ }
247
+ try {
248
+ const properties = extractObjectLiteralProperties(configObject);
249
+ const propertyValue = properties.get(propertyName);
250
+ if (!propertyValue) {
251
+ return null;
252
+ }
253
+ if (isIdentifier(propertyValue)) {
254
+ const declaration = traceIdentifierToDeclaration(propertyValue);
255
+ if (!declaration) {
256
+ return null;
257
+ }
258
+ if (isVariableDeclaration(declaration)) {
259
+ return traceVariableDataFlow(declaration);
260
+ }
261
+ if (isImportDeclaration(declaration.getParent())) {
262
+ return declaration.getParent();
263
+ }
264
+ return declaration;
265
+ }
266
+ if (isObjectLiteralExpression(propertyValue) || isCallExpression(propertyValue)) {
267
+ return propertyValue;
268
+ }
269
+ return propertyValue;
270
+ } catch (error) {
271
+ console.error(`[traceConfigProperty] Error tracing property "${propertyName}":`, error);
272
+ return null;
273
+ }
274
+ }
275
+ function extractComponentPathsFromImports(sourceFile, projectPath) {
276
+ const componentPaths = [];
277
+ try {
278
+ const importDeclarations = sourceFile.getChildrenOfKind(SyntaxKind.ImportDeclaration);
279
+ for (const importDecl of importDeclarations) {
280
+ try {
281
+ const importedSourceFile = getImportSourceFile(importDecl);
282
+ if (!importedSourceFile) {
283
+ continue;
284
+ }
285
+ const filePath = importedSourceFile.getFilePath();
286
+ const relativePath = filePath.replace(projectPath + "/", "");
287
+ if (relativePath.includes("node_modules")) {
288
+ continue;
289
+ }
290
+ componentPaths.push(relativePath);
291
+ } catch (error) {
292
+ console.error("[extractComponentPathsFromImports] Error processing import:", error);
293
+ }
294
+ }
295
+ } catch (error) {
296
+ console.error("[extractComponentPathsFromImports] Error extracting imports:", error);
297
+ }
298
+ return componentPaths;
299
+ }
300
+ function findNodesInFile(filePath, nodeMap) {
301
+ const nodes = [];
302
+ for (const [nodeId, node] of nodeMap.entries()) {
303
+ const filePathInId = nodeId.split("::")[0];
304
+ if (filePathInId === filePath) {
305
+ nodes.push(node);
306
+ }
307
+ }
308
+ return nodes;
309
+ }
310
+ function createConfigBasedEdges(sourceNode, targetFilePaths, nodeMap, edges, edgeType = "config") {
311
+ let edgesCreated = 0;
312
+ for (const targetFilePath of targetFilePaths) {
313
+ const targetNodes = findNodesInFile(targetFilePath, nodeMap);
314
+ for (const targetNode of targetNodes) {
315
+ if (sourceNode.id === targetNode.id) {
316
+ continue;
317
+ }
318
+ const edgeId = `e-${sourceNode.id}-${targetNode.id}`;
319
+ if (edges.find((e) => e.id === edgeId)) {
320
+ continue;
321
+ }
322
+ edges.push({
323
+ id: edgeId,
324
+ source: sourceNode.id,
325
+ target: targetNode.id,
326
+ type: "floating",
327
+ label: edgeType
328
+ });
329
+ edgesCreated++;
330
+ }
331
+ }
332
+ return edgesCreated;
333
+ }
334
+ function analyzeJsxPropsForComponents(jsxElement, propName, projectPath) {
335
+ const componentPaths = [];
336
+ try {
337
+ const attributes = jsxElement.getChildrenOfKind(SyntaxKind.JsxAttribute);
338
+ for (const attr of attributes) {
339
+ const attrName = attr.getChildrenOfKind(SyntaxKind.Identifier)[0]?.getText();
340
+ if (attrName !== propName) {
341
+ continue;
342
+ }
343
+ const initializer = attr.getChildrenOfKind(SyntaxKind.JsxExpression)[0];
344
+ if (!initializer) continue;
345
+ const identifier = initializer.getChildrenOfKind(SyntaxKind.Identifier)[0];
346
+ if (!identifier) continue;
347
+ const declaration = traceIdentifierToDeclaration(identifier);
348
+ if (!declaration || !isVariableDeclaration(declaration)) continue;
349
+ const dataFlow = traceVariableDataFlow(declaration);
350
+ if (!dataFlow || !isCallExpression(dataFlow)) continue;
351
+ const args = dataFlow.getChildrenOfKind(SyntaxKind.SyntaxList)[0];
352
+ if (!args) continue;
353
+ const configArg = args.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0];
354
+ if (!configArg) continue;
355
+ const commonPropNames = ["routeTree", "routes", "children", "components"];
356
+ for (const commonPropName of commonPropNames) {
357
+ const paths = traceConfigToComponentPaths(configArg, commonPropName, projectPath);
358
+ if (paths.length > 0) {
359
+ return paths;
360
+ }
361
+ }
362
+ }
363
+ } catch (error) {
364
+ console.error("[analyzeJsxPropsForComponents] Error:", error);
365
+ }
366
+ return componentPaths;
367
+ }
368
+ function traceConfigToComponentPaths(configObject, propertyName, projectPath) {
369
+ try {
370
+ const propertyNode = traceConfigProperty(configObject, propertyName);
371
+ if (!propertyNode) {
372
+ return [];
373
+ }
374
+ if (isImportDeclaration(propertyNode)) {
375
+ const sourceFile = getImportSourceFile(propertyNode);
376
+ if (sourceFile) {
377
+ return extractComponentPathsFromImports(sourceFile, projectPath);
378
+ }
379
+ }
380
+ if (isObjectLiteralExpression(propertyNode)) {
381
+ const properties = extractObjectLiteralProperties(propertyNode);
382
+ const allPaths = [];
383
+ for (const [, value] of properties) {
384
+ if (isIdentifier(value)) {
385
+ const decl = traceIdentifierToDeclaration(value);
386
+ if (decl && isImportDeclaration(decl.getParent())) {
387
+ const sourceFile = getImportSourceFile(decl.getParent());
388
+ if (sourceFile) {
389
+ const paths = extractComponentPathsFromImports(sourceFile, projectPath);
390
+ allPaths.push(...paths);
391
+ }
392
+ }
393
+ }
394
+ }
395
+ return allPaths;
396
+ }
397
+ } catch (error) {
398
+ console.error("[traceConfigToComponentPaths] Error:", error);
399
+ }
400
+ return [];
401
+ }
402
+ function detectConfigBasedComponents(sourceFile, nodeMap, edges, projectPath) {
403
+ let totalEdgesCreated = 0;
404
+ try {
405
+ const jsxElements = sourceFile.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement);
406
+ for (const jsxElement of jsxElements) {
407
+ const containingFunc = jsxElement.getFirstAncestorByKind(SyntaxKind.FunctionDeclaration) || jsxElement.getFirstAncestorByKind(SyntaxKind.ArrowFunction);
408
+ if (!containingFunc) continue;
409
+ const parentName = containingFunc.getName?.() || containingFunc.getParent()?.asKind(SyntaxKind.VariableDeclaration)?.getName() || null;
410
+ if (!parentName) continue;
411
+ const sourceNode = Array.from(nodeMap.values()).find((node) => {
412
+ const nodeName = node.id.split("::")[1];
413
+ return nodeName === parentName;
414
+ });
415
+ if (!sourceNode) continue;
416
+ const commonPropNames = ["router", "config", "routes", "navigation"];
417
+ for (const propName of commonPropNames) {
418
+ const componentPaths = analyzeJsxPropsForComponents(jsxElement, propName, projectPath);
419
+ if (componentPaths.length > 0) {
420
+ const edgesCreated = createConfigBasedEdges(
421
+ sourceNode,
422
+ componentPaths,
423
+ nodeMap,
424
+ edges,
425
+ `config:${propName}`
426
+ );
427
+ totalEdgesCreated += edgesCreated;
428
+ }
429
+ }
430
+ }
431
+ } catch (error) {
432
+ console.error("[detectConfigBasedComponents] Error:", error);
433
+ }
434
+ return totalEdgesCreated;
435
+ }
127
436
  async function analyzeProject(projectPath, projectId, onLog) {
128
437
  const logs = [];
129
438
  const log = (message) => {
@@ -184,7 +493,17 @@ async function analyzeProject(projectPath, projectId, onLog) {
184
493
  for (const sourceFile of sourceFiles) {
185
494
  generateEdges(sourceFile, nodeMap, edges);
186
495
  }
187
- log(` Generated ${edges.length} edges`);
496
+ log(` Generated ${edges.length} edges (syntactic analysis)`);
497
+ log(` Analyzing config-based components...`);
498
+ let totalConfigEdges = 0;
499
+ for (const sourceFile of sourceFiles) {
500
+ const configEdges = detectConfigBasedComponents(sourceFile, nodeMap, edges, projectPath);
501
+ totalConfigEdges += configEdges;
502
+ }
503
+ if (totalConfigEdges > 0) {
504
+ log(` Generated ${totalConfigEdges} additional edges from config analysis`);
505
+ }
506
+ log(` Total edges: ${edges.length}`);
188
507
  const packageJsonPath = path2.join(projectPath, "package.json");
189
508
  let packageJson = { name: path2.basename(projectPath) };
190
509
  if (fs.existsSync(packageJsonPath)) {
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-XZXZKHVG.js";
12
+ } from "./chunk-JMVBDG54.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rayburstPlugin
3
- } from "./chunk-XZXZKHVG.js";
3
+ } from "./chunk-JMVBDG54.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.2.6",
3
+ "version": "0.2.7",
4
4
  "description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",