{"id":24656576,"url":"https://github.com/tree-sitter/swift-tree-sitter","last_synced_at":"2025-12-11T23:01:47.514Z","repository":{"id":38818364,"uuid":"422852058","full_name":"tree-sitter/swift-tree-sitter","owner":"tree-sitter","description":"Swift API for the tree-sitter incremental parsing system","archived":false,"fork":false,"pushed_at":"2025-02-24T11:16:46.000Z","size":421,"stargazers_count":302,"open_issues_count":3,"forks_count":34,"subscribers_count":6,"default_branch":"main","last_synced_at":"2025-05-12T06:56:21.597Z","etag":null,"topics":["ios","macos","parser","parsing","swift","tree-sitter"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tree-sitter.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["mattmassicotte"]}},"created_at":"2021-10-30T10:39:57.000Z","updated_at":"2025-05-06T16:01:54.000Z","dependencies_parsed_at":"2023-10-15T03:23:16.569Z","dependency_job_id":"2b4390e2-c49d-47a6-9a47-19ed5f670d6b","html_url":"https://github.com/tree-sitter/swift-tree-sitter","commit_stats":{"total_commits":248,"total_committers":17,"mean_commits":"14.588235294117647","dds":0.08467741935483875,"last_synced_commit":"d0938d3607abcc5669bdf1d7d3b0485a8740fc65"},"previous_names":["tree-sitter/swift-tree-sitter","chimehq/swifttreesitter"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tree-sitter%2Fswift-tree-sitter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tree-sitter%2Fswift-tree-sitter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tree-sitter%2Fswift-tree-sitter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tree-sitter%2Fswift-tree-sitter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tree-sitter","download_url":"https://codeload.github.com/tree-sitter/swift-tree-sitter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254485063,"owners_count":22078767,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","macos","parser","parsing","swift","tree-sitter"],"created_at":"2025-01-25T23:05:16.744Z","updated_at":"2025-12-11T23:01:42.175Z","avatar_url":"https://github.com/tree-sitter.png","language":"Swift","funding_links":["https://github.com/sponsors/mattmassicotte"],"categories":["Swift"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n[![Build Status][build status badge]][build status]\n[![Platforms][platforms badge]][platforms]\n[![Documentation][documentation badge]][documentation]\n[![Discord][discord badge]][discord]\n\n\u003c/div\u003e\n\n# SwiftTreeSitter\n\nSwift API for the [tree-sitter](https://tree-sitter.github.io/) incremental parsing system.\n\n- Close to full coverage of the C API\n- Swift/Foundation types where possible\n- Standard query result mapping for highlights and injections\n- Query predicate/directive support via `ResolvingQueryMatchSequence`\n- Nested language support\n- Swift concurrency support where possible\n\n# Structure\n\nThis project is actually split into two parts: `SwiftTreeSitter` and `SwiftTreeSitterLayer`.\n\nThe SwiftTreeSitter target is a close match to the C runtime API. It adds only a few additional types to help support querying. It is fairly low-level, and there will be significant work to use it in a real project.\n\nSwiftTreeSitterLayer is an abstraction built on top of SwiftTreeSitter. It supports documents with nested languages and transparent querying across those nestings. It also supports asynchronous language resolution. While still low-level, SwiftTreeSitterLayer is easier to work with while also supporting more features.\n\nAnd yet there's more! If you are looking a higher-level system for syntax highlighting and other syntactic operations, you might want to have a look at [Neon](https://github.com/ChimeHQ/Neon). It is much easier to integrate with a text system, and has lots of additional performance-related features.\n\n\n## Integration\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/ChimeHQ/SwiftTreeSitter\")\n],\ntargets: [\n    .target(\n        name: \"MySwiftTreeSitterTarget\",\n        dependencies: [\"SwiftTreeSitter\"]\n    ),\n    .target(\n        name: \"MySwiftTreeSitterLayerTarget\",\n        dependencies: [\n            .product(name: \"SwiftTreeSitterLayer\", package: \"SwiftTreeSitter\"),\n        ]\n    ),\n]\n```\n\n## Range Translation\n\nThe tree-sitter runtime operates on raw string data. This means it works with bytes, and is string-encoding-sensitive. Swift's `String` type is an abstraction on top of raw data and cannot be used directly. To overcome this, you also have to be aware of the types of indexes you are using and how string data is translated back and forth.\n\nTo help, SwiftTreeSitter supports the base tree-sitter encoding facilities. You can control this via `Parser.parse(tree:encoding:readBlock:)`. But, by default this will assume UTF-16-encoded data. This is done to offer direct compatibility with Foundation strings and `NSRange`, which both use UTF-16.\n\nAlso, to help with all the back and forth, SwiftTreeSitter includes some accessors that are NSRange-based, as well as extension on `NSRange`. These **must** be used when working with the native tree-sitter types unless you take care to handle encoding yourself.\n\nTo keep things clear, consistent naming and types are used. `Node.byteRange` returns a `Range\u003cUInt32\u003e`, which is an encoding-dependent value. `Node.range` is an `NSRange` which is defined to use UTF-16.\n    \n```swift\nlet node = tree.rootNode!\n\n// this is encoding-dependent and cannot be used with your storage\nnode.byteRange\n\n// this is a UTF-16-assumed translation of the byte ranges\nnode.range\n\n// converting UTF-16-based changed ranges on re-parse\nlet ranges: [NSRange] = newtree.changedRanges(from: oldTree)\n    .map{ $0.bytes.range }\n```\n\n## Query Conflicts\n\nSwiftTreeSitter does its best to resolve poor/incorrect query constructs, which are surprisingly common.\n\nWhen using injections, child query ranges are automatically expanded using parent matches. This handles cases where a parent has queries that overlap with children in conflicting ways. Without expansion, it is possible to construct queries that fall within children ranges but produce on parent matches.\n\nAll matches are sorted by:\n\n- depth\n- location in content\n- specificity of match label (more components =\u003e more specific)\n- occurrence in the query source\n\nEven with these, it is possible to produce queries that will result in \"incorrect\" behavior that are either ambiguous or undefined in the query definition.\n\n## Highlighting\n\nA very common use of tree-sitter is to do syntax highlighting. It is possible to use this library directly, especially if your source text does not change. Here's a little example that sets everything up with a SPM-bundled language.\n\nFirst, check out how it works with SwiftTreeSitterLayer. It's complex, but does a lot for you.\n\n````swift\n// LanguageConfiguration takes care of finding and loading queries in SPM-created bundles.\nlet markdownConfig = try LanguageConfiguration(tree_sitter_markdown(), name: \"Markdown\")\nlet markdownInlineConfig = try LanguageConfiguration(\n    tree_sitter_markdown_inline(),\n    name: \"MarkdownInline\",\n    bundleName: \"TreeSitterMarkdown_TreeSitterMarkdownInline\"\n)\nlet swiftConfig = try LanguageConfiguration(tree_sitter_swift(), name: \"Swift\")\n\n// Unfortunately, injections do not use standardized language names, and can even be content-dependent. Your system must do this mapping.\nlet config = LanguageLayer.Configuration(\n    languageProvider: {\n        name in\n        switch name {\n        case \"markdown\":\n            return markdownConfig\n        case \"markdown_inline\":\n            return markdownInlineConfig\n        case \"swift\":\n            return swiftConfig\n        default:\n            return nil\n        }\n    }\n)\n\nlet rootLayer = try LanguageLayer(languageConfig: markdownConfig, configuration: config)\n\nlet source = \"\"\"\n# this is markdown\n\n```swift\nfunc main(a: Int) {\n}\n```\n\n## also markdown\n\n```swift\nlet value = \"abc\"\n```\n\"\"\"\n\nrootLayer.replaceContent(with: source)\n\nlet fullRange = NSRange(source.startIndex..\u003csource.endIndex, in: source)\n\nlet textProvider = source.predicateTextProvider\nlet highlights = try rootLayer.highlights(in: fullRange, provider: textProvider)\n\nfor namedRange in highlights {\n    print(\"\\(namedRange.name): \\(namedRange.range)\")\n}\n````\n\nYou can also use SwiftTreeSitter directly:\n\n```swift\nlet swiftConfig = try LanguageConfiguration(tree_sitter_swift(), name: \"Swift\")\n\nlet parser = Parser()\ntry parser.setLanguage(swiftConfig.language)\n\nlet source = \"\"\"\nfunc main() {}\n\"\"\"\nlet tree = parser.parse(source)!\n\nlet query = swiftConfig.queries[.highlights]!\n\nlet cursor = query.execute(in: tree)\nlet highlights = cursor\n    .resolve(with: .init(string: source))\n    .highlights()\n\nfor namedRange in highlights {\n    print(\"range: \", namedRange)\n}\n```\n\n## Language Parsers\n\nTree-sitter language parsers are separate projects, and you'll probably need at least one. More details are available in the [documentation][documentation]. How they can be installed an incorporated varies.\n\nHere's a list of parsers that support SPM. Since you're here, you might find that convenient. And the `LanguageConfiguration` type supports loading bundled queries directly.\n\n| Parser | Make | SPM | Official Repo |\n| --- | :---: | :---: | :---: |\n| [Bash](https://github.com/tree-sitter/tree-sitter-bash) | | ✅ | ✅ |\n| [C](https://github.com/tree-sitter/tree-sitter-c) | | ✅ | ✅ |\n| [C++](https://github.com/tree-sitter/tree-sitter-cpp) | | ✅ | ✅ |\n| [C#](https://github.com/tree-sitter/tree-sitter-c-sharp) | | ✅ | ✅ |\n| [Clojure](https://github.com/mattmassicotte/tree-sitter-clojure/tree/feature/spm) | | ✅ | |\n| [CSS](https://github.com/tree-sitter/tree-sitter-css) | ✅ | ✅ | ✅ |\n| [Dockerfile](https://github.com/camdencheek/tree-sitter-dockerfile) | ✅ | ✅ | ✅ |\n| [Diff](https://github.com/the-mikedavis/tree-sitter-diff) | | ✅ | ✅ |\n| [Elixir](https://github.com/elixir-lang/tree-sitter-elixir) | ✅ | ✅ | ✅ |\n| [Elm](https://github.com/elm-tooling/tree-sitter-elm) | | ✅ | ✅ |\n| [Go](https://github.com/tree-sitter/tree-sitter-go) | ✅ | ✅ | ✅ |\n| [GoMod](https://github.com/camdencheek/tree-sitter-go-mod) | ✅ | ✅ | ✅ |\n| [GoWork](https://github.com/omertuc/tree-sitter-go-work) | ✅ | | |\n| [Haskell](https://github.com/tree-sitter/tree-sitter-haskell) | | ✅ | ✅ |\n| [HCL](https://github.com/MichaHoffmann/tree-sitter-hcl) | | ✅ | ✅ |\n| [HTML](https://github.com/tree-sitter/tree-sitter-html) | | ✅ | ✅ |\n| [Java](https://github.com/tree-sitter/tree-sitter-java) | ✅ | ✅ | ✅ |\n| [Javascript](https://github.com/tree-sitter/tree-sitter-javascript) | | ✅ | ✅ |\n| [JSON](https://github.com/tree-sitter/tree-sitter-json) | ✅ | ✅ | ✅ |\n| [JSDoc](https://github.com/tree-sitter/tree-sitter-jsdoc) | | ✅ | ✅ |\n| [Julia](https://github.com/tree-sitter/tree-sitter-julia) | | ✅ | ✅ |\n| [Kotlin](https://github.com/fwcd/tree-sitter-kotlin) | ✅ | | |\n| [Latex](https://github.com/latex-lsp/tree-sitter-latex) | ✅ | ✅ | ✅ |\n| [Lua](https://github.com/Azganoth/tree-sitter-lua) | | ✅ | ✅ |\n| [Markdown](https://github.com/MDeiml/tree-sitter-markdown) | | ✅ | ✅ |\n| [OCaml](https://github.com/tree-sitter/tree-sitter-ocaml) | | ✅ | ✅ |\n| [Perl](https://github.com/ganezdragon/tree-sitter-perl) | | ✅ | ✅ |\n| [PHP](https://github.com/tree-sitter/tree-sitter-php) | ✅ | ✅ | ✅ |\n| [Pkl](https://github.com/apple/tree-sitter-pkl) | | ✅ | ✅ |\n| [Python](https://github.com/tree-sitter/tree-sitter-python) | | ✅ | ✅ |\n| [Ruby](https://github.com/tree-sitter/tree-sitter-ruby) | ✅ | ✅ | ✅ |\n| [Rust](https://github.com/tree-sitter/tree-sitter-rust) | | ✅ | ✅ |\n| [Scala](https://github.com/tree-sitter/tree-sitter-scala) | | ✅ | ✅ |\n| [SQL](https://github.com/DerekStride/tree-sitter-sql/tree/gh-pages) | | ✅ | ✅ |\n| [SSH](https://github.com/metio/tree-sitter-ssh-client-config) | | ✅ | ✅ |\n| [Swift](https://github.com/alex-pinkus/tree-sitter-swift/tree/with-generated-files) | ✅ | ✅ | ✅ |\n| [TOML](https://github.com/mattmassicotte/tree-sitter-toml/feature/spm) | | ✅ | |\n| [Tree-sitter query language](https://github.com/nvim-treesitter/tree-sitter-query) | | ✅ | ✅ |\n| [Typescript](https://github.com/tree-sitter/tree-sitter-typescript) | | ✅ | ✅ |\n| [Verilog](https://github.com/tree-sitter/tree-sitter-verilog) | | ✅ | ✅ |\n| [YAML](https://github.com/mattmassicotte/tree-sitter-yaml/tree/feature/spm) | | ✅ | |\n| [Zig](https://github.com/maxxnino/tree-sitter-zig) | ✅ | ✅ | ✅ |\n\n## Contributing and Collaboration\n\nI would love to hear from you! Issues or pull requests work great. A [Discord server][discord] is also available for live help, but I have a strong bias towards answering in the form of documentation.\n\nI prefer collaboration, and would love to find ways to work together if you have a similar project.\n\nI prefer indentation with tabs for improved accessibility. But, I'd rather you use the system you want and make a PR than hesitate because of whitespace.\n\nBy participating in this project you agree to abide by the [Contributor Code of Conduct](CODE_OF_CONDUCT.md).\n\n[build status]: https://github.com/tree-sitter/swift-tree-sitter/actions\n[build status badge]: https://github.com/tree-sitter/swift-tree-sitter/workflows/CI/badge.svg\n[platforms]: https://swiftpackageindex.com/tree-sitter/swift-tree-sitter\n[platforms badge]: https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ftree-sitter%2Fswift-tree-sitter%2Fbadge%3Ftype%3Dplatforms\n[documentation]: https://swiftpackageindex.com/tree-sitter/swift-tree-sitter/main/documentation\n[documentation badge]: https://img.shields.io/badge/Documentation-DocC-blue\n[discord]: https://discord.gg/esFpX6sErJ\n[discord badge]: https://img.shields.io/badge/Discord-purple?logo=Discord\u0026label=Chat\u0026color=%235A64EC\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftree-sitter%2Fswift-tree-sitter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftree-sitter%2Fswift-tree-sitter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftree-sitter%2Fswift-tree-sitter/lists"}