autodocs-engine 0.9.9 → 0.10.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/README.md +123 -117
- package/dist/anti-pattern-detector.js +22 -0
- package/dist/anti-pattern-detector.js.map +1 -1
- package/dist/ast-parser.js +31 -3
- package/dist/ast-parser.js.map +1 -1
- package/dist/benchmark/scorer.js +3 -1
- package/dist/benchmark/scorer.js.map +1 -1
- package/dist/bin/autodocs-engine.js +7 -0
- package/dist/bin/autodocs-engine.js.map +1 -1
- package/dist/bin/serve.d.ts +1 -0
- package/dist/bin/serve.js +5 -1
- package/dist/bin/serve.js.map +1 -1
- package/dist/bin/setup-hooks.d.ts +1 -0
- package/dist/bin/setup-hooks.js +59 -0
- package/dist/bin/setup-hooks.js.map +1 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.js +4 -0
- package/dist/config.js.map +1 -1
- package/dist/convention-extractor.js +10 -0
- package/dist/convention-extractor.js.map +1 -1
- package/dist/detectors/api-patterns.d.ts +2 -0
- package/dist/detectors/api-patterns.js +101 -0
- package/dist/detectors/api-patterns.js.map +1 -0
- package/dist/detectors/async-patterns.d.ts +2 -0
- package/dist/detectors/async-patterns.js +79 -0
- package/dist/detectors/async-patterns.js.map +1 -0
- package/dist/detectors/error-handling.js +82 -30
- package/dist/detectors/error-handling.js.map +1 -1
- package/dist/detectors/state-management.d.ts +2 -0
- package/dist/detectors/state-management.js +75 -0
- package/dist/detectors/state-management.js.map +1 -0
- package/dist/execution-flow.d.ts +23 -0
- package/dist/execution-flow.js +286 -0
- package/dist/execution-flow.js.map +1 -0
- package/dist/git-history.js +18 -7
- package/dist/git-history.js.map +1 -1
- package/dist/implicit-coupling.d.ts +7 -0
- package/dist/implicit-coupling.js +40 -0
- package/dist/implicit-coupling.js.map +1 -0
- package/dist/import-chain.js +12 -3
- package/dist/import-chain.js.map +1 -1
- package/dist/index.js +20 -1
- package/dist/index.js.map +1 -1
- package/dist/llm/serializer.js +8 -6
- package/dist/llm/serializer.js.map +1 -1
- package/dist/mcp/cache.d.ts +11 -1
- package/dist/mcp/cache.js +49 -7
- package/dist/mcp/cache.js.map +1 -1
- package/dist/mcp/queries.d.ts +19 -3
- package/dist/mcp/queries.js +342 -62
- package/dist/mcp/queries.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +42 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -0
- package/dist/mcp/tools.js +162 -20
- package/dist/mcp/tools.js.map +1 -1
- package/dist/output-validator.js +73 -0
- package/dist/output-validator.js.map +1 -1
- package/dist/pipeline.js +37 -0
- package/dist/pipeline.js.map +1 -1
- package/dist/symbol-graph.js +4 -0
- package/dist/symbol-graph.js.map +1 -1
- package/dist/type-enricher.d.ts +17 -0
- package/dist/type-enricher.js +127 -0
- package/dist/type-enricher.js.map +1 -0
- package/dist/type-resolver.d.ts +13 -0
- package/dist/type-resolver.js +75 -0
- package/dist/type-resolver.js.map +1 -0
- package/dist/types.d.ts +36 -3
- package/dist/types.js +5 -1
- package/dist/types.js.map +1 -1
- package/hooks/autodocs-hook.cjs +227 -0
- package/package.json +3 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"async-patterns.js","sourceRoot":"","sources":["../../src/detectors/async-patterns.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,47 +1,99 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// src/detectors/error-handling.ts — Error handling pattern detector
|
|
2
|
+
// Detects: custom error classes, Result/Either patterns, error class hierarchies.
|
|
3
|
+
// Does NOT use try/catch density — per adversarial review, that's a false signal
|
|
4
|
+
// (mature codebases use middleware/Result types, not widespread try/catch).
|
|
5
|
+
import { buildConfidence, sourceParsedFiles } from "../convention-extractor.js";
|
|
6
|
+
// Libraries that provide typed error/result patterns
|
|
7
|
+
const RESULT_LIBRARIES = {
|
|
8
|
+
neverthrow: "neverthrow (Result<T, E>)",
|
|
9
|
+
"fp-ts": "fp-ts (Either<E, A>)",
|
|
10
|
+
"oxide.ts": "oxide.ts (Result<T, E>)",
|
|
11
|
+
effect: "Effect (typed errors via Effect<A, E, R>)",
|
|
12
|
+
"ts-results": "ts-results (Result<T, E>)",
|
|
13
|
+
"true-myth": "true-myth (Result<T, E>)",
|
|
14
|
+
};
|
|
15
|
+
// Names that suggest a custom Result/Either type
|
|
16
|
+
const RESULT_EXPORT_NAMES = new Set(["Result", "Ok", "Err", "Either", "Left", "Right", "Success", "Failure"]);
|
|
17
|
+
export const errorHandlingDetector = (files, tiers, _warnings, _context) => {
|
|
3
18
|
const conventions = [];
|
|
4
19
|
const sourceFiles = sourceParsedFiles(files, tiers);
|
|
5
20
|
if (sourceFiles.length === 0)
|
|
6
21
|
return conventions;
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
22
|
+
// 1. Custom error classes — exports with kind:"class" and name ending in Error/Exception
|
|
23
|
+
const errorClasses = [];
|
|
24
|
+
for (const file of sourceFiles) {
|
|
25
|
+
for (const exp of file.exports) {
|
|
26
|
+
if (exp.kind === "class" && (/Error$/.test(exp.name) || /Exception$/.test(exp.name))) {
|
|
27
|
+
errorClasses.push(exp.name);
|
|
28
|
+
}
|
|
14
29
|
}
|
|
15
|
-
if (f.contentSignals.hasErrorBoundary)
|
|
16
|
-
errorBoundaryCount++;
|
|
17
30
|
}
|
|
18
|
-
if (
|
|
31
|
+
if (errorClasses.length >= 2) {
|
|
32
|
+
// Check for hierarchy pattern: multiple error classes suggest a typed error hierarchy
|
|
33
|
+
const isHierarchy = errorClasses.length >= 3;
|
|
34
|
+
const name = isHierarchy ? "Typed error class hierarchy" : "Custom error classes";
|
|
35
|
+
const description = isHierarchy
|
|
36
|
+
? `Uses a hierarchy of ${errorClasses.length} typed error classes (${errorClasses.slice(0, 3).join(", ")}${errorClasses.length > 3 ? `, ...${errorClasses.length - 3} more` : ""})`
|
|
37
|
+
: `Defines custom error classes: ${errorClasses.join(", ")}`;
|
|
19
38
|
conventions.push({
|
|
20
39
|
category: "error-handling",
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
40
|
+
source: "errorHandling",
|
|
41
|
+
name,
|
|
42
|
+
description,
|
|
43
|
+
confidence: buildConfidence(errorClasses.length, errorClasses.length),
|
|
44
|
+
examples: errorClasses.slice(0, 5),
|
|
25
45
|
});
|
|
26
46
|
}
|
|
27
|
-
|
|
47
|
+
// 2. Result/Either pattern — check imports for known result-type libraries (count files, not imports)
|
|
48
|
+
const resultLibraryImports = new Map();
|
|
49
|
+
for (const file of sourceFiles) {
|
|
50
|
+
const fileLibs = new Set(); // dedupe per file
|
|
51
|
+
for (const imp of file.imports) {
|
|
52
|
+
if (imp.isTypeOnly)
|
|
53
|
+
continue;
|
|
54
|
+
for (const [pkg, label] of Object.entries(RESULT_LIBRARIES)) {
|
|
55
|
+
if (imp.moduleSpecifier === pkg || imp.moduleSpecifier.startsWith(`${pkg}/`)) {
|
|
56
|
+
fileLibs.add(label);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const label of fileLibs) {
|
|
61
|
+
resultLibraryImports.set(label, (resultLibraryImports.get(label) ?? 0) + 1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (resultLibraryImports.size > 0) {
|
|
65
|
+
const totalFiles = [...resultLibraryImports.values()].reduce((a, b) => a + b, 0);
|
|
66
|
+
const libs = [...resultLibraryImports.entries()].sort((a, b) => b[1] - a[1]);
|
|
28
67
|
conventions.push({
|
|
29
68
|
category: "error-handling",
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
69
|
+
source: "errorHandling",
|
|
70
|
+
name: "Result/Either pattern",
|
|
71
|
+
description: `Uses ${libs[0][0]} for typed error handling (${totalFiles} files)`,
|
|
72
|
+
confidence: buildConfidence(totalFiles, sourceFiles.length),
|
|
73
|
+
examples: libs.map(([lib, count]) => `${lib}: ${count} files`),
|
|
34
74
|
});
|
|
35
75
|
}
|
|
76
|
+
// 3. Custom Result types — exports named Result/Ok/Err/Either without a library
|
|
77
|
+
if (resultLibraryImports.size === 0) {
|
|
78
|
+
const resultExports = [];
|
|
79
|
+
for (const file of sourceFiles) {
|
|
80
|
+
for (const exp of file.exports) {
|
|
81
|
+
if (RESULT_EXPORT_NAMES.has(exp.name) && (exp.kind === "type" || exp.kind === "interface")) {
|
|
82
|
+
resultExports.push(exp.name);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (resultExports.length >= 2) {
|
|
87
|
+
conventions.push({
|
|
88
|
+
category: "error-handling",
|
|
89
|
+
source: "errorHandling",
|
|
90
|
+
name: "Custom Result type pattern",
|
|
91
|
+
description: `Defines custom Result types: ${[...new Set(resultExports)].join(", ")}`,
|
|
92
|
+
confidence: buildConfidence(resultExports.length, resultExports.length),
|
|
93
|
+
examples: [...new Set(resultExports)].slice(0, 5),
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
36
97
|
return conventions;
|
|
37
98
|
};
|
|
38
|
-
function conf(matched, total) {
|
|
39
|
-
const percentage = total > 0 ? Math.round((matched / total) * 100) : 0;
|
|
40
|
-
return {
|
|
41
|
-
matched,
|
|
42
|
-
total,
|
|
43
|
-
percentage,
|
|
44
|
-
description: `${matched} of ${total} (${percentage}%)`,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
99
|
//# sourceMappingURL=error-handling.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/detectors/error-handling.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"error-handling.js","sourceRoot":"","sources":["../../src/detectors/error-handling.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// src/detectors/state-management.ts — State management pattern detector
|
|
2
|
+
// Import-based detection for Redux, Zustand, Jotai, MobX, Recoil, Signals, Context API.
|
|
3
|
+
// Reports ALL detected libraries (dominant + supplementary) per adversarial review.
|
|
4
|
+
import { buildConfidence, sourceParsedFiles } from "../convention-extractor.js";
|
|
5
|
+
const STATE_LIBRARIES = {
|
|
6
|
+
redux: { label: "Redux", packages: ["@reduxjs/toolkit", "react-redux", "redux"] },
|
|
7
|
+
zustand: { label: "Zustand", packages: ["zustand"] },
|
|
8
|
+
jotai: { label: "Jotai", packages: ["jotai"] },
|
|
9
|
+
recoil: { label: "Recoil", packages: ["recoil"] },
|
|
10
|
+
mobx: { label: "MobX", packages: ["mobx", "mobx-react", "mobx-react-lite"] },
|
|
11
|
+
signals: { label: "Signals", packages: ["@preact/signals", "@preact/signals-react", "@angular/core"] },
|
|
12
|
+
valtio: { label: "Valtio", packages: ["valtio"] },
|
|
13
|
+
xstate: { label: "XState", packages: ["xstate", "@xstate/react"] },
|
|
14
|
+
};
|
|
15
|
+
export const stateManagementDetector = (files, tiers, _warnings, _context) => {
|
|
16
|
+
const conventions = [];
|
|
17
|
+
const sourceFiles = sourceParsedFiles(files, tiers);
|
|
18
|
+
if (sourceFiles.length === 0)
|
|
19
|
+
return conventions;
|
|
20
|
+
// Count files importing each state management library
|
|
21
|
+
const libFileCounts = new Map(); // library key → file count
|
|
22
|
+
for (const file of sourceFiles) {
|
|
23
|
+
const fileLibs = new Set(); // dedupe per file
|
|
24
|
+
for (const imp of file.imports) {
|
|
25
|
+
if (imp.isTypeOnly)
|
|
26
|
+
continue;
|
|
27
|
+
for (const [key, { packages }] of Object.entries(STATE_LIBRARIES)) {
|
|
28
|
+
if (packages.some((pkg) => imp.moduleSpecifier === pkg || imp.moduleSpecifier.startsWith(`${pkg}/`))) {
|
|
29
|
+
fileLibs.add(key);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for (const key of fileLibs) {
|
|
34
|
+
libFileCounts.set(key, (libFileCounts.get(key) ?? 0) + 1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// Detect Context API usage: imports of createContext from react
|
|
38
|
+
let contextApiFiles = 0;
|
|
39
|
+
for (const file of sourceFiles) {
|
|
40
|
+
for (const imp of file.imports) {
|
|
41
|
+
if (imp.isTypeOnly)
|
|
42
|
+
continue;
|
|
43
|
+
if (imp.moduleSpecifier === "react" && imp.importedNames.includes("createContext")) {
|
|
44
|
+
contextApiFiles++;
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (contextApiFiles > 0) {
|
|
50
|
+
libFileCounts.set("context", contextApiFiles);
|
|
51
|
+
}
|
|
52
|
+
if (libFileCounts.size === 0)
|
|
53
|
+
return conventions;
|
|
54
|
+
// Sort by file count descending
|
|
55
|
+
const sorted = [...libFileCounts.entries()].sort((a, b) => b[1] - a[1]);
|
|
56
|
+
const totalFiles = sorted.reduce((sum, [, count]) => sum + count, 0);
|
|
57
|
+
// Build description showing all detected libraries with roles
|
|
58
|
+
const dominant = sorted[0];
|
|
59
|
+
const dominantLabel = dominant[0] === "context" ? "React Context API" : (STATE_LIBRARIES[dominant[0]]?.label ?? dominant[0]);
|
|
60
|
+
const parts = [];
|
|
61
|
+
for (const [key, count] of sorted) {
|
|
62
|
+
const label = key === "context" ? "React Context API" : (STATE_LIBRARIES[key]?.label ?? key);
|
|
63
|
+
parts.push(`${label} (${count} files)`);
|
|
64
|
+
}
|
|
65
|
+
conventions.push({
|
|
66
|
+
category: "state-management",
|
|
67
|
+
source: "stateManagement",
|
|
68
|
+
name: sorted.length === 1 ? `${dominantLabel} state management` : `${dominantLabel} + ${sorted.length - 1} more`,
|
|
69
|
+
description: sorted.length === 1 ? `Uses ${dominantLabel} for state management` : `State management: ${parts.join(", ")}`,
|
|
70
|
+
confidence: buildConfidence(totalFiles, sourceFiles.length),
|
|
71
|
+
examples: parts,
|
|
72
|
+
});
|
|
73
|
+
return conventions;
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=state-management.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state-management.js","sourceRoot":"","sources":["../../src/detectors/state-management.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { CallGraphEdge, CoChangeEdge, DependencyInsights, ExecutionFlow, PublicAPIEntry } from "./types.js";
|
|
2
|
+
type NodeId = string;
|
|
3
|
+
interface ScoredEntry {
|
|
4
|
+
nodeId: NodeId;
|
|
5
|
+
score: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function scoreEntryPoints(callGraph: CallGraphEdge[], publicAPI: PublicAPIEntry[], dependencyInsights?: DependencyInsights): ScoredEntry[];
|
|
8
|
+
interface RawFlow {
|
|
9
|
+
nodeIds: NodeId[];
|
|
10
|
+
}
|
|
11
|
+
export declare function traceFlows(callGraph: CallGraphEdge[], entries: ScoredEntry[]): RawFlow[];
|
|
12
|
+
export declare function deduplicateFlows(candidates: RawFlow[], maxFlows: number): RawFlow[];
|
|
13
|
+
/**
|
|
14
|
+
* Enrich existing flows with co-change confidence scores.
|
|
15
|
+
* Called after git history is attached to the package analysis.
|
|
16
|
+
*/
|
|
17
|
+
export declare function enrichFlowConfidence(flows: ExecutionFlow[], coChangeEdges: CoChangeEdge[]): void;
|
|
18
|
+
/**
|
|
19
|
+
* Detect execution flows via forward BFS from scored entry points.
|
|
20
|
+
* Returns empty array if call graph is too sparse (<10 edges) or package is React-only.
|
|
21
|
+
*/
|
|
22
|
+
export declare function computeExecutionFlows(callGraph: CallGraphEdge[], publicAPI: PublicAPIEntry[], dependencyInsights?: DependencyInsights, coChangeEdges?: CoChangeEdge[]): ExecutionFlow[];
|
|
23
|
+
export {};
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
// src/execution-flow.ts — Execution flow tracing via forward BFS from entry points.
|
|
2
|
+
// Detects labeled execution paths: "runPipeline → analyzePackage → buildSymbolGraph (3 steps)"
|
|
3
|
+
// Uses spine-first tracing (full primary chain + fork paths) instead of fixed maxBranching.
|
|
4
|
+
// Co-change Jaccard validates flows — our unique advantage over GitNexus.
|
|
5
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
6
|
+
const MIN_CALL_GRAPH_EDGES = 10; // Skip flow detection for sparse graphs
|
|
7
|
+
const MAX_TRACE_DEPTH = 10; // Maximum steps in a single flow
|
|
8
|
+
const MIN_STEPS = 3; // Minimum steps for a meaningful flow
|
|
9
|
+
const MAX_FORK_PATHS = 3; // Alternative callees explored at each spine node
|
|
10
|
+
const MAX_TRACES_PER_ENTRY = 15; // Cap traces from a single entry point
|
|
11
|
+
function makeNodeId(file, fn) {
|
|
12
|
+
return `${file}#${fn}`;
|
|
13
|
+
}
|
|
14
|
+
function nodeName(id) {
|
|
15
|
+
return id.split("#")[1];
|
|
16
|
+
}
|
|
17
|
+
function nodeFile(id) {
|
|
18
|
+
return id.split("#")[0];
|
|
19
|
+
}
|
|
20
|
+
// ─── Entry Point Scoring ─────────────────────────────────────────────────────
|
|
21
|
+
// Boost: patterns that indicate genuine entry points in TS/JS
|
|
22
|
+
const ENTRY_PATTERNS = /^(main|run|start|handle|execute|process|serve|init|bootstrap|listen|register|setup|configure|launch)/i;
|
|
23
|
+
const ENTRY_SUFFIX_PATTERNS = /(?:Controller|Middleware|Handler|Router|Command|Plugin)$/;
|
|
24
|
+
// Penalty: utility functions that are rarely true entry points
|
|
25
|
+
const UTILITY_PATTERNS = /^(get|set|is|has|to|from|parse|format|validate|normalize|ensure|assert|check|clone|merge|map|filter|reduce|compose|pipe|wrap|create(?!.*Server))/i;
|
|
26
|
+
// Exclude: test orchestration functions
|
|
27
|
+
const TEST_PATTERNS = /^(describe|it|test|beforeEach|afterEach|beforeAll|afterAll|expect)$/;
|
|
28
|
+
// Framework-specific: high-value entry points detected from dependencies
|
|
29
|
+
const FRAMEWORK_PATTERNS = {
|
|
30
|
+
next: { patterns: [/^(getServerSideProps|getStaticProps|getStaticPaths|loader|action|default)$/], multiplier: 2.5 },
|
|
31
|
+
express: { patterns: [/Middleware$/i, /Router$/i], multiplier: 2.5 },
|
|
32
|
+
fastify: { patterns: [/Middleware$/i, /Router$/i], multiplier: 2.5 },
|
|
33
|
+
hono: { patterns: [/Middleware$/i, /Handler$/i], multiplier: 2.5 },
|
|
34
|
+
"@nestjs/core": { patterns: [/Controller$/i], multiplier: 2.5 },
|
|
35
|
+
"@nestjs/common": { patterns: [/Controller$/i], multiplier: 2.5 },
|
|
36
|
+
};
|
|
37
|
+
export function scoreEntryPoints(callGraph, publicAPI, dependencyInsights) {
|
|
38
|
+
// Build adjacency counts
|
|
39
|
+
const outDegree = new Map();
|
|
40
|
+
const inDegree = new Map();
|
|
41
|
+
const allNodes = new Set();
|
|
42
|
+
for (const edge of callGraph) {
|
|
43
|
+
const from = makeNodeId(edge.fromFile, edge.from);
|
|
44
|
+
const to = makeNodeId(edge.toFile, edge.to);
|
|
45
|
+
allNodes.add(from);
|
|
46
|
+
allNodes.add(to);
|
|
47
|
+
outDegree.set(from, (outDegree.get(from) ?? 0) + 1);
|
|
48
|
+
inDegree.set(to, (inDegree.get(to) ?? 0) + 1);
|
|
49
|
+
}
|
|
50
|
+
// Detect active frameworks for multipliers
|
|
51
|
+
const activeFrameworks = new Set();
|
|
52
|
+
if (dependencyInsights?.frameworks) {
|
|
53
|
+
for (const fw of dependencyInsights.frameworks) {
|
|
54
|
+
if (FRAMEWORK_PATTERNS[fw.name])
|
|
55
|
+
activeFrameworks.add(fw.name);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const exportedNames = new Set(publicAPI.filter((e) => !e.isTypeOnly).map((e) => e.name));
|
|
59
|
+
const scored = [];
|
|
60
|
+
for (const nodeId of allNodes) {
|
|
61
|
+
const fn = nodeName(nodeId);
|
|
62
|
+
const out = outDegree.get(nodeId) ?? 0;
|
|
63
|
+
const inD = inDegree.get(nodeId) ?? 0;
|
|
64
|
+
// Exclude test orchestration
|
|
65
|
+
if (TEST_PATTERNS.test(fn))
|
|
66
|
+
continue;
|
|
67
|
+
// Base: functions with high out-degree relative to in-degree are entry-like
|
|
68
|
+
const baseScore = (out + 1) / (inD + 1);
|
|
69
|
+
// Export boost: exported functions are more likely externally invoked
|
|
70
|
+
const exportMul = exportedNames.has(fn) ? 1.5 : 1.0;
|
|
71
|
+
// Zero-caller boost: exported with no internal callers = likely framework-invoked
|
|
72
|
+
const externalOnlyMul = inD === 0 && out >= 2 && exportedNames.has(fn) ? 1.8 : 1.0;
|
|
73
|
+
// Framework multiplier (checked first — overrides name penalty for framework entry points)
|
|
74
|
+
let frameworkMul = 1.0;
|
|
75
|
+
for (const fwName of activeFrameworks) {
|
|
76
|
+
const fw = FRAMEWORK_PATTERNS[fwName];
|
|
77
|
+
if (fw.patterns.some((p) => p.test(fn))) {
|
|
78
|
+
frameworkMul = Math.max(frameworkMul, fw.multiplier);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Name pattern multiplier (skip penalty if framework multiplier already boosted)
|
|
82
|
+
let nameMul = 1.0;
|
|
83
|
+
if (ENTRY_PATTERNS.test(fn) || ENTRY_SUFFIX_PATTERNS.test(fn))
|
|
84
|
+
nameMul = 2.0;
|
|
85
|
+
else if (UTILITY_PATTERNS.test(fn) && frameworkMul <= 1.0)
|
|
86
|
+
nameMul = 0.3;
|
|
87
|
+
const score = baseScore * exportMul * externalOnlyMul * nameMul * frameworkMul;
|
|
88
|
+
if (score > 0)
|
|
89
|
+
scored.push({ nodeId, score });
|
|
90
|
+
}
|
|
91
|
+
// Dynamic cap: scale with codebase size
|
|
92
|
+
const maxEntries = Math.max(10, Math.min(200, Math.floor(allNodes.size / 10)));
|
|
93
|
+
scored.sort((a, b) => b.score - a.score);
|
|
94
|
+
return scored.slice(0, maxEntries);
|
|
95
|
+
}
|
|
96
|
+
export function traceFlows(callGraph, entries) {
|
|
97
|
+
// Build forward adjacency with out-degree for callee ranking
|
|
98
|
+
const adj = new Map();
|
|
99
|
+
const outDegree = new Map();
|
|
100
|
+
for (const edge of callGraph) {
|
|
101
|
+
const from = makeNodeId(edge.fromFile, edge.from);
|
|
102
|
+
const to = makeNodeId(edge.toFile, edge.to);
|
|
103
|
+
const callees = adj.get(from) ?? [];
|
|
104
|
+
callees.push(to);
|
|
105
|
+
adj.set(from, callees);
|
|
106
|
+
outDegree.set(to, (outDegree.get(to) ?? 0) + (adj.get(to)?.length ?? 0));
|
|
107
|
+
}
|
|
108
|
+
// Recount out-degree properly
|
|
109
|
+
for (const [node, callees] of adj) {
|
|
110
|
+
outDegree.set(node, callees.length);
|
|
111
|
+
}
|
|
112
|
+
const allFlows = [];
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
const traces = [];
|
|
115
|
+
// PRIMARY SPINE: follow highest out-degree callee at each step (no branching limit)
|
|
116
|
+
const spine = traceSpine(entry.nodeId, adj, outDegree);
|
|
117
|
+
if (spine.length >= MIN_STEPS) {
|
|
118
|
+
traces.push({ nodeIds: spine });
|
|
119
|
+
}
|
|
120
|
+
// FORK PATHS: at each spine node, explore alternative callees
|
|
121
|
+
for (let i = 0; i < spine.length && traces.length < MAX_TRACES_PER_ENTRY; i++) {
|
|
122
|
+
const node = spine[i];
|
|
123
|
+
const callees = adj.get(node) ?? [];
|
|
124
|
+
if (callees.length <= 1)
|
|
125
|
+
continue; // No forks at this node
|
|
126
|
+
// Sort callees by out-degree descending, skip the spine callee
|
|
127
|
+
const spineNext = i + 1 < spine.length ? spine[i + 1] : null;
|
|
128
|
+
const forks = callees
|
|
129
|
+
.filter((c) => c !== spineNext)
|
|
130
|
+
.sort((a, b) => (outDegree.get(b) ?? 0) - (outDegree.get(a) ?? 0))
|
|
131
|
+
.slice(0, MAX_FORK_PATHS);
|
|
132
|
+
for (const fork of forks) {
|
|
133
|
+
// Trace a sub-spine from this fork point
|
|
134
|
+
const pathPrefix = spine.slice(0, i + 1);
|
|
135
|
+
const visited = new Set(pathPrefix);
|
|
136
|
+
if (visited.has(fork))
|
|
137
|
+
continue;
|
|
138
|
+
const forkSpine = traceSpine(fork, adj, outDegree, visited);
|
|
139
|
+
const fullPath = [...pathPrefix, ...forkSpine];
|
|
140
|
+
if (fullPath.length >= MIN_STEPS) {
|
|
141
|
+
traces.push({ nodeIds: fullPath });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
allFlows.push(...traces);
|
|
146
|
+
}
|
|
147
|
+
return allFlows;
|
|
148
|
+
}
|
|
149
|
+
/** Trace a single spine: follow highest out-degree callee at each step. */
|
|
150
|
+
function traceSpine(start, adj, outDegree, visited) {
|
|
151
|
+
const path = [start];
|
|
152
|
+
const seen = visited ?? new Set([start]);
|
|
153
|
+
if (visited)
|
|
154
|
+
seen.add(start);
|
|
155
|
+
let current = start;
|
|
156
|
+
for (let depth = 1; depth < MAX_TRACE_DEPTH; depth++) {
|
|
157
|
+
const callees = (adj.get(current) ?? []).filter((c) => !seen.has(c));
|
|
158
|
+
if (callees.length === 0)
|
|
159
|
+
break;
|
|
160
|
+
// Pick callee with highest out-degree (leads to deeper paths)
|
|
161
|
+
// Tie-break: alphabetical nodeId for determinism
|
|
162
|
+
callees.sort((a, b) => {
|
|
163
|
+
const diff = (outDegree.get(b) ?? 0) - (outDegree.get(a) ?? 0);
|
|
164
|
+
return diff !== 0 ? diff : a.localeCompare(b);
|
|
165
|
+
});
|
|
166
|
+
const next = callees[0];
|
|
167
|
+
seen.add(next);
|
|
168
|
+
path.push(next);
|
|
169
|
+
current = next;
|
|
170
|
+
}
|
|
171
|
+
return path;
|
|
172
|
+
}
|
|
173
|
+
// ─── Deduplication ───────────────────────────────────────────────────────────
|
|
174
|
+
export function deduplicateFlows(candidates, maxFlows) {
|
|
175
|
+
// Sort by length descending — longer flows are preferred
|
|
176
|
+
const sorted = [...candidates].sort((a, b) => b.nodeIds.length - a.nodeIds.length);
|
|
177
|
+
// Phase 1: Subset removal — discard flows that are contiguous subpaths of a longer flow
|
|
178
|
+
const kept = [];
|
|
179
|
+
for (const flow of sorted) {
|
|
180
|
+
const isSubset = kept.some((existing) => isContiguousSubpath(flow.nodeIds, existing.nodeIds));
|
|
181
|
+
if (!isSubset)
|
|
182
|
+
kept.push(flow);
|
|
183
|
+
}
|
|
184
|
+
// Phase 2: Endpoint dedup — keep longest per (entry, terminal) pair
|
|
185
|
+
const byEndpoints = new Map();
|
|
186
|
+
for (const flow of kept) {
|
|
187
|
+
const key = `${flow.nodeIds[0]}::${flow.nodeIds[flow.nodeIds.length - 1]}`;
|
|
188
|
+
const existing = byEndpoints.get(key);
|
|
189
|
+
if (!existing || flow.nodeIds.length > existing.nodeIds.length) {
|
|
190
|
+
byEndpoints.set(key, flow);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return [...byEndpoints.values()].sort((a, b) => b.nodeIds.length - a.nodeIds.length).slice(0, maxFlows);
|
|
194
|
+
}
|
|
195
|
+
/** Check if `sub` is a contiguous subpath of `sup` (sliding window). */
|
|
196
|
+
function isContiguousSubpath(sub, sup) {
|
|
197
|
+
if (sub.length >= sup.length)
|
|
198
|
+
return false;
|
|
199
|
+
for (let i = 0; i <= sup.length - sub.length; i++) {
|
|
200
|
+
if (sub.every((step, j) => step === sup[i + j]))
|
|
201
|
+
return true;
|
|
202
|
+
}
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
// ─── Co-Change Confidence ────────────────────────────────────────────────────
|
|
206
|
+
function computeFlowConfidence(files, coChangeEdges) {
|
|
207
|
+
if (!coChangeEdges || coChangeEdges.length === 0 || files.length < 2)
|
|
208
|
+
return 0;
|
|
209
|
+
// Build fast pairwise Jaccard lookup
|
|
210
|
+
const jaccardMap = new Map();
|
|
211
|
+
for (const e of coChangeEdges) {
|
|
212
|
+
jaccardMap.set(`${e.file1}\0${e.file2}`, e.jaccard);
|
|
213
|
+
jaccardMap.set(`${e.file2}\0${e.file1}`, e.jaccard);
|
|
214
|
+
}
|
|
215
|
+
let total = 0;
|
|
216
|
+
let pairs = 0;
|
|
217
|
+
for (let i = 0; i < files.length - 1; i++) {
|
|
218
|
+
if (files[i] === files[i + 1])
|
|
219
|
+
continue; // Skip same-file adjacent steps
|
|
220
|
+
total += jaccardMap.get(`${files[i]}\0${files[i + 1]}`) ?? 0;
|
|
221
|
+
pairs++;
|
|
222
|
+
}
|
|
223
|
+
return pairs > 0 ? total / pairs : 0;
|
|
224
|
+
}
|
|
225
|
+
// ─── Label Generation ────────────────────────────────────────────────────────
|
|
226
|
+
function generateLabel(steps, files) {
|
|
227
|
+
const uniqueFiles = new Set(files).size;
|
|
228
|
+
if (steps.length <= 4) {
|
|
229
|
+
return `${steps.join(" → ")} (${steps.length} steps, ${uniqueFiles} files)`;
|
|
230
|
+
}
|
|
231
|
+
return `${steps[0]} → ${steps[1]} → ... → ${steps[steps.length - 1]} (${steps.length} steps, ${uniqueFiles} files)`;
|
|
232
|
+
}
|
|
233
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
234
|
+
/**
|
|
235
|
+
* Enrich existing flows with co-change confidence scores.
|
|
236
|
+
* Called after git history is attached to the package analysis.
|
|
237
|
+
*/
|
|
238
|
+
export function enrichFlowConfidence(flows, coChangeEdges) {
|
|
239
|
+
for (const flow of flows) {
|
|
240
|
+
flow.confidence = computeFlowConfidence(flow.files, coChangeEdges);
|
|
241
|
+
}
|
|
242
|
+
// Re-sort by confidence
|
|
243
|
+
flows.sort((a, b) => b.confidence - a.confidence || b.length - a.length);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Detect execution flows via forward BFS from scored entry points.
|
|
247
|
+
* Returns empty array if call graph is too sparse (<10 edges) or package is React-only.
|
|
248
|
+
*/
|
|
249
|
+
export function computeExecutionFlows(callGraph, publicAPI, dependencyInsights, coChangeEdges) {
|
|
250
|
+
if (callGraph.length < MIN_CALL_GRAPH_EDGES)
|
|
251
|
+
return [];
|
|
252
|
+
// Score and select entry points
|
|
253
|
+
const entries = scoreEntryPoints(callGraph, publicAPI, dependencyInsights);
|
|
254
|
+
if (entries.length === 0)
|
|
255
|
+
return [];
|
|
256
|
+
// Trace flows via spine-first BFS
|
|
257
|
+
const rawFlows = traceFlows(callGraph, entries);
|
|
258
|
+
if (rawFlows.length === 0)
|
|
259
|
+
return [];
|
|
260
|
+
// Deduplicate
|
|
261
|
+
const functionCount = new Set(callGraph.flatMap((e) => [makeNodeId(e.fromFile, e.from), makeNodeId(e.toFile, e.to)]))
|
|
262
|
+
.size;
|
|
263
|
+
const maxFlows = Math.max(10, Math.min(200, Math.floor(functionCount / 10)));
|
|
264
|
+
const deduped = deduplicateFlows(rawFlows, maxFlows);
|
|
265
|
+
// Convert to ExecutionFlow with co-change confidence
|
|
266
|
+
const flows = deduped.map((raw) => {
|
|
267
|
+
const steps = raw.nodeIds.map(nodeName);
|
|
268
|
+
const files = raw.nodeIds.map(nodeFile);
|
|
269
|
+
const confidence = computeFlowConfidence(files, coChangeEdges);
|
|
270
|
+
return {
|
|
271
|
+
label: generateLabel(steps, files),
|
|
272
|
+
entryPoint: steps[0],
|
|
273
|
+
entryFile: files[0],
|
|
274
|
+
terminal: steps[steps.length - 1],
|
|
275
|
+
terminalFile: files[files.length - 1],
|
|
276
|
+
steps,
|
|
277
|
+
files,
|
|
278
|
+
length: steps.length,
|
|
279
|
+
confidence,
|
|
280
|
+
};
|
|
281
|
+
});
|
|
282
|
+
// Sort by confidence descending, then length descending
|
|
283
|
+
flows.sort((a, b) => b.confidence - a.confidence || b.length - a.length);
|
|
284
|
+
return flows;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=execution-flow.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execution-flow.js","sourceRoot":"","sources":["../src/execution-flow.ts"],"names":[],"mappings":"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"}
|
package/dist/git-history.js
CHANGED
|
@@ -8,8 +8,11 @@ import { relative, resolve } from "node:path";
|
|
|
8
8
|
import { SOURCE_EXTENSIONS } from "./types.js";
|
|
9
9
|
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
10
10
|
const MIN_COMMITS = 10;
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const INITIAL_MAX_COMMITS = 500;
|
|
12
|
+
const EXPANDED_MAX_COMMITS = 1000;
|
|
13
|
+
const FULL_MAX_COMMITS = 2000;
|
|
14
|
+
const MAX_DAYS = 365; // expanded from 90 — recency decay handles old data
|
|
15
|
+
const MIN_USEFUL_EDGES = 5; // minimum co-change edges before expanding
|
|
13
16
|
const MAX_FILES_PER_COMMIT = 30;
|
|
14
17
|
const HUB_FILE_THRESHOLD = 0.7;
|
|
15
18
|
const HUB_FILE_THRESHOLD_YOUNG = 0.9;
|
|
@@ -37,15 +40,23 @@ export function mineGitHistory(repoDir, packageDirs, warnings, options = {}) {
|
|
|
37
40
|
});
|
|
38
41
|
return null;
|
|
39
42
|
}
|
|
40
|
-
const maxCommits = options.maxCommits ?? MAX_COMMITS;
|
|
41
43
|
const maxDays = options.maxDays ?? MAX_DAYS;
|
|
42
|
-
const raw = runGitLog(absRepoDir, maxCommits, maxDays);
|
|
43
|
-
if (raw === null)
|
|
44
|
-
return null;
|
|
45
44
|
const gitRoot = resolveGitRoot(absRepoDir);
|
|
46
45
|
if (gitRoot === null)
|
|
47
46
|
return null;
|
|
48
|
-
|
|
47
|
+
// Adaptive windowing: start with 500 commits, expand if insufficient signal
|
|
48
|
+
const commitTargets = [options.maxCommits ?? INITIAL_MAX_COMMITS, EXPANDED_MAX_COMMITS, FULL_MAX_COMMITS];
|
|
49
|
+
let allCommits = [];
|
|
50
|
+
for (const target of commitTargets) {
|
|
51
|
+
if (allCommits.length >= target)
|
|
52
|
+
break; // already have enough from prior expansion
|
|
53
|
+
const raw = runGitLog(absRepoDir, target, maxDays);
|
|
54
|
+
if (raw === null)
|
|
55
|
+
return null;
|
|
56
|
+
allCommits = parseGitLog(raw);
|
|
57
|
+
if (allCommits.length >= target * 0.8)
|
|
58
|
+
break; // got most of what we asked for — no point expanding
|
|
59
|
+
}
|
|
49
60
|
if (allCommits.length < MIN_COMMITS) {
|
|
50
61
|
warnings.push({
|
|
51
62
|
level: "info",
|