projscan 1.6.2 → 1.8.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.
Files changed (108) hide show
  1. package/dist/core/applyFix.js +5 -46
  2. package/dist/core/applyFix.js.map +1 -1
  3. package/dist/core/embeddings.d.ts +9 -0
  4. package/dist/core/embeddings.js +45 -5
  5. package/dist/core/embeddings.js.map +1 -1
  6. package/dist/core/languages/LanguageAdapter.d.ts +1 -1
  7. package/dist/core/languages/cppAdapter.d.ts +2 -0
  8. package/dist/core/languages/cppAdapter.js +145 -0
  9. package/dist/core/languages/cppAdapter.js.map +1 -0
  10. package/dist/core/languages/cppCallSites.d.ts +13 -0
  11. package/dist/core/languages/cppCallSites.js +62 -0
  12. package/dist/core/languages/cppCallSites.js.map +1 -0
  13. package/dist/core/languages/cppCyclomatic.d.ts +25 -0
  14. package/dist/core/languages/cppCyclomatic.js +82 -0
  15. package/dist/core/languages/cppCyclomatic.js.map +1 -0
  16. package/dist/core/languages/cppExports.d.ts +13 -0
  17. package/dist/core/languages/cppExports.js +120 -0
  18. package/dist/core/languages/cppExports.js.map +1 -0
  19. package/dist/core/languages/cppFunctions.d.ts +30 -0
  20. package/dist/core/languages/cppFunctions.js +281 -0
  21. package/dist/core/languages/cppFunctions.js.map +1 -0
  22. package/dist/core/languages/cppImports.d.ts +25 -0
  23. package/dist/core/languages/cppImports.js +77 -0
  24. package/dist/core/languages/cppImports.js.map +1 -0
  25. package/dist/core/languages/cppManifests.d.ts +18 -0
  26. package/dist/core/languages/cppManifests.js +41 -0
  27. package/dist/core/languages/cppManifests.js.map +1 -0
  28. package/dist/core/languages/kotlinAdapter.d.ts +2 -0
  29. package/dist/core/languages/kotlinAdapter.js +141 -0
  30. package/dist/core/languages/kotlinAdapter.js.map +1 -0
  31. package/dist/core/languages/kotlinCallSites.d.ts +15 -0
  32. package/dist/core/languages/kotlinCallSites.js +62 -0
  33. package/dist/core/languages/kotlinCallSites.js.map +1 -0
  34. package/dist/core/languages/kotlinCyclomatic.d.ts +24 -0
  35. package/dist/core/languages/kotlinCyclomatic.js +54 -0
  36. package/dist/core/languages/kotlinCyclomatic.js.map +1 -0
  37. package/dist/core/languages/kotlinExports.d.ts +13 -0
  38. package/dist/core/languages/kotlinExports.js +103 -0
  39. package/dist/core/languages/kotlinExports.js.map +1 -0
  40. package/dist/core/languages/kotlinFunctions.d.ts +27 -0
  41. package/dist/core/languages/kotlinFunctions.js +147 -0
  42. package/dist/core/languages/kotlinFunctions.js.map +1 -0
  43. package/dist/core/languages/kotlinImports.d.ts +25 -0
  44. package/dist/core/languages/kotlinImports.js +74 -0
  45. package/dist/core/languages/kotlinImports.js.map +1 -0
  46. package/dist/core/languages/kotlinManifests.d.ts +20 -0
  47. package/dist/core/languages/kotlinManifests.js +46 -0
  48. package/dist/core/languages/kotlinManifests.js.map +1 -0
  49. package/dist/core/languages/registry.js +16 -1
  50. package/dist/core/languages/registry.js.map +1 -1
  51. package/dist/core/languages/swiftAdapter.d.ts +2 -0
  52. package/dist/core/languages/swiftAdapter.js +130 -0
  53. package/dist/core/languages/swiftAdapter.js.map +1 -0
  54. package/dist/core/languages/swiftCallSites.d.ts +14 -0
  55. package/dist/core/languages/swiftCallSites.js +60 -0
  56. package/dist/core/languages/swiftCallSites.js.map +1 -0
  57. package/dist/core/languages/swiftCyclomatic.d.ts +24 -0
  58. package/dist/core/languages/swiftCyclomatic.js +54 -0
  59. package/dist/core/languages/swiftCyclomatic.js.map +1 -0
  60. package/dist/core/languages/swiftExports.d.ts +13 -0
  61. package/dist/core/languages/swiftExports.js +95 -0
  62. package/dist/core/languages/swiftExports.js.map +1 -0
  63. package/dist/core/languages/swiftFunctions.d.ts +28 -0
  64. package/dist/core/languages/swiftFunctions.js +162 -0
  65. package/dist/core/languages/swiftFunctions.js.map +1 -0
  66. package/dist/core/languages/swiftImports.d.ts +26 -0
  67. package/dist/core/languages/swiftImports.js +45 -0
  68. package/dist/core/languages/swiftImports.js.map +1 -0
  69. package/dist/core/languages/swiftManifests.d.ts +17 -0
  70. package/dist/core/languages/swiftManifests.js +49 -0
  71. package/dist/core/languages/swiftManifests.js.map +1 -0
  72. package/dist/core/languages/treeSitterLoader.js +21 -1
  73. package/dist/core/languages/treeSitterLoader.js.map +1 -1
  74. package/dist/core/memory.d.ts +30 -0
  75. package/dist/core/memory.js +42 -0
  76. package/dist/core/memory.js.map +1 -1
  77. package/dist/core/session.d.ts +23 -4
  78. package/dist/core/session.js +28 -8
  79. package/dist/core/session.js.map +1 -1
  80. package/dist/core/taint.d.ts +17 -0
  81. package/dist/core/taint.js +19 -1
  82. package/dist/core/taint.js.map +1 -1
  83. package/dist/grammars/tree-sitter-cpp.wasm +0 -0
  84. package/dist/grammars/tree-sitter-kotlin.wasm +0 -0
  85. package/dist/grammars/tree-sitter-swift.wasm +0 -0
  86. package/dist/mcp/server.js +107 -11
  87. package/dist/mcp/server.js.map +1 -1
  88. package/dist/mcp/sessionTouchScanner.js +8 -2
  89. package/dist/mcp/sessionTouchScanner.js.map +1 -1
  90. package/dist/mcp/tools/_shared.d.ts +25 -1
  91. package/dist/mcp/tools/_shared.js.map +1 -1
  92. package/dist/mcp/tools/costSummary.d.ts +26 -0
  93. package/dist/mcp/tools/costSummary.js +152 -0
  94. package/dist/mcp/tools/costSummary.js.map +1 -0
  95. package/dist/mcp/tools/fixSuggest.js +23 -2
  96. package/dist/mcp/tools/fixSuggest.js.map +1 -1
  97. package/dist/mcp/tools/memory.js +37 -4
  98. package/dist/mcp/tools/memory.js.map +1 -1
  99. package/dist/mcp/tools/reviewWatch.d.ts +7 -0
  100. package/dist/mcp/tools/reviewWatch.js +228 -0
  101. package/dist/mcp/tools/reviewWatch.js.map +1 -0
  102. package/dist/mcp/tools.js +4 -0
  103. package/dist/mcp/tools.js.map +1 -1
  104. package/dist/tool-manifest.json +52 -4
  105. package/dist/utils/atomicWrite.d.ts +26 -0
  106. package/dist/utils/atomicWrite.js +69 -0
  107. package/dist/utils/atomicWrite.js.map +1 -0
  108. package/package.json +6 -2
@@ -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 {};
@@ -0,0 +1,147 @@
1
+ const KOTLIN_DECISION_NODES = new Set([
2
+ 'if_expression',
3
+ 'for_statement',
4
+ 'while_statement',
5
+ 'do_while_statement',
6
+ 'try_expression',
7
+ 'catch_block',
8
+ ]);
9
+ /**
10
+ * Per-function McCabe CC for Kotlin. Walks `function_declaration` nodes
11
+ * (top-level functions and class methods). Methods inside `class Foo { fun m() }`
12
+ * are named `Foo.m`; top-level functions stay bare. Anonymous functions and
13
+ * lambdas are not extracted as separate entries; their decision points fold
14
+ * into the enclosing function (analogous to JS arrow/closure handling
15
+ * elsewhere in projscan).
16
+ *
17
+ * `when` expressions count one branch per non-else arm.
18
+ */
19
+ export function extractKotlinFunctions(root) {
20
+ const out = [];
21
+ walk(root, null, out);
22
+ return out;
23
+ }
24
+ function walk(node, ownerName, out) {
25
+ if (node.type === 'class_declaration' ||
26
+ node.type === 'object_declaration') {
27
+ const name = nameOfDecl(node) ?? ownerName;
28
+ const body = bodyOf(node);
29
+ if (body) {
30
+ for (const child of body.namedChildren)
31
+ walk(child, name, out);
32
+ }
33
+ return;
34
+ }
35
+ if (node.type === 'function_declaration') {
36
+ const baseName = nameOfDecl(node) ?? '<anonymous>';
37
+ const fnName = ownerName ? `${ownerName}.${baseName}` : baseName;
38
+ const line = node.startPosition.row + 1;
39
+ const endLine = node.endPosition.row + 1;
40
+ const { cc, callSites } = analyzeBody(node);
41
+ out.push({ name: fnName, line, endLine, cyclomaticComplexity: cc, callSites });
42
+ return;
43
+ }
44
+ for (const child of node.namedChildren)
45
+ walk(child, ownerName, out);
46
+ }
47
+ function nameOfDecl(node) {
48
+ if (node.childForFieldName) {
49
+ const id = node.childForFieldName('name');
50
+ if (id && id.text)
51
+ return id.text;
52
+ }
53
+ for (const c of node.namedChildren) {
54
+ if (c.type === 'simple_identifier' || c.type === 'identifier' || c.type === 'type_identifier') {
55
+ return c.text;
56
+ }
57
+ }
58
+ return null;
59
+ }
60
+ function bodyOf(node) {
61
+ if (node.childForFieldName) {
62
+ const b = node.childForFieldName('body');
63
+ if (b)
64
+ return b;
65
+ }
66
+ for (const c of node.namedChildren) {
67
+ if (c.type === 'class_body' ||
68
+ c.type === 'enum_class_body' ||
69
+ c.type === 'function_body') {
70
+ return c;
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ function analyzeBody(fnNode) {
76
+ let count = 0;
77
+ const calls = new Set();
78
+ const body = bodyOf(fnNode);
79
+ if (!body)
80
+ return { cc: 1, callSites: [] };
81
+ walkSkipNested(body, (n) => {
82
+ if (KOTLIN_DECISION_NODES.has(n.type)) {
83
+ count++;
84
+ return;
85
+ }
86
+ // when expressions: each non-else entry counts as a branch.
87
+ if (n.type === 'when_entry') {
88
+ // Non-else arms have ≥1 `when_condition` child; the `else` arm has none
89
+ // (the `else` keyword is anonymous in tree-sitter-kotlin's grammar).
90
+ const hasCondition = n.namedChildren.some((c) => c.type === 'when_condition');
91
+ if (hasCondition)
92
+ count++;
93
+ return;
94
+ }
95
+ // && / ||
96
+ if (n.type === 'conjunction_expression' || n.type === 'disjunction_expression') {
97
+ count++;
98
+ return;
99
+ }
100
+ if (n.type === 'call_expression') {
101
+ const fn = n.childForFieldName ? n.childForFieldName('function') : n.namedChildren[0] ?? null;
102
+ const name = bareName(fn);
103
+ if (name)
104
+ calls.add(name);
105
+ }
106
+ });
107
+ return { cc: count + 1, callSites: [...calls] };
108
+ }
109
+ function bareName(node) {
110
+ if (!node)
111
+ return null;
112
+ switch (node.type) {
113
+ case 'simple_identifier':
114
+ case 'identifier':
115
+ case 'type_identifier':
116
+ return node.text;
117
+ case 'navigation_expression': {
118
+ // a.b.c → take the last suffix
119
+ const named = node.namedChildren;
120
+ return named.length > 0 ? bareName(named[named.length - 1]) : null;
121
+ }
122
+ case 'navigation_suffix': {
123
+ for (const c of node.namedChildren) {
124
+ const n = bareName(c);
125
+ if (n)
126
+ return n;
127
+ }
128
+ return null;
129
+ }
130
+ default:
131
+ return null;
132
+ }
133
+ }
134
+ function walkSkipNested(node, visit) {
135
+ visit(node);
136
+ for (const child of node.namedChildren) {
137
+ if (child.type === 'function_declaration' ||
138
+ child.type === 'class_declaration' ||
139
+ child.type === 'object_declaration' ||
140
+ child.type === 'lambda_literal' ||
141
+ child.type === 'anonymous_function') {
142
+ continue;
143
+ }
144
+ walkSkipNested(child, visit);
145
+ }
146
+ }
147
+ //# sourceMappingURL=kotlinFunctions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kotlinFunctions.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinFunctions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { AstImport } 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
+ /**
13
+ * Extract Kotlin `import` statements from a tree-sitter-kotlin AST.
14
+ *
15
+ * Handled forms:
16
+ * import com.foo.Bar → source = "com.foo.Bar"
17
+ * import com.foo.* → source = "com.foo.*"
18
+ * import com.foo.Bar as Baz → source = "com.foo.Bar", alias = "Baz"
19
+ *
20
+ * Kotlin doesn't have an explicit "re-export" notion at the import site
21
+ * (re-exports are done via top-level `typealias` / `val` exposing imported
22
+ * symbols). All imports are flagged as `static`.
23
+ */
24
+ export declare function extractKotlinImports(root: TsNode): AstImport[];
25
+ export {};