tree_haver 4.0.4 → 4.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/CHANGELOG.md +50 -2
- data/README.md +1 -1
- data/lib/tree_haver/backends/ffi.rb +181 -1
- data/lib/tree_haver/grammar_finder.rb +1 -3
- data/lib/tree_haver/language.rb +2 -8
- data/lib/tree_haver/parser.rb +1 -7
- data/lib/tree_haver/rspec/dependency_tags.rb +75 -18
- data/lib/tree_haver/version.rb +1 -1
- data.tar.gz.sig +0 -0
- metadata +4 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a3f6764cb2c0399f4255cc4536745156cd8391fa1818b9b84db9d0b39ca17fa9
|
|
4
|
+
data.tar.gz: d9e12364a4480307b8cd8a7ca0315bbeba7764c6bfe20747b3b8ff792e9fe2e7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6a95af29f397cea98bc29a93885f9285637ae82469417b62c981629d21861f5b64560ca0e2c21b0405abdc541d04b39f6c1848928273b82679ba3f169f885549
|
|
7
|
+
data.tar.gz: bbd048585aed007eed86bdd117b18cff1e72e378fd20bbc07a252b6095ab38d4c5c9eb83fc572c21bcd07e515b2ad1bfae50f9705b75f69f4d955ecf65d4b844
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Changelog
|
|
1
|
+
ed# Changelog
|
|
2
2
|
|
|
3
3
|
[![SemVer 2.0.0][📌semver-img]][📌semver] [![Keep-A-Changelog 1.0.0][📗keep-changelog-img]][📗keep-changelog]
|
|
4
4
|
|
|
@@ -30,6 +30,52 @@ Please file a bug if you notice a violation of semantic versioning.
|
|
|
30
30
|
|
|
31
31
|
### Security
|
|
32
32
|
|
|
33
|
+
## [4.0.5] - 2026-01-09
|
|
34
|
+
|
|
35
|
+
- TAG: [v4.0.5][4.0.5t]
|
|
36
|
+
- COVERAGE: 93.50% -- 2058/2201 lines in 28 files
|
|
37
|
+
- BRANCH COVERAGE: 81.11% -- 803/990 branches in 28 files
|
|
38
|
+
- 95.60% documented
|
|
39
|
+
|
|
40
|
+
### Added
|
|
41
|
+
|
|
42
|
+
- **FFI Backend**: Added `child_by_field_name` method to `TreeHaver::Backends::FFI::Node`
|
|
43
|
+
- Enables field-based child access using tree-sitter's `ts_node_child_by_field_name` C API
|
|
44
|
+
- Works with all grammars (JSON, JSONC, TOML, Bash, etc.) that define field names
|
|
45
|
+
- Fixes compatibility issues with json-merge, jsonc-merge, and other gems that use field access
|
|
46
|
+
- Example: `pair.child_by_field_name("key")` returns the key node from a JSON pair
|
|
47
|
+
- **RSpec Dependency Tags**: Added `compute_blocked_backends` method
|
|
48
|
+
- Determines blocked backends from `TREE_HAVER_BACKEND` env and ARGV `--tag` options
|
|
49
|
+
- Called by `summary` when `@blocked_backends` isn't set yet (before RSpec.configure runs)
|
|
50
|
+
- Fixes issue where gem-specific `before(:suite)` hooks could load blocked backends
|
|
51
|
+
- **RSpec Dependency Tags**: Added `LD_LIBRARY_PATH` and `DYLD_LIBRARY_PATH` to `env_summary`
|
|
52
|
+
- These library paths are relevant for tree-sitter shared library loading
|
|
53
|
+
- Useful for debugging grammar loading issues
|
|
54
|
+
- **RSpec Dependency Tags**: Added `TREE_SITTER_RBS_PATH` to `env_summary`
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- **Language#method_missing**: Simplified error handling in `Language#method_missing`
|
|
59
|
+
- Removed unreachable rescue block for `FFI::NotFoundError`
|
|
60
|
+
- `FFI::NotFoundError` inherits from `LoadError`, so it's already caught by the prior rescue clause
|
|
61
|
+
- Reduces code complexity without changing behavior
|
|
62
|
+
- **Parser#initialize**: Simplified error handling in `Parser#initialize`
|
|
63
|
+
- Same fix as Language - removed unreachable `FFI::NotFoundError` handling
|
|
64
|
+
- Added comment noting that `FFI::NotFoundError` inherits from `LoadError`
|
|
65
|
+
- **FFI Backend Native#try_load!**: Removed redundant `FFI::NotFoundError` from rescue clause
|
|
66
|
+
- Only rescues `LoadError` now with comment explaining inheritance
|
|
67
|
+
- **GrammarFinder.tree_sitter_runtime_usable?**: Removed redundant `StandardError` rescue clause
|
|
68
|
+
- `LoadError` already catches `FFI::NotFoundError`
|
|
69
|
+
- Added comment explaining the inheritance relationship
|
|
70
|
+
|
|
71
|
+
### Fixed
|
|
72
|
+
|
|
73
|
+
- **Test Isolation**: Fixed state leakage in `language_registry_spec.rb`
|
|
74
|
+
- Tests were registering real language names (`:toml`, `:json`, `:yaml`) with fake paths
|
|
75
|
+
- These registrations persisted and polluted other tests that expected real grammar paths
|
|
76
|
+
- Changed all tests to use unique test-only language names (prefixed with `test_lang_`)
|
|
77
|
+
- Fixes 2 spec failures when running all tests together (`TreeHaver::Tree#edit` specs)
|
|
78
|
+
|
|
33
79
|
## [4.0.4] - 2026-01-09
|
|
34
80
|
|
|
35
81
|
- TAG: [v4.0.4][4.0.4t]
|
|
@@ -1024,7 +1070,9 @@ Despite the major version bump to 3.0.0 (following semver due to the breaking `L
|
|
|
1024
1070
|
|
|
1025
1071
|
- Initial release
|
|
1026
1072
|
|
|
1027
|
-
[Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v4.0.
|
|
1073
|
+
[Unreleased]: https://github.com/kettle-rb/tree_haver/compare/v4.0.5...HEAD
|
|
1074
|
+
[4.0.5]: https://github.com/kettle-rb/tree_haver/compare/v4.0.4...v4.0.5
|
|
1075
|
+
[4.0.5t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.5
|
|
1028
1076
|
[4.0.4]: https://github.com/kettle-rb/tree_haver/compare/v4.0.3...v4.0.4
|
|
1029
1077
|
[4.0.4t]: https://github.com/kettle-rb/tree_haver/releases/tag/v4.0.4
|
|
1030
1078
|
[4.0.3]: https://github.com/kettle-rb/tree_haver/compare/v4.0.2...v4.0.3
|
data/README.md
CHANGED
|
@@ -2182,7 +2182,7 @@ Thanks for RTFM. ☺️
|
|
|
2182
2182
|
[📌gitmoji]: https://gitmoji.dev
|
|
2183
2183
|
[📌gitmoji-img]: https://img.shields.io/badge/gitmoji_commits-%20%F0%9F%98%9C%20%F0%9F%98%8D-34495e.svg?style=flat-square
|
|
2184
2184
|
[🧮kloc]: https://www.youtube.com/watch?v=dQw4w9WgXcQ
|
|
2185
|
-
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.
|
|
2185
|
+
[🧮kloc-img]: https://img.shields.io/badge/KLOC-2.201-FFDD67.svg?style=for-the-badge&logo=YouTube&logoColor=blue
|
|
2186
2186
|
[🔐security]: SECURITY.md
|
|
2187
2187
|
[🔐security-img]: https://img.shields.io/badge/security-policy-259D6C.svg?style=flat
|
|
2188
2188
|
[📄copyright-notice-explainer]: https://opensource.stackexchange.com/questions/5778/why-do-licenses-such-as-the-mit-license-specify-a-single-year
|
|
@@ -236,7 +236,8 @@ module TreeHaver
|
|
|
236
236
|
ffi_lib(name)
|
|
237
237
|
lib_loaded = true
|
|
238
238
|
break
|
|
239
|
-
rescue
|
|
239
|
+
rescue LoadError => e
|
|
240
|
+
# Note: FFI::NotFoundError inherits from LoadError, so it's caught here too
|
|
240
241
|
last_error = e
|
|
241
242
|
end
|
|
242
243
|
|
|
@@ -267,6 +268,7 @@ module TreeHaver
|
|
|
267
268
|
attach_function(:ts_node_type, [:ts_node], :string)
|
|
268
269
|
attach_function(:ts_node_child_count, [:ts_node], :uint32)
|
|
269
270
|
attach_function(:ts_node_child, [:ts_node, :uint32], :ts_node)
|
|
271
|
+
attach_function(:ts_node_child_by_field_name, [:ts_node, :string, :uint32], :ts_node)
|
|
270
272
|
attach_function(:ts_node_start_byte, [:ts_node], :uint32)
|
|
271
273
|
attach_function(:ts_node_end_byte, [:ts_node], :uint32)
|
|
272
274
|
attach_function(:ts_node_start_point, [:ts_node], :ts_point)
|
|
@@ -276,6 +278,21 @@ module TreeHaver
|
|
|
276
278
|
attach_function(:ts_node_is_missing, [:ts_node], :bool)
|
|
277
279
|
attach_function(:ts_node_has_error, [:ts_node], :bool)
|
|
278
280
|
|
|
281
|
+
# Node navigation functions
|
|
282
|
+
attach_function(:ts_node_parent, [:ts_node], :ts_node)
|
|
283
|
+
attach_function(:ts_node_next_sibling, [:ts_node], :ts_node)
|
|
284
|
+
attach_function(:ts_node_prev_sibling, [:ts_node], :ts_node)
|
|
285
|
+
attach_function(:ts_node_next_named_sibling, [:ts_node], :ts_node)
|
|
286
|
+
attach_function(:ts_node_prev_named_sibling, [:ts_node], :ts_node)
|
|
287
|
+
attach_function(:ts_node_named_child, [:ts_node, :uint32], :ts_node)
|
|
288
|
+
attach_function(:ts_node_named_child_count, [:ts_node], :uint32)
|
|
289
|
+
|
|
290
|
+
# Descendant lookup functions
|
|
291
|
+
attach_function(:ts_node_descendant_for_byte_range, [:ts_node, :uint32, :uint32], :ts_node)
|
|
292
|
+
attach_function(:ts_node_descendant_for_point_range, [:ts_node, :ts_point, :ts_point], :ts_node)
|
|
293
|
+
attach_function(:ts_node_named_descendant_for_byte_range, [:ts_node, :uint32, :uint32], :ts_node)
|
|
294
|
+
attach_function(:ts_node_named_descendant_for_point_range, [:ts_node, :ts_point, :ts_point], :ts_node)
|
|
295
|
+
|
|
279
296
|
# Only mark as fully loaded after all attach_function calls succeed
|
|
280
297
|
@loaded = true
|
|
281
298
|
end
|
|
@@ -663,6 +680,25 @@ module TreeHaver
|
|
|
663
680
|
Node.new(child_node)
|
|
664
681
|
end
|
|
665
682
|
|
|
683
|
+
# Get a child node by field name
|
|
684
|
+
#
|
|
685
|
+
# Tree-sitter grammars define named fields for certain child positions.
|
|
686
|
+
# For example, in JSON, a "pair" node has "key" and "value" fields.
|
|
687
|
+
#
|
|
688
|
+
# @param field_name [String] the field name to look up
|
|
689
|
+
# @return [Node, nil] the child node, or nil if no child has that field
|
|
690
|
+
# @example Get the key from a JSON pair
|
|
691
|
+
# pair.child_by_field_name("key") #=> Node (type: "string")
|
|
692
|
+
# pair.child_by_field_name("value") #=> Node (type: "string" or "number", etc.)
|
|
693
|
+
def child_by_field_name(field_name)
|
|
694
|
+
name = String(field_name)
|
|
695
|
+
child_node = Native.ts_node_child_by_field_name(@val, name, name.bytesize)
|
|
696
|
+
# ts_node_child_by_field_name returns a null node if field not found
|
|
697
|
+
return if Native.ts_node_is_null(child_node)
|
|
698
|
+
|
|
699
|
+
Node.new(child_node)
|
|
700
|
+
end
|
|
701
|
+
|
|
666
702
|
# Get start byte offset
|
|
667
703
|
#
|
|
668
704
|
# @return [Integer]
|
|
@@ -718,6 +754,150 @@ module TreeHaver
|
|
|
718
754
|
!!Native.ts_node_is_missing(@val)
|
|
719
755
|
end
|
|
720
756
|
|
|
757
|
+
# Check if this is a named node
|
|
758
|
+
#
|
|
759
|
+
# Named nodes represent syntactic constructs (e.g., "pair", "object").
|
|
760
|
+
# Anonymous nodes represent syntax/punctuation (e.g., "{", ",").
|
|
761
|
+
#
|
|
762
|
+
# @return [Boolean] true if this is a named node
|
|
763
|
+
def named?
|
|
764
|
+
!!Native.ts_node_is_named(@val)
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# Get the parent node
|
|
768
|
+
#
|
|
769
|
+
# @return [Node, nil] parent node or nil if this is the root
|
|
770
|
+
def parent
|
|
771
|
+
parent_node = Native.ts_node_parent(@val)
|
|
772
|
+
return if Native.ts_node_is_null(parent_node)
|
|
773
|
+
|
|
774
|
+
Node.new(parent_node)
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
# Get the next sibling node
|
|
778
|
+
#
|
|
779
|
+
# @return [Node, nil] next sibling or nil if none
|
|
780
|
+
def next_sibling
|
|
781
|
+
sibling = Native.ts_node_next_sibling(@val)
|
|
782
|
+
return if Native.ts_node_is_null(sibling)
|
|
783
|
+
|
|
784
|
+
Node.new(sibling)
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
# Get the previous sibling node
|
|
788
|
+
#
|
|
789
|
+
# @return [Node, nil] previous sibling or nil if none
|
|
790
|
+
def prev_sibling
|
|
791
|
+
sibling = Native.ts_node_prev_sibling(@val)
|
|
792
|
+
return if Native.ts_node_is_null(sibling)
|
|
793
|
+
|
|
794
|
+
Node.new(sibling)
|
|
795
|
+
end
|
|
796
|
+
|
|
797
|
+
# Get the next named sibling node
|
|
798
|
+
#
|
|
799
|
+
# @return [Node, nil] next named sibling or nil if none
|
|
800
|
+
def next_named_sibling
|
|
801
|
+
sibling = Native.ts_node_next_named_sibling(@val)
|
|
802
|
+
return if Native.ts_node_is_null(sibling)
|
|
803
|
+
|
|
804
|
+
Node.new(sibling)
|
|
805
|
+
end
|
|
806
|
+
|
|
807
|
+
# Get the previous named sibling node
|
|
808
|
+
#
|
|
809
|
+
# @return [Node, nil] previous named sibling or nil if none
|
|
810
|
+
def prev_named_sibling
|
|
811
|
+
sibling = Native.ts_node_prev_named_sibling(@val)
|
|
812
|
+
return if Native.ts_node_is_null(sibling)
|
|
813
|
+
|
|
814
|
+
Node.new(sibling)
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
# Get a named child by index
|
|
818
|
+
#
|
|
819
|
+
# @param index [Integer] named child index (0-based)
|
|
820
|
+
# @return [Node, nil] named child or nil if index out of bounds
|
|
821
|
+
def named_child(index)
|
|
822
|
+
return if index < 0 || index >= named_child_count
|
|
823
|
+
|
|
824
|
+
child_node = Native.ts_node_named_child(@val, index)
|
|
825
|
+
return if Native.ts_node_is_null(child_node)
|
|
826
|
+
|
|
827
|
+
Node.new(child_node)
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
# Get the count of named children
|
|
831
|
+
#
|
|
832
|
+
# @return [Integer] number of named children
|
|
833
|
+
def named_child_count
|
|
834
|
+
Native.ts_node_named_child_count(@val)
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
# Find the smallest descendant that spans the given byte range
|
|
838
|
+
#
|
|
839
|
+
# @param start_byte [Integer] start byte offset
|
|
840
|
+
# @param end_byte [Integer] end byte offset
|
|
841
|
+
# @return [Node, nil] descendant node or nil if not found
|
|
842
|
+
def descendant_for_byte_range(start_byte, end_byte)
|
|
843
|
+
node = Native.ts_node_descendant_for_byte_range(@val, start_byte, end_byte)
|
|
844
|
+
return if Native.ts_node_is_null(node)
|
|
845
|
+
|
|
846
|
+
Node.new(node)
|
|
847
|
+
end
|
|
848
|
+
|
|
849
|
+
# Find the smallest named descendant that spans the given byte range
|
|
850
|
+
#
|
|
851
|
+
# @param start_byte [Integer] start byte offset
|
|
852
|
+
# @param end_byte [Integer] end byte offset
|
|
853
|
+
# @return [Node, nil] named descendant node or nil if not found
|
|
854
|
+
def named_descendant_for_byte_range(start_byte, end_byte)
|
|
855
|
+
node = Native.ts_node_named_descendant_for_byte_range(@val, start_byte, end_byte)
|
|
856
|
+
return if Native.ts_node_is_null(node)
|
|
857
|
+
|
|
858
|
+
Node.new(node)
|
|
859
|
+
end
|
|
860
|
+
|
|
861
|
+
# Find the smallest descendant that spans the given point range
|
|
862
|
+
#
|
|
863
|
+
# @param start_point [TreeHaver::Point, Hash] start point with :row and :column
|
|
864
|
+
# @param end_point [TreeHaver::Point, Hash] end point with :row and :column
|
|
865
|
+
# @return [Node, nil] descendant node or nil if not found
|
|
866
|
+
def descendant_for_point_range(start_point, end_point)
|
|
867
|
+
start_pt = Native::TSPoint.new
|
|
868
|
+
start_pt[:row] = start_point.respond_to?(:row) ? start_point.row : start_point[:row]
|
|
869
|
+
start_pt[:column] = start_point.respond_to?(:column) ? start_point.column : start_point[:column]
|
|
870
|
+
|
|
871
|
+
end_pt = Native::TSPoint.new
|
|
872
|
+
end_pt[:row] = end_point.respond_to?(:row) ? end_point.row : end_point[:row]
|
|
873
|
+
end_pt[:column] = end_point.respond_to?(:column) ? end_point.column : end_point[:column]
|
|
874
|
+
|
|
875
|
+
node = Native.ts_node_descendant_for_point_range(@val, start_pt, end_pt)
|
|
876
|
+
return if Native.ts_node_is_null(node)
|
|
877
|
+
|
|
878
|
+
Node.new(node)
|
|
879
|
+
end
|
|
880
|
+
|
|
881
|
+
# Find the smallest named descendant that spans the given point range
|
|
882
|
+
#
|
|
883
|
+
# @param start_point [TreeHaver::Point, Hash] start point with :row and :column
|
|
884
|
+
# @param end_point [TreeHaver::Point, Hash] end point with :row and :column
|
|
885
|
+
# @return [Node, nil] named descendant node or nil if not found
|
|
886
|
+
def named_descendant_for_point_range(start_point, end_point)
|
|
887
|
+
start_pt = Native::TSPoint.new
|
|
888
|
+
start_pt[:row] = start_point.respond_to?(:row) ? start_point.row : start_point[:row]
|
|
889
|
+
start_pt[:column] = start_point.respond_to?(:column) ? start_point.column : start_point[:column]
|
|
890
|
+
|
|
891
|
+
end_pt = Native::TSPoint.new
|
|
892
|
+
end_pt[:row] = end_point.respond_to?(:row) ? end_point.row : end_point[:row]
|
|
893
|
+
end_pt[:column] = end_point.respond_to?(:column) ? end_point.column : end_point[:column]
|
|
894
|
+
|
|
895
|
+
node = Native.ts_node_named_descendant_for_point_range(@val, start_pt, end_pt)
|
|
896
|
+
return if Native.ts_node_is_null(node)
|
|
897
|
+
|
|
898
|
+
Node.new(node)
|
|
899
|
+
end
|
|
900
|
+
|
|
721
901
|
# Iterate over child nodes
|
|
722
902
|
#
|
|
723
903
|
# @yieldparam child [Node] each child node
|
|
@@ -271,9 +271,7 @@ module TreeHaver
|
|
|
271
271
|
mod::Parser.new
|
|
272
272
|
true
|
|
273
273
|
rescue NoMethodError, LoadError, NotAvailable => _e
|
|
274
|
-
|
|
275
|
-
rescue StandardError => _e
|
|
276
|
-
# Catch FFI::NotFoundError and other errors when FFI is loaded
|
|
274
|
+
# Note: FFI::NotFoundError inherits from LoadError, so it's caught here too
|
|
277
275
|
false
|
|
278
276
|
end
|
|
279
277
|
end
|
data/lib/tree_haver/language.rb
CHANGED
|
@@ -198,14 +198,8 @@ module TreeHaver
|
|
|
198
198
|
return from_library(path, symbol: symbol, name: name)
|
|
199
199
|
rescue NotAvailable, ArgumentError, LoadError => e
|
|
200
200
|
# Tree-sitter failed to load - check for Citrus fallback
|
|
201
|
+
# Note: FFI::NotFoundError inherits from LoadError, so it's caught here too
|
|
201
202
|
handle_tree_sitter_load_failure(e, all_backends)
|
|
202
|
-
rescue => e
|
|
203
|
-
# Also catch FFI::NotFoundError if FFI is loaded (can't reference directly as FFI may not exist)
|
|
204
|
-
if defined?(::FFI::NotFoundError) && e.is_a?(::FFI::NotFoundError)
|
|
205
|
-
handle_tree_sitter_load_failure(e, all_backends)
|
|
206
|
-
else
|
|
207
|
-
raise
|
|
208
|
-
end
|
|
209
203
|
end
|
|
210
204
|
end
|
|
211
205
|
|
|
@@ -237,7 +231,7 @@ module TreeHaver
|
|
|
237
231
|
#
|
|
238
232
|
# This handles cases where:
|
|
239
233
|
# - The .so file doesn't exist or can't be loaded (NotAvailable, LoadError)
|
|
240
|
-
# - FFI can't find required symbols like ts_parser_new (FFI::NotFoundError)
|
|
234
|
+
# - FFI can't find required symbols like ts_parser_new (FFI::NotFoundError inherits from LoadError)
|
|
241
235
|
# - Invalid arguments were provided (ArgumentError)
|
|
242
236
|
#
|
|
243
237
|
# Fallback to Citrus ONLY happens when:
|
data/lib/tree_haver/parser.rb
CHANGED
|
@@ -62,14 +62,8 @@ module TreeHaver
|
|
|
62
62
|
@impl = mod::Parser.new
|
|
63
63
|
@explicit_backend = backend # Remember for introspection (always a Symbol or nil)
|
|
64
64
|
rescue NoMethodError, LoadError => e
|
|
65
|
+
# Note: FFI::NotFoundError inherits from LoadError, so it's caught here too
|
|
65
66
|
handle_parser_creation_failure(e, backend)
|
|
66
|
-
rescue => e
|
|
67
|
-
# Also catch FFI::NotFoundError if FFI is loaded (can't reference directly as FFI may not exist)
|
|
68
|
-
if defined?(::FFI::NotFoundError) && e.is_a?(::FFI::NotFoundError)
|
|
69
|
-
handle_parser_creation_failure(e, backend)
|
|
70
|
-
else
|
|
71
|
-
raise
|
|
72
|
-
end
|
|
73
67
|
end
|
|
74
68
|
end
|
|
75
69
|
|
|
@@ -724,39 +724,92 @@ module TreeHaver
|
|
|
724
724
|
# Summary and Reset
|
|
725
725
|
# ============================================================
|
|
726
726
|
|
|
727
|
+
# Determine which backends are blocked based on environment and ARGV
|
|
728
|
+
#
|
|
729
|
+
# This replicates the logic from RSpec.configure to determine blocked
|
|
730
|
+
# backends BEFORE the RSpec.configure block has run. This is necessary
|
|
731
|
+
# because summary may be called in a before(:suite) hook that runs
|
|
732
|
+
# before the blocked_backends instance variable is set.
|
|
733
|
+
#
|
|
734
|
+
# @return [Set<Symbol>] set of blocked backend symbols
|
|
735
|
+
def compute_blocked_backends
|
|
736
|
+
blocked = Set.new
|
|
737
|
+
|
|
738
|
+
# Check TREE_HAVER_BACKEND environment variable
|
|
739
|
+
env_backend = ENV["TREE_HAVER_BACKEND"]
|
|
740
|
+
if env_backend && !env_backend.empty? && env_backend != "auto"
|
|
741
|
+
backend_sym = env_backend.to_sym
|
|
742
|
+
TreeHaver::Backends::BLOCKED_BY[backend_sym]&.each { |blocker| blocked << blocker }
|
|
743
|
+
end
|
|
744
|
+
|
|
745
|
+
# Check ARGV for --tag options that indicate isolated backend testing
|
|
746
|
+
ARGV.each_with_index do |arg, i|
|
|
747
|
+
tag_value = nil
|
|
748
|
+
if arg == "--tag" && ARGV[i + 1]
|
|
749
|
+
tag_str = ARGV[i + 1]
|
|
750
|
+
next if tag_str.start_with?("~")
|
|
751
|
+
tag_value = tag_str.to_sym
|
|
752
|
+
elsif arg.start_with?("--tag=")
|
|
753
|
+
tag_str = arg.sub("--tag=", "")
|
|
754
|
+
next if tag_str.start_with?("~")
|
|
755
|
+
tag_value = tag_str.to_sym
|
|
756
|
+
end
|
|
757
|
+
|
|
758
|
+
next unless tag_value
|
|
759
|
+
|
|
760
|
+
# Check for standard backend tags (e.g., :ffi_backend)
|
|
761
|
+
TreeHaver::Backends::BLOCKED_BY.each do |backend, blockers|
|
|
762
|
+
standard_tag = :"#{backend}_backend"
|
|
763
|
+
legacy_tag = :"#{backend}_backend_only"
|
|
764
|
+
if tag_value == standard_tag || tag_value == legacy_tag
|
|
765
|
+
blockers.each { |blocker| blocked << blocker }
|
|
766
|
+
end
|
|
767
|
+
end
|
|
768
|
+
end
|
|
769
|
+
|
|
770
|
+
blocked
|
|
771
|
+
end
|
|
772
|
+
|
|
727
773
|
# Get a summary of available dependencies (for debugging)
|
|
728
774
|
#
|
|
775
|
+
# This method respects blocked_backends to avoid loading backends
|
|
776
|
+
# that would conflict with isolated test modes (e.g., FFI-only tests).
|
|
777
|
+
#
|
|
729
778
|
# @return [Hash{Symbol => Boolean}] map of dependency name to availability
|
|
730
779
|
def summary
|
|
780
|
+
# Use stored blocked_backends if available, otherwise compute dynamically
|
|
781
|
+
blocked = @blocked_backends || compute_blocked_backends
|
|
782
|
+
|
|
731
783
|
{
|
|
732
784
|
# Backend selection from environment variables
|
|
733
785
|
selected_backend: selected_backend,
|
|
734
786
|
allowed_native_backends: allowed_native_backends,
|
|
735
787
|
allowed_ruby_backends: allowed_ruby_backends,
|
|
736
|
-
# TreeHaver backends (*_backend)
|
|
737
|
-
ffi_backend: ffi_available?,
|
|
738
|
-
mri_backend: mri_backend_available?,
|
|
739
|
-
rust_backend: rust_backend_available?,
|
|
740
|
-
java_backend: java_backend_available?,
|
|
741
|
-
prism_backend: prism_available?,
|
|
742
|
-
psych_backend: psych_available?,
|
|
743
|
-
commonmarker_backend: commonmarker_available?,
|
|
744
|
-
markly_backend: markly_available?,
|
|
745
|
-
citrus_backend: citrus_available?,
|
|
746
|
-
rbs_backend: rbs_backend_available?,
|
|
788
|
+
# TreeHaver backends (*_backend) - skip blocked backends to avoid loading them
|
|
789
|
+
ffi_backend: blocked.include?(:ffi) ? :blocked : ffi_available?,
|
|
790
|
+
mri_backend: blocked.include?(:mri) ? :blocked : mri_backend_available?,
|
|
791
|
+
rust_backend: blocked.include?(:rust) ? :blocked : rust_backend_available?,
|
|
792
|
+
java_backend: blocked.include?(:java) ? :blocked : java_backend_available?,
|
|
793
|
+
prism_backend: blocked.include?(:prism) ? :blocked : prism_available?,
|
|
794
|
+
psych_backend: blocked.include?(:psych) ? :blocked : psych_available?,
|
|
795
|
+
commonmarker_backend: blocked.include?(:commonmarker) ? :blocked : commonmarker_available?,
|
|
796
|
+
markly_backend: blocked.include?(:markly) ? :blocked : markly_available?,
|
|
797
|
+
citrus_backend: blocked.include?(:citrus) ? :blocked : citrus_available?,
|
|
798
|
+
rbs_backend: blocked.include?(:rbs) ? :blocked : rbs_backend_available?,
|
|
747
799
|
# Ruby engines (*_engine)
|
|
748
800
|
ruby_engine: RUBY_ENGINE,
|
|
749
801
|
mri_engine: mri?,
|
|
750
802
|
jruby_engine: jruby?,
|
|
751
803
|
truffleruby_engine: truffleruby?,
|
|
752
|
-
# Tree-sitter grammars (*_grammar)
|
|
804
|
+
# Tree-sitter grammars (*_grammar) - also respect blocked backends
|
|
805
|
+
# since grammar checks may load backends
|
|
753
806
|
libtree_sitter: libtree_sitter_available?,
|
|
754
|
-
bash_grammar: tree_sitter_bash_available?,
|
|
755
|
-
toml_grammar: tree_sitter_toml_available?,
|
|
756
|
-
json_grammar: tree_sitter_json_available?,
|
|
757
|
-
jsonc_grammar: tree_sitter_jsonc_available?,
|
|
758
|
-
rbs_grammar: tree_sitter_rbs_available?,
|
|
759
|
-
any_native_grammar: any_native_grammar_available?,
|
|
807
|
+
bash_grammar: blocked.include?(:mri) ? :blocked : tree_sitter_bash_available?,
|
|
808
|
+
toml_grammar: blocked.include?(:mri) ? :blocked : tree_sitter_toml_available?,
|
|
809
|
+
json_grammar: blocked.include?(:mri) ? :blocked : tree_sitter_json_available?,
|
|
810
|
+
jsonc_grammar: blocked.include?(:mri) ? :blocked : tree_sitter_jsonc_available?,
|
|
811
|
+
rbs_grammar: blocked.include?(:mri) ? :blocked : tree_sitter_rbs_available?,
|
|
812
|
+
any_native_grammar: blocked.include?(:mri) ? :blocked : any_native_grammar_available?,
|
|
760
813
|
# Language parsing capabilities (*_parsing)
|
|
761
814
|
toml_parsing: any_toml_backend_available?,
|
|
762
815
|
markdown_parsing: any_markdown_backend_available?,
|
|
@@ -776,9 +829,13 @@ module TreeHaver
|
|
|
776
829
|
"TREE_SITTER_TOML_PATH" => ENV["TREE_SITTER_TOML_PATH"],
|
|
777
830
|
"TREE_SITTER_JSON_PATH" => ENV["TREE_SITTER_JSON_PATH"],
|
|
778
831
|
"TREE_SITTER_JSONC_PATH" => ENV["TREE_SITTER_JSONC_PATH"],
|
|
832
|
+
"TREE_SITTER_RBS_PATH" => ENV["TREE_SITTER_RBS_PATH"],
|
|
779
833
|
"TREE_SITTER_RUNTIME_LIB" => ENV["TREE_SITTER_RUNTIME_LIB"],
|
|
780
834
|
"TREE_HAVER_BACKEND" => ENV["TREE_HAVER_BACKEND"],
|
|
781
835
|
"TREE_HAVER_DEBUG" => ENV["TREE_HAVER_DEBUG"],
|
|
836
|
+
# Library paths used by tree-sitter shared libraries
|
|
837
|
+
"LD_LIBRARY_PATH" => ENV["LD_LIBRARY_PATH"],
|
|
838
|
+
"DYLD_LIBRARY_PATH" => ENV["DYLD_LIBRARY_PATH"],
|
|
782
839
|
}
|
|
783
840
|
end
|
|
784
841
|
|
data/lib/tree_haver/version.rb
CHANGED
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tree_haver
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter H. Boling
|
|
@@ -298,10 +298,10 @@ licenses:
|
|
|
298
298
|
- MIT
|
|
299
299
|
metadata:
|
|
300
300
|
homepage_uri: https://tree-haver.galtzo.com/
|
|
301
|
-
source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v4.0.
|
|
302
|
-
changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v4.0.
|
|
301
|
+
source_code_uri: https://github.com/kettle-rb/tree_haver/tree/v4.0.5
|
|
302
|
+
changelog_uri: https://github.com/kettle-rb/tree_haver/blob/v4.0.5/CHANGELOG.md
|
|
303
303
|
bug_tracker_uri: https://github.com/kettle-rb/tree_haver/issues
|
|
304
|
-
documentation_uri: https://www.rubydoc.info/gems/tree_haver/4.0.
|
|
304
|
+
documentation_uri: https://www.rubydoc.info/gems/tree_haver/4.0.5
|
|
305
305
|
funding_uri: https://github.com/sponsors/pboling
|
|
306
306
|
wiki_uri: https://github.com/kettle-rb/tree_haver/wiki
|
|
307
307
|
news_uri: https://www.railsbling.com/tags/tree_haver
|
metadata.gz.sig
CHANGED
|
Binary file
|