tree_haver 3.2.4 → 3.2.6
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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +35 -1
- data/README.md +83 -81
- data/lib/tree_haver/backends/commonmarker.rb +7 -6
- data/lib/tree_haver/backends/java.rb +53 -10
- data/lib/tree_haver/backends/markly.rb +10 -4
- data/lib/tree_haver/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6e544c31dc86e71be78cfcf24e7cbf8a779ef954845b736ec37ed6b550ffe714
|
|
4
|
+
data.tar.gz: 54f83ef36c8167f5071db278ce33f2603864d339a9c246a733957da41540eab4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c991da086ba12a279f461f337e7dfa9d0b98d8d6d4f4c5d3d78cc3b848a6174ed42ce71b674e8a2d4ed81c5b17289d6c3903c2ef813db86cd4557a33aa1c1599
|
|
7
|
+
data.tar.gz: 034b9f7df24e5f757013f011b7661559fed243b3fde752d95ab2cac94a0fdfc8270d9ca002d07972c74c1d5455293ac12c7472eacdc106934051cc3231d005b9
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -30,6 +30,36 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [3.2.6] - 2026-01-06
|
|
34
|
+
|
|
35
|
+
- TAG: [v3.2.6][3.2.6t]
|
|
36
|
+
- COVERAGE: 92.07% -- 2230/2422 lines in 23 files
|
|
37
|
+
- BRANCH COVERAGE: 74.69% -- 788/1055 branches in 23 files
|
|
38
|
+
- 90.37% documented
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **Java backend**: Fixed Optional handling in Node methods that could return nil incorrectly
|
|
43
|
+
- `child(index)`, `child_by_field_name(name)`, `parent`, `next_sibling`, `prev_sibling` now properly check for nil before attempting to unwrap Java Optional
|
|
44
|
+
- Previously, the ternary-based Optional check could fail when jtreesitter returned null directly instead of Optional.empty()
|
|
45
|
+
- This fixes JRuby test failures where `key_name` returned nil and object keys were not extracted
|
|
46
|
+
|
|
47
|
+
## [3.2.5] - 2026-01-05
|
|
48
|
+
|
|
49
|
+
- TAG: [v3.2.5][3.2.5t]
|
|
50
|
+
- COVERAGE: 92.07% -- 2230/2422 lines in 23 files
|
|
51
|
+
- BRANCH COVERAGE: 74.69% -- 788/1055 branches in 23 files
|
|
52
|
+
- 90.37% documented
|
|
53
|
+
|
|
54
|
+
### Fixed
|
|
55
|
+
|
|
56
|
+
- **Markly backend**: `Node#text` now correctly handles container nodes (headings, paragraphs, etc.)
|
|
57
|
+
- Previously returned empty string because `string_content` was checked first (responds but returns empty for containers)
|
|
58
|
+
- Now falls through to `to_plaintext` or children concatenation when `string_content` is empty
|
|
59
|
+
- **Commonmarker backend**: `Node#text` now correctly handles container nodes
|
|
60
|
+
- Previously could return empty string in edge cases
|
|
61
|
+
- Now consistently falls through to children concatenation when `string_content` is empty or raises TypeError
|
|
62
|
+
|
|
33
63
|
## [3.2.4] - 2026-01-04
|
|
34
64
|
|
|
35
65
|
- TAG: [v3.2.4][3.2.4t]
|
|
@@ -885,7 +915,11 @@ Despite the major version bump to 3.0.0 (following semver due to the breaking `L
|
|
|
885
915
|
|
|
886
916
|
- Initial release
|
|
887
917
|
|
|
888
|
-
[Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v3.2.
|
|
918
|
+
[Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v3.2.6...HEAD
|
|
919
|
+
[3.2.6]: https://github.com/kettle-rb/tree_haver/compare/v3.2.5...v3.2.6
|
|
920
|
+
[3.2.6t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.6
|
|
921
|
+
[3.2.5]: https://github.com/kettle-rb/tree_haver/compare/v3.2.4...v3.2.5
|
|
922
|
+
[3.2.5t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.5
|
|
889
923
|
[3.2.4]: https://github.com/kettle-rb/tree_haver/compare/v3.2.3...v3.2.4
|
|
890
924
|
[3.2.4t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.4
|
|
891
925
|
[3.2.3]: https://github.com/kettle-rb/tree_haver/compare/v3.2.2...v3.2.3
|
data/README.md
CHANGED
|
@@ -141,8 +141,8 @@ The Rust backend uses [tree\_stump](https://github.com/joker1007/tree_stump), wh
|
|
|
141
141
|
|
|
142
142
|
- **JRuby**: Cannot load native `.so` extensions (runs on JVM)
|
|
143
143
|
- **TruffleRuby**: magnus/rb-sys are incompatible with TruffleRuby's C API emulation
|
|
144
|
-
NOTE: `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
145
|
-
|
|
144
|
+
NOTE: `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
145
|
+
<!-- end list -->
|
|
146
146
|
``` ruby
|
|
147
147
|
# Add to your Gemfile for Rust backend (MRI only)
|
|
148
148
|
gem "tree_stump", github: "joker1007/tree_stump", branch: "main"
|
|
@@ -155,7 +155,6 @@ gem "tree_stump", github: "joker1007/tree_stump", branch: "main"
|
|
|
155
155
|
Requires the `ffi` gem and a system installation of `libtree-sitter`.
|
|
156
156
|
|
|
157
157
|
- **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`.
|
|
158
|
-
|
|
159
158
|
<!-- end list -->
|
|
160
159
|
``` ruby
|
|
161
160
|
# Add to your Gemfile for FFI backend (MRI and JRuby)
|
|
@@ -185,9 +184,9 @@ gem "citrus", "~> 3.0"
|
|
|
185
184
|
|
|
186
185
|
#### Java Backend (JRuby only)
|
|
187
186
|
|
|
188
|
-
**Requires jtreesitter
|
|
187
|
+
**Requires jtreesitter \>= 0.26.0** from Maven Central. Older versions are not supported due to breaking API changes.
|
|
189
188
|
|
|
190
|
-
```ruby
|
|
189
|
+
``` ruby
|
|
191
190
|
# No gem dependency - uses JRuby's built-in Java integration
|
|
192
191
|
# Download the JAR:
|
|
193
192
|
# curl -L -o jtreesitter-0.26.0.jar \
|
|
@@ -198,9 +197,8 @@ gem "citrus", "~> 3.0"
|
|
|
198
197
|
```
|
|
199
198
|
|
|
200
199
|
**Also requires**:
|
|
201
|
-
- Tree-sitter runtime library (`libtree-sitter.so`) version 0.26+ (must match jtreesitter version)
|
|
202
|
-
- Grammar `.so` files built against tree-sitter 0.26+ (or rebuilt with `tree-sitter generate`)
|
|
203
|
-
|
|
200
|
+
- Tree-sitter runtime library (`libtree-sitter.so`) version 0.26+ (must match jtreesitter version)
|
|
201
|
+
- Grammar `.so` files built against tree-sitter 0.26+ (or rebuilt with `tree-sitter generate`)
|
|
204
202
|
### Backend Platform Compatibility
|
|
205
203
|
|
|
206
204
|
Not all backends work on all Ruby platforms. Here's a complete compatibility matrix:
|
|
@@ -210,7 +208,7 @@ Not all backends work on all Ruby platforms. Here's a complete compatibility mat
|
|
|
210
208
|
| **MRI** ([ruby\_tree\_sitter](https://github.com/Faveod/ruby-tree-sitter)) | ✅ | ❌ | ❌ | ✅ | C extension, MRI only |
|
|
211
209
|
| **Rust** ([tree\_stump](https://github.com/joker1007/tree_stump)) | ✅ | ❌ | ❌ | ✅ | magnus/rb-sys incompatible with non-MRI |
|
|
212
210
|
| **FFI** | ✅ | ✅ | ❌ | ⚠️ | TruffleRuby FFI doesn't support `STRUCT_BY_VALUE` |
|
|
213
|
-
| **Java** ([jtreesitter](https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter)) | ❌ | ✅ | ❌ | ✅ | JRuby only, requires jtreesitter
|
|
211
|
+
| **Java** ([jtreesitter](https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter)) | ❌ | ✅ | ❌ | ✅ | JRuby only, requires jtreesitter \>= 0.26.0 |
|
|
214
212
|
| **Prism** | ✅ | ✅ | ✅ | ✅ | Ruby parsing, stdlib in Ruby 3.4+ |
|
|
215
213
|
| **Psych** | ✅ | ✅ | ✅ | ✅ | YAML parsing, stdlib |
|
|
216
214
|
| **Citrus** | ✅ | ✅ | ✅ | ⚠️ | Pure Ruby, no native dependencies |
|
|
@@ -227,7 +225,7 @@ Not all backends work on all Ruby platforms. Here's a complete compatibility mat
|
|
|
227
225
|
|
|
228
226
|
All tree-sitter backends (MRI, Rust, FFI, Java) require the tree-sitter runtime library. **Version 0.26+ is required** for the Java backend (to match jtreesitter 0.26.0). Other backends may work with 0.24+, but 0.26+ is recommended for consistency.
|
|
229
227
|
|
|
230
|
-
```bash
|
|
228
|
+
``` bash
|
|
231
229
|
# Check your tree-sitter version
|
|
232
230
|
tree-sitter --version # Should be 0.26.0 or newer for Java backend
|
|
233
231
|
|
|
@@ -243,16 +241,15 @@ dnf install tree-sitter tree-sitter-devel
|
|
|
243
241
|
|
|
244
242
|
#### jtreesitter (Java Backend)
|
|
245
243
|
|
|
246
|
-
**The Java backend requires jtreesitter
|
|
247
|
-
|
|
248
|
-
- `Parser.parse()` returns `Optional<Tree>` instead of `Tree`
|
|
249
|
-
- `Tree.getRootNode()` returns `Node` directly (not `Optional<Node>`)
|
|
250
|
-
- `Node.getChild()`, `getParent()`, `getNextSibling()`, `getPrevSibling()` return `Optional<Node>`
|
|
251
|
-
- `Language.load(name)` was removed; use `SymbolLookup` API instead
|
|
244
|
+
**The Java backend requires jtreesitter \>= 0.26.0.** This version introduced breaking API changes:
|
|
252
245
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
246
|
+
- `Parser.parse()` returns `Optional<Tree>` instead of `Tree`
|
|
247
|
+
- `Tree.getRootNode()` returns `Node` directly (not `Optional<Node>`)
|
|
248
|
+
- `Node.getChild()`, `getParent()`, `getNextSibling()`, `getPrevSibling()` return `Optional<Node>`
|
|
249
|
+
- `Language.load(name)` was removed; use `SymbolLookup` API instead
|
|
250
|
+
Older versions of jtreesitter are **NOT supported**.
|
|
251
|
+
<!-- end list -->
|
|
252
|
+
``` bash
|
|
256
253
|
# Download jtreesitter 0.26.0 from Maven Central
|
|
257
254
|
curl -L -o jtreesitter-0.26.0.jar \
|
|
258
255
|
"https://repo1.maven.org/maven2/io/github/tree-sitter/jtreesitter/0.26.0/jtreesitter-0.26.0.jar"
|
|
@@ -263,7 +260,7 @@ bin/setup-jtreesitter
|
|
|
263
260
|
|
|
264
261
|
Set the environment variable to point to your JAR directory:
|
|
265
262
|
|
|
266
|
-
```bash
|
|
263
|
+
``` bash
|
|
267
264
|
export TREE_SITTER_JAVA_JARS_DIR=/path/to/jars
|
|
268
265
|
```
|
|
269
266
|
|
|
@@ -273,14 +270,11 @@ export TREE_SITTER_JAVA_JARS_DIR=/path/to/jars
|
|
|
273
270
|
|
|
274
271
|
Tree-sitter 0.24+ changed how language ABI versions are reported (from `ts_language_version()` to `ts_language_abi_version()`). For the Java backend with jtreesitter 0.26.0, grammars must be built against tree-sitter 0.26+. If you get errors like:
|
|
275
272
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
Version mismatch detected: The grammar was built against tree-sitter < 0.26
|
|
279
|
-
```
|
|
280
|
-
|
|
273
|
+
Failed to load tree_sitter_toml
|
|
274
|
+
Version mismatch detected: The grammar was built against tree-sitter < 0.26
|
|
281
275
|
You need to rebuild the grammar from source:
|
|
282
276
|
|
|
283
|
-
```bash
|
|
277
|
+
``` bash
|
|
284
278
|
# Use the provided build script
|
|
285
279
|
bin/build-grammar toml
|
|
286
280
|
|
|
@@ -306,21 +300,18 @@ TruffleRuby has **no working tree-sitter backend**:
|
|
|
306
300
|
|
|
307
301
|
- **FFI**: TruffleRuby's FFI doesn't support `STRUCT_BY_VALUE` return types (used by `ts_tree_root_node`, `ts_node_child`, etc.)
|
|
308
302
|
- **MRI/Rust**: C and Rust extensions require MRI's C API internals (`RBasic.flags`, `rb_gc_writebarrier`, etc.) that TruffleRuby doesn't expose
|
|
309
|
-
TruffleRuby users should use: **Prism** (Ruby), **Psych** (YAML), **Citrus** (TOML via toml-rb), or potentially **Commonmarker/Markly** (Markdown).
|
|
310
|
-
|
|
303
|
+
TruffleRuby users should use: **Prism** (Ruby), **Psych** (YAML), **Citrus** (TOML via toml-rb), or potentially **Commonmarker/Markly** (Markdown).
|
|
311
304
|
#### JRuby Limitations
|
|
312
305
|
|
|
313
306
|
JRuby runs on the JVM and **cannot load native `.so` extensions via Ruby's C API**:
|
|
314
307
|
|
|
315
308
|
- **MRI/Rust**: C and Rust extensions simply cannot be loaded
|
|
316
309
|
- **FFI**: Works\! JRuby has excellent FFI support
|
|
317
|
-
- **Java**: Works\! The Java backend uses jtreesitter (requires
|
|
318
|
-
JRuby users should use: **Java backend** (best performance, full API) or **FFI backend** for tree-sitter, plus **Prism**, **Psych**, **Citrus** for other formats.
|
|
319
|
-
|
|
320
|
-
[
|
|
321
|
-
[
|
|
322
|
-
[jtreesitter]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
|
|
323
|
-
|
|
310
|
+
- **Java**: Works\! The Java backend uses jtreesitter (requires \>= 0.26.0)
|
|
311
|
+
JRuby users should use: **Java backend** (best performance, full API) or **FFI backend** for tree-sitter, plus **Prism**, **Psych**, **Citrus** for other formats.
|
|
312
|
+
[ruby\_tree\_sitter](https://github.com/Faveod/ruby-tree-sitter): https://github.com/Faveod/ruby-tree-sitter
|
|
313
|
+
[tree\_stump](https://github.com/joker1007/tree_stump): https://github.com/joker1007/tree\_stump
|
|
314
|
+
\[jtreesitter\]: https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter
|
|
324
315
|
### Why TreeHaver?
|
|
325
316
|
|
|
326
317
|
tree-sitter is a powerful parser generator that creates incremental parsers for many programming languages. However, integrating it into Ruby applications can be challenging:
|
|
@@ -328,28 +319,27 @@ tree-sitter is a powerful parser generator that creates incremental parsers for
|
|
|
328
319
|
- MRI-based C extensions don't work on JRuby
|
|
329
320
|
- FFI-based solutions may not be optimal for MRI
|
|
330
321
|
- Managing different backends for different Ruby implementations is cumbersome
|
|
331
|
-
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.
|
|
332
|
-
|
|
322
|
+
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.
|
|
333
323
|
|
|
334
324
|
### The `*-merge` Gem Family
|
|
335
325
|
|
|
336
326
|
The `*-merge` gem family provides intelligent, AST-based merging for various file formats. At the foundation is [tree_haver][tree_haver], which provides a unified cross-Ruby parsing API that works seamlessly across MRI, JRuby, and TruffleRuby.
|
|
337
327
|
|
|
338
|
-
| Gem | Format
|
|
339
|
-
|
|
340
|
-
| [tree_haver][tree_haver] | Multi
|
|
341
|
-
| [ast-merge][ast-merge] | Text
|
|
342
|
-
| [
|
|
343
|
-
| [
|
|
344
|
-
| [
|
|
345
|
-
| [
|
|
346
|
-
| [
|
|
347
|
-
| [
|
|
348
|
-
| [
|
|
349
|
-
| [
|
|
350
|
-
| [
|
|
351
|
-
| [
|
|
352
|
-
| [
|
|
328
|
+
| Gem | Language<br>/ Format | Parser Backend(s) | Description |
|
|
329
|
+
|------------------------------------------|----------------------|-----------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------|
|
|
330
|
+
| [tree_haver][tree_haver] | Multi | MRI C, Rust, FFI, Java, Prism, Psych, Commonmarker, Markly, Citrus | **Foundation**: Cross-Ruby adapter for parsing libraries (like Faraday for HTTP) |
|
|
331
|
+
| [ast-merge][ast-merge] | Text | internal | **Infrastructure**: Shared base classes and merge logic for all `*-merge` gems |
|
|
332
|
+
| [bash-merge][bash-merge] | Bash | [tree-sitter-bash][ts-bash] (via tree_haver) | Smart merge for Bash scripts |
|
|
333
|
+
| [commonmarker-merge][commonmarker-merge] | Markdown | [Commonmarker][commonmarker] (via tree_haver) | Smart merge for Markdown (CommonMark via comrak Rust) |
|
|
334
|
+
| [dotenv-merge][dotenv-merge] | Dotenv | internal | Smart merge for `.env` files |
|
|
335
|
+
| [json-merge][json-merge] | JSON | [tree-sitter-json][ts-json] (via tree_haver) | Smart merge for JSON files |
|
|
336
|
+
| [jsonc-merge][jsonc-merge] | JSONC | [tree-sitter-jsonc][ts-jsonc] (via tree_haver) | ⚠️ Proof of concept; Smart merge for JSON with Comments |
|
|
337
|
+
| [markdown-merge][markdown-merge] | Markdown | [Commonmarker][commonmarker] / [Markly][markly] (via tree_haver) | **Foundation**: Shared base for Markdown mergers with inner code block merging |
|
|
338
|
+
| [markly-merge][markly-merge] | Markdown | [Markly][markly] (via tree_haver) | Smart merge for Markdown (CommonMark via cmark-gfm C) |
|
|
339
|
+
| [prism-merge][prism-merge] | Ruby | [Prism][prism] (`prism` std lib gem) | Smart merge for Ruby source files |
|
|
340
|
+
| [psych-merge][psych-merge] | YAML | [Psych][psych] (`psych` std lib gem) | Smart merge for YAML files |
|
|
341
|
+
| [rbs-merge][rbs-merge] | RBS | [tree-sitter-bash][ts-rbs] (via tree_haver), [RBS][rbs] (`rbs` std lib gem) | Smart merge for Ruby type signatures |
|
|
342
|
+
| [toml-merge][toml-merge] | TOML | [Citrus + toml-rb][toml-rb] (default, via tree_haver), [tree-sitter-toml][ts-toml] (via tree_haver) | Smart merge for TOML files |
|
|
353
343
|
|
|
354
344
|
**Example implementations** for the gem templating use case:
|
|
355
345
|
|
|
@@ -412,7 +402,7 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
|
|
|
412
402
|
|
|
413
403
|
**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.
|
|
414
404
|
|
|
415
|
-
**Note:** TreeHaver can use `ruby_tree_sitter` (MRI) or `tree_stump` (MRI) as backends, or `java-tree-sitter` / `jtreesitter`
|
|
405
|
+
**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](https://central.sonatype.com/artifact/io.github.tree-sitter/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.
|
|
416
406
|
|
|
417
407
|
**Note:** `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
418
408
|
|
|
@@ -421,28 +411,42 @@ The `*-merge` gem family provides intelligent, AST-based merging for various fil
|
|
|
421
411
|
**Choose TreeHaver when:**
|
|
422
412
|
|
|
423
413
|
- You need JRuby or TruffleRuby support
|
|
414
|
+
|
|
424
415
|
- You're building a library that should work across Ruby implementations
|
|
416
|
+
|
|
425
417
|
- You want automatic grammar discovery and security validations
|
|
418
|
+
|
|
426
419
|
- You want flexibility to switch backends without code changes
|
|
420
|
+
|
|
427
421
|
- You need incremental parsing with a unified API
|
|
428
|
-
**Choose ruby\_tree\_sitter directly when:**
|
|
422
|
+
**Choose ruby\_tree\_sitter directly when:**
|
|
429
423
|
|
|
430
424
|
- You only target MRI Ruby
|
|
425
|
+
|
|
431
426
|
- You need the full Query API without abstraction
|
|
427
|
+
|
|
432
428
|
- You want the most battle-tested C bindings
|
|
429
|
+
|
|
433
430
|
- You don't need TreeHaver's grammar discovery
|
|
434
|
-
**Choose tree\_stump directly when:**
|
|
431
|
+
**Choose tree\_stump directly when:**
|
|
435
432
|
|
|
436
433
|
- You only target MRI Ruby
|
|
434
|
+
|
|
437
435
|
- You prefer Rust-based native extensions
|
|
436
|
+
|
|
438
437
|
- You want precompiled binaries without system dependencies
|
|
438
|
+
|
|
439
439
|
- You don't need TreeHaver's grammar discovery
|
|
440
|
+
|
|
440
441
|
- **Note:** `tree_stump` currently requires unreleased fixes in the `main` branch.
|
|
441
|
-
**Choose citrus directly when:**
|
|
442
|
+
**Choose citrus directly when:**
|
|
442
443
|
|
|
443
444
|
- You need zero native dependencies (pure Ruby)
|
|
445
|
+
|
|
444
446
|
- You're using a Citrus grammar (not tree-sitter grammars)
|
|
447
|
+
|
|
445
448
|
- Performance is less critical than portability
|
|
449
|
+
|
|
446
450
|
- You don't need TreeHaver's unified API
|
|
447
451
|
## 💡 Info you can shake a stick at
|
|
448
452
|
|
|
@@ -495,12 +499,16 @@ The maintainers of this and thousands of other packages are working with Tidelif
|
|
|
495
499
|
[](https://tidelift.com/subscription/pkg/rubygems-tree_haver?utm_source=rubygems-tree_haver&utm_medium=referral&utm_campaign=readme)
|
|
496
500
|
|
|
497
501
|
- 💡Subscribe for support guarantees covering *all* your FLOSS dependencies
|
|
502
|
+
|
|
498
503
|
- 💡Tidelift is part of [Sonar](https://blog.tidelift.com/tidelift-joins-sonar)
|
|
504
|
+
|
|
499
505
|
- 💡Tidelift pays maintainers to maintain the software you depend on\!<br/>📊`@`Pointy Haired Boss: An [enterprise support](https://tidelift.com/subscription/pkg/rubygems-tree_haver?utm_source=rubygems-tree_haver&utm_medium=referral&utm_campaign=readme) subscription is "[never gonna let you down](https://www.youtube.com/watch?v=dQw4w9WgXcQ)", and *supports* open source maintainers
|
|
500
|
-
Alternatively:
|
|
506
|
+
Alternatively:
|
|
501
507
|
|
|
502
508
|
- [](https://discord.gg/3qme4XHNKN)
|
|
509
|
+
|
|
503
510
|
- [](https://www.upwork.com/freelancers/~014942e9b056abdf86?mp_source=share)
|
|
511
|
+
|
|
504
512
|
- [](https://www.codementor.io/peterboling?utm_source=github&utm_medium=button&utm_term=peterboling&utm_campaign=github)
|
|
505
513
|
</details>
|
|
506
514
|
|
|
@@ -567,7 +575,7 @@ TreeHaver supports 10 parsing backends, each with different trade-offs. The `aut
|
|
|
567
575
|
| **MRI** | C extension via ruby\_tree\_sitter | ⚡ Fastest | MRI only | [JSON](examples/mri_json.rb) · [JSONC](examples/mri_jsonc.rb) · \~\~Bash\~\~\* · [TOML](examples/mri_toml.rb) |
|
|
568
576
|
| **Rust** | Precompiled via tree\_stump | ⚡ Very Fast | ✅ Good | [JSON](examples/rust_json.rb) · [JSONC](examples/rust_jsonc.rb) · \~\~Bash\~\~\* · [TOML](examples/rust_toml.rb) |
|
|
569
577
|
| **FFI** | Dynamic linking via FFI | 🔵 Fast | ✅ Universal | [JSON](examples/ffi_json.rb) · [JSONC](examples/ffi_jsonc.rb) · [Bash](examples/ffi_bash.rb) · [TOML](examples/ffi_toml.rb) |
|
|
570
|
-
| **Java** | JNI bindings (jtreesitter
|
|
578
|
+
| **Java** | JNI bindings (jtreesitter \>= 0.26.0) | ⚡ Very Fast | JRuby only | [JSON](examples/java_json.rb) · [JSONC](examples/java_jsonc.rb) · [Bash](examples/java_bash.rb) · [TOML](examples/java_toml.rb) |
|
|
571
579
|
|
|
572
580
|
#### Language-Specific Backends (Native Parser Integration)
|
|
573
581
|
|
|
@@ -584,8 +592,8 @@ TreeHaver supports 10 parsing backends, each with different trade-offs. The `aut
|
|
|
584
592
|
**Known Issues:**
|
|
585
593
|
- \*MRI + Bash: ABI incompatibility (use FFI instead)
|
|
586
594
|
- \*Rust + Bash: Version mismatch (use FFI instead)
|
|
587
|
-
**Backend Requirements:**
|
|
588
|
-
|
|
595
|
+
**Backend Requirements:**
|
|
596
|
+
<!-- end list -->
|
|
589
597
|
``` ruby
|
|
590
598
|
# Tree-sitter backends
|
|
591
599
|
gem "ruby_tree_sitter", "~> 2.0" # MRI backend
|
|
@@ -659,7 +667,6 @@ This is particularly useful for:
|
|
|
659
667
|
- **Performance comparison**: Benchmark different backends
|
|
660
668
|
- **Fallback scenarios**: Try one backend, fall back to another
|
|
661
669
|
- **Thread isolation**: Each thread can use a different backend safely
|
|
662
|
-
|
|
663
670
|
<!-- end list -->
|
|
664
671
|
``` ruby
|
|
665
672
|
# Example: Testing with multiple backends
|
|
@@ -729,10 +736,9 @@ The `find_library_path_safe` method only returns paths in trusted directories.
|
|
|
729
736
|
- `/usr/lib/x86_64-linux-gnu`, `/usr/lib/aarch64-linux-gnu`
|
|
730
737
|
- `/usr/local/lib`
|
|
731
738
|
- `/opt/homebrew/lib`, `/opt/local/lib`
|
|
732
|
-
**Adding custom trusted directories:**
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
739
|
+
**Adding custom trusted directories:**
|
|
740
|
+
For non-standard installations (Homebrew on Linux, luarocks, mise, asdf, etc.), register additional trusted directories:
|
|
741
|
+
<!-- end list -->
|
|
736
742
|
``` ruby
|
|
737
743
|
# Programmatically at application startup
|
|
738
744
|
TreeHaver::PathValidator.add_trusted_directory("/home/linuxbrew/.linuxbrew/Cellar")
|
|
@@ -826,7 +832,6 @@ When loading a language grammar, if you don't specify the `symbol:` parameter, T
|
|
|
826
832
|
1. **`TREE_SITTER_LANG_SYMBOL`**: Explicit symbol override
|
|
827
833
|
2. Guessed from filename (e.g., `libtree-sitter-toml.so` → `tree_sitter_toml`)
|
|
828
834
|
3. Default fallback (`tree_sitter_toml`)
|
|
829
|
-
|
|
830
835
|
<!-- end list -->
|
|
831
836
|
``` bash
|
|
832
837
|
export TREE_SITTER_LANG_SYMBOL=tree_sitter_toml
|
|
@@ -845,10 +850,10 @@ export TREE_SITTER_JSON_PATH=/usr/local/lib/libtree-sitter-json.so
|
|
|
845
850
|
|
|
846
851
|
For the Java backend on JRuby, you need:
|
|
847
852
|
|
|
848
|
-
1.
|
|
849
|
-
2.
|
|
850
|
-
3.
|
|
851
|
-
|
|
853
|
+
1. **jtreesitter \>= 0.26.0** JAR from Maven Central
|
|
854
|
+
2. **Tree-sitter runtime library** (`libtree-sitter.so`) version 0.26+
|
|
855
|
+
3. **Grammar `.so` files** built against tree-sitter 0.26+
|
|
856
|
+
<!-- end list -->
|
|
852
857
|
``` bash
|
|
853
858
|
# Download jtreesitter JAR (or use bin/setup-jtreesitter)
|
|
854
859
|
export TREE_SITTER_JAVA_JARS_DIR=/path/to/java-tree-sitter/jars
|
|
@@ -864,7 +869,7 @@ export TREE_SITTER_TOML_PATH=/path/to/libtree-sitter-toml.so
|
|
|
864
869
|
|
|
865
870
|
If you get "version mismatch" errors, rebuild the grammar:
|
|
866
871
|
|
|
867
|
-
```bash
|
|
872
|
+
``` bash
|
|
868
873
|
# Use the provided build script
|
|
869
874
|
bin/build-grammar toml
|
|
870
875
|
|
|
@@ -1047,7 +1052,6 @@ end
|
|
|
1047
1052
|
└── TreeHaver::Error # Base error class
|
|
1048
1053
|
├── TreeHaver::NotAvailable # Backend/grammar not available
|
|
1049
1054
|
└── TreeHaver::BackendConflict # Backend incompatibility detected
|
|
1050
|
-
|
|
1051
1055
|
**Compatibility Mode Behavior:**
|
|
1052
1056
|
|
|
1053
1057
|
The compat mode (`require "tree_haver/compat"`) creates aliases but **does not change the exception hierarchy**:
|
|
@@ -1084,14 +1088,13 @@ end
|
|
|
1084
1088
|
```
|
|
1085
1089
|
|
|
1086
1090
|
2. **Never rely on `rescue => e`** to catch TreeHaver errors (it won't work)
|
|
1087
|
-
**Why inherit from Exception?**
|
|
1088
|
-
|
|
1089
|
-
|
|
1091
|
+
**Why inherit from Exception?**
|
|
1092
|
+
Following ruby\_tree\_sitter's reasoning:
|
|
1093
|
+
<!-- end list -->
|
|
1090
1094
|
- **Thread safety**: Prevents accidental catching in thread cleanup code
|
|
1091
1095
|
- **Signal handling**: Ensures parsing errors don't interfere with SIGTERM/SIGINT
|
|
1092
1096
|
- **Intentional handling**: Forces developers to explicitly handle parsing errors
|
|
1093
|
-
See `lib/tree_haver/compat.rb` for compatibility layer documentation.
|
|
1094
|
-
|
|
1097
|
+
See `lib/tree_haver/compat.rb` for compatibility layer documentation.
|
|
1095
1098
|
## 🔧 Basic Usage
|
|
1096
1099
|
|
|
1097
1100
|
### Quick Start
|
|
@@ -1309,7 +1312,6 @@ This flexibility is useful for:
|
|
|
1309
1312
|
- **Versioning**: Register different grammar versions (e.g., `:ruby_2`, `:ruby_3`)
|
|
1310
1313
|
- **Testing**: Use unique names to avoid collisions between tests
|
|
1311
1314
|
- **Context-specific naming**: Use names that make sense for your application
|
|
1312
|
-
|
|
1313
1315
|
<!-- end list -->
|
|
1314
1316
|
``` ruby
|
|
1315
1317
|
# Register the same TOML grammar under different names for different purposes
|
|
@@ -1506,8 +1508,8 @@ The Java backend will work with:
|
|
|
1506
1508
|
|
|
1507
1509
|
- Grammar JARs built specifically for java-tree-sitter / jtreesitter (self-contained, [docs](https://tree-sitter.github.io/java-tree-sitter/), [maven](https://central.sonatype.com/artifact/io.github.tree-sitter/jtreesitter), [source](https://github.com/tree-sitter/java-tree-sitter))
|
|
1508
1510
|
- Grammar `.so` files that statically link tree-sitter
|
|
1509
|
-
**Option 3: Citrus Backend (pure Ruby, portable)**
|
|
1510
|
-
|
|
1511
|
+
**Option 3: Citrus Backend (pure Ruby, portable)**
|
|
1512
|
+
<!-- end list -->
|
|
1511
1513
|
``` ruby
|
|
1512
1514
|
# Gemfile
|
|
1513
1515
|
gem "tree_haver"
|
|
@@ -2095,7 +2097,7 @@ Thanks for RTFM. ☺️
|
|
|
2095
2097
|
[📌gitmoji]: https://gitmoji.dev
|
|
2096
2098
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
2097
2099
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
2098
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
2100
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.422-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
2099
2101
|
[🔐security]: SECURITY.md
|
|
2100
2102
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
2101
2103
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -231,15 +231,16 @@ module TreeHaver
|
|
|
231
231
|
# Container nodes don't have string_content and will raise TypeError
|
|
232
232
|
if @inner_node.respond_to?(:string_content)
|
|
233
233
|
begin
|
|
234
|
-
@inner_node.string_content.to_s
|
|
234
|
+
content = @inner_node.string_content.to_s
|
|
235
|
+
# If string_content is non-empty, use it (leaf node)
|
|
236
|
+
return content unless content.empty?
|
|
235
237
|
rescue TypeError
|
|
236
|
-
# Container node - concatenate children
|
|
237
|
-
children.map(&:text).join
|
|
238
|
+
# Container node - fall through to concatenate children
|
|
238
239
|
end
|
|
239
|
-
else
|
|
240
|
-
# For container nodes, concatenate children's text
|
|
241
|
-
children.map(&:text).join
|
|
242
240
|
end
|
|
241
|
+
|
|
242
|
+
# For container nodes, concatenate children's text
|
|
243
|
+
children.map(&:text).join
|
|
243
244
|
end
|
|
244
245
|
|
|
245
246
|
# Get child nodes
|
|
@@ -640,8 +640,17 @@ module TreeHaver
|
|
|
640
640
|
def child(index)
|
|
641
641
|
# jtreesitter 0.26.0: getChild returns Optional<Node> or throws IndexOutOfBoundsException
|
|
642
642
|
result = @impl.getChild(index)
|
|
643
|
-
return
|
|
644
|
-
|
|
643
|
+
return if result.nil?
|
|
644
|
+
|
|
645
|
+
# Handle Java Optional
|
|
646
|
+
if result.respond_to?(:isPresent)
|
|
647
|
+
return unless result.isPresent
|
|
648
|
+
java_node = result.get
|
|
649
|
+
else
|
|
650
|
+
# Direct Node return (some jtreesitter versions)
|
|
651
|
+
java_node = result
|
|
652
|
+
end
|
|
653
|
+
|
|
645
654
|
Node.new(java_node)
|
|
646
655
|
rescue ::Java::JavaLang::IndexOutOfBoundsException
|
|
647
656
|
nil
|
|
@@ -653,9 +662,19 @@ module TreeHaver
|
|
|
653
662
|
# @return [Node, nil] the child node or nil if not found
|
|
654
663
|
def child_by_field_name(name)
|
|
655
664
|
# jtreesitter 0.26.0: getChildByFieldName returns Optional<Node>
|
|
665
|
+
# However, some versions or scenarios may return null directly
|
|
656
666
|
result = @impl.getChildByFieldName(name)
|
|
657
|
-
return
|
|
658
|
-
|
|
667
|
+
return if result.nil?
|
|
668
|
+
|
|
669
|
+
# Handle Java Optional
|
|
670
|
+
if result.respond_to?(:isPresent)
|
|
671
|
+
return unless result.isPresent
|
|
672
|
+
java_node = result.get
|
|
673
|
+
else
|
|
674
|
+
# Direct Node return (some jtreesitter versions)
|
|
675
|
+
java_node = result
|
|
676
|
+
end
|
|
677
|
+
|
|
659
678
|
Node.new(java_node)
|
|
660
679
|
end
|
|
661
680
|
|
|
@@ -727,8 +746,16 @@ module TreeHaver
|
|
|
727
746
|
def parent
|
|
728
747
|
# jtreesitter 0.26.0: getParent returns Optional<Node>
|
|
729
748
|
result = @impl.getParent
|
|
730
|
-
return
|
|
731
|
-
|
|
749
|
+
return if result.nil?
|
|
750
|
+
|
|
751
|
+
# Handle Java Optional
|
|
752
|
+
if result.respond_to?(:isPresent)
|
|
753
|
+
return unless result.isPresent
|
|
754
|
+
java_node = result.get
|
|
755
|
+
else
|
|
756
|
+
java_node = result
|
|
757
|
+
end
|
|
758
|
+
|
|
732
759
|
Node.new(java_node)
|
|
733
760
|
end
|
|
734
761
|
|
|
@@ -738,8 +765,16 @@ module TreeHaver
|
|
|
738
765
|
def next_sibling
|
|
739
766
|
# jtreesitter 0.26.0: getNextSibling returns Optional<Node>
|
|
740
767
|
result = @impl.getNextSibling
|
|
741
|
-
return
|
|
742
|
-
|
|
768
|
+
return if result.nil?
|
|
769
|
+
|
|
770
|
+
# Handle Java Optional
|
|
771
|
+
if result.respond_to?(:isPresent)
|
|
772
|
+
return unless result.isPresent
|
|
773
|
+
java_node = result.get
|
|
774
|
+
else
|
|
775
|
+
java_node = result
|
|
776
|
+
end
|
|
777
|
+
|
|
743
778
|
Node.new(java_node)
|
|
744
779
|
end
|
|
745
780
|
|
|
@@ -749,8 +784,16 @@ module TreeHaver
|
|
|
749
784
|
def prev_sibling
|
|
750
785
|
# jtreesitter 0.26.0: getPrevSibling returns Optional<Node>
|
|
751
786
|
result = @impl.getPrevSibling
|
|
752
|
-
return
|
|
753
|
-
|
|
787
|
+
return if result.nil?
|
|
788
|
+
|
|
789
|
+
# Handle Java Optional
|
|
790
|
+
if result.respond_to?(:isPresent)
|
|
791
|
+
return unless result.isPresent
|
|
792
|
+
java_node = result.get
|
|
793
|
+
else
|
|
794
|
+
java_node = result
|
|
795
|
+
end
|
|
796
|
+
|
|
754
797
|
Node.new(java_node)
|
|
755
798
|
end
|
|
756
799
|
|
|
@@ -288,11 +288,17 @@ module TreeHaver
|
|
|
288
288
|
#
|
|
289
289
|
# @return [String] Node text
|
|
290
290
|
def text
|
|
291
|
-
# Markly nodes have string_content for leaf nodes
|
|
291
|
+
# Markly nodes have string_content for leaf nodes (text, code, etc.)
|
|
292
|
+
# Container nodes (heading, paragraph, etc.) have empty string_content
|
|
293
|
+
# and need to use to_plaintext or concatenate children's text.
|
|
292
294
|
if @inner_node.respond_to?(:string_content)
|
|
293
|
-
@inner_node.string_content.to_s
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
content = @inner_node.string_content.to_s
|
|
296
|
+
# If string_content is non-empty, use it (leaf node)
|
|
297
|
+
return content unless content.empty?
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
# For container nodes, use to_plaintext or concatenate children
|
|
301
|
+
if @inner_node.respond_to?(:to_plaintext)
|
|
296
302
|
begin
|
|
297
303
|
@inner_node.to_plaintext
|
|
298
304
|
rescue
|
data/lib/tree_haver/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tree_haver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.2.
|
|
4
|
+
version: 3.2.6
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -293,10 +293,10 @@ licenses:
|
|
|
293
293
|
- MIT
|
|
294
294
|
metadata:
|
|
295
295
|
homepage_uri: https://tree-haver.galtzo.com/
|
|
296
|
-
source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v3.2.
|
|
297
|
-
changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v3.2.
|
|
296
|
+
source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v3.2.6
|
|
297
|
+
changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v3.2.6/CHANGELOG.md
|
|
298
298
|
bug_tracker_uri: https://github.com/kettle-rb/tree_haver/issues
|
|
299
|
-
documentation_uri: https://www.rubydoc.info/gems/tree_haver/3.2.
|
|
299
|
+
documentation_uri: https://www.rubydoc.info/gems/tree_haver/3.2.6
|
|
300
300
|
funding_uri: https://github.com/sponsors/pboling
|
|
301
301
|
wiki_uri: https://github.com/kettle-rb/tree_haver/wiki
|
|
302
302
|
news_uri: https://www.railsbling.com/tags/tree_haver
|
metadata.gz.sig
CHANGED
|
Binary file
|