@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.
- package/CHANGELOG.md +93 -0
- package/README.md +5 -5
- package/package.json +1 -1
- package/src/ai/document-plan.js +16 -0
- package/src/ai/generate-sections.js +6 -6
- package/src/ai/provider.js +27 -3
- package/src/analyzers/complexity-analyzer.js +297 -0
- package/src/analyzers/jsdoc-analyzer.js +354 -0
- package/src/analyzers/security-patterns.js +329 -0
- package/src/docs/generate-doc-set.js +34 -4
- package/src/init.js +484 -41
- package/src/publishers/github-wiki.js +10 -1
- package/src/publishers/markdown.js +3 -1
- package/src/renderers/render.js +96 -1
- package/src/renderers/renderAnalysis.js +184 -0
|
@@ -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 +
|
|
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) {
|