diff --git a/docs/src/content/docs/core-concepts/plugin-system.mdx b/docs/src/content/docs/core-concepts/plugin-system.mdx index 1d497da..50e8fdf 100644 --- a/docs/src/content/docs/core-concepts/plugin-system.mdx +++ b/docs/src/content/docs/core-concepts/plugin-system.mdx @@ -24,6 +24,7 @@ kit comes with built-in support for 12+ programming languages: - **Dart** (`.dart`) - Classes, functions, mixins, enums, extensions - **HCL/Terraform** (`.hcl`, `.tf`) - Resources, variables, modules - **Haskell** (`.hs`) - Module header, functions (including lambda-binds), common type-level declarations +- **Swift** (`.swift`) - Classes, structs, enums, protocols, actors, extensions, functions Each language supports comprehensive symbol extraction including: - **Classes and interfaces** with inheritance relationships diff --git a/src/kit/queries/swift/tags.scm b/src/kit/queries/swift/tags.scm new file mode 100644 index 0000000..59650d5 --- /dev/null +++ b/src/kit/queries/swift/tags.scm @@ -0,0 +1,42 @@ +;; tags.scm for Swift symbol extraction (tree-sitter-swift) + +; Function declarations +(function_declaration + name: (simple_identifier) @name) @definition.function + +; Class declarations (keyword-differentiated from struct/enum/extension) +(class_declaration + "class" + name: (type_identifier) @name) @definition.class + +; Actor declarations +(class_declaration + "actor" + name: (type_identifier) @name) @definition.actor + +; Struct declarations +(class_declaration + "struct" + name: (type_identifier) @name) @definition.struct + +; Enum declarations +(class_declaration + "enum" + name: (type_identifier) @name) @definition.enum + +; Extension declarations (name field is user_type, not type_identifier) +(class_declaration + "extension" + name: (user_type) @name) @definition.extension + +; Protocol declarations +(protocol_declaration + name: (type_identifier) @name) @definition.protocol + +; Type alias declarations +(typealias_declaration + name: (type_identifier) @name) @definition.typealias + +; Initializer declarations +(init_declaration + "init" @name) @definition.initializer diff --git a/src/kit/tree_sitter_symbol_extractor.py b/src/kit/tree_sitter_symbol_extractor.py index 273346f..245ce2b 100644 --- a/src/kit/tree_sitter_symbol_extractor.py +++ b/src/kit/tree_sitter_symbol_extractor.py @@ -34,6 +34,7 @@ ".hxx": "cpp", ".zig": "zig", ".cs": "csharp", + ".swift": "swift", } @@ -350,6 +351,7 @@ def reset_plugins(cls) -> None: ".hxx": "cpp", ".zig": "zig", ".cs": "csharp", + ".swift": "swift", } LANGUAGES.clear() LANGUAGES.update(original_languages) diff --git a/tests/test_swift_symbols.py b/tests/test_swift_symbols.py new file mode 100644 index 0000000..9ada0b2 --- /dev/null +++ b/tests/test_swift_symbols.py @@ -0,0 +1,91 @@ +import pytest + +from kit.tree_sitter_symbol_extractor import TreeSitterSymbolExtractor + +SWIFT_SAMPLE = """\ +class Animal { + var name: String + init(name: String) { + self.name = name + } +} + +struct Point { + var x: Int + var y: Int +} + +enum Direction { + case north, south, east, west +} + +extension Animal { + func speak() -> String { + return name + } +} + +actor Worker { + func run() {} +} + +protocol Drawable { + func draw() +} + +typealias StringMap = [String: String] + +func greet(person: String) -> String { + return "Hello, \\(person)!" +} +""" + + +def test_swift_parser_and_query_available(): + parser = TreeSitterSymbolExtractor.get_parser(".swift") + query = TreeSitterSymbolExtractor.get_query(".swift") + if not parser or not query: + pytest.skip("Swift parser or query not available in this environment") + + tree = parser.parse(SWIFT_SAMPLE.encode("utf-8")) + assert tree.root_node is not None + + +def test_swift_symbols(): + parser = TreeSitterSymbolExtractor.get_parser(".swift") + query = TreeSitterSymbolExtractor.get_query(".swift") + if not parser or not query: + pytest.skip("Swift parser or query not available in this environment") + + symbols = TreeSitterSymbolExtractor.extract_symbols(".swift", SWIFT_SAMPLE) + names = {s["name"] for s in symbols} + types = {s["type"] for s in symbols} + animal_symbols = [s for s in symbols if s["name"] == "Animal"] + + assert "Animal" in names + assert "Point" in names + assert "Direction" in names + assert "Worker" in names + assert "Drawable" in names + assert "StringMap" in names + assert "greet" in names + assert "init" in names + + assert len(animal_symbols) == 2 + assert {s["type"] for s in animal_symbols} == {"class", "extension"} + + assert "class" in types + assert "actor" in types + assert "struct" in types + assert "enum" in types + assert "extension" in types + assert "protocol" in types + assert "typealias" in types + assert "function" in types + assert "initializer" in types + + +def test_swift_in_supported_languages(): + supported = TreeSitterSymbolExtractor.list_supported_languages() + assert "swift" in supported + assert ".swift" in supported["swift"] diff --git a/tests/test_symbol_extraction_multilang.py b/tests/test_symbol_extraction_multilang.py index 7776728..0b117fa 100644 --- a/tests/test_symbol_extraction_multilang.py +++ b/tests/test_symbol_extraction_multilang.py @@ -9,6 +9,7 @@ ".java": "class Bar { void foo() {} }\n", ".rs": "fn foo() {}\nstruct Bar;\n", ".zig": "pub fn foo() void {}\npub const Bar = struct {};\n", + ".swift": "func foo() -> Int { return 42 }\nclass Bar {}\n", } diff --git a/tests/test_tree_sitter_languages.py b/tests/test_tree_sitter_languages.py index f08160a..fe5e1e9 100644 --- a/tests/test_tree_sitter_languages.py +++ b/tests/test_tree_sitter_languages.py @@ -12,6 +12,7 @@ "c": b"int foo() { return 42; }\n", "dart": b"int foo() { return 42; }\n", "zig": b"pub fn foo() void { }\n", + "swift": b"func foo() -> Int { return 42 }\n", }