tree_haver 5.0.4 → 7.0.0
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/lib/tree_haver/backend_context.rb +28 -0
- data/lib/tree_haver/backend_registry.rb +19 -432
- data/lib/tree_haver/contracts.rb +460 -0
- data/lib/tree_haver/kaitai_backend.rb +30 -0
- data/lib/tree_haver/language_pack.rb +190 -0
- data/lib/tree_haver/peg_backends.rb +76 -0
- data/lib/tree_haver/version.rb +1 -12
- data/lib/tree_haver.rb +7 -1316
- data.tar.gz.sig +0 -0
- metadata +34 -245
- metadata.gz.sig +0 -0
- data/CHANGELOG.md +0 -1366
- data/CITATION.cff +0 -20
- data/CODE_OF_CONDUCT.md +0 -134
- data/CONTRIBUTING.md +0 -359
- data/FUNDING.md +0 -74
- data/LICENSE.txt +0 -21
- data/README.md +0 -2347
- data/REEK +0 -0
- data/RUBOCOP.md +0 -71
- data/SECURITY.md +0 -21
- data/lib/tree_haver/backend_api.rb +0 -349
- data/lib/tree_haver/backends/citrus.rb +0 -487
- data/lib/tree_haver/backends/ffi.rb +0 -1009
- data/lib/tree_haver/backends/java.rb +0 -893
- data/lib/tree_haver/backends/mri.rb +0 -362
- data/lib/tree_haver/backends/parslet.rb +0 -560
- data/lib/tree_haver/backends/prism.rb +0 -471
- data/lib/tree_haver/backends/psych.rb +0 -375
- data/lib/tree_haver/backends/rust.rb +0 -239
- data/lib/tree_haver/base/language.rb +0 -98
- data/lib/tree_haver/base/node.rb +0 -322
- data/lib/tree_haver/base/parser.rb +0 -24
- data/lib/tree_haver/base/point.rb +0 -48
- data/lib/tree_haver/base/tree.rb +0 -128
- data/lib/tree_haver/base.rb +0 -12
- data/lib/tree_haver/citrus_grammar_finder.rb +0 -218
- data/lib/tree_haver/compat.rb +0 -43
- data/lib/tree_haver/grammar_finder.rb +0 -374
- data/lib/tree_haver/language.rb +0 -295
- data/lib/tree_haver/language_registry.rb +0 -190
- data/lib/tree_haver/library_path_utils.rb +0 -80
- data/lib/tree_haver/node.rb +0 -579
- data/lib/tree_haver/parser.rb +0 -438
- data/lib/tree_haver/parslet_grammar_finder.rb +0 -224
- data/lib/tree_haver/path_validator.rb +0 -353
- data/lib/tree_haver/point.rb +0 -27
- data/lib/tree_haver/rspec/dependency_tags.rb +0 -1392
- data/lib/tree_haver/rspec/testable_node.rb +0 -217
- data/lib/tree_haver/rspec.rb +0 -33
- data/lib/tree_haver/tree.rb +0 -258
- data/sig/tree_haver/backends.rbs +0 -352
- data/sig/tree_haver/grammar_finder.rbs +0 -29
- data/sig/tree_haver/path_validator.rbs +0 -32
- data/sig/tree_haver.rbs +0 -234
data/CHANGELOG.md
DELETED
|
@@ -1,1366 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
[![SemVer 2.0.0][📌semver-img]][📌semver] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog]
|
|
4
|
-
|
|
5
|
-
All notable changes to this project will be documented in this file.
|
|
6
|
-
|
|
7
|
-
The format is based on [Keep a Changelog][📗keep-changelog],
|
|
8
|
-
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html),
|
|
9
|
-
and [yes][📌major-versions-not-sacred], platform and engine support are part of the [public API][📌semver-breaking].
|
|
10
|
-
Please file a bug if you notice a violation of semantic versioning.
|
|
11
|
-
|
|
12
|
-
[📌semver]: https://semver.org/spec/v2.0.0.html
|
|
13
|
-
[📌semver-img]: https://img.shields.io/badge/semver-2.0.0-FFDD67.svg?style=flat
|
|
14
|
-
[📌semver-breaking]: https://github.com/semver/semver/issues/716#issuecomment-869336139
|
|
15
|
-
[📌major-versions-not-sacred]: https://tom.preston-werner.com/2022/05/23/major-version-numbers-are-not-sacred.html
|
|
16
|
-
[📗keep-changelog]: https://keepachangelog.com/en/1.0.0/
|
|
17
|
-
[📗keep-changelog-img]: https://img.shields.io/badge/keep--a--changelog-1.0.0-FFDD67.svg?style=flat
|
|
18
|
-
|
|
19
|
-
## [Unreleased]
|
|
20
|
-
|
|
21
|
-
### Added
|
|
22
|
-
|
|
23
|
-
### Changed
|
|
24
|
-
|
|
25
|
-
### Deprecated
|
|
26
|
-
|
|
27
|
-
### Removed
|
|
28
|
-
|
|
29
|
-
### Fixed
|
|
30
|
-
|
|
31
|
-
### Security
|
|
32
|
-
|
|
33
|
-
## [5.0.4] - 2026-02-04
|
|
34
|
-
|
|
35
|
-
- TAG: [v5.0.4][5.0.4t]
|
|
36
|
-
- COVERAGE: 83.68% -- 2128/2543 lines in 30 files
|
|
37
|
-
- BRANCH COVERAGE: 72.58% -- 863/1189 branches in 30 files
|
|
38
|
-
- 94.78% documented
|
|
39
|
-
|
|
40
|
-
### Changed
|
|
41
|
-
|
|
42
|
-
- Update documentation on which fork/SHA to use for tree_stump & ruby_tree_sitter
|
|
43
|
-
|
|
44
|
-
## [5.0.3] - 2026-01-30
|
|
45
|
-
|
|
46
|
-
- TAG: [v5.0.3][5.0.3t]
|
|
47
|
-
- COVERAGE: 83.68% -- 2128/2543 lines in 30 files
|
|
48
|
-
- BRANCH COVERAGE: 72.50% -- 862/1189 branches in 30 files
|
|
49
|
-
- 94.78% documented
|
|
50
|
-
|
|
51
|
-
### Changed
|
|
52
|
-
|
|
53
|
-
- test against Prism v1.9.0
|
|
54
|
-
- CI updated to use latest version of ore
|
|
55
|
-
|
|
56
|
-
### Fixed
|
|
57
|
-
|
|
58
|
-
- **Improved dependency handling and test robustness**:
|
|
59
|
-
- Added missing RSpec backend tags (`:parslet_backend`, `:citrus_backend`, etc.) to ensure tests are skipped when dependencies are unavailable.
|
|
60
|
-
- Enhanced `GrammarFinder` to support both `ENV.key?` and `ENV[var]` checks, fixing issues with environment stubbing in tests.
|
|
61
|
-
- Improved `GrammarFinder` spec reliability by using `allow(File).to receive(:exist?).and_call_original`.
|
|
62
|
-
- Configured RSpec to mark grammar-dependent tests as `pending` with helpful instructions when shared libraries are missing.
|
|
63
|
-
- Renamed `:toml_rb` tag to `:toml_rb_gem` for consistency across the codebase.
|
|
64
|
-
- Documentation fixes related to gem family section
|
|
65
|
-
|
|
66
|
-
## [5.0.2] - 2026-01-13
|
|
67
|
-
|
|
68
|
-
- TAG: [v5.0.2][5.0.2t]
|
|
69
|
-
- COVERAGE: 90.79% -- 2308/2542 lines in 30 files
|
|
70
|
-
- BRANCH COVERAGE: 78.09% -- 930/1191 branches in 30 files
|
|
71
|
-
- 94.78% documented
|
|
72
|
-
|
|
73
|
-
### Added
|
|
74
|
-
|
|
75
|
-
- More documentation about the Merge Gem Family
|
|
76
|
-
- **`:json_parsing` and `:jsonc_parsing` RSpec dependency tags**: Added missing parsing capability tags
|
|
77
|
-
for JSON and JSONC (JSON with Comments) languages
|
|
78
|
-
- `any_json_backend_available?` - Checks if tree-sitter-json is available
|
|
79
|
-
- `any_jsonc_backend_available?` - Checks if tree-sitter-jsonc is available
|
|
80
|
-
- Tests tagged with `:jsonc_parsing` will now be properly skipped on TruffleRuby and other
|
|
81
|
-
platforms where tree-sitter backends are not available
|
|
82
|
-
- Fixes issue where jsonc-merge specs were running on TruffleRuby and failing because
|
|
83
|
-
the tag was undefined and therefore not excluded
|
|
84
|
-
|
|
85
|
-
### Changed
|
|
86
|
-
|
|
87
|
-
- Restored README.md (was accidentally corrupted during the last release)
|
|
88
|
-
|
|
89
|
-
## [5.0.1] - 2026-01-11
|
|
90
|
-
|
|
91
|
-
- TAG: [v5.0.1][5.0.1t]
|
|
92
|
-
- COVERAGE: 90.79% -- 2308/2542 lines in 30 files
|
|
93
|
-
- BRANCH COVERAGE: 78.09% -- 930/1191 branches in 30 files
|
|
94
|
-
- 94.76% documented
|
|
95
|
-
|
|
96
|
-
### Added
|
|
97
|
-
|
|
98
|
-
- `TreeHaver::RSpec::TestableNode` - A testable node class for creating mock TreeHaver::Node instances
|
|
99
|
-
in tests without requiring an actual parser backend. Available via `require "tree_haver/rspec/testable_node"`
|
|
100
|
-
or automatically when using `require "tree_haver/rspec"`.
|
|
101
|
-
- `TestableNode.create(type:, text:, ...)` - Create a single test node
|
|
102
|
-
- `TestableNode.create_list(...)` - Create multiple test nodes
|
|
103
|
-
- `MockInnerNode` - The underlying mock that simulates backend-specific nodes
|
|
104
|
-
- Top-level `TestableNode` constant for convenience in specs
|
|
105
|
-
- **Fully Dynamic Tag Registration** in `TreeHaver::BackendRegistry`:
|
|
106
|
-
- `register_tag(tag_name, category:, backend_name:, require_path:)` - Register a complete dependency tag
|
|
107
|
-
with lazy loading support. External gems can now get full RSpec tag support without any hardcoded
|
|
108
|
-
knowledge in tree_haver.
|
|
109
|
-
- `tag_available?(tag_name)` - Check if a tag's dependency is available, with automatic lazy loading
|
|
110
|
-
via the registered `require_path`
|
|
111
|
-
- `registered_tags` - Get all registered tag names
|
|
112
|
-
- `tags_by_category(category)` - Get tags filtered by category (:backend, :gem, :parsing, :grammar, :engine, :other)
|
|
113
|
-
- `tag_metadata(tag_name)` - Get full metadata for a registered tag
|
|
114
|
-
- `tag_summary` - Get availability status of all registered tags
|
|
115
|
-
|
|
116
|
-
### Changed
|
|
117
|
-
|
|
118
|
-
- **Fully Dynamic Backend Availability** in `BackendRegistry` and `DependencyTags`:
|
|
119
|
-
- `register_tag` now dynamically defines `*_available?` methods on `DependencyTags` at registration time
|
|
120
|
-
- External gems automatically get availability methods when they call `register_tag`
|
|
121
|
-
- No changes to tree_haver are needed for new external backend gems
|
|
122
|
-
- Built-in backends (prism, psych, citrus, parslet) retain explicit methods
|
|
123
|
-
- `summary` method dynamically includes registered backends from BackendRegistry
|
|
124
|
-
- `backend_availability_methods` and `backend_tags` hashes are built dynamically
|
|
125
|
-
- RSpec exclusion filters for backend tags are configured dynamically from BackendRegistry
|
|
126
|
-
|
|
127
|
-
### Fixed
|
|
128
|
-
|
|
129
|
-
- **`TreeHaver::Parser#unwrap_language` bug fix for MRI and Rust backends**
|
|
130
|
-
- `:mri` and `:rust` cases were not returning the unwrapped language value
|
|
131
|
-
- The code called `lang.to_language` / `lang.inner_language` / `lang.name` but didn't `return` the result
|
|
132
|
-
- Now properly returns the unwrapped language for all backend types
|
|
133
|
-
- `any_markdown_backend_available?` now uses `BackendRegistry.tag_available?` instead of calling
|
|
134
|
-
`markly_available?` and `commonmarker_available?` directly. This fixes `NoMethodError` when
|
|
135
|
-
the external markdown backend gems haven't registered their tags yet.
|
|
136
|
-
|
|
137
|
-
## [5.0.0] - 2026-01-11
|
|
138
|
-
|
|
139
|
-
- TAG: [v5.0.0][5.0.0t]
|
|
140
|
-
- COVERAGE: 92.04% -- 2289/2487 lines in 30 files
|
|
141
|
-
- BRANCH COVERAGE: 79.33% -- 929/1171 branches in 30 files
|
|
142
|
-
- 96.21% documented
|
|
143
|
-
|
|
144
|
-
### Added
|
|
145
|
-
|
|
146
|
-
- **Shared Example Groups for Backend API Compliance Testing**
|
|
147
|
-
- `node_api_examples.rb` - Tests for Node API compliance:
|
|
148
|
-
- `"node api compliance"` - Core Node interface (type, start_byte, end_byte, children)
|
|
149
|
-
- `"node position api"` - Position API (start_point, end_point, start_line, end_line, source_position)
|
|
150
|
-
- `"node children api"` - Children traversal (#child, #first_child, #last_child)
|
|
151
|
-
- `"node enumerable behavior"` - Enumerable methods (#each, #map, #select, #find)
|
|
152
|
-
- `"node comparison behavior"` - Comparison and equality (#==, #<=>, #hash)
|
|
153
|
-
- `"node text extraction"` - Text content (#text, #to_s)
|
|
154
|
-
- `"node inspection"` - Debug output (#inspect)
|
|
155
|
-
- `tree_api_examples.rb` - Tests for Tree API compliance:
|
|
156
|
-
- `"tree api compliance"` - Core Tree interface (root_node, source, errors, warnings, comments)
|
|
157
|
-
- `"tree error handling"` - Error detection (#has_error?, #errors)
|
|
158
|
-
- `"tree traversal"` - Depth-first traversal via root_node
|
|
159
|
-
- `parser_api_examples.rb` - Tests for Parser API compliance:
|
|
160
|
-
- `"parser api compliance"` - Core Parser interface (#parse, #parse_string, #language=)
|
|
161
|
-
- `"parser incremental parsing"` - Incremental parsing support
|
|
162
|
-
- `"parser error handling"` - Error recovery behavior
|
|
163
|
-
- `language_api_examples.rb` - Tests for Language API compliance:
|
|
164
|
-
- `"language api compliance"` - Core Language interface (#backend, #name/#language_name)
|
|
165
|
-
- `"language comparison"` - Comparison and equality
|
|
166
|
-
- `"language factory methods"` - Factory methods (.from_library, .from_path)
|
|
167
|
-
- `backend_api_examples.rb` - Tests for Backend module API compliance:
|
|
168
|
-
- `"backend module api"` - Backend availability and capabilities
|
|
169
|
-
- `"backend class structure"` - Nested class verification
|
|
170
|
-
- `"backend integration"` - Full parse cycle testing
|
|
171
|
-
- `spec/support/shared_examples.rb` - Master loader for all shared examples
|
|
172
|
-
- `spec/integration/backend_api_compliance_spec.rb` - Integration tests using all shared examples
|
|
173
|
-
- **Parslet Backend**: New pure Ruby PEG parser backend (`TreeHaver::Backends::Parslet`)
|
|
174
|
-
- Wraps Parslet-based parsers (like the `toml` gem) to provide a pure Ruby alternative to tree-sitter
|
|
175
|
-
- `Parslet.available?` - Check if parslet gem is available
|
|
176
|
-
- `Parslet.capabilities` - Returns `{ backend: :parslet, query: false, bytes_field: true, incremental: false, pure_ruby: true }`
|
|
177
|
-
- `Parslet::Language` - Wrapper for Parslet grammar classes
|
|
178
|
-
- `Language.new(grammar_class)` - Create from a Parslet::Parser subclass
|
|
179
|
-
- `Language.from_library(path, symbol:, name:)` - API-compatible lookup via LanguageRegistry
|
|
180
|
-
- `#language_name` / `#name` - Derive language name from grammar class
|
|
181
|
-
- `Parslet::Parser` - Wrapper that creates parser instances from grammar classes
|
|
182
|
-
- Accepts both raw grammar class and Language wrapper (normalized API)
|
|
183
|
-
- `Parslet::Tree` - Wraps Parslet parse results, inherits from `Base::Tree`
|
|
184
|
-
- `Parslet::Node` - Unified node interface, inherits from `Base::Node`
|
|
185
|
-
- Supports both Hash nodes (with named children) and Array nodes (with indexed children)
|
|
186
|
-
- `#type` - Returns the node type (key name or "array"/"document")
|
|
187
|
-
- `#children` - Returns child nodes
|
|
188
|
-
- `#child_by_field_name(name)` - Access named children in Hash nodes
|
|
189
|
-
- `#text` - Returns the matched text from Parslet::Slice
|
|
190
|
-
- `#start_byte`, `#end_byte` - Byte positions from Parslet::Slice
|
|
191
|
-
- `#start_point`, `#end_point` - Line/column positions (computed from source)
|
|
192
|
-
- Registered with `BackendRegistry.register_availability_checker(:parslet)`
|
|
193
|
-
- **RSpec Dependency Tags**: Added `parslet_available?` method
|
|
194
|
-
- Checks if parslet gem is installed via `BackendRegistry.available?(:parslet)`
|
|
195
|
-
- `:parslet_backend` tag for specs requiring Parslet
|
|
196
|
-
- `:not_parslet_backend` negated tag for specs that should skip when Parslet is available
|
|
197
|
-
- **RSpec Dependency Tags**: Added `toml_gem_available?` method and updated `any_toml_backend_available?`
|
|
198
|
-
- `:toml_gem` tag for specs requiring the `toml` gem to be available
|
|
199
|
-
- `:not_toml_gem` negated tag for specs that should skip when the `toml` gem is not available
|
|
200
|
-
- **ParsletGrammarFinder**: Utility for discovering and registering Parslet grammar gems
|
|
201
|
-
- `ParsletGrammarFinder.new(language:, gem_name:, grammar_const:, require_path:)` - Find Parslet grammars
|
|
202
|
-
- `#available?` - Check if the Parslet grammar gem is installed and functional
|
|
203
|
-
- `#grammar_class` - Get the resolved Parslet::Parser subclass
|
|
204
|
-
- `#register!` - Register the grammar with TreeHaver
|
|
205
|
-
- Auto-loads via `TreeHaver::PARSLET_DEFAULTS` for known languages (toml)
|
|
206
|
-
- **TreeHaver.register_language**: Extended with `grammar_class:` parameter for Parslet grammars
|
|
207
|
-
- **TreeHaver.parser_for**: Extended with `parslet_config:` parameter for explicit Parslet configuration
|
|
208
|
-
- `MRI::Language#language_name` / `#name` - Derive language name from symbol or path
|
|
209
|
-
- `FFI::Language#language_name` / `#name` - Derive language name from symbol or path
|
|
210
|
-
- **spec_helper.rb**: Added `require "toml"` to load the toml gem for Parslet backend tests
|
|
211
|
-
|
|
212
|
-
### Changed
|
|
213
|
-
|
|
214
|
-
- **BREAKING: `TreeHaver::Language` converted from class to module**
|
|
215
|
-
- Previously `TreeHaver::Language` was a class that wrapped backend language objects
|
|
216
|
-
- Now `TreeHaver::Language` is a module providing factory methods (`method_missing` for dynamic language loading)
|
|
217
|
-
- Backend-specific language classes (e.g., `TreeHaver::Backends::MRI::Language`) are now the concrete implementations
|
|
218
|
-
- Code that instantiated `TreeHaver::Language.new(...)` directly must be updated to use backend-specific classes or the factory methods
|
|
219
|
-
- **BREAKING: `TreeHaver::Tree` now inherits from `TreeHaver::Base::Tree`**
|
|
220
|
-
- `TreeHaver::Tree` is now a proper subclass of `TreeHaver::Base::Tree`
|
|
221
|
-
- Inherits `inner_tree`, `source`, `lines` attributes from base class
|
|
222
|
-
- Base class provides default implementations; subclass documents divergence
|
|
223
|
-
- **BREAKING: `TreeHaver::Node` now inherits from `TreeHaver::Base::Node`**
|
|
224
|
-
- `TreeHaver::Node` is now a proper subclass of `TreeHaver::Base::Node`
|
|
225
|
-
- Inherits `inner_node`, `source`, `lines` attributes from base class
|
|
226
|
-
- Base class documents the API contract; subclass documents divergence
|
|
227
|
-
- **BREAKING: `Citrus::Node` and `Citrus::Tree` now inherit from Base classes**
|
|
228
|
-
- `Citrus::Node` now inherits from `TreeHaver::Base::Node`
|
|
229
|
-
- `Citrus::Tree` now inherits from `TreeHaver::Base::Tree`
|
|
230
|
-
- Removes duplicated methods, uses inherited implementations
|
|
231
|
-
- Adds `#language_name` / `#name` methods for API compliance
|
|
232
|
-
- **BREAKING: `Parslet::Node` and `Parslet::Tree` now inherit from Base classes**
|
|
233
|
-
- `Parslet::Node` now inherits from `TreeHaver::Base::Node`
|
|
234
|
-
- `Parslet::Tree` now inherits from `TreeHaver::Base::Tree`
|
|
235
|
-
- Removes duplicated methods, uses inherited implementations
|
|
236
|
-
- **Base::Node#child now returns nil for negative indices** (tree-sitter API compatibility)
|
|
237
|
-
- **Citrus::Parser#language= now accepts Language wrapper or raw grammar module**
|
|
238
|
-
- Both patterns now work: `parser.language = TomlRB::Document` or `parser.language = Citrus::Language.new(TomlRB::Document)`
|
|
239
|
-
- **Parslet::Parser#language= now accepts Language wrapper or raw grammar class**
|
|
240
|
-
- Both patterns now work: `parser.language = TOML::Parslet` or `parser.language = Parslet::Language.new(TOML::Parslet)`
|
|
241
|
-
- **TreeHaver::Parser#unwrap_language** now passes Language wrappers directly to Citrus/Parslet backends
|
|
242
|
-
- Previously unwrapped to raw grammar; now backends handle their own Language wrappers
|
|
243
|
-
- **Language.method_missing**: Now recognizes `:parslet` backend type and creates `Parslet::Language` instances
|
|
244
|
-
- **Parser**: Updated to recognize Parslet languages and switch to Parslet parser automatically
|
|
245
|
-
- `#backend` now returns `:parslet` for Parslet-based parsers
|
|
246
|
-
- `#language=` detects `Parslet::Language` and switches implementation
|
|
247
|
-
- `handle_parser_creation_failure` tries Parslet as fallback after Citrus
|
|
248
|
-
- `unwrap_language` extracts `grammar_class` for Parslet languages
|
|
249
|
-
|
|
250
|
-
### Fixed
|
|
251
|
-
|
|
252
|
-
- **FFI Backend Compliance Tests**: Fixed tests to use `TreeHaver::Parser` wrapper instead of raw `FFI::Parser`
|
|
253
|
-
- Raw FFI classes (`FFI::Tree`, `FFI::Node`) don't have full API (missing `#children`, `#text`, `#source`, etc.)
|
|
254
|
-
- TreeHaver wrapper classes (`TreeHaver::Tree`, `TreeHaver::Node`) provide the complete unified API
|
|
255
|
-
- Tests now properly test the wrapped API that users actually interact with
|
|
256
|
-
- **Parslet TOML Sources**: Fixed test sources to be valid for the `toml` gem's Parslet grammar
|
|
257
|
-
- Grammar requires table sections (not bare key-value pairs at root)
|
|
258
|
-
- Grammar requires trailing newlines
|
|
259
|
-
- **Examples**: Fixed broken markdown examples that referenced non-existent TreeHaver backends
|
|
260
|
-
- `commonmarker_markdown.rb` - Rewrote to use commonmarker gem directly (not a TreeHaver backend)
|
|
261
|
-
- `markly_markdown.rb` - Rewrote to use markly gem directly with correct `source_position` API
|
|
262
|
-
- `commonmarker_merge_example.rb` - Fixed to use `commonmarker/merge` gem properly
|
|
263
|
-
- `markly_merge_example.rb` - Fixed to use `markly/merge` gem properly
|
|
264
|
-
- `parslet_toml.rb` - Rewrote to properly use TreeHaver's Parslet backend with language registration
|
|
265
|
-
- **Examples**: Fixed `run_all.rb` test runner
|
|
266
|
-
- Added parslet example to the test list
|
|
267
|
-
- Changed markdown examples to use `backend: "standalone"` (they're not TreeHaver backends)
|
|
268
|
-
- Added MRI+TOML to known incompatibilities (parse returns nil)
|
|
269
|
-
- Added proper skip reason messages for all known incompatibilities
|
|
270
|
-
- **Examples**: Updated `examples/README.md` documentation
|
|
271
|
-
- Added Parslet backend section with usage examples
|
|
272
|
-
- Renamed "Commonmarker Backend" and "Markly Backend" to "Commonmarker (Standalone)" and "Markly (Standalone)"
|
|
273
|
-
- Clarified that commonmarker and markly are standalone parsers, not TreeHaver backends
|
|
274
|
-
- **Duplicate Constants**: Removed duplicate `CITRUS_DEFAULTS` and `PARSLET_DEFAULTS` definitions
|
|
275
|
-
- Constants were defined twice in `tree_haver.rb` (lines 170 and 315)
|
|
276
|
-
- This was causing "already initialized constant" warnings on every require
|
|
277
|
-
|
|
278
|
-
## [4.0.5] - 2026-01-09
|
|
279
|
-
|
|
280
|
-
- TAG: [v4.0.5][4.0.5t]
|
|
281
|
-
- COVERAGE: 93.50% -- 2058/2201 lines in 28 files
|
|
282
|
-
- BRANCH COVERAGE: 81.11% -- 803/990 branches in 28 files
|
|
283
|
-
- 95.60% documented
|
|
284
|
-
|
|
285
|
-
### Added
|
|
286
|
-
|
|
287
|
-
- **FFI Backend**: Added `child_by_field_name` method to `TreeHaver::Backends::FFI::Node`
|
|
288
|
-
- Enables field-based child access using tree-sitter's `ts_node_child_by_field_name` C API
|
|
289
|
-
- Works with all grammars (JSON, JSONC, TOML, Bash, etc.) that define field names
|
|
290
|
-
- Fixes compatibility issues with json-merge, jsonc-merge, and other gems that use field access
|
|
291
|
-
- Example: `pair.child_by_field_name("key")` returns the key node from a JSON pair
|
|
292
|
-
- **RSpec Dependency Tags**: Added `compute_blocked_backends` method
|
|
293
|
-
- Determines blocked backends from `TREE_HAVER_BACKEND` env and ARGV `--tag` options
|
|
294
|
-
- Called by `summary` when `@blocked_backends` isn't set yet (before RSpec.configure runs)
|
|
295
|
-
- Fixes issue where gem-specific `before(:suite)` hooks could load blocked backends
|
|
296
|
-
- **RSpec Dependency Tags**: Added `LD_LIBRARY_PATH` and `DYLD_LIBRARY_PATH` to `env_summary`
|
|
297
|
-
- These library paths are relevant for tree-sitter shared library loading
|
|
298
|
-
- Useful for debugging grammar loading issues
|
|
299
|
-
- **RSpec Dependency Tags**: Added `TREE_SITTER_RBS_PATH` to `env_summary`
|
|
300
|
-
|
|
301
|
-
### Changed
|
|
302
|
-
|
|
303
|
-
- **Language#method_missing**: Simplified error handling in `Language#method_missing`
|
|
304
|
-
- Removed unreachable rescue block for `FFI::NotFoundError`
|
|
305
|
-
- `FFI::NotFoundError` inherits from `LoadError`, so it's already caught by the prior rescue clause
|
|
306
|
-
- Reduces code complexity without changing behavior
|
|
307
|
-
- **Parser#initialize**: Simplified error handling in `Parser#initialize`
|
|
308
|
-
- Same fix as Language - removed unreachable `FFI::NotFoundError` handling
|
|
309
|
-
- Added comment noting that `FFI::NotFoundError` inherits from `LoadError`
|
|
310
|
-
- **FFI Backend Native#try_load!**: Removed redundant `FFI::NotFoundError` from rescue clause
|
|
311
|
-
- Only rescues `LoadError` now with comment explaining inheritance
|
|
312
|
-
- **GrammarFinder.tree_sitter_runtime_usable?**: Removed redundant `StandardError` rescue clause
|
|
313
|
-
- `LoadError` already catches `FFI::NotFoundError`
|
|
314
|
-
- Added comment explaining the inheritance relationship
|
|
315
|
-
|
|
316
|
-
### Fixed
|
|
317
|
-
|
|
318
|
-
- **Test Isolation**: Fixed state leakage in `language_registry_spec.rb`
|
|
319
|
-
- Tests were registering real language names (`:toml`, `:json`, `:yaml`) with fake paths
|
|
320
|
-
- These registrations persisted and polluted other tests that expected real grammar paths
|
|
321
|
-
- Changed all tests to use unique test-only language names (prefixed with `test_lang_`)
|
|
322
|
-
- Fixes 2 spec failures when running all tests together (`TreeHaver::Tree#edit` specs)
|
|
323
|
-
|
|
324
|
-
## [4.0.4] - 2026-01-09
|
|
325
|
-
|
|
326
|
-
- TAG: [v4.0.4][4.0.4t]
|
|
327
|
-
- COVERAGE: 95.27% -- 2033/2134 lines in 28 files
|
|
328
|
-
- BRANCH COVERAGE: 84.07% -- 802/954 branches in 28 files
|
|
329
|
-
- 95.49% documented
|
|
330
|
-
|
|
331
|
-
### Fixed
|
|
332
|
-
|
|
333
|
-
- **RSpec Dependency Tags**: Fixed blocked backend tests not being excluded on JRuby
|
|
334
|
-
- When `TREE_HAVER_BACKEND=ffi` is set, MRI backend is blocked to prevent conflicts
|
|
335
|
-
- Previously, this skipped BOTH the availability check AND the exclusion
|
|
336
|
-
- Now blocked backends are excluded without checking availability
|
|
337
|
-
- Tests tagged with `:mri_backend` now properly skip on JRuby when FFI is selected
|
|
338
|
-
|
|
339
|
-
## [4.0.3] - 2026-01-08
|
|
340
|
-
|
|
341
|
-
- TAG: [v4.0.3][4.0.3t]
|
|
342
|
-
- COVERAGE: 95.27% -- 2033/2134 lines in 28 files
|
|
343
|
-
- BRANCH COVERAGE: 84.17% -- 803/954 branches in 28 files
|
|
344
|
-
- 95.49% documented
|
|
345
|
-
|
|
346
|
-
### Changed
|
|
347
|
-
|
|
348
|
-
- **RSpec Dependency Tags**: Refactored FFI backend isolation to use standard `:ffi_backend` tag
|
|
349
|
-
- The `--tag ffi_backend` now triggers `isolated_test_mode` in `dependency_tags.rb`
|
|
350
|
-
- This prevents MRI backend from loading during availability checks
|
|
351
|
-
- Legacy `*_backend_only` tags are still supported for backwards compatibility
|
|
352
|
-
- Simplifies the testing pattern: one tag serves as both dependency tag and isolation trigger
|
|
353
|
-
|
|
354
|
-
### Deprecated
|
|
355
|
-
|
|
356
|
-
- **`:ffi_backend_only` tag**: Use `:ffi_backend` instead. The `*_backend_only` tags are now redundant.
|
|
357
|
-
|
|
358
|
-
## [4.0.2] - 2026-01-08
|
|
359
|
-
|
|
360
|
-
- TAG: [v4.0.2][4.0.2t]
|
|
361
|
-
- COVERAGE: 95.27% -- 2033/2134 lines in 28 files
|
|
362
|
-
- BRANCH COVERAGE: 84.07% -- 802/954 branches in 28 files
|
|
363
|
-
- 95.49% documented
|
|
364
|
-
|
|
365
|
-
### Added
|
|
366
|
-
|
|
367
|
-
- **FFI Backend**: Implemented `missing?` method on `TreeHaver::Backends::FFI::Node`
|
|
368
|
-
- Added `ts_node_is_missing` FFI function attachment
|
|
369
|
-
- This method was missing entirely, causing `NoMethodError` when checking for MISSING nodes
|
|
370
|
-
|
|
371
|
-
### Changed
|
|
372
|
-
|
|
373
|
-
- **TreeHaver::Node**: Removed defensive `respond_to?` checks from `has_error?` and `missing?` methods
|
|
374
|
-
- All tree-sitter backends (MRI, Rust, FFI, Java) must implement these methods on their inner nodes
|
|
375
|
-
- This enforces proper backend API compliance rather than silently masking missing implementations
|
|
376
|
-
|
|
377
|
-
### Fixed
|
|
378
|
-
|
|
379
|
-
- **FFI Backend**: Added explicit boolean conversion (`!!`) to `has_error?` return value
|
|
380
|
-
- FFI `:bool` return type may behave inconsistently across Ruby versions and platforms
|
|
381
|
-
- Ensures `has_error?` always returns `true` or `false`, not truthy/falsy values
|
|
382
|
-
|
|
383
|
-
## [4.0.1] - 2026-01-08
|
|
384
|
-
|
|
385
|
-
- TAG: [v4.0.1][4.0.1t]
|
|
386
|
-
- COVERAGE: 95.31% -- 2032/2132 lines in 28 files
|
|
387
|
-
- BRANCH COVERAGE: 84.10% -- 804/956 branches in 28 files
|
|
388
|
-
- 95.48% documented
|
|
389
|
-
|
|
390
|
-
### Fixed
|
|
391
|
-
|
|
392
|
-
- **FFI Backend**: Implemented `has_error?` method on `TreeHaver::Backends::FFI::Node`
|
|
393
|
-
- Previously was a stub that always returned `false`, causing parse errors to go undetected
|
|
394
|
-
- Now properly calls `ts_node_has_error` FFI function to detect syntax errors in parsed trees
|
|
395
|
-
- This fixes error detection on JRuby when using the FFI backend with tree-sitter grammars
|
|
396
|
-
|
|
397
|
-
## [4.0.0] - 2026-01-08
|
|
398
|
-
|
|
399
|
-
- TAG: [v4.0.0][4.0.0t]
|
|
400
|
-
- COVERAGE: 95.31% -- 2031/2131 lines in 28 files
|
|
401
|
-
- BRANCH COVERAGE: 84.21% -- 805/956 branches in 28 files
|
|
402
|
-
- 95.48% documented
|
|
403
|
-
|
|
404
|
-
### Added
|
|
405
|
-
|
|
406
|
-
- **BackendRegistry**: New `TreeHaver::BackendRegistry` module for registering backend availability checkers
|
|
407
|
-
- Allows external gems (like `commonmarker-merge`, `markly-merge`, `rbs-merge`) to register their availability checkers
|
|
408
|
-
- `register_availability_checker(backend_name, &block)` - Register a callable that returns true if backend is available
|
|
409
|
-
- `available?(backend_name)` - Check if a backend is available (results are cached)
|
|
410
|
-
- `registered?(backend_name)` - Check if a checker is registered
|
|
411
|
-
- `registered_backends` - Get all registered backend names
|
|
412
|
-
- Used by `TreeHaver::RSpec::DependencyTags` for dynamic backend detection
|
|
413
|
-
- **Plugin System**: `commonmarker-merge` and `markly-merge` now provide their own backends via `TreeHaver`'s registry system, removing them from `TreeHaver` core.
|
|
414
|
-
- **Backend Architecture Documentation**: Added comprehensive documentation to base classes and all tree-sitter backends explaining the two backend categories:
|
|
415
|
-
- Tree-sitter backends (MRI, Rust, FFI, Java): Use `TreeHaver::Tree` and `TreeHaver::Node` wrappers for raw tree-sitter objects
|
|
416
|
-
- Pure-Ruby/Plugin backends (Citrus, Prism, Psych, Commonmarker, Markly): Define own `Backend::X::Tree` and `Backend::X::Node` classes
|
|
417
|
-
|
|
418
|
-
### Changed
|
|
419
|
-
|
|
420
|
-
- **Base Class Inheritance**: `TreeHaver::Tree` and `TreeHaver::Node` now properly inherit from their respective `Base::` classes
|
|
421
|
-
- `TreeHaver::Tree < Base::Tree` - inherits `inner_tree`, `source`, `lines` attributes and default implementations
|
|
422
|
-
- `TreeHaver::Node < Base::Node` - inherits `inner_node`, `source`, `lines` attributes and API contract
|
|
423
|
-
- Base classes document the API contract; subclasses document divergence
|
|
424
|
-
- **Base::Node#initialize**: Now accepts keyword arguments `source:` and `lines:` instead of positional for consistency with subclasses
|
|
425
|
-
- **DependencyTags**: Now uses `BackendRegistry.available?(:backend_name)` instead of hardcoded `TreeHaver::Backends::*` checks
|
|
426
|
-
- **TreeHaver**: `commonmarker` and `markly` backends are no longer built-in. Use `commonmarker-merge` and `markly-merge` gems which register themselves.
|
|
427
|
-
- **All backends**: Now register their availability checkers with `BackendRegistry` when loaded (MRI, Rust, FFI, Java, Prism, Psych, Citrus)
|
|
428
|
-
|
|
429
|
-
### Removed
|
|
430
|
-
|
|
431
|
-
- **TreeHaver**: Removed `TreeHaver::Backends::Commonmarker` and `TreeHaver::Backends::Markly` modules. These implementations have moved to their respective gems.
|
|
432
|
-
|
|
433
|
-
## [3.2.6] - 2026-01-06
|
|
434
|
-
|
|
435
|
-
- TAG: [v3.2.6][3.2.6t]
|
|
436
|
-
- COVERAGE: 92.07% -- 2230/2422 lines in 23 files
|
|
437
|
-
- BRANCH COVERAGE: 74.69% -- 788/1055 branches in 23 files
|
|
438
|
-
- 90.37% documented
|
|
439
|
-
|
|
440
|
-
### Fixed
|
|
441
|
-
|
|
442
|
-
- **Java backend**: Fixed Optional handling in Node methods that could return nil incorrectly
|
|
443
|
-
- `child(index)`, `child_by_field_name(name)`, `parent`, `next_sibling`, `prev_sibling` now properly check for nil before attempting to unwrap Java Optional
|
|
444
|
-
- Previously, the ternary-based Optional check could fail when jtreesitter returned null directly instead of Optional.empty()
|
|
445
|
-
- This fixes JRuby test failures where `key_name` returned nil and object keys were not extracted
|
|
446
|
-
|
|
447
|
-
## [3.2.5] - 2026-01-05
|
|
448
|
-
|
|
449
|
-
- TAG: [v3.2.5][3.2.5t]
|
|
450
|
-
- COVERAGE: 92.07% -- 2230/2422 lines in 23 files
|
|
451
|
-
- BRANCH COVERAGE: 74.69% -- 788/1055 branches in 23 files
|
|
452
|
-
- 90.37% documented
|
|
453
|
-
|
|
454
|
-
### Fixed
|
|
455
|
-
|
|
456
|
-
- **Markly backend**: `Node#text` now correctly handles container nodes (headings, paragraphs, etc.)
|
|
457
|
-
- Previously returned empty string because `string_content` was checked first (responds but returns empty for containers)
|
|
458
|
-
- Now falls through to `to_plaintext` or children concatenation when `string_content` is empty
|
|
459
|
-
- **Commonmarker backend**: `Node#text` now correctly handles container nodes
|
|
460
|
-
- Previously could return empty string in edge cases
|
|
461
|
-
- Now consistently falls through to children concatenation when `string_content` is empty or raises TypeError
|
|
462
|
-
|
|
463
|
-
## [3.2.4] - 2026-01-04
|
|
464
|
-
|
|
465
|
-
- TAG: [v3.2.4][3.2.4t]
|
|
466
|
-
- COVERAGE: 92.07% -- 2229/2421 lines in 23 files
|
|
467
|
-
- BRANCH COVERAGE: 74.79% -- 786/1051 branches in 23 files
|
|
468
|
-
- 90.37% documented
|
|
469
|
-
|
|
470
|
-
### Added
|
|
471
|
-
|
|
472
|
-
- **External backend registration via `backend_module`** - External gems can now register
|
|
473
|
-
their own pure Ruby backends using the same API as built-in backends. This enables gems
|
|
474
|
-
like rbs-merge to integrate with `TreeHaver.parser_for` without modifying tree_haver:
|
|
475
|
-
```ruby
|
|
476
|
-
TreeHaver.register_language(
|
|
477
|
-
:rbs,
|
|
478
|
-
backend_module: Rbs::Merge::Backends::RbsBackend,
|
|
479
|
-
backend_type: :rbs,
|
|
480
|
-
gem_name: "rbs",
|
|
481
|
-
)
|
|
482
|
-
# Now TreeHaver.parser_for(:rbs) works!
|
|
483
|
-
```
|
|
484
|
-
- **`Backends::PURE_RUBY_BACKENDS` constant** - Maps pure Ruby backend names to their
|
|
485
|
-
language and module info. Used for auto-registration of built-in backends.
|
|
486
|
-
- **`TreeHaver.register_builtin_backends!`** - Registers built-in pure Ruby backends
|
|
487
|
-
(Prism, Psych, Commonmarker, Markly) in the LanguageRegistry using the same API that
|
|
488
|
-
external backends use. Called automatically by `parser_for` on first use.
|
|
489
|
-
- **`TreeHaver.ensure_builtin_backends_registered!`** - Idempotent helper that ensures
|
|
490
|
-
built-in backends are registered exactly once.
|
|
491
|
-
- **`parser_for` now supports registered `backend_module` backends** - When a language
|
|
492
|
-
has a registered `backend_module`, `parser_for` will use it. This enables external
|
|
493
|
-
gems to provide language support without tree-sitter grammars:
|
|
494
|
-
- Checks LanguageRegistry for registered `backend_module` entries
|
|
495
|
-
- Creates parser from the backend module's `Parser` and `Language` classes
|
|
496
|
-
- Falls back to tree-sitter and Citrus if no backend_module matches
|
|
497
|
-
- **RBS dependency tags in `DependencyTags`** - New RSpec tags for RBS parsing:
|
|
498
|
-
- `:rbs_grammar` - tree-sitter-rbs grammar is available and parsing works
|
|
499
|
-
- `:rbs_parsing` - at least one RBS parser (rbs gem OR tree-sitter-rbs) is available
|
|
500
|
-
- `:rbs_gem` - the official rbs gem is available (MRI only)
|
|
501
|
-
- Negated versions: `:not_rbs_grammar`, `:not_rbs_parsing`, `:not_rbs_gem`
|
|
502
|
-
- New availability methods: `tree_sitter_rbs_available?`, `rbs_gem_available?`, `any_rbs_backend_available?`
|
|
503
|
-
- **Support for tree-sitter 0.26.x ABI** - TreeHaver now fully supports grammars built
|
|
504
|
-
against tree-sitter 0.26.x (LANGUAGE_VERSION 15). This required updates to vendored
|
|
505
|
-
dependencies:
|
|
506
|
-
- **ruby-tree-sitter**: Updated to support tree-sitter 0.26.3 C library API changes
|
|
507
|
-
including new `ts_language_abi_version()` function, UTF-16 encoding split, and
|
|
508
|
-
removal of deprecated parser timeout/cancellation APIs
|
|
509
|
-
- **tree_stump (Rust backend)**: Updated to tree-sitter Rust crate 0.26.3 with new
|
|
510
|
-
`abi_version()` method, `u32` child indices, and streaming iterator-based query matches
|
|
511
|
-
- **MRI backend now loads grammars with LANGUAGE_VERSION 15** - Previously, MRI backend
|
|
512
|
-
using ruby_tree_sitter could only load grammars with LANGUAGE_VERSION ≤ 14. Now supports
|
|
513
|
-
grammars built against tree-sitter 0.26.x.
|
|
514
|
-
- **Rust backend now loads grammars with LANGUAGE_VERSION 15** - Previously, the tree_stump
|
|
515
|
-
Rust backend reported "Incompatible language version 15. Expected minimum 13, maximum 14".
|
|
516
|
-
Now supports the latest grammar format.
|
|
517
|
-
- **BackendAPI validation module** - New `TreeHaver::BackendAPI` module for validating
|
|
518
|
-
backend API compliance:
|
|
519
|
-
- `BackendAPI.validate(backend_module)` - Returns validation results hash
|
|
520
|
-
- `BackendAPI.validate!(backend_module)` - Raises on validation failure
|
|
521
|
-
- `BackendAPI.validate_node_instance(node)` - Validates a node instance
|
|
522
|
-
- Defines required and optional methods for Language, Parser, Tree, and Node classes
|
|
523
|
-
- Documents API contract for wrapper vs raw backends
|
|
524
|
-
- New `examples/validate_backends.rb` script to validate all backends
|
|
525
|
-
- **Java backend Node class now implements full API** - Added missing methods to ensure
|
|
526
|
-
API consistency with other backends:
|
|
527
|
-
- `parent` - Get parent node
|
|
528
|
-
- `next_sibling` - Get next sibling node
|
|
529
|
-
- `prev_sibling` - Get previous sibling node
|
|
530
|
-
- `named?` - Check if node is named
|
|
531
|
-
- `child_by_field_name` - Get child by field name
|
|
532
|
-
- All methods properly handle jtreesitter 0.26.0's `Optional<Node>` return types
|
|
533
|
-
- **Three environment variables for backend control** - Fine-grained control over which
|
|
534
|
-
backends are available:
|
|
535
|
-
- `TREE_HAVER_BACKEND` - Single backend selection (auto, mri, ffi, rust, java, citrus, etc.)
|
|
536
|
-
- `TREE_HAVER_NATIVE_BACKEND` - Allow list for native backends (auto, none, or comma-separated
|
|
537
|
-
list like `mri,ffi`). Use `none` for pure-Ruby-only mode.
|
|
538
|
-
- `TREE_HAVER_RUBY_BACKEND` - Allow list for pure Ruby backends (auto, none, or comma-separated
|
|
539
|
-
list like `citrus,prism`). Use `none` for native-only mode.
|
|
540
|
-
- **Backend availability now respects allow lists** - When `TREE_HAVER_NATIVE_BACKEND` is set
|
|
541
|
-
to specific backends (e.g., `mri,ffi`), all other native backends are treated as unavailable.
|
|
542
|
-
This applies to ALL backend selection mechanisms:
|
|
543
|
-
- Auto-selection in `backend_module`
|
|
544
|
-
- Explicit selection via `with_backend(:rust)` - returns nil/unavailable
|
|
545
|
-
- Explicit selection via `resolve_backend_module(:rust)` - returns nil
|
|
546
|
-
- RSpec dependency tags (`ffi_available?`, etc.)
|
|
547
|
-
|
|
548
|
-
This makes the environment variables a **hard restriction**, not just a hint for auto-selection.
|
|
549
|
-
Use `TREE_HAVER_NATIVE_BACKEND=none` for pure-Ruby-only mode, or specify exactly which
|
|
550
|
-
native backends are permitted (e.g., `mri,ffi`).
|
|
551
|
-
- **Java backend updated for jtreesitter 0.26.0** - Full compatibility with jtreesitter 0.26.0:
|
|
552
|
-
- Updated `Parser#parse` and `Parser#parse_string` to handle `Optional<Tree>` return type
|
|
553
|
-
- Updated `Tree#root_node` to handle `Optional<Node>` return type
|
|
554
|
-
- Fixed `parse_string` argument order to match jtreesitter 0.26.0 API: `parse(String, Tree)`
|
|
555
|
-
- Updated `Language.load_by_name` to use `SymbolLookup` API (single-arg `load(name)` removed)
|
|
556
|
-
- Added `bin/setup-jtreesitter` script to download jtreesitter JAR from Maven Central
|
|
557
|
-
- Added `bin/build-grammar` script to build tree-sitter grammars from source
|
|
558
|
-
- Older versions of jtreesitter are NOT supported
|
|
559
|
-
- **`TREE_HAVER_BACKEND_PROTECT` environment variable** - Explicit control over backend
|
|
560
|
-
conflict protection. Set to `false` to disable protection that prevents mixing
|
|
561
|
-
incompatible native backends (e.g., FFI after MRI). Useful for testing scenarios
|
|
562
|
-
where you understand the risks. Default behavior (protection enabled) unchanged.
|
|
563
|
-
|
|
564
|
-
### Changed
|
|
565
|
-
|
|
566
|
-
- **API normalized: `from_library` is now universal** - All language-specific backends
|
|
567
|
-
(Psych, Prism, Commonmarker, Markly) now implement `Language.from_library` for API
|
|
568
|
-
consistency. This allows `TreeHaver.parser_for(:yaml)` to work uniformly regardless
|
|
569
|
-
of which backend is active:
|
|
570
|
-
- **Psych**: `from_library` accepts (and ignores) path/symbol, returns YAML language
|
|
571
|
-
- **Prism**: `from_library` accepts (and ignores) path/symbol, returns Ruby language
|
|
572
|
-
- **Commonmarker**: `from_library` accepts (and ignores) path/symbol, returns Markdown language
|
|
573
|
-
- **Markly**: `from_library` accepts (and ignores) path/symbol, returns Markdown language
|
|
574
|
-
- All raise `TreeHaver::NotAvailable` if a different language is requested
|
|
575
|
-
- **Citrus backend `from_library` now looks up registered grammars** - Instead of always
|
|
576
|
-
raising an error, `Backends::Citrus::Language.from_library` now looks up registered
|
|
577
|
-
Citrus grammars by name via `LanguageRegistry`. This enables `TreeHaver.parser_for(:toml)`
|
|
578
|
-
to work seamlessly when a Citrus grammar has been registered with
|
|
579
|
-
`TreeHaver.register_language(:toml, grammar_module: TomlRB::Document)`.
|
|
580
|
-
- **Java backend requires jtreesitter >= 0.26.0** - Due to API changes in jtreesitter,
|
|
581
|
-
older versions are no longer supported. The tree-sitter runtime library must also be
|
|
582
|
-
version 0.26.x to match.
|
|
583
|
-
by the RSpec dependency tags. This ensures tests tagged with `:mri_backend` only run when
|
|
584
|
-
MRI is in the allow list. Same for `TREE_HAVER_RUBY_BACKEND` and pure Ruby backends.
|
|
585
|
-
- New `TreeHaver.allowed_native_backends` method returns the allow list for native backends.
|
|
586
|
-
- New `TreeHaver.allowed_ruby_backends` method returns the allow list for pure Ruby backends.
|
|
587
|
-
- New `TreeHaver.backend_allowed?(backend)` method checks if a specific backend is allowed
|
|
588
|
-
based on the current environment variable settings.
|
|
589
|
-
- New `DependencyTags.allowed_native_backends` and `DependencyTags.allowed_ruby_backends` methods.
|
|
590
|
-
- Updated `examples/test_backend_selection.rb` script to test all three environment variables.
|
|
591
|
-
- **`LanguageRegistry` now supports any backend type** - Previously only `:tree_sitter` and
|
|
592
|
-
`:citrus` were documented. Now supports arbitrary backend types including `:prism`, `:psych`,
|
|
593
|
-
`:commonmarker`, `:markly`, `:rbs`, or any custom type. External gems can register their
|
|
594
|
-
own backend types using the same API.
|
|
595
|
-
- **`register_language` accepts `backend_module` parameter** - New parameter for registering
|
|
596
|
-
pure Ruby backends. The module must provide `Language` and `Parser` classes with the
|
|
597
|
-
standard TreeHaver API (`available?`, `capabilities`, `from_library`, etc.).
|
|
598
|
-
|
|
599
|
-
### Fixed
|
|
600
|
-
|
|
601
|
-
- **`TreeHaver::Node#text` now handles backends with different `text` method signatures** -
|
|
602
|
-
Previously, `Node#text` would call `@inner_node.text` directly, but `TreeStump::Node#text`
|
|
603
|
-
(Rust backend) requires the source as an argument (`text(source)`). This caused
|
|
604
|
-
`ArgumentError: wrong number of arguments (given 0, expected 1)` when using the Rust
|
|
605
|
-
backend. Now `Node#text` checks the method arity and passes the source when required:
|
|
606
|
-
- Arity 0 or -1: calls `@inner_node.text` without arguments
|
|
607
|
-
- Arity >= 1: calls `@inner_node.text(@source)` with source
|
|
608
|
-
- Falls back to byte-based extraction if source is available
|
|
609
|
-
|
|
610
|
-
- **AUTO mode now gracefully falls back when explicitly requested backend is blocked** -
|
|
611
|
-
Previously, if `TREE_HAVER_BACKEND=ffi` was set in the environment but FFI was blocked
|
|
612
|
-
due to MRI being used first (backend conflict protection), `parser_for` would raise a
|
|
613
|
-
`BackendConflict` error. Now, when the explicitly requested backend is blocked by a
|
|
614
|
-
**backend conflict** (e.g., FFI after MRI causes segfaults):
|
|
615
|
-
- `backend_module` detects the conflict and falls back to auto-selection
|
|
616
|
-
- `resolve_native_backend_module` rescues `BackendConflict` and continues to the next
|
|
617
|
-
backend in the priority list
|
|
618
|
-
- This enables seamless multi-backend usage in test suites where different tests use
|
|
619
|
-
different backends, but one backend has already "poisoned" the process for another.
|
|
620
|
-
|
|
621
|
-
Note: This fallback only applies to **backend conflicts** (runtime incompatibility).
|
|
622
|
-
If a backend is disallowed by `TREE_HAVER_NATIVE_BACKEND` or `TREE_HAVER_RUBY_BACKEND`,
|
|
623
|
-
it will simply be unavailable—no error is raised, but no fallback occurs either.
|
|
624
|
-
|
|
625
|
-
- **`java_backend_available?` now verifies grammar loading works** - Previously, the
|
|
626
|
-
`DependencyTags.java_backend_available?` method only checked if java-tree-sitter
|
|
627
|
-
classes could be loaded, but didn't verify that grammars could actually be used.
|
|
628
|
-
This caused tests tagged with `:java_backend` to run on JRuby even when the grammar
|
|
629
|
-
`.so` files (built for MRI) were incompatible with java-tree-sitter's Foreign Function
|
|
630
|
-
Memory API. Now the check does a live test by attempting to load a grammar, ensuring
|
|
631
|
-
the tag accurately reflects whether the Java backend is fully functional.
|
|
632
|
-
|
|
633
|
-
## [3.2.3] - 2026-01-02
|
|
634
|
-
|
|
635
|
-
- TAG: [v3.2.3][3.2.3t]
|
|
636
|
-
- COVERAGE: 94.91% -- 2088/2200 lines in 22 files
|
|
637
|
-
- BRANCH COVERAGE: 81.37% -- 738/907 branches in 22 files
|
|
638
|
-
- 90.14% documented
|
|
639
|
-
|
|
640
|
-
### Fixed
|
|
641
|
-
|
|
642
|
-
- **`parser_for` now respects explicitly requested non-native backends** - Previously,
|
|
643
|
-
`parser_for` would always try tree-sitter backends first and only fall back to alternative
|
|
644
|
-
backends if tree-sitter was unavailable. Now it checks `effective_backend` and skips
|
|
645
|
-
tree-sitter attempts entirely when a non-native backend is explicitly requested via:
|
|
646
|
-
- `TREE_HAVER_BACKEND=citrus` (or `prism`, `psych`, `commonmarker`, `markly`)
|
|
647
|
-
- `TreeHaver.backend = :citrus`
|
|
648
|
-
- `TreeHaver.with_backend(:citrus) { ... }`
|
|
649
|
-
|
|
650
|
-
Native backends (`:mri`, `:rust`, `:ffi`, `:java`) still use tree-sitter grammar discovery.
|
|
651
|
-
|
|
652
|
-
- **`load_tree_sitter_language` now correctly ignores Citrus registrations** - Previously,
|
|
653
|
-
if a language was registered with Citrus first, `load_tree_sitter_language` would
|
|
654
|
-
incorrectly try to use it even when a native backend was explicitly requested. Now it
|
|
655
|
-
only uses registrations that have a `:tree_sitter` key, allowing proper backend switching
|
|
656
|
-
between Citrus and native tree-sitter backends.
|
|
657
|
-
|
|
658
|
-
- **`load_tree_sitter_language` now validates registered paths exist** - Previously,
|
|
659
|
-
if a language had a stale/invalid tree-sitter registration with a non-existent path
|
|
660
|
-
(e.g., from a test), the code would try to use it and fail. Now it checks
|
|
661
|
-
`File.exist?(path)` before using a registered path, falling back to auto-discovery
|
|
662
|
-
via `GrammarFinder` if the registered path doesn't exist.
|
|
663
|
-
|
|
664
|
-
- **`Language.method_missing` no longer falls back to Citrus when native backend explicitly requested** -
|
|
665
|
-
Previously, when tree-sitter loading failed (e.g., .so file missing), the code would
|
|
666
|
-
silently fall back to Citrus even if the user explicitly requested `:mri`, `:rust`,
|
|
667
|
-
`:ffi`, or `:java`. Now fallback to Citrus only happens when `effective_backend` is `:auto`.
|
|
668
|
-
This is a **breaking change** for users who relied on silent fallback behavior.
|
|
669
|
-
|
|
670
|
-
- **Simplified `parser_for` implementation** - Refactored from complex nested conditionals to
|
|
671
|
-
cleaner helper methods (`load_tree_sitter_language`, `load_citrus_language`). The logic is
|
|
672
|
-
now easier to follow and maintain.
|
|
673
|
-
|
|
674
|
-
## [3.2.2] - 2026-01-01
|
|
675
|
-
|
|
676
|
-
- TAG: [v3.2.2][3.2.2t]
|
|
677
|
-
- COVERAGE: 94.79% -- 2076/2190 lines in 22 files
|
|
678
|
-
- BRANCH COVERAGE: 81.35% -- 733/901 branches in 22 files
|
|
679
|
-
- 90.14% documented
|
|
680
|
-
|
|
681
|
-
### Fixed
|
|
682
|
-
|
|
683
|
-
- RSpec dependency tags now respect `TREE_HAVER_BACKEND` environment variable
|
|
684
|
-
- When `TREE_HAVER_BACKEND=ffi` is set, MRI backend availability is not checked
|
|
685
|
-
- Prevents `BackendConflict` errors when loading gems that use tree-sitter grammars
|
|
686
|
-
- The `blocked_backends` set now includes backends that would conflict with the explicitly selected backend
|
|
687
|
-
- This allows `*-merge` gems to load correctly in test suites when a specific backend is selected
|
|
688
|
-
|
|
689
|
-
## [3.2.1] - 2025-12-31
|
|
690
|
-
|
|
691
|
-
- TAG: [v3.2.1][3.2.1t]
|
|
692
|
-
- COVERAGE: 94.75% -- 2075/2190 lines in 22 files
|
|
693
|
-
- BRANCH COVERAGE: 81.35% -- 733/901 branches in 22 files
|
|
694
|
-
- 90.14% documented
|
|
695
|
-
|
|
696
|
-
### Added
|
|
697
|
-
|
|
698
|
-
- `TreeHaver::LibraryPathUtils` module for consistent path parsing across all backends
|
|
699
|
-
- `derive_symbol_from_path(path)` - derives tree-sitter symbol (e.g., `tree_sitter_toml`) from library path
|
|
700
|
-
- `derive_language_name_from_path(path)` - derives language name (e.g., `toml`) from library path
|
|
701
|
-
- `derive_language_name_from_symbol(symbol)` - strips `tree_sitter_` prefix from symbol
|
|
702
|
-
- Handles various naming conventions: `libtree-sitter-toml.so`, `libtree_sitter_toml.so`, `tree-sitter-toml.so`, `toml.so`
|
|
703
|
-
- Isolated backend RSpec tags for running tests without loading conflicting backends
|
|
704
|
-
- `:ffi_backend_only` - runs FFI tests without triggering `mri_backend_available?` check
|
|
705
|
-
- `:mri_backend_only` - runs MRI tests without triggering `ffi_available?` check
|
|
706
|
-
- Uses `TreeHaver::Backends::BLOCKED_BY` to dynamically determine which availability checks to skip
|
|
707
|
-
- Enables `rake ffi_specs` to run FFI tests before MRI is loaded
|
|
708
|
-
- `DependencyTags.ffi_backend_only_available?` - checks FFI availability without loading MRI
|
|
709
|
-
- `DependencyTags.mri_backend_only_available?` - checks MRI availability without checking FFI
|
|
710
|
-
|
|
711
|
-
### Changed
|
|
712
|
-
|
|
713
|
-
- All backends now use shared `LibraryPathUtils` for path parsing
|
|
714
|
-
- MRI, Rust, FFI, and Java backends updated for consistency
|
|
715
|
-
- Ensures identical behavior across all tree-sitter backends
|
|
716
|
-
- `TreeHaver::Language` class extracted to `lib/tree_haver/language.rb`
|
|
717
|
-
- No API changes, just file organization
|
|
718
|
-
- Loaded via autoload for lazy loading
|
|
719
|
-
- `TreeHaver::Parser` class extracted to `lib/tree_haver/parser.rb`
|
|
720
|
-
- No API changes, just file organization
|
|
721
|
-
- Loaded via autoload for lazy loading
|
|
722
|
-
- Backend availability exclusions in `dependency_tags.rb` are now dynamic
|
|
723
|
-
- Uses `TreeHaver::Backends::BLOCKED_BY` to skip availability checks for blocked backends
|
|
724
|
-
- When running with `--tag ffi_backend_only`, MRI availability is not checked
|
|
725
|
-
- Prevents MRI from being loaded before FFI tests can run
|
|
726
|
-
- Rakefile `ffi_specs` task now uses `:ffi_backend_only` tag
|
|
727
|
-
- Ensures FFI tests run without loading MRI backend first
|
|
728
|
-
|
|
729
|
-
### Fixed
|
|
730
|
-
|
|
731
|
-
- Rakefile now uses correct RSpec tags for FFI isolation
|
|
732
|
-
- The `ffi_specs` task uses `:ffi_backend_only` to prevent MRI from loading
|
|
733
|
-
- The `remaining_specs` task excludes `:ffi_backend_only` tests
|
|
734
|
-
- Tags in Rakefile align with canonical tags from `dependency_tags.rb`
|
|
735
|
-
- `TreeHaver::RSpec::DependencyTags.mri_backend_available?` now uses correct require path
|
|
736
|
-
- Was: `require "ruby_tree_sitter"` (wrong - causes LoadError)
|
|
737
|
-
- Now: `require "tree_sitter"` (correct - gem name is ruby_tree_sitter but require path is tree_sitter)
|
|
738
|
-
- This fix ensures the MRI backend is correctly detected as available in CI environments
|
|
739
|
-
- `TreeHaver::Backends::MRI::Language.from_library` now properly derives symbol from path
|
|
740
|
-
- Previously, calling `from_library(path)` without `symbol:` would fail because `language_name` was nil
|
|
741
|
-
- Now delegates to private `from_path` after deriving symbol, ensuring proper language name derivation
|
|
742
|
-
- `from_path` is now private (but still accessible via `send` for testing if needed)
|
|
743
|
-
- Extracts language name from paths like `/usr/lib/libtree-sitter-toml.so` → `tree_sitter_toml`
|
|
744
|
-
- Handles both dash and underscore separators in filenames
|
|
745
|
-
- Handles simple language names like `toml.so` → `tree_sitter_toml`
|
|
746
|
-
- `TreeHaver::Backends::MRI::Parser#language=` now unwraps `TreeHaver::Backends::MRI::Language` wrappers
|
|
747
|
-
- Accepts both raw `TreeSitter::Language` and wrapped `TreeHaver::Backends::MRI::Language`
|
|
748
|
-
- `TreeHaver::GrammarFinder.tree_sitter_runtime_usable?` no longer references `FFI::NotFoundError` directly
|
|
749
|
-
- Prevents `NameError` when FFI gem is not loaded
|
|
750
|
-
- `TreeHaver::Parser#initialize` no longer references `FFI::NotFoundError` directly in rescue clause
|
|
751
|
-
- Uses `defined?(::FFI::NotFoundError)` check to safely handle FFI errors when FFI is loaded
|
|
752
|
-
- Prevents `NameError: uninitialized constant TreeHaver::Parser::FFI` when FFI gem is not available
|
|
753
|
-
- Extracted error handling to `handle_parser_creation_failure` private method for clarity
|
|
754
|
-
- RSpec `dependency_tags.rb` now correctly detects `--tag` options during configuration
|
|
755
|
-
- RSpec's `config.inclusion_filter.rules` is empty during configuration phase
|
|
756
|
-
- Now parses `ARGV` directly to detect `--tag ffi_backend_only` and similar tags
|
|
757
|
-
- Skips grammar availability checks (which load MRI) when running isolated backend tests
|
|
758
|
-
- Skips full dependency summary in `before(:suite)` when backends are blocked
|
|
759
|
-
- `TreeHaver::Backends::FFI.reset!` now uses consistent pattern with other backends
|
|
760
|
-
- Was using `@ffi_gem_available` with `defined?()` check, which returned truthy after `reset!` set it to nil
|
|
761
|
-
- Now uses `@load_attempted` / `@loaded` pattern like MRI, Rust, Citrus, Prism, Psych, etc.
|
|
762
|
-
- This fixes FFI tests failing after the first test when `reset!` was called in `after` blocks
|
|
763
|
-
- `TreeHaver::Language.method_missing` no longer references `FFI::NotFoundError` directly in rescue clause
|
|
764
|
-
- Uses `defined?(::FFI::NotFoundError)` check to safely handle FFI errors when FFI is loaded
|
|
765
|
-
- Prevents `NameError` when FFI gem is not available but tree-sitter backends are used
|
|
766
|
-
- Extracted Citrus fallback logic to `handle_tree_sitter_load_failure` private method
|
|
767
|
-
|
|
768
|
-
## [3.2.0] - 2025-12-30
|
|
769
|
-
|
|
770
|
-
- TAG: [v3.2.0][3.2.0t]
|
|
771
|
-
- COVERAGE: 86.82% -- 2167/2496 lines in 22 files
|
|
772
|
-
- BRANCH COVERAGE: 66.79% -- 734/1099 branches in 22 files
|
|
773
|
-
- 90.03% documented
|
|
774
|
-
|
|
775
|
-
### Added
|
|
776
|
-
|
|
777
|
-
- `TreeHaver::CITRUS_DEFAULTS` constant with default Citrus configurations for known languages
|
|
778
|
-
- Enables automatic Citrus fallback for TOML without explicit `citrus_config` parameter
|
|
779
|
-
- Currently includes configuration for `:toml` (gem: `toml-rb`, const: `TomlRB::Document`)
|
|
780
|
-
- Regression test suite for Citrus fallback (`spec/integration/citrus_fallback_spec.rb`)
|
|
781
|
-
- Tests `parser_for` with all tree-sitter backends stubbed as unavailable (simulating TruffleRuby)
|
|
782
|
-
- Tests `CitrusGrammarFinder` with nil `gem_name` and `require_path`
|
|
783
|
-
- Tests explicit Citrus backend usage on MRI via `with_backend(:citrus)`
|
|
784
|
-
- Shared examples for TOML parsing tests (`spec/support/shared_examples/toml_parsing_examples.rb`)
|
|
785
|
-
- `"toml parsing basics"` - tests basic parsing, positions, children, text extraction
|
|
786
|
-
- `"toml node navigation"` - tests first_child, named_children navigation
|
|
787
|
-
- Multi-backend TOML test suite (`spec/integration/multi_backend_toml_spec.rb`)
|
|
788
|
-
- Runs shared examples against both tree-sitter-toml and Citrus/toml-rb backends
|
|
789
|
-
- Tests backend equivalence for parsing results and positions
|
|
790
|
-
- Tagged appropriately so tests run on whichever backends are available
|
|
791
|
-
- Backend Platform Compatibility section to README
|
|
792
|
-
- Complete compatibility matrix showing which backends work on MRI, JRuby, TruffleRuby
|
|
793
|
-
- Detailed explanations for TruffleRuby and JRuby limitations
|
|
794
|
-
- `FFI.available?` method at module level for API consistency with other backends
|
|
795
|
-
- `TreeHaver.resolve_native_backend_module` method for resolving only tree-sitter backends
|
|
796
|
-
- `TreeHaver::NATIVE_BACKENDS` constant listing backends that support shared libraries
|
|
797
|
-
- TruffleRuby short-circuit in `resolve_native_backend_module` for efficiency
|
|
798
|
-
- Avoids trying 3 backends that are all known to fail on TruffleRuby
|
|
799
|
-
- `citrus_available?` method to check if Citrus backend is available
|
|
800
|
-
|
|
801
|
-
### Fixed
|
|
802
|
-
|
|
803
|
-
- **`TreeHaver::Node#child` now returns `nil` for out-of-bounds indices on all backends**
|
|
804
|
-
- MRI backend (ruby_tree_sitter) raises `IndexError` for invalid indices
|
|
805
|
-
- Other backends return `nil` for invalid indices
|
|
806
|
-
- Now consistently returns `nil` across all backends for API compatibility
|
|
807
|
-
- **Citrus backend `calculate_point` returns negative column values**
|
|
808
|
-
- When `offset` was 0, `@source.rindex("\n", -1)` searched from end of string
|
|
809
|
-
- This caused `column = 0 - (position_of_last_newline) - 1` to be negative (e.g., -34)
|
|
810
|
-
- Fix: Early return `{row: 0, column: 0}` for `offset <= 0`
|
|
811
|
-
- This bug affected both MRI and TruffleRuby when using Citrus backend
|
|
812
|
-
- **Citrus fallback fails on TruffleRuby when no explicit `citrus_config` provided**
|
|
813
|
-
- `parser_for(:toml)` would fail with `TypeError: no implicit conversion of nil into String`
|
|
814
|
-
- Root cause: `citrus_config` defaulted to `{}`, so `citrus_config[:gem_name]` was `nil`
|
|
815
|
-
- `CitrusGrammarFinder` was instantiated with `gem_name: nil`, causing `require nil`
|
|
816
|
-
- On TruffleRuby, this triggered a bug in `bundled_gems.rb` calling `File.path` on nil
|
|
817
|
-
- Fix: Added `CITRUS_DEFAULTS` with known Citrus configurations (TOML currently)
|
|
818
|
-
- Fix: `parser_for` now uses `CITRUS_DEFAULTS[name]` when no explicit config provided
|
|
819
|
-
- Fix: Added guard in `CitrusGrammarFinder#available?` to return false when `require_path` is nil
|
|
820
|
-
- Fix: Added `TypeError` to rescue clause for TruffleRuby-specific edge cases
|
|
821
|
-
- **`from_library` no longer falls back to pure-Ruby backends**
|
|
822
|
-
- Previously, calling `Language.from_library(path)` on TruffleRuby would fall back to Citrus
|
|
823
|
-
backend which then raised a confusing error about not supporting shared libraries
|
|
824
|
-
- Now `from_library` only considers native tree-sitter backends (MRI, Rust, FFI, Java)
|
|
825
|
-
- Clear error message when no native backend is available explaining the situation
|
|
826
|
-
- **Integration specs now use `parser_for` instead of explicit paths**
|
|
827
|
-
- `tree_edge_cases_spec.rb` and `node_edge_cases_spec.rb` now use `TreeHaver.parser_for(:toml)`
|
|
828
|
-
which auto-discovers the best available backend (tree-sitter or Citrus fallback)
|
|
829
|
-
- Tests now work correctly on all platforms (MRI, JRuby, TruffleRuby)
|
|
830
|
-
- Tagged with `:toml_parsing` which passes if ANY toml parser is available
|
|
831
|
-
- **Core specs now use `parser_for` instead of explicit paths**
|
|
832
|
-
- `tree_spec.rb`, `node_spec.rb`, `parser_spec.rb` converted to use `TreeHaver.parser_for(:toml)`
|
|
833
|
-
- All `:toml_grammar` tags changed to `:toml_parsing` for cross-platform compatibility
|
|
834
|
-
- Tests now run on JRuby and TruffleRuby via Citrus/toml-rb fallback
|
|
835
|
-
- FFI backend now properly reports as unavailable on TruffleRuby
|
|
836
|
-
- `ffi_gem_available?` returns `false` on TruffleRuby since tree-sitter uses STRUCT_BY_VALUE return types
|
|
837
|
-
- `FFI.available?` added at module level (was only in Native submodule)
|
|
838
|
-
- Prevents confusing runtime errors (Polyglot::ForeignException) by detecting incompatibility upfront
|
|
839
|
-
- Dependency tags now check `truffleruby?` before attempting FFI backend tests
|
|
840
|
-
- MRI backend now properly reports as unavailable on JRuby and TruffleRuby
|
|
841
|
-
- `available?` returns `false` on non-MRI platforms (C extension only works on MRI)
|
|
842
|
-
- Rust backend now properly reports as unavailable on JRuby and TruffleRuby
|
|
843
|
-
- `available?` returns `false` on non-MRI platforms (magnus requires MRI's C API)
|
|
844
|
-
- Backend compatibility matrix spec now properly skips tests for platform-incompatible backends
|
|
845
|
-
- MRI and Rust backends skip on JRuby/TruffleRuby with clear skip messages
|
|
846
|
-
- FFI backend skips on TruffleRuby with clear skip message
|
|
847
|
-
|
|
848
|
-
### Changed
|
|
849
|
-
|
|
850
|
-
- **BREAKING: RSpec Dependency Tag Naming Convention Overhaul**
|
|
851
|
-
- All dependency tags now follow consistent naming conventions with suffixes
|
|
852
|
-
- Backend tags now use `*_backend` suffix (e.g., `:commonmarker_backend`, `:markly_backend`)
|
|
853
|
-
- Engine tags now use `*_engine` suffix (e.g., `:mri_engine`, `:jruby_engine`, `:truffleruby_engine`)
|
|
854
|
-
- Grammar tags now use `*_grammar` suffix (e.g., `:bash_grammar`, `:toml_grammar`, `:json_grammar`)
|
|
855
|
-
- Parsing capability tags now use `*_parsing` suffix (e.g., `:toml_parsing`, `:markdown_parsing`)
|
|
856
|
-
- **Migration required**: Update specs using legacy tags:
|
|
857
|
-
- `:commonmarker` → `:commonmarker_backend`
|
|
858
|
-
- `:markly` → `:markly_backend`
|
|
859
|
-
- `:mri` → `:mri_engine`
|
|
860
|
-
- `:jruby` → `:jruby_engine`
|
|
861
|
-
- `:truffleruby` → `:truffleruby_engine`
|
|
862
|
-
- `:tree_sitter_bash` → `:bash_grammar`
|
|
863
|
-
- `:tree_sitter_toml` → `:toml_grammar`
|
|
864
|
-
- `:tree_sitter_json` → `:json_grammar`
|
|
865
|
-
- `:tree_sitter_jsonc` → `:jsonc_grammar`
|
|
866
|
-
- `:toml_backend` → `:toml_parsing`
|
|
867
|
-
- `:markdown_backend` → `:markdown_parsing`
|
|
868
|
-
- **Removed inner-merge dependency tags from tree_haver**
|
|
869
|
-
- Tags `:toml_merge`, `:json_merge`, `:prism_merge`, `:psych_merge` removed
|
|
870
|
-
- These belong in ast-merge gem, not tree_haver
|
|
871
|
-
- Use `require "ast/merge/rspec/dependency_tags"` for merge gem tags
|
|
872
|
-
- **API Consistency**: All backends now have uniform `available?` API at module level:
|
|
873
|
-
- `TreeHaver::Backends::FFI.available?` - checks ffi gem + not TruffleRuby + MRI not loaded
|
|
874
|
-
- `TreeHaver::Backends::MRI.available?` - checks MRI platform + ruby_tree_sitter gem
|
|
875
|
-
- `TreeHaver::Backends::Rust.available?` - checks MRI platform + tree_stump gem
|
|
876
|
-
- `TreeHaver::Backends::Java.available?` - checks JRuby platform + jtreesitter JAR
|
|
877
|
-
- `TreeHaver::Backends::Prism.available?` - checks prism gem (all platforms)
|
|
878
|
-
- `TreeHaver::Backends::Psych.available?` - checks psych stdlib (all platforms)
|
|
879
|
-
- `TreeHaver::Backends::Commonmarker.available?` - checks commonmarker gem (all platforms)
|
|
880
|
-
- `TreeHaver::Backends::Markly.available?` - checks markly gem (all platforms)
|
|
881
|
-
- `TreeHaver::Backends::Citrus.available?` - checks citrus gem (all platforms)
|
|
882
|
-
- README now accurately documents TruffleRuby backend support
|
|
883
|
-
- FFI backend doesn't work on TruffleRuby due to `STRUCT_BY_VALUE` limitation in TruffleRuby's FFI
|
|
884
|
-
- Rust backend (tree_stump) doesn't work due to magnus/rb-sys incompatibility with TruffleRuby's C API
|
|
885
|
-
- TruffleRuby users should use Prism, Psych, Commonmarker, Markly, or Citrus backends
|
|
886
|
-
- Documented confirmed tree-sitter backend limitations:
|
|
887
|
-
- **TruffleRuby**: No tree-sitter backend works (FFI, MRI, Rust all fail)
|
|
888
|
-
- **JRuby**: Only Java and FFI backends work; Rust/MRI don't
|
|
889
|
-
- Updated Rust Backend section with platform compatibility notes
|
|
890
|
-
- Updated FFI Backend section with TruffleRuby limitation details
|
|
891
|
-
- Use kettle-rb/ts-grammar-setup GHA in CI workflows
|
|
892
|
-
|
|
893
|
-
### Fixed
|
|
894
|
-
|
|
895
|
-
- Rakefile now properly overrides `test` task after `require "kettle/dev"`
|
|
896
|
-
- Works around a bug in kettle-dev where test task runs minitest loader in CI
|
|
897
|
-
- Ensures `rake test` runs RSpec specs instead of empty minitest suite
|
|
898
|
-
- `TreeHaver::RSpec::DependencyTags` now catches TruffleRuby FFI exceptions
|
|
899
|
-
- TruffleRuby's FFI raises `Polyglot::ForeignException` for unsupported types like `STRUCT_BY_VALUE`
|
|
900
|
-
- `ffi_available?` and `libtree_sitter_available?` now return `false` instead of crashing
|
|
901
|
-
- Fixes spec loading errors on TruffleRuby
|
|
902
|
-
- `TreeHaver::Backends::FFI::Language.from_library` now catches `RuntimeError` from TruffleRuby
|
|
903
|
-
- TruffleRuby raises `RuntimeError` instead of `LoadError` when a shared library cannot be opened
|
|
904
|
-
- Now properly converts to `TreeHaver::NotAvailable` with descriptive message
|
|
905
|
-
- `TreeHaver::Backends::FFI::Native.try_load!` now only sets `@loaded = true` after all `attach_function` calls succeed
|
|
906
|
-
- Previously, `loaded?` returned `true` even when `attach_function` failed (e.g., on TruffleRuby)
|
|
907
|
-
- Now `loaded?` correctly returns `false` when FFI functions couldn't be attached
|
|
908
|
-
- Ensures FFI tests are properly skipped on TruffleRuby
|
|
909
|
-
|
|
910
|
-
## [3.1.2] - 2025-12-29
|
|
911
|
-
|
|
912
|
-
- TAG: [v3.1.2][3.1.2t]
|
|
913
|
-
- COVERAGE: 87.40% -- 2171/2484 lines in 22 files
|
|
914
|
-
- BRANCH COVERAGE: 67.04% -- 726/1083 branches in 22 files
|
|
915
|
-
- 90.03% documented
|
|
916
|
-
|
|
917
|
-
### Added
|
|
918
|
-
|
|
919
|
-
- Enhanced `TreeHaver::RSpec::DependencyTags` debugging
|
|
920
|
-
- `env_summary` method returns relevant environment variables for diagnosis
|
|
921
|
-
- `grammar_works?` now logs detailed trace when `TREE_HAVER_DEBUG=1`
|
|
922
|
-
- `before(:suite)` prints both env vars and dependency status when debugging
|
|
923
|
-
- Helps diagnose differences between local and CI environments
|
|
924
|
-
- Many new specs for:
|
|
925
|
-
- TreeHaver::GrammarFinder
|
|
926
|
-
- TreeHaver::Node
|
|
927
|
-
- TreeHaver::Tree
|
|
928
|
-
|
|
929
|
-
## [3.1.1] - 2025-12-28
|
|
930
|
-
|
|
931
|
-
- TAG: [v3.1.1][3.1.1t]
|
|
932
|
-
- COVERAGE: 87.44% -- 2152/2461 lines in 22 files
|
|
933
|
-
- BRANCH COVERAGE: 66.67% -- 710/1065 branches in 22 files
|
|
934
|
-
- 90.02% documented
|
|
935
|
-
|
|
936
|
-
### Added
|
|
937
|
-
|
|
938
|
-
- **`TreeHaver::RSpec::DependencyTags`**: Shared RSpec dependency detection for the entire gem family
|
|
939
|
-
- New `lib/tree_haver/rspec.rb` entry point - other gems can simply `require "tree_haver/rspec"`
|
|
940
|
-
- Detects all TreeHaver backends: FFI, MRI, Rust, Java, Prism, Psych, Commonmarker, Markly, Citrus
|
|
941
|
-
- Ruby engine detection: `jruby?`, `truffleruby?`, `mri?`
|
|
942
|
-
- Language grammar detection: `tree_sitter_bash_available?`, `tree_sitter_toml_available?`, `tree_sitter_json_available?`, `tree_sitter_jsonc_available?`
|
|
943
|
-
- Inner-merge dependency detection: `toml_merge_available?`, `json_merge_available?`, `prism_merge_available?`, `psych_merge_available?`
|
|
944
|
-
- Composite checks: `any_toml_backend_available?`, `any_markdown_backend_available?`
|
|
945
|
-
- Records MRI backend usage when checking availability (critical for FFI conflict detection)
|
|
946
|
-
- Configures RSpec exclusion filters for all dependency tags automatically
|
|
947
|
-
- Supports debug output via `TREE_HAVER_DEBUG=1` environment variable
|
|
948
|
-
- Comprehensive documentation with usage examples
|
|
949
|
-
|
|
950
|
-
- **`TreeHaver.parser_for`**: New high-level factory method for creating configured parsers
|
|
951
|
-
- Handles all language loading complexity in one call
|
|
952
|
-
- Auto-discovers tree-sitter grammar via `GrammarFinder`
|
|
953
|
-
- Falls back to Citrus grammar if tree-sitter unavailable
|
|
954
|
-
- Accepts `library_path` for explicit grammar location
|
|
955
|
-
- Accepts `citrus_config` for Citrus fallback configuration
|
|
956
|
-
- Raises `NotAvailable` with helpful message if no backend works
|
|
957
|
-
- Example: `parser = TreeHaver.parser_for(:toml)`
|
|
958
|
-
- Raises `NotAvailable` if the specified path doesn't exist (Principle of Least Surprise)
|
|
959
|
-
- Does not back to auto-discovery when an explicit path is provided
|
|
960
|
-
- Re-raises with context-rich error message if loading from explicit path fails
|
|
961
|
-
- Auto-discovery still works normally when no `library_path` is provided
|
|
962
|
-
|
|
963
|
-
### Changed
|
|
964
|
-
|
|
965
|
-
- **Backend sibling navigation**: Backends that don't support sibling/parent navigation now raise `NotImplementedError` instead of returning `nil`
|
|
966
|
-
- This distinguishes "not implemented" from "no sibling exists"
|
|
967
|
-
- Affected backends: Prism, Psych
|
|
968
|
-
- Affected methods: `next_sibling`, `prev_sibling`, `parent`
|
|
969
|
-
|
|
970
|
-
- **Canonical sibling method name**: All backends now use `prev_sibling` as the canonical method name (not `previous_sibling`)
|
|
971
|
-
- Matches the universal `TreeHaver::Node` API
|
|
972
|
-
|
|
973
|
-
### Fixed
|
|
974
|
-
|
|
975
|
-
- **Backend conflict detection**: Fixed bug where MRI backend usage wasn't being recorded during availability checks
|
|
976
|
-
- `mri_backend_available?` now calls `TreeHaver.record_backend_usage(:mri)` after successfully loading ruby_tree_sitter
|
|
977
|
-
- This ensures FFI conflict detection works correctly even when MRI is loaded indirectly
|
|
978
|
-
|
|
979
|
-
- **GrammarFinder#not_found_message**: Improved error message when grammar file exists but no tree-sitter runtime is available
|
|
980
|
-
- Now suggests adding `ruby_tree_sitter`, `ffi`, or `tree_stump` gem to Gemfile
|
|
981
|
-
- Clearer guidance for users who have grammar files but are missing the Ruby tree-sitter bindings
|
|
982
|
-
|
|
983
|
-
## [3.1.0] - 2025-12-18
|
|
984
|
-
|
|
985
|
-
- TAG: [v3.1.0][3.1.0t]
|
|
986
|
-
- COVERAGE: 82.65% -- 943/1141 lines in 11 files
|
|
987
|
-
- BRANCH COVERAGE: 63.80% -- 349/547 branches in 11 files
|
|
988
|
-
- 88.97% documented
|
|
989
|
-
|
|
990
|
-
### Added
|
|
991
|
-
|
|
992
|
-
- **Position API Enhancements** – Added consistent position methods to all backend Node classes for compatibility with `*-merge` gems
|
|
993
|
-
- `start_line` - Returns 1-based line number where node starts (converts 0-based `start_point.row` to 1-based)
|
|
994
|
-
- `end_line` - Returns 1-based line number where node ends (converts 0-based `end_point.row` to 1-based)
|
|
995
|
-
- `source_position` - Returns hash `{start_line:, end_line:, start_column:, end_column:}` with 1-based lines and 0-based columns
|
|
996
|
-
- `first_child` - Convenience method that returns `children.first` for iteration compatibility
|
|
997
|
-
- **Fixed:** `TreeHaver::Node#start_point` and `#end_point` now handle both Point objects and hashes from backends (Prism, Citrus return hashes)
|
|
998
|
-
- **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.
|
|
999
|
-
- **Fixed:** Added Prism, Psych, Commonmarker, and Markly backends to `unwrap_language` method so language objects are properly passed to backend parsers
|
|
1000
|
-
- **Fixed:** Commonmarker backend's `text` method now safely handles container nodes that don't have string_content (wraps in rescue TypeError)
|
|
1001
|
-
- **Added to:**
|
|
1002
|
-
- Main `TreeHaver::Node` wrapper (used by tree-sitter backends: MRI, FFI, Java, Rust)
|
|
1003
|
-
- `Backends::Commonmarker::Node` - uses Commonmarker's `sourcepos` (already 1-based)
|
|
1004
|
-
- `Backends::Markly::Node` - uses Markly's `source_position` (already 1-based)
|
|
1005
|
-
- `Backends::Prism::Node` - uses Prism's `location` (already 1-based)
|
|
1006
|
-
- `Backends::Psych::Node` - calculates from `start_point`/`end_point` (0-based)
|
|
1007
|
-
- `Backends::Citrus::Node` - calculates from `start_point`/`end_point` (0-based)
|
|
1008
|
-
- **Backward Compatible:** Existing `start_point`/`end_point` methods continue to work unchanged
|
|
1009
|
-
- **Purpose:** Enables all `*-merge` gems to use consistent position API without backend-specific workarounds
|
|
1010
|
-
|
|
1011
|
-
- **Prism Backend** – New backend wrapping Ruby's official Prism parser (stdlib in Ruby 3.4+, gem for 3.2+)
|
|
1012
|
-
- `TreeHaver::Backends::Prism::Language` - Language wrapper (Ruby-only)
|
|
1013
|
-
- `TreeHaver::Backends::Prism::Parser` - Parser with `parse` and `parse_string` methods
|
|
1014
|
-
- `TreeHaver::Backends::Prism::Tree` - Tree wrapper with `root_node`, `errors`, `warnings`, `comments`
|
|
1015
|
-
- `TreeHaver::Backends::Prism::Node` - Node wrapper implementing full TreeHaver::Node protocol
|
|
1016
|
-
- Registered with `:prism` backend name, no conflicts with other backends
|
|
1017
|
-
|
|
1018
|
-
- **Psych Backend** – New backend wrapping Ruby's standard library YAML parser
|
|
1019
|
-
- `TreeHaver::Backends::Psych::Language` - Language wrapper (YAML-only)
|
|
1020
|
-
- `TreeHaver::Backends::Psych::Parser` - Parser with `parse` and `parse_string` methods
|
|
1021
|
-
- `TreeHaver::Backends::Psych::Tree` - Tree wrapper with `root_node`, `errors`
|
|
1022
|
-
- `TreeHaver::Backends::Psych::Node` - Node wrapper implementing TreeHaver::Node protocol
|
|
1023
|
-
- Psych-specific methods: `mapping?`, `sequence?`, `scalar?`, `alias?`, `mapping_entries`, `anchor`, `tag`, `value`
|
|
1024
|
-
- Registered with `:psych` backend name, no conflicts with other backends
|
|
1025
|
-
|
|
1026
|
-
- **Commonmarker Backend** – New backend wrapping the Commonmarker gem (comrak Rust parser)
|
|
1027
|
-
- `TreeHaver::Backends::Commonmarker::Language` - Language wrapper with parse options passthrough
|
|
1028
|
-
- `TreeHaver::Backends::Commonmarker::Parser` - Parser with `parse` and `parse_string` methods
|
|
1029
|
-
- `TreeHaver::Backends::Commonmarker::Tree` - Tree wrapper with `root_node`
|
|
1030
|
-
- `TreeHaver::Backends::Commonmarker::Node` - Node wrapper implementing TreeHaver::Node protocol
|
|
1031
|
-
- Commonmarker-specific methods: `header_level`, `fence_info`, `url`, `title`, `next_sibling`, `previous_sibling`, `parent`
|
|
1032
|
-
- Registered with `:commonmarker` backend name, no conflicts with other backends
|
|
1033
|
-
|
|
1034
|
-
- **Markly Backend** – New backend wrapping the Markly gem (cmark-gfm C library)
|
|
1035
|
-
- `TreeHaver::Backends::Markly::Language` - Language wrapper with flags and extensions passthrough
|
|
1036
|
-
- `TreeHaver::Backends::Markly::Parser` - Parser with `parse` and `parse_string` methods
|
|
1037
|
-
- `TreeHaver::Backends::Markly::Tree` - Tree wrapper with `root_node`
|
|
1038
|
-
- `TreeHaver::Backends::Markly::Node` - Node wrapper implementing TreeHaver::Node protocol
|
|
1039
|
-
- Type normalization: `:header` → `"heading"`, `:hrule` → `"thematic_break"`, `:html` → `"html_block"`
|
|
1040
|
-
- Markly-specific methods: `header_level`, `fence_info`, `url`, `title`, `next_sibling`, `previous_sibling`, `parent`, `raw_type`
|
|
1041
|
-
- Registered with `:markly` backend name, no conflicts with other backends
|
|
1042
|
-
|
|
1043
|
-
- **Automatic Citrus Fallback** – When tree-sitter fails, automatically fall back to Citrus backend
|
|
1044
|
-
- `TreeHaver::Language.method_missing` now catches tree-sitter loading errors (`NotAvailable`, `ArgumentError`, `LoadError`, `FFI::NotFoundError`) and falls back to registered Citrus grammar
|
|
1045
|
-
- `TreeHaver::Parser#initialize` now catches parser creation errors and falls back to Citrus parser when backend is `:auto`
|
|
1046
|
-
- `TreeHaver::Parser#language=` automatically switches to Citrus parser when a Citrus language is assigned
|
|
1047
|
-
- Enables seamless use of pure-Ruby parsers (like toml-rb) when tree-sitter runtime is unavailable
|
|
1048
|
-
|
|
1049
|
-
- **GrammarFinder Runtime Check** – `GrammarFinder#available?` now verifies tree-sitter runtime is actually usable
|
|
1050
|
-
- New `GrammarFinder.tree_sitter_runtime_usable?` class method tests if parser can be created
|
|
1051
|
-
- `TREE_SITTER_BACKENDS` constant defines which backends use tree-sitter (MRI, FFI, Rust, Java)
|
|
1052
|
-
- Prevents registration of grammars when tree-sitter runtime isn't functional
|
|
1053
|
-
- `GrammarFinder.reset_runtime_check!` for testing
|
|
1054
|
-
|
|
1055
|
-
- **Empty ENV Variable as Explicit Skip** – Setting `TREE_SITTER_<LANG>_PATH=''` explicitly disables that grammar
|
|
1056
|
-
- Previously, empty string was treated same as unset (would search paths)
|
|
1057
|
-
- Now, empty string means "do not use tree-sitter for this language"
|
|
1058
|
-
- Allows explicit opt-out to force fallback to alternative backends like Citrus
|
|
1059
|
-
- Useful for testing and environments where tree-sitter isn't desired
|
|
1060
|
-
|
|
1061
|
-
- **TOML Examples** – New example scripts demonstrating TOML parsing with various backends
|
|
1062
|
-
- `examples/auto_toml.rb` - Auto backend selection with Citrus fallback demonstration
|
|
1063
|
-
- `examples/ffi_toml.rb` - FFI backend with TOML
|
|
1064
|
-
- `examples/mri_toml.rb` - MRI backend with TOML
|
|
1065
|
-
- `examples/rust_toml.rb` - Rust backend with TOML
|
|
1066
|
-
- `examples/java_toml.rb` - Java backend with TOML (JRuby only)
|
|
1067
|
-
|
|
1068
|
-
### Fixed
|
|
1069
|
-
|
|
1070
|
-
- **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
|
|
1071
|
-
- Previously: Would raise "No grammar registered for :lang compatible with tree_sitter backend"
|
|
1072
|
-
- Now: Returns `TreeHaver::Backends::Citrus::Language` if Citrus grammar is registered
|
|
1073
|
-
- Migration: If you were catching this error, update your code to handle the fallback behavior
|
|
1074
|
-
- This is a bug fix, but would be a breaking change for some users who were relying on the old behavior
|
|
1075
|
-
|
|
1076
|
-
## [3.0.0] - 2025-12-16
|
|
1077
|
-
|
|
1078
|
-
- TAG: [v3.0.0][3.0.0t]
|
|
1079
|
-
- COVERAGE: 85.19% -- 909/1067 lines in 11 files
|
|
1080
|
-
- BRANCH COVERAGE: 67.47% -- 338/501 branches in 11 files
|
|
1081
|
-
- 92.93% documented
|
|
1082
|
-
|
|
1083
|
-
### Added
|
|
1084
|
-
|
|
1085
|
-
#### Backend Requirements
|
|
1086
|
-
|
|
1087
|
-
- **MRI Backend**: Requires `ruby_tree_sitter` v2.0+ (exceptions inherit from `Exception` not `StandardError`)
|
|
1088
|
-
- In ruby_tree_sitter v2.0, TreeSitter errors were changed to inherit from Exception for thread-safety
|
|
1089
|
-
- TreeHaver now properly handles: `ParserNotFoundError`, `LanguageLoadError`, `SymbolNotFoundError`, etc.
|
|
1090
|
-
|
|
1091
|
-
#### Thread-Safe Backend Selection (Hybrid Approach)
|
|
1092
|
-
|
|
1093
|
-
- **NEW: Block-based backend API** - `TreeHaver.with_backend(:ffi) { ... }` for thread-safe backend selection
|
|
1094
|
-
- Thread-local context with proper nesting support
|
|
1095
|
-
- Exception-safe (context restored even on errors)
|
|
1096
|
-
- Fully backward compatible with existing global backend setting
|
|
1097
|
-
- **NEW: Explicit backend parameters**
|
|
1098
|
-
- `Parser.new(backend: :mri)` - specify backend when creating parser
|
|
1099
|
-
- `Language.from_library(path, backend: :ffi)` - specify backend when loading language
|
|
1100
|
-
- Backend parameters override thread context and global settings
|
|
1101
|
-
- **NEW: Backend introspection** - `parser.backend` returns the current backend name (`:ffi`, `:mri`, etc.)
|
|
1102
|
-
- **Backend precedence chain**: `explicit parameter > thread context > global setting > :auto`
|
|
1103
|
-
- **Backend-aware caching** - Language cache now includes backend in cache key to prevent cross-backend pollution
|
|
1104
|
-
- Added `TreeHaver.effective_backend` - returns the currently effective backend considering precedence
|
|
1105
|
-
- Added `TreeHaver.current_backend_context` - returns thread-local backend context
|
|
1106
|
-
- Added `TreeHaver.resolve_backend_module(explicit_backend)` - resolves backend module with precedence
|
|
1107
|
-
|
|
1108
|
-
#### Examples and Discovery
|
|
1109
|
-
|
|
1110
|
-
- Added 18 comprehensive examples demonstrating all backends and languages
|
|
1111
|
-
- JSON examples (5): auto, MRI, Rust, FFI, Java
|
|
1112
|
-
- JSONC examples (5): auto, MRI, Rust, FFI, Java
|
|
1113
|
-
- Bash examples (5): auto, MRI, Rust, FFI, Java
|
|
1114
|
-
- Citrus examples (3): TOML, Finitio, Dhall
|
|
1115
|
-
- All examples use bundler inline (self-contained, no Gemfile needed)
|
|
1116
|
-
- Added `examples/run_all.rb` - comprehensive test runner with colored output
|
|
1117
|
-
- Updated `examples/README.md` - complete guide to all examples
|
|
1118
|
-
- Added `TreeHaver::CitrusGrammarFinder` for language-agnostic discovery and registration of Citrus-based grammar gems
|
|
1119
|
-
- Automatically discovers Citrus grammar gems by gem name and grammar constant path
|
|
1120
|
-
- Validates grammar modules respond to `.parse(source)` before registration
|
|
1121
|
-
- Provides helpful error messages when grammars are not found
|
|
1122
|
-
- Added multi-backend language registry supporting multiple backends per language simultaneously
|
|
1123
|
-
- Restructured `LanguageRegistry` to use nested hash: `{ language: { backend_type: config } }`
|
|
1124
|
-
- Enables registering both tree-sitter and Citrus grammars for the same language without conflicts
|
|
1125
|
-
- Supports runtime backend switching, benchmarking, and fallback scenarios
|
|
1126
|
-
- Added `LanguageRegistry.register(name, backend_type, **config)` with backend-specific configuration storage
|
|
1127
|
-
- Added `LanguageRegistry.registered(name, backend_type = nil)` to query by specific backend or get all backends
|
|
1128
|
-
- Added `TreeHaver::Backends::Citrus::Node#structural?` method to distinguish structural nodes from terminals
|
|
1129
|
-
- Uses Citrus grammar's `terminal?` method to dynamically determine node classification
|
|
1130
|
-
- Works with any Citrus grammar without language-specific knowledge
|
|
1131
|
-
|
|
1132
|
-
### Changed
|
|
1133
|
-
|
|
1134
|
-
- **BREAKING**: All errors now inherit from `TreeHaver::Error` which inherits from `Exception`
|
|
1135
|
-
- see: https://github.com/Faveod/ruby-tree-sitter/pull/83 for reasoning
|
|
1136
|
-
- **BREAKING**: `LanguageRegistry.register` signature changed from `register(name, path:, symbol:)` to `register(name, backend_type, **config)`
|
|
1137
|
-
- This enables proper separation of tree-sitter and Citrus configurations
|
|
1138
|
-
- Users should update to use `TreeHaver.register_language` instead of calling `LanguageRegistry.register` directly
|
|
1139
|
-
- Updated `TreeHaver.register_language` to support both tree-sitter and Citrus grammars in single call or separate calls
|
|
1140
|
-
- Can now register: `register_language(:toml, path: "...", symbol: "...", grammar_module: TomlRB::Document)`
|
|
1141
|
-
- **INTENTIONAL DESIGN**: Uses separate `if` statements (not `elsif`) to allow registering both backends simultaneously
|
|
1142
|
-
- Enables maximum flexibility: runtime backend switching, performance benchmarking, fallback scenarios
|
|
1143
|
-
- Multiple registrations for same language now merge instead of overwrite
|
|
1144
|
-
|
|
1145
|
-
### Improved
|
|
1146
|
-
|
|
1147
|
-
#### Code Quality and Documentation
|
|
1148
|
-
|
|
1149
|
-
- **Uniform backend API**: All backends now implement `reset!` method for consistent testing interface
|
|
1150
|
-
- Eliminates need for tests to manipulate private instance variables
|
|
1151
|
-
- Provides clean way to reset backend state between tests
|
|
1152
|
-
- **Documented design decisions** with inline rationale
|
|
1153
|
-
- FFI Tree finalizer behavior and why Parser doesn't use finalizers
|
|
1154
|
-
- `resolve_backend_module` early-return pattern with comprehensive comments
|
|
1155
|
-
- `register_language` multi-backend registration capability extensively documented
|
|
1156
|
-
- **Enhanced YARD documentation**
|
|
1157
|
-
- All Citrus examples now include `gem_name` parameter (matches actual usage patterns)
|
|
1158
|
-
- Added complete examples showing both single-backend and multi-backend registration
|
|
1159
|
-
- Documented backend precedence chain and thread-safety guarantees
|
|
1160
|
-
- **Comprehensive test coverage** for thread-safe backend selection
|
|
1161
|
-
- Thread-local context tests
|
|
1162
|
-
- Parser backend parameter tests
|
|
1163
|
-
- Language backend parameter tests
|
|
1164
|
-
- Concurrent parsing tests with multiple backends
|
|
1165
|
-
- Backend-aware cache isolation tests
|
|
1166
|
-
- Nested block behavior tests (inner blocks override outer blocks)
|
|
1167
|
-
- Exception safety tests (context restored even on errors)
|
|
1168
|
-
- Explicit parameter precedence tests
|
|
1169
|
-
- Updated `Language.method_missing` to automatically select appropriate grammar based on active backend
|
|
1170
|
-
- tree-sitter backends (MRI, Rust, FFI, Java) query `:tree_sitter` registry key
|
|
1171
|
-
- Citrus backend queries `:citrus` registry key
|
|
1172
|
-
- Provides clear error messages when requested backend has no registered grammar
|
|
1173
|
-
- Improved `TreeHaver::Backends::Citrus::Node#type` to use dynamic Citrus grammar introspection
|
|
1174
|
-
- Uses event `.name` method and Symbol events for accurate type extraction
|
|
1175
|
-
- Works with any Citrus grammar without language-specific code
|
|
1176
|
-
- Handles compound rules (Repeat, Choice, Optional) intelligently
|
|
1177
|
-
|
|
1178
|
-
### Fixed
|
|
1179
|
-
|
|
1180
|
-
#### Thread-Safety and Backend Selection
|
|
1181
|
-
|
|
1182
|
-
- Fixed `resolve_backend_module` to properly handle mocked backends without `available?` method
|
|
1183
|
-
- Assumes modules without `available?` are available (for test compatibility and backward compatibility)
|
|
1184
|
-
- Only rejects if module explicitly has `available?` method and returns false
|
|
1185
|
-
- Makes code more defensive and test-friendly
|
|
1186
|
-
- Fixed Language cache to include backend in cache key
|
|
1187
|
-
- Prevents returning wrong backend's Language object when switching backends
|
|
1188
|
-
- Essential for correctness with multiple backends in use
|
|
1189
|
-
- Cache key now: `"#{path}:#{symbol}:#{backend}"` instead of just `"#{path}:#{symbol}"`
|
|
1190
|
-
- Fixed `TreeHaver.register_language` to properly support multi-backend registration
|
|
1191
|
-
- Documented intentional design: uses `if` not `elsif` to allow both backends in one call
|
|
1192
|
-
- Added comprehensive inline comments explaining why no early return
|
|
1193
|
-
- Added extensive YARD documentation with examples
|
|
1194
|
-
|
|
1195
|
-
#### Backend Bug Fixes
|
|
1196
|
-
|
|
1197
|
-
- Fixed critical double-wrapping bug in ALL backends (MRI, Rust, FFI, Java, Citrus)
|
|
1198
|
-
- Backend `Parser#parse` and `parse_string` methods now return raw backend trees
|
|
1199
|
-
- TreeHaver::Parser wraps the raw tree in TreeHaver::Tree (single wrapping)
|
|
1200
|
-
- Previously backends were returning TreeHaver::Tree, then TreeHaver::Parser wrapped it again (double wrapping)
|
|
1201
|
-
- This caused `@inner_tree` to be a TreeHaver::Tree instead of raw backend tree, leading to nil errors
|
|
1202
|
-
- Fixed TreeHaver::Parser to pass source parameter when wrapping backend trees
|
|
1203
|
-
- Enables `Node#text` to work correctly by providing source for text extraction
|
|
1204
|
-
- Fixes all parse and parse_string methods to include `source: source` parameter
|
|
1205
|
-
- Fixed MRI backend to properly use ruby_tree_sitter API
|
|
1206
|
-
- Fixed `require "tree_sitter"` (gem name is `ruby_tree_sitter` but requires `tree_sitter`)
|
|
1207
|
-
- Fixed `Language.load` to use correct argument order: `(symbol_name, path)`
|
|
1208
|
-
- Fixed `Parser#parse` to use `parse_string(nil, source)` instead of creating Input objects
|
|
1209
|
-
- Fixed `Language.from_library` to implement the expected signature matching other backends
|
|
1210
|
-
- Fixed FFI backend missing essential node methods
|
|
1211
|
-
- Added `ts_node_start_byte`, `ts_node_end_byte`, `ts_node_start_point`, `ts_node_end_point`
|
|
1212
|
-
- Added `ts_node_is_null`, `ts_node_is_named`
|
|
1213
|
-
- These methods are required for accessing node byte positions and metadata
|
|
1214
|
-
- Fixes `NoMethodError` when using FFI backend to traverse AST nodes
|
|
1215
|
-
- Fixed GrammarFinder error messages for environment variable validation
|
|
1216
|
-
- Detects leading/trailing whitespace in paths and provides correction suggestions
|
|
1217
|
-
- Shows when TREE_SITTER_*_PATH is set but points to nonexistent file
|
|
1218
|
-
- Provides helpful guidance for setting environment variables correctly
|
|
1219
|
-
- Fixed registry conflicts when registering multiple backend types for the same language
|
|
1220
|
-
- Fixed `CitrusGrammarFinder` to use gem name as-is for require path (e.g., `require "toml-rb"` not `require "toml/rb"`)
|
|
1221
|
-
- Fixed Citrus backend infinite recursion in `Node#extract_type_from_event`
|
|
1222
|
-
- Added cycle detection to prevent stack overflow when traversing recursive grammar structures
|
|
1223
|
-
|
|
1224
|
-
### Known Issues
|
|
1225
|
-
|
|
1226
|
-
- **MRI backend + Bash grammar**: ABI/symbol loading incompatibility
|
|
1227
|
-
- The ruby_tree_sitter gem cannot load tree-sitter-bash grammar (symbol not found)
|
|
1228
|
-
- Workaround: Use FFI backend instead (works perfectly)
|
|
1229
|
-
- This is documented in examples and test runner
|
|
1230
|
-
- **Rust backend + Bash grammar**: Version mismatch due to static linking
|
|
1231
|
-
- tree_stump statically links tree-sitter at compile time
|
|
1232
|
-
- System bash.so may be compiled with different tree-sitter version
|
|
1233
|
-
- Workaround: Use FFI backend (dynamic linking avoids version conflicts)
|
|
1234
|
-
- This is documented in examples with detailed explanations
|
|
1235
|
-
|
|
1236
|
-
### Notes on Backward Compatibility
|
|
1237
|
-
|
|
1238
|
-
Despite the major version bump to 3.0.0 (following semver due to the breaking `LanguageRegistry.register` signature change), **most users will experience NO BREAKING CHANGES**:
|
|
1239
|
-
|
|
1240
|
-
#### Why 3.0.0?
|
|
1241
|
-
|
|
1242
|
-
- `LanguageRegistry.register` signature changed to support multi-backend registration
|
|
1243
|
-
- However, most users should use `TreeHaver.register_language` (which remains backward compatible)
|
|
1244
|
-
- Direct calls to `LanguageRegistry.register` are rare in practice
|
|
1245
|
-
|
|
1246
|
-
#### What Stays the Same?
|
|
1247
|
-
|
|
1248
|
-
- **Global backend setting**: `TreeHaver.backend = :ffi` works unchanged
|
|
1249
|
-
- **Parser creation**: `Parser.new` without parameters works as before
|
|
1250
|
-
- **Language loading**: `Language.from_library(path)` works as before
|
|
1251
|
-
- **Auto-detection**: Backend auto-selection still works when backend is `:auto`
|
|
1252
|
-
- **All existing code** continues to work without modifications
|
|
1253
|
-
|
|
1254
|
-
#### What's New (All Optional)?
|
|
1255
|
-
|
|
1256
|
-
- Thread-safe block API: `TreeHaver.with_backend(:ffi) { ... }`
|
|
1257
|
-
- Explicit backend parameters: `Parser.new(backend: :mri)`
|
|
1258
|
-
- Backend introspection: `parser.backend`
|
|
1259
|
-
- Multi-backend language registration
|
|
1260
|
-
|
|
1261
|
-
**Migration Path**: Existing codebases can upgrade to 3.0.0 and gain access to new thread-safe features without changing any existing code. The new features are purely additive and opt-in.
|
|
1262
|
-
|
|
1263
|
-
## [2.0.0] - 2025-12-15
|
|
1264
|
-
|
|
1265
|
-
- TAG: [v2.0.0][2.0.0t]
|
|
1266
|
-
- COVERAGE: 82.78% -- 601/726 lines in 11 files
|
|
1267
|
-
- BRANCH COVERAGE: 70.45% -- 186/264 branches in 11 files
|
|
1268
|
-
- 91.90% documented
|
|
1269
|
-
|
|
1270
|
-
### Added
|
|
1271
|
-
|
|
1272
|
-
- Added support for Citrus backend (`backends/citrus.rb`) - a pure Ruby grammar parser with its own distinct grammar structure
|
|
1273
|
-
- Added `TreeHaver::Tree` unified wrapper class providing consistent API across all backends
|
|
1274
|
-
- Added `TreeHaver::Node` unified wrapper class providing consistent API across all backends
|
|
1275
|
-
- Added `TreeHaver::Point` class that works as both object and hash for position compatibility
|
|
1276
|
-
- Added passthrough mechanism via `method_missing` for accessing backend-specific features
|
|
1277
|
-
- Added `inner_node` accessor on `TreeHaver::Node` for advanced backend-specific usage
|
|
1278
|
-
- Added `inner_tree` accessor on `TreeHaver::Tree` for advanced backend-specific usage
|
|
1279
|
-
- Added comprehensive test suite for `TreeHaver::Node` wrapper class (88 examples)
|
|
1280
|
-
- Added comprehensive test suite for `TreeHaver::Tree` wrapper class (17 examples)
|
|
1281
|
-
- Added comprehensive test suite for `TreeHaver::Parser` class (12 examples)
|
|
1282
|
-
- Added complete test coverage for Citrus backend (41 examples)
|
|
1283
|
-
- Enhanced `TreeHaver::Language` tests for dynamic language helpers
|
|
1284
|
-
|
|
1285
|
-
### Changed
|
|
1286
|
-
|
|
1287
|
-
- **BREAKING:** All backends now return `TreeHaver::Tree` from `Parser#parse` and `Parser#parse_string`
|
|
1288
|
-
- **BREAKING:** `TreeHaver::Tree#root_node` now returns `TreeHaver::Node` instead of backend-specific node
|
|
1289
|
-
- **BREAKING:** All child/sibling/parent methods on nodes now return `TreeHaver::Node` wrappers
|
|
1290
|
-
- Updated MRI backend (`backends/mri.rb`) to return wrapped `TreeHaver::Tree` with source
|
|
1291
|
-
- Updated Rust backend (`backends/rust.rb`) to return wrapped `TreeHaver::Tree` with source
|
|
1292
|
-
- Updated FFI backend (`backends/ffi.rb`) to return wrapped `TreeHaver::Tree` with source
|
|
1293
|
-
- Updated Java backend (`backends/java.rb`) to return wrapped `TreeHaver::Tree` with source
|
|
1294
|
-
- Updated Citrus backend (`backends/citrus.rb`) to return wrapped `TreeHaver::Tree` with source
|
|
1295
|
-
- Disabled old pass-through stub classes in `tree_haver.rb` (wrapped in `if false` for reference)
|
|
1296
|
-
|
|
1297
|
-
### Fixed
|
|
1298
|
-
|
|
1299
|
-
- Fixed `TreeHaver::Tree#supports_editing?` and `#edit` to handle Delegator wrappers correctly by using `.method(:edit)` check instead of `respond_to?`
|
|
1300
|
-
- Fixed `PathValidator` to accept versioned `.so` files (e.g., `.so.0`, `.so.14`) which are standard on Linux systems
|
|
1301
|
-
- Fixed backend portability - code now works identically across MRI, Rust, FFI, Java, and Citrus backends
|
|
1302
|
-
- Fixed inconsistent API - `node.type` now works on all backends (was `node.kind` on TreeStump)
|
|
1303
|
-
- Fixed position objects - `start_point` and `end_point` now return objects that work as both `.row` and `[:row]`
|
|
1304
|
-
- Fixed child iteration - `node.each` and `node.children` now consistently return `TreeHaver::Node` objects
|
|
1305
|
-
- Fixed text extraction - `node.text` now works consistently by storing source in `TreeHaver::Tree`
|
|
1306
|
-
|
|
1307
|
-
## [1.0.0] - 2025-12-15
|
|
1308
|
-
|
|
1309
|
-
- TAG: [v1.0.0][1.0.0t]
|
|
1310
|
-
- COVERAGE: 97.21% -- 487/501 lines in 8 files
|
|
1311
|
-
- BRANCH COVERAGE: 90.75% -- 157/173 branches in 8 files
|
|
1312
|
-
- 97.31% documented
|
|
1313
|
-
|
|
1314
|
-
### Added
|
|
1315
|
-
|
|
1316
|
-
- Initial release
|
|
1317
|
-
|
|
1318
|
-
[Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v5.0.4...HEAD
|
|
1319
|
-
[5.0.4]: https://github.com/kettle-rb/tree_haver/compare/v5.0.3...v5.0.4
|
|
1320
|
-
[5.0.4t]: https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.4
|
|
1321
|
-
[5.0.3]: https://github.com/kettle-rb/tree_haver/compare/v5.0.2...v5.0.3
|
|
1322
|
-
[5.0.3t]: https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.3
|
|
1323
|
-
[5.0.2]: https://github.com/kettle-rb/tree_haver/compare/v5.0.1...v5.0.2
|
|
1324
|
-
[5.0.2t]: https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.2
|
|
1325
|
-
[5.0.1]: https://github.com/kettle-rb/tree_haver/compare/v5.0.0...v5.0.1
|
|
1326
|
-
[5.0.1t]: https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.1
|
|
1327
|
-
[5.0.0]: https://github.com/kettle-rb/tree_haver/compare/v4.0.5...v5.0.0
|
|
1328
|
-
[5.0.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v5.0.0
|
|
1329
|
-
[4.0.5]: https://github.com/kettle-rb/tree_haver/compare/v4.0.4...v4.0.5
|
|
1330
|
-
[4.0.5t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.5
|
|
1331
|
-
[4.0.4]: https://github.com/kettle-rb/tree_haver/compare/v4.0.3...v4.0.4
|
|
1332
|
-
[4.0.4t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.4
|
|
1333
|
-
[4.0.3]: https://github.com/kettle-rb/tree_haver/compare/v4.0.2...v4.0.3
|
|
1334
|
-
[4.0.3t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.3
|
|
1335
|
-
[4.0.2]: https://github.com/kettle-rb/tree_haver/compare/v4.0.1...v4.0.2
|
|
1336
|
-
[4.0.2t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.2
|
|
1337
|
-
[4.0.1]: https://github.com/kettle-rb/tree_haver/compare/v4.0.0...v4.0.1
|
|
1338
|
-
[4.0.1t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.1
|
|
1339
|
-
[4.0.0]: https://github.com/kettle-rb/tree_haver/compare/v3.2.6...v4.0.0
|
|
1340
|
-
[4.0.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.0
|
|
1341
|
-
[3.2.6]: https://github.com/kettle-rb/tree_haver/compare/v3.2.5...v3.2.6
|
|
1342
|
-
[3.2.6t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.6
|
|
1343
|
-
[3.2.5]: https://github.com/kettle-rb/tree_haver/compare/v3.2.4...v3.2.5
|
|
1344
|
-
[3.2.5t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.5
|
|
1345
|
-
[3.2.4]: https://github.com/kettle-rb/tree_haver/compare/v3.2.3...v3.2.4
|
|
1346
|
-
[3.2.4t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.4
|
|
1347
|
-
[3.2.3]: https://github.com/kettle-rb/tree_haver/compare/v3.2.2...v3.2.3
|
|
1348
|
-
[3.2.3t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.3
|
|
1349
|
-
[3.2.2]: https://github.com/kettle-rb/tree_haver/compare/v3.2.1...v3.2.2
|
|
1350
|
-
[3.2.2t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.2
|
|
1351
|
-
[3.2.1]: https://github.com/kettle-rb/tree_haver/compare/v3.2.0...v3.2.1
|
|
1352
|
-
[3.2.1t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.1
|
|
1353
|
-
[3.2.0]: https://github.com/kettle-rb/tree_haver/compare/v3.1.2...v3.2.0
|
|
1354
|
-
[3.2.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.2.0
|
|
1355
|
-
[3.1.2]: https://github.com/kettle-rb/tree_haver/compare/v3.1.1...v3.1.2
|
|
1356
|
-
[3.1.2t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.1.2
|
|
1357
|
-
[3.1.1]: https://github.com/kettle-rb/tree_haver/compare/v3.1.0...v3.1.1
|
|
1358
|
-
[3.1.1t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.1.1
|
|
1359
|
-
[3.1.0]: https://github.com/kettle-rb/tree_haver/compare/v3.0.0...v3.1.0
|
|
1360
|
-
[3.1.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.1.0
|
|
1361
|
-
[3.0.0]: https://github.com/kettle-rb/tree_haver/compare/v2.0.0...v3.0.0
|
|
1362
|
-
[3.0.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v3.0.0
|
|
1363
|
-
[2.0.0]: https://github.com/kettle-rb/tree_haver/compare/v1.0.0...v2.0.0
|
|
1364
|
-
[2.0.0t]: https://github.com/kettle-rb/tree_haver/releases/tag/v2.0.0
|
|
1365
|
-
[1.0.0]: https://github.com/kettle-rb/tree_haver/compare/a89211bff10f4440b96758a8ac9d7d539001b0c8...v1.0.0
|
|
1366
|
-
[1.0.0t]: https://github.com/kettle-rb/tree_haver/tags/v1.0.0
|