diff --git a/README.md b/README.md
index 2cf84826f..eb04cdde6 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,29 @@
# GitNexus
-
+
-**Building git for agent context.**
+
+
+
+
+
Join the official Discord to discuss ideas, issues etc!
+
+
+
+
+
+
+
+
+
+
+
+
+
+**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
diff --git a/gitnexus-web/public/wasm/swift/tree-sitter-swift.wasm b/gitnexus-web/public/wasm/swift/tree-sitter-swift.wasm
new file mode 100755
index 000000000..87282f216
Binary files /dev/null and b/gitnexus-web/public/wasm/swift/tree-sitter-swift.wasm differ
diff --git a/gitnexus-web/src/config/supported-languages.ts b/gitnexus-web/src/config/supported-languages.ts
index a9bcd8248..5df70ed83 100644
--- a/gitnexus-web/src/config/supported-languages.ts
+++ b/gitnexus-web/src/config/supported-languages.ts
@@ -10,5 +10,5 @@ export enum SupportedLanguages {
Rust = 'rust',
PHP = 'php',
// Ruby = 'ruby',
- // Swift = 'swift',
+ Swift = 'swift',
}
\ No newline at end of file
diff --git a/gitnexus-web/src/core/ingestion/entry-point-scoring.ts b/gitnexus-web/src/core/ingestion/entry-point-scoring.ts
index 9285e407d..89645769e 100644
--- a/gitnexus-web/src/core/ingestion/entry-point-scoring.ts
+++ b/gitnexus-web/src/core/ingestion/entry-point-scoring.ts
@@ -103,6 +103,26 @@ const ENTRY_POINT_PATTERNS: Record = {
/^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') ||
diff --git a/gitnexus-web/src/core/ingestion/framework-detection.ts b/gitnexus-web/src/core/ingestion/framework-detection.ts
index 4aec27f7c..67f773574 100644
--- a/gitnexus-web/src/core/ingestion/framework-detection.ts
+++ b/gitnexus-web/src/core/ingestion/framework-detection.ts
@@ -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'],
};
diff --git a/gitnexus-web/src/core/ingestion/tree-sitter-queries.ts b/gitnexus-web/src/core/ingestion/tree-sitter-queries.ts
index 5cb2d46ff..3ba476ba3 100644
--- a/gitnexus-web/src/core/ingestion/tree-sitter-queries.ts
+++ b/gitnexus-web/src/core/ingestion/tree-sitter-queries.ts
@@ -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.TypeScript]: TYPESCRIPT_QUERIES,
[SupportedLanguages.JavaScript]: JAVASCRIPT_QUERIES,
@@ -407,5 +460,6 @@ export const LANGUAGE_QUERIES: Record = {
[SupportedLanguages.CSharp]: CSHARP_QUERIES,
[SupportedLanguages.Rust]: RUST_QUERIES,
[SupportedLanguages.PHP]: PHP_QUERIES,
+ [SupportedLanguages.Swift]: SWIFT_QUERIES,
};
\ No newline at end of file
diff --git a/gitnexus-web/src/core/ingestion/utils.ts b/gitnexus-web/src/core/ingestion/utils.ts
index c53fa4248..c7479aaa6 100644
--- a/gitnexus-web/src/core/ingestion/utils.ts
+++ b/gitnexus-web/src/core/ingestion/utils.ts
@@ -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;
};
diff --git a/gitnexus-web/src/core/tree-sitter/parser-loader.ts b/gitnexus-web/src/core/tree-sitter/parser-loader.ts
index e38e8d5d2..e434874c4 100644
--- a/gitnexus-web/src/core/tree-sitter/parser-loader.ts
+++ b/gitnexus-web/src/core/tree-sitter/parser-loader.ts
@@ -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];
diff --git a/gitnexus/README.md b/gitnexus/README.md
index e6aa62940..d66f94fe2 100644
--- a/gitnexus/README.md
+++ b/gitnexus/README.md
@@ -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
diff --git a/gitnexus/package-lock.json b/gitnexus/package-lock.json
index b57c2208f..a229f0564 100644
--- a/gitnexus/package-lock.json
+++ b/gitnexus/package-lock.json
@@ -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",
diff --git a/gitnexus/package.json b/gitnexus/package.json
index 0845899e2..5b11308ae 100644
--- a/gitnexus/package.json
+++ b/gitnexus/package.json
@@ -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",
diff --git a/gitnexus/scripts/patch-tree-sitter-swift.cjs b/gitnexus/scripts/patch-tree-sitter-swift.cjs
new file mode 100644
index 000000000..3c3dcad50
--- /dev/null
+++ b/gitnexus/scripts/patch-tree-sitter-swift.cjs
@@ -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');
+}
diff --git a/gitnexus/src/cli/index.ts b/gitnexus/src/cli/index.ts
index f86aac4e5..e7b7bd194 100644
--- a/gitnexus/src/cli/index.ts
+++ b/gitnexus/src/cli/index.ts
@@ -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')
diff --git a/gitnexus/src/config/supported-languages.ts b/gitnexus/src/config/supported-languages.ts
index 7f72bc112..9d67eaf05 100644
--- a/gitnexus/src/config/supported-languages.ts
+++ b/gitnexus/src/config/supported-languages.ts
@@ -11,5 +11,5 @@ export enum SupportedLanguages {
PHP = 'php',
Kotlin = 'kotlin',
// Ruby = 'ruby',
- // Swift = 'swift',
+ Swift = 'swift',
}
\ No newline at end of file
diff --git a/gitnexus/src/core/ingestion/call-processor.ts b/gitnexus/src/core/ingestion/call-processor.ts
index e82236e51..c5fc3f8df 100644
--- a/gitnexus/src/core/ingestion/call-processor.ts
+++ b/gitnexus/src/core/ingestion/call-processor.ts
@@ -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);
diff --git a/gitnexus/src/core/ingestion/entry-point-scoring.ts b/gitnexus/src/core/ingestion/entry-point-scoring.ts
index ed328cc13..b7b9d457e 100644
--- a/gitnexus/src/core/ingestion/entry-point-scoring.ts
+++ b/gitnexus/src/core/ingestion/entry-point-scoring.ts
@@ -103,6 +103,26 @@ const ENTRY_POINT_PATTERNS: Record = {
/^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') ||
diff --git a/gitnexus/src/core/ingestion/framework-detection.ts b/gitnexus/src/core/ingestion/framework-detection.ts
index c3ab00bca..aecff1126 100644
--- a/gitnexus/src/core/ingestion/framework-detection.ts
+++ b/gitnexus/src/core/ingestion/framework-detection.ts
@@ -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 {
diff --git a/gitnexus/src/core/ingestion/import-processor.ts b/gitnexus/src/core/ingestion/import-processor.ts
index e3e4f74c0..990f968af 100644
--- a/gitnexus/src/core/ingestion/import-processor.ts
+++ b/gitnexus/src/core/ingestion/import-processor.ts
@@ -153,6 +153,42 @@ async function loadComposerConfig(repoRoot: string): Promise source directory path (e.g., "SiuperModel" -> "Package/Sources/SiuperModel") */
+ targets: Map;
+}
+
+async function loadSwiftPackageConfig(repoRoot: string): Promise {
+ // Swift imports are module-name based (e.g., `import SiuperModel`)
+ // SPM convention: Sources// or Package/Sources//
+ // We scan for these directories to build a target map
+ const targets = new Map();
+
+ 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,
diff --git a/gitnexus/src/core/ingestion/parsing-processor.ts b/gitnexus/src/core/ingestion/parsing-processor.ts
index 7d753aae5..8c60802c2 100644
--- a/gitnexus/src/core/ingestion/parsing-processor.ts
+++ b/gitnexus/src/core/ingestion/parsing-processor.ts
@@ -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;
}
diff --git a/gitnexus/src/core/ingestion/tree-sitter-queries.ts b/gitnexus/src/core/ingestion/tree-sitter-queries.ts
index b98a1d653..7eeeb73e0 100644
--- a/gitnexus/src/core/ingestion/tree-sitter-queries.ts
+++ b/gitnexus/src/core/ingestion/tree-sitter-queries.ts
@@ -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.TypeScript]: TYPESCRIPT_QUERIES,
[SupportedLanguages.JavaScript]: JAVASCRIPT_QUERIES,
@@ -488,5 +541,6 @@ export const LANGUAGE_QUERIES: Record = {
[SupportedLanguages.Rust]: RUST_QUERIES,
[SupportedLanguages.PHP]: PHP_QUERIES,
[SupportedLanguages.Kotlin]: KOTLIN_QUERIES,
+ [SupportedLanguages.Swift]: SWIFT_QUERIES,
};
\ No newline at end of file
diff --git a/gitnexus/src/core/ingestion/utils.ts b/gitnexus/src/core/ingestion/utils.ts
index 927e32e60..47fa8cbe4 100644
--- a/gitnexus/src/core/ingestion/utils.ts
+++ b/gitnexus/src/core/ingestion/utils.ts
@@ -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;
};
diff --git a/gitnexus/src/core/ingestion/workers/parse-worker.ts b/gitnexus/src/core/ingestion/workers/parse-worker.ts
index cd9c03eaf..d31c980fe 100644
--- a/gitnexus/src/core/ingestion/workers/parse-worker.ts
+++ b/gitnexus/src/core/ingestion/workers/parse-worker.ts
@@ -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 = {
[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',
]);
// ============================================================================
diff --git a/gitnexus/src/core/kuzu/schema.ts b/gitnexus/src/core/kuzu/schema.ts
index 5d634cba8..9989bd6c1 100644
--- a/gitnexus/src/core/kuzu/schema.ts
+++ b/gitnexus/src/core/kuzu/schema.ts
@@ -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,
diff --git a/gitnexus/src/core/tree-sitter/parser-loader.ts b/gitnexus/src/core/tree-sitter/parser-loader.ts
index fb3a0ae93..f0133e5e2 100644
--- a/gitnexus/src/core/tree-sitter/parser-loader.ts
+++ b/gitnexus/src/core/tree-sitter/parser-loader.ts
@@ -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 = {
[SupportedLanguages.Rust]: Rust,
[SupportedLanguages.PHP]: PHP.php_only,
[SupportedLanguages.Kotlin]: Kotlin,
+ [SupportedLanguages.Swift]: Swift,
};
export const loadParser = async (): Promise => {