@chappibunny/repolens 1.10.0 → 1.12.0

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.
@@ -5,6 +5,9 @@ import { inferDataFlows } from "../analyzers/flow-inference.js";
5
5
  import { analyzeGraphQL } from "../analyzers/graphql-analyzer.js";
6
6
  import { analyzeTypeScript } from "../analyzers/typescript-analyzer.js";
7
7
  import { analyzeDependencyGraph } from "../analyzers/dependency-graph.js";
8
+ import { analyzeJSDoc } from "../analyzers/jsdoc-analyzer.js";
9
+ import { analyzeSecurityPatterns } from "../analyzers/security-patterns.js";
10
+ import { analyzeComplexity, computeCodeHealth } from "../analyzers/complexity-analyzer.js";
8
11
  import { buildSnapshot, loadBaseline, saveBaseline, detectDrift } from "../analyzers/drift-detector.js";
9
12
  import { parseCodeowners, buildOwnershipMap } from "../analyzers/codeowners.js";
10
13
  import { getActiveDocuments } from "../ai/document-plan.js";
@@ -25,7 +28,9 @@ import {
25
28
  renderGraphQLSchema,
26
29
  renderTypeGraph,
27
30
  renderDependencyGraph,
28
- renderArchitectureDrift as renderDriftReport
31
+ renderArchitectureDrift as renderDriftReport,
32
+ renderCodeHealth,
33
+ renderSecurityHotspots
29
34
  } from "../renderers/renderAnalysis.js";
30
35
  import { info, warn } from "../utils/logger.js";
31
36
  import path from "node:path";
@@ -46,9 +51,15 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
46
51
  let graphqlResult = { detected: false };
47
52
  let tsResult = { detected: false };
48
53
  let depGraph = { stats: {}, graph: {} };
54
+ let jsdocResult = { detected: false, exports: [], summary: null };
49
55
  try { graphqlResult = await analyzeGraphQL(scanFiles, repoRoot); } catch (e) { warn(`GraphQL analysis failed: ${e.message}`); }
50
56
  try { tsResult = await analyzeTypeScript(scanFiles, repoRoot); } catch (e) { warn(`TypeScript analysis failed: ${e.message}`); }
51
57
  try { depGraph = await analyzeDependencyGraph(scanFiles, repoRoot); } catch (e) { warn(`Dependency graph analysis failed: ${e.message}`); }
58
+ try { jsdocResult = await analyzeJSDoc(scanFiles, repoRoot); } catch (e) { warn(`JSDoc analysis failed: ${e.message}`); }
59
+ let securityResult = { detected: false, findings: [], bySeverity: { high: 0, medium: 0, low: 0 } };
60
+ try { securityResult = await analyzeSecurityPatterns(scanFiles, repoRoot); } catch (e) { warn(`Security pattern analysis failed: ${e.message}`); }
61
+ let complexityResult = { files: [], functions: [], filesAnalyzed: 0 };
62
+ try { complexityResult = await analyzeComplexity(scanFiles, repoRoot); } catch (e) { warn(`Complexity analysis failed: ${e.message}`); }
52
63
 
53
64
  // Architecture drift detection
54
65
  const outputDir = path.join(repoRoot, ".repolens");
@@ -73,6 +84,10 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
73
84
  const ownershipMap = codeowners.found
74
85
  ? buildOwnershipMap(scanResult.modules, scanFiles, codeowners.rules)
75
86
  : {};
87
+
88
+ // Compute unified code health scores (synthesizes complexity + coupling + docs + security)
89
+ let codeHealthResult = { modules: [], summary: "No health data", stats: { totalFiles: 0, avgScore: 100, avgComplexity: 0, gradeDistribution: { A: 0, B: 0, C: 0, D: 0, F: 0 } }, hotspots: [], topComplexFunctions: [] };
90
+ try { codeHealthResult = computeCodeHealth(complexityResult, depGraph, jsdocResult, securityResult); } catch (e) { warn(`Code health computation failed: ${e.message}`); }
76
91
 
77
92
  // Get active documents based on config
78
93
  const activeDocuments = getActiveDocuments(config);
@@ -86,8 +101,11 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
86
101
  flows,
87
102
  graphql: graphqlResult.detected ? graphqlResult : undefined,
88
103
  typescript: tsResult.detected ? tsResult : undefined,
104
+ jsdoc: jsdocResult.detected ? jsdocResult : undefined,
89
105
  dependencyGraph: depGraph.stats,
90
106
  drift: driftResult,
107
+ security: securityResult.detected ? securityResult : undefined,
108
+ codeHealth: complexityResult.files.length > 0 ? true : undefined,
91
109
  codeowners: codeowners.found ? { file: codeowners.file, ruleCount: codeowners.rules.length } : undefined,
92
110
  ownershipMap: Object.keys(ownershipMap).length > 0 ? ownershipMap : undefined,
93
111
  };
@@ -117,8 +135,11 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
117
135
  diffData,
118
136
  graphqlResult,
119
137
  tsResult,
138
+ jsdocResult,
120
139
  depGraph,
121
140
  driftResult,
141
+ securityResult,
142
+ codeHealthResult,
122
143
  ownershipMap,
123
144
  pluginManager,
124
145
  });
@@ -167,8 +188,11 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
167
188
  diffData,
168
189
  graphqlResult,
169
190
  tsResult,
191
+ jsdocResult,
170
192
  depGraph,
171
193
  driftResult,
194
+ securityResult,
195
+ codeHealthResult,
172
196
  });
173
197
 
174
198
  documents.push({
@@ -203,7 +227,7 @@ export async function generateDocumentSet(scanResult, config, diffData = null, p
203
227
 
204
228
  async function generateDocument(docPlan, context) {
205
229
  const { key } = docPlan;
206
- const { scanResult, config, aiContext, moduleContext, flows, diffData, graphqlResult, tsResult, depGraph, driftResult, ownershipMap, pluginManager } = context;
230
+ const { scanResult, config, aiContext, moduleContext, flows, diffData, graphqlResult, tsResult, jsdocResult, depGraph, driftResult, securityResult, codeHealthResult, ownershipMap, pluginManager } = context;
207
231
 
208
232
  switch (key) {
209
233
  case "executive_summary":
@@ -227,8 +251,8 @@ async function generateDocument(docPlan, context) {
227
251
  return renderRouteMapOriginal(config, scanResult, aiContext);
228
252
 
229
253
  case "api_surface":
230
- // Hybrid: deterministic skeleton + AI enhancement (for now, just deterministic)
231
- return renderApiSurfaceOriginal(config, scanResult);
254
+ // Hybrid: deterministic skeleton + JSDoc documentation
255
+ return renderApiSurfaceOriginal(config, scanResult, jsdocResult);
232
256
 
233
257
  case "data_flows":
234
258
  return await generateDataFlows(flows, aiContext, { depGraph, scanResult, moduleContext }, config);
@@ -258,6 +282,12 @@ async function generateDocument(docPlan, context) {
258
282
  case "architecture_drift":
259
283
  return renderDriftReport(driftResult);
260
284
 
285
+ case "security_hotspots":
286
+ return renderSecurityHotspots(securityResult);
287
+
288
+ case "code_health":
289
+ return renderCodeHealth(codeHealthResult);
290
+
261
291
  default: {
262
292
  // Check if a plugin provides this renderer
263
293
  if (pluginManager) {