gitnexus 1.3.6 → 1.3.8
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/cli/ai-context.js +77 -23
- package/dist/cli/analyze.js +4 -11
- package/dist/cli/eval-server.d.ts +7 -0
- package/dist/cli/eval-server.js +16 -7
- package/dist/cli/index.js +2 -20
- package/dist/cli/mcp.js +2 -0
- package/dist/cli/setup.js +6 -1
- package/dist/config/supported-languages.d.ts +1 -0
- package/dist/config/supported-languages.js +1 -0
- package/dist/core/ingestion/call-processor.d.ts +5 -1
- package/dist/core/ingestion/call-processor.js +78 -0
- package/dist/core/ingestion/framework-detection.d.ts +1 -0
- package/dist/core/ingestion/framework-detection.js +49 -2
- package/dist/core/ingestion/import-processor.js +90 -39
- package/dist/core/ingestion/parsing-processor.d.ts +12 -1
- package/dist/core/ingestion/parsing-processor.js +92 -51
- package/dist/core/ingestion/pipeline.js +21 -2
- package/dist/core/ingestion/process-processor.js +0 -1
- package/dist/core/ingestion/tree-sitter-queries.d.ts +1 -0
- package/dist/core/ingestion/tree-sitter-queries.js +80 -0
- package/dist/core/ingestion/utils.d.ts +5 -0
- package/dist/core/ingestion/utils.js +20 -0
- package/dist/core/ingestion/workers/parse-worker.d.ts +11 -0
- package/dist/core/ingestion/workers/parse-worker.js +473 -51
- package/dist/core/kuzu/csv-generator.d.ts +4 -0
- package/dist/core/kuzu/csv-generator.js +23 -9
- package/dist/core/kuzu/kuzu-adapter.js +9 -3
- package/dist/core/tree-sitter/parser-loader.d.ts +1 -0
- package/dist/core/tree-sitter/parser-loader.js +3 -0
- package/dist/mcp/core/kuzu-adapter.d.ts +4 -3
- package/dist/mcp/core/kuzu-adapter.js +79 -16
- package/dist/mcp/local/local-backend.d.ts +13 -0
- package/dist/mcp/local/local-backend.js +148 -105
- package/dist/mcp/server.js +26 -11
- package/dist/storage/git.js +4 -1
- package/dist/storage/repo-manager.js +16 -2
- package/hooks/claude/gitnexus-hook.cjs +28 -8
- package/hooks/claude/pre-tool-use.sh +2 -1
- package/package.json +11 -3
- package/dist/cli/claude-hooks.d.ts +0 -22
- package/dist/cli/claude-hooks.js +0 -97
- package/dist/cli/view.d.ts +0 -13
- package/dist/cli/view.js +0 -59
- package/dist/core/graph/html-graph-viewer.d.ts +0 -15
- package/dist/core/graph/html-graph-viewer.js +0 -542
- package/dist/core/graph/html-graph-viewer.test.d.ts +0 -1
- package/dist/core/graph/html-graph-viewer.test.js +0 -67
|
@@ -141,6 +141,8 @@ const EXTENSIONS = [
|
|
|
141
141
|
'.py', '/__init__.py',
|
|
142
142
|
// Java
|
|
143
143
|
'.java',
|
|
144
|
+
// Kotlin
|
|
145
|
+
'.kt', '.kts',
|
|
144
146
|
// C/C++
|
|
145
147
|
'.c', '.h', '.cpp', '.hpp', '.cc', '.cxx', '.hxx', '.hh',
|
|
146
148
|
// C#
|
|
@@ -406,19 +408,32 @@ function tryRustModulePath(modulePath, allFiles) {
|
|
|
406
408
|
}
|
|
407
409
|
return null;
|
|
408
410
|
}
|
|
411
|
+
/**
|
|
412
|
+
* Append .* to a Kotlin import path if the AST has a wildcard_import sibling node.
|
|
413
|
+
* Pure function — returns a new string without mutating the input.
|
|
414
|
+
*/
|
|
415
|
+
const appendKotlinWildcard = (importPath, importNode) => {
|
|
416
|
+
for (let i = 0; i < importNode.childCount; i++) {
|
|
417
|
+
if (importNode.child(i)?.type === 'wildcard_import') {
|
|
418
|
+
return importPath.endsWith('.*') ? importPath : `${importPath}.*`;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
return importPath;
|
|
422
|
+
};
|
|
409
423
|
// ============================================================================
|
|
410
|
-
//
|
|
424
|
+
// JVM MULTI-FILE RESOLUTION (Java + Kotlin)
|
|
411
425
|
// ============================================================================
|
|
426
|
+
/** Kotlin file extensions for JVM resolver reuse */
|
|
427
|
+
const KOTLIN_EXTENSIONS = ['.kt', '.kts'];
|
|
412
428
|
/**
|
|
413
|
-
* Resolve a
|
|
414
|
-
*
|
|
429
|
+
* Resolve a JVM wildcard import (com.example.*) to all matching files.
|
|
430
|
+
* Works for both Java (.java) and Kotlin (.kt, .kts).
|
|
415
431
|
*/
|
|
416
|
-
function
|
|
432
|
+
function resolveJvmWildcard(importPath, normalizedFileList, allFileList, extensions, index) {
|
|
417
433
|
// "com.example.util.*" -> "com/example/util"
|
|
418
434
|
const packagePath = importPath.slice(0, -2).replace(/\./g, '/');
|
|
419
435
|
if (index) {
|
|
420
|
-
|
|
421
|
-
const candidates = index.getFilesInDir(packagePath, '.java');
|
|
436
|
+
const candidates = extensions.flatMap(ext => index.getFilesInDir(packagePath, ext));
|
|
422
437
|
// Filter to only direct children (no subdirectories)
|
|
423
438
|
const packageSuffix = '/' + packagePath + '/';
|
|
424
439
|
return candidates.filter(f => {
|
|
@@ -435,7 +450,8 @@ function resolveJavaWildcard(importPath, normalizedFileList, allFileList, index)
|
|
|
435
450
|
const matches = [];
|
|
436
451
|
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
437
452
|
const normalized = normalizedFileList[i];
|
|
438
|
-
if (normalized.includes(packageSuffix) &&
|
|
453
|
+
if (normalized.includes(packageSuffix) &&
|
|
454
|
+
extensions.some(ext => normalized.endsWith(ext))) {
|
|
439
455
|
const afterPackage = normalized.substring(normalized.indexOf(packageSuffix) + packageSuffix.length);
|
|
440
456
|
if (!afterPackage.includes('/')) {
|
|
441
457
|
matches.push(allFileList[i]);
|
|
@@ -445,29 +461,34 @@ function resolveJavaWildcard(importPath, normalizedFileList, allFileList, index)
|
|
|
445
461
|
return matches;
|
|
446
462
|
}
|
|
447
463
|
/**
|
|
448
|
-
* Try to resolve a
|
|
449
|
-
* "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
464
|
+
* Try to resolve a JVM member/static import by stripping the member name.
|
|
465
|
+
* Java: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
466
|
+
* Kotlin: "com.example.Constants.VALUE" -> resolve "com.example.Constants"
|
|
450
467
|
*/
|
|
451
|
-
function
|
|
452
|
-
//
|
|
453
|
-
// The last segment is a member name
|
|
468
|
+
function resolveJvmMemberImport(importPath, normalizedFileList, allFileList, extensions, index) {
|
|
469
|
+
// Member imports: com.example.Constants.VALUE or com.example.Constants.*
|
|
470
|
+
// The last segment is a member name if it starts with lowercase, is ALL_CAPS, or is a wildcard
|
|
454
471
|
const segments = importPath.split('.');
|
|
455
472
|
if (segments.length < 3)
|
|
456
473
|
return null;
|
|
457
474
|
const lastSeg = segments[segments.length - 1];
|
|
458
|
-
// If last segment is a wildcard or ALL_CAPS constant or starts with lowercase, strip it
|
|
459
475
|
if (lastSeg === '*' || /^[a-z]/.test(lastSeg) || /^[A-Z_]+$/.test(lastSeg)) {
|
|
460
476
|
const classPath = segments.slice(0, -1).join('/');
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
477
|
+
for (const ext of extensions) {
|
|
478
|
+
const classSuffix = classPath + ext;
|
|
479
|
+
if (index) {
|
|
480
|
+
const result = index.get(classSuffix) || index.getInsensitive(classSuffix);
|
|
481
|
+
if (result)
|
|
482
|
+
return result;
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
const fullSuffix = '/' + classSuffix;
|
|
486
|
+
for (let i = 0; i < normalizedFileList.length; i++) {
|
|
487
|
+
if (normalizedFileList[i].endsWith(fullSuffix) ||
|
|
488
|
+
normalizedFileList[i].toLowerCase().endsWith(fullSuffix.toLowerCase())) {
|
|
489
|
+
return allFileList[i];
|
|
490
|
+
}
|
|
491
|
+
}
|
|
471
492
|
}
|
|
472
493
|
}
|
|
473
494
|
}
|
|
@@ -637,24 +658,40 @@ export const processImports = async (graph, files, astCache, importMap, onProgre
|
|
|
637
658
|
return;
|
|
638
659
|
}
|
|
639
660
|
// Clean path (remove quotes and angle brackets for C/C++ includes)
|
|
640
|
-
const rawImportPath =
|
|
661
|
+
const rawImportPath = language === SupportedLanguages.Kotlin
|
|
662
|
+
? appendKotlinWildcard(sourceNode.text.replace(/['"<>]/g, ''), captureMap['import'])
|
|
663
|
+
: sourceNode.text.replace(/['"<>]/g, '');
|
|
641
664
|
totalImportsFound++;
|
|
642
|
-
// ---- Java: handle wildcards and
|
|
643
|
-
if (language === SupportedLanguages.Java) {
|
|
665
|
+
// ---- JVM languages (Java + Kotlin): handle wildcards and member imports ----
|
|
666
|
+
if (language === SupportedLanguages.Java || language === SupportedLanguages.Kotlin) {
|
|
667
|
+
const exts = language === SupportedLanguages.Java ? ['.java'] : KOTLIN_EXTENSIONS;
|
|
644
668
|
if (rawImportPath.endsWith('.*')) {
|
|
645
|
-
const matchedFiles =
|
|
669
|
+
const matchedFiles = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, exts, index);
|
|
670
|
+
// Kotlin can import Java files in mixed codebases — try .java as fallback
|
|
671
|
+
if (matchedFiles.length === 0 && language === SupportedLanguages.Kotlin) {
|
|
672
|
+
const javaMatches = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
|
|
673
|
+
for (const matchedFile of javaMatches) {
|
|
674
|
+
addImportEdge(file.path, matchedFile);
|
|
675
|
+
}
|
|
676
|
+
if (javaMatches.length > 0)
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
646
679
|
for (const matchedFile of matchedFiles) {
|
|
647
680
|
addImportEdge(file.path, matchedFile);
|
|
648
681
|
}
|
|
649
682
|
return; // skip single-file resolution
|
|
650
683
|
}
|
|
651
|
-
// Try static import resolution (strip member name)
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
684
|
+
// Try member/static import resolution (strip member name)
|
|
685
|
+
let memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, exts, index);
|
|
686
|
+
// Kotlin can import Java files in mixed codebases — try .java as fallback
|
|
687
|
+
if (!memberResolved && language === SupportedLanguages.Kotlin) {
|
|
688
|
+
memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
|
|
689
|
+
}
|
|
690
|
+
if (memberResolved) {
|
|
691
|
+
addImportEdge(file.path, memberResolved);
|
|
655
692
|
return;
|
|
656
693
|
}
|
|
657
|
-
// Fall through to normal resolution for regular
|
|
694
|
+
// Fall through to normal resolution for regular imports
|
|
658
695
|
}
|
|
659
696
|
// ---- Go: handle package-level imports ----
|
|
660
697
|
if (language === SupportedLanguages.Go && goModule && rawImportPath.startsWith(goModule.modulePath)) {
|
|
@@ -779,19 +816,33 @@ export const processImportsFromExtracted = async (graph, files, extractedImports
|
|
|
779
816
|
addImportEdge(filePath, cached);
|
|
780
817
|
continue;
|
|
781
818
|
}
|
|
782
|
-
// Java: handle wildcards and
|
|
783
|
-
if (language === SupportedLanguages.Java) {
|
|
819
|
+
// JVM languages (Java + Kotlin): handle wildcards and member imports
|
|
820
|
+
if (language === SupportedLanguages.Java || language === SupportedLanguages.Kotlin) {
|
|
821
|
+
const exts = language === SupportedLanguages.Java ? ['.java'] : KOTLIN_EXTENSIONS;
|
|
784
822
|
if (rawImportPath.endsWith('.*')) {
|
|
785
|
-
const matchedFiles =
|
|
823
|
+
const matchedFiles = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, exts, index);
|
|
824
|
+
// Kotlin can import Java files in mixed codebases — try .java as fallback
|
|
825
|
+
if (matchedFiles.length === 0 && language === SupportedLanguages.Kotlin) {
|
|
826
|
+
const javaMatches = resolveJvmWildcard(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
|
|
827
|
+
for (const matchedFile of javaMatches) {
|
|
828
|
+
addImportEdge(filePath, matchedFile);
|
|
829
|
+
}
|
|
830
|
+
if (javaMatches.length > 0)
|
|
831
|
+
continue;
|
|
832
|
+
}
|
|
786
833
|
for (const matchedFile of matchedFiles) {
|
|
787
834
|
addImportEdge(filePath, matchedFile);
|
|
788
835
|
}
|
|
789
836
|
continue;
|
|
790
837
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
838
|
+
let memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, exts, index);
|
|
839
|
+
// Kotlin can import Java files in mixed codebases — try .java as fallback
|
|
840
|
+
if (!memberResolved && language === SupportedLanguages.Kotlin) {
|
|
841
|
+
memberResolved = resolveJvmMemberImport(rawImportPath, normalizedFileList, allFileList, ['.java'], index);
|
|
842
|
+
}
|
|
843
|
+
if (memberResolved) {
|
|
844
|
+
resolveCache.set(cacheKey, memberResolved);
|
|
845
|
+
addImportEdge(filePath, memberResolved);
|
|
795
846
|
continue;
|
|
796
847
|
}
|
|
797
848
|
}
|
|
@@ -2,13 +2,24 @@ import { KnowledgeGraph } from '../graph/types.js';
|
|
|
2
2
|
import { SymbolTable } from './symbol-table.js';
|
|
3
3
|
import { ASTCache } from './ast-cache.js';
|
|
4
4
|
import { WorkerPool } from './workers/worker-pool.js';
|
|
5
|
-
import type { ExtractedImport, ExtractedCall, ExtractedHeritage } from './workers/parse-worker.js';
|
|
5
|
+
import type { ExtractedImport, ExtractedCall, ExtractedHeritage, ExtractedRoute } from './workers/parse-worker.js';
|
|
6
6
|
export type FileProgressCallback = (current: number, total: number, filePath: string) => void;
|
|
7
7
|
export interface WorkerExtractedData {
|
|
8
8
|
imports: ExtractedImport[];
|
|
9
9
|
calls: ExtractedCall[];
|
|
10
10
|
heritage: ExtractedHeritage[];
|
|
11
|
+
routes: ExtractedRoute[];
|
|
11
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Check if a symbol (function, class, etc.) is exported/public
|
|
15
|
+
* Handles all 9 supported languages with explicit logic
|
|
16
|
+
*
|
|
17
|
+
* @param node - The AST node for the symbol name
|
|
18
|
+
* @param name - The symbol name
|
|
19
|
+
* @param language - The programming language
|
|
20
|
+
* @returns true if the symbol is exported/public
|
|
21
|
+
*/
|
|
22
|
+
export declare const isNodeExported: (node: any, name: string, language: string) => boolean;
|
|
12
23
|
export declare const processParsing: (graph: KnowledgeGraph, files: {
|
|
13
24
|
path: string;
|
|
14
25
|
content: string;
|
|
@@ -2,34 +2,34 @@ import Parser from 'tree-sitter';
|
|
|
2
2
|
import { loadParser, loadLanguage } from '../tree-sitter/parser-loader.js';
|
|
3
3
|
import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
|
|
4
4
|
import { generateId } from '../../lib/utils.js';
|
|
5
|
-
import { getLanguageFromFilename, yieldToEventLoop } from './utils.js';
|
|
5
|
+
import { findSiblingChild, getLanguageFromFilename, yieldToEventLoop } from './utils.js';
|
|
6
6
|
import { detectFrameworkFromAST } from './framework-detection.js';
|
|
7
|
+
const DEFINITION_CAPTURE_KEYS = [
|
|
8
|
+
'definition.function',
|
|
9
|
+
'definition.class',
|
|
10
|
+
'definition.interface',
|
|
11
|
+
'definition.method',
|
|
12
|
+
'definition.struct',
|
|
13
|
+
'definition.enum',
|
|
14
|
+
'definition.namespace',
|
|
15
|
+
'definition.module',
|
|
16
|
+
'definition.trait',
|
|
17
|
+
'definition.impl',
|
|
18
|
+
'definition.type',
|
|
19
|
+
'definition.const',
|
|
20
|
+
'definition.static',
|
|
21
|
+
'definition.typedef',
|
|
22
|
+
'definition.macro',
|
|
23
|
+
'definition.union',
|
|
24
|
+
'definition.property',
|
|
25
|
+
'definition.record',
|
|
26
|
+
'definition.delegate',
|
|
27
|
+
'definition.annotation',
|
|
28
|
+
'definition.constructor',
|
|
29
|
+
'definition.template',
|
|
30
|
+
];
|
|
7
31
|
const getDefinitionNodeFromCaptures = (captureMap) => {
|
|
8
|
-
const
|
|
9
|
-
'definition.function',
|
|
10
|
-
'definition.class',
|
|
11
|
-
'definition.interface',
|
|
12
|
-
'definition.method',
|
|
13
|
-
'definition.struct',
|
|
14
|
-
'definition.enum',
|
|
15
|
-
'definition.namespace',
|
|
16
|
-
'definition.module',
|
|
17
|
-
'definition.trait',
|
|
18
|
-
'definition.impl',
|
|
19
|
-
'definition.type',
|
|
20
|
-
'definition.const',
|
|
21
|
-
'definition.static',
|
|
22
|
-
'definition.typedef',
|
|
23
|
-
'definition.macro',
|
|
24
|
-
'definition.union',
|
|
25
|
-
'definition.property',
|
|
26
|
-
'definition.record',
|
|
27
|
-
'definition.delegate',
|
|
28
|
-
'definition.annotation',
|
|
29
|
-
'definition.constructor',
|
|
30
|
-
'definition.template',
|
|
31
|
-
];
|
|
32
|
-
for (const key of definitionKeys) {
|
|
32
|
+
for (const key of DEFINITION_CAPTURE_KEYS) {
|
|
33
33
|
if (captureMap[key])
|
|
34
34
|
return captureMap[key];
|
|
35
35
|
}
|
|
@@ -47,7 +47,7 @@ const getDefinitionNodeFromCaptures = (captureMap) => {
|
|
|
47
47
|
* @param language - The programming language
|
|
48
48
|
* @returns true if the symbol is exported/public
|
|
49
49
|
*/
|
|
50
|
-
const isNodeExported = (node, name, language) => {
|
|
50
|
+
export const isNodeExported = (node, name, language) => {
|
|
51
51
|
let current = node;
|
|
52
52
|
switch (language) {
|
|
53
53
|
// JavaScript/TypeScript: Check for export keyword in ancestors
|
|
@@ -121,6 +121,24 @@ const isNodeExported = (node, name, language) => {
|
|
|
121
121
|
current = current.parent;
|
|
122
122
|
}
|
|
123
123
|
return false;
|
|
124
|
+
// Kotlin: Default visibility is public (unlike Java)
|
|
125
|
+
// visibility_modifier is inside modifiers, a sibling of the name node within the declaration
|
|
126
|
+
case 'kotlin':
|
|
127
|
+
while (current) {
|
|
128
|
+
if (current.parent) {
|
|
129
|
+
const visMod = findSiblingChild(current.parent, 'modifiers', 'visibility_modifier');
|
|
130
|
+
if (visMod) {
|
|
131
|
+
const text = visMod.text;
|
|
132
|
+
if (text === 'private' || text === 'internal' || text === 'protected')
|
|
133
|
+
return false;
|
|
134
|
+
if (text === 'public')
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
current = current.parent;
|
|
139
|
+
}
|
|
140
|
+
// No visibility modifier = public (Kotlin default)
|
|
141
|
+
return true;
|
|
124
142
|
// C/C++: No native export concept at language level
|
|
125
143
|
// Entry points will be detected via name patterns (main, etc.)
|
|
126
144
|
case 'c':
|
|
@@ -137,6 +155,21 @@ const isNodeExported = (node, name, language) => {
|
|
|
137
155
|
current = current.parent;
|
|
138
156
|
}
|
|
139
157
|
return false;
|
|
158
|
+
// PHP: Check for visibility modifier or top-level scope
|
|
159
|
+
case 'php':
|
|
160
|
+
while (current) {
|
|
161
|
+
if (current.type === 'class_declaration' ||
|
|
162
|
+
current.type === 'interface_declaration' ||
|
|
163
|
+
current.type === 'trait_declaration' ||
|
|
164
|
+
current.type === 'enum_declaration') {
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
if (current.type === 'visibility_modifier') {
|
|
168
|
+
return current.text === 'public';
|
|
169
|
+
}
|
|
170
|
+
current = current.parent;
|
|
171
|
+
}
|
|
172
|
+
return true; // Top-level functions are globally accessible
|
|
140
173
|
default:
|
|
141
174
|
return false;
|
|
142
175
|
}
|
|
@@ -153,7 +186,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
153
186
|
parseableFiles.push({ path: file.path, content: file.content });
|
|
154
187
|
}
|
|
155
188
|
if (parseableFiles.length === 0)
|
|
156
|
-
return { imports: [], calls: [], heritage: [] };
|
|
189
|
+
return { imports: [], calls: [], heritage: [], routes: [] };
|
|
157
190
|
const total = files.length;
|
|
158
191
|
// Dispatch to worker pool — pool handles splitting into chunks and sub-batching
|
|
159
192
|
const chunkResults = await workerPool.dispatch(parseableFiles, (filesProcessed) => {
|
|
@@ -163,6 +196,7 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
163
196
|
const allImports = [];
|
|
164
197
|
const allCalls = [];
|
|
165
198
|
const allHeritage = [];
|
|
199
|
+
const allRoutes = [];
|
|
166
200
|
for (const result of chunkResults) {
|
|
167
201
|
for (const node of result.nodes) {
|
|
168
202
|
graph.addNode({
|
|
@@ -180,10 +214,11 @@ const processParsingWithWorkers = async (graph, files, symbolTable, astCache, wo
|
|
|
180
214
|
allImports.push(...result.imports);
|
|
181
215
|
allCalls.push(...result.calls);
|
|
182
216
|
allHeritage.push(...result.heritage);
|
|
217
|
+
allRoutes.push(...result.routes);
|
|
183
218
|
}
|
|
184
219
|
// Final progress
|
|
185
220
|
onFileProgress?.(total, total, 'done');
|
|
186
|
-
return { imports: allImports, calls: allCalls, heritage: allHeritage };
|
|
221
|
+
return { imports: allImports, calls: allCalls, heritage: allHeritage, routes: allRoutes };
|
|
187
222
|
};
|
|
188
223
|
// ============================================================================
|
|
189
224
|
// Sequential fallback (original implementation)
|
|
@@ -202,7 +237,12 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
202
237
|
// Skip very large files — they can crash tree-sitter or cause OOM
|
|
203
238
|
if (file.content.length > 512 * 1024)
|
|
204
239
|
continue;
|
|
205
|
-
|
|
240
|
+
try {
|
|
241
|
+
await loadLanguage(language, file.path);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
continue; // parser unavailable — already warned in pipeline
|
|
245
|
+
}
|
|
206
246
|
let tree;
|
|
207
247
|
try {
|
|
208
248
|
tree = parser.parse(file.content, undefined, { bufferSize: 1024 * 256 });
|
|
@@ -239,9 +279,10 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
239
279
|
return;
|
|
240
280
|
}
|
|
241
281
|
const nameNode = captureMap['name'];
|
|
242
|
-
|
|
282
|
+
// Synthesize name for constructors without explicit @name capture (e.g. Swift init)
|
|
283
|
+
if (!nameNode && !captureMap['definition.constructor'])
|
|
243
284
|
return;
|
|
244
|
-
const nodeName = nameNode.text;
|
|
285
|
+
const nodeName = nameNode ? nameNode.text : 'init';
|
|
245
286
|
let nodeLabel = 'CodeElement';
|
|
246
287
|
if (captureMap['definition.function'])
|
|
247
288
|
nodeLabel = 'Function';
|
|
@@ -287,28 +328,28 @@ const processParsingSequential = async (graph, files, symbolTable, astCache, onF
|
|
|
287
328
|
nodeLabel = 'Constructor';
|
|
288
329
|
else if (captureMap['definition.template'])
|
|
289
330
|
nodeLabel = 'Template';
|
|
290
|
-
const
|
|
331
|
+
const definitionNodeForRange = getDefinitionNodeFromCaptures(captureMap);
|
|
332
|
+
const startLine = definitionNodeForRange ? definitionNodeForRange.startPosition.row : (nameNode ? nameNode.startPosition.row : 0);
|
|
333
|
+
const nodeId = generateId(nodeLabel, `${file.path}:${nodeName}:${startLine}`);
|
|
334
|
+
const definitionNode = getDefinitionNodeFromCaptures(captureMap);
|
|
335
|
+
const frameworkHint = definitionNode
|
|
336
|
+
? detectFrameworkFromAST(language, (definitionNode.text || '').slice(0, 300))
|
|
337
|
+
: null;
|
|
291
338
|
const node = {
|
|
292
339
|
id: nodeId,
|
|
293
340
|
label: nodeLabel,
|
|
294
|
-
properties:
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
...(frameworkHint ? {
|
|
307
|
-
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
308
|
-
astFrameworkReason: frameworkHint.reason,
|
|
309
|
-
} : {}),
|
|
310
|
-
};
|
|
311
|
-
})()
|
|
341
|
+
properties: {
|
|
342
|
+
name: nodeName,
|
|
343
|
+
filePath: file.path,
|
|
344
|
+
startLine: definitionNodeForRange ? definitionNodeForRange.startPosition.row : startLine,
|
|
345
|
+
endLine: definitionNodeForRange ? definitionNodeForRange.endPosition.row : startLine,
|
|
346
|
+
language: language,
|
|
347
|
+
isExported: isNodeExported(nameNode || definitionNodeForRange, nodeName, language),
|
|
348
|
+
...(frameworkHint ? {
|
|
349
|
+
astFrameworkMultiplier: frameworkHint.entryPointMultiplier,
|
|
350
|
+
astFrameworkReason: frameworkHint.reason,
|
|
351
|
+
} : {}),
|
|
352
|
+
},
|
|
312
353
|
};
|
|
313
354
|
graph.addNode(node);
|
|
314
355
|
symbolTable.add(file.path, nodeName, nodeId, nodeLabel);
|
|
@@ -2,7 +2,7 @@ import { createKnowledgeGraph } from '../graph/graph.js';
|
|
|
2
2
|
import { processStructure } from './structure-processor.js';
|
|
3
3
|
import { processParsing } from './parsing-processor.js';
|
|
4
4
|
import { processImports, processImportsFromExtracted, createImportMap, buildImportResolutionContext } from './import-processor.js';
|
|
5
|
-
import { processCalls, processCallsFromExtracted } from './call-processor.js';
|
|
5
|
+
import { processCalls, processCallsFromExtracted, processRoutesFromExtracted } from './call-processor.js';
|
|
6
6
|
import { processHeritage, processHeritageFromExtracted } from './heritage-processor.js';
|
|
7
7
|
import { processCommunities } from './community-processor.js';
|
|
8
8
|
import { processProcesses } from './process-processor.js';
|
|
@@ -10,6 +10,7 @@ import { createSymbolTable } from './symbol-table.js';
|
|
|
10
10
|
import { createASTCache } from './ast-cache.js';
|
|
11
11
|
import { walkRepositoryPaths, readFileContents } from './filesystem-walker.js';
|
|
12
12
|
import { getLanguageFromFilename } from './utils.js';
|
|
13
|
+
import { isLanguageAvailable } from '../tree-sitter/parser-loader.js';
|
|
13
14
|
import { createWorkerPool } from './workers/worker-pool.js';
|
|
14
15
|
const isDev = process.env.NODE_ENV === 'development';
|
|
15
16
|
/** Max bytes of source content to load per parse chunk. Each chunk's source +
|
|
@@ -70,7 +71,21 @@ export const runPipelineFromRepo = async (repoPath, onProgress) => {
|
|
|
70
71
|
// ── Phase 3+4: Chunked read + parse ────────────────────────────────
|
|
71
72
|
// Group parseable files into byte-budget chunks so only ~20MB of source
|
|
72
73
|
// is in memory at a time. Each chunk is: read → parse → extract → free.
|
|
73
|
-
const parseableScanned = scannedFiles.filter(f =>
|
|
74
|
+
const parseableScanned = scannedFiles.filter(f => {
|
|
75
|
+
const lang = getLanguageFromFilename(f.path);
|
|
76
|
+
return lang && isLanguageAvailable(lang);
|
|
77
|
+
});
|
|
78
|
+
// Warn about files skipped due to unavailable parsers
|
|
79
|
+
const skippedByLang = new Map();
|
|
80
|
+
for (const f of scannedFiles) {
|
|
81
|
+
const lang = getLanguageFromFilename(f.path);
|
|
82
|
+
if (lang && !isLanguageAvailable(lang)) {
|
|
83
|
+
skippedByLang.set(lang, (skippedByLang.get(lang) || 0) + 1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const [lang, count] of skippedByLang) {
|
|
87
|
+
console.warn(`Skipping ${count} ${lang} file(s) — ${lang} parser not available (native binding may not have built). Try: npm rebuild tree-sitter-${lang}`);
|
|
88
|
+
}
|
|
74
89
|
const totalParseable = parseableScanned.length;
|
|
75
90
|
// Build byte-budget chunks
|
|
76
91
|
const chunks = [];
|
|
@@ -151,6 +166,10 @@ export const runPipelineFromRepo = async (repoPath, onProgress) => {
|
|
|
151
166
|
if (chunkWorkerData.heritage.length > 0) {
|
|
152
167
|
await processHeritageFromExtracted(graph, chunkWorkerData.heritage, symbolTable);
|
|
153
168
|
}
|
|
169
|
+
// Routes — resolve immediately (Laravel route→controller CALLS edges)
|
|
170
|
+
if (chunkWorkerData.routes && chunkWorkerData.routes.length > 0) {
|
|
171
|
+
await processRoutesFromExtracted(graph, chunkWorkerData.routes, symbolTable, importMap);
|
|
172
|
+
}
|
|
154
173
|
}
|
|
155
174
|
else {
|
|
156
175
|
await processImports(graph, chunkFiles, astCache, importMap, undefined, repoPath, allPaths);
|
|
@@ -219,7 +219,6 @@ const traceFromEntryPoint = (entryId, callsEdges, config) => {
|
|
|
219
219
|
// BFS with path tracking
|
|
220
220
|
// Each queue item: [currentNodeId, pathSoFar]
|
|
221
221
|
const queue = [[entryId, [entryId]]];
|
|
222
|
-
const visited = new Set();
|
|
223
222
|
while (queue.length > 0 && traces.length < config.maxBranching * 3) {
|
|
224
223
|
const [currentId, path] = queue.shift();
|
|
225
224
|
// Get outgoing calls
|
|
@@ -9,5 +9,6 @@ export declare const CPP_QUERIES = "\n; Classes, Structs, Namespaces\n(class_spe
|
|
|
9
9
|
export declare const CSHARP_QUERIES = "\n; Types\n(class_declaration name: (identifier) @name) @definition.class\n(interface_declaration name: (identifier) @name) @definition.interface\n(struct_declaration name: (identifier) @name) @definition.struct\n(enum_declaration name: (identifier) @name) @definition.enum\n(record_declaration name: (identifier) @name) @definition.record\n(delegate_declaration name: (identifier) @name) @definition.delegate\n\n; Namespaces\n(namespace_declaration name: (identifier) @name) @definition.namespace\n(namespace_declaration name: (qualified_name) @name) @definition.namespace\n\n; Methods & Properties\n(method_declaration name: (identifier) @name) @definition.method\n(local_function_statement name: (identifier) @name) @definition.function\n(constructor_declaration name: (identifier) @name) @definition.constructor\n(property_declaration name: (identifier) @name) @definition.property\n\n; Using\n(using_directive (qualified_name) @import.source) @import\n(using_directive (identifier) @import.source) @import\n\n; Calls\n(invocation_expression function: (identifier) @call.name) @call\n(invocation_expression function: (member_access_expression name: (identifier) @call.name)) @call\n\n; Heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (simple_base_type (identifier) @heritage.extends))) @heritage\n(class_declaration name: (identifier) @heritage.class\n (base_list (simple_base_type (generic_name (identifier) @heritage.extends)))) @heritage\n";
|
|
10
10
|
export declare const RUST_QUERIES = "\n; Functions & Items\n(function_item name: (identifier) @name) @definition.function\n(struct_item name: (type_identifier) @name) @definition.struct\n(enum_item name: (type_identifier) @name) @definition.enum\n(trait_item name: (type_identifier) @name) @definition.trait\n(impl_item type: (type_identifier) @name) @definition.impl\n(mod_item name: (identifier) @name) @definition.module\n\n; Type aliases, const, static, macros\n(type_item name: (type_identifier) @name) @definition.type\n(const_item name: (identifier) @name) @definition.const\n(static_item name: (identifier) @name) @definition.static\n(macro_definition name: (identifier) @name) @definition.macro\n\n; Use statements\n(use_declaration argument: (_) @import.source) @import\n\n; Calls\n(call_expression function: (identifier) @call.name) @call\n(call_expression function: (field_expression field: (field_identifier) @call.name)) @call\n(call_expression function: (scoped_identifier name: (identifier) @call.name)) @call\n(call_expression function: (generic_function function: (identifier) @call.name)) @call\n\n; Heritage (trait implementation)\n(impl_item trait: (type_identifier) @heritage.trait type: (type_identifier) @heritage.class) @heritage\n(impl_item trait: (generic_type type: (type_identifier) @heritage.trait) type: (type_identifier) @heritage.class) @heritage\n";
|
|
11
11
|
export declare const PHP_QUERIES = "\n; \u2500\u2500 Namespace \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(namespace_definition\n name: (namespace_name) @name) @definition.namespace\n\n; \u2500\u2500 Classes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @name) @definition.class\n\n; \u2500\u2500 Interfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(interface_declaration\n name: (name) @name) @definition.interface\n\n; \u2500\u2500 Traits \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(trait_declaration\n name: (name) @name) @definition.trait\n\n; \u2500\u2500 Enums (PHP 8.1) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(enum_declaration\n name: (name) @name) @definition.enum\n\n; \u2500\u2500 Top-level functions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(function_definition\n name: (name) @name) @definition.function\n\n; \u2500\u2500 Methods (including constructors) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(method_declaration\n name: (name) @name) @definition.method\n\n; \u2500\u2500 Class properties (including Eloquent $fillable, $casts, etc.) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(property_declaration\n (property_element\n (variable_name\n (name) @name))) @definition.property\n\n; \u2500\u2500 Imports: use statements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Simple: use App\\Models\\User;\n(namespace_use_declaration\n (namespace_use_clause\n (qualified_name) @import.source)) @import\n\n; \u2500\u2500 Function/method calls \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Regular function call: foo()\n(function_call_expression\n function: (name) @call.name) @call\n\n; Method call: $obj->method()\n(member_call_expression\n name: (name) @call.name) @call\n\n; Nullsafe method call: $obj?->method()\n(nullsafe_member_call_expression\n name: (name) @call.name) @call\n\n; Static call: Foo::bar() (php_only uses scoped_call_expression)\n(scoped_call_expression\n name: (name) @call.name) @call\n\n; \u2500\u2500 Heritage: extends \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (base_clause\n [(name) (qualified_name)] @heritage.extends)) @heritage\n\n; \u2500\u2500 Heritage: implements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n (class_interface_clause\n [(name) (qualified_name)] @heritage.implements)) @heritage.impl\n\n; \u2500\u2500 Heritage: use trait (must capture enclosing class name) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(class_declaration\n name: (name) @heritage.class\n body: (declaration_list\n (use_declaration\n [(name) (qualified_name)] @heritage.trait))) @heritage\n";
|
|
12
|
+
export declare const KOTLIN_QUERIES = "\n; \u2500\u2500 Interfaces \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; tree-sitter-kotlin (fwcd) has no interface_declaration node type.\n; Interfaces are class_declaration nodes with an anonymous \"interface\" keyword child.\n(class_declaration\n \"interface\"\n (type_identifier) @name) @definition.interface\n\n; \u2500\u2500 Classes (regular, data, sealed, enum) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; All have the anonymous \"class\" keyword child. enum class has both\n; \"enum\" and \"class\" children \u2014 the \"class\" child still matches.\n(class_declaration\n \"class\"\n (type_identifier) @name) @definition.class\n\n; \u2500\u2500 Object declarations (Kotlin singletons) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(object_declaration\n (type_identifier) @name) @definition.class\n\n; \u2500\u2500 Companion objects (named only) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(companion_object\n (type_identifier) @name) @definition.class\n\n; \u2500\u2500 Functions (top-level, member, extension) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(function_declaration\n (simple_identifier) @name) @definition.function\n\n; \u2500\u2500 Properties \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(property_declaration\n (variable_declaration\n (simple_identifier) @name)) @definition.property\n\n; \u2500\u2500 Enum entries \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(enum_entry\n (simple_identifier) @name) @definition.enum\n\n; \u2500\u2500 Type aliases \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(type_alias\n (type_identifier) @name) @definition.type\n\n; \u2500\u2500 Imports \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(import_header\n (identifier) @import.source) @import\n\n; \u2500\u2500 Function calls (direct) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(call_expression\n (simple_identifier) @call.name) @call\n\n; \u2500\u2500 Method calls (via navigation: obj.method()) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(call_expression\n (navigation_expression\n (navigation_suffix\n (simple_identifier) @call.name))) @call\n\n; \u2500\u2500 Constructor invocations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(constructor_invocation\n (user_type\n (type_identifier) @call.name)) @call\n\n; \u2500\u2500 Infix function calls (e.g., a to b, x until y) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n(infix_expression\n (simple_identifier) @call.name) @call\n\n; \u2500\u2500 Heritage: extends / implements via delegation_specifier \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n; Interface implementation (bare user_type): class Foo : Bar\n(class_declaration\n (type_identifier) @heritage.class\n (delegation_specifier\n (user_type (type_identifier) @heritage.extends))) @heritage\n\n; Class extension (constructor_invocation): class Foo : Bar()\n(class_declaration\n (type_identifier) @heritage.class\n (delegation_specifier\n (constructor_invocation\n (user_type (type_identifier) @heritage.extends)))) @heritage\n";
|
|
12
13
|
export declare const SWIFT_QUERIES = "\n; Classes\n(class_declaration \"class\" name: (type_identifier) @name) @definition.class\n\n; Structs\n(class_declaration \"struct\" name: (type_identifier) @name) @definition.struct\n\n; Enums\n(class_declaration \"enum\" name: (type_identifier) @name) @definition.enum\n\n; Extensions (mapped to class \u2014 no dedicated label in schema)\n(class_declaration \"extension\" name: (user_type (type_identifier) @name)) @definition.class\n\n; Actors\n(class_declaration \"actor\" name: (type_identifier) @name) @definition.class\n\n; Protocols (mapped to interface)\n(protocol_declaration name: (type_identifier) @name) @definition.interface\n\n; Type aliases\n(typealias_declaration name: (type_identifier) @name) @definition.type\n\n; Functions (top-level and methods)\n(function_declaration name: (simple_identifier) @name) @definition.function\n\n; Protocol method declarations\n(protocol_function_declaration name: (simple_identifier) @name) @definition.method\n\n; Initializers\n(init_declaration) @definition.constructor\n\n; Properties (stored and computed)\n(property_declaration (pattern (simple_identifier) @name)) @definition.property\n\n; Imports\n(import_declaration (identifier (simple_identifier) @import.source)) @import\n\n; Calls - direct function calls\n(call_expression (simple_identifier) @call.name) @call\n\n; Calls - member/navigation calls (obj.method())\n(call_expression (navigation_expression (navigation_suffix (simple_identifier) @call.name))) @call\n\n; Heritage - class/struct/enum inheritance and protocol conformance\n(class_declaration name: (type_identifier) @heritage.class\n (inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage\n\n; Heritage - protocol inheritance\n(protocol_declaration name: (type_identifier) @heritage.class\n (inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage\n";
|
|
13
14
|
export declare const LANGUAGE_QUERIES: Record<SupportedLanguages, string>;
|
|
@@ -384,6 +384,85 @@ export const PHP_QUERIES = `
|
|
|
384
384
|
(use_declaration
|
|
385
385
|
[(name) (qualified_name)] @heritage.trait))) @heritage
|
|
386
386
|
`;
|
|
387
|
+
// Kotlin queries - works with tree-sitter-kotlin (fwcd/tree-sitter-kotlin)
|
|
388
|
+
// Based on official tags.scm; functions use simple_identifier, classes use type_identifier
|
|
389
|
+
export const KOTLIN_QUERIES = `
|
|
390
|
+
; ── Interfaces ─────────────────────────────────────────────────────────────
|
|
391
|
+
; tree-sitter-kotlin (fwcd) has no interface_declaration node type.
|
|
392
|
+
; Interfaces are class_declaration nodes with an anonymous "interface" keyword child.
|
|
393
|
+
(class_declaration
|
|
394
|
+
"interface"
|
|
395
|
+
(type_identifier) @name) @definition.interface
|
|
396
|
+
|
|
397
|
+
; ── Classes (regular, data, sealed, enum) ────────────────────────────────
|
|
398
|
+
; All have the anonymous "class" keyword child. enum class has both
|
|
399
|
+
; "enum" and "class" children — the "class" child still matches.
|
|
400
|
+
(class_declaration
|
|
401
|
+
"class"
|
|
402
|
+
(type_identifier) @name) @definition.class
|
|
403
|
+
|
|
404
|
+
; ── Object declarations (Kotlin singletons) ──────────────────────────────
|
|
405
|
+
(object_declaration
|
|
406
|
+
(type_identifier) @name) @definition.class
|
|
407
|
+
|
|
408
|
+
; ── Companion objects (named only) ───────────────────────────────────────
|
|
409
|
+
(companion_object
|
|
410
|
+
(type_identifier) @name) @definition.class
|
|
411
|
+
|
|
412
|
+
; ── Functions (top-level, member, extension) ──────────────────────────────
|
|
413
|
+
(function_declaration
|
|
414
|
+
(simple_identifier) @name) @definition.function
|
|
415
|
+
|
|
416
|
+
; ── Properties ───────────────────────────────────────────────────────────
|
|
417
|
+
(property_declaration
|
|
418
|
+
(variable_declaration
|
|
419
|
+
(simple_identifier) @name)) @definition.property
|
|
420
|
+
|
|
421
|
+
; ── Enum entries ─────────────────────────────────────────────────────────
|
|
422
|
+
(enum_entry
|
|
423
|
+
(simple_identifier) @name) @definition.enum
|
|
424
|
+
|
|
425
|
+
; ── Type aliases ─────────────────────────────────────────────────────────
|
|
426
|
+
(type_alias
|
|
427
|
+
(type_identifier) @name) @definition.type
|
|
428
|
+
|
|
429
|
+
; ── Imports ──────────────────────────────────────────────────────────────
|
|
430
|
+
(import_header
|
|
431
|
+
(identifier) @import.source) @import
|
|
432
|
+
|
|
433
|
+
; ── Function calls (direct) ──────────────────────────────────────────────
|
|
434
|
+
(call_expression
|
|
435
|
+
(simple_identifier) @call.name) @call
|
|
436
|
+
|
|
437
|
+
; ── Method calls (via navigation: obj.method()) ──────────────────────────
|
|
438
|
+
(call_expression
|
|
439
|
+
(navigation_expression
|
|
440
|
+
(navigation_suffix
|
|
441
|
+
(simple_identifier) @call.name))) @call
|
|
442
|
+
|
|
443
|
+
; ── Constructor invocations ──────────────────────────────────────────────
|
|
444
|
+
(constructor_invocation
|
|
445
|
+
(user_type
|
|
446
|
+
(type_identifier) @call.name)) @call
|
|
447
|
+
|
|
448
|
+
; ── Infix function calls (e.g., a to b, x until y) ──────────────────────
|
|
449
|
+
(infix_expression
|
|
450
|
+
(simple_identifier) @call.name) @call
|
|
451
|
+
|
|
452
|
+
; ── Heritage: extends / implements via delegation_specifier ──────────────
|
|
453
|
+
; Interface implementation (bare user_type): class Foo : Bar
|
|
454
|
+
(class_declaration
|
|
455
|
+
(type_identifier) @heritage.class
|
|
456
|
+
(delegation_specifier
|
|
457
|
+
(user_type (type_identifier) @heritage.extends))) @heritage
|
|
458
|
+
|
|
459
|
+
; Class extension (constructor_invocation): class Foo : Bar()
|
|
460
|
+
(class_declaration
|
|
461
|
+
(type_identifier) @heritage.class
|
|
462
|
+
(delegation_specifier
|
|
463
|
+
(constructor_invocation
|
|
464
|
+
(user_type (type_identifier) @heritage.extends)))) @heritage
|
|
465
|
+
`;
|
|
387
466
|
// Swift queries - works with tree-sitter-swift
|
|
388
467
|
export const SWIFT_QUERIES = `
|
|
389
468
|
; Classes
|
|
@@ -447,5 +526,6 @@ export const LANGUAGE_QUERIES = {
|
|
|
447
526
|
[SupportedLanguages.CSharp]: CSHARP_QUERIES,
|
|
448
527
|
[SupportedLanguages.Rust]: RUST_QUERIES,
|
|
449
528
|
[SupportedLanguages.PHP]: PHP_QUERIES,
|
|
529
|
+
[SupportedLanguages.Kotlin]: KOTLIN_QUERIES,
|
|
450
530
|
[SupportedLanguages.Swift]: SWIFT_QUERIES,
|
|
451
531
|
};
|