feat: upgrade tree-sitter to 0.22.4 and tree-sitter-swift to 0.7.1

Upgrades:
- tree-sitter: ^0.21.0 → ^0.22.4
- tree-sitter-swift: ^0.6.0 → ^0.7.1

Benefits:
- tree-sitter-swift@0.7.1 ships prebuilds (no manual node-gyp needed)
- Fixes parsing of Swift 5.9+ features: #Predicate, typed throws, ~Copyable
- All 13 language parsers verified compatible with tree-sitter@0.22.4

Tested:
- All 141 query/import/call tests pass
- All 13 parsers (C, C++, C#, Go, Java, JS, Kotlin, PHP, Python, Ruby,
  Rust, TypeScript, Swift) parse correctly with 0.22.4
- PricePal (61-file iOS 26 project) indexes fully: 3,094 nodes, 10,459 edges

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
marxo126 2026-03-21 10:54:26 +01:00
parent dfe83f333e
commit 90c9153ccc
3 changed files with 89 additions and 30 deletions

View file

@ -26,7 +26,7 @@
"mnemonist": "^0.39.0",
"onnxruntime-node": "^1.24.0",
"pandemonium": "^2.4.0",
"tree-sitter": "^0.21.0",
"tree-sitter": "^0.22.4",
"tree-sitter-c": "^0.21.0",
"tree-sitter-c-sharp": "^0.21.0",
"tree-sitter-cpp": "^0.22.0",
@ -59,7 +59,7 @@
},
"optionalDependencies": {
"tree-sitter-kotlin": "^0.3.8",
"tree-sitter-swift": "^0.6.0"
"tree-sitter-swift": "^0.7.1"
}
},
"node_modules/@babel/helper-string-parser": {
@ -3480,13 +3480,6 @@
"graphology-types": ">=0.20.0"
}
},
"node_modules/graphology-types": {
"version": "0.24.8",
"resolved": "https://registry.npmjs.org/graphology-types/-/graphology-types-0.24.8.tgz",
"integrity": "sha512-hDRKYXa8TsoZHjgEaysSRyPdT6uB78Ci8WnjgbStlQysz7xR52PInxNsmnB7IBOM1BhikxkNyCVEFgmPKnpx3Q==",
"license": "MIT",
"peer": true
},
"node_modules/graphology-utils": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/graphology-utils/-/graphology-utils-2.5.2.tgz",
@ -3548,16 +3541,6 @@
"node": ">= 0.4"
}
},
"node_modules/hono": {
"version": "4.11.7",
"resolved": "https://registry.npmjs.org/hono/-/hono-4.11.7.tgz",
"integrity": "sha512-l7qMiNee7t82bH3SeyUCt9UF15EVmaBvsppY2zQtrbIhl/yzBTny+YUxsVjSjQ6gaqaeVtZmGocom8TzBlA4Yw==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=16.9.0"
}
},
"node_modules/html-escaper": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz",
@ -4941,14 +4924,14 @@
}
},
"node_modules/tree-sitter": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.21.1.tgz",
"integrity": "sha512-7dxoA6kYvtgWw80265MyqJlkRl4yawIjO7S5MigytjELkX43fV2WsAXzsNfO7sBpPPCF5Gp0+XzHk0DwLCq3xQ==",
"version": "0.22.4",
"resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz",
"integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==",
"hasInstallScript": true,
"license": "MIT",
"dependencies": {
"node-addon-api": "^8.0.0",
"node-gyp-build": "^4.8.0"
"node-addon-api": "^8.3.0",
"node-gyp-build": "^4.8.4"
}
},
"node_modules/tree-sitter-c": {
@ -5267,9 +5250,9 @@
"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==",
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/tree-sitter-swift/-/tree-sitter-swift-0.7.1.tgz",
"integrity": "sha512-pneKVTuGamaBsqqqfB9BvNQjktzh/0IVPR54jLB5Fq/JTDQwYHd0Wo6pVyZ5jAYpbztzq+rJ/rpL9ruxTmSoKw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@ -5280,7 +5263,7 @@
"which": "2.0.2"
},
"peerDependencies": {
"tree-sitter": "^0.21.1"
"tree-sitter": "^0.22.1"
},
"peerDependenciesMeta": {
"tree_sitter": {

View file

@ -66,7 +66,7 @@
"lru-cache": "^11.0.0",
"mnemonist": "^0.39.0",
"pandemonium": "^2.4.0",
"tree-sitter": "^0.21.0",
"tree-sitter": "^0.22.4",
"tree-sitter-c": "^0.21.0",
"tree-sitter-c-sharp": "^0.21.0",
"tree-sitter-cpp": "^0.22.0",
@ -82,7 +82,7 @@
},
"optionalDependencies": {
"tree-sitter-kotlin": "^0.3.8",
"tree-sitter-swift": "^0.6.0"
"tree-sitter-swift": "^0.7.1"
},
"devDependencies": {
"@types/cli-progress": "^3.11.6",

View file

@ -5,6 +5,8 @@ import { isLanguageAvailable, loadParser, loadLanguage } from '../tree-sitter/pa
import { LANGUAGE_QUERIES } from './tree-sitter-queries.js';
import { generateId } from '../../lib/utils.js';
import { getLanguageFromFilename, isVerboseIngestionEnabled, yieldToEventLoop } from './utils.js';
import { SupportedLanguages } from '../../config/supported-languages.js';
import type { SwiftPackageConfig } from './language-config.js';
import type { ExtractedImport } from './workers/parse-worker.js';
import { getTreeSitterBufferSize } from './constants.js';
import { loadImportConfigs } from './language-config.js';
@ -97,6 +99,80 @@ function createImportEdgeHelpers(graph: KnowledgeGraph, importMap: ImportMap) {
return { addImportEdge, addImportGraphEdge, getResolvedCount: () => totalImportsResolved };
}
/**
* Group Swift files by target for implicit module visibility.
*
* If SwiftPackageConfig is available, use SPM target directory mappings.
* Otherwise, group all Swift files under a single "default" target
* (assumes a single-module Xcode project).
*/
function groupSwiftFilesByTarget(
swiftFiles: string[],
swiftPackageConfig: SwiftPackageConfig | null,
): Map<string, string[]> {
const groups = new Map<string, string[]>();
if (swiftPackageConfig && swiftPackageConfig.targets.size > 0) {
for (const file of swiftFiles) {
const normalized = file.replace(/\\/g, '/');
let assigned = false;
for (const [targetName, targetDir] of swiftPackageConfig.targets) {
const dirPrefix = targetDir + '/';
const idx = normalized.indexOf(dirPrefix);
if (idx === 0 || (idx > 0 && normalized[idx - 1] === '/')) {
if (!groups.has(targetName)) groups.set(targetName, []);
groups.get(targetName)!.push(file);
assigned = true;
break;
}
}
if (!assigned) {
if (!groups.has('__default__')) groups.set('__default__', []);
groups.get('__default__')!.push(file);
}
}
} else {
groups.set('__default__', [...swiftFiles]);
}
return groups;
}
/**
* Add implicit IMPORTS edges between all Swift files in the same module/target.
* Swift has no file-level imports all files in a module see each other.
*/
function addSwiftImplicitImports(
files: { path: string }[],
swiftPackageConfig: SwiftPackageConfig | null,
importMap: Map<string, Set<string>>,
addImportEdge: (src: string, target: string) => void,
logSuffix = '',
): void {
const swiftFiles = files
.filter(f => getLanguageFromFilename(f.path) === SupportedLanguages.Swift)
.map(f => f.path);
if (swiftFiles.length <= 1) return;
const targetGroups = groupSwiftFilesByTarget(swiftFiles, swiftPackageConfig);
for (const group of targetGroups.values()) {
for (const srcFile of group) {
const existing = importMap.get(srcFile);
for (const otherFile of group) {
if (srcFile === otherFile) continue;
if (existing?.has(otherFile)) continue;
addImportEdge(srcFile, otherFile);
}
}
}
if (isDev) {
console.log(`📊 Swift: ${swiftFiles.length} files in ${targetGroups.size} target group(s), implicit imports added${logSuffix}`);
}
}
/**
* Apply an ImportResult: emit graph edges and update ImportMap/PackageMap.
* If namedBindings are provided and the import resolves to a single file,