tree_haver 5.0.0 → 5.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -31,7 +31,7 @@
31
31
  [rubygems-maint-policy]: https://github.com/ruby/rubygems/blob/b1ab33a3d52310a84d16b193991af07f5a6a07c0/doc/rubygems/POLICIES.md?plain=1#L187-L196
32
32
  [policy-fail]: https://www.reddit.com/r/ruby/comments/1ove9vp/rubycentral_hates_this_one_fact/
33
33
 
34
- [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]](https://discord.gg/3qme4XHNKN) [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]](https://www.ruby-lang.org/) [![kettle-rb Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-rb-i]](https://github.com/kettle-rb)
34
+ [![Galtzo FLOSS Logo by Aboling0, CC BY-SA 4.0][🖼️galtzo-i]][🖼️galtzo-discord] [![ruby-lang Logo, Yukihiro Matsumoto, Ruby Visual Identity Team, CC BY-SA 2.5][🖼️ruby-lang-i]][🖼️ruby-lang] [![kettle-rb Logo by Aboling0, CC BY-SA 4.0][🖼️kettle-rb-i]][🖼️kettle-rb]
35
35
 
36
36
  [🖼️galtzo-i]: https://logos.galtzo.com/assets/images/galtzo-floss/avatar-192px.svg
37
37
  [🖼️galtzo-discord]: https://discord.gg/3qme4XHNKN
@@ -42,7 +42,7 @@
42
42
 
43
43
  # 🌴 TreeHaver
44
44
 
45
- [![Version][👽versioni]](https://bestgems.org/gems/tree_haver) [![GitHub tag (latest SemVer)][⛳️tag-img]](http://github.com/kettle-rb/tree_haver/releases) [![License: MIT][📄license-img]](https://opensource.org/licenses/MIT) [![Downloads Rank][👽dl-ranki]](https://bestgems.org/gems/tree_haver) [![Open Source Helpers][👽oss-helpi]](https://www.codetriage.com/kettle-rb/tree_haver) [![CodeCov Test Coverage][🏀codecovi]](https://codecov.io/gh/kettle-rb/tree_haver) [![Coveralls Test Coverage][🏀coveralls-img]](https://coveralls.io/github/kettle-rb/tree_haver?branch=main) [![QLTY Test Coverage][🏀qlty-covi]](https://qlty.sh/gh/kettle-rb/projects/tree_haver/metrics/code?sort=coverageRating) [![QLTY Maintainability][🏀qlty-mnti]](https://qlty.sh/gh/kettle-rb/projects/tree_haver) [![CI Heads][🚎3-hd-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/heads.yml) [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/dep-heads.yml) [![CI Current][🚎11-c-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml) [![CI Truffle Ruby][🚎9-t-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/truffle.yml) [![Deps Locked][🚎13-🔒️-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/locked_deps.yml) [![Deps Unlocked][🚎14-🔓️-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/unlocked_deps.yml) [![CI Supported][🚎6-s-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/supported.yml) [![CI Test Coverage][🚎2-cov-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/coverage.yml) [![CI Style][🚎5-st-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/style.yml) [![CodeQL][🖐codeQL-img]](https://github.com/kettle-rb/tree_haver/security/code-scanning) [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]](https://github.com/kettle-rb/tree_haver/actions/workflows/license-eye.yml)
45
+ [![Version][👽versioni]][👽dl-rank] [![GitHub tag (latest SemVer)][⛳️tag-img]][⛳️tag] [![License: MIT][📄license-img]][📄license-ref] [![Downloads Rank][👽dl-ranki]][👽dl-rank] [![Open Source Helpers][👽oss-helpi]][👽oss-help] [![CodeCov Test Coverage][🏀codecovi]][🏀codecov] [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls] [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov] [![QLTY Maintainability][🏀qlty-mnti]][🏀qlty-mnt] [![CI Heads][🚎3-hd-wfi]][🚎3-hd-wf] [![CI Runtime Dependencies @ HEAD][🚎12-crh-wfi]][🚎12-crh-wf] [![CI Current][🚎11-c-wfi]][🚎11-c-wf] [![CI Truffle Ruby][🚎9-t-wfi]][🚎9-t-wf] [![Deps Locked][🚎13-🔒️-wfi]][🚎13-🔒️-wf] [![Deps Unlocked][🚎14-🔓️-wfi]][🚎14-🔓️-wf] [![CI Supported][🚎6-s-wfi]][🚎6-s-wf] [![CI Test Coverage][🚎2-cov-wfi]][🚎2-cov-wf] [![CI Style][🚎5-st-wfi]][🚎5-st-wf] [![CodeQL][🖐codeQL-img]][🖐codeQL] [![Apache SkyWalking Eyes License Compatibility Check][🚎15-🪪-wfi]][🚎15-🪪-wf]
46
46
 
47
47
  `if ci_badges.map(&:color).detect { it != "green"}` ☝️ [let me know][🖼️galtzo-discord], as I may have missed the [discord notification][🖼️galtzo-discord].
48
48
 
@@ -50,7 +50,7 @@
50
50
 
51
51
  `if ci_badges.map(&:color).all? { it == "green"}` 👇️ send money so I can do more of this. FLOSS maintenance is now my full-time job.
52
52
 
53
- [![OpenCollective Backers][🖇osc-backers-i]](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors][🖇osc-sponsors-i]](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github][🖇sponsor-img]](https://github.com/sponsors/pboling) [![Liberapay Goal Progress][⛳liberapay-img]](https://liberapay.com/pboling/donate) [![Donate on PayPal][🖇paypal-img]](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee][🖇buyme-small-img]](https://www.buymeacoffee.com/pboling) [![Donate on Polar][🖇polar-img]](https://polar.sh/pboling) [![Donate at ko-fi.com][🖇kofi-img]](https://ko-fi.com/O5O86SNP4)
53
+ [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate at ko-fi.com][🖇kofi-img]][🖇kofi]
54
54
 
55
55
  ## 🌻 Synopsis
56
56
 
@@ -88,28 +88,28 @@ tree = parser.parse(source_code)
88
88
 
89
89
  ### Key Features
90
90
 
91
- - **Universal Ruby Support**: Works on MRI Ruby, JRuby, and TruffleRuby
92
- - **10 Parsing Backends** - Choose the right backend for your needs:
93
- - **Tree-sitter Backends** (high-performance, incremental parsing):
94
- - **MRI Backend**: Leverages [`ruby_tree_sitter`][ruby_tree_sitter] gem (C extension, fastest on MRI)
95
- - **Rust Backend**: Uses [`tree_stump`][tree_stump] gem (Rust with precompiled binaries)
96
- - **Note**: `tree_stump` currently requires unreleased fixes in the `main` branch.
97
- - **FFI Backend**: Pure Ruby FFI bindings to `libtree-sitter` (JRuby only; TruffleRuby's FFI doesn't support tree-sitter's struct-by-value returns)
98
- - **Java Backend**: Native Java integration for JRuby with [`java-tree-sitter`](https://github.com/tree-sitter/java-tree-sitter) / [`jtreesitter`][jtreesitter] grammar JARs
99
- - **Language-Specific Backends** (native parser integration):
100
- - **Prism Backend**: Ruby's official parser ([Prism][prism], stdlib in Ruby 3.4+)
101
- - **Psych Backend**: Ruby's YAML parser ([Psych][psych], stdlib)
102
- - **Commonmarker Backend**: Fast Markdown parser ([Commonmarker][commonmarker], comrak Rust)
103
- - **Markly Backend**: GitHub Flavored Markdown ([Markly][markly], cmark-gfm C)
104
- - **Pure Ruby Fallback**:
105
- - **Citrus Backend**: Pure Ruby PEG parsing via [`citrus`][citrus] (no native dependencies)
106
- - **Parslet Backend**: Pure Ruby PEG parsing via [`parslet`][parslet] (no native dependencies)
107
- - **Automatic Backend Selection**: Intelligently selects the best backend for your Ruby implementation
108
- - **Language Agnostic**: Parse any language - Ruby, Markdown, YAML, JSON, Bash, TOML, JavaScript, etc.
109
- - **Grammar Discovery**: Built-in `GrammarFinder` utility for platform-aware grammar library discovery
110
- - **Unified Position API**: Consistent `start_line`, `end_line`, `source_position` across all backends
111
- - **Thread-Safe**: Built-in language registry with thread-safe caching
112
- - **Minimal API Surface**: Simple, focused API that covers the most common use cases
91
+ - **Universal Ruby Support**: Works on MRI Ruby, JRuby, and TruffleRuby
92
+ - **10 Parsing Backends** - Choose the right backend for your needs:
93
+ - **Tree-sitter Backends** (high-performance, incremental parsing):
94
+ - **MRI Backend**: Leverages [`ruby_tree_sitter`][ruby_tree_sitter] gem (C extension, fastest on MRI)
95
+ - **Rust Backend**: Uses [`tree_stump`][tree_stump] gem (Rust with precompiled binaries)
96
+ - **Note**: `tree_stump` currently requires unreleased fixes in the `main` branch.
97
+ - **FFI Backend**: Pure Ruby FFI bindings to `libtree-sitter` (JRuby only; TruffleRuby's FFI doesn't support tree-sitter's struct-by-value returns)
98
+ - **Java Backend**: Native Java integration for JRuby with [`java-tree-sitter`](https://github.com/tree-sitter/java-tree-sitter) / [`jtreesitter`][jtreesitter] grammar JARs
99
+ - **Language-Specific Backends** (native parser integration):
100
+ - **Prism Backend**: Ruby's official parser ([Prism][prism], stdlib in Ruby 3.4+)
101
+ - **Psych Backend**: Ruby's YAML parser ([Psych][psych], stdlib)
102
+ - **Commonmarker Backend**: Fast Markdown parser ([Commonmarker][commonmarker], comrak Rust)
103
+ - **Markly Backend**: GitHub Flavored Markdown ([Markly][markly], cmark-gfm C)
104
+ - **Pure Ruby Fallback**:
105
+ - **Citrus Backend**: Pure Ruby PEG parsing via [`citrus`][citrus] (no native dependencies)
106
+ - **Parslet Backend**: Pure Ruby PEG parsing via [`parslet`][parslet] (no native dependencies)
107
+ - **Automatic Backend Selection**: Intelligently selects the best backend for your Ruby implementation
108
+ - **Language Agnostic**: Parse any language - Ruby, Markdown, YAML, JSON, Bash, TOML, JavaScript, etc.
109
+ - **Grammar Discovery**: Built-in `GrammarFinder` utility for platform-aware grammar library discovery
110
+ - **Unified Position API**: Consistent `start_line`, `end_line`, `source_position` across all backends
111
+ - **Thread-Safe**: Built-in language registry with thread-safe caching
112
+ - **Minimal API Surface**: Simple, focused API that covers the most common use cases
113
113
 
114
114
  ### Backend Requirements
115
115
 
@@ -142,9 +142,9 @@ gem "ruby_tree_sitter", "~> 2.0"
142
142
 
143
143
  The Rust backend uses [tree\_stump][tree_stump], which is a Rust native extension built with [magnus](https://github.com/matsadler/magnus) and [rb-sys](https://github.com/oxidize-rb/rb-sys). These libraries are only compatible with MRI Ruby's C API.
144
144
 
145
- - **JRuby**: Cannot load native `.so` extensions (runs on JVM)
146
- - **TruffleRuby**: magnus/rb-sys are incompatible with TruffleRuby's C API emulation
147
- NOTE: `tree_stump` currently requires unreleased fixes in the `main` branch.
145
+ - **JRuby**: Cannot load native `.so` extensions (runs on JVM)
146
+ - **TruffleRuby**: magnus/rb-sys are incompatible with TruffleRuby's C API emulation
147
+ NOTE: `tree_stump` currently requires unreleased fixes in the `main` branch.
148
148
 
149
149
  ```ruby
150
150
  # Add to your Gemfile for Rust backend (MRI only)
@@ -157,7 +157,7 @@ gem "tree_stump", github: "joker1007/tree_stump", branch: "main"
157
157
 
158
158
  Requires the `ffi` gem and a system installation of `libtree-sitter`.
159
159
 
160
- - **TruffleRuby**: TruffleRuby's FFI implementation doesn't support `STRUCT_BY_VALUE` return types, which tree-sitter's C API uses for functions like `ts_tree_root_node` and `ts_node_child`.
160
+ - **TruffleRuby**: TruffleRuby's FFI implementation doesn't support `STRUCT_BY_VALUE` return types, which tree-sitter's C API uses for functions like `ts_tree_root_node` and `ts_node_child`.
161
161
 
162
162
  ```ruby
163
163
  # Add to your Gemfile for FFI backend (MRI and JRuby)
@@ -210,8 +210,8 @@ gem "parslet", "~> 2.0"
210
210
 
211
211
  **Also requires**:
212
212
 
213
- - Tree-sitter runtime library (`libtree-sitter.so`) version 0.26+ (must match jtreesitter version)
214
- - Grammar `.so` files built against tree-sitter 0.26+ (or rebuilt with `tree-sitter generate`)
213
+ - Tree-sitter runtime library (`libtree-sitter.so`) version 0.26+ (must match jtreesitter version)
214
+ - Grammar `.so` files built against tree-sitter 0.26+ (or rebuilt with `tree-sitter generate`)
215
215
 
216
216
  ### Version Requirements for Tree-Sitter Backends
217
217
 
@@ -237,11 +237,11 @@ dnf install tree-sitter tree-sitter-devel
237
237
 
238
238
  **The Java backend requires jtreesitter \>= 0.26.0.** This version introduced breaking API changes:
239
239
 
240
- - `Parser.parse()` returns `Optional<Tree>` instead of `Tree`
241
- - `Tree.getRootNode()` returns `Node` directly (not `Optional<Node>`)
242
- - `Node.getChild()`, `getParent()`, `getNextSibling()`, `getPrevSibling()` return `Optional<Node>`
243
- - `Language.load(name)` was removed; use `SymbolLookup` API instead
244
- Older versions of jtreesitter are **NOT supported**.
240
+ - `Parser.parse()` returns `Optional<Tree>` instead of `Tree`
241
+ - `Tree.getRootNode()` returns `Node` directly (not `Optional<Node>`)
242
+ - `Node.getChild()`, `getParent()`, `getNextSibling()`, `getPrevSibling()` return `Optional<Node>`
243
+ - `Language.load(name)` was removed; use `SymbolLookup` API instead
244
+ Older versions of jtreesitter are **NOT supported**.
245
245
 
246
246
  ```bash
247
247
  # Download jtreesitter 0.26.0 from Maven Central
@@ -293,30 +293,27 @@ cc -shared -fPIC -o libtree-sitter-toml.so src/parser.c src/scanner.c -I src
293
293
 
294
294
  TruffleRuby has **no working tree-sitter backend**:
295
295
 
296
- - **FFI**: TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` return types (used by `ts_tree_root_node`, `ts_node_child`, etc.)
297
- - **MRI/Rust**: C and Rust extensions require MRI's C API internals (`RBasic.flags`, `rb_gc_writebarrier`, etc.) that TruffleRuby doesn't expose
298
- TruffleRuby users should use: **Prism** (Ruby), **Psych** (YAML), **Citrus/Parslet** (e.g., TOML via toml-rb/toml), or potentially **Commonmarker/Markly** (Markdown).
296
+ - **FFI**: TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` return types (used by `ts_tree_root_node`, `ts_node_child`, etc.)
297
+ - **MRI/Rust**: C and Rust extensions require MRI's C API internals (`RBasic.flags`, `rb_gc_writebarrier`, etc.) that TruffleRuby doesn't expose
298
+ TruffleRuby users should use: **Prism** (Ruby), **Psych** (YAML), **Citrus/Parslet** (e.g., TOML via toml-rb/toml), or potentially **Commonmarker/Markly** (Markdown).
299
299
 
300
300
  #### JRuby Limitations
301
301
 
302
302
  JRuby runs on the JVM and **cannot load native `.so` extensions via Ruby's C API**:
303
303
 
304
- - **MRI/Rust**: C and Rust extensions simply cannot be loaded
305
- - **FFI**: Works\! JRuby has excellent FFI support
306
- - **Java**: Works\! The Java backend uses jtreesitter (requires \>= 0.26.0)
307
- JRuby users should use: **Java backend** (best performance, full API) or **FFI backend** for tree-sitter, plus **Prism**, **Psych**, **Citrus/Parslet** for other formats.
308
- [ruby\_tree\_sitter][ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
309
- [tree\_stump][tree_stump]: https://github.com/joker1007/tree\_stump
310
- \[jtreesitter\]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
304
+ - **MRI/Rust**: C and Rust extensions simply cannot be loaded
305
+ - **FFI**: Works\! JRuby has excellent FFI support
306
+ - **Java**: Works\! The Java backend uses jtreesitter (requires \>= 0.26.0)
307
+ JRuby users should use: **Java backend** (best performance, full API) or **FFI backend** for tree-sitter, plus **Prism**, **Psych**, **Citrus/Parslet** for other formats.
311
308
 
312
309
  ### Why TreeHaver?
313
310
 
314
311
  tree-sitter is a powerful parser generator that creates incremental parsers for many programming languages. However, integrating it into Ruby applications can be challenging:
315
312
 
316
- - MRI-based C extensions don't work on JRuby
317
- - FFI-based solutions may not be optimal for MRI
318
- - Managing different backends for different Ruby implementations is cumbersome
319
- TreeHaver solves these problems by providing a unified API that automatically selects the appropriate backend for your Ruby implementation, allowing you to write code once and run it anywhere.
313
+ - MRI-based C extensions don't work on JRuby
314
+ - FFI-based solutions may not be optimal for MRI
315
+ - Managing different backends for different Ruby implementations is cumbersome
316
+ TreeHaver solves these problems by providing a unified API that automatically selects the appropriate backend for your Ruby implementation, allowing you to write code once and run it anywhere.
320
317
 
321
318
  ### The `*-merge` Gem Family
322
319
 
@@ -324,7 +321,7 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
324
321
 
325
322
  | Gem | Version | CI | | Language<br>/ Format | Parser Backend(s) | Description |
326
323
  |------------------------------------------|----------------------------------------------------------------|--------------------------------------------------------------|----------|-------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|-------------|
327
- | [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] | [![Version][tree_haver-ci-i]][tree_haver-ci] | Multi | MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
324
+ | [tree_haver][tree_haver] | [![Version][tree_haver-gem-i]][tree_haver-gem] | [![Version][tree_haver-ci-i]][tree_haver-ci] | Multi | Supported Backends: MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus, Parslet | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
328
325
  | [ast-merge][ast-merge] | [![Version][ast-merge-gem-i]][ast-merge-gem] | [![Version][ast-merge-ci-i]][ast-merge-ci] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
329
326
  | [bash-merge][bash-merge] | [![Version][bash-merge-gem-i]][bash-merge-gem] | [![Version][bash-merge-ci-i]][bash-merge-ci] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
330
327
  | [commonmarker-merge][commonmarker-merge] | [![Version][commonmarker-merge-gem-i]][commonmarker-merge-gem] | [![Version][commonmarker-merge-ci-i]][commonmarker-merge-ci] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
@@ -342,18 +339,18 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
342
339
 
343
340
  tree_haver supports multiple parsing backends, but not all backends work on all Ruby platforms:
344
341
 
345
- | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
346
- |------------------------------------------------|:---:|:-----:|:-----------:|-----------------------------------------------------|
347
- | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
348
- | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
349
- | **FFI** | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
350
- | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
351
- | **Prism** | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
352
- | **Psych** | ✅ | ✅ | ✅ | YAML parsing, stdlib |
353
- | **Citrus** | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
354
- | **Parslet** | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
355
- | **Commonmarker** | ✅ | ❌ | ❓ | Rust extension for Markdown |
356
- | **Markly** | ✅ | ❌ | ❓ | C extension for Markdown |
342
+ | Platform 👉️<br> TreeHaver Backend 👇️ | MRI | JRuby | TruffleRuby | Notes |
343
+ |-------------------------------------------------|:---:|:-----:|:-----------:|----------------------------------------------------------------------------|
344
+ | **MRI** ([ruby_tree_sitter][ruby_tree_sitter]) | ✅ | ❌ | ❌ | C extension, MRI only |
345
+ | **Rust** ([tree_stump][tree_stump]) | ✅ | ❌ | ❌ | Rust extension via magnus/rb-sys, MRI only |
346
+ | **FFI** ([ffi][ffi]) | ✅ | ✅ | ❌ | TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` |
347
+ | **Java** ([jtreesitter][jtreesitter]) | ❌ | ✅ | ❌ | JRuby only, requires grammar JARs |
348
+ | **Prism** ([prism][prism]) | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
349
+ | **Psych** ([psych][psych]) | ✅ | ✅ | ✅ | YAML parsing, stdlib |
350
+ | **Citrus** ([citrus][citrus]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
351
+ | **Parslet** ([parslet][parslet]) | ✅ | ✅ | ✅ | Pure Ruby PEG parser, no native dependencies |
352
+ | **Commonmarker** ([commonmarker][commonmarker]) | ✅ | ❌ | ❓ | Rust extension for Markdown (via [commonmarker-merge][commonmarker-merge]) |
353
+ | **Markly** ([markly][markly]) | ✅ | ❌ | ❓ | C extension for Markdown (via [markly-merge][markly-merge]) |
357
354
 
358
355
  **Legend**: ✅ = Works, ❌ = Does not work, ❓ = Untested
359
356
 
@@ -447,6 +444,7 @@ tree_haver supports multiple parsing backends, but not all backends work on all
447
444
  [kettle-jem-ci]: https://github.com/kettle-rb/kettle-jem/actions/workflows/current.yml
448
445
  [prism]: https://github.com/ruby/prism
449
446
  [psych]: https://github.com/ruby/psych
447
+ [ffi]: https://github.com/ffi/ffi
450
448
  [ts-json]: https://github.com/tree-sitter/tree-sitter-json
451
449
  [ts-jsonc]: https://gitlab.com/WhyNotHugo/tree-sitter-jsonc
452
450
  [ts-bash]: https://github.com/tree-sitter/tree-sitter-bash
@@ -461,30 +459,27 @@ tree_haver supports multiple parsing backends, but not all backends work on all
461
459
  [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
462
460
  [tree_stump]: https://github.com/joker1007/tree_stump
463
461
  [jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
462
+ [citrus]: https://github.com/mjackson/citrus
463
+ [parslet]: https://github.com/kschiess/parslet
464
464
 
465
465
  ### Comparison with Other Ruby AST / Parser Bindings
466
466
 
467
- | Feature | [tree\_haver][📜src-gh] (this gem) | [ruby\_tree\_sitter][ruby_tree_sitter] | [tree\_stump][tree_stump] | [citrus][citrus] | [parslet][parslet] |
468
- |---------------------------|-----------------------------------------------|----------------------------------------|---------------------------|------------------|--------------------|
469
- | **MRI Ruby** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
470
- | **JRuby** | ✅ Yes (FFI, Java, Citrus, or Parslet backend) | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
471
- | **TruffleRuby** | ✅ Yes (FFI, Citrus, or Parslet) | ❌ No | ❓ Unknown | ✅ Yes | ✅ Yes |
472
- | **Backend** | Multi (MRI C, Rust, FFI, Java, Citrus, Parslet) | C extension only | Rust extension | Pure Ruby | Pure Ruby |
473
- | **Incremental Parsing** | ✅ Via MRI C/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
474
- | **Query API** | ⚡ Via MRI/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
475
- | **Grammar Discovery** | ✅ Built-in `GrammarFinder` | ❌ Manual | ❌ Manual | ❌ Manual | ❌ Manual |
476
- | **Security Validations** | ✅ `PathValidator` | ❌ No | ❌ No | ❌ No | ❌ No |
477
- | **Language Registration** | ✅ Thread-safe registry | ❌ No | ❌ No | ❌ No | ❌ No |
478
- | **Native Performance** | ⚡ Backend-dependent | ✅ Native C | ✅ Native Rust | ❌ Pure Ruby | ❌ Pure Ruby |
479
- | **Precompiled Binaries** | ⚡ Via Rust backend | ✅ Yes | ✅ Yes | ✅ Pure Ruby | ✅ Pure Ruby |
480
- | **Zero Native Deps** | ⚡ Via Citrus/Parslet backend | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
481
- | **Minimum Ruby** | 3.2+ | 3.0+ | 3.1+ | 0+ | 0+ |
467
+ | Feature | [tree\_haver][📜src-gh] (this gem) | [ruby\_tree\_sitter][ruby_tree_sitter] | [tree\_stump][tree_stump] | [citrus][citrus] | [parslet][parslet] |
468
+ |---------------------------|-------------------------------------------------|----------------------------------------|---------------------------|------------------|--------------------|
469
+ | **MRI Ruby** | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes |
470
+ | **JRuby** | ✅ Yes (FFI, Java, Citrus, or Parslet backend) | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
471
+ | **TruffleRuby** | ✅ Yes (FFI, Citrus, or Parslet) | ❌ No | ❓ Unknown | ✅ Yes | ✅ Yes |
472
+ | **Backend** | Multi (MRI C, Rust, FFI, Java, Citrus, Parslet) | C extension only | Rust extension | Pure Ruby | Pure Ruby |
473
+ | **Incremental Parsing** | ✅ Via MRI C/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
474
+ | **Query API** | ⚡ Via MRI/Rust/Java backend | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
475
+ | **Grammar Discovery** | ✅ Built-in `GrammarFinder` | ❌ Manual | ❌ Manual | ❌ Manual | ❌ Manual |
476
+ | **Security Validations** | ✅ `PathValidator` | ❌ No | ❌ No | ❌ No | ❌ No |
477
+ | **Language Registration** | ✅ Thread-safe registry | ❌ No | ❌ No | ❌ No | ❌ No |
478
+ | **Native Performance** | ⚡ Backend-dependent | ✅ Native C | ✅ Native Rust | ❌ Pure Ruby | ❌ Pure Ruby |
479
+ | **Precompiled Binaries** | ⚡ Via Rust backend | ✅ Yes | ✅ Yes | ✅ Pure Ruby | ✅ Pure Ruby |
480
+ | **Zero Native Deps** | ⚡ Via Citrus/Parslet backend | ❌ No | ❌ No | ✅ Yes | ✅ Yes |
481
+ | **Minimum Ruby** | 3.2+ | 3.0+ | 3.1+ | 0+ | 0+ |
482
482
 
483
- [ruby_tree_sitter]: https://github.com/Faveod/ruby-tree-sitter
484
- [tree_stump]: https://github.com/joker1007/tree_stump
485
- [citrus]: https://github.com/mjackson/citrus
486
- [parslet]: https://github.com/kschiess/parslet
487
- [tree_haver]: https://github.com/kettle-rb/tree_haver
488
483
  **Note:** Java backend works with grammar `.so` files built against tree-sitter 0.24+. The grammars must be rebuilt with `tree-sitter generate` if they were compiled against older tree-sitter versions. FFI is recommended for JRuby as it's easier to set up.
489
484
 
490
485
  **Note:** TreeHaver can use `ruby_tree_sitter` (MRI) or `tree_stump` (MRI) as backends, or `java-tree-sitter` / `jtreesitter` \>= 0.26.0 ([docs](https://tree-sitter.github.io/java-tree-sitter/), [maven][jtreesitter], [source](https://github.com/tree-sitter/java-tree-sitter), JRuby), or FFI on any backend, giving you TreeHaver's unified API, grammar discovery, and security features, plus full access to incremental parsing when using those backends.
@@ -525,18 +520,18 @@ tree_haver supports multiple parsing backends, but not all backends work on all
525
520
 
526
521
  ## 💡 Info you can shake a stick at
527
522
 
528
- | Tokens to Remember | [![Gem name][⛳️name-img]](https://bestgems.org/gems/tree_haver) [![Gem namespace][⛳️namespace-img]](https://github.com/kettle-rb/tree_haver) |
523
+ | Tokens to Remember | [![Gem name][⛳️name-img]][👽dl-rank] [![Gem namespace][⛳️namespace-img]][📜src-gh] |
529
524
  |-------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
530
- | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]](https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml) [![JRuby HEAD Compat][💎jruby-headi]](https://github.com/kettle-rb/tree_haver/actions/workflows/heads.yml) |
531
- | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]](https://github.com/kettle-rb/tree_haver/actions/workflows/truffle.yml) [![Truffle Ruby 24.1 Compat][💎truby-c-i]](https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml) |
532
- | Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]](https://github.com/kettle-rb/tree_haver/actions/workflows/supported.yml) [![Ruby 3.3 Compat][💎ruby-3.3i]](https://github.com/kettle-rb/tree_haver/actions/workflows/supported.yml) [![Ruby 3.4 Compat][💎ruby-c-i]](https://github.com/kettle-rb/tree_haver/actions/workflows/current.yml) [![Ruby HEAD Compat][💎ruby-headi]](https://github.com/kettle-rb/tree_haver/actions/workflows/heads.yml) |
533
- | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]](https://app.daily.dev/squads/rubyfriends) [![Live Chat on Discord][✉️discord-invite-img-ftb]](https://discord.gg/3qme4XHNKN) [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share) [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github) |
534
- | Source | [![Source on GitLab.com][📜src-gl-img]](https://gitlab.com/kettle-rb/tree_haver/) [![Source on CodeBerg.org][📜src-cb-img]](https://codeberg.org/kettle-rb/tree_haver) [![Source on Github.com][📜src-gh-img]](https://github.com/kettle-rb/tree_haver) [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-2.484-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)](https://www.youtube.com/watch?v=dQw4w9WgXcQ) |
535
- | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]](http://rubydoc.info/gems/tree_haver) [![YARD on Galtzo.com][📜docs-head-rd-img]](https://tree-haver.galtzo.com) [![Maintainer Blog][🚂maint-blog-img]](http://www.railsbling.com/tags/tree_haver) [![GitLab Wiki][📜gl-wiki-img]](https://gitlab.com/kettle-rb/tree_haver/-/wikis/home) [![GitHub Wiki][📜gh-wiki-img]](https://github.com/kettle-rb/tree_haver/wiki) |
536
- | Compliance | [![License: MIT][📄license-img]](https://opensource.org/licenses/MIT) [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]](https://dev.to/galtzo/how-to-check-license-compatibility-41h0) [![📄ilo-declaration-img][📄ilo-declaration-img]](https://www.ilo.org/declaration/lang--en/index.htm) [![Security Policy][🔐security-img]](SECURITY.md) [![Contributor Covenant 2.1][🪇conduct-img]](CODE_OF_CONDUCT.md) [![SemVer 2.0.0][📌semver-img]](https://semver.org/spec/v2.0.0.html) |
537
- | Style | [![Enforced Code Style Linter][💎rlts-img]](https://github.com/rubocop-lts/rubocop-lts) [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]](https://keepachangelog.com/en/1.0.0/) [![Gitmoji Commits][📌gitmoji-img]](https://gitmoji.dev) [![Compatibility appraised by: appraisal2][💎appraisal2-img]](https://github.com/appraisal-rb/appraisal2) |
538
- | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]](http://www.linkedin.com/in/peterboling) [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]](https://ruby.social/@galtzo) [![Follow Me on Bluesky][💖🦋bluesky-img]](https://bsky.app/profile/galtzo.com) [![Contact Maintainer][🚂maint-contact-img]](http://www.railsbling.com/contact) [![My technical writing][💖💁🏼‍♂️devto-img]](https://dev.to/galtzo) |
539
- | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]](https://wellfound.com/u/peter-boling) [![Find Me on CrunchBase][💖💲crunchbase-img]](https://www.crunchbase.com/person/peter-boling) [![My LinkTree][💖🌳linktree-img]](https://linktr.ee/galtzo) [![More About Me][💖💁🏼‍♂️aboutme-img]](https://about.me/peter.boling) [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
525
+ | Works with JRuby | [![JRuby 10.0 Compat][💎jruby-c-i]][🚎11-c-wf] [![JRuby HEAD Compat][💎jruby-headi]][🚎3-hd-wf] |
526
+ | Works with Truffle Ruby | [![Truffle Ruby 23.1 Compat][💎truby-23.1i]][🚎9-t-wf] [![Truffle Ruby 24.1 Compat][💎truby-c-i]][🚎11-c-wf] |
527
+ | Works with MRI Ruby 3 | [![Ruby 3.2 Compat][💎ruby-3.2i]][🚎6-s-wf] [![Ruby 3.3 Compat][💎ruby-3.3i]][🚎6-s-wf] [![Ruby 3.4 Compat][💎ruby-c-i]][🚎11-c-wf] [![Ruby HEAD Compat][💎ruby-headi]][🚎3-hd-wf] |
528
+ | Support & Community | [![Join Me on Daily.dev's RubyFriends][✉️ruby-friends-img]][✉️ruby-friends] [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork] [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor] |
529
+ | Source | [![Source on GitLab.com][📜src-gl-img]][📜src-gl] [![Source on CodeBerg.org][📜src-cb-img]][📜src-cb] [![Source on Github.com][📜src-gh-img]][📜src-gh] [![The best SHA: dQw4w9WgXcQ\!](https://img.shields.io/badge/KLOC-2.484-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue)][🧮kloc] |
530
+ | Documentation | [![Current release on RubyDoc.info][📜docs-cr-rd-img]][🚎yard-current] [![YARD on Galtzo.com][📜docs-head-rd-img]][🚎yard-head] [![Maintainer Blog][🚂maint-blog-img]][🚂maint-blog] [![GitLab Wiki][📜gl-wiki-img]][📜gl-wiki] [![GitHub Wiki][📜gh-wiki-img]][📜gh-wiki] |
531
+ | Compliance | [![License: MIT][📄license-img]][📄license-ref] [![Compatible with Apache Software Projects: Verified by SkyWalking Eyes][📄license-compat-img]][📄license-compat] [![📄ilo-declaration-img][📄ilo-declaration-img]][📄ilo-declaration] [![Security Policy][🔐security-img]][🔐security] [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct] [![SemVer 2.0.0][📌semver-img]][📌semver] |
532
+ | Style | [![Enforced Code Style Linter][💎rlts-img]][💎rlts] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog] [![Gitmoji Commits][📌gitmoji-img]][📌gitmoji] [![Compatibility appraised by: appraisal2][💎appraisal2-img]][💎appraisal2] |
533
+ | Maintainer 🎖️ | [![Follow Me on LinkedIn][💖🖇linkedin-img]][💖🖇linkedin] [![Follow Me on Ruby.Social][💖🐘ruby-mast-img]][💖🐘ruby-mast] [![Follow Me on Bluesky][💖🦋bluesky-img]][💖🦋bluesky] [![Contact Maintainer][🚂maint-contact-img]][🚂maint-contact] [![My technical writing][💖💁🏼‍♂️devto-img]][💖💁🏼‍♂️devto] |
534
+ | `...` 💖 | [![Find Me on WellFound:][💖✌️wellfound-img]][💖✌️wellfound] [![Find Me on CrunchBase][💖💲crunchbase-img]][💖💲crunchbase] [![My LinkTree][💖🌳linktree-img]][💖🌳linktree] [![More About Me][💖💁🏼‍♂️aboutme-img]][💖💁🏼‍♂️aboutme] [🧊][💖🧊berg] [🐙][💖🐙hub] [🛖][💖🛖hut] [🧪][💖🧪lab] |
540
535
 
541
536
  ### Compatibility
542
537
 
@@ -556,13 +551,13 @@ Compatible with MRI Ruby 3.2.0+, and concordant releases of JRuby, and TruffleRu
556
551
  | 🧪 [kettle-rb/tree\_haver on GitLab][📜src-gl] | The Truth | [💚][🤝gl-issues] | [💚][🤝gl-pulls] | [💚][📜gl-wiki] | 🐭 Tiny Matrix | ➖ |
557
552
  | 🧊 [kettle-rb/tree\_haver on CodeBerg][📜src-cb] | An Ethical Mirror ([Donate][🤝cb-donate]) | [💚][🤝cb-issues] | [💚][🤝cb-pulls] | ➖ | ⭕️ No Matrix | ➖ |
558
553
  | 🐙 [kettle-rb/tree\_haver on GitHub][📜src-gh] | Another Mirror | [💚][🤝gh-issues] | [💚][🤝gh-pulls] | [💚][📜gh-wiki] | 💯 Full Matrix | [💚][gh-discussions] |
559
- | 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]](https://discord.gg/3qme4XHNKN) | [Let's][🖼️galtzo-discord] | [talk][🖼️galtzo-discord] | [about][🖼️galtzo-discord] | [this][🖼️galtzo-discord] | [library\!][🖼️galtzo-discord] |
554
+ | 🎮️ [Discord Server][🖼️galtzo-discord] | [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord] | [Let's][🖼️galtzo-discord] | [talk][🖼️galtzo-discord] | [about][🖼️galtzo-discord] | [this][🖼️galtzo-discord] | [library\!][🖼️galtzo-discord] |
560
555
 
561
556
  </details>
562
557
 
563
558
  [gh-discussions]: https://github.com/kettle-rb/tree_haver/discussions
564
559
 
565
- ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/tree_haver)](https://tidelift.com/subscription/pkg/rubygems-tree_haver?utm_source=rubygems-tree_haver&utm_medium=referral&utm_campaign=readme)
560
+ ### Enterprise Support [![Tidelift](https://tidelift.com/badges/package/rubygems/tree_haver)][🏙️entsup-tidelift]
566
561
 
567
562
  Available as part of the Tidelift Subscription.
568
563
 
@@ -571,20 +566,20 @@ Available as part of the Tidelift Subscription.
571
566
 
572
567
  The maintainers of this and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
573
568
 
574
- [![Get help from me on Tidelift][🏙️entsup-tidelift-img]](https://tidelift.com/subscription/pkg/rubygems-tree_haver?utm_source=rubygems-tree_haver&utm_medium=referral&utm_campaign=readme)
569
+ [![Get help from me on Tidelift][🏙️entsup-tidelift-img]][🏙️entsup-tidelift]
575
570
 
576
- - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
571
+ - 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
577
572
 
578
- - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
573
+ - 💡Tidelift is part of [Sonar][🏙️entsup-tidelift-sonar]
579
574
 
580
- - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
581
- Alternatively:
575
+ - 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support][🏙️entsup-tidelift] subscription is "[never gonna let you down][🧮kloc]", and *supports* open source maintainers
576
+ Alternatively:
582
577
 
583
- - [![Live Chat on Discord][✉️discord-invite-img-ftb]](https://discord.gg/3qme4XHNKN)
578
+ - [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
584
579
 
585
- - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share)
580
+ - [![Get help from me on Upwork][👨🏼‍🏫expsup-upwork-img]][👨🏼‍🏫expsup-upwork]
586
581
 
587
- - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github)
582
+ - [![Get help from me on Codementor][👨🏼‍🏫expsup-codementor-img]][👨🏼‍🏫expsup-codementor]
588
583
 
589
584
  </details>
590
585
 
@@ -668,9 +663,9 @@ TreeHaver supports 10 parsing backends, each with different trade-offs. The `aut
668
663
 
669
664
  **Known Issues:**
670
665
 
671
- - \*MRI + Bash: ABI incompatibility (use FFI instead)
672
- - \*Rust + Bash: Version mismatch (use FFI instead)
673
- **Backend Requirements:**
666
+ - \*MRI + Bash: ABI incompatibility (use FFI instead)
667
+ - \*Rust + Bash: Version mismatch (use FFI instead)
668
+ **Backend Requirements:**
674
669
 
675
670
  ```ruby
676
671
  # Tree-sitter backends
@@ -746,10 +741,10 @@ end
746
741
 
747
742
  This is particularly useful for:
748
743
 
749
- - **Testing**: Test the same code with different backends
750
- - **Performance comparison**: Benchmark different backends
751
- - **Fallback scenarios**: Try one backend, fall back to another
752
- - **Thread isolation**: Each thread can use a different backend safely
744
+ - **Testing**: Test the same code with different backends
745
+ - **Performance comparison**: Benchmark different backends
746
+ - **Fallback scenarios**: Try one backend, fall back to another
747
+ - **Thread isolation**: Each thread can use a different backend safely
753
748
 
754
749
  ```ruby
755
750
  # Example: Testing with multiple backends
@@ -782,13 +777,13 @@ TreeHaver provides defense-in-depth validations, but you should understand the r
782
777
 
783
778
  TreeHaver's `PathValidator` module protects against:
784
779
 
785
- - **Path traversal**: Paths containing `/../` or `/./` are rejected
786
- - **Null byte injection**: Paths containing null bytes are rejected
787
- - **Non-absolute paths**: Relative paths are rejected to prevent CWD-based attacks
788
- - **Invalid extensions**: Only `.so`, `.dylib`, and `.dll` files are accepted
789
- - **Malicious filenames**: Filenames must match a safe pattern (alphanumeric, hyphens, underscores)
790
- - **Invalid language names**: Language names must be lowercase alphanumeric with underscores
791
- - **Invalid symbol names**: Symbol names must be valid C identifiers
780
+ - **Path traversal**: Paths containing `/../` or `/./` are rejected
781
+ - **Null byte injection**: Paths containing null bytes are rejected
782
+ - **Non-absolute paths**: Relative paths are rejected to prevent CWD-based attacks
783
+ - **Invalid extensions**: Only `.so`, `.dylib`, and `.dll` files are accepted
784
+ - **Malicious filenames**: Filenames must match a safe pattern (alphanumeric, hyphens, underscores)
785
+ - **Invalid language names**: Language names must be lowercase alphanumeric with underscores
786
+ - **Invalid symbol names**: Symbol names must be valid C identifiers
792
787
 
793
788
  #### Secure Usage
794
789
 
@@ -816,12 +811,12 @@ The `find_library_path_safe` method only returns paths in trusted directories.
816
811
 
817
812
  **Default trusted directories:**
818
813
 
819
- - `/usr/lib`, `/usr/lib64`
820
- - `/usr/lib/x86_64-linux-gnu`, `/usr/lib/aarch64-linux-gnu`
821
- - `/usr/local/lib`
822
- - `/opt/homebrew/lib`, `/opt/local/lib`
823
- **Adding custom trusted directories:**
824
- For non-standard installations (Homebrew on Linux, luarocks, mise, asdf, etc.), register additional trusted directories:
814
+ - `/usr/lib`, `/usr/lib64`
815
+ - `/usr/lib/x86_64-linux-gnu`, `/usr/lib/aarch64-linux-gnu`
816
+ - `/usr/local/lib`
817
+ - `/opt/homebrew/lib`, `/opt/local/lib`
818
+ **Adding custom trusted directories:**
819
+ For non-standard installations (Homebrew on Linux, luarocks, mise, asdf, etc.), register additional trusted directories:
825
820
 
826
821
  ```ruby
827
822
  # Programmatically at application startup
@@ -951,29 +946,29 @@ TreeHaver recognizes several environment variables for configuration:
951
946
 
952
947
  #### Security Configuration
953
948
 
954
- - **`TREE_HAVER_TRUSTED_DIRS`**: Comma-separated list of additional trusted directories for grammar libraries
949
+ - **`TREE_HAVER_TRUSTED_DIRS`**: Comma-separated list of additional trusted directories for grammar libraries
955
950
 
956
- ```bash
957
- # For Homebrew on Linux and luarocks
958
- export TREE_HAVER_TRUSTED_DIRS="/home/linuxbrew/.linuxbrew/Cellar,~/.local/share/mise/installs/lua"
959
- ```
951
+ ```bash
952
+ # For Homebrew on Linux and luarocks
953
+ export TREE_HAVER_TRUSTED_DIRS="/home/linuxbrew/.linuxbrew/Cellar,~/.local/share/mise/installs/lua"
954
+ ```
960
955
 
961
- Tilde (`~`) is expanded to the user's home directory. Directories listed here are considered safe for `find_library_path_safe`.
956
+ Tilde (`~`) is expanded to the user's home directory. Directories listed here are considered safe for `find_library_path_safe`.
962
957
 
963
958
  #### Core Runtime Library
964
959
 
965
- - **`TREE_SITTER_RUNTIME_LIB`**: Absolute path to the core `libtree-sitter` shared library
966
- ```bash
967
- export TREE_SITTER_RUNTIME_LIB=/usr/local/lib/libtree-sitter.so
968
- ```
960
+ - **`TREE_SITTER_RUNTIME_LIB`**: Absolute path to the core `libtree-sitter` shared library
961
+ ```bash
962
+ export TREE_SITTER_RUNTIME_LIB=/usr/local/lib/libtree-sitter.so
963
+ ```
969
964
 
970
965
  If not set, TreeHaver tries these names in order:
971
966
 
972
- - `tree-sitter`
973
- - `libtree-sitter.so.0`
974
- - `libtree-sitter.so`
975
- - `libtree-sitter.dylib`
976
- - `libtree-sitter.dll`
967
+ - `tree-sitter`
968
+ - `libtree-sitter.so.0`
969
+ - `libtree-sitter.so`
970
+ - `libtree-sitter.dylib`
971
+ - `libtree-sitter.dll`
977
972
 
978
973
  #### Language Symbol Resolution
979
974
 
@@ -1245,10 +1240,10 @@ end
1245
1240
  **Why inherit from Exception?**
1246
1241
  Following ruby\_tree\_sitter's reasoning:
1247
1242
 
1248
- - **Thread safety**: Prevents accidental catching in thread cleanup code
1249
- - **Signal handling**: Ensures parsing errors don't interfere with SIGTERM/SIGINT
1250
- - **Intentional handling**: Forces developers to explicitly handle parsing errors
1251
- See `lib/tree_haver/compat.rb` for compatibility layer documentation.
1243
+ - **Thread safety**: Prevents accidental catching in thread cleanup code
1244
+ - **Signal handling**: Ensures parsing errors don't interfere with SIGTERM/SIGINT
1245
+ - **Intentional handling**: Forces developers to explicitly handle parsing errors
1246
+ See `lib/tree_haver/compat.rb` for compatibility layer documentation.
1252
1247
 
1253
1248
  ## 🔧 Basic Usage
1254
1249
 
@@ -1686,11 +1681,11 @@ end
1686
1681
 
1687
1682
  **⚠️ Citrus Backend Limitations:**
1688
1683
 
1689
- - Uses Citrus grammars (not tree-sitter grammars)
1690
- - No incremental parsing support
1691
- - No query API
1692
- - Pure Ruby performance (slower than native backends)
1693
- - Best for: prototyping, environments without native extension support, teaching
1684
+ - Uses Citrus grammars (not tree-sitter grammars)
1685
+ - No incremental parsing support
1686
+ - No query API
1687
+ - Pure Ruby performance (slower than native backends)
1688
+ - Best for: prototyping, environments without native extension support, teaching
1694
1689
 
1695
1690
  ##### Option 4: Parslet Backend (pure Ruby, portable)
1696
1691
 
@@ -1712,11 +1707,11 @@ end
1712
1707
 
1713
1708
  **⚠️ Parslet Backend Limitations:**
1714
1709
 
1715
- - Uses Parslet grammars (not tree-sitter grammars)
1716
- - No incremental parsing support
1717
- - No query API
1718
- - Pure Ruby performance (slower than native backends)
1719
- - Best for: prototyping, environments without native extension support, teaching
1710
+ - Uses Parslet grammars (not tree-sitter grammars)
1711
+ - No incremental parsing support
1712
+ - No query API
1713
+ - Pure Ruby performance (slower than native backends)
1714
+ - Best for: prototyping, environments without native extension support, teaching
1720
1715
 
1721
1716
  #### TruffleRuby
1722
1717
 
@@ -2033,7 +2028,7 @@ I’m developing a new library, [floss\_funding][🖇floss-funding-gem], designe
2033
2028
 
2034
2029
  **[Floss-Funding.dev][🖇floss-funding.dev]: 👉️ No network calls. 👉️ No tracking. 👉️ No oversight. 👉️ Minimal crypto hashing. 💡 Easily disabled nags**
2035
2030
 
2036
- [![OpenCollective Backers][🖇osc-backers-i]](https://opencollective.com/kettle-rb#backer) [![OpenCollective Sponsors][🖇osc-sponsors-i]](https://opencollective.com/kettle-rb#sponsor) [![Sponsor Me on Github][🖇sponsor-img]](https://github.com/sponsors/pboling) [![Liberapay Goal Progress][⛳liberapay-img]](https://liberapay.com/pboling/donate) [![Donate on PayPal][🖇paypal-img]](https://www.paypal.com/paypalme/peterboling) [![Buy me a coffee][🖇buyme-small-img]](https://www.buymeacoffee.com/pboling) [![Donate on Polar][🖇polar-img]](https://polar.sh/pboling) [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]](https://ko-fi.com/O5O86SNP4) [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]](https://patreon.com/galtzo)
2031
+ [![OpenCollective Backers][🖇osc-backers-i]][🖇osc-backers] [![OpenCollective Sponsors][🖇osc-sponsors-i]][🖇osc-sponsors] [![Sponsor Me on Github][🖇sponsor-img]][🖇sponsor] [![Liberapay Goal Progress][⛳liberapay-img]][⛳liberapay] [![Donate on PayPal][🖇paypal-img]][🖇paypal] [![Buy me a coffee][🖇buyme-small-img]][🖇buyme] [![Donate on Polar][🖇polar-img]][🖇polar] [![Donate to my FLOSS efforts at ko-fi.com][🖇kofi-img]][🖇kofi] [![Donate to my FLOSS efforts using Patreon][🖇patreon-img]][🖇patreon]
2037
2032
 
2038
2033
  ## 🔐 Security
2039
2034
 
@@ -2045,7 +2040,7 @@ If you need some ideas of where to help, you could work on adding more code cove
2045
2040
  or if it is already 💯 (see [below](#code-coverage)) check [reek](REEK), [issues][🤝gh-issues], or [PRs][🤝gh-pulls],
2046
2041
  or use the gem and think about how it could be better.
2047
2042
 
2048
- We [![Keep A Changelog][📗keep-changelog-img]](https://keepachangelog.com/en/1.0.0/) so if you make changes, remember to update it.
2043
+ We [![Keep A Changelog][📗keep-changelog-img]][📗keep-changelog] so if you make changes, remember to update it.
2049
2044
 
2050
2045
  See [CONTRIBUTING.md][🤝contributing] for more detailed instructions.
2051
2046
 
@@ -2055,20 +2050,20 @@ See [CONTRIBUTING.md][🤝contributing].
2055
2050
 
2056
2051
  ### Code Coverage
2057
2052
 
2058
- [![Coverage Graph][🏀codecov-g]](https://codecov.io/gh/kettle-rb/tree_haver)
2053
+ [![Coverage Graph][🏀codecov-g]][🏀codecov]
2059
2054
 
2060
- [![Coveralls Test Coverage][🏀coveralls-img]](https://coveralls.io/github/kettle-rb/tree_haver?branch=main)
2055
+ [![Coveralls Test Coverage][🏀coveralls-img]][🏀coveralls]
2061
2056
 
2062
- [![QLTY Test Coverage][🏀qlty-covi]](https://qlty.sh/gh/kettle-rb/projects/tree_haver/metrics/code?sort=coverageRating)
2057
+ [![QLTY Test Coverage][🏀qlty-covi]][🏀qlty-cov]
2063
2058
 
2064
2059
  ### 🪇 Code of Conduct
2065
2060
 
2066
2061
  Everyone interacting with this project's codebases, issue trackers,
2067
- chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]](CODE_OF_CONDUCT.md).
2062
+ chat rooms and mailing lists agrees to follow the [![Contributor Covenant 2.1][🪇conduct-img]][🪇conduct].
2068
2063
 
2069
2064
  ## 🌈 Contributors
2070
2065
 
2071
- [![Contributors][🖐contributors-img]](https://github.com/kettle-rb/tree_haver/graphs/contributors)
2066
+ [![Contributors][🖐contributors-img]][🖐contributors]
2072
2067
 
2073
2068
  Made with [contributors-img][🖐contrib-rocks].
2074
2069
 
@@ -2089,7 +2084,7 @@ Also see GitLab Contributors: <https://gitlab.com/kettle-rb/tree_haver/-/graphs/
2089
2084
 
2090
2085
  ## 📌 Versioning
2091
2086
 
2092
- This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]](https://semver.org/spec/v2.0.0.html).
2087
+ This Library adheres to [![Semantic Versioning 2.0.0][📌semver-img]][📌semver].
2093
2088
  Violations of this scheme should be reported as bugs.
2094
2089
  Specifically, if a minor or patch version is released that breaks backward compatibility,
2095
2090
  a new version should be immediately released that restores compatibility.
@@ -2118,7 +2113,7 @@ is a *breaking change* to an API, and for that reason the bike shedding is endle
2118
2113
  To get a better understanding of how SemVer is intended to work over a project's lifetime,
2119
2114
  read this article from the creator of SemVer:
2120
2115
 
2121
- - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
2116
+ - ["Major Version Numbers are Not Sacred"][📌major-versions-not-sacred]
2122
2117
 
2123
2118
  </details>
2124
2119
 
@@ -2127,7 +2122,7 @@ See [CHANGELOG.md][📌changelog] for a list of releases.
2127
2122
  ## 📄 License
2128
2123
 
2129
2124
  The gem is available as open source under the terms of
2130
- the [MIT License][📄license] [![License: MIT][📄license-img]](https://opensource.org/licenses/MIT).
2125
+ the [MIT License][📄license] [![License: MIT][📄license-img]][📄license-ref].
2131
2126
  See [LICENSE.txt][📄license] for the official [Copyright Notice][📄copyright-notice-explainer].
2132
2127
 
2133
2128
  ### © Copyright
@@ -2155,11 +2150,11 @@ Please consider sponsoring me or the project.
2155
2150
 
2156
2151
  To join the community or get help 👇️ Join the Discord.
2157
2152
 
2158
- [![Live Chat on Discord][✉️discord-invite-img-ftb]](https://discord.gg/3qme4XHNKN)
2153
+ [![Live Chat on Discord][✉️discord-invite-img-ftb]][🖼️galtzo-discord]
2159
2154
 
2160
2155
  To say "thanks\!" ☝️ Join the Discord or 👇️ send money.
2161
2156
 
2162
- [![Sponsor kettle-rb/tree\_haver on Open Source Collective][🖇osc-all-bottom-img]](https://opencollective.com/kettle-rb) 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]](https://github.com/sponsors/pboling) 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]](https://liberapay.com/pboling/donate) 💌 [![Donate on PayPal][🖇paypal-bottom-img]](https://www.paypal.com/paypalme/peterboling)
2157
+ [![Sponsor kettle-rb/tree\_haver on Open Source Collective][🖇osc-all-bottom-img]][🖇osc] 💌 [![Sponsor me on GitHub Sponsors][🖇sponsor-bottom-img]][🖇sponsor] 💌 [![Sponsor me on Liberapay][⛳liberapay-bottom-img]][⛳liberapay] 💌 [![Donate on PayPal][🖇paypal-bottom-img]][🖇paypal]
2163
2158
 
2164
2159
  ### Please give the project a star ⭐ ♥.
2165
2160
 
@@ -2323,7 +2318,7 @@ Thanks for RTFM. ☺️
2323
2318
  [📌gitmoji]: https://gitmoji.dev
2324
2319
  [📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
2325
2320
  [🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
2326
- [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.487-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
2321
+ [🧮kloc-img]: https://img.shields.io/badge/KLOC-2.542-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
2327
2322
  [🔐security]: SECURITY.md
2328
2323
  [🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
2329
2324
  [📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year