projscan 1.6.1 → 1.7.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/dist/core/applyFix.js +57 -4
- package/dist/core/applyFix.js.map +1 -1
- package/dist/core/codeGraph.js +6 -2
- package/dist/core/codeGraph.js.map +1 -1
- package/dist/core/fileInspector.js +42 -7
- package/dist/core/fileInspector.js.map +1 -1
- package/dist/core/languages/LanguageAdapter.d.ts +1 -1
- package/dist/core/languages/cppAdapter.d.ts +2 -0
- package/dist/core/languages/cppAdapter.js +145 -0
- package/dist/core/languages/cppAdapter.js.map +1 -0
- package/dist/core/languages/cppCallSites.d.ts +13 -0
- package/dist/core/languages/cppCallSites.js +62 -0
- package/dist/core/languages/cppCallSites.js.map +1 -0
- package/dist/core/languages/cppCyclomatic.d.ts +25 -0
- package/dist/core/languages/cppCyclomatic.js +82 -0
- package/dist/core/languages/cppCyclomatic.js.map +1 -0
- package/dist/core/languages/cppExports.d.ts +13 -0
- package/dist/core/languages/cppExports.js +120 -0
- package/dist/core/languages/cppExports.js.map +1 -0
- package/dist/core/languages/cppFunctions.d.ts +30 -0
- package/dist/core/languages/cppFunctions.js +242 -0
- package/dist/core/languages/cppFunctions.js.map +1 -0
- package/dist/core/languages/cppImports.d.ts +25 -0
- package/dist/core/languages/cppImports.js +77 -0
- package/dist/core/languages/cppImports.js.map +1 -0
- package/dist/core/languages/cppManifests.d.ts +18 -0
- package/dist/core/languages/cppManifests.js +41 -0
- package/dist/core/languages/cppManifests.js.map +1 -0
- package/dist/core/languages/kotlinAdapter.d.ts +2 -0
- package/dist/core/languages/kotlinAdapter.js +141 -0
- package/dist/core/languages/kotlinAdapter.js.map +1 -0
- package/dist/core/languages/kotlinCallSites.d.ts +15 -0
- package/dist/core/languages/kotlinCallSites.js +62 -0
- package/dist/core/languages/kotlinCallSites.js.map +1 -0
- package/dist/core/languages/kotlinCyclomatic.d.ts +24 -0
- package/dist/core/languages/kotlinCyclomatic.js +54 -0
- package/dist/core/languages/kotlinCyclomatic.js.map +1 -0
- package/dist/core/languages/kotlinExports.d.ts +13 -0
- package/dist/core/languages/kotlinExports.js +103 -0
- package/dist/core/languages/kotlinExports.js.map +1 -0
- package/dist/core/languages/kotlinFunctions.d.ts +27 -0
- package/dist/core/languages/kotlinFunctions.js +147 -0
- package/dist/core/languages/kotlinFunctions.js.map +1 -0
- package/dist/core/languages/kotlinImports.d.ts +25 -0
- package/dist/core/languages/kotlinImports.js +74 -0
- package/dist/core/languages/kotlinImports.js.map +1 -0
- package/dist/core/languages/kotlinManifests.d.ts +20 -0
- package/dist/core/languages/kotlinManifests.js +46 -0
- package/dist/core/languages/kotlinManifests.js.map +1 -0
- package/dist/core/languages/registry.js +14 -1
- package/dist/core/languages/registry.js.map +1 -1
- package/dist/core/languages/treeSitterLoader.js +19 -1
- package/dist/core/languages/treeSitterLoader.js.map +1 -1
- package/dist/core/memory.d.ts +30 -0
- package/dist/core/memory.js +42 -0
- package/dist/core/memory.js.map +1 -1
- package/dist/core/prDiff.js +3 -1
- package/dist/core/prDiff.js.map +1 -1
- package/dist/core/review.js +42 -6
- package/dist/core/review.js.map +1 -1
- package/dist/core/searchIndex.js +8 -4
- package/dist/core/searchIndex.js.map +1 -1
- package/dist/core/session.d.ts +5 -0
- package/dist/core/session.js +18 -8
- package/dist/core/session.js.map +1 -1
- package/dist/grammars/tree-sitter-cpp.wasm +0 -0
- package/dist/grammars/tree-sitter-kotlin.wasm +0 -0
- package/dist/mcp/server.js +57 -11
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/sessionTouchScanner.js +8 -2
- package/dist/mcp/sessionTouchScanner.js.map +1 -1
- package/dist/mcp/tools/costSummary.d.ts +26 -0
- package/dist/mcp/tools/costSummary.js +143 -0
- package/dist/mcp/tools/costSummary.js.map +1 -0
- package/dist/mcp/tools/fixSuggest.js +23 -2
- package/dist/mcp/tools/fixSuggest.js.map +1 -1
- package/dist/mcp/tools/memory.js +37 -4
- package/dist/mcp/tools/memory.js.map +1 -1
- package/dist/mcp/tools.js +2 -0
- package/dist/mcp/tools.js.map +1 -1
- package/dist/tool-manifest.json +18 -4
- package/dist/utils/concurrency.d.ts +23 -0
- package/dist/utils/concurrency.js +37 -0
- package/dist/utils/concurrency.js.map +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
const COMMON_CPP_ROOTS = ['include', 'src', 'lib', '.'];
|
|
4
|
+
/**
|
|
5
|
+
* Detect C++ source roots. We don't parse CMakeLists / Make files; we
|
|
6
|
+
* survey .cpp/.cc/.cxx/.h/.hpp file paths and pick whichever conventional
|
|
7
|
+
* roots actually contain sources.
|
|
8
|
+
*/
|
|
9
|
+
export async function detectCppProject(rootPath, files) {
|
|
10
|
+
const cppFiles = files.filter((f) => isCppExtension(f.relativePath));
|
|
11
|
+
if (cppFiles.length === 0)
|
|
12
|
+
return null;
|
|
13
|
+
const hasCMake = await fileExists(path.join(rootPath, 'CMakeLists.txt'));
|
|
14
|
+
const hasMakefile = await fileExists(path.join(rootPath, 'Makefile'));
|
|
15
|
+
const includeRoots = [];
|
|
16
|
+
for (const candidate of COMMON_CPP_ROOTS) {
|
|
17
|
+
if (candidate === '.') {
|
|
18
|
+
if (cppFiles.some((f) => !f.relativePath.includes('/')))
|
|
19
|
+
includeRoots.push('.');
|
|
20
|
+
}
|
|
21
|
+
else if (cppFiles.some((f) => f.relativePath.startsWith(candidate + '/'))) {
|
|
22
|
+
includeRoots.push(candidate);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (includeRoots.length === 0)
|
|
26
|
+
includeRoots.push('.');
|
|
27
|
+
return { includeRoots, hasCMake, hasMakefile };
|
|
28
|
+
}
|
|
29
|
+
async function fileExists(p) {
|
|
30
|
+
try {
|
|
31
|
+
await fs.access(p);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function isCppExtension(p) {
|
|
39
|
+
return /\.(cpp|cc|cxx|c\+\+|c|h|hpp|hxx|h\+\+)$/.test(p);
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cppManifests.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cppManifests.js","sourceRoot":"","sources":["../../../src/core/languages/cppManifests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B,MAAM,gBAAgB,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;AAExD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,QAAgB,EAChB,KAAkB;IAElB,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IACrE,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC,CAAC;IACzE,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC,CAAC;IACtE,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,SAAS,IAAI,gBAAgB,EAAE,CAAC;QACzC,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;YACtB,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;gBAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAClF,CAAC;aAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;YAC5E,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACjD,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,CAAS;IACjC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,yCAAyC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { createParserFor } from './treeSitterLoader.js';
|
|
3
|
+
import { extractKotlinImports } from './kotlinImports.js';
|
|
4
|
+
import { extractKotlinExports } from './kotlinExports.js';
|
|
5
|
+
import { extractKotlinCyclomatic } from './kotlinCyclomatic.js';
|
|
6
|
+
import { extractKotlinFunctions } from './kotlinFunctions.js';
|
|
7
|
+
import { extractKotlinCallSites } from './kotlinCallSites.js';
|
|
8
|
+
import { detectKotlinProject } from './kotlinManifests.js';
|
|
9
|
+
const KOTLIN_EXTENSIONS = new Set(['.kt', '.kts']);
|
|
10
|
+
const MAX_KOTLIN_FILE = 1024 * 1024;
|
|
11
|
+
let parserPromise = null;
|
|
12
|
+
async function getParser() {
|
|
13
|
+
if (!parserPromise)
|
|
14
|
+
parserPromise = createParserFor('tree-sitter-kotlin.wasm');
|
|
15
|
+
return parserPromise;
|
|
16
|
+
}
|
|
17
|
+
export const kotlinAdapter = {
|
|
18
|
+
id: 'kotlin',
|
|
19
|
+
extensions: KOTLIN_EXTENSIONS,
|
|
20
|
+
sourceExtensions: KOTLIN_EXTENSIONS,
|
|
21
|
+
// Kotlin has no "barrel-file" idiom; entry-points are .kt files with `fun main`.
|
|
22
|
+
barrelBasenames: new Set(),
|
|
23
|
+
maxFileSize: MAX_KOTLIN_FILE,
|
|
24
|
+
async parse(_filePath, content) {
|
|
25
|
+
try {
|
|
26
|
+
const parser = await getParser();
|
|
27
|
+
const tree = parser.parse(content);
|
|
28
|
+
if (!tree || !tree.rootNode) {
|
|
29
|
+
return {
|
|
30
|
+
ok: false,
|
|
31
|
+
reason: 'tree-sitter returned null tree',
|
|
32
|
+
imports: [],
|
|
33
|
+
exports: [],
|
|
34
|
+
callSites: [],
|
|
35
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
36
|
+
cyclomaticComplexity: 0,
|
|
37
|
+
functions: [],
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const root = tree.rootNode;
|
|
41
|
+
const imports = extractKotlinImports(root);
|
|
42
|
+
const exports = extractKotlinExports(root);
|
|
43
|
+
const cyclomaticComplexity = extractKotlinCyclomatic(root);
|
|
44
|
+
const callSites = extractKotlinCallSites(root);
|
|
45
|
+
const functions = extractKotlinFunctions(root);
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
imports,
|
|
49
|
+
exports,
|
|
50
|
+
callSites,
|
|
51
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
52
|
+
cyclomaticComplexity,
|
|
53
|
+
functions,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
58
|
+
return {
|
|
59
|
+
ok: false,
|
|
60
|
+
reason: `kotlin parse failure: ${msg.slice(0, 120)}`,
|
|
61
|
+
imports: [],
|
|
62
|
+
exports: [],
|
|
63
|
+
callSites: [],
|
|
64
|
+
lineCount: content ? content.split('\n').length : 0,
|
|
65
|
+
cyclomaticComplexity: 0,
|
|
66
|
+
functions: [],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
resolveImport(importingFile, source, graphFiles, context) {
|
|
71
|
+
return resolveKotlinImport(importingFile, source, graphFiles, context);
|
|
72
|
+
},
|
|
73
|
+
toPackageName(source) {
|
|
74
|
+
if (!source)
|
|
75
|
+
return null;
|
|
76
|
+
// Heuristic: a Kotlin import that begins with the project's own
|
|
77
|
+
// detected source-root directory shouldn't be a "package" — but at
|
|
78
|
+
// graph-build time we don't have project info here. Defer to
|
|
79
|
+
// resolveImport: anything that resolveImport can't pin to a local
|
|
80
|
+
// file falls through as external.
|
|
81
|
+
return source.split('.')[0] || null;
|
|
82
|
+
},
|
|
83
|
+
async preparePackageRoots(rootPath, files) {
|
|
84
|
+
const info = await detectKotlinProject(rootPath, files);
|
|
85
|
+
return {
|
|
86
|
+
packageRoots: info ? info.packageRoots.map((r) => path.relative(rootPath, path.join(rootPath, r)) || '.') : [],
|
|
87
|
+
meta: info ? { kotlinProject: info } : undefined,
|
|
88
|
+
};
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Resolve a Kotlin `import com.foo.Bar` to a repo-local file. The path
|
|
93
|
+
* `com.foo.Bar` becomes `com/foo/Bar.kt` under each known package root.
|
|
94
|
+
* Wildcard imports (`com.foo.*`) resolve to `com/foo/<any>.kt` and we
|
|
95
|
+
* pick the first match if any. Non-local (stdlib, third-party) imports
|
|
96
|
+
* return null.
|
|
97
|
+
*/
|
|
98
|
+
function resolveKotlinImport(_importingFile, source, graphFiles, context) {
|
|
99
|
+
if (!source)
|
|
100
|
+
return null;
|
|
101
|
+
const project = context.meta?.kotlinProject;
|
|
102
|
+
const packageRoots = context.packageRoots ?? project?.packageRoots ?? [];
|
|
103
|
+
if (packageRoots.length === 0)
|
|
104
|
+
return null;
|
|
105
|
+
const isWildcard = source.endsWith('.*');
|
|
106
|
+
const cleanedSegments = (isWildcard ? source.slice(0, -2) : source).split('.').filter(Boolean);
|
|
107
|
+
if (cleanedSegments.length === 0)
|
|
108
|
+
return null;
|
|
109
|
+
for (const root of packageRoots) {
|
|
110
|
+
const rootSegs = root === '.' || root === '' ? [] : root.split('/').filter(Boolean);
|
|
111
|
+
if (isWildcard) {
|
|
112
|
+
const dirParts = [...rootSegs, ...cleanedSegments];
|
|
113
|
+
const prefix = dirParts.join('/') + '/';
|
|
114
|
+
// Pick any file under that package directory.
|
|
115
|
+
for (const key of graphFiles.keys()) {
|
|
116
|
+
if (key.startsWith(prefix) && (key.endsWith('.kt') || key.endsWith('.kts'))) {
|
|
117
|
+
return key;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
// Non-wildcard: try each segment count from full → 1, since the last segment
|
|
123
|
+
// could be a class name OR a file name. Try `com/foo/Bar.kt`, then if not
|
|
124
|
+
// found try `com/foo.kt` (top-level decl in Foo.kt).
|
|
125
|
+
for (let drop = 0; drop <= 1; drop++) {
|
|
126
|
+
const segs = cleanedSegments.slice(0, cleanedSegments.length - drop);
|
|
127
|
+
if (segs.length === 0)
|
|
128
|
+
break;
|
|
129
|
+
const baseSegs = [...rootSegs, ...segs.slice(0, -1)];
|
|
130
|
+
const fileName = segs[segs.length - 1];
|
|
131
|
+
const asKt = [...baseSegs, `${fileName}.kt`].join('/');
|
|
132
|
+
if (graphFiles.has(asKt))
|
|
133
|
+
return asKt;
|
|
134
|
+
const asKts = [...baseSegs, `${fileName}.kts`].join('/');
|
|
135
|
+
if (graphFiles.has(asKts))
|
|
136
|
+
return asKts;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=kotlinAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kotlinAdapter.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface TsNode {
|
|
2
|
+
type: string;
|
|
3
|
+
text: string;
|
|
4
|
+
namedChildren: TsNode[];
|
|
5
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Extract the called identifier from each `call_expression` in a
|
|
9
|
+
* tree-sitter-kotlin AST. Mirrors the existing adapter behaviour: we
|
|
10
|
+
* deduplicate names and strip qualification so that `foo.bar()` and `bar()`
|
|
11
|
+
* both produce `bar`. Constructor calls (`Foo()`) and infix-form calls are
|
|
12
|
+
* captured the same way.
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractKotlinCallSites(root: TsNode): string[];
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract the called identifier from each `call_expression` in a
|
|
3
|
+
* tree-sitter-kotlin AST. Mirrors the existing adapter behaviour: we
|
|
4
|
+
* deduplicate names and strip qualification so that `foo.bar()` and `bar()`
|
|
5
|
+
* both produce `bar`. Constructor calls (`Foo()`) and infix-form calls are
|
|
6
|
+
* captured the same way.
|
|
7
|
+
*/
|
|
8
|
+
export function extractKotlinCallSites(root) {
|
|
9
|
+
const seen = new Set();
|
|
10
|
+
walk(root, (n) => {
|
|
11
|
+
if (n.type !== 'call_expression')
|
|
12
|
+
return;
|
|
13
|
+
const fn = pickCallee(n);
|
|
14
|
+
if (!fn)
|
|
15
|
+
return;
|
|
16
|
+
const name = bareName(fn);
|
|
17
|
+
if (name)
|
|
18
|
+
seen.add(name);
|
|
19
|
+
});
|
|
20
|
+
return [...seen];
|
|
21
|
+
}
|
|
22
|
+
function pickCallee(node) {
|
|
23
|
+
if (node.childForFieldName) {
|
|
24
|
+
const f = node.childForFieldName('function');
|
|
25
|
+
if (f)
|
|
26
|
+
return f;
|
|
27
|
+
}
|
|
28
|
+
return node.namedChildren[0] ?? null;
|
|
29
|
+
}
|
|
30
|
+
function bareName(node) {
|
|
31
|
+
switch (node.type) {
|
|
32
|
+
case 'simple_identifier':
|
|
33
|
+
case 'identifier':
|
|
34
|
+
case 'type_identifier':
|
|
35
|
+
return node.text;
|
|
36
|
+
case 'navigation_expression': {
|
|
37
|
+
const last = node.namedChildren[node.namedChildren.length - 1];
|
|
38
|
+
return last ? bareName(last) : null;
|
|
39
|
+
}
|
|
40
|
+
case 'navigation_suffix': {
|
|
41
|
+
for (const c of node.namedChildren) {
|
|
42
|
+
const n = bareName(c);
|
|
43
|
+
if (n)
|
|
44
|
+
return n;
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
case 'call_expression': {
|
|
49
|
+
// Foo()() — a chained invocation; recurse on the inner callee.
|
|
50
|
+
const inner = pickCallee(node);
|
|
51
|
+
return inner ? bareName(inner) : null;
|
|
52
|
+
}
|
|
53
|
+
default:
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function walk(node, visit) {
|
|
58
|
+
visit(node);
|
|
59
|
+
for (const child of node.namedChildren)
|
|
60
|
+
walk(child, visit);
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=kotlinCallSites.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kotlinCallSites.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinCallSites.ts"],"names":[],"mappings":"AAOA;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB;YAAE,OAAO;QACzC,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC;QACzB,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC;QAC1B,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;AACnB,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC;QAC7C,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACvC,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC5B,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,mBAAmB,CAAC;QACzB,KAAK,YAAY,CAAC;QAClB,KAAK,iBAAiB;YACpB,OAAO,IAAI,CAAC,IAAI,CAAC;QACnB,KAAK,uBAAuB,CAAC,CAAC,CAAC;YAC7B,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YAC/D,OAAO,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACtC,CAAC;QACD,KAAK,mBAAmB,CAAC,CAAC,CAAC;YACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACtB,IAAI,CAAC;oBAAE,OAAO,CAAC,CAAC;YAClB,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QACD,KAAK,iBAAiB,CAAC,CAAC,CAAC;YACvB,+DAA+D;YAC/D,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;YAC/B,OAAO,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QACxC,CAAC;QACD;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,KAA0B;IACpD,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
interface TsNode {
|
|
2
|
+
type: string;
|
|
3
|
+
text: string;
|
|
4
|
+
namedChildren: TsNode[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* File-level McCabe cyclomatic complexity for a tree-sitter-kotlin AST.
|
|
8
|
+
*
|
|
9
|
+
* Decision points in Kotlin:
|
|
10
|
+
* if_expression +1 (the `if` itself; `else` does not count)
|
|
11
|
+
* for_statement +1
|
|
12
|
+
* while_statement +1
|
|
13
|
+
* do_while_statement +1
|
|
14
|
+
* try_expression +1 (success vs throw paths)
|
|
15
|
+
* catch_block +1 (each catch is a separate handler)
|
|
16
|
+
* when_entry (non-else) +1 (each non-else `when` arm is a branch)
|
|
17
|
+
* conjunction_expression +1 (Kotlin's `&&`)
|
|
18
|
+
* disjunction_expression +1 (Kotlin's `||`)
|
|
19
|
+
*
|
|
20
|
+
* The Elvis operator `?:` and safe-call `?.` do NOT count as branches —
|
|
21
|
+
* matches the convention used elsewhere in projscan and most analyzers.
|
|
22
|
+
*/
|
|
23
|
+
export declare function extractKotlinCyclomatic(root: TsNode): number;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-level McCabe cyclomatic complexity for a tree-sitter-kotlin AST.
|
|
3
|
+
*
|
|
4
|
+
* Decision points in Kotlin:
|
|
5
|
+
* if_expression +1 (the `if` itself; `else` does not count)
|
|
6
|
+
* for_statement +1
|
|
7
|
+
* while_statement +1
|
|
8
|
+
* do_while_statement +1
|
|
9
|
+
* try_expression +1 (success vs throw paths)
|
|
10
|
+
* catch_block +1 (each catch is a separate handler)
|
|
11
|
+
* when_entry (non-else) +1 (each non-else `when` arm is a branch)
|
|
12
|
+
* conjunction_expression +1 (Kotlin's `&&`)
|
|
13
|
+
* disjunction_expression +1 (Kotlin's `||`)
|
|
14
|
+
*
|
|
15
|
+
* The Elvis operator `?:` and safe-call `?.` do NOT count as branches —
|
|
16
|
+
* matches the convention used elsewhere in projscan and most analyzers.
|
|
17
|
+
*/
|
|
18
|
+
export function extractKotlinCyclomatic(root) {
|
|
19
|
+
let decisions = 0;
|
|
20
|
+
walk(root, (n) => {
|
|
21
|
+
if (isDecisionPoint(n))
|
|
22
|
+
decisions++;
|
|
23
|
+
});
|
|
24
|
+
return decisions + 1;
|
|
25
|
+
}
|
|
26
|
+
function isDecisionPoint(n) {
|
|
27
|
+
switch (n.type) {
|
|
28
|
+
case 'if_expression':
|
|
29
|
+
case 'for_statement':
|
|
30
|
+
case 'while_statement':
|
|
31
|
+
case 'do_while_statement':
|
|
32
|
+
case 'try_expression':
|
|
33
|
+
case 'catch_block':
|
|
34
|
+
case 'conjunction_expression':
|
|
35
|
+
case 'disjunction_expression':
|
|
36
|
+
return true;
|
|
37
|
+
case 'when_entry': {
|
|
38
|
+
// The `else` arm has no `when_condition` child — the `else` keyword is
|
|
39
|
+
// an anonymous token in tree-sitter-kotlin, so checking child text
|
|
40
|
+
// doesn't work reliably. Non-else arms always carry at least one
|
|
41
|
+
// `when_condition` (multi-value arms like `1, 2 ->` carry several).
|
|
42
|
+
const hasCondition = n.namedChildren.some((c) => c.type === 'when_condition');
|
|
43
|
+
return hasCondition;
|
|
44
|
+
}
|
|
45
|
+
default:
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function walk(node, visit) {
|
|
50
|
+
visit(node);
|
|
51
|
+
for (const child of node.namedChildren)
|
|
52
|
+
walk(child, visit);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=kotlinCyclomatic.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kotlinCyclomatic.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinCyclomatic.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,eAAe,CAAC,CAAC,CAAC;YAAE,SAAS,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;IACH,OAAO,SAAS,GAAG,CAAC,CAAC;AACvB,CAAC;AAED,SAAS,eAAe,CAAC,CAAS;IAChC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC;QACf,KAAK,eAAe,CAAC;QACrB,KAAK,eAAe,CAAC;QACrB,KAAK,iBAAiB,CAAC;QACvB,KAAK,oBAAoB,CAAC;QAC1B,KAAK,gBAAgB,CAAC;QACtB,KAAK,aAAa,CAAC;QACnB,KAAK,wBAAwB,CAAC;QAC9B,KAAK,wBAAwB;YAC3B,OAAO,IAAI,CAAC;QACd,KAAK,YAAY,CAAC,CAAC,CAAC;YAClB,uEAAuE;YACvE,mEAAmE;YACnE,iEAAiE;YACjE,oEAAoE;YACpE,MAAM,YAAY,GAAG,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;YAC9E,OAAO,YAAY,CAAC;QACtB,CAAC;QACD;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,IAAY,EAAE,KAA0B;IACpD,KAAK,CAAC,IAAI,CAAC,CAAC;IACZ,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa;QAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AAC7D,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AstExport } from '../ast.js';
|
|
2
|
+
interface TsNode {
|
|
3
|
+
type: string;
|
|
4
|
+
text: string;
|
|
5
|
+
startPosition: {
|
|
6
|
+
row: number;
|
|
7
|
+
column: number;
|
|
8
|
+
};
|
|
9
|
+
namedChildren: TsNode[];
|
|
10
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
11
|
+
}
|
|
12
|
+
export declare function extractKotlinExports(root: TsNode): AstExport[];
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract Kotlin top-level declarations as exports. Kotlin's default
|
|
3
|
+
* visibility is `public`; only declarations marked `private` or `internal`
|
|
4
|
+
* are excluded. `protected` only applies to class members and is treated
|
|
5
|
+
* as exported when on a top-level decl (which is unusual but valid in
|
|
6
|
+
* tree-sitter's grammar).
|
|
7
|
+
*
|
|
8
|
+
* Kinds:
|
|
9
|
+
* fun foo() → function
|
|
10
|
+
* class Foo → class
|
|
11
|
+
* interface Foo → interface
|
|
12
|
+
* object Foo → class (Kotlin singleton object, modeled as class)
|
|
13
|
+
* enum class Color → enum
|
|
14
|
+
* typealias Bar = ... → type
|
|
15
|
+
* val/const x → variable
|
|
16
|
+
*/
|
|
17
|
+
const EXPORT_NODE_TO_KIND = {
|
|
18
|
+
function_declaration: 'function',
|
|
19
|
+
class_declaration: 'class',
|
|
20
|
+
object_declaration: 'class',
|
|
21
|
+
type_alias: 'type',
|
|
22
|
+
property_declaration: 'variable',
|
|
23
|
+
};
|
|
24
|
+
export function extractKotlinExports(root) {
|
|
25
|
+
const exports = [];
|
|
26
|
+
// Top-level only: descend into the source_file/file_node body but not into
|
|
27
|
+
// nested classes (their members aren't top-level exports for graph purposes).
|
|
28
|
+
for (const child of root.namedChildren) {
|
|
29
|
+
visitTopLevel(child, exports);
|
|
30
|
+
}
|
|
31
|
+
return exports;
|
|
32
|
+
}
|
|
33
|
+
function visitTopLevel(node, out) {
|
|
34
|
+
// Some grammars wrap top-level decls in `package_header` / `import_list` /
|
|
35
|
+
// an explicit `top_level_object` node. We descend through wrappers.
|
|
36
|
+
if (node.type === 'package_header' ||
|
|
37
|
+
node.type === 'import_list' ||
|
|
38
|
+
node.type === 'file_annotation') {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
if (node.type === 'class_declaration') {
|
|
42
|
+
const isInterface = /\binterface\b/.test(headerText(node));
|
|
43
|
+
const isEnum = /\benum\s+class\b/.test(headerText(node));
|
|
44
|
+
const kind = isEnum ? 'enum' : isInterface ? 'interface' : 'class';
|
|
45
|
+
if (!isPrivate(node)) {
|
|
46
|
+
const name = nameOf(node);
|
|
47
|
+
if (name)
|
|
48
|
+
out.push({ name, kind, typeOnly: false, line: node.startPosition.row + 1 });
|
|
49
|
+
}
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const kind = EXPORT_NODE_TO_KIND[node.type];
|
|
53
|
+
if (!kind) {
|
|
54
|
+
// Walk container nodes (e.g., source_file already iterated, but defensively descend).
|
|
55
|
+
for (const c of node.namedChildren)
|
|
56
|
+
visitTopLevel(c, out);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (isPrivate(node))
|
|
60
|
+
return;
|
|
61
|
+
const name = nameOf(node);
|
|
62
|
+
if (!name)
|
|
63
|
+
return;
|
|
64
|
+
out.push({ name, kind, typeOnly: false, line: node.startPosition.row + 1 });
|
|
65
|
+
}
|
|
66
|
+
function headerText(node) {
|
|
67
|
+
// Just the first line — the `class`/`interface`/`enum class` keyword
|
|
68
|
+
// appears in the header before the body opens.
|
|
69
|
+
const idx = node.text.indexOf('{');
|
|
70
|
+
return idx >= 0 ? node.text.slice(0, idx) : node.text;
|
|
71
|
+
}
|
|
72
|
+
function isPrivate(node) {
|
|
73
|
+
for (const c of node.namedChildren) {
|
|
74
|
+
if (c.type === 'modifiers' || c.type === 'modifier_list') {
|
|
75
|
+
for (const m of c.namedChildren) {
|
|
76
|
+
if (m.type === 'visibility_modifier') {
|
|
77
|
+
const t = m.text.trim();
|
|
78
|
+
if (t === 'private' || t === 'internal')
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
function nameOf(node) {
|
|
87
|
+
if (node.childForFieldName) {
|
|
88
|
+
const id = node.childForFieldName('name');
|
|
89
|
+
if (id && id.text)
|
|
90
|
+
return id.text;
|
|
91
|
+
}
|
|
92
|
+
for (const c of node.namedChildren) {
|
|
93
|
+
if (c.type === 'simple_identifier' || c.type === 'identifier' || c.type === 'type_identifier') {
|
|
94
|
+
return c.text;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// property_declaration: `val/var <name> = ...`
|
|
98
|
+
const m = /\b(val|var|const\s+val)\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(node.text);
|
|
99
|
+
if (m)
|
|
100
|
+
return m[2];
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=kotlinExports.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kotlinExports.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinExports.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { FunctionInfo } from '../ast.js';
|
|
2
|
+
interface TsNode {
|
|
3
|
+
type: string;
|
|
4
|
+
text: string;
|
|
5
|
+
startPosition: {
|
|
6
|
+
row: number;
|
|
7
|
+
column: number;
|
|
8
|
+
};
|
|
9
|
+
endPosition: {
|
|
10
|
+
row: number;
|
|
11
|
+
column: number;
|
|
12
|
+
};
|
|
13
|
+
namedChildren: TsNode[];
|
|
14
|
+
childForFieldName?: (name: string) => TsNode | null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Per-function McCabe CC for Kotlin. Walks `function_declaration` nodes
|
|
18
|
+
* (top-level functions and class methods). Methods inside `class Foo { fun m() }`
|
|
19
|
+
* are named `Foo.m`; top-level functions stay bare. Anonymous functions and
|
|
20
|
+
* lambdas are not extracted as separate entries; their decision points fold
|
|
21
|
+
* into the enclosing function (analogous to JS arrow/closure handling
|
|
22
|
+
* elsewhere in projscan).
|
|
23
|
+
*
|
|
24
|
+
* `when` expressions count one branch per non-else arm.
|
|
25
|
+
*/
|
|
26
|
+
export declare function extractKotlinFunctions(root: TsNode): FunctionInfo[];
|
|
27
|
+
export {};
|