Add Swift grammar support and skeleton coverage#71
Add Swift grammar support and skeleton coverage#71marvin-yorke wants to merge 1 commit intoRyandonofrio3:mainfrom
Conversation
WalkthroughThe changes add comprehensive Swift language support to the codebase by introducing a Swift language definition with AST node mappings, extending skeleton field configurations for Swift containers, and refactoring symbol extraction logic to be language-aware with Swift-specific formatting for function calls. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge base: Disabled due to data retention organization setting
📒 Files selected for processing (3)
src/lib/core/languages.ts(1 hunks)src/lib/skeleton/body-fields.ts(2 hunks)src/lib/skeleton/skeletonizer.ts(4 hunks)
🔇 Additional comments (1)
src/lib/skeleton/skeletonizer.ts (1)
293-320: Good: referenced symbol extraction is now language-aware.
PassinglangIdintoextractReferencedSymbolsis the right hook for Swift-specific call formatting without impacting other languages.
| { | ||
| id: "swift", | ||
| extensions: [".swift"], | ||
| grammar: { | ||
| name: "swift", | ||
| url: "https://github.com/alex-pinkus/tree-sitter-swift/releases/download/0.7.1/tree-sitter-swift.wasm", | ||
| }, | ||
| definitionTypes: [ | ||
| "function_declaration", | ||
| "class_declaration", | ||
| "protocol_declaration", | ||
| "property_declaration", | ||
| "typealias_declaration", | ||
| "init_declaration", | ||
| "deinit_declaration", | ||
| "macro_declaration", | ||
| "subscript_declaration", | ||
| ], | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# Find the grammar loader implementation
rg -t ts -t js "Language\.load\|grammar.*url" --max-count 20Repository: Ryandonofrio3/osgrep
Length of output: 184
🏁 Script executed:
# Check if there are existing tests for language definitions
fd -e test -e spec | head -20Repository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
# Look for Swift-specific tests or references
rg -i "swift" --max-count 20Repository: Ryandonofrio3/osgrep
Length of output: 1348
🏁 Script executed:
# Check the web-tree-sitter version and dependencies
cat package.json | grep -A 5 -B 5 "web-tree-sitter"Repository: Ryandonofrio3/osgrep
Length of output: 354
🏁 Script executed:
# View the body-fields.ts Swift mappings in detail
cat -n src/lib/skeleton/body-fields.ts | grep -A 10 -B 2 "swift:"Repository: Ryandonofrio3/osgrep
Length of output: 959
🏁 Script executed:
# Check for any existing Swift tests
find . -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "swift" 2>/dev/null || echo "No Swift tests found"Repository: Ryandonofrio3/osgrep
Length of output: 84
🏁 Script executed:
# Look for integration or fixture files related to languages
find . -type f -name "*language*" -o -name "*grammar*" | grep -v node_modules | head -20Repository: Ryandonofrio3/osgrep
Length of output: 125
🌐 Web query:
tree-sitter-swift 0.7.1 release github alex-pinkus wasm
💡 Result:
Yes — alex-pinkus's tree-sitter-swift has a 0.7.1 release (published June 23, 2025) and the repo includes instructions for building/using a WebAssembly (wasm) bundle with web-tree-sitter. Sources: GitHub repo (README with wasm instructions) and crate release listing. [1][2]
Sources
- alex-pinkus/tree-sitter-swift (README, wasm usage). [1]
- crate/release listing showing 0.7.1 — Jun 23, 2025. [2]
🏁 Script executed:
# Check grammar-loader.ts to understand how Language.load() works
cat -n src/lib/index/grammar-loader.tsRepository: Ryandonofrio3/osgrep
Length of output: 2413
🏁 Script executed:
# Search for property_declaration, typealias_declaration, macro_declaration, subscript_declaration usage
rg "property_declaration|typealias_declaration|macro_declaration|subscript_declaration" --max-count 30Repository: Ryandonofrio3/osgrep
Length of output: 286
🏁 Script executed:
# Check if there are any comments or docs about supported node types for Swift
rg -i "node.*type|definition.*type" src/lib/core/languages.ts -A 3 -B 3Repository: Ryandonofrio3/osgrep
Length of output: 3601
🌐 Web query:
tree-sitter-swift property_declaration macro_declaration subscript_declaration node structure
💡 Result:
I can’t reliably list exact fields without reading the grammar’s generated node-types.json, but you can inspect the precise node structure (fields, children and supertypes) for property_declaration, macro_declaration and subscript_declaration in the tree-sitter‑swift grammar’s node‑types.json. Useful links:
- tree-sitter docs on node-types.json (explains format and how to read fields/children). [1]
- tree-sitter‑swift repository (contains src/node-types.json to inspect exact node shapes). [2]
- Rust crate / package pages for tree-sitter‑swift (versions/releases). [3][4]
If you want, I can fetch and paste the exact node-types.json entries for: property_declaration, macro_declaration, and subscript_declaration — tell me which repository/version (e.g., alex-pinkus/tree-sitter-swift main or the tree-sitter-swift v0.7.1 release) and I’ll extract and show the exact JSON for those node types.
Sources:
[1] https://tree-sitter.github.io/tree-sitter/using-parsers/6-static-node-types
[2] https://github.com/alex-pinkus/tree-sitter-swift
[3] https://crates.io/crates/tree-sitter-swift
[4] https://pypi.org/project/tree-sitter-swift/
🏁 Script executed:
# Check if there's any documentation or comments about why certain types are excluded
rg -B 5 -A 5 "body-fields|definitionTypes" src/lib/core/languages.tsRepository: Ryandonofrio3/osgrep
Length of output: 4791
🏁 Script executed:
# Look for any usage of property_declaration, macro_declaration, subscript_declaration in the codebase
rg -r "property_declaration|macro_declaration|subscript_declaration" src/ --type-listRepository: Ryandonofrio3/osgrep
Length of output: 453
🏁 Script executed:
# Try to download and inspect tree-sitter-swift node-types.json from the repository
curl -s "https://raw.githubusercontent.com/alex-pinkus/tree-sitter-swift/0.7.1/src/node-types.json" 2>/dev/null | python3 << 'EOF'
import sys
import json
try:
data = json.load(sys.stdin)
# Look for property_declaration, macro_declaration, subscript_declaration, typealias_declaration
target_types = ["property_declaration", "macro_declaration", "subscript_declaration", "typealias_declaration"]
for item in data:
if isinstance(item, dict) and item.get("type") in target_types:
print(f"\n{item['type']}:")
print(json.dumps(item, indent=2))
except Exception as e:
print(f"Error: {e}", file=sys.stderr)
EOFRepository: Ryandonofrio3/osgrep
Length of output: 150
🏁 Script executed:
# Also check if there's a skeletonizer pattern that processes definitionTypes
rg -A 20 "definitionTypes" src/lib/skeleton/skeletonizer.tsRepository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
# Check how definitionTypes are actually used - search for usage patterns
rg "definitionTypes" src/ -B 2 -A 2 | head -40Repository: Ryandonofrio3/osgrep
Length of output: 2207
🏁 Script executed:
# Look for the extraction logic that uses definitionTypes
rg -t ts "function.*extract|walk.*node|traverse" src/lib/skeleton/ | head -20Repository: Ryandonofrio3/osgrep
Length of output: 157
Add body-field mappings for property_declaration, typealias_declaration, macro_declaration, and subscript_declaration in src/lib/skeleton/body-fields.ts.
The Swift grammar (0.7.1 WASM URL is valid and loads correctly), but src/lib/core/languages.ts declares 9 definitionTypes while src/lib/skeleton/body-fields.ts only maps 5. When chunker.ts classifies nodes by definitionTypes, the four unmapped types (property_declaration, typealias_declaration, macro_declaration, subscript_declaration) will be identified as definitions but their bodies will fail to extract, breaking semantic chunking. Determine whether these types should have body mappings (e.g., property_declaration → "value" field) or be removed from definitionTypes if they don't contain extractable bodies.
🤖 Prompt for AI Agents
In src/lib/core/languages.ts around lines 178-196, the Swift entry lists
definitionTypes that are not mapped in src/lib/skeleton/body-fields.ts, causing
body extraction to fail; update src/lib/skeleton/body-fields.ts to add
body-field mappings for the missing Swift node types (property_declaration →
"value", typealias_declaration → "type", macro_declaration → "body" (or
"declaration" if that matches the grammar), subscript_declaration → "accessors"
or "body" depending on tree-sitter fields), or alternatively remove those four
types from the Swift definitionTypes in src/lib/core/languages.ts if they truly
have no extractable body; ensure chosen field names match the tree-sitter-swift
grammar fields and run the chunker unit tests to confirm correct extraction.
| swift: { | ||
| function_declaration: "body", | ||
| init_declaration: "body", | ||
| deinit_declaration: "body", | ||
| class_declaration: null, // Container (covers class/struct/enum/actor) | ||
| protocol_declaration: null, // Container | ||
| enum_class_body: null, // Container for nested declarations | ||
| }, |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate the body-fields.ts file and see its context
find . -name "body-fields.ts" -type f 2>/dev/null | head -5Repository: Ryandonofrio3/osgrep
Length of output: 97
🏁 Script executed:
# Search for tree-sitter-swift references in the codebase
rg "tree-sitter-swift" --type json --type ts --type js -i | head -20Repository: Ryandonofrio3/osgrep
Length of output: 199
🏁 Script executed:
# Look for package.json to check dependencies and versions
find . -name "package.json" -type f -exec grep -l "tree-sitter" {} \; 2>/dev/null | head -5Repository: Ryandonofrio3/osgrep
Length of output: 78
🏁 Script executed:
# Read the body-fields.ts file to see the full context
cat -n ./src/lib/skeleton/body-fields.ts | head -130Repository: Ryandonofrio3/osgrep
Length of output: 4775
🏁 Script executed:
# Look for grammar or schema definitions in the codebase
find . -type f \( -name "*.json" -o -name "*.ts" -o -name "*.js" \) -path "*/grammar*" 2>/dev/null | head -10Repository: Ryandonofrio3/osgrep
Length of output: 97
🏁 Script executed:
# Search for Swift-related grammar or schema definitions
rg "class_declaration|init_declaration|deinit_declaration" --type ts --type json -B2 -A2 | head -40Repository: Ryandonofrio3/osgrep
Length of output: 2406
🏁 Script executed:
# Check if there's documentation about tree-sitter node types
find . -name "*swift*" -type f 2>/dev/null | grep -E "\.(md|txt|json)$" | head -10Repository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
# Check the grammar-loader.ts file
cat -n ./src/lib/index/grammar-loader.ts | head -100Repository: Ryandonofrio3/osgrep
Length of output: 2413
🏁 Script executed:
# Look for tests or validation that use Swift node types
find . -name "*.test.*" -o -name "*.spec.*" | xargs grep -l "swift" 2>/dev/null | head -5Repository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
# Search for any test files that might validate body-fields
rg "init_declaration|deinit_declaration|function_declaration" --type ts -B2 -A2 | head -50Repository: Ryandonofrio3/osgrep
Length of output: 2792
🏁 Script executed:
# Check if there's a CONTAINER_TYPES entry for Swift
cat -n ./src/lib/skeleton/body-fields.ts | grep -A 20 "swift:" | tail -20Repository: Ryandonofrio3/osgrep
Length of output: 741
🏁 Script executed:
# Get full CONTAINER_TYPES section to see if Swift is included
sed -n '127,150p' ./src/lib/skeleton/body-fields.tsRepository: Ryandonofrio3/osgrep
Length of output: 933
🏁 Script executed:
# Search for any schema files that might define node types
find . -name "*schema*" -o -name "*grammar*" | grep -v node_modules | head -10Repository: Ryandonofrio3/osgrep
Length of output: 97
🏁 Script executed:
# Check if there's documentation about supported node types
find . -name "README*" -o -name "*.md" | xargs grep -l "swift\|node.type" 2>/dev/null | head -5Repository: Ryandonofrio3/osgrep
Length of output: 46
🌐 Web query:
tree-sitter-swift 0.7.1 grammar node types class_declaration struct_declaration enum_declaration
💡 Result:
In tree-sitter-swift v0.7.1 the grammar's generated node-types file includes the node types named:
- class_declaration
- struct_declaration
- enum_declaration
You can view the grammar / package (v0.7.1) on the project repo and package metadata. [1][2]
Sources:
[1] alex-pinkus/tree-sitter-swift (GitHub, v0.7.1). [2] tree-sitter-swift package metadata (tree-sitter.json / v0.7.1).
🌐 Web query:
tree-sitter-swift 0.7.1 init_declaration deinit_declaration body field
💡 Result:
Yes — in tree-sitter-swift v0.7.1 the grammar exposes init_declaration and deinit_declaration nodes and places them inside class/protocol bodies (they're used by the package TAGS query). The repository and crate docs show init_declaration and deinit_declaration are matched inside class_body / protocol_body (used as method-like definitions). See the TAGS_QUERY and project repo for v0.7.1. [1][2]
Sources:
- TAGS_QUERY (shows init_declaration / deinit_declaration inside class_body / protocol_body). [1]
- tree-sitter-swift v0.7.1 repository (grammar package info, release 0.7.1). [2]
🌐 Web query:
site:github.com tree-sitter-swift v0.7.1 grammar.js node-types.json
💡 Result:
Here are locations for tree-sitter-swift v0.7.1 on GitHub / npm (includes node-types.json and the grammar source):
-
GitHub repo (source/metadata; v0.7.1 is the published package version referenced in README). https://github.com/alex-pinkus/tree-sitter-swift. [1]
-
Published package (v0.7.1) on the CDN — package manifest showing version 0.7.1; package files (including src/node-types.json and src/grammar.ts) are available via unpkg/jsDelivr for the v0.7.1 release. Example manifest on unpkg: app.unpkg.com/tree-sitter-swift@0.7.1/files/tree-sitter.json. Use URLs like:
- https://unpkg.com/tree-sitter-swift@0.7.1/src/node-types.json
- https://unpkg.com/tree-sitter-swift@0.7.1/src/grammar.ts
(or the equivalent jsDelivr URL). [2][3]
-
Rust crate / release info (version 0.7.1). [4]
References
[1] https://github.com/alex-pinkus/tree-sitter-swift.
[2] https://app.unpkg.com/tree-sitter-swift@0.7.1/files/tree-sitter.json.
[3] https://www.jsdelivr.com/package/npm/tree-sitter-swift (package v0.7.1).
[4] https://lib.rs/crates/tree-sitter-swift (shows 0.7.1 release).
Want me to fetch and paste the contents of src/node-types.json or src/grammar.ts/grammar.js for v0.7.1?
🌐 Web query:
tree-sitter-swift 0.7.1 function_declaration struct_declaration enum_declaration body field
💡 Result:
Do you want (A) the exact grammar node shapes for tree-sitter-swift v0.7.1 (so I should fetch and quote the grammar source/grammar.json), (B) examples of how those nodes appear in parse trees, or (C) help matching/extracting those nodes with queries?
🏁 Script executed:
# Check languages.ts to see how Swift is defined and what node types are used
cat -n ./src/lib/core/languages.ts | grep -A 20 "swift"Repository: Ryandonofrio3/osgrep
Length of output: 930
🏁 Script executed:
# Fetch node-types.json for tree-sitter-swift 0.7.1
curl -s "https://unpkg.com/tree-sitter-swift@0.7.1/src/node-types.json" | head -200Repository: Ryandonofrio3/osgrep
Length of output: 4166
🏁 Script executed:
# Also try to get grammar.js or grammar structure
curl -s "https://unpkg.com/tree-sitter-swift@0.7.1/package.json" | grep -A 5 -B 5 "version"Repository: Ryandonofrio3/osgrep
Length of output: 308
🏁 Script executed:
# Extract just the declaration types and their fields from the node-types.json
curl -s "https://unpkg.com/tree-sitter-swift@0.7.1/src/node-types.json" | python3 << 'EOF'
import json
import sys
data = json.load(sys.stdin)
# Filter for declaration types
declarations = [
"function_declaration", "init_declaration", "deinit_declaration",
"class_declaration", "struct_declaration", "enum_declaration",
"protocol_declaration", "property_declaration", "macro_declaration",
"subscript_declaration"
]
for node in data:
if node.get("type") in declarations:
print(f"\n{node['type']}:")
print(f" fields: {list(node.get('fields', {}).keys())}")
if "body" in node.get("fields", {}):
print(f" body: {node['fields']['body']}")
EOFRepository: Ryandonofrio3/osgrep
Length of output: 150
Add missing Swift node type mappings for struct_declaration and enum_declaration.
In tree-sitter-swift 0.7.1, class_declaration, struct_declaration, and enum_declaration are separate node types, not covered by a single type. The mappings at lines 113–120 are incomplete and the comment on line 117 is misleading. Add explicit entries for struct_declaration and enum_declaration to prevent silent failures when eliding struct and enum bodies in Swift code.
🤖 Prompt for AI Agents
In src/lib/skeleton/body-fields.ts around lines 113 to 120, the Swift mapping
only lists class_declaration while tree-sitter-swift 0.7.1 uses separate node
types for class_declaration, struct_declaration, and enum_declaration; update
the mapping to add explicit entries for struct_declaration and enum_declaration
(matching the same value used for class_declaration), and update or remove the
misleading comment about Container so the code will correctly elide struct and
enum bodies instead of silently failing.
| c: [], | ||
| ruby: ["class", "module"], | ||
| php: ["class_declaration", "trait_declaration"], | ||
| swift: ["class_declaration", "class_body", "enum_class_body", "protocol_declaration", "protocol_body"], |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cd src/lib/skeleton && find . -name "*body-fields*" -o -name "*CONTAINER*" | head -20Repository: Ryandonofrio3/osgrep
Length of output: 80
🏁 Script executed:
rg "CONTAINER_TYPES" --type ts -A 5 -B 5 | head -100Repository: Ryandonofrio3/osgrep
Length of output: 1472
🏁 Script executed:
rg "swift.*class_declaration" --type ts -A 2 -B 2 | head -50Repository: Ryandonofrio3/osgrep
Length of output: 413
🏁 Script executed:
rg "enum_class_body|struct_declaration|enum_declaration|actor_declaration" --type ts | head -20Repository: Ryandonofrio3/osgrep
Length of output: 997
🏁 Script executed:
rg "swift" --type ts -i | grep -i "grammar\|node\|tree" | head -30Repository: Ryandonofrio3/osgrep
Length of output: 291
🏁 Script executed:
find . -name "*.swift" -o -name "*swift*" -o -name "*tree-sitter*" | grep -E "\.(json|md|txt)$" | head -20Repository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
rg "tree-sitter" . --type json --type md | head -30Repository: Ryandonofrio3/osgrep
Length of output: 265
🏁 Script executed:
rg "BODY_FIELDS" --type ts -A 100 | grep -A 100 "swift:" | head -80Repository: Ryandonofrio3/osgrep
Length of output: 2010
🏁 Script executed:
rg "struct_declaration|enum_declaration|actor_declaration" --type ts -B 3 -A 1 | grep -E "swift|struct|enum|actor" | head -40Repository: Ryandonofrio3/osgrep
Length of output: 981
🏁 Script executed:
cat -n src/lib/skeleton/body-fields.ts | head -200Repository: Ryandonofrio3/osgrep
Length of output: 6656
🏁 Script executed:
find . -name "*.test.*" -o -name "*.spec.*" -o -name "__tests__" -o -name "test*" | head -20Repository: Ryandonofrio3/osgrep
Length of output: 331
🏁 Script executed:
rg "swift" --type ts | grep -i "test\|example\|grammar\|node" | head -40Repository: Ryandonofrio3/osgrep
Length of output: 46
🏁 Script executed:
rg "class_declaration|enum_class_body" --type ts -B 5 -A 5 | head -80Repository: Ryandonofrio3/osgrep
Length of output: 4681
🏁 Script executed:
cat test_skeleton.py | head -150Repository: Ryandonofrio3/osgrep
Length of output: 95
🏁 Script executed:
rg "swift" . -i -A 3 -B 3 | grep -E "swift|struct|enum|actor|class" | head -60Repository: Ryandonofrio3/osgrep
Length of output: 793
🏁 Script executed:
find . -path "./node_modules" -prune -o -type f -name "*.swift" -printRepository: Ryandonofrio3/osgrep
Length of output: 46
🌐 Web query:
tree-sitter-swift 0.7.1 grammar node types struct_declaration enum_declaration actor_declaration
💡 Result:
Yes — tree-sitter-swift v0.7.1 exposes node types for struct_declaration, enum_declaration and actor_declaration (see the crate/github packaging for v0.7.1 which includes the generated node-types.json). [1][2]
Sources:
- crate docs (node-types included in the v0.7.1 package). [1]
- repository / package metadata for tree-sitter-swift v0.7.1. [2]
🌐 Web query:
tree-sitter-swift struct_body enum_body actor_body node types
💡 Result:
Yes — the Swift tree-sitter grammar exposes node types for struct/enum/actor bodies via its generated node-types.json. To inspect them:
- The tree-sitter docs explain the generated node-types.json format (fields, children, named/unamed). [1]
- The tree-sitter-swift grammar (npm/rust package) is available (package metadata / repo). You can fetch its generated node-types.json from the package or by building the grammar; it contains node types such as struct_body, enum_body and actor_body. See the tree-sitter-swift repository / package pages. [2][3]
How to get the exact node entries:
- Install or download the tree-sitter-swift package (npm or repo) and open src/node-types.json (or run tree-sitter to generate node-types.json after building). The file lists each node like:
- "struct_body"
- "enum_body"
- "actor_body"
and shows their fields/children. [1][2][3]
References
- Tree-sitter — Static node types / node-types.json docs. [1]
- tree-sitter-swift (alex-pinkus) repository / package info. [2]
- tree-sitter-swift npm/package metadata (tree-sitter.json listing). [3]
If you want, I can fetch and paste the exact node-types.json entries for struct_body / enum_body / actor_body from the latest tree-sitter-swift release — tell me which release (or “latest”) and I’ll fetch it.
🏁 Script executed:
rg "enum_class_body" --type ts -B 10 -A 10Repository: Ryandonofrio3/osgrep
Length of output: 2807
🌐 Web query:
tree-sitter-swift "enum_class_body" node type
💡 Result:
Do you want the node's definition/fields from the tree-sitter-swift node-types.json, examples of how it appears in parsed Swift code, or how to query it with a Tree-sitter query?
Add missing Swift container types to CONTAINER_TYPES.swift.
Tree-sitter-swift 0.7.1 exposes separate node types for struct_declaration, enum_declaration, and actor_declaration (each with corresponding _body variants). These should be added to the Swift entry in CONTAINER_TYPES so that methods and nested declarations within structs, enums, and actors are properly recursed into during skeletonization. Currently only class_declaration, class_body, enum_class_body, protocol_declaration, and protocol_body are included, which misses structs and actors entirely and may not correctly handle enums. Also update the code comment on line 117 which incorrectly states that class_declaration "covers class/struct/enum/actor"—these are separate node types in the grammar.
🤖 Prompt for AI Agents
In src/lib/skeleton/body-fields.ts around line 140, the Swift entry in
CONTAINER_TYPES only lists class/protocol nodes and is missing
struct_declaration, struct_body, enum_declaration, enum_body, actor_declaration,
and actor_body; update the array to include these node types so skeletonization
recurses into structs, enums, and actors. Also update the comment at line 117 to
remove the incorrect claim that class_declaration "covers
class/struct/enum/actor" and state that class, struct, enum, and actor are
separate node types in tree-sitter-swift 0.7.1.
| private extractReferencedSymbols( | ||
| node: TreeSitterNode, | ||
| langId: string, | ||
| ): string[] { | ||
| const refs: string[] = []; | ||
| const seen = new Set<string>(); | ||
|
|
||
| const extract = (n: TreeSitterNode) => { | ||
| if (n.type === "call_expression" || n.type === "call") { | ||
| const func = n.childForFieldName?.("function"); | ||
| if (func) { | ||
| let funcName = func.text; | ||
|
|
||
| // Handle member access (obj.method) - extract just method | ||
| if (func.type === "member_expression") { | ||
| const prop = func.childForFieldName?.("property"); | ||
| if (prop) funcName = prop.text; | ||
| } else if (func.type === "attribute") { | ||
| const attr = func.childForFieldName?.("attribute"); | ||
| if (attr) funcName = attr.text; | ||
| } | ||
| const getNavigationIdentifier = (node: TreeSitterNode): string | null => { | ||
| if (node.type !== "navigation_expression") return null; | ||
| const suffixes = (node.namedChildren || []).filter( | ||
| (child) => child.type === "navigation_suffix", | ||
| ); | ||
| const lastSuffix = suffixes[suffixes.length - 1]; | ||
| if (lastSuffix) { | ||
| const simple = (lastSuffix.namedChildren || []).find( | ||
| (child) => child.type === "simple_identifier", | ||
| ); | ||
| if (simple?.text) return simple.text; | ||
| } | ||
| // Fallback: look at nested navigation expressions or identifiers | ||
| const fallbacks = [...(node.namedChildren || [])].reverse(); | ||
| for (const child of fallbacks) { | ||
| if (child.type === "simple_identifier" && child.text) { | ||
| return child.text; | ||
| } | ||
| if (child.type === "navigation_expression") { | ||
| const nested = getNavigationIdentifier(child); | ||
| if (nested) return nested; | ||
| } | ||
| } | ||
| return null; | ||
| }; | ||
|
|
||
| const getCallFunctionNode = ( | ||
| node: TreeSitterNode, | ||
| ): TreeSitterNode | null => { | ||
| const direct = | ||
| node.childForFieldName?.("function") || | ||
| node.childForFieldName?.("name") || | ||
| null; | ||
| if (direct) return direct; | ||
| return node.namedChildren && node.namedChildren.length > 0 | ||
| ? node.namedChildren[0] | ||
| : null; | ||
| }; | ||
|
|
||
| const extractFunctionName = ( | ||
| func: TreeSitterNode | null, | ||
| ): string | null => { | ||
| if (!func) return null; | ||
| if (func.type === "member_expression") { | ||
| const prop = func.childForFieldName?.("property"); | ||
| if (prop?.text) return prop.text; | ||
| } else if (func.type === "attribute") { | ||
| const attr = func.childForFieldName?.("attribute"); | ||
| if (attr?.text) return attr.text; | ||
| } else if (func.type === "navigation_expression") { | ||
| const navName = getNavigationIdentifier(func); | ||
| if (navName) return navName; | ||
| } | ||
|
|
||
| // Dedupe and filter noise | ||
| if (funcName && !seen.has(funcName) && funcName.length < 30) { | ||
| seen.add(funcName); | ||
| refs.push(funcName); | ||
| // Fallback: use direct text (strip qualifiers like Module.) | ||
| const raw = func.text || ""; | ||
| if (raw.includes(".")) { | ||
| const lastSegment = raw.split(".").pop(); | ||
| if (lastSegment) return lastSegment; | ||
| } | ||
| return raw || null; | ||
| }; | ||
|
|
||
| const extractSwiftArgumentLabels = ( | ||
| callNode: TreeSitterNode, | ||
| ): string[] => { | ||
| const suffix = | ||
| callNode.childForFieldName?.("call_suffix") || | ||
| (callNode.namedChildren || []).find( | ||
| (child) => child.type === "call_suffix", | ||
| ); | ||
| if (!suffix) return []; | ||
|
|
||
| const labels: string[] = []; | ||
| const collect = (current: TreeSitterNode) => { | ||
| if (current.type === "value_argument") { | ||
| const labelNode = | ||
| current.childForFieldName?.("label") || | ||
| (current.namedChildren || []).find( | ||
| (child) => child.type === "value_argument_label", | ||
| ); | ||
|
|
||
| if (labelNode) { | ||
| const simple = (labelNode.namedChildren || []).find( | ||
| (child) => child.type === "simple_identifier", | ||
| ); | ||
| labels.push(simple?.text || labelNode.text.replace(/[:\s]/g, "")); | ||
| } else { | ||
| labels.push("_"); | ||
| } | ||
| } else { | ||
| for (const child of current.namedChildren || []) { | ||
| collect(child); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| collect(suffix); | ||
| return labels; | ||
| }; | ||
|
|
||
| const formatSwiftFunction = ( | ||
| baseName: string, | ||
| callNode: TreeSitterNode, | ||
| ): string => { | ||
| const labels = extractSwiftArgumentLabels(callNode); | ||
| const meaningful = labels.filter((label) => label && label !== "_"); | ||
| if (labels.length === 0 || meaningful.length === 0) return baseName; | ||
|
|
||
| const truncated = labels.slice(0, 3).map((label) => `${label || "_"}:`); | ||
| if (labels.length > 3) truncated.push("…"); | ||
| return `${baseName}(${truncated.join("")})`; | ||
| }; |
There was a problem hiding this comment.
Verify tree-sitter-swift AST node and field names against version 0.7.1 grammar.
The code assumes specific AST shapes (navigation_expression, call_suffix, value_argument, value_argument_label, field names function, property, attribute, label) that must match tree-sitter-swift's grammar. If any differ, Swift call summaries will regress to empty or misformatted symbols. Add a fixture test asserting formatting like greet(name:) to lock down this contract.
🤖 Prompt for AI Agents
In src/lib/skeleton/skeletonizer.ts around lines 448 to 567 the Swift
symbol-extraction helpers assume specific tree-sitter-swift node types and field
names (navigation_expression, call_suffix, value_argument, value_argument_label
and fields function/property/attribute/label) which may differ from v0.7.1
grammar; add a fixture unit test that parses a Swift call like `greet(name:)`
and asserts the formatter returns `greet(name:)`, and update the extraction
logic to defensively handle alternate node type/field names used by
tree-sitter-swift v0.7.1 (e.g., accept both
navigation_expression/member_expression variants, search for call argument lists
if call_suffix absent, accept value_argument/value_label variations, and
fallback to scanning namedChildren for identifiers/labels), then run/update
tests and pin or document the required tree-sitter-swift grammar version to
prevent regressions.
| const pushRef = (name: string | null) => { | ||
| if (!name) return; | ||
| const trimmed = name.trim(); | ||
| if (!trimmed || trimmed.length >= 30) return; | ||
| if (seen.has(trimmed)) return; | ||
| seen.add(trimmed); | ||
| refs.push(trimmed); | ||
| }; | ||
|
|
||
| const extract = (n: TreeSitterNode) => { | ||
| if (n.type === "call_expression" || n.type === "call") { | ||
| const funcNode = getCallFunctionNode(n); | ||
| let funcName = extractFunctionName(funcNode); | ||
| if (funcName && langId === "swift") { | ||
| funcName = formatSwiftFunction(funcName, n); | ||
| } | ||
| pushRef(funcName); | ||
| } else if ( |
There was a problem hiding this comment.
Avoid dropping Swift call symbols just because the formatted signature crosses the 30-char cap.
Right now pushRef() will discard long baseName(label1:label2:…) names, and you don’t fall back to the unformatted base name—so you can lose the call entirely in summaries.
Suggested minimal tweak (fallback to baseName when formatted is too long):
- if (funcName && langId === "swift") {
- funcName = formatSwiftFunction(funcName, n);
- }
- pushRef(funcName);
+ if (funcName && langId === "swift") {
+ const formatted = formatSwiftFunction(funcName, n);
+ // If the formatted signature is too long, keep at least the base name.
+ pushRef(formatted);
+ if (!seen.has(formatted.trim()) && formatted.trim().length >= 30) {
+ pushRef(funcName);
+ }
+ } else {
+ pushRef(funcName);
+ }🤖 Prompt for AI Agents
In src/lib/skeleton/skeletonizer.ts around lines 569 to 586, Swift call symbols
are being dropped when the formatted signature exceeds the 30-char limit because
pushRef is only given the formatted name; compute the raw base name (unformatted
function name) before formatting, then for Swift: first try
formatSwiftFunction(funcName, n) and if that result is null/empty or length >=
30, fall back to the unformatted base name (trimmed) before calling pushRef;
keep the existing trimming, seen set checks and pushRef behavior otherwise.
The readme file mentions support for Swift, but there's no Tree-sitter grammar defined in the source code itself. This PR introduces https://github.com/alex-pinkus/tree-sitter-swift grammar for parsing Swift code files, as the official https://github.com/tree-sitter/tree-sitter-swift/ is abandoned
The additional code in
skeletonizer.jssolves the argument names being the part of the Swift function signature. In case we have something likeonly outputting
-> greetas callee is not enough, there are two separate functions,greet(name:)andgreet(person:)which we need to distinguishSummary by CodeRabbit
.swiftfiles✏️ Tip: You can customize this high-level summary in your review settings.