projscan 1.6.2 → 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.
Files changed (70) hide show
  1. package/dist/core/languages/LanguageAdapter.d.ts +1 -1
  2. package/dist/core/languages/cppAdapter.d.ts +2 -0
  3. package/dist/core/languages/cppAdapter.js +145 -0
  4. package/dist/core/languages/cppAdapter.js.map +1 -0
  5. package/dist/core/languages/cppCallSites.d.ts +13 -0
  6. package/dist/core/languages/cppCallSites.js +62 -0
  7. package/dist/core/languages/cppCallSites.js.map +1 -0
  8. package/dist/core/languages/cppCyclomatic.d.ts +25 -0
  9. package/dist/core/languages/cppCyclomatic.js +82 -0
  10. package/dist/core/languages/cppCyclomatic.js.map +1 -0
  11. package/dist/core/languages/cppExports.d.ts +13 -0
  12. package/dist/core/languages/cppExports.js +120 -0
  13. package/dist/core/languages/cppExports.js.map +1 -0
  14. package/dist/core/languages/cppFunctions.d.ts +30 -0
  15. package/dist/core/languages/cppFunctions.js +242 -0
  16. package/dist/core/languages/cppFunctions.js.map +1 -0
  17. package/dist/core/languages/cppImports.d.ts +25 -0
  18. package/dist/core/languages/cppImports.js +77 -0
  19. package/dist/core/languages/cppImports.js.map +1 -0
  20. package/dist/core/languages/cppManifests.d.ts +18 -0
  21. package/dist/core/languages/cppManifests.js +41 -0
  22. package/dist/core/languages/cppManifests.js.map +1 -0
  23. package/dist/core/languages/kotlinAdapter.d.ts +2 -0
  24. package/dist/core/languages/kotlinAdapter.js +141 -0
  25. package/dist/core/languages/kotlinAdapter.js.map +1 -0
  26. package/dist/core/languages/kotlinCallSites.d.ts +15 -0
  27. package/dist/core/languages/kotlinCallSites.js +62 -0
  28. package/dist/core/languages/kotlinCallSites.js.map +1 -0
  29. package/dist/core/languages/kotlinCyclomatic.d.ts +24 -0
  30. package/dist/core/languages/kotlinCyclomatic.js +54 -0
  31. package/dist/core/languages/kotlinCyclomatic.js.map +1 -0
  32. package/dist/core/languages/kotlinExports.d.ts +13 -0
  33. package/dist/core/languages/kotlinExports.js +103 -0
  34. package/dist/core/languages/kotlinExports.js.map +1 -0
  35. package/dist/core/languages/kotlinFunctions.d.ts +27 -0
  36. package/dist/core/languages/kotlinFunctions.js +147 -0
  37. package/dist/core/languages/kotlinFunctions.js.map +1 -0
  38. package/dist/core/languages/kotlinImports.d.ts +25 -0
  39. package/dist/core/languages/kotlinImports.js +74 -0
  40. package/dist/core/languages/kotlinImports.js.map +1 -0
  41. package/dist/core/languages/kotlinManifests.d.ts +20 -0
  42. package/dist/core/languages/kotlinManifests.js +46 -0
  43. package/dist/core/languages/kotlinManifests.js.map +1 -0
  44. package/dist/core/languages/registry.js +14 -1
  45. package/dist/core/languages/registry.js.map +1 -1
  46. package/dist/core/languages/treeSitterLoader.js +19 -1
  47. package/dist/core/languages/treeSitterLoader.js.map +1 -1
  48. package/dist/core/memory.d.ts +30 -0
  49. package/dist/core/memory.js +42 -0
  50. package/dist/core/memory.js.map +1 -1
  51. package/dist/core/session.d.ts +5 -0
  52. package/dist/core/session.js +8 -3
  53. package/dist/core/session.js.map +1 -1
  54. package/dist/grammars/tree-sitter-cpp.wasm +0 -0
  55. package/dist/grammars/tree-sitter-kotlin.wasm +0 -0
  56. package/dist/mcp/server.js +47 -10
  57. package/dist/mcp/server.js.map +1 -1
  58. package/dist/mcp/sessionTouchScanner.js +8 -2
  59. package/dist/mcp/sessionTouchScanner.js.map +1 -1
  60. package/dist/mcp/tools/costSummary.d.ts +26 -0
  61. package/dist/mcp/tools/costSummary.js +143 -0
  62. package/dist/mcp/tools/costSummary.js.map +1 -0
  63. package/dist/mcp/tools/fixSuggest.js +23 -2
  64. package/dist/mcp/tools/fixSuggest.js.map +1 -1
  65. package/dist/mcp/tools/memory.js +37 -4
  66. package/dist/mcp/tools/memory.js.map +1 -1
  67. package/dist/mcp/tools.js +2 -0
  68. package/dist/mcp/tools.js.map +1 -1
  69. package/dist/tool-manifest.json +18 -4
  70. package/package.json +5 -2
@@ -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":"AAUA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,mBAAmB,GAA+B;IACtD,oBAAoB,EAAE,UAAU;IAChC,iBAAiB,EAAE,OAAO;IAC1B,kBAAkB,EAAE,OAAO;IAC3B,UAAU,EAAE,MAAM;IAClB,oBAAoB,EAAE,UAAU;CACjC,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,2EAA2E;IAC3E,8EAA8E;IAC9E,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACvC,aAAa,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,aAAa,CAAC,IAAY,EAAE,GAAgB;IACnD,2EAA2E;IAC3E,oEAAoE;IACpE,IACE,IAAI,CAAC,IAAI,KAAK,gBAAgB;QAC9B,IAAI,CAAC,IAAI,KAAK,aAAa;QAC3B,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAC/B,CAAC;QACD,OAAO;IACT,CAAC;IACD,IAAI,IAAI,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACtC,MAAM,WAAW,GAAG,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QAC3D,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;QACzD,MAAM,IAAI,GAAe,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC;QAC/E,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;YAC1B,IAAI,IAAI;gBAAE,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC;QACD,OAAO;IACT,CAAC;IACD,MAAM,IAAI,GAAG,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,sFAAsF;QACtF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;YAAE,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QAC1D,OAAO;IACT,CAAC;IACD,IAAI,SAAS,CAAC,IAAI,CAAC;QAAE,OAAO;IAC5B,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,CAAC,IAAI;QAAE,OAAO;IAClB,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,qEAAqE;IACrE,+CAA+C;IAC/C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;AACxD,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,EAAE,CAAC;YACzD,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;gBAChC,IAAI,CAAC,CAAC,IAAI,KAAK,qBAAqB,EAAE,CAAC;oBACrC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;oBACxB,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,UAAU;wBAAE,OAAO,IAAI,CAAC;gBACvD,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,MAAM,CAAC,IAAY;IAC1B,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI;YAAE,OAAO,EAAE,CAAC,IAAI,CAAC;IACpC,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YAC9F,OAAO,CAAC,CAAC,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;IACD,+CAA+C;IAC/C,MAAM,CAAC,GAAG,oDAAoD,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/E,IAAI,CAAC;QAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACnB,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -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 {};
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Extract Kotlin `import` statements from a tree-sitter-kotlin AST.
3
+ *
4
+ * Handled forms:
5
+ * import com.foo.Bar → source = "com.foo.Bar"
6
+ * import com.foo.* → source = "com.foo.*"
7
+ * import com.foo.Bar as Baz → source = "com.foo.Bar", alias = "Baz"
8
+ *
9
+ * Kotlin doesn't have an explicit "re-export" notion at the import site
10
+ * (re-exports are done via top-level `typealias` / `val` exposing imported
11
+ * symbols). All imports are flagged as `static`.
12
+ */
13
+ export function extractKotlinImports(root) {
14
+ const imports = [];
15
+ walk(root, (n) => {
16
+ if (n.type !== 'import_header')
17
+ return;
18
+ const source = readImportPath(n);
19
+ if (!source)
20
+ return;
21
+ const alias = readAlias(n);
22
+ imports.push({
23
+ source,
24
+ kind: 'static',
25
+ specifiers: alias ? [alias] : [],
26
+ typeOnly: false,
27
+ line: n.startPosition.row + 1,
28
+ });
29
+ });
30
+ return imports;
31
+ }
32
+ function readImportPath(node) {
33
+ const segments = [];
34
+ collectIdentifiers(node, segments, false);
35
+ if (node.text.includes('.*'))
36
+ segments.push('*');
37
+ return segments.join('.');
38
+ }
39
+ function collectIdentifiers(node, out, insideAlias) {
40
+ if (insideAlias)
41
+ return;
42
+ if (node.type === 'import_alias')
43
+ return;
44
+ if (node.type === 'identifier' ||
45
+ node.type === 'simple_identifier' ||
46
+ node.type === 'type_identifier') {
47
+ out.push(node.text);
48
+ return;
49
+ }
50
+ for (const c of node.namedChildren)
51
+ collectIdentifiers(c, out, insideAlias);
52
+ }
53
+ function readAlias(node) {
54
+ for (const c of node.namedChildren) {
55
+ if (c.type !== 'import_alias')
56
+ continue;
57
+ for (const sub of c.namedChildren) {
58
+ if (sub.type === 'type_identifier' || sub.type === 'identifier' || sub.type === 'simple_identifier') {
59
+ return sub.text;
60
+ }
61
+ }
62
+ // Fallback: last token of `as <name>` text
63
+ const m = /\bas\s+([A-Za-z_][A-Za-z0-9_]*)/.exec(c.text);
64
+ if (m)
65
+ return m[1];
66
+ }
67
+ return null;
68
+ }
69
+ function walk(node, visit) {
70
+ visit(node);
71
+ for (const child of node.namedChildren)
72
+ walk(child, visit);
73
+ }
74
+ //# sourceMappingURL=kotlinImports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kotlinImports.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinImports.ts"],"names":[],"mappings":"AAUA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAY;IAC/C,MAAM,OAAO,GAAgB,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACf,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe;YAAE,OAAO;QACvC,MAAM,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM;YAAE,OAAO;QACpB,MAAM,KAAK,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;QAC3B,OAAO,CAAC,IAAI,CAAC;YACX,MAAM;YACN,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;YAChC,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,GAAG,GAAG,CAAC;SAC9B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,IAAY;IAClC,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,kBAAkB,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjD,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAY,EAAE,GAAa,EAAE,WAAoB;IAC3E,IAAI,WAAW;QAAE,OAAO;IACxB,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc;QAAE,OAAO;IACzC,IACE,IAAI,CAAC,IAAI,KAAK,YAAY;QAC1B,IAAI,CAAC,IAAI,KAAK,mBAAmB;QACjC,IAAI,CAAC,IAAI,KAAK,iBAAiB,EAC/B,CAAC;QACD,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa;QAAE,kBAAkB,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;AAC9E,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;QACnC,IAAI,CAAC,CAAC,IAAI,KAAK,cAAc;YAAE,SAAS;QACxC,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,aAAa,EAAE,CAAC;YAClC,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;gBACpG,OAAO,GAAG,CAAC,IAAI,CAAC;YAClB,CAAC;QACH,CAAC;QACD,2CAA2C;QAC3C,MAAM,CAAC,GAAG,iCAAiC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,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,20 @@
1
+ import type { FileEntry } from '../../types.js';
2
+ export interface KotlinProjectInfo {
3
+ /**
4
+ * Detected package roots — directories under which Kotlin source files
5
+ * live. For Gradle / Maven projects this is typically `src/main/kotlin`
6
+ * and / or `src/test/kotlin`. Imports like `import com.foo.Bar` resolve
7
+ * against each root.
8
+ */
9
+ packageRoots: string[];
10
+ /** Did we see a Gradle build file? Used for diagnostics only. */
11
+ hasGradle: boolean;
12
+ }
13
+ /**
14
+ * Detect Kotlin source roots. We don't parse Gradle / Maven manifests; we
15
+ * just check for the conventional `src/main/kotlin` layout and fall back
16
+ * to surveying the .kt file paths to find any prefix that looks like a
17
+ * package root (a directory whose first .kt file's `package` declaration
18
+ * matches its sub-path).
19
+ */
20
+ export declare function detectKotlinProject(rootPath: string, files: FileEntry[]): Promise<KotlinProjectInfo | null>;
@@ -0,0 +1,46 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ const COMMON_KOTLIN_ROOTS = [
4
+ 'src/main/kotlin',
5
+ 'src/test/kotlin',
6
+ 'src/main/java', // Kotlin / Java mixed projects
7
+ 'src/test/java',
8
+ 'src',
9
+ ];
10
+ /**
11
+ * Detect Kotlin source roots. We don't parse Gradle / Maven manifests; we
12
+ * just check for the conventional `src/main/kotlin` layout and fall back
13
+ * to surveying the .kt file paths to find any prefix that looks like a
14
+ * package root (a directory whose first .kt file's `package` declaration
15
+ * matches its sub-path).
16
+ */
17
+ export async function detectKotlinProject(rootPath, files) {
18
+ const ktFiles = files.filter((f) => f.relativePath.endsWith('.kt') || f.relativePath.endsWith('.kts'));
19
+ if (ktFiles.length === 0)
20
+ return null;
21
+ const hasGradle = await hasGradleManifest(rootPath);
22
+ const packageRoots = [];
23
+ for (const candidate of COMMON_KOTLIN_ROOTS) {
24
+ if (ktFiles.some((f) => f.relativePath.startsWith(candidate + '/'))) {
25
+ packageRoots.push(candidate);
26
+ }
27
+ }
28
+ // Fallback: bare repo with .kt files at the root.
29
+ if (packageRoots.length === 0)
30
+ packageRoots.push('.');
31
+ return { packageRoots, hasGradle };
32
+ }
33
+ async function hasGradleManifest(rootPath) {
34
+ const candidates = ['build.gradle', 'build.gradle.kts', 'settings.gradle', 'settings.gradle.kts', 'pom.xml'];
35
+ for (const c of candidates) {
36
+ try {
37
+ await fs.access(path.join(rootPath, c));
38
+ return true;
39
+ }
40
+ catch {
41
+ // try next
42
+ }
43
+ }
44
+ return false;
45
+ }
46
+ //# sourceMappingURL=kotlinManifests.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"kotlinManifests.js","sourceRoot":"","sources":["../../../src/core/languages/kotlinManifests.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAe7B,MAAM,mBAAmB,GAAG;IAC1B,iBAAiB;IACjB,iBAAiB;IACjB,eAAe,EAAE,+BAA+B;IAChD,eAAe;IACf,KAAK;CACN,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAgB,EAChB,KAAkB;IAElB,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAC1B,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,QAAQ,CAAC,MAAM,CAAC,CACzE,CAAC;IACF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtC,MAAM,SAAS,GAAG,MAAM,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACpD,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,KAAK,MAAM,SAAS,IAAI,mBAAmB,EAAE,CAAC;QAC5C,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,UAAU,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;YACpE,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IACD,kDAAkD;IAClD,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACtD,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;AACrC,CAAC;AAED,KAAK,UAAU,iBAAiB,CAAC,QAAgB;IAC/C,MAAM,UAAU,GAAG,CAAC,cAAc,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,SAAS,CAAC,CAAC;IAC7G,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC;YACxC,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,WAAW;QACb,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -7,7 +7,20 @@ import { rubyAdapter } from './rubyAdapter.js';
7
7
  import { rustAdapter } from './rustAdapter.js';
8
8
  import { phpAdapter } from './phpAdapter.js';
9
9
  import { csharpAdapter } from './csharpAdapter.js';
10
- const adapters = [javascriptAdapter, pythonAdapter, goAdapter, javaAdapter, rubyAdapter, rustAdapter, phpAdapter, csharpAdapter];
10
+ import { kotlinAdapter } from './kotlinAdapter.js';
11
+ import { cppAdapter } from './cppAdapter.js';
12
+ const adapters = [
13
+ javascriptAdapter,
14
+ pythonAdapter,
15
+ goAdapter,
16
+ javaAdapter,
17
+ rubyAdapter,
18
+ rustAdapter,
19
+ phpAdapter,
20
+ csharpAdapter,
21
+ kotlinAdapter,
22
+ cppAdapter,
23
+ ];
11
24
  const byExtension = new Map();
12
25
  function rebuildIndex() {
13
26
  byExtension.clear();
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/languages/registry.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAGnD,MAAM,QAAQ,GAAsB,CAAC,iBAAiB,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,CAAC,CAAC;AACpJ,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEvD,SAAS,YAAY;IACnB,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACrC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;AACH,CAAC;AACD,YAAY,EAAE,CAAC;AAEf,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,YAAY,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/core/languages/registry.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,QAAQ,GAAsB;IAClC,iBAAiB;IACjB,aAAa;IACb,SAAS;IACT,WAAW;IACX,WAAW;IACX,WAAW;IACX,UAAU;IACV,aAAa;IACb,aAAa;IACb,UAAU;CACX,CAAC;AACF,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;AAEvD,SAAS,YAAY;IACnB,WAAW,CAAC,KAAK,EAAE,CAAC;IACpB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACrC,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;AACH,CAAC;AACD,YAAY,EAAE,CAAC;AAEf,MAAM,UAAU,eAAe,CAAC,OAAwB;IACtD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAChC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,YAAY,EAAE,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -28,7 +28,25 @@ function grammarDirs() {
28
28
  const nodeModulesRust = path.join(repoRoot, 'node_modules', 'tree-sitter-rust');
29
29
  const nodeModulesPhp = path.join(repoRoot, 'node_modules', 'tree-sitter-php');
30
30
  const nodeModulesCSharp = path.join(repoRoot, 'node_modules', 'tree-sitter-c-sharp');
31
- return [distDir, nodeModulesWebTs, nodeModulesPy, nodeModulesGo, nodeModulesJava, nodeModulesRuby, nodeModulesRust, nodeModulesPhp, nodeModulesCSharp];
31
+ // 1.7+ Kotlin doesn't ship a prebuilt wasm in the npm tarball; we
32
+ // build it locally during `npm run build` (see scripts/copy-wasm.mjs's
33
+ // ensureBuiltWasm). At test time (vitest running off src/) the wasm
34
+ // sits inside the package directory, so probe it there too.
35
+ const nodeModulesKotlin = path.join(repoRoot, 'node_modules', 'tree-sitter-kotlin');
36
+ const nodeModulesCpp = path.join(repoRoot, 'node_modules', 'tree-sitter-cpp');
37
+ return [
38
+ distDir,
39
+ nodeModulesWebTs,
40
+ nodeModulesPy,
41
+ nodeModulesGo,
42
+ nodeModulesJava,
43
+ nodeModulesRuby,
44
+ nodeModulesRust,
45
+ nodeModulesPhp,
46
+ nodeModulesCSharp,
47
+ nodeModulesKotlin,
48
+ nodeModulesCpp,
49
+ ];
32
50
  }
33
51
  function findWasm(filename) {
34
52
  for (const dir of grammarDirs()) {