tree_haver 3.1.1 → 3.2.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/CHANGELOG.md +167 -2
- data/README.md +391 -357
- data/lib/tree_haver/backends/citrus.rb +7 -1
- data/lib/tree_haver/backends/ffi.rb +73 -61
- data/lib/tree_haver/backends/java.rb +6 -1
- data/lib/tree_haver/backends/mri.rb +24 -1
- data/lib/tree_haver/backends/rust.rb +14 -1
- data/lib/tree_haver/citrus_grammar_finder.rb +57 -9
- data/lib/tree_haver/node.rb +4 -1
- data/lib/tree_haver/rspec/dependency_tags.rb +211 -201
- data/lib/tree_haver/version.rb +1 -1
- data/lib/tree_haver.rb +122 -15
- data.tar.gz.sig +1 -2
- metadata +4 -4
- metadata.gz.sig +0 -0
|
@@ -49,45 +49,45 @@
|
|
|
49
49
|
# # This test only runs when Psych is available
|
|
50
50
|
# end
|
|
51
51
|
#
|
|
52
|
-
# it "requires Commonmarker backend", :
|
|
52
|
+
# it "requires Commonmarker backend", :commonmarker_backend do
|
|
53
53
|
# # This test only runs when commonmarker gem is available
|
|
54
54
|
# end
|
|
55
55
|
#
|
|
56
|
-
# it "requires Markly backend", :
|
|
56
|
+
# it "requires Markly backend", :markly_backend do
|
|
57
57
|
# # This test only runs when markly gem is available
|
|
58
58
|
# end
|
|
59
59
|
#
|
|
60
|
-
# it "requires Citrus
|
|
61
|
-
# # This test only runs when
|
|
60
|
+
# it "requires Citrus backend", :citrus_backend do
|
|
61
|
+
# # This test only runs when Citrus gem is available
|
|
62
62
|
# end
|
|
63
63
|
#
|
|
64
64
|
# @example Language-specific grammar tags (for *-merge gems)
|
|
65
|
-
# it "requires tree-sitter-bash", :
|
|
65
|
+
# it "requires tree-sitter-bash", :bash_grammar do
|
|
66
66
|
# # This test only runs when bash grammar is available and parsing works
|
|
67
67
|
# end
|
|
68
68
|
#
|
|
69
|
-
# it "requires tree-sitter-json", :
|
|
69
|
+
# it "requires tree-sitter-json", :json_grammar do
|
|
70
70
|
# # This test only runs when json grammar is available and parsing works
|
|
71
71
|
# end
|
|
72
72
|
#
|
|
73
|
-
#
|
|
74
|
-
# it "requires toml-merge", :toml_merge do
|
|
75
|
-
# # This test only runs when toml-merge is fully functional
|
|
76
|
-
# end
|
|
73
|
+
# == Available Tags
|
|
77
74
|
#
|
|
78
|
-
#
|
|
79
|
-
# # This test only runs when prism-merge is fully functional
|
|
80
|
-
# end
|
|
75
|
+
# === Naming Conventions
|
|
81
76
|
#
|
|
82
|
-
#
|
|
77
|
+
# - `*_backend` = TreeHaver backends (mri, rust, ffi, java, prism, psych, commonmarker, markly, citrus)
|
|
78
|
+
# - `*_engine` = Ruby engines (mri, jruby, truffleruby)
|
|
79
|
+
# - `*_grammar` = tree-sitter grammar files (.so)
|
|
80
|
+
# - `*_parsing` = any parsing capability for a language (combines multiple backends/grammars)
|
|
81
|
+
# - `*_merge` = ast-merge family gems (toml-merge, json-merge, etc.)
|
|
83
82
|
#
|
|
84
83
|
# === Positive Tags (run when dependency IS available)
|
|
85
84
|
#
|
|
86
|
-
# ==== TreeHaver Backend Tags
|
|
85
|
+
# ==== TreeHaver Backend Tags (*_backend)
|
|
87
86
|
#
|
|
88
|
-
# [:
|
|
87
|
+
# [:ffi_backend]
|
|
89
88
|
# FFI backend is available. Checked dynamically per-test because FFI becomes
|
|
90
89
|
# unavailable after MRI backend is used (due to libtree-sitter runtime conflicts).
|
|
90
|
+
# Legacy alias: :ffi
|
|
91
91
|
#
|
|
92
92
|
# [:mri_backend]
|
|
93
93
|
# ruby_tree_sitter gem is available.
|
|
@@ -104,83 +104,66 @@
|
|
|
104
104
|
# [:psych_backend]
|
|
105
105
|
# Psych is available (stdlib, should always be true).
|
|
106
106
|
#
|
|
107
|
-
# [:
|
|
107
|
+
# [:commonmarker_backend]
|
|
108
108
|
# commonmarker gem is available.
|
|
109
109
|
#
|
|
110
|
-
# [:
|
|
110
|
+
# [:markly_backend]
|
|
111
111
|
# markly gem is available.
|
|
112
112
|
#
|
|
113
|
-
# [:
|
|
114
|
-
#
|
|
113
|
+
# [:citrus_backend]
|
|
114
|
+
# Citrus gem is available.
|
|
115
115
|
#
|
|
116
|
-
# ==== Ruby Engine Tags
|
|
116
|
+
# ==== Ruby Engine Tags (*_engine)
|
|
117
117
|
#
|
|
118
|
-
# [:
|
|
118
|
+
# [:mri_engine]
|
|
119
|
+
# Running on MRI (CRuby).
|
|
120
|
+
#
|
|
121
|
+
# [:jruby_engine]
|
|
119
122
|
# Running on JRuby.
|
|
120
123
|
#
|
|
121
|
-
# [:
|
|
124
|
+
# [:truffleruby_engine]
|
|
122
125
|
# Running on TruffleRuby.
|
|
123
126
|
#
|
|
124
|
-
#
|
|
125
|
-
# Running on MRI (CRuby).
|
|
126
|
-
#
|
|
127
|
-
# ==== Grammar/Library Tags
|
|
127
|
+
# ==== Tree-Sitter Grammar Tags (*_grammar)
|
|
128
128
|
#
|
|
129
129
|
# [:libtree_sitter]
|
|
130
130
|
# libtree-sitter.so is loadable via FFI.
|
|
131
131
|
#
|
|
132
|
-
# [:
|
|
133
|
-
# A TOML grammar library is available (via TREE_SITTER_TOML_PATH env var).
|
|
134
|
-
#
|
|
135
|
-
# [:native_parsing]
|
|
136
|
-
# Both libtree_sitter and toml_grammar are available.
|
|
137
|
-
#
|
|
138
|
-
# ==== Language-Specific Grammar Tags (for *-merge gems)
|
|
139
|
-
#
|
|
140
|
-
# [:tree_sitter_bash]
|
|
132
|
+
# [:bash_grammar]
|
|
141
133
|
# tree-sitter-bash grammar is available and parsing works.
|
|
142
134
|
#
|
|
143
|
-
# [:
|
|
135
|
+
# [:toml_grammar]
|
|
144
136
|
# tree-sitter-toml grammar is available and parsing works.
|
|
145
137
|
#
|
|
146
|
-
# [:
|
|
138
|
+
# [:json_grammar]
|
|
147
139
|
# tree-sitter-json grammar is available and parsing works.
|
|
148
140
|
#
|
|
149
|
-
# [:
|
|
141
|
+
# [:jsonc_grammar]
|
|
150
142
|
# tree-sitter-jsonc grammar is available and parsing works.
|
|
151
143
|
#
|
|
152
|
-
#
|
|
153
|
-
# toml-rb gem is available (Citrus backend for TOML).
|
|
154
|
-
#
|
|
155
|
-
# [:toml_backend]
|
|
156
|
-
# At least one TOML backend (tree-sitter or toml-rb) is available.
|
|
157
|
-
#
|
|
158
|
-
# [:markdown_backend]
|
|
159
|
-
# At least one markdown backend (markly or commonmarker) is available.
|
|
144
|
+
# ==== Language Parsing Capability Tags (*_parsing)
|
|
160
145
|
#
|
|
161
|
-
#
|
|
146
|
+
# [:toml_parsing]
|
|
147
|
+
# At least one TOML parser (tree-sitter-toml OR toml-rb/Citrus) is available.
|
|
162
148
|
#
|
|
163
|
-
# [:
|
|
164
|
-
#
|
|
149
|
+
# [:markdown_parsing]
|
|
150
|
+
# At least one markdown parser (commonmarker OR markly) is available.
|
|
165
151
|
#
|
|
166
|
-
# [:
|
|
167
|
-
#
|
|
152
|
+
# [:native_parsing]
|
|
153
|
+
# A native tree-sitter backend and grammar are available.
|
|
168
154
|
#
|
|
169
|
-
#
|
|
170
|
-
# prism-merge gem is available and functional.
|
|
155
|
+
# ==== Specific Library Tags
|
|
171
156
|
#
|
|
172
|
-
# [:
|
|
173
|
-
#
|
|
157
|
+
# [:toml_rb]
|
|
158
|
+
# toml-rb gem is available (Citrus backend for TOML).
|
|
174
159
|
#
|
|
175
160
|
# === Negated Tags (run when dependency is NOT available)
|
|
176
161
|
#
|
|
177
162
|
# All positive tags have negated versions prefixed with `not_`:
|
|
178
|
-
# - :not_mri_backend, :not_rust_backend, :not_java_backend
|
|
179
|
-
# - :
|
|
180
|
-
# - :not_libtree_sitter, :not_toml_grammar
|
|
181
|
-
# - :
|
|
182
|
-
# - :not_toml_rb, :not_toml_backend, :not_markdown_backend
|
|
183
|
-
# - :not_toml_merge, :not_json_merge, :not_prism_merge, :not_psych_merge
|
|
163
|
+
# - :not_mri_backend, :not_rust_backend, :not_java_backend, etc.
|
|
164
|
+
# - :not_mri_engine, :not_jruby_engine, :not_truffleruby_engine
|
|
165
|
+
# - :not_libtree_sitter, :not_bash_grammar, :not_toml_grammar, etc.
|
|
166
|
+
# - :not_toml_parsing, :not_markdown_parsing
|
|
184
167
|
#
|
|
185
168
|
# == Backend Conflict Protection
|
|
186
169
|
#
|
|
@@ -225,6 +208,10 @@ module TreeHaver
|
|
|
225
208
|
#
|
|
226
209
|
# @return [Boolean] true if FFI backend is usable
|
|
227
210
|
def ffi_available?
|
|
211
|
+
# TruffleRuby's FFI doesn't support STRUCT_BY_VALUE return types
|
|
212
|
+
# (used by ts_tree_root_node, ts_node_child, ts_node_start_point, etc.)
|
|
213
|
+
return false if truffleruby?
|
|
214
|
+
|
|
228
215
|
# Try to actually use the FFI backend
|
|
229
216
|
path = find_toml_grammar_path
|
|
230
217
|
return false unless path && File.exist?(path)
|
|
@@ -235,10 +222,14 @@ module TreeHaver
|
|
|
235
222
|
true
|
|
236
223
|
rescue TreeHaver::BackendConflict, TreeHaver::NotAvailable, LoadError
|
|
237
224
|
false
|
|
225
|
+
rescue StandardError
|
|
226
|
+
# Catch any other FFI-related errors (e.g., Polyglot::ForeignException)
|
|
227
|
+
false
|
|
238
228
|
end
|
|
239
229
|
|
|
240
230
|
# Check if ruby_tree_sitter gem is available (MRI backend)
|
|
241
231
|
#
|
|
232
|
+
# The MRI backend only works on MRI Ruby (C extension).
|
|
242
233
|
# When this returns true, it also records MRI backend usage with
|
|
243
234
|
# TreeHaver.record_backend_usage(:mri). This is critical for conflict
|
|
244
235
|
# detection - without it, FFI would not know that MRI has been loaded.
|
|
@@ -246,6 +237,10 @@ module TreeHaver
|
|
|
246
237
|
# @return [Boolean] true if ruby_tree_sitter gem is available
|
|
247
238
|
def mri_backend_available?
|
|
248
239
|
return @mri_backend_available if defined?(@mri_backend_available)
|
|
240
|
+
|
|
241
|
+
# ruby_tree_sitter is a C extension that only works on MRI
|
|
242
|
+
return @mri_backend_available = false unless mri?
|
|
243
|
+
|
|
249
244
|
@mri_backend_available = begin
|
|
250
245
|
require "ruby_tree_sitter"
|
|
251
246
|
# Record that MRI backend is now loaded - this is critical for
|
|
@@ -259,9 +254,15 @@ module TreeHaver
|
|
|
259
254
|
|
|
260
255
|
# Check if tree_stump gem is available (Rust backend)
|
|
261
256
|
#
|
|
257
|
+
# The Rust backend only works on MRI Ruby (magnus uses MRI's C API).
|
|
258
|
+
#
|
|
262
259
|
# @return [Boolean] true if tree_stump gem is available
|
|
263
260
|
def rust_backend_available?
|
|
264
261
|
return @rust_backend_available if defined?(@rust_backend_available)
|
|
262
|
+
|
|
263
|
+
# tree_stump uses magnus which requires MRI's C API
|
|
264
|
+
return @rust_backend_available = false unless mri?
|
|
265
|
+
|
|
265
266
|
@rust_backend_available = begin
|
|
266
267
|
require "tree_stump"
|
|
267
268
|
true
|
|
@@ -289,6 +290,10 @@ module TreeHaver
|
|
|
289
290
|
true
|
|
290
291
|
rescue TreeHaver::NotAvailable, LoadError
|
|
291
292
|
false
|
|
293
|
+
rescue StandardError
|
|
294
|
+
# TruffleRuby raises Polyglot::ForeignException when FFI
|
|
295
|
+
# encounters unsupported types like STRUCT_BY_VALUE
|
|
296
|
+
false
|
|
292
297
|
end
|
|
293
298
|
end
|
|
294
299
|
|
|
@@ -343,22 +348,14 @@ module TreeHaver
|
|
|
343
348
|
@psych_available = TreeHaver::Backends::Psych.available?
|
|
344
349
|
end
|
|
345
350
|
|
|
346
|
-
# Check if
|
|
351
|
+
# Check if Citrus backend is available
|
|
347
352
|
#
|
|
348
|
-
#
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
language: :toml,
|
|
355
|
-
gem_name: "toml-rb",
|
|
356
|
-
grammar_const: "TomlRB::Document",
|
|
357
|
-
)
|
|
358
|
-
finder.available?
|
|
359
|
-
rescue LoadError, NameError
|
|
360
|
-
false
|
|
361
|
-
end
|
|
353
|
+
# This checks if the citrus gem is installed and the backend works.
|
|
354
|
+
#
|
|
355
|
+
# @return [Boolean] true if Citrus backend is available
|
|
356
|
+
def citrus_available?
|
|
357
|
+
return @citrus_available if defined?(@citrus_available)
|
|
358
|
+
@citrus_available = TreeHaver::Backends::Citrus.available?
|
|
362
359
|
end
|
|
363
360
|
|
|
364
361
|
# ============================================================
|
|
@@ -423,16 +420,20 @@ module TreeHaver
|
|
|
423
420
|
@tree_sitter_jsonc_available = grammar_works?(:jsonc, '{"key": "value" /* comment */}')
|
|
424
421
|
end
|
|
425
422
|
|
|
426
|
-
# Check if toml-rb gem is available (Citrus backend for TOML)
|
|
423
|
+
# Check if toml-rb gem is available and functional (Citrus backend for TOML)
|
|
427
424
|
#
|
|
428
|
-
# @return [Boolean] true if toml-rb gem is available
|
|
425
|
+
# @return [Boolean] true if toml-rb gem is available and can parse TOML
|
|
429
426
|
def toml_rb_available?
|
|
430
427
|
return @toml_rb_available if defined?(@toml_rb_available)
|
|
431
428
|
@toml_rb_available = begin
|
|
432
429
|
require "toml-rb"
|
|
430
|
+
# Verify it can actually parse - just requiring isn't enough
|
|
431
|
+
TomlRB.parse('key = "value"')
|
|
433
432
|
true
|
|
434
433
|
rescue LoadError
|
|
435
434
|
false
|
|
435
|
+
rescue StandardError
|
|
436
|
+
false
|
|
436
437
|
end
|
|
437
438
|
end
|
|
438
439
|
|
|
@@ -450,41 +451,13 @@ module TreeHaver
|
|
|
450
451
|
markly_available? || commonmarker_available?
|
|
451
452
|
end
|
|
452
453
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
# @return [Boolean] true if toml-merge works
|
|
461
|
-
def toml_merge_available?
|
|
462
|
-
return @toml_merge_available if defined?(@toml_merge_available)
|
|
463
|
-
@toml_merge_available = inner_merge_works?("toml/merge", "Toml::Merge::SmartMerger", "key = 'test'")
|
|
464
|
-
end
|
|
465
|
-
|
|
466
|
-
# Check if json-merge is available and functional
|
|
467
|
-
#
|
|
468
|
-
# @return [Boolean] true if json-merge works
|
|
469
|
-
def json_merge_available?
|
|
470
|
-
return @json_merge_available if defined?(@json_merge_available)
|
|
471
|
-
@json_merge_available = inner_merge_works?("json/merge", "Json::Merge::SmartMerger", '{"a":1}')
|
|
472
|
-
end
|
|
473
|
-
|
|
474
|
-
# Check if prism-merge is available and functional
|
|
475
|
-
#
|
|
476
|
-
# @return [Boolean] true if prism-merge works
|
|
477
|
-
def prism_merge_available?
|
|
478
|
-
return @prism_merge_available if defined?(@prism_merge_available)
|
|
479
|
-
@prism_merge_available = inner_merge_works?("prism/merge", "Prism::Merge::SmartMerger", "puts 1")
|
|
480
|
-
end
|
|
481
|
-
|
|
482
|
-
# Check if psych-merge is available and functional
|
|
483
|
-
#
|
|
484
|
-
# @return [Boolean] true if psych-merge works
|
|
485
|
-
def psych_merge_available?
|
|
486
|
-
return @psych_merge_available if defined?(@psych_merge_available)
|
|
487
|
-
@psych_merge_available = inner_merge_works?("psych/merge", "Psych::Merge::SmartMerger", "key: value")
|
|
454
|
+
def any_native_grammar_available?
|
|
455
|
+
libtree_sitter_available? && (
|
|
456
|
+
tree_sitter_bash_available? ||
|
|
457
|
+
tree_sitter_toml_available? ||
|
|
458
|
+
tree_sitter_json_available? ||
|
|
459
|
+
tree_sitter_jsonc_available?
|
|
460
|
+
)
|
|
488
461
|
end
|
|
489
462
|
|
|
490
463
|
# ============================================================
|
|
@@ -496,37 +469,48 @@ module TreeHaver
|
|
|
496
469
|
# @return [Hash{Symbol => Boolean}] map of dependency name to availability
|
|
497
470
|
def summary
|
|
498
471
|
{
|
|
499
|
-
# TreeHaver backends
|
|
500
|
-
|
|
472
|
+
# TreeHaver backends (*_backend)
|
|
473
|
+
ffi_backend: ffi_available?,
|
|
501
474
|
mri_backend: mri_backend_available?,
|
|
502
475
|
rust_backend: rust_backend_available?,
|
|
503
476
|
java_backend: java_backend_available?,
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
#
|
|
510
|
-
libtree_sitter: libtree_sitter_available?,
|
|
511
|
-
toml_grammar: toml_grammar_available?,
|
|
512
|
-
# Ruby engines
|
|
477
|
+
prism_backend: prism_available?,
|
|
478
|
+
psych_backend: psych_available?,
|
|
479
|
+
commonmarker_backend: commonmarker_available?,
|
|
480
|
+
markly_backend: markly_available?,
|
|
481
|
+
citrus_backend: citrus_available?,
|
|
482
|
+
# Ruby engines (*_engine)
|
|
513
483
|
ruby_engine: RUBY_ENGINE,
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
#
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
484
|
+
mri_engine: mri?,
|
|
485
|
+
jruby_engine: jruby?,
|
|
486
|
+
truffleruby_engine: truffleruby?,
|
|
487
|
+
# Tree-sitter grammars (*_grammar)
|
|
488
|
+
libtree_sitter: libtree_sitter_available?,
|
|
489
|
+
bash_grammar: tree_sitter_bash_available?,
|
|
490
|
+
toml_grammar: tree_sitter_toml_available?,
|
|
491
|
+
json_grammar: tree_sitter_json_available?,
|
|
492
|
+
jsonc_grammar: tree_sitter_jsonc_available?,
|
|
493
|
+
any_native_grammar: any_native_grammar_available?,
|
|
494
|
+
# Language parsing capabilities (*_parsing)
|
|
495
|
+
toml_parsing: any_toml_backend_available?,
|
|
496
|
+
markdown_parsing: any_markdown_backend_available?,
|
|
497
|
+
# Specific libraries
|
|
522
498
|
toml_rb: toml_rb_available?,
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
499
|
+
}
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
# Get environment variable summary for debugging
|
|
503
|
+
#
|
|
504
|
+
# @return [Hash{String => String}] relevant environment variables
|
|
505
|
+
def env_summary
|
|
506
|
+
{
|
|
507
|
+
"TREE_SITTER_BASH_PATH" => ENV["TREE_SITTER_BASH_PATH"],
|
|
508
|
+
"TREE_SITTER_TOML_PATH" => ENV["TREE_SITTER_TOML_PATH"],
|
|
509
|
+
"TREE_SITTER_JSON_PATH" => ENV["TREE_SITTER_JSON_PATH"],
|
|
510
|
+
"TREE_SITTER_JSONC_PATH" => ENV["TREE_SITTER_JSONC_PATH"],
|
|
511
|
+
"TREE_SITTER_RUNTIME_LIB" => ENV["TREE_SITTER_RUNTIME_LIB"],
|
|
512
|
+
"TREE_HAVER_BACKEND" => ENV["TREE_HAVER_BACKEND"],
|
|
513
|
+
"TREE_HAVER_DEBUG" => ENV["TREE_HAVER_DEBUG"],
|
|
530
514
|
}
|
|
531
515
|
end
|
|
532
516
|
|
|
@@ -550,25 +534,37 @@ module TreeHaver
|
|
|
550
534
|
# @param test_source [String] sample source code to parse
|
|
551
535
|
# @return [Boolean] true if parsing works without errors
|
|
552
536
|
def grammar_works?(language, test_source)
|
|
537
|
+
debug = ENV["TREE_HAVER_DEBUG"]
|
|
538
|
+
env_var = "TREE_SITTER_#{language.to_s.upcase}_PATH"
|
|
539
|
+
env_value = ENV[env_var]
|
|
540
|
+
|
|
541
|
+
if debug
|
|
542
|
+
puts " [grammar_works? #{language}] ENV[#{env_var}] = #{env_value.inspect}"
|
|
543
|
+
puts " [grammar_works? #{language}] Attempting TreeHaver.parser_for(#{language.inspect})..."
|
|
544
|
+
end
|
|
545
|
+
|
|
553
546
|
parser = TreeHaver.parser_for(language)
|
|
547
|
+
if debug
|
|
548
|
+
puts " [grammar_works? #{language}] Parser created: #{parser.class}"
|
|
549
|
+
puts " [grammar_works? #{language}] Parser backend: #{parser.respond_to?(:backend) ? parser.backend : "unknown"}"
|
|
550
|
+
end
|
|
551
|
+
|
|
554
552
|
result = parser.parse(test_source)
|
|
555
|
-
!result.nil? && result.root_node && !result.root_node.has_error?
|
|
556
|
-
rescue TreeHaver::NotAvailable, TreeHaver::Error, StandardError
|
|
557
|
-
false
|
|
558
|
-
end
|
|
553
|
+
success = !result.nil? && result.root_node && !result.root_node.has_error?
|
|
559
554
|
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
555
|
+
if debug
|
|
556
|
+
puts " [grammar_works? #{language}] Parse result nil?: #{result.nil?}"
|
|
557
|
+
puts " [grammar_works? #{language}] Root node: #{result&.root_node&.class}"
|
|
558
|
+
puts " [grammar_works? #{language}] Has error?: #{result&.root_node&.has_error?}"
|
|
559
|
+
puts " [grammar_works? #{language}] Success: #{success}"
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
success
|
|
563
|
+
rescue TreeHaver::NotAvailable, TreeHaver::Error, StandardError => e
|
|
564
|
+
if debug
|
|
565
|
+
puts " [grammar_works? #{language}] Exception: #{e.class}: #{e.message}"
|
|
566
|
+
puts " [grammar_works? #{language}] Returning false"
|
|
567
|
+
end
|
|
572
568
|
false
|
|
573
569
|
end
|
|
574
570
|
end
|
|
@@ -586,6 +582,11 @@ RSpec.configure do |config|
|
|
|
586
582
|
config.before(:suite) do
|
|
587
583
|
# Print dependency summary if TREE_HAVER_DEBUG is set
|
|
588
584
|
if ENV["TREE_HAVER_DEBUG"]
|
|
585
|
+
puts "\n=== TreeHaver Environment Variables ==="
|
|
586
|
+
deps.env_summary.each do |var, value|
|
|
587
|
+
puts " #{var}: #{value.inspect}"
|
|
588
|
+
end
|
|
589
|
+
|
|
589
590
|
puts "\n=== TreeHaver Test Dependencies ==="
|
|
590
591
|
deps.summary.each do |dep, available|
|
|
591
592
|
status = case available
|
|
@@ -602,10 +603,16 @@ RSpec.configure do |config|
|
|
|
602
603
|
# ============================================================
|
|
603
604
|
# TreeHaver Backend Tags
|
|
604
605
|
# ============================================================
|
|
606
|
+
# Tags: *_backend - require a specific TreeHaver backend to be available
|
|
607
|
+
#
|
|
608
|
+
# Native backends (load .so files):
|
|
609
|
+
# :ffi_backend, :mri_backend, :rust_backend, :java_backend
|
|
610
|
+
# Pure-Ruby backends:
|
|
611
|
+
# :prism_backend, :psych_backend, :commonmarker_backend, :markly_backend, :citrus_backend
|
|
605
612
|
|
|
606
613
|
# FFI availability is checked dynamically per-test (not at load time)
|
|
607
614
|
# because FFI becomes unavailable after MRI backend is used.
|
|
608
|
-
config.before(:each, :
|
|
615
|
+
config.before(:each, :ffi_backend) do
|
|
609
616
|
skip "FFI backend not available (MRI backend may have been used)" unless deps.ffi_available?
|
|
610
617
|
end
|
|
611
618
|
|
|
@@ -614,52 +621,60 @@ RSpec.configure do |config|
|
|
|
614
621
|
config.filter_run_excluding(java_backend: true) unless deps.java_backend_available?
|
|
615
622
|
config.filter_run_excluding(prism_backend: true) unless deps.prism_available?
|
|
616
623
|
config.filter_run_excluding(psych_backend: true) unless deps.psych_available?
|
|
617
|
-
config.filter_run_excluding(
|
|
618
|
-
config.filter_run_excluding(
|
|
619
|
-
config.filter_run_excluding(
|
|
624
|
+
config.filter_run_excluding(commonmarker_backend: true) unless deps.commonmarker_available?
|
|
625
|
+
config.filter_run_excluding(markly_backend: true) unless deps.markly_available?
|
|
626
|
+
config.filter_run_excluding(citrus_backend: true) unless deps.citrus_available?
|
|
620
627
|
|
|
621
628
|
# ============================================================
|
|
622
629
|
# Ruby Engine Tags
|
|
623
630
|
# ============================================================
|
|
631
|
+
# Tags: *_engine - require a specific Ruby engine
|
|
632
|
+
# :mri_engine, :jruby_engine, :truffleruby_engine
|
|
624
633
|
|
|
625
|
-
config.filter_run_excluding(
|
|
626
|
-
config.filter_run_excluding(
|
|
627
|
-
config.filter_run_excluding(
|
|
634
|
+
config.filter_run_excluding(mri_engine: true) unless deps.mri?
|
|
635
|
+
config.filter_run_excluding(jruby_engine: true) unless deps.jruby?
|
|
636
|
+
config.filter_run_excluding(truffleruby_engine: true) unless deps.truffleruby?
|
|
628
637
|
|
|
629
638
|
# ============================================================
|
|
630
|
-
#
|
|
639
|
+
# Tree-Sitter Grammar Tags
|
|
631
640
|
# ============================================================
|
|
641
|
+
# Tags: *_grammar - require a specific tree-sitter grammar (.so file)
|
|
642
|
+
# :bash_grammar, :toml_grammar, :json_grammar, :jsonc_grammar
|
|
643
|
+
#
|
|
644
|
+
# Also: :libtree_sitter - requires the libtree-sitter runtime library
|
|
632
645
|
|
|
633
646
|
config.filter_run_excluding(libtree_sitter: true) unless deps.libtree_sitter_available?
|
|
634
|
-
config.filter_run_excluding(
|
|
635
|
-
config.filter_run_excluding(
|
|
647
|
+
config.filter_run_excluding(bash_grammar: true) unless deps.tree_sitter_bash_available?
|
|
648
|
+
config.filter_run_excluding(toml_grammar: true) unless deps.tree_sitter_toml_available?
|
|
649
|
+
config.filter_run_excluding(json_grammar: true) unless deps.tree_sitter_json_available?
|
|
650
|
+
config.filter_run_excluding(jsonc_grammar: true) unless deps.tree_sitter_jsonc_available?
|
|
636
651
|
|
|
637
652
|
# ============================================================
|
|
638
|
-
# Language
|
|
653
|
+
# Language Parsing Capability Tags
|
|
639
654
|
# ============================================================
|
|
655
|
+
# Tags: *_parsing - require ANY parser for a language (any backend that can parse it)
|
|
656
|
+
# :toml_parsing - any TOML parser (tree-sitter-toml OR toml-rb/Citrus)
|
|
657
|
+
# :markdown_parsing - any Markdown parser (commonmarker OR markly)
|
|
658
|
+
# :native_parsing - any native tree-sitter backend + grammar
|
|
640
659
|
|
|
641
|
-
config.filter_run_excluding(
|
|
642
|
-
config.filter_run_excluding(
|
|
643
|
-
config.filter_run_excluding(
|
|
644
|
-
config.filter_run_excluding(tree_sitter_jsonc: true) unless deps.tree_sitter_jsonc_available?
|
|
645
|
-
config.filter_run_excluding(toml_rb: true) unless deps.toml_rb_available?
|
|
646
|
-
config.filter_run_excluding(toml_backend: true) unless deps.any_toml_backend_available?
|
|
647
|
-
config.filter_run_excluding(markdown_backend: true) unless deps.any_markdown_backend_available?
|
|
660
|
+
config.filter_run_excluding(toml_parsing: true) unless deps.any_toml_backend_available?
|
|
661
|
+
config.filter_run_excluding(markdown_parsing: true) unless deps.any_markdown_backend_available?
|
|
662
|
+
config.filter_run_excluding(native_parsing: true) unless deps.any_native_grammar_available?
|
|
648
663
|
|
|
649
664
|
# ============================================================
|
|
650
|
-
#
|
|
665
|
+
# Specific Library Tags
|
|
651
666
|
# ============================================================
|
|
667
|
+
# Tags for specific gems/libraries (not backends, but dependencies)
|
|
668
|
+
# :toml_rb - the toml-rb gem (Citrus-based TOML parser)
|
|
652
669
|
|
|
653
|
-
config.filter_run_excluding(
|
|
654
|
-
config.filter_run_excluding(json_merge: true) unless deps.json_merge_available?
|
|
655
|
-
config.filter_run_excluding(prism_merge: true) unless deps.prism_merge_available?
|
|
656
|
-
config.filter_run_excluding(psych_merge: true) unless deps.psych_merge_available?
|
|
670
|
+
config.filter_run_excluding(toml_rb: true) unless deps.toml_rb_available?
|
|
657
671
|
|
|
658
672
|
# ============================================================
|
|
659
673
|
# Negated Tags (run when dependency is NOT available)
|
|
660
674
|
# ============================================================
|
|
675
|
+
# Prefix: not_* - exclude tests when the dependency IS available
|
|
661
676
|
|
|
662
|
-
# NOTE: :
|
|
677
|
+
# NOTE: :not_ffi_backend tag is not provided because FFI availability is dynamic.
|
|
663
678
|
|
|
664
679
|
# TreeHaver backends
|
|
665
680
|
config.filter_run_excluding(not_mri_backend: true) if deps.mri_backend_available?
|
|
@@ -667,31 +682,26 @@ RSpec.configure do |config|
|
|
|
667
682
|
config.filter_run_excluding(not_java_backend: true) if deps.java_backend_available?
|
|
668
683
|
config.filter_run_excluding(not_prism_backend: true) if deps.prism_available?
|
|
669
684
|
config.filter_run_excluding(not_psych_backend: true) if deps.psych_available?
|
|
670
|
-
config.filter_run_excluding(
|
|
671
|
-
config.filter_run_excluding(
|
|
672
|
-
config.filter_run_excluding(
|
|
685
|
+
config.filter_run_excluding(not_commonmarker_backend: true) if deps.commonmarker_available?
|
|
686
|
+
config.filter_run_excluding(not_markly_backend: true) if deps.markly_available?
|
|
687
|
+
config.filter_run_excluding(not_citrus_backend: true) if deps.citrus_available?
|
|
673
688
|
|
|
674
689
|
# Ruby engines
|
|
675
|
-
config.filter_run_excluding(
|
|
676
|
-
config.filter_run_excluding(
|
|
677
|
-
config.filter_run_excluding(
|
|
690
|
+
config.filter_run_excluding(not_mri_engine: true) if deps.mri?
|
|
691
|
+
config.filter_run_excluding(not_jruby_engine: true) if deps.jruby?
|
|
692
|
+
config.filter_run_excluding(not_truffleruby_engine: true) if deps.truffleruby?
|
|
678
693
|
|
|
679
|
-
#
|
|
694
|
+
# Tree-sitter grammars
|
|
680
695
|
config.filter_run_excluding(not_libtree_sitter: true) if deps.libtree_sitter_available?
|
|
681
|
-
config.filter_run_excluding(
|
|
696
|
+
config.filter_run_excluding(not_bash_grammar: true) if deps.tree_sitter_bash_available?
|
|
697
|
+
config.filter_run_excluding(not_toml_grammar: true) if deps.tree_sitter_toml_available?
|
|
698
|
+
config.filter_run_excluding(not_json_grammar: true) if deps.tree_sitter_json_available?
|
|
699
|
+
config.filter_run_excluding(not_jsonc_grammar: true) if deps.tree_sitter_jsonc_available?
|
|
700
|
+
|
|
701
|
+
# Language parsing capabilities
|
|
702
|
+
config.filter_run_excluding(not_toml_parsing: true) if deps.any_toml_backend_available?
|
|
703
|
+
config.filter_run_excluding(not_markdown_parsing: true) if deps.any_markdown_backend_available?
|
|
682
704
|
|
|
683
|
-
#
|
|
684
|
-
config.filter_run_excluding(not_tree_sitter_bash: true) if deps.tree_sitter_bash_available?
|
|
685
|
-
config.filter_run_excluding(not_tree_sitter_toml: true) if deps.tree_sitter_toml_available?
|
|
686
|
-
config.filter_run_excluding(not_tree_sitter_json: true) if deps.tree_sitter_json_available?
|
|
687
|
-
config.filter_run_excluding(not_tree_sitter_jsonc: true) if deps.tree_sitter_jsonc_available?
|
|
705
|
+
# Specific libraries
|
|
688
706
|
config.filter_run_excluding(not_toml_rb: true) if deps.toml_rb_available?
|
|
689
|
-
config.filter_run_excluding(not_toml_backend: true) if deps.any_toml_backend_available?
|
|
690
|
-
config.filter_run_excluding(not_markdown_backend: true) if deps.any_markdown_backend_available?
|
|
691
|
-
|
|
692
|
-
# Inner-merge dependencies
|
|
693
|
-
config.filter_run_excluding(not_toml_merge: true) if deps.toml_merge_available?
|
|
694
|
-
config.filter_run_excluding(not_json_merge: true) if deps.json_merge_available?
|
|
695
|
-
config.filter_run_excluding(not_prism_merge: true) if deps.prism_merge_available?
|
|
696
|
-
config.filter_run_excluding(not_psych_merge: true) if deps.psych_merge_available?
|
|
697
707
|
end
|