@rayburst/cli 0.2.2 → 0.2.4

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.
@@ -8,6 +8,25 @@ import crypto from "crypto";
8
8
  // src/git-utils.ts
9
9
  import { execSync } from "child_process";
10
10
  import path from "path";
11
+ function getUncommittedChanges(projectPath) {
12
+ try {
13
+ if (!isGitRepository(projectPath)) {
14
+ return [];
15
+ }
16
+ const command = "git diff --name-only HEAD && git diff --name-only --cached";
17
+ const output = execSync(command, {
18
+ cwd: projectPath,
19
+ encoding: "utf8",
20
+ stdio: ["pipe", "pipe", "ignore"]
21
+ // Ignore stderr
22
+ });
23
+ const files = output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
24
+ return [...new Set(files)];
25
+ } catch (error) {
26
+ console.error("Failed to get git diff:", error.message);
27
+ return [];
28
+ }
29
+ }
11
30
  function isGitRepository(projectPath) {
12
31
  try {
13
32
  execSync("git rev-parse --is-inside-work-tree", {
@@ -20,6 +39,27 @@ function isGitRepository(projectPath) {
20
39
  return false;
21
40
  }
22
41
  }
42
+ function getUntrackedFiles(projectPath) {
43
+ try {
44
+ if (!isGitRepository(projectPath)) {
45
+ return [];
46
+ }
47
+ const output = execSync("git ls-files --others --exclude-standard", {
48
+ cwd: projectPath,
49
+ encoding: "utf8",
50
+ stdio: ["pipe", "pipe", "ignore"]
51
+ });
52
+ return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
53
+ } catch (error) {
54
+ console.error("Failed to get untracked files:", error.message);
55
+ return [];
56
+ }
57
+ }
58
+ function getAllChangedFiles(projectPath) {
59
+ const uncommitted = getUncommittedChanges(projectPath);
60
+ const untracked = getUntrackedFiles(projectPath);
61
+ return [.../* @__PURE__ */ new Set([...uncommitted, ...untracked])];
62
+ }
23
63
  function getChangedFilesVsRemote(projectPath, remoteBranch = void 0) {
24
64
  try {
25
65
  if (!isGitRepository(projectPath)) {
@@ -74,7 +114,9 @@ function getChangedFilesVsRemote(projectPath, remoteBranch = void 0) {
74
114
  encoding: "utf8",
75
115
  stdio: ["pipe", "pipe", "ignore"]
76
116
  });
77
- return output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
117
+ const committedChanges = output.split("\n").filter(Boolean).map((file) => path.resolve(projectPath, file.trim()));
118
+ const uncommittedChanges = getAllChangedFiles(projectPath);
119
+ return [.../* @__PURE__ */ new Set([...committedChanges, ...uncommittedChanges])];
78
120
  } catch (error) {
79
121
  console.warn("Failed to get changed files vs remote:", error.message);
80
122
  return [];
@@ -267,10 +309,119 @@ function getUniqueNodeId(filePath, nodeName, gitHash, usedIds, idCounters) {
267
309
  return id;
268
310
  }
269
311
  function isReactComponent(func) {
312
+ const name = func.getName() || func.getParent()?.asKind?.(SyntaxKind.VariableDeclaration)?.getName?.();
313
+ const hasComponentName = name && /^[A-Z]/.test(name);
314
+ const returnType = func.getReturnType().getText();
315
+ const hasJsxReturnType = returnType.includes("JSX.Element") || returnType.includes("React.ReactElement") || returnType.includes("ReactElement") || returnType.includes("React.ReactNode") || returnType.includes("ReactNode");
270
316
  const body = func.getBody();
271
317
  if (!body) return false;
272
- const text = body.getText();
273
- return text.includes("return") && (text.includes("</") || text.includes("<>") || text.includes("jsx"));
318
+ const hasJsxElements = body.getDescendantsOfKind(SyntaxKind.JsxElement).length > 0 || body.getDescendantsOfKind(SyntaxKind.JsxSelfClosingElement).length > 0 || body.getDescendantsOfKind(SyntaxKind.JsxFragment).length > 0;
319
+ const hasHooks = body.getDescendantsOfKind(SyntaxKind.CallExpression).some((call) => {
320
+ const expr = call.getExpression().getText();
321
+ return expr.startsWith("use") && /^use[A-Z]/.test(expr);
322
+ });
323
+ if (hasJsxElements) return true;
324
+ if (hasJsxReturnType) return true;
325
+ if (hasComponentName && hasHooks) return true;
326
+ return false;
327
+ }
328
+ function analyzeReturnStatements(func) {
329
+ const body = func.getBody();
330
+ if (!body) {
331
+ return {
332
+ hasJsxReturn: false,
333
+ hasNullReturn: false,
334
+ hasUndefinedReturn: false,
335
+ returnValueSummary: "void",
336
+ primaryReturnType: "undefined"
337
+ };
338
+ }
339
+ const returnStatements = body.getDescendantsOfKind(SyntaxKind.ReturnStatement);
340
+ let hasJsxReturn = false;
341
+ let hasNullReturn = false;
342
+ let hasUndefinedReturn = false;
343
+ const returnTypes = [];
344
+ for (const returnStmt of returnStatements) {
345
+ const expr = returnStmt.getExpression();
346
+ if (!expr) {
347
+ hasUndefinedReturn = true;
348
+ returnTypes.push("undefined");
349
+ continue;
350
+ }
351
+ if (Node.isJsxElement(expr) || Node.isJsxSelfClosingElement(expr) || Node.isJsxFragment(expr)) {
352
+ hasJsxReturn = true;
353
+ let jsxName = "JSX";
354
+ if (Node.isJsxElement(expr)) {
355
+ jsxName = expr.getOpeningElement().getTagNameNode().getText();
356
+ } else if (Node.isJsxSelfClosingElement(expr)) {
357
+ jsxName = expr.getTagNameNode().getText();
358
+ } else {
359
+ jsxName = "<>";
360
+ }
361
+ returnTypes.push(`<${jsxName}>`);
362
+ continue;
363
+ }
364
+ if (expr.getKind() === SyntaxKind.NullKeyword) {
365
+ hasNullReturn = true;
366
+ returnTypes.push("null");
367
+ continue;
368
+ }
369
+ if (expr.getKind() === SyntaxKind.Identifier && expr.getText() === "undefined") {
370
+ hasUndefinedReturn = true;
371
+ returnTypes.push("undefined");
372
+ continue;
373
+ }
374
+ if (Node.isConditionalExpression(expr)) {
375
+ const whenTrue = expr.getWhenTrue();
376
+ const whenFalse = expr.getWhenFalse();
377
+ const trueIsJsx = Node.isJsxElement(whenTrue) || Node.isJsxSelfClosingElement(whenTrue);
378
+ const falseIsJsx = Node.isJsxElement(whenFalse) || Node.isJsxSelfClosingElement(whenFalse);
379
+ if (trueIsJsx || falseIsJsx) hasJsxReturn = true;
380
+ if (whenTrue.getText() === "null") hasNullReturn = true;
381
+ if (whenFalse.getText() === "null") hasNullReturn = true;
382
+ const trueText = whenTrue.getText().length > 20 ? whenTrue.getText().substring(0, 17) + "..." : whenTrue.getText();
383
+ const falseText = whenFalse.getText().length > 20 ? whenFalse.getText().substring(0, 17) + "..." : whenFalse.getText();
384
+ returnTypes.push(`${trueText} : ${falseText}`);
385
+ continue;
386
+ }
387
+ const exprText = expr.getText();
388
+ const truncated = exprText.length > 50 ? exprText.substring(0, 47) + "..." : exprText;
389
+ returnTypes.push(truncated);
390
+ }
391
+ let primaryReturnType = "mixed";
392
+ if (hasJsxReturn && !hasNullReturn && !hasUndefinedReturn) {
393
+ primaryReturnType = "jsx";
394
+ } else if (hasNullReturn && !hasJsxReturn && !hasUndefinedReturn) {
395
+ primaryReturnType = "null";
396
+ } else if (hasUndefinedReturn && !hasJsxReturn && !hasNullReturn) {
397
+ primaryReturnType = "undefined";
398
+ } else if (returnTypes.length === 1) {
399
+ primaryReturnType = "primitive";
400
+ }
401
+ const uniqueReturns = Array.from(new Set(returnTypes));
402
+ const returnValueSummary = uniqueReturns.join(" | ") || "void";
403
+ return {
404
+ hasJsxReturn,
405
+ hasNullReturn,
406
+ hasUndefinedReturn,
407
+ returnValueSummary,
408
+ primaryReturnType
409
+ };
410
+ }
411
+ function getReturnDescription(returnAnalysis) {
412
+ if (returnAnalysis.hasJsxReturn && returnAnalysis.hasNullReturn) {
413
+ return "Returns JSX or null";
414
+ }
415
+ if (returnAnalysis.hasJsxReturn) {
416
+ return "Returns JSX";
417
+ }
418
+ if (returnAnalysis.hasNullReturn) {
419
+ return "Returns null";
420
+ }
421
+ if (returnAnalysis.hasUndefinedReturn) {
422
+ return "Returns void";
423
+ }
424
+ return "Returns value";
274
425
  }
275
426
  function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nodes, nodeMap, usedIds, idCounters) {
276
427
  let count = 0;
@@ -283,6 +434,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
283
434
  const params = func.getParameters();
284
435
  const propsParam = params[0];
285
436
  const propsType = propsParam ? propsParam.getType().getText() : "any";
437
+ const returnAnalysis = analyzeReturnStatements(func);
286
438
  const node = {
287
439
  id,
288
440
  type: "component",
@@ -291,7 +443,12 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
291
443
  componentName: name,
292
444
  props: propsType,
293
445
  label: name,
294
- description: `Component in ${relativePath}`
446
+ description: `Component in ${relativePath}`,
447
+ returnValueSummary: returnAnalysis.returnValueSummary,
448
+ returnDescription: getReturnDescription(returnAnalysis),
449
+ hasJsxReturn: returnAnalysis.hasJsxReturn,
450
+ hasNullReturn: returnAnalysis.hasNullReturn,
451
+ primaryReturnType: returnAnalysis.primaryReturnType
295
452
  }
296
453
  };
297
454
  nodes.push(node);
@@ -311,6 +468,7 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
311
468
  const params = init.getParameters();
312
469
  const propsParam = params[0];
313
470
  const propsType = propsParam ? propsParam.getType().getText() : "any";
471
+ const returnAnalysis = analyzeReturnStatements(init);
314
472
  const node = {
315
473
  id,
316
474
  type: "component",
@@ -319,7 +477,12 @@ function extractComponents(sourceFile, relativePath, gitHash, baseX, startY, nod
319
477
  componentName: name,
320
478
  props: propsType,
321
479
  label: name,
322
- description: `Component in ${relativePath}`
480
+ description: `Component in ${relativePath}`,
481
+ returnValueSummary: returnAnalysis.returnValueSummary,
482
+ returnDescription: getReturnDescription(returnAnalysis),
483
+ hasJsxReturn: returnAnalysis.hasJsxReturn,
484
+ hasNullReturn: returnAnalysis.hasNullReturn,
485
+ primaryReturnType: returnAnalysis.primaryReturnType
323
486
  }
324
487
  };
325
488
  nodes.push(node);
@@ -347,6 +510,7 @@ function extractFunctions(sourceFile, relativePath, gitHash, baseX, startY, node
347
510
  return `${paramName}: ${paramType}`;
348
511
  }).join(", ");
349
512
  const returnType = func.getReturnType().getText();
513
+ const returnAnalysis = analyzeReturnStatements(func);
350
514
  const node = {
351
515
  id,
352
516
  type: "function",
@@ -356,7 +520,12 @@ function extractFunctions(sourceFile, relativePath, gitHash, baseX, startY, node
356
520
  parameters: params,
357
521
  returnType,
358
522
  label: name,
359
- description: `Function in ${relativePath}`
523
+ description: `Function in ${relativePath}`,
524
+ returnValueSummary: returnAnalysis.returnValueSummary,
525
+ returnDescription: getReturnDescription(returnAnalysis),
526
+ hasJsxReturn: returnAnalysis.hasJsxReturn,
527
+ hasNullReturn: returnAnalysis.hasNullReturn,
528
+ primaryReturnType: returnAnalysis.primaryReturnType
360
529
  }
361
530
  };
362
531
  nodes.push(node);
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ import {
9
9
  readLocalMeta,
10
10
  writeLocalAnalysis,
11
11
  writeLocalMeta
12
- } from "./chunk-ZAT3D23Y.js";
12
+ } from "./chunk-74JMCHWV.js";
13
13
  export {
14
14
  addGitignoreEntry,
15
15
  analyzeProject,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  rayburstPlugin
3
- } from "./chunk-ZAT3D23Y.js";
3
+ } from "./chunk-74JMCHWV.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.2",
3
+ "version": "0.2.4",
4
4
  "description": "Rayburst - Automatic code analysis for TypeScript/JavaScript projects via Vite plugin",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -42,12 +42,12 @@
42
42
  }
43
43
  },
44
44
  "dependencies": {
45
- "@rayburst/types": "^0.1.3",
46
45
  "chalk": "^5.3.0",
47
46
  "ts-morph": "^21.0.1",
48
47
  "zod": "^4.2.0"
49
48
  },
50
49
  "devDependencies": {
50
+ "@rayburst/types": "^0.1.4",
51
51
  "@types/node": "^25.0.2",
52
52
  "tsup": "^8.5.1",
53
53
  "typescript": "^5.9.3",