projscan 0.4.0 → 0.6.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 +82 -33
- package/dist/analyzers/deadCodeCheck.d.ts +18 -0
- package/dist/analyzers/deadCodeCheck.js +168 -0
- package/dist/analyzers/deadCodeCheck.js.map +1 -0
- package/dist/cli/index.js +50 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/ast.d.ts +34 -0
- package/dist/core/ast.js +270 -0
- package/dist/core/ast.js.map +1 -0
- package/dist/core/codeGraph.d.ts +36 -0
- package/dist/core/codeGraph.js +167 -0
- package/dist/core/codeGraph.js.map +1 -0
- package/dist/core/coverageJoin.d.ts +6 -0
- package/dist/core/coverageJoin.js +50 -0
- package/dist/core/coverageJoin.js.map +1 -0
- package/dist/core/coverageParser.d.ts +15 -0
- package/dist/core/coverageParser.js +187 -0
- package/dist/core/coverageParser.js.map +1 -0
- package/dist/core/fileInspector.js +20 -13
- package/dist/core/fileInspector.js.map +1 -1
- package/dist/core/hotspotAnalyzer.d.ts +2 -0
- package/dist/core/hotspotAnalyzer.js +20 -1
- package/dist/core/hotspotAnalyzer.js.map +1 -1
- package/dist/core/importGraph.d.ts +5 -15
- package/dist/core/importGraph.js +12 -110
- package/dist/core/importGraph.js.map +1 -1
- package/dist/core/indexCache.d.ts +12 -0
- package/dist/core/indexCache.js +97 -0
- package/dist/core/indexCache.js.map +1 -0
- package/dist/core/issueEngine.js +2 -0
- package/dist/core/issueEngine.js.map +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +12 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tokenBudget.d.ts +25 -0
- package/dist/mcp/tokenBudget.js +89 -0
- package/dist/mcp/tokenBudget.js.map +1 -0
- package/dist/mcp/tools.js +197 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/reporters/consoleReporter.d.ts +2 -1
- package/dist/reporters/consoleReporter.js +39 -0
- package/dist/reporters/consoleReporter.js.map +1 -1
- package/dist/reporters/jsonReporter.d.ts +2 -1
- package/dist/reporters/jsonReporter.js +3 -0
- package/dist/reporters/jsonReporter.js.map +1 -1
- package/dist/reporters/markdownReporter.d.ts +2 -1
- package/dist/reporters/markdownReporter.js +27 -0
- package/dist/reporters/markdownReporter.js.map +1 -1
- package/dist/types.d.ts +33 -0
- package/dist/utils/banner.js +7 -6
- package/dist/utils/banner.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type SymbolKind = 'function' | 'class' | 'variable' | 'type' | 'interface' | 'enum' | 'default' | 'unknown';
|
|
2
|
+
export interface AstImport {
|
|
3
|
+
source: string;
|
|
4
|
+
kind: 'static' | 'dynamic' | 'require' | 'reexport';
|
|
5
|
+
specifiers: string[];
|
|
6
|
+
typeOnly: boolean;
|
|
7
|
+
line: number;
|
|
8
|
+
}
|
|
9
|
+
export interface AstExport {
|
|
10
|
+
name: string;
|
|
11
|
+
kind: SymbolKind;
|
|
12
|
+
typeOnly: boolean;
|
|
13
|
+
line: number;
|
|
14
|
+
}
|
|
15
|
+
export interface AstResult {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
reason?: string;
|
|
18
|
+
imports: AstImport[];
|
|
19
|
+
exports: AstExport[];
|
|
20
|
+
callSites: string[];
|
|
21
|
+
lineCount: number;
|
|
22
|
+
}
|
|
23
|
+
/** Is this a file we should try to AST-parse at all? */
|
|
24
|
+
export declare function isParseable(filePath: string): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Parse a source file and extract imports, exports, and call sites.
|
|
27
|
+
*
|
|
28
|
+
* Uses @babel/parser with generous options so we accept real-world code:
|
|
29
|
+
* TypeScript, JSX, decorators, top-level await, class properties, etc.
|
|
30
|
+
*
|
|
31
|
+
* Failures return ok:false with a reason — callers decide whether to fall
|
|
32
|
+
* back to regex or skip the file. Never throws.
|
|
33
|
+
*/
|
|
34
|
+
export declare function parseSource(filePath: string, content: string): AstResult;
|
package/dist/core/ast.js
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { parse } from '@babel/parser';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const EMPTY = {
|
|
4
|
+
ok: false,
|
|
5
|
+
reason: 'unparsed',
|
|
6
|
+
imports: [],
|
|
7
|
+
exports: [],
|
|
8
|
+
callSites: [],
|
|
9
|
+
lineCount: 0,
|
|
10
|
+
};
|
|
11
|
+
const SOURCE_EXTENSIONS = new Set([
|
|
12
|
+
'.ts',
|
|
13
|
+
'.tsx',
|
|
14
|
+
'.js',
|
|
15
|
+
'.jsx',
|
|
16
|
+
'.mjs',
|
|
17
|
+
'.cjs',
|
|
18
|
+
'.mts',
|
|
19
|
+
'.cts',
|
|
20
|
+
]);
|
|
21
|
+
/** Is this a file we should try to AST-parse at all? */
|
|
22
|
+
export function isParseable(filePath) {
|
|
23
|
+
return SOURCE_EXTENSIONS.has(path.extname(filePath).toLowerCase());
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse a source file and extract imports, exports, and call sites.
|
|
27
|
+
*
|
|
28
|
+
* Uses @babel/parser with generous options so we accept real-world code:
|
|
29
|
+
* TypeScript, JSX, decorators, top-level await, class properties, etc.
|
|
30
|
+
*
|
|
31
|
+
* Failures return ok:false with a reason — callers decide whether to fall
|
|
32
|
+
* back to regex or skip the file. Never throws.
|
|
33
|
+
*/
|
|
34
|
+
export function parseSource(filePath, content) {
|
|
35
|
+
if (!isParseable(filePath)) {
|
|
36
|
+
return { ...EMPTY, reason: 'non-source extension' };
|
|
37
|
+
}
|
|
38
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
39
|
+
const isTypeScript = ext === '.ts' || ext === '.tsx' || ext === '.mts' || ext === '.cts';
|
|
40
|
+
const isJSX = ext === '.tsx' || ext === '.jsx';
|
|
41
|
+
const plugins = [];
|
|
42
|
+
if (isTypeScript)
|
|
43
|
+
plugins.push('typescript');
|
|
44
|
+
if (isJSX)
|
|
45
|
+
plugins.push('jsx');
|
|
46
|
+
plugins.push('decorators-legacy', 'dynamicImport', 'topLevelAwait');
|
|
47
|
+
let ast;
|
|
48
|
+
try {
|
|
49
|
+
ast = parse(content, {
|
|
50
|
+
sourceType: 'module',
|
|
51
|
+
allowImportExportEverywhere: true,
|
|
52
|
+
allowAwaitOutsideFunction: true,
|
|
53
|
+
allowReturnOutsideFunction: true,
|
|
54
|
+
allowSuperOutsideMethod: true,
|
|
55
|
+
errorRecovery: true,
|
|
56
|
+
plugins,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
61
|
+
return { ...EMPTY, reason: `parse error: ${msg.slice(0, 120)}` };
|
|
62
|
+
}
|
|
63
|
+
const imports = [];
|
|
64
|
+
const exports = [];
|
|
65
|
+
const callSites = [];
|
|
66
|
+
for (const node of ast.program.body) {
|
|
67
|
+
visitTopLevel(node, imports, exports);
|
|
68
|
+
}
|
|
69
|
+
// Second pass: extract dynamic imports + call sites. Walk the whole tree
|
|
70
|
+
// (cheap — we already have the AST in memory).
|
|
71
|
+
walk(ast.program, (n) => {
|
|
72
|
+
if (n.type === 'CallExpression') {
|
|
73
|
+
const callee = n.callee;
|
|
74
|
+
if (callee.type === 'Identifier') {
|
|
75
|
+
callSites.push(callee.name);
|
|
76
|
+
}
|
|
77
|
+
else if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier') {
|
|
78
|
+
callSites.push(callee.property.name);
|
|
79
|
+
}
|
|
80
|
+
else if (callee.type === 'Import' && n.arguments[0] && n.arguments[0].type === 'StringLiteral') {
|
|
81
|
+
imports.push({
|
|
82
|
+
source: n.arguments[0].value,
|
|
83
|
+
kind: 'dynamic',
|
|
84
|
+
specifiers: [],
|
|
85
|
+
typeOnly: false,
|
|
86
|
+
line: n.loc?.start.line ?? 0,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// CommonJS require()
|
|
90
|
+
if (callee.type === 'Identifier' &&
|
|
91
|
+
callee.name === 'require' &&
|
|
92
|
+
n.arguments[0] &&
|
|
93
|
+
n.arguments[0].type === 'StringLiteral') {
|
|
94
|
+
imports.push({
|
|
95
|
+
source: n.arguments[0].value,
|
|
96
|
+
kind: 'require',
|
|
97
|
+
specifiers: [],
|
|
98
|
+
typeOnly: false,
|
|
99
|
+
line: n.loc?.start.line ?? 0,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return {
|
|
105
|
+
ok: true,
|
|
106
|
+
imports,
|
|
107
|
+
exports,
|
|
108
|
+
callSites: [...new Set(callSites)],
|
|
109
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function visitTopLevel(node, imports, exports) {
|
|
113
|
+
switch (node.type) {
|
|
114
|
+
case 'ImportDeclaration': {
|
|
115
|
+
imports.push(importFromNode(node));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
case 'ExportNamedDeclaration': {
|
|
119
|
+
collectNamedExport(node, exports, imports);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
case 'ExportDefaultDeclaration': {
|
|
123
|
+
exports.push({
|
|
124
|
+
name: 'default',
|
|
125
|
+
kind: 'default',
|
|
126
|
+
typeOnly: false,
|
|
127
|
+
line: node.loc?.start.line ?? 0,
|
|
128
|
+
});
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
case 'ExportAllDeclaration': {
|
|
132
|
+
const source = node.source.value;
|
|
133
|
+
imports.push({
|
|
134
|
+
source,
|
|
135
|
+
kind: 'reexport',
|
|
136
|
+
specifiers: [],
|
|
137
|
+
typeOnly: Boolean(node.exportKind === 'type'),
|
|
138
|
+
line: node.loc?.start.line ?? 0,
|
|
139
|
+
});
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function importFromNode(node) {
|
|
147
|
+
const specifiers = node.specifiers.map((s) => {
|
|
148
|
+
if (s.type === 'ImportDefaultSpecifier')
|
|
149
|
+
return 'default';
|
|
150
|
+
if (s.type === 'ImportNamespaceSpecifier')
|
|
151
|
+
return '*';
|
|
152
|
+
if (s.type === 'ImportSpecifier') {
|
|
153
|
+
const imported = s.imported;
|
|
154
|
+
if (imported.type === 'Identifier')
|
|
155
|
+
return imported.name;
|
|
156
|
+
return imported.value;
|
|
157
|
+
}
|
|
158
|
+
return '';
|
|
159
|
+
});
|
|
160
|
+
return {
|
|
161
|
+
source: node.source.value,
|
|
162
|
+
kind: 'static',
|
|
163
|
+
specifiers: specifiers.filter(Boolean),
|
|
164
|
+
typeOnly: node.importKind === 'type',
|
|
165
|
+
line: node.loc?.start.line ?? 0,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function collectNamedExport(node, exports, imports) {
|
|
169
|
+
// Re-export: export { X } from 'source'
|
|
170
|
+
if (node.source) {
|
|
171
|
+
imports.push({
|
|
172
|
+
source: node.source.value,
|
|
173
|
+
kind: 'reexport',
|
|
174
|
+
specifiers: node.specifiers.map((s) => {
|
|
175
|
+
if (s.type === 'ExportSpecifier') {
|
|
176
|
+
const exported = s.exported;
|
|
177
|
+
return exported.type === 'Identifier' ? exported.name : exported.value;
|
|
178
|
+
}
|
|
179
|
+
return '';
|
|
180
|
+
}).filter(Boolean),
|
|
181
|
+
typeOnly: node.exportKind === 'type',
|
|
182
|
+
line: node.loc?.start.line ?? 0,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Inline declaration: export function foo() {} / export const x = ... / etc.
|
|
186
|
+
if (node.declaration) {
|
|
187
|
+
const typeOnly = node.exportKind === 'type';
|
|
188
|
+
const line = node.declaration.loc?.start.line ?? node.loc?.start.line ?? 0;
|
|
189
|
+
switch (node.declaration.type) {
|
|
190
|
+
case 'FunctionDeclaration': {
|
|
191
|
+
const name = node.declaration.id?.name;
|
|
192
|
+
if (name)
|
|
193
|
+
exports.push({ name, kind: 'function', typeOnly, line });
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
case 'ClassDeclaration': {
|
|
197
|
+
const name = node.declaration.id?.name;
|
|
198
|
+
if (name)
|
|
199
|
+
exports.push({ name, kind: 'class', typeOnly, line });
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
case 'VariableDeclaration': {
|
|
203
|
+
for (const decl of node.declaration.declarations) {
|
|
204
|
+
if (decl.id.type === 'Identifier') {
|
|
205
|
+
exports.push({ name: decl.id.name, kind: 'variable', typeOnly, line });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
case 'TSInterfaceDeclaration': {
|
|
211
|
+
const name = node.declaration.id.name;
|
|
212
|
+
exports.push({ name, kind: 'interface', typeOnly: true, line });
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
case 'TSTypeAliasDeclaration': {
|
|
216
|
+
const name = node.declaration.id.name;
|
|
217
|
+
exports.push({ name, kind: 'type', typeOnly: true, line });
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
case 'TSEnumDeclaration': {
|
|
221
|
+
const name = node.declaration.id.name;
|
|
222
|
+
exports.push({ name, kind: 'enum', typeOnly, line });
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
default:
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
// Named re-export of local symbols: export { foo, bar }
|
|
230
|
+
for (const spec of node.specifiers) {
|
|
231
|
+
if (spec.type !== 'ExportSpecifier')
|
|
232
|
+
continue;
|
|
233
|
+
const exported = spec.exported;
|
|
234
|
+
const name = exported.type === 'Identifier' ? exported.name : exported.value;
|
|
235
|
+
exports.push({
|
|
236
|
+
name,
|
|
237
|
+
kind: 'unknown',
|
|
238
|
+
typeOnly: node.exportKind === 'type',
|
|
239
|
+
line: spec.loc?.start.line ?? node.loc?.start.line ?? 0,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Lightweight AST walker. We only care about recursing through node properties
|
|
245
|
+
* to find CallExpressions (for call sites + dynamic imports + require).
|
|
246
|
+
* Avoids the full babel-traverse dependency.
|
|
247
|
+
*/
|
|
248
|
+
function walk(node, visit) {
|
|
249
|
+
if (!node || typeof node !== 'object')
|
|
250
|
+
return;
|
|
251
|
+
visit(node);
|
|
252
|
+
for (const key of Object.keys(node)) {
|
|
253
|
+
if (key === 'loc' || key === 'range' || key === 'leadingComments' || key === 'trailingComments')
|
|
254
|
+
continue;
|
|
255
|
+
const child = node[key];
|
|
256
|
+
if (!child)
|
|
257
|
+
continue;
|
|
258
|
+
if (Array.isArray(child)) {
|
|
259
|
+
for (const item of child) {
|
|
260
|
+
if (item && typeof item === 'object' && 'type' in item) {
|
|
261
|
+
walk(item, visit);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (typeof child === 'object' && 'type' in child) {
|
|
266
|
+
walk(child, visit);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/core/ast.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { FileEntry } from '../types.js';
|
|
2
|
+
import { type AstImport, type AstExport } from './ast.js';
|
|
3
|
+
export interface GraphFile {
|
|
4
|
+
relativePath: string;
|
|
5
|
+
imports: AstImport[];
|
|
6
|
+
exports: AstExport[];
|
|
7
|
+
callSites: string[];
|
|
8
|
+
lineCount: number;
|
|
9
|
+
mtimeMs: number;
|
|
10
|
+
parseOk: boolean;
|
|
11
|
+
parseReason?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface CodeGraph {
|
|
14
|
+
/** per-file parse results, keyed by relativePath */
|
|
15
|
+
files: Map<string, GraphFile>;
|
|
16
|
+
/** package name → relativePaths that import it */
|
|
17
|
+
packageImporters: Map<string, Set<string>>;
|
|
18
|
+
/** relativePath → relativePaths that import it (local resolution) */
|
|
19
|
+
localImporters: Map<string, Set<string>>;
|
|
20
|
+
/** symbol name → relativePaths that export it */
|
|
21
|
+
symbolDefs: Map<string, Set<string>>;
|
|
22
|
+
/** scanned file count */
|
|
23
|
+
scannedFiles: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function buildCodeGraph(rootPath: string, files: FileEntry[], previousGraph?: CodeGraph): Promise<CodeGraph>;
|
|
26
|
+
/**
|
|
27
|
+
* Convert an import specifier to a bare package name.
|
|
28
|
+
*/
|
|
29
|
+
export declare function toPackageName(specifier: string): string | null;
|
|
30
|
+
export declare function packagesUsed(graph: CodeGraph): Set<string>;
|
|
31
|
+
export declare function filesImportingPackage(graph: CodeGraph, pkg: string): string[];
|
|
32
|
+
export declare function filesImportingFile(graph: CodeGraph, relativePath: string): string[];
|
|
33
|
+
export declare function filesDefiningSymbol(graph: CodeGraph, name: string): string[];
|
|
34
|
+
export declare function importersOf(graph: CodeGraph, relativePath: string): string[];
|
|
35
|
+
export declare function exportsOf(graph: CodeGraph, relativePath: string): AstExport[];
|
|
36
|
+
export declare function importsOf(graph: CodeGraph, relativePath: string): AstImport[];
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { parseSource, isParseable } from './ast.js';
|
|
4
|
+
const NODE_BUILTINS = new Set([
|
|
5
|
+
'assert', 'async_hooks', 'buffer', 'child_process', 'cluster', 'console', 'constants', 'crypto',
|
|
6
|
+
'dgram', 'dns', 'domain', 'events', 'fs', 'fs/promises', 'http', 'http2', 'https', 'inspector',
|
|
7
|
+
'module', 'net', 'os', 'path', 'perf_hooks', 'process', 'punycode', 'querystring', 'readline',
|
|
8
|
+
'repl', 'stream', 'string_decoder', 'sys', 'timers', 'tls', 'trace_events', 'tty', 'url', 'util',
|
|
9
|
+
'v8', 'vm', 'wasi', 'worker_threads', 'zlib',
|
|
10
|
+
]);
|
|
11
|
+
const RESOLUTION_EXTS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.mts', '.cts'];
|
|
12
|
+
const MAX_FILE_SIZE = 1024 * 1024;
|
|
13
|
+
export async function buildCodeGraph(rootPath, files, previousGraph) {
|
|
14
|
+
const parseable = files.filter((f) => isParseable(f.relativePath) && f.sizeBytes <= MAX_FILE_SIZE);
|
|
15
|
+
const graphFiles = new Map();
|
|
16
|
+
const packageImporters = new Map();
|
|
17
|
+
const localImporters = new Map();
|
|
18
|
+
const symbolDefs = new Map();
|
|
19
|
+
// Parse each file (with mtime-based reuse if we have a previous graph)
|
|
20
|
+
await Promise.all(parseable.map(async (file) => {
|
|
21
|
+
const absolutePath = path.isAbsolute(file.absolutePath)
|
|
22
|
+
? file.absolutePath
|
|
23
|
+
: path.resolve(rootPath, file.relativePath);
|
|
24
|
+
let mtimeMs;
|
|
25
|
+
try {
|
|
26
|
+
const stat = await fs.stat(absolutePath);
|
|
27
|
+
mtimeMs = stat.mtimeMs;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const cached = previousGraph?.files.get(file.relativePath);
|
|
33
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
34
|
+
graphFiles.set(file.relativePath, cached);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
let content;
|
|
38
|
+
try {
|
|
39
|
+
content = await fs.readFile(absolutePath, 'utf-8');
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const result = parseSource(file.relativePath, content);
|
|
45
|
+
graphFiles.set(file.relativePath, {
|
|
46
|
+
relativePath: file.relativePath,
|
|
47
|
+
imports: result.imports,
|
|
48
|
+
exports: result.exports,
|
|
49
|
+
callSites: result.callSites,
|
|
50
|
+
lineCount: result.lineCount,
|
|
51
|
+
mtimeMs,
|
|
52
|
+
parseOk: result.ok,
|
|
53
|
+
parseReason: result.reason,
|
|
54
|
+
});
|
|
55
|
+
}));
|
|
56
|
+
// Build derived indexes after all parsing is done
|
|
57
|
+
for (const [importingFile, entry] of graphFiles) {
|
|
58
|
+
const importingDir = path.posix.dirname(importingFile);
|
|
59
|
+
for (const imp of entry.imports) {
|
|
60
|
+
const pkg = toPackageName(imp.source);
|
|
61
|
+
if (pkg) {
|
|
62
|
+
if (!packageImporters.has(pkg))
|
|
63
|
+
packageImporters.set(pkg, new Set());
|
|
64
|
+
packageImporters.get(pkg).add(importingFile);
|
|
65
|
+
}
|
|
66
|
+
else if (imp.source.startsWith('.') || imp.source.startsWith('/')) {
|
|
67
|
+
const resolved = resolveRelative(importingDir, imp.source, graphFiles);
|
|
68
|
+
if (resolved) {
|
|
69
|
+
if (!localImporters.has(resolved))
|
|
70
|
+
localImporters.set(resolved, new Set());
|
|
71
|
+
localImporters.get(resolved).add(importingFile);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
for (const exp of entry.exports) {
|
|
76
|
+
if (!exp.name)
|
|
77
|
+
continue;
|
|
78
|
+
if (!symbolDefs.has(exp.name))
|
|
79
|
+
symbolDefs.set(exp.name, new Set());
|
|
80
|
+
symbolDefs.get(exp.name).add(importingFile);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
files: graphFiles,
|
|
85
|
+
packageImporters,
|
|
86
|
+
localImporters,
|
|
87
|
+
symbolDefs,
|
|
88
|
+
scannedFiles: graphFiles.size,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Convert an import specifier to a bare package name.
|
|
93
|
+
*/
|
|
94
|
+
export function toPackageName(specifier) {
|
|
95
|
+
if (!specifier)
|
|
96
|
+
return null;
|
|
97
|
+
if (specifier.startsWith('.') || specifier.startsWith('/'))
|
|
98
|
+
return null;
|
|
99
|
+
if (specifier.startsWith('node:'))
|
|
100
|
+
return null;
|
|
101
|
+
if (NODE_BUILTINS.has(specifier))
|
|
102
|
+
return null;
|
|
103
|
+
if (specifier.startsWith('@')) {
|
|
104
|
+
const segments = specifier.split('/');
|
|
105
|
+
if (segments.length < 2)
|
|
106
|
+
return null;
|
|
107
|
+
return `${segments[0]}/${segments[1]}`;
|
|
108
|
+
}
|
|
109
|
+
return specifier.split('/')[0];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Resolve a relative import to a file in the graph, or null if no match.
|
|
113
|
+
* Supports:
|
|
114
|
+
* - direct hit (./foo.ts → foo.ts)
|
|
115
|
+
* - extension inference (./foo → foo.ts)
|
|
116
|
+
* - barrel index (./foo → foo/index.ts)
|
|
117
|
+
* - .js that resolves to .ts under NodeNext
|
|
118
|
+
*/
|
|
119
|
+
function resolveRelative(importingDir, specifier, graphFiles) {
|
|
120
|
+
const base = path.posix.normalize(path.posix.join(importingDir, specifier));
|
|
121
|
+
if (graphFiles.has(base))
|
|
122
|
+
return base;
|
|
123
|
+
for (const ext of RESOLUTION_EXTS) {
|
|
124
|
+
if (graphFiles.has(base + ext))
|
|
125
|
+
return base + ext;
|
|
126
|
+
}
|
|
127
|
+
for (const ext of RESOLUTION_EXTS) {
|
|
128
|
+
const barrel = `${base}/index${ext}`;
|
|
129
|
+
if (graphFiles.has(barrel))
|
|
130
|
+
return barrel;
|
|
131
|
+
}
|
|
132
|
+
// .js → .ts fallback (NodeNext)
|
|
133
|
+
if (base.endsWith('.js')) {
|
|
134
|
+
const trimmed = base.slice(0, -3);
|
|
135
|
+
if (graphFiles.has(`${trimmed}.ts`))
|
|
136
|
+
return `${trimmed}.ts`;
|
|
137
|
+
if (graphFiles.has(`${trimmed}.tsx`))
|
|
138
|
+
return `${trimmed}.tsx`;
|
|
139
|
+
}
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
// ── Query API ──────────────────────────────────────────────
|
|
143
|
+
export function packagesUsed(graph) {
|
|
144
|
+
return new Set(graph.packageImporters.keys());
|
|
145
|
+
}
|
|
146
|
+
export function filesImportingPackage(graph, pkg) {
|
|
147
|
+
const set = graph.packageImporters.get(pkg);
|
|
148
|
+
return set ? [...set].sort() : [];
|
|
149
|
+
}
|
|
150
|
+
export function filesImportingFile(graph, relativePath) {
|
|
151
|
+
const set = graph.localImporters.get(relativePath);
|
|
152
|
+
return set ? [...set].sort() : [];
|
|
153
|
+
}
|
|
154
|
+
export function filesDefiningSymbol(graph, name) {
|
|
155
|
+
const set = graph.symbolDefs.get(name);
|
|
156
|
+
return set ? [...set].sort() : [];
|
|
157
|
+
}
|
|
158
|
+
export function importersOf(graph, relativePath) {
|
|
159
|
+
return filesImportingFile(graph, relativePath);
|
|
160
|
+
}
|
|
161
|
+
export function exportsOf(graph, relativePath) {
|
|
162
|
+
return graph.files.get(relativePath)?.exports ?? [];
|
|
163
|
+
}
|
|
164
|
+
export function importsOf(graph, relativePath) {
|
|
165
|
+
return graph.files.get(relativePath)?.imports ?? [];
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=codeGraph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codeGraph.js","sourceRoot":"","sources":["../../src/core/codeGraph.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { CoverageJoinedReport, CoverageReport, HotspotReport } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Join a hotspot report with a coverage report and rank entries by
|
|
4
|
+
* "risk × uncovered fraction" — the files that most deserve tests.
|
|
5
|
+
*/
|
|
6
|
+
export declare function joinCoverageWithHotspots(hotspots: HotspotReport, coverage: CoverageReport): CoverageJoinedReport;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Join a hotspot report with a coverage report and rank entries by
|
|
3
|
+
* "risk × uncovered fraction" — the files that most deserve tests.
|
|
4
|
+
*/
|
|
5
|
+
export function joinCoverageWithHotspots(hotspots, coverage) {
|
|
6
|
+
if (!hotspots.available) {
|
|
7
|
+
return {
|
|
8
|
+
available: false,
|
|
9
|
+
reason: hotspots.reason ?? 'hotspots unavailable',
|
|
10
|
+
coverageSource: coverage.source,
|
|
11
|
+
coverageSourceFile: coverage.sourceFile,
|
|
12
|
+
entries: [],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
if (!coverage.available) {
|
|
16
|
+
return {
|
|
17
|
+
available: false,
|
|
18
|
+
reason: coverage.reason ?? 'coverage unavailable',
|
|
19
|
+
coverageSource: coverage.source,
|
|
20
|
+
coverageSourceFile: coverage.sourceFile,
|
|
21
|
+
entries: [],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
const coverageMap = new Map();
|
|
25
|
+
for (const f of coverage.files)
|
|
26
|
+
coverageMap.set(f.relativePath, f.lineCoverage);
|
|
27
|
+
const entries = hotspots.hotspots.map((h) => {
|
|
28
|
+
const cov = coverageMap.get(h.relativePath);
|
|
29
|
+
const uncovered = typeof cov === 'number' ? Math.max(0, (100 - cov) / 100) : 1;
|
|
30
|
+
const priority = h.riskScore * (0.3 + 0.7 * uncovered);
|
|
31
|
+
return {
|
|
32
|
+
relativePath: h.relativePath,
|
|
33
|
+
riskScore: h.riskScore,
|
|
34
|
+
churn: h.churn,
|
|
35
|
+
lineCount: h.lineCount,
|
|
36
|
+
issueCount: h.issueCount,
|
|
37
|
+
coverage: typeof cov === 'number' ? cov : null,
|
|
38
|
+
priority: Math.round(priority * 10) / 10,
|
|
39
|
+
reasons: h.reasons,
|
|
40
|
+
};
|
|
41
|
+
});
|
|
42
|
+
entries.sort((a, b) => b.priority - a.priority);
|
|
43
|
+
return {
|
|
44
|
+
available: true,
|
|
45
|
+
coverageSource: coverage.source,
|
|
46
|
+
coverageSourceFile: coverage.sourceFile,
|
|
47
|
+
entries,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=coverageJoin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverageJoin.js","sourceRoot":"","sources":["../../src/core/coverageJoin.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAuB,EACvB,QAAwB;IAExB,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QACxB,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,sBAAsB;YACjD,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,kBAAkB,EAAE,QAAQ,CAAC,UAAU;YACvC,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC;QACxB,OAAO;YACL,SAAS,EAAE,KAAK;YAChB,MAAM,EAAE,QAAQ,CAAC,MAAM,IAAI,sBAAsB;YACjD,cAAc,EAAE,QAAQ,CAAC,MAAM;YAC/B,kBAAkB,EAAE,QAAQ,CAAC,UAAU;YACvC,OAAO,EAAE,EAAE;SACZ,CAAC;IACJ,CAAC;IAED,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC9C,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK;QAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;IAEhF,MAAM,OAAO,GAA4B,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACnE,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;QAC5C,MAAM,SAAS,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/E,MAAM,QAAQ,GAAG,CAAC,CAAC,SAAS,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,SAAS,CAAC,CAAC;QACvD,OAAO;YACL,YAAY,EAAE,CAAC,CAAC,YAAY;YAC5B,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,SAAS,EAAE,CAAC,CAAC,SAAS;YACtB,UAAU,EAAE,CAAC,CAAC,UAAU;YACxB,QAAQ,EAAE,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI;YAC9C,QAAQ,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,EAAE,CAAC,GAAG,EAAE;YACxC,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IAEhD,OAAO;QACL,SAAS,EAAE,IAAI;QACf,cAAc,EAAE,QAAQ,CAAC,MAAM;QAC/B,kBAAkB,EAAE,QAAQ,CAAC,UAAU;QACvC,OAAO;KACR,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CoverageReport } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Detect and parse whatever coverage file the project has. Supports the three
|
|
4
|
+
* common formats produced by Istanbul/c8/Vitest/Jest:
|
|
5
|
+
* - lcov.info (line-oriented LCOV)
|
|
6
|
+
* - coverage-final.json (Istanbul per-file detail)
|
|
7
|
+
* - coverage-summary.json (Istanbul per-file summary)
|
|
8
|
+
*
|
|
9
|
+
* Returns per-file line coverage, normalized to relative posix paths.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseCoverage(rootPath: string): Promise<CoverageReport>;
|
|
12
|
+
/**
|
|
13
|
+
* Build a Map<relativePath, coverage%> for fast lookup.
|
|
14
|
+
*/
|
|
15
|
+
export declare function coverageMap(report: CoverageReport): Map<string, number>;
|