mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-08-28 05:25:25 +00:00
chore: merge upstream main into feat/kotlin-language-support
Resolve conflicts between Kotlin and Swift language support additions. Both languages are now fully supported side by side.
This commit is contained in:
commit
e046bf734d
24 changed files with 606 additions and 17 deletions
28
README.md
28
README.md
|
|
@ -1,13 +1,29 @@
|
|||
# GitNexus
|
||||
|
||||
<a href="https://trendshift.io/repositories/19809" target="_blank"><img src="https://trendshift.io/api/badge/repositories/19809" alt="abhigyanpatwari%2FGitNexus | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
<div align="center">
|
||||
|
||||
**Building git for agent context.**
|
||||
<a href="https://trendshift.io/repositories/19809" target="_blank">
|
||||
<img src="https://trendshift.io/api/badge/repositories/19809" alt="abhigyanpatwari%2FGitNexus | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
|
||||
</a>
|
||||
|
||||
<h2>Join the official Discord to discuss ideas, issues etc!</h2>
|
||||
|
||||
<a href="https://discord.gg/AAsRVT6fGb">
|
||||
<img src="https://img.shields.io/discord/1477255801545429032?color=5865F2&logo=discord&logoColor=white" alt="Discord"/>
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/gitnexus">
|
||||
<img src="https://img.shields.io/npm/v/gitnexus.svg" alt="npm version"/>
|
||||
</a>
|
||||
<a href="https://polyformproject.org/licenses/noncommercial/1.0.0/">
|
||||
<img src="https://img.shields.io/badge/License-PolyForm%20Noncommercial-blue.svg" alt="License: PolyForm Noncommercial"/>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
**Building nervous system for agent context.**
|
||||
|
||||
Indexes any codebase into a knowledge graph — every dependency, call chain, cluster, and execution flow — then exposes it through smart tools so AI agents never miss code.
|
||||
|
||||
[](https://www.npmjs.com/package/gitnexus)
|
||||
[](https://polyformproject.org/licenses/noncommercial/1.0.0/)
|
||||
|
||||
|
||||
|
||||
|
|
@ -303,7 +319,7 @@ GitNexus builds a complete knowledge graph of your codebase through a multi-phas
|
|||
|
||||
### Supported Languages
|
||||
|
||||
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust
|
||||
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust, PHP, Swift
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -465,7 +481,7 @@ The wiki generator reads the indexed graph structure, groups files into modules
|
|||
|
||||
- [X] Wiki Generation, Multi-File Rename, Git-Diff Impact Analysis
|
||||
- [X] Process-Grouped Search, 360-Degree Context, Claude Code Hooks
|
||||
- [X] Multi-Repo MCP, Zero-Config Setup, 9 Language Support
|
||||
- [X] Multi-Repo MCP, Zero-Config Setup, 11 Language Support
|
||||
- [X] Community Detection, Process Detection, Confidence Scoring
|
||||
- [X] Hybrid Search, Vector Index
|
||||
|
||||
|
|
|
|||
BIN
gitnexus-web/public/wasm/swift/tree-sitter-swift.wasm
Executable file
BIN
gitnexus-web/public/wasm/swift/tree-sitter-swift.wasm
Executable file
Binary file not shown.
|
|
@ -10,5 +10,5 @@ export enum SupportedLanguages {
|
|||
Rust = 'rust',
|
||||
PHP = 'php',
|
||||
// Ruby = 'ruby',
|
||||
// Swift = 'swift',
|
||||
Swift = 'swift',
|
||||
}
|
||||
|
|
@ -103,6 +103,26 @@ const ENTRY_POINT_PATTERNS: Record<string, RegExp[]> = {
|
|||
/^Start$/, // Start methods
|
||||
],
|
||||
|
||||
// Swift / iOS
|
||||
'swift': [
|
||||
/^viewDidLoad$/, // UIKit lifecycle
|
||||
/^viewWillAppear$/, // UIKit lifecycle
|
||||
/^viewDidAppear$/, // UIKit lifecycle
|
||||
/^viewWillDisappear$/, // UIKit lifecycle
|
||||
/^viewDidDisappear$/, // UIKit lifecycle
|
||||
/^application\(/, // AppDelegate methods
|
||||
/^scene\(/, // SceneDelegate methods
|
||||
/^body$/, // SwiftUI View.body
|
||||
/Coordinator$/, // Coordinator pattern
|
||||
/^sceneDidBecomeActive$/, // SceneDelegate lifecycle
|
||||
/^sceneWillResignActive$/, // SceneDelegate lifecycle
|
||||
/^didFinishLaunchingWithOptions$/, // AppDelegate
|
||||
/ViewController$/, // ViewController classes
|
||||
/^configure[A-Z]/, // Configuration methods
|
||||
/^setup[A-Z]/, // Setup methods
|
||||
/^makeBody$/, // SwiftUI ViewModifier
|
||||
],
|
||||
|
||||
// PHP / Laravel
|
||||
'php': [
|
||||
/Controller$/, // UserController (class name convention)
|
||||
|
|
@ -271,6 +291,10 @@ export function isTestFile(filePath: string): boolean {
|
|||
p.includes('/src/test/') ||
|
||||
// Rust test patterns (inline tests are different, but test files)
|
||||
p.includes('/tests/') ||
|
||||
// Swift/iOS test patterns
|
||||
p.endsWith('tests.swift') ||
|
||||
p.endsWith('test.swift') ||
|
||||
p.includes('uitests/') ||
|
||||
// C# test patterns
|
||||
p.includes('.tests/') ||
|
||||
p.includes('tests.cs') ||
|
||||
|
|
|
|||
|
|
@ -257,16 +257,63 @@ export function detectFrameworkFromPath(filePath: string): FrameworkHint | null
|
|||
return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-repository' };
|
||||
}
|
||||
|
||||
// ========== SWIFT / iOS ==========
|
||||
|
||||
// iOS App entry points (highest priority)
|
||||
if (p.endsWith('/appdelegate.swift') || p.endsWith('/scenedelegate.swift') || p.endsWith('/app.swift')) {
|
||||
return { framework: 'ios', entryPointMultiplier: 3.0, reason: 'ios-app-entry' };
|
||||
}
|
||||
|
||||
// SwiftUI App entry (@main)
|
||||
if (p.endsWith('app.swift') && p.includes('/sources/')) {
|
||||
return { framework: 'swiftui', entryPointMultiplier: 3.0, reason: 'swiftui-app' };
|
||||
}
|
||||
|
||||
// UIKit ViewControllers (high priority - screen entry points)
|
||||
if ((p.includes('/viewcontrollers/') || p.includes('/controllers/') || p.includes('/screens/')) && p.endsWith('.swift')) {
|
||||
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller' };
|
||||
}
|
||||
|
||||
// ViewController by filename convention
|
||||
if (p.endsWith('viewcontroller.swift') || p.endsWith('vc.swift')) {
|
||||
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller-file' };
|
||||
}
|
||||
|
||||
// Coordinator pattern (navigation entry points)
|
||||
if (p.includes('/coordinators/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator' };
|
||||
}
|
||||
|
||||
// Coordinator by filename
|
||||
if (p.endsWith('coordinator.swift')) {
|
||||
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator-file' };
|
||||
}
|
||||
|
||||
// SwiftUI Views (moderate - reusable components)
|
||||
if ((p.includes('/views/') || p.includes('/scenes/')) && p.endsWith('.swift')) {
|
||||
return { framework: 'swiftui', entryPointMultiplier: 1.8, reason: 'swiftui-view' };
|
||||
}
|
||||
|
||||
// Service layer
|
||||
if (p.includes('/services/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-service', entryPointMultiplier: 1.8, reason: 'ios-service' };
|
||||
}
|
||||
|
||||
// Router / navigation
|
||||
if (p.includes('/router/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
|
||||
}
|
||||
|
||||
// ========== GENERIC PATTERNS ==========
|
||||
|
||||
// Any language: index files in API folders
|
||||
if (p.includes('/api/') && (
|
||||
p.endsWith('/index.ts') || p.endsWith('/index.js') ||
|
||||
p.endsWith('/index.ts') || p.endsWith('/index.js') ||
|
||||
p.endsWith('/__init__.py')
|
||||
)) {
|
||||
return { framework: 'api', entryPointMultiplier: 1.8, reason: 'api-index' };
|
||||
}
|
||||
|
||||
|
||||
// No framework detected - return null for graceful fallback (1.0 multiplier)
|
||||
return null;
|
||||
}
|
||||
|
|
@ -306,4 +353,9 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|||
'actix': ['#[get', '#[post', '#[put', '#[delete'],
|
||||
'axum': ['Router::new'],
|
||||
'rocket': ['#[get', '#[post'],
|
||||
|
||||
// Swift/iOS
|
||||
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
|
||||
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
|
||||
'combine': ['sink', 'assign', 'Publisher', 'Subscriber'],
|
||||
};
|
||||
|
|
|
|||
|
|
@ -396,6 +396,59 @@ export const PHP_QUERIES = `
|
|||
[(name) (qualified_name)] @heritage.trait))) @heritage
|
||||
`;
|
||||
|
||||
// Swift queries - works with tree-sitter-swift
|
||||
export const SWIFT_QUERIES = `
|
||||
; Classes
|
||||
(class_declaration "class" name: (type_identifier) @name) @definition.class
|
||||
|
||||
; Structs
|
||||
(class_declaration "struct" name: (type_identifier) @name) @definition.struct
|
||||
|
||||
; Enums
|
||||
(class_declaration "enum" name: (type_identifier) @name) @definition.enum
|
||||
|
||||
; Extensions (mapped to class — no dedicated label in schema)
|
||||
(class_declaration "extension" name: (user_type (type_identifier) @name)) @definition.class
|
||||
|
||||
; Actors
|
||||
(class_declaration "actor" name: (type_identifier) @name) @definition.class
|
||||
|
||||
; Protocols (mapped to interface)
|
||||
(protocol_declaration name: (type_identifier) @name) @definition.interface
|
||||
|
||||
; Type aliases
|
||||
(typealias_declaration name: (type_identifier) @name) @definition.type
|
||||
|
||||
; Functions (top-level and methods)
|
||||
(function_declaration name: (simple_identifier) @name) @definition.function
|
||||
|
||||
; Protocol method declarations
|
||||
(protocol_function_declaration name: (simple_identifier) @name) @definition.method
|
||||
|
||||
; Initializers
|
||||
(init_declaration) @definition.constructor
|
||||
|
||||
; Properties (stored and computed)
|
||||
(property_declaration (pattern (simple_identifier) @name)) @definition.property
|
||||
|
||||
; Imports
|
||||
(import_declaration (identifier (simple_identifier) @import.source)) @import
|
||||
|
||||
; Calls - direct function calls
|
||||
(call_expression (simple_identifier) @call.name) @call
|
||||
|
||||
; Calls - member/navigation calls (obj.method())
|
||||
(call_expression (navigation_expression (navigation_suffix (simple_identifier) @call.name))) @call
|
||||
|
||||
; Heritage - class/struct/enum inheritance and protocol conformance
|
||||
(class_declaration name: (type_identifier) @heritage.class
|
||||
(inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage
|
||||
|
||||
; Heritage - protocol inheritance
|
||||
(protocol_declaration name: (type_identifier) @heritage.class
|
||||
(inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage
|
||||
`;
|
||||
|
||||
export const LANGUAGE_QUERIES: Record<SupportedLanguages, string> = {
|
||||
[SupportedLanguages.TypeScript]: TYPESCRIPT_QUERIES,
|
||||
[SupportedLanguages.JavaScript]: JAVASCRIPT_QUERIES,
|
||||
|
|
@ -407,5 +460,6 @@ export const LANGUAGE_QUERIES: Record<SupportedLanguages, string> = {
|
|||
[SupportedLanguages.CSharp]: CSHARP_QUERIES,
|
||||
[SupportedLanguages.Rust]: RUST_QUERIES,
|
||||
[SupportedLanguages.PHP]: PHP_QUERIES,
|
||||
[SupportedLanguages.Swift]: SWIFT_QUERIES,
|
||||
};
|
||||
|
||||
|
|
@ -31,6 +31,8 @@ export const getLanguageFromFilename = (filename: string): SupportedLanguages |
|
|||
filename.endsWith('.php5') || filename.endsWith('.php8')) {
|
||||
return SupportedLanguages.PHP;
|
||||
}
|
||||
// Swift
|
||||
if (filename.endsWith('.swift')) return SupportedLanguages.Swift;
|
||||
return null;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const getWasmPath = (language: SupportedLanguages, filePath?: string): string =>
|
|||
[SupportedLanguages.Go]: '/wasm/go/tree-sitter-go.wasm',
|
||||
[SupportedLanguages.Rust]: '/wasm/rust/tree-sitter-rust.wasm',
|
||||
[SupportedLanguages.PHP]: '/wasm/php/tree-sitter-php.wasm',
|
||||
[SupportedLanguages.Swift]: '/wasm/swift/tree-sitter-swift.wasm',
|
||||
};
|
||||
|
||||
return languageFileMap[language];
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ GitNexus supports indexing multiple repositories. Each `gitnexus analyze` regist
|
|||
|
||||
## Supported Languages
|
||||
|
||||
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust
|
||||
TypeScript, JavaScript, Python, Java, C, C++, C#, Go, Rust, PHP, Swift
|
||||
|
||||
## Agent Skills
|
||||
|
||||
|
|
|
|||
49
gitnexus/package-lock.json
generated
49
gitnexus/package-lock.json
generated
|
|
@ -1,12 +1,13 @@
|
|||
{
|
||||
"name": "gitnexus",
|
||||
"version": "1.3.4",
|
||||
"version": "1.3.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "gitnexus",
|
||||
"version": "1.3.4",
|
||||
"version": "1.3.5",
|
||||
"hasInstallScript": true,
|
||||
"license": "PolyForm-Noncommercial-1.0.0",
|
||||
"dependencies": {
|
||||
"@huggingface/transformers": "^3.0.0",
|
||||
|
|
@ -34,6 +35,7 @@
|
|||
"tree-sitter-php": "^0.23.12",
|
||||
"tree-sitter-python": "^0.21.0",
|
||||
"tree-sitter-rust": "^0.21.0",
|
||||
"tree-sitter-swift": "^0.6.0",
|
||||
"tree-sitter-typescript": "^0.21.0",
|
||||
"typescript": "^5.4.5",
|
||||
"uuid": "^13.0.0"
|
||||
|
|
@ -4268,6 +4270,19 @@
|
|||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-cli": {
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cli/-/tree-sitter-cli-0.23.2.tgz",
|
||||
"integrity": "sha512-kPPXprOqREX+C/FgUp2Qpt9jd0vSwn+hOgjzVv/7hapdoWpa+VeWId53rf4oNNd29ikheF12BYtGD/W90feMbA==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tree-sitter": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-cpp": {
|
||||
"version": "0.22.3",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-cpp/-/tree-sitter-cpp-0.22.3.tgz",
|
||||
|
|
@ -4483,6 +4498,36 @@
|
|||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tree-sitter-swift": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-swift/-/tree-sitter-swift-0.6.0.tgz",
|
||||
"integrity": "sha512-9vOJZes4/UFjBr4COHtp6ZHVuZYwfChSQbpneXQog04dAstfx5px3ybVX2cN+ylvLqsvVpmXLpidxxgF2rDQ7A==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"node-addon-api": "^8.0.0",
|
||||
"node-gyp-build": "^4.8.0",
|
||||
"tree-sitter-cli": "^0.23",
|
||||
"which": "2.0.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"tree-sitter": "^0.21.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"tree_sitter": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-swift/node_modules/node-addon-api": {
|
||||
"version": "8.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.6.0.tgz",
|
||||
"integrity": "sha512-gBVjCaqDlRUk0EwoPNKzIr9KkS9041G/q31IBShPs1Xz6UTA+EXdZADbzqAJQrpDRq71CIMnOP5VMut3SL0z5Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^18 || ^20 || >= 21"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-sitter-typescript": {
|
||||
"version": "0.21.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-sitter-typescript/-/tree-sitter-typescript-0.21.2.tgz",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "gitnexus",
|
||||
"version": "1.3.4",
|
||||
"version": "1.3.5",
|
||||
"description": "Graph-powered code intelligence for AI agents. Index any codebase, query via MCP or CLI.",
|
||||
"author": "Abhigyan Patwari",
|
||||
"license": "PolyForm-Noncommercial-1.0.0",
|
||||
|
|
@ -32,13 +32,15 @@
|
|||
"files": [
|
||||
"dist",
|
||||
"hooks",
|
||||
"scripts",
|
||||
"skills",
|
||||
"vendor"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"dev": "tsx watch src/cli/index.ts",
|
||||
"prepare": "npm run build"
|
||||
"prepare": "npm run build",
|
||||
"postinstall": "node scripts/patch-tree-sitter-swift.cjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@huggingface/transformers": "^3.0.0",
|
||||
|
|
@ -64,6 +66,7 @@
|
|||
"tree-sitter-javascript": "^0.21.0",
|
||||
"tree-sitter-kotlin": "^0.3.8",
|
||||
"tree-sitter-php": "^0.23.12",
|
||||
"tree-sitter-swift": "^0.6.0",
|
||||
"tree-sitter-python": "^0.21.0",
|
||||
"tree-sitter-rust": "^0.21.0",
|
||||
"tree-sitter-typescript": "^0.21.0",
|
||||
|
|
|
|||
74
gitnexus/scripts/patch-tree-sitter-swift.cjs
Normal file
74
gitnexus/scripts/patch-tree-sitter-swift.cjs
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* WORKAROUND: tree-sitter-swift@0.6.0 binding.gyp build failure
|
||||
*
|
||||
* Background:
|
||||
* tree-sitter-swift@0.6.0's binding.gyp contains an "actions" array that
|
||||
* invokes `tree-sitter generate` to regenerate parser.c from grammar.js.
|
||||
* This is intended for grammar developers, but the published npm package
|
||||
* already ships pre-generated parser files (parser.c, scanner.c), so the
|
||||
* actions are unnecessary for consumers. Since consumers don't have
|
||||
* tree-sitter-cli installed, the actions always fail during `npm install`.
|
||||
*
|
||||
* Why we can't just upgrade:
|
||||
* tree-sitter-swift@0.7.1 fixes this (removes postinstall, ships prebuilds),
|
||||
* but it requires tree-sitter@^0.22.1. The upstream project pins tree-sitter
|
||||
* to ^0.21.0 and all other grammar packages depend on that version.
|
||||
* Upgrading tree-sitter would be a separate breaking change.
|
||||
*
|
||||
* How this workaround works:
|
||||
* 1. tree-sitter-swift's own postinstall fails (npm warns but continues)
|
||||
* 2. This script runs as gitnexus's postinstall
|
||||
* 3. It removes the "actions" array from binding.gyp
|
||||
* 4. It rebuilds the native binding with the cleaned binding.gyp
|
||||
*
|
||||
* TODO: Remove this script when tree-sitter is upgraded to ^0.22.x,
|
||||
* which allows using tree-sitter-swift@0.7.1+ directly.
|
||||
*/
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const { execSync } = require('child_process');
|
||||
|
||||
const swiftDir = path.join(__dirname, '..', 'node_modules', 'tree-sitter-swift');
|
||||
const bindingPath = path.join(swiftDir, 'binding.gyp');
|
||||
|
||||
try {
|
||||
if (!fs.existsSync(bindingPath)) {
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(bindingPath, 'utf8');
|
||||
let needsRebuild = false;
|
||||
|
||||
if (content.includes('"actions"')) {
|
||||
// Strip Python-style comments (#) before JSON parsing
|
||||
const cleaned = content.replace(/#[^\n]*/g, '');
|
||||
const gyp = JSON.parse(cleaned);
|
||||
|
||||
if (gyp.targets && gyp.targets[0] && gyp.targets[0].actions) {
|
||||
delete gyp.targets[0].actions;
|
||||
fs.writeFileSync(bindingPath, JSON.stringify(gyp, null, 2) + '\n');
|
||||
console.log('[tree-sitter-swift] Patched binding.gyp (removed actions array)');
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if native binding exists
|
||||
const bindingNode = path.join(swiftDir, 'build', 'Release', 'tree_sitter_swift_binding.node');
|
||||
if (!fs.existsSync(bindingNode)) {
|
||||
needsRebuild = true;
|
||||
}
|
||||
|
||||
if (needsRebuild) {
|
||||
console.log('[tree-sitter-swift] Rebuilding native binding...');
|
||||
execSync('npx node-gyp rebuild', {
|
||||
cwd: swiftDir,
|
||||
stdio: 'pipe',
|
||||
timeout: 120000,
|
||||
});
|
||||
console.log('[tree-sitter-swift] Native binding built successfully');
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[tree-sitter-swift] Could not build native binding:', err.message);
|
||||
console.warn('[tree-sitter-swift] You may need to manually run: cd node_modules/tree-sitter-swift && npx node-gyp rebuild');
|
||||
}
|
||||
|
|
@ -32,12 +32,15 @@ import { augmentCommand } from './augment.js';
|
|||
import { wikiCommand } from './wiki.js';
|
||||
import { queryCommand, contextCommand, impactCommand, cypherCommand } from './tool.js';
|
||||
import { evalServerCommand } from './eval-server.js';
|
||||
import { createRequire } from 'node:module';
|
||||
const _require = createRequire(import.meta.url);
|
||||
const pkg = _require('../../package.json');
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name('gitnexus')
|
||||
.description('GitNexus local CLI and MCP server')
|
||||
.version('1.2.0');
|
||||
.version(pkg.version);
|
||||
|
||||
program
|
||||
.command('setup')
|
||||
|
|
|
|||
|
|
@ -11,5 +11,5 @@ export enum SupportedLanguages {
|
|||
PHP = 'php',
|
||||
Kotlin = 'kotlin',
|
||||
// Ruby = 'ruby',
|
||||
// Swift = 'swift',
|
||||
Swift = 'swift',
|
||||
}
|
||||
|
|
@ -40,6 +40,9 @@ const FUNCTION_NODE_TYPES = new Set([
|
|||
// Kotlin (function_declaration already included above via JS/TS)
|
||||
'anonymous_function',
|
||||
'lambda_literal',
|
||||
// Swift
|
||||
'init_declaration',
|
||||
'deinit_declaration',
|
||||
]);
|
||||
|
||||
/**
|
||||
|
|
@ -60,7 +63,13 @@ const findEnclosingFunction = (
|
|||
let label = 'Function';
|
||||
|
||||
// Different node types have different name locations
|
||||
if (current.type === 'function_declaration' ||
|
||||
// Swift init/deinit — handle before generic cases (more specific)
|
||||
if (current.type === 'init_declaration' || current.type === 'deinit_declaration') {
|
||||
const funcName = current.type === 'init_declaration' ? 'init' : 'deinit';
|
||||
return generateId('Constructor', `${filePath}:${funcName}`);
|
||||
}
|
||||
|
||||
if (current.type === 'function_declaration' ||
|
||||
current.type === 'function_definition' ||
|
||||
current.type === 'async_function_declaration' ||
|
||||
current.type === 'generator_function_declaration' ||
|
||||
|
|
@ -355,6 +364,37 @@ const BUILT_IN_NAMES = new Set([
|
|||
'stateIn', 'shareIn', 'launchIn',
|
||||
// Kotlin infix stdlib functions
|
||||
'to', 'until', 'downTo', 'step',
|
||||
// Swift/iOS built-ins and standard library
|
||||
'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
|
||||
'assert', 'assertionFailure', 'NSLog',
|
||||
'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
|
||||
'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
|
||||
'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
|
||||
'type', 'MemoryLayout',
|
||||
// Swift collection/string methods (common noise)
|
||||
'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
|
||||
'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
|
||||
'sorted', 'reversed', 'enumerated', 'joined', 'split',
|
||||
'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
|
||||
'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
|
||||
// UIKit/Foundation common methods (noise in call graph)
|
||||
'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
|
||||
'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
|
||||
'addTarget', 'removeTarget', 'addGestureRecognizer',
|
||||
'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
|
||||
'NSLocalizedString', 'Bundle',
|
||||
'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
|
||||
'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
|
||||
'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
|
||||
'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
|
||||
'performSegue', 'prepare',
|
||||
// GCD / async
|
||||
'DispatchQueue', 'async', 'sync', 'asyncAfter',
|
||||
'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
|
||||
// Combine
|
||||
'sink', 'store', 'assign', 'receive', 'subscribe',
|
||||
// Notification / KVO
|
||||
'addObserver', 'removeObserver', 'post', 'NotificationCenter',
|
||||
]);
|
||||
|
||||
const isBuiltInOrNoise = (name: string): boolean => BUILT_IN_NAMES.has(name);
|
||||
|
|
|
|||
|
|
@ -103,6 +103,26 @@ const ENTRY_POINT_PATTERNS: Record<string, RegExp[]> = {
|
|||
/^Start$/, // Start methods
|
||||
],
|
||||
|
||||
// Swift / iOS
|
||||
'swift': [
|
||||
/^viewDidLoad$/, // UIKit lifecycle
|
||||
/^viewWillAppear$/, // UIKit lifecycle
|
||||
/^viewDidAppear$/, // UIKit lifecycle
|
||||
/^viewWillDisappear$/, // UIKit lifecycle
|
||||
/^viewDidDisappear$/, // UIKit lifecycle
|
||||
/^application\(/, // AppDelegate methods
|
||||
/^scene\(/, // SceneDelegate methods
|
||||
/^body$/, // SwiftUI View.body
|
||||
/Coordinator$/, // Coordinator pattern
|
||||
/^sceneDidBecomeActive$/, // SceneDelegate lifecycle
|
||||
/^sceneWillResignActive$/, // SceneDelegate lifecycle
|
||||
/^didFinishLaunchingWithOptions$/, // AppDelegate
|
||||
/ViewController$/, // ViewController classes
|
||||
/^configure[A-Z]/, // Configuration methods
|
||||
/^setup[A-Z]/, // Setup methods
|
||||
/^makeBody$/, // SwiftUI ViewModifier
|
||||
],
|
||||
|
||||
// PHP / Laravel
|
||||
'php': [
|
||||
/Controller$/, // UserController (class name convention)
|
||||
|
|
@ -271,6 +291,10 @@ export function isTestFile(filePath: string): boolean {
|
|||
p.includes('/src/test/') ||
|
||||
// Rust test patterns (inline tests are different, but test files)
|
||||
p.includes('/tests/') ||
|
||||
// Swift/iOS test patterns
|
||||
p.endsWith('tests.swift') ||
|
||||
p.endsWith('test.swift') ||
|
||||
p.includes('uitests/') ||
|
||||
// C# test patterns
|
||||
p.includes('.tests/') ||
|
||||
p.includes('tests.cs') ||
|
||||
|
|
|
|||
|
|
@ -302,6 +302,53 @@ export function detectFrameworkFromPath(filePath: string): FrameworkHint | null
|
|||
return { framework: 'laravel', entryPointMultiplier: 1.5, reason: 'laravel-repository' };
|
||||
}
|
||||
|
||||
// ========== SWIFT / iOS ==========
|
||||
|
||||
// iOS App entry points (highest priority)
|
||||
if (p.endsWith('/appdelegate.swift') || p.endsWith('/scenedelegate.swift') || p.endsWith('/app.swift')) {
|
||||
return { framework: 'ios', entryPointMultiplier: 3.0, reason: 'ios-app-entry' };
|
||||
}
|
||||
|
||||
// SwiftUI App entry (@main)
|
||||
if (p.endsWith('app.swift') && p.includes('/sources/')) {
|
||||
return { framework: 'swiftui', entryPointMultiplier: 3.0, reason: 'swiftui-app' };
|
||||
}
|
||||
|
||||
// UIKit ViewControllers (high priority - screen entry points)
|
||||
if ((p.includes('/viewcontrollers/') || p.includes('/controllers/') || p.includes('/screens/')) && p.endsWith('.swift')) {
|
||||
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller' };
|
||||
}
|
||||
|
||||
// ViewController by filename convention
|
||||
if (p.endsWith('viewcontroller.swift') || p.endsWith('vc.swift')) {
|
||||
return { framework: 'uikit', entryPointMultiplier: 2.5, reason: 'uikit-viewcontroller-file' };
|
||||
}
|
||||
|
||||
// Coordinator pattern (navigation entry points)
|
||||
if (p.includes('/coordinators/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator' };
|
||||
}
|
||||
|
||||
// Coordinator by filename
|
||||
if (p.endsWith('coordinator.swift')) {
|
||||
return { framework: 'ios-coordinator', entryPointMultiplier: 2.5, reason: 'ios-coordinator-file' };
|
||||
}
|
||||
|
||||
// SwiftUI Views (moderate - reusable components)
|
||||
if ((p.includes('/views/') || p.includes('/scenes/')) && p.endsWith('.swift')) {
|
||||
return { framework: 'swiftui', entryPointMultiplier: 1.8, reason: 'swiftui-view' };
|
||||
}
|
||||
|
||||
// Service layer
|
||||
if (p.includes('/services/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-service', entryPointMultiplier: 1.8, reason: 'ios-service' };
|
||||
}
|
||||
|
||||
// Router / navigation
|
||||
if (p.includes('/router/') && p.endsWith('.swift')) {
|
||||
return { framework: 'ios-router', entryPointMultiplier: 2.0, reason: 'ios-router' };
|
||||
}
|
||||
|
||||
// ========== GENERIC PATTERNS ==========
|
||||
|
||||
// Any language: index files in API folders
|
||||
|
|
@ -351,6 +398,11 @@ export const FRAMEWORK_AST_PATTERNS = {
|
|||
'actix': ['#[get', '#[post', '#[put', '#[delete'],
|
||||
'axum': ['Router::new'],
|
||||
'rocket': ['#[get', '#[post'],
|
||||
|
||||
// Swift/iOS
|
||||
'uikit': ['viewDidLoad', 'viewWillAppear', 'viewDidAppear', 'UIViewController'],
|
||||
'swiftui': ['@main', 'WindowGroup', 'ContentView', '@StateObject', '@ObservedObject'],
|
||||
'combine': ['sink', 'assign', 'Publisher', 'Subscriber'],
|
||||
};
|
||||
|
||||
interface AstFrameworkPatternConfig {
|
||||
|
|
|
|||
|
|
@ -153,6 +153,42 @@ async function loadComposerConfig(repoRoot: string): Promise<ComposerConfig | nu
|
|||
}
|
||||
}
|
||||
|
||||
/** Swift Package Manager module config */
|
||||
interface SwiftPackageConfig {
|
||||
/** Map of target name -> source directory path (e.g., "SiuperModel" -> "Package/Sources/SiuperModel") */
|
||||
targets: Map<string, string>;
|
||||
}
|
||||
|
||||
async function loadSwiftPackageConfig(repoRoot: string): Promise<SwiftPackageConfig | null> {
|
||||
// Swift imports are module-name based (e.g., `import SiuperModel`)
|
||||
// SPM convention: Sources/<TargetName>/ or Package/Sources/<TargetName>/
|
||||
// We scan for these directories to build a target map
|
||||
const targets = new Map<string, string>();
|
||||
|
||||
const sourceDirs = ['Sources', 'Package/Sources', 'src'];
|
||||
for (const sourceDir of sourceDirs) {
|
||||
try {
|
||||
const fullPath = path.join(repoRoot, sourceDir);
|
||||
const entries = await fs.readdir(fullPath, { withFileTypes: true });
|
||||
for (const entry of entries) {
|
||||
if (entry.isDirectory()) {
|
||||
targets.set(entry.name, sourceDir + '/' + entry.name);
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Directory doesn't exist
|
||||
}
|
||||
}
|
||||
|
||||
if (targets.size > 0) {
|
||||
if (isDev) {
|
||||
console.log(`📦 Loaded ${targets.size} Swift package targets`);
|
||||
}
|
||||
return { targets };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// IMPORT PATH RESOLUTION
|
||||
// ============================================================================
|
||||
|
|
@ -178,6 +214,8 @@ const EXTENSIONS = [
|
|||
'.rs', '/mod.rs',
|
||||
// PHP
|
||||
'.php', '.phtml',
|
||||
// Swift
|
||||
'.swift',
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
@ -710,6 +748,7 @@ export const processImports = async (
|
|||
const tsconfigPaths = await loadTsconfigPaths(effectiveRoot);
|
||||
const goModule = await loadGoModulePath(effectiveRoot);
|
||||
const composerConfig = await loadComposerConfig(effectiveRoot);
|
||||
const swiftPackageConfig = await loadSwiftPackageConfig(effectiveRoot);
|
||||
|
||||
// Helper: add an IMPORTS edge + update import map
|
||||
const addImportEdge = (filePath: string, resolvedPath: string) => {
|
||||
|
|
@ -859,6 +898,25 @@ export const processImports = async (
|
|||
return;
|
||||
}
|
||||
|
||||
// ---- Swift: handle module imports ----
|
||||
if (language === SupportedLanguages.Swift && swiftPackageConfig) {
|
||||
// Swift imports are module names: `import SiuperModel`
|
||||
// Resolve to the module's source directory → all .swift files in it
|
||||
const targetDir = swiftPackageConfig.targets.get(rawImportPath);
|
||||
if (targetDir) {
|
||||
// Find all .swift files in this target directory
|
||||
const dirPrefix = targetDir + '/';
|
||||
for (const filePath2 of allFileList) {
|
||||
if (filePath2.startsWith(dirPrefix) && filePath2.endsWith('.swift')) {
|
||||
addImportEdge(file.path, filePath2);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// External framework (Foundation, UIKit, etc.) — skip
|
||||
return;
|
||||
}
|
||||
|
||||
// ---- Standard single-file resolution ----
|
||||
const resolvedPath = resolveImportPath(
|
||||
file.path,
|
||||
|
|
@ -909,6 +967,7 @@ export const processImportsFromExtracted = async (
|
|||
const tsconfigPaths = await loadTsconfigPaths(effectiveRoot);
|
||||
const goModule = await loadGoModulePath(effectiveRoot);
|
||||
const composerConfig = await loadComposerConfig(effectiveRoot);
|
||||
const swiftPackageConfig = await loadSwiftPackageConfig(effectiveRoot);
|
||||
|
||||
const addImportEdge = (filePath: string, resolvedPath: string) => {
|
||||
const sourceId = generateId('File', filePath);
|
||||
|
|
@ -1032,6 +1091,20 @@ export const processImportsFromExtracted = async (
|
|||
continue;
|
||||
}
|
||||
|
||||
// Swift: handle module imports
|
||||
if (language === SupportedLanguages.Swift && swiftPackageConfig) {
|
||||
const targetDir = swiftPackageConfig.targets.get(rawImportPath);
|
||||
if (targetDir) {
|
||||
const dirPrefix = targetDir + '/';
|
||||
for (const fp of allFileList) {
|
||||
if (fp.startsWith(dirPrefix) && fp.endsWith('.swift')) {
|
||||
addImportEdge(filePath, fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// Standard resolution (has its own internal cache)
|
||||
const resolvedPath = resolveImportPath(
|
||||
filePath,
|
||||
|
|
|
|||
|
|
@ -164,6 +164,17 @@ const isNodeExported = (node: any, name: string, language: string): boolean => {
|
|||
// No visibility modifier = public (Kotlin default)
|
||||
return true;
|
||||
|
||||
// Swift: Check for 'public' or 'open' access modifiers
|
||||
case 'swift':
|
||||
while (current) {
|
||||
if (current.type === 'modifiers' || current.type === 'visibility_modifier') {
|
||||
const text = current.text || '';
|
||||
if (text.includes('public') || text.includes('open')) return true;
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
return false;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -476,6 +476,59 @@ export const KOTLIN_QUERIES = `
|
|||
(user_type (type_identifier) @heritage.extends)))) @heritage
|
||||
`;
|
||||
|
||||
// Swift queries - works with tree-sitter-swift
|
||||
export const SWIFT_QUERIES = `
|
||||
; Classes
|
||||
(class_declaration "class" name: (type_identifier) @name) @definition.class
|
||||
|
||||
; Structs
|
||||
(class_declaration "struct" name: (type_identifier) @name) @definition.struct
|
||||
|
||||
; Enums
|
||||
(class_declaration "enum" name: (type_identifier) @name) @definition.enum
|
||||
|
||||
; Extensions (mapped to class — no dedicated label in schema)
|
||||
(class_declaration "extension" name: (user_type (type_identifier) @name)) @definition.class
|
||||
|
||||
; Actors
|
||||
(class_declaration "actor" name: (type_identifier) @name) @definition.class
|
||||
|
||||
; Protocols (mapped to interface)
|
||||
(protocol_declaration name: (type_identifier) @name) @definition.interface
|
||||
|
||||
; Type aliases
|
||||
(typealias_declaration name: (type_identifier) @name) @definition.type
|
||||
|
||||
; Functions (top-level and methods)
|
||||
(function_declaration name: (simple_identifier) @name) @definition.function
|
||||
|
||||
; Protocol method declarations
|
||||
(protocol_function_declaration name: (simple_identifier) @name) @definition.method
|
||||
|
||||
; Initializers
|
||||
(init_declaration) @definition.constructor
|
||||
|
||||
; Properties (stored and computed)
|
||||
(property_declaration (pattern (simple_identifier) @name)) @definition.property
|
||||
|
||||
; Imports
|
||||
(import_declaration (identifier (simple_identifier) @import.source)) @import
|
||||
|
||||
; Calls - direct function calls
|
||||
(call_expression (simple_identifier) @call.name) @call
|
||||
|
||||
; Calls - member/navigation calls (obj.method())
|
||||
(call_expression (navigation_expression (navigation_suffix (simple_identifier) @call.name))) @call
|
||||
|
||||
; Heritage - class/struct/enum inheritance and protocol conformance
|
||||
(class_declaration name: (type_identifier) @heritage.class
|
||||
(inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage
|
||||
|
||||
; Heritage - protocol inheritance
|
||||
(protocol_declaration name: (type_identifier) @heritage.class
|
||||
(inheritance_specifier inherits_from: (user_type (type_identifier) @heritage.extends))) @heritage
|
||||
`;
|
||||
|
||||
export const LANGUAGE_QUERIES: Record<SupportedLanguages, string> = {
|
||||
[SupportedLanguages.TypeScript]: TYPESCRIPT_QUERIES,
|
||||
[SupportedLanguages.JavaScript]: JAVASCRIPT_QUERIES,
|
||||
|
|
@ -488,5 +541,6 @@ export const LANGUAGE_QUERIES: Record<SupportedLanguages, string> = {
|
|||
[SupportedLanguages.Rust]: RUST_QUERIES,
|
||||
[SupportedLanguages.PHP]: PHP_QUERIES,
|
||||
[SupportedLanguages.Kotlin]: KOTLIN_QUERIES,
|
||||
[SupportedLanguages.Swift]: SWIFT_QUERIES,
|
||||
};
|
||||
|
||||
|
|
@ -56,6 +56,7 @@ export const getLanguageFromFilename = (filename: string): SupportedLanguages |
|
|||
filename.endsWith('.php5') || filename.endsWith('.php8')) {
|
||||
return SupportedLanguages.PHP;
|
||||
}
|
||||
if (filename.endsWith('.swift')) return SupportedLanguages.Swift;
|
||||
return null;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import Go from 'tree-sitter-go';
|
|||
import Rust from 'tree-sitter-rust';
|
||||
import PHP from 'tree-sitter-php';
|
||||
import Kotlin from 'tree-sitter-kotlin';
|
||||
import Swift from 'tree-sitter-swift';
|
||||
import { SupportedLanguages } from '../../../config/supported-languages.js';
|
||||
import { LANGUAGE_QUERIES } from '../tree-sitter-queries.js';
|
||||
import { findSiblingChild, getLanguageFromFilename } from '../utils.js';
|
||||
|
|
@ -108,6 +109,7 @@ const languageMap: Record<string, any> = {
|
|||
[SupportedLanguages.Rust]: Rust,
|
||||
[SupportedLanguages.PHP]: PHP.php_only,
|
||||
[SupportedLanguages.Kotlin]: Kotlin,
|
||||
[SupportedLanguages.Swift]: Swift,
|
||||
};
|
||||
|
||||
const setLanguage = (language: SupportedLanguages, filePath: string): void => {
|
||||
|
|
@ -193,6 +195,16 @@ const isNodeExported = (node: any, name: string, language: string): boolean => {
|
|||
case 'cpp':
|
||||
return false;
|
||||
|
||||
case 'swift':
|
||||
while (current) {
|
||||
if (current.type === 'modifiers' || current.type === 'visibility_modifier') {
|
||||
const text = current.text || '';
|
||||
if (text.includes('public') || text.includes('open')) return true;
|
||||
}
|
||||
current = current.parent;
|
||||
}
|
||||
return false;
|
||||
|
||||
case 'php':
|
||||
// Top-level classes/interfaces/traits are always accessible
|
||||
// Methods/properties are exported only if they have 'public' modifier
|
||||
|
|
@ -246,6 +258,7 @@ const FUNCTION_NODE_TYPES = new Set([
|
|||
'anonymous_function_creation_expression', // PHP anonymous functions
|
||||
// Kotlin (function_declaration already included above via JS/TS)
|
||||
'anonymous_function', 'lambda_literal',
|
||||
'init_declaration', 'deinit_declaration', // Swift initializers/deinitializers
|
||||
]);
|
||||
|
||||
/** Walk up AST to find enclosing function, return its generateId or null for top-level */
|
||||
|
|
@ -256,6 +269,12 @@ const findEnclosingFunctionId = (node: any, filePath: string): string | null =>
|
|||
let funcName: string | null = null;
|
||||
let label = 'Function';
|
||||
|
||||
if (current.type === 'init_declaration' || current.type === 'deinit_declaration') {
|
||||
const funcName = current.type === 'init_declaration' ? 'init' : 'deinit';
|
||||
const label = 'Constructor';
|
||||
return generateId(label, `${filePath}:${funcName}`);
|
||||
}
|
||||
|
||||
if (['function_declaration', 'function_definition', 'async_function_declaration',
|
||||
'generator_function_declaration', 'function_item'].includes(current.type)) {
|
||||
const nameNode = current.childForFieldName?.('name') ||
|
||||
|
|
@ -376,6 +395,37 @@ const BUILT_INS = new Set([
|
|||
'stateIn', 'shareIn', 'launchIn',
|
||||
// Kotlin infix stdlib functions
|
||||
'to', 'until', 'downTo', 'step',
|
||||
// Swift/iOS built-ins and standard library
|
||||
'print', 'debugPrint', 'dump', 'fatalError', 'precondition', 'preconditionFailure',
|
||||
'assert', 'assertionFailure', 'NSLog',
|
||||
'abs', 'min', 'max', 'zip', 'stride', 'sequence', 'repeatElement',
|
||||
'swap', 'withUnsafePointer', 'withUnsafeMutablePointer', 'withUnsafeBytes',
|
||||
'autoreleasepool', 'unsafeBitCast', 'unsafeDowncast', 'numericCast',
|
||||
'type', 'MemoryLayout',
|
||||
// Swift collection/string methods (common noise)
|
||||
'map', 'flatMap', 'compactMap', 'filter', 'reduce', 'forEach', 'contains',
|
||||
'first', 'last', 'prefix', 'suffix', 'dropFirst', 'dropLast',
|
||||
'sorted', 'reversed', 'enumerated', 'joined', 'split',
|
||||
'append', 'insert', 'remove', 'removeAll', 'removeFirst', 'removeLast',
|
||||
'isEmpty', 'count', 'index', 'startIndex', 'endIndex',
|
||||
// UIKit/Foundation common methods (noise in call graph)
|
||||
'addSubview', 'removeFromSuperview', 'layoutSubviews', 'setNeedsLayout',
|
||||
'layoutIfNeeded', 'setNeedsDisplay', 'invalidateIntrinsicContentSize',
|
||||
'addTarget', 'removeTarget', 'addGestureRecognizer',
|
||||
'addConstraint', 'addConstraints', 'removeConstraint', 'removeConstraints',
|
||||
'NSLocalizedString', 'Bundle',
|
||||
'reloadData', 'reloadSections', 'reloadRows', 'performBatchUpdates',
|
||||
'register', 'dequeueReusableCell', 'dequeueReusableSupplementaryView',
|
||||
'beginUpdates', 'endUpdates', 'insertRows', 'deleteRows', 'insertSections', 'deleteSections',
|
||||
'present', 'dismiss', 'pushViewController', 'popViewController', 'popToRootViewController',
|
||||
'performSegue', 'prepare',
|
||||
// GCD / async
|
||||
'DispatchQueue', 'async', 'sync', 'asyncAfter',
|
||||
'Task', 'withCheckedContinuation', 'withCheckedThrowingContinuation',
|
||||
// Combine
|
||||
'sink', 'store', 'assign', 'receive', 'subscribe',
|
||||
// Notification / KVO
|
||||
'addObserver', 'removeObserver', 'post', 'NotificationCenter',
|
||||
]);
|
||||
|
||||
// ============================================================================
|
||||
|
|
|
|||
|
|
@ -242,6 +242,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|||
FROM Function TO \`Const\`,
|
||||
FROM Function TO \`Typedef\`,
|
||||
FROM Function TO \`Union\`,
|
||||
FROM Function TO \`Property\`,
|
||||
FROM Class TO Method,
|
||||
FROM Class TO Function,
|
||||
FROM Class TO Class,
|
||||
|
|
@ -301,7 +302,11 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|||
FROM \`Struct\` TO \`Enum\`,
|
||||
FROM \`Struct\` TO Function,
|
||||
FROM \`Struct\` TO Method,
|
||||
FROM \`Struct\` TO Interface,
|
||||
FROM \`Enum\` TO \`Enum\`,
|
||||
FROM \`Enum\` TO Community,
|
||||
FROM \`Enum\` TO Class,
|
||||
FROM \`Enum\` TO Interface,
|
||||
FROM \`Macro\` TO Community,
|
||||
FROM \`Macro\` TO Function,
|
||||
FROM \`Macro\` TO Method,
|
||||
|
|
@ -318,6 +323,7 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|||
FROM \`Impl\` TO \`Impl\`,
|
||||
FROM \`TypeAlias\` TO Community,
|
||||
FROM \`TypeAlias\` TO \`Trait\`,
|
||||
FROM \`TypeAlias\` TO Class,
|
||||
FROM \`Const\` TO Community,
|
||||
FROM \`Static\` TO Community,
|
||||
FROM \`Property\` TO Community,
|
||||
|
|
@ -339,6 +345,8 @@ CREATE REL TABLE ${REL_TABLE_NAME} (
|
|||
FROM \`Constructor\` TO \`Impl\`,
|
||||
FROM \`Constructor\` TO \`Namespace\`,
|
||||
FROM \`Constructor\` TO \`Module\`,
|
||||
FROM \`Constructor\` TO \`Property\`,
|
||||
FROM \`Constructor\` TO \`Typedef\`,
|
||||
FROM \`Template\` TO Community,
|
||||
FROM \`Module\` TO Community,
|
||||
FROM Function TO Process,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import Go from 'tree-sitter-go';
|
|||
import Rust from 'tree-sitter-rust';
|
||||
import PHP from 'tree-sitter-php';
|
||||
import Kotlin from 'tree-sitter-kotlin';
|
||||
import Swift from 'tree-sitter-swift';
|
||||
import { SupportedLanguages } from '../../config/supported-languages.js';
|
||||
|
||||
let parser: Parser | null = null;
|
||||
|
|
@ -27,6 +28,7 @@ const languageMap: Record<string, any> = {
|
|||
[SupportedLanguages.Rust]: Rust,
|
||||
[SupportedLanguages.PHP]: PHP.php_only,
|
||||
[SupportedLanguages.Kotlin]: Kotlin,
|
||||
[SupportedLanguages.Swift]: Swift,
|
||||
};
|
||||
|
||||
export const loadParser = async (): Promise<Parser> => {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue