tree_haver 3.0.0 → 3.1.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0ddc5d837509119a581acd92a33fc7819b6e6dd40a727d1eb0b074d1e944c22f
4
- data.tar.gz: f7b329ee2245068b3bc05e9e6c250e565bbb3b617a50840617f389c2f18dc679
3
+ metadata.gz: 141cf04a77bd50b8802a20eb098ddb03352b08fa6b1592b95180dcf336cc25e1
4
+ data.tar.gz: 134418492ecd86ef348221dfb7cef3f7c459acee00318c2669bdd666dc37d4ba
5
5
  SHA512:
6
- metadata.gz: 66e9dda1e2638d5340ad99a48959d63002293225a3fc636ea776f5718e0ed388628a4a9fe87c1b0150ae265ec812dd763b1cecfe434044148a1fffc16a9e78b1
7
- data.tar.gz: 9545f9a6b25e6f5944c60b1c7e1a3ecc278cea04c5274b3c34a3d3a0d9d83f14324bda96820286e21ae627c380200866ee47cf6161a12f9bffc9ff72064c3aec
6
+ metadata.gz: bafe3a43549cecf6e38a3c8f68c4f072348050d2a3807c4ad8fa9ec2f1d073892abaf5b4300e750a2282849c1bdd081c9ef122b1f2dcb0c5044bddedb451c7b2
7
+ data.tar.gz: 62e7cd0947fdda50ea54f9e9a1b07a05c142388ef56a7a25a9ebb177f12804883cc3fc59dbfbbd3d5f08d062f59f89e850bb5d71733521344c53b5eec19ada78
checksums.yaml.gz.sig CHANGED
Binary file
data/CHANGELOG.md CHANGED
@@ -30,6 +30,153 @@ Please file a bug if you notice a violation of semantic versioning.
30
30
 
31
31
  ### Security
32
32
 
33
+ ## [3.1.1] - 2025-12-28
34
+
35
+ - TAG: [v3.1.1][3.1.1t]
36
+ - COVERAGE: 87.44% -- 2152/2461 lines in 22 files
37
+ - BRANCH COVERAGE: 66.67% -- 710/1065 branches in 22 files
38
+ - 90.02% documented
39
+
40
+ ### Added
41
+
42
+ - **`TreeHaver::RSpec::DependencyTags`**: Shared RSpec dependency detection for the entire gem family
43
+ - New `lib/tree_haver/rspec.rb` entry point - other gems can simply `require "tree_haver/rspec"`
44
+ - Detects all TreeHaver backends: FFI, MRI, Rust, Java, Prism, Psych, Commonmarker, Markly, Citrus
45
+ - Ruby engine detection: `jruby?`, `truffleruby?`, `mri?`
46
+ - Language grammar detection: `tree_sitter_bash_available?`, `tree_sitter_toml_available?`, `tree_sitter_json_available?`, `tree_sitter_jsonc_available?`
47
+ - Inner-merge dependency detection: `toml_merge_available?`, `json_merge_available?`, `prism_merge_available?`, `psych_merge_available?`
48
+ - Composite checks: `any_toml_backend_available?`, `any_markdown_backend_available?`
49
+ - Records MRI backend usage when checking availability (critical for FFI conflict detection)
50
+ - Configures RSpec exclusion filters for all dependency tags automatically
51
+ - Supports debug output via `TREE_HAVER_DEBUG=1` environment variable
52
+ - Comprehensive documentation with usage examples
53
+
54
+ - **`TreeHaver.parser_for`**: New high-level factory method for creating configured parsers
55
+ - Handles all language loading complexity in one call
56
+ - Auto-discovers tree-sitter grammar via `GrammarFinder`
57
+ - Falls back to Citrus grammar if tree-sitter unavailable
58
+ - Accepts `library_path` for explicit grammar location
59
+ - Accepts `citrus_config` for Citrus fallback configuration
60
+ - Raises `NotAvailable` with helpful message if no backend works
61
+ - Example: `parser = TreeHaver.parser_for(:toml)`
62
+ - Raises `NotAvailable` if the specified path doesn't exist (Principle of Least Surprise)
63
+ - Does not back to auto-discovery when an explicit path is provided
64
+ - Re-raises with context-rich error message if loading from explicit path fails
65
+ - Auto-discovery still works normally when no `library_path` is provided
66
+
67
+ ### Changed
68
+
69
+ - **Backend sibling navigation**: Backends that don't support sibling/parent navigation now raise `NotImplementedError` instead of returning `nil`
70
+ - This distinguishes "not implemented" from "no sibling exists"
71
+ - Affected backends: Prism, Psych
72
+ - Affected methods: `next_sibling`, `prev_sibling`, `parent`
73
+
74
+ - **Canonical sibling method name**: All backends now use `prev_sibling` as the canonical method name (not `previous_sibling`)
75
+ - Matches the universal `TreeHaver::Node` API
76
+
77
+ ### Fixed
78
+
79
+ - **Backend conflict detection**: Fixed bug where MRI backend usage wasn't being recorded during availability checks
80
+ - `mri_backend_available?` now calls `TreeHaver.record_backend_usage(:mri)` after successfully loading ruby_tree_sitter
81
+ - This ensures FFI conflict detection works correctly even when MRI is loaded indirectly
82
+
83
+ - **GrammarFinder#not_found_message**: Improved error message when grammar file exists but no tree-sitter runtime is available
84
+ - Now suggests adding `ruby_tree_sitter`, `ffi`, or `tree_stump` gem to Gemfile
85
+ - Clearer guidance for users who have grammar files but are missing the Ruby tree-sitter bindings
86
+
87
+ ## [3.1.0] - 2025-12-18
88
+
89
+ - TAG: [v3.1.0][3.1.0t]
90
+ - COVERAGE: 82.65% -- 943/1141 lines in 11 files
91
+ - BRANCH COVERAGE: 63.80% -- 349/547 branches in 11 files
92
+ - 88.97% documented
93
+
94
+ ### Added
95
+
96
+ - **Position API Enhancements** – Added consistent position methods to all backend Node classes for compatibility with `*-merge` gems
97
+ - `start_line` - Returns 1-based line number where node starts (converts 0-based `start_point.row` to 1-based)
98
+ - `end_line` - Returns 1-based line number where node ends (converts 0-based `end_point.row` to 1-based)
99
+ - `source_position` - Returns hash `{start_line:, end_line:, start_column:, end_column:}` with 1-based lines and 0-based columns
100
+ - `first_child` - Convenience method that returns `children.first` for iteration compatibility
101
+ - **Fixed:** `TreeHaver::Node#start_point` and `#end_point` now handle both Point objects and hashes from backends (Prism, Citrus return hashes)
102
+ - **Fixed:** Added Psych, Commonmarker, and Markly backends to `resolve_backend_module` and `backend_module` case statements so they can be explicitly selected with `TreeHaver.backend = :psych` etc.
103
+ - **Fixed:** Added Prism, Psych, Commonmarker, and Markly backends to `unwrap_language` method so language objects are properly passed to backend parsers
104
+ - **Fixed:** Commonmarker backend's `text` method now safely handles container nodes that don't have string_content (wraps in rescue TypeError)
105
+ - **Added to:**
106
+ - Main `TreeHaver::Node` wrapper (used by tree-sitter backends: MRI, FFI, Java, Rust)
107
+ - `Backends::Commonmarker::Node` - uses Commonmarker's `sourcepos` (already 1-based)
108
+ - `Backends::Markly::Node` - uses Markly's `source_position` (already 1-based)
109
+ - `Backends::Prism::Node` - uses Prism's `location` (already 1-based)
110
+ - `Backends::Psych::Node` - calculates from `start_point`/`end_point` (0-based)
111
+ - `Backends::Citrus::Node` - calculates from `start_point`/`end_point` (0-based)
112
+ - **Backward Compatible:** Existing `start_point`/`end_point` methods continue to work unchanged
113
+ - **Purpose:** Enables all `*-merge` gems to use consistent position API without backend-specific workarounds
114
+
115
+ - **Prism Backend** – New backend wrapping Ruby's official Prism parser (stdlib in Ruby 3.4+, gem for 3.2+)
116
+ - `TreeHaver::Backends::Prism::Language` - Language wrapper (Ruby-only)
117
+ - `TreeHaver::Backends::Prism::Parser` - Parser with `parse` and `parse_string` methods
118
+ - `TreeHaver::Backends::Prism::Tree` - Tree wrapper with `root_node`, `errors`, `warnings`, `comments`
119
+ - `TreeHaver::Backends::Prism::Node` - Node wrapper implementing full TreeHaver::Node protocol
120
+ - Registered with `:prism` backend name, no conflicts with other backends
121
+
122
+ - **Psych Backend** – New backend wrapping Ruby's standard library YAML parser
123
+ - `TreeHaver::Backends::Psych::Language` - Language wrapper (YAML-only)
124
+ - `TreeHaver::Backends::Psych::Parser` - Parser with `parse` and `parse_string` methods
125
+ - `TreeHaver::Backends::Psych::Tree` - Tree wrapper with `root_node`, `errors`
126
+ - `TreeHaver::Backends::Psych::Node` - Node wrapper implementing TreeHaver::Node protocol
127
+ - Psych-specific methods: `mapping?`, `sequence?`, `scalar?`, `alias?`, `mapping_entries`, `anchor`, `tag`, `value`
128
+ - Registered with `:psych` backend name, no conflicts with other backends
129
+
130
+ - **Commonmarker Backend** – New backend wrapping the Commonmarker gem (comrak Rust parser)
131
+ - `TreeHaver::Backends::Commonmarker::Language` - Language wrapper with parse options passthrough
132
+ - `TreeHaver::Backends::Commonmarker::Parser` - Parser with `parse` and `parse_string` methods
133
+ - `TreeHaver::Backends::Commonmarker::Tree` - Tree wrapper with `root_node`
134
+ - `TreeHaver::Backends::Commonmarker::Node` - Node wrapper implementing TreeHaver::Node protocol
135
+ - Commonmarker-specific methods: `header_level`, `fence_info`, `url`, `title`, `next_sibling`, `previous_sibling`, `parent`
136
+ - Registered with `:commonmarker` backend name, no conflicts with other backends
137
+
138
+ - **Markly Backend** – New backend wrapping the Markly gem (cmark-gfm C library)
139
+ - `TreeHaver::Backends::Markly::Language` - Language wrapper with flags and extensions passthrough
140
+ - `TreeHaver::Backends::Markly::Parser` - Parser with `parse` and `parse_string` methods
141
+ - `TreeHaver::Backends::Markly::Tree` - Tree wrapper with `root_node`
142
+ - `TreeHaver::Backends::Markly::Node` - Node wrapper implementing TreeHaver::Node protocol
143
+ - Type normalization: `:header` → `"heading"`, `:hrule` → `"thematic_break"`, `:html` → `"html_block"`
144
+ - Markly-specific methods: `header_level`, `fence_info`, `url`, `title`, `next_sibling`, `previous_sibling`, `parent`, `raw_type`
145
+ - Registered with `:markly` backend name, no conflicts with other backends
146
+
147
+ - **Automatic Citrus Fallback** – When tree-sitter fails, automatically fall back to Citrus backend
148
+ - `TreeHaver::Language.method_missing` now catches tree-sitter loading errors (`NotAvailable`, `ArgumentError`, `LoadError`, `FFI::NotFoundError`) and falls back to registered Citrus grammar
149
+ - `TreeHaver::Parser#initialize` now catches parser creation errors and falls back to Citrus parser when backend is `:auto`
150
+ - `TreeHaver::Parser#language=` automatically switches to Citrus parser when a Citrus language is assigned
151
+ - Enables seamless use of pure-Ruby parsers (like toml-rb) when tree-sitter runtime is unavailable
152
+
153
+ - **GrammarFinder Runtime Check** – `GrammarFinder#available?` now verifies tree-sitter runtime is actually usable
154
+ - New `GrammarFinder.tree_sitter_runtime_usable?` class method tests if parser can be created
155
+ - `TREE_SITTER_BACKENDS` constant defines which backends use tree-sitter (MRI, FFI, Rust, Java)
156
+ - Prevents registration of grammars when tree-sitter runtime isn't functional
157
+ - `GrammarFinder.reset_runtime_check!` for testing
158
+
159
+ - **Empty ENV Variable as Explicit Skip** – Setting `TREE_SITTER_<LANG>_PATH=''` explicitly disables that grammar
160
+ - Previously, empty string was treated same as unset (would search paths)
161
+ - Now, empty string means "do not use tree-sitter for this language"
162
+ - Allows explicit opt-out to force fallback to alternative backends like Citrus
163
+ - Useful for testing and environments where tree-sitter isn't desired
164
+
165
+ - **TOML Examples** – New example scripts demonstrating TOML parsing with various backends
166
+ - `examples/auto_toml.rb` - Auto backend selection with Citrus fallback demonstration
167
+ - `examples/ffi_toml.rb` - FFI backend with TOML
168
+ - `examples/mri_toml.rb` - MRI backend with TOML
169
+ - `examples/rust_toml.rb` - Rust backend with TOML
170
+ - `examples/java_toml.rb` - Java backend with TOML (JRuby only)
171
+
172
+ ### Fixed
173
+
174
+ - **BREAKING**: `TreeHaver::Language.method_missing` no longer raises `ArgumentError` when only Citrus grammar is registered and tree-sitter backend is active – it now falls back to Citrus instead
175
+ - Previously: Would raise "No grammar registered for :lang compatible with tree_sitter backend"
176
+ - Now: Returns `TreeHaver::Backends::Citrus::Language` if Citrus grammar is registered
177
+ - Migration: If you were catching this error, update your code to handle the fallback behavior
178
+ - This is a bug fix, but would be a breaking change for some users who were relying on the old behavior
179
+
33
180
  ## [3.0.0] - 2025-12-16
34
181
 
35
182
  - TAG: [v3.0.0][3.0.0t]
@@ -272,7 +419,11 @@ Despite the major version bump to 3.0.0 (following semver due to the breaking `L
272
419
 
273
420
  - Initial release
274
421
 
275
- [Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v3.0.0...HEAD
422
+ [Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v3.1.1...HEAD
423
+ [3.1.1]: https://github.com/kettle-rb/tree_haver/compare/v3.1.0...v3.1.1
424
+ [3.1.1t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.1.1
425
+ [3.1.0]: https://github.com/kettle-rb/tree_haver/compare/v3.0.0...v3.1.0
426
+ [3.1.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.1.0
276
427
  [3.0.0]: https://github.com/kettle-rb/tree_haver/compare/v2.0.0...v3.0.0
277
428
  [3.0.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.0.0
278
429
  [2.0.0]: https://github.com/kettle-rb/tree_haver/compare/v1.0.0...v2.0.0
data/CONTRIBUTING.md CHANGED
@@ -44,9 +44,21 @@ bin/rake -T
44
44
 
45
45
  ## Backend Compatibility Testing
46
46
 
47
- TreeHaver supports multiple backends (MRI, FFI, Rust, Citrus), but not all backends can coexist
48
- in the same Ruby process. Notably, **FFI and MRI backends conflict** at the libtree-sitter runtime
49
- level—using both in the same process will cause segfaults.
47
+ TreeHaver supports multiple backends with different characteristics:
48
+
49
+ - **MRI**: ruby_tree_sitter (C extension, tree-sitter grammars)
50
+ - **FFI**: Pure Ruby FFI bindings (tree-sitter grammars)
51
+ - **Rust**: tree_stump (Rust extension, tree-sitter grammars)
52
+ - **Citrus**: Pure Ruby parser (TOML only via toml-rb grammar)
53
+
54
+ Not all backends can coexist in the same Ruby process. Notably, **FFI and MRI backends conflict**
55
+ at the libtree-sitter runtime level—using both in the same process will cause segfaults.
56
+
57
+ The **Citrus backend** works differently:
58
+ - Uses pure Ruby parsing (no .so files)
59
+ - Currently only supports TOML via toml-rb grammar
60
+ - Can coexist with tree-sitter backends
61
+ - Useful for testing multi-backend scenarios
50
62
 
51
63
  The `bin/backend-matrix` script helps test and document backend compatibility by running tests
52
64
  in isolated subprocesses.
@@ -57,14 +69,21 @@ in isolated subprocesses.
57
69
  # Test all backends with TOML grammar (default)
58
70
  bin/backend-matrix
59
71
 
60
- # Test specific backend order
61
- bin/backend-matrix ffi mri rust
72
+ # Test specific backend order (including Citrus)
73
+ bin/backend-matrix ffi mri rust citrus
74
+
75
+ # Test Citrus with tree-sitter backends
76
+ bin/backend-matrix citrus mri ffi # Citrus before tree-sitter
77
+ bin/backend-matrix mri citrus ffi # Citrus between tree-sitter
62
78
 
63
79
  # Test with a different grammar
64
80
  bin/backend-matrix --grammar=json
65
81
 
66
82
  # Test multiple grammars
67
83
  bin/backend-matrix --grammars=json,toml,bash
84
+
85
+ # Citrus only supports TOML
86
+ bin/backend-matrix --grammar=toml citrus
68
87
  ```
69
88
 
70
89
  ### All Permutations Mode
@@ -72,11 +91,13 @@ bin/backend-matrix --grammars=json,toml,bash
72
91
  Test all possible backend combinations by spawning fresh subprocesses for each:
73
92
 
74
93
  ```shell
75
- # Test all 15 backend combinations (1-backend, 2-backend, 3-backend)
94
+ # Test all 64 backend combinations (4 backends: 4 1-backend + 12 2-backend + 24 3-backend + 24 4-backend)
76
95
  bin/backend-matrix --all-permutations
77
96
 
78
97
  # With multiple grammars
79
98
  bin/backend-matrix --all-permutations --grammars=json,toml
99
+
100
+ # Note: Citrus only supports TOML, so JSON/Bash tests will skip for Citrus
80
101
  ```
81
102
 
82
103
  ### Cross-Grammar Testing
@@ -121,18 +142,23 @@ Example findings:
121
142
 
122
143
  ```
123
144
  Backend Pair Compatibility:
124
- ╭──────────────┬────────────────────┬─────────┬────────╮
125
- │ Backend Pair │ Compatibility │ Working │ Failed │
126
- ├──────────────┼────────────────────┼─────────┼────────┤
127
- │ ffi+mri │ ✗ Incompatible │ 0 │ 8 │
128
- │ mri+rust │ ✓ Fully compatible │ 8 │ 0 │
129
- │ ffi+rust │ ✓ Fully compatible │ 8 │ 0 │
130
- ╰──────────────┴────────────────────┴─────────┴────────╯
145
+ ╭───────────────┬────────────────────┬─────────┬────────╮
146
+ │ Backend Pair │ Compatibility │ Working │ Failed │
147
+ ├───────────────┼────────────────────┼─────────┼────────┤
148
+ │ ffi+mri │ ✗ Incompatible │ 0 │ 8 │
149
+ │ mri+rust │ ✓ Fully compatible │ 8 │ 0 │
150
+ │ ffi+rust │ ✓ Fully compatible │ 8 │ 0 │
151
+ │ citrus+mri │ ✓ Fully compatible │ 2 │ 0 │
152
+ │ citrus+ffi │ ✓ Fully compatible │ 2 │ 0 │
153
+ │ citrus+rust │ ✓ Fully compatible │ 2 │ 0 │
154
+ ╰───────────────┴────────────────────┴─────────┴────────╯
155
+
156
+ Note: Citrus only supports TOML, so it has fewer total combinations.
131
157
  ```
132
158
 
133
159
  ### Required Environment Variables
134
160
 
135
- The script requires grammar paths to be set:
161
+ The script requires grammar paths to be set for tree-sitter backends:
136
162
 
137
163
  ```shell
138
164
  export TREE_SITTER_TOML_PATH=/path/to/libtree-sitter-toml.so
@@ -142,6 +168,12 @@ export TREE_SITTER_BASH_PATH=/path/to/libtree-sitter-bash.so
142
168
 
143
169
  See `.envrc` for examples of how these are typically configured.
144
170
 
171
+ **For Citrus backend:**
172
+ - Requires the `toml-rb` gem (pure Ruby TOML parser)
173
+ - **Auto-installs**: Script uses bundler inline to install `toml-rb` automatically if missing
174
+ - No environment variables needed (doesn't use .so files)
175
+ - Only supports TOML grammar
176
+
145
177
  ## Environment Variables for Local Development
146
178
 
147
179
  Below are the primary environment variables recognized by stone_checksums (and its integrated tools). Unless otherwise noted, set boolean values to the string "true" to enable.