tree_haver 5.0.5 → 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 -251
- metadata.gz.sig +0 -0
- data/CHANGELOG.md +0 -1393
- 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 -2320
- 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
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module TreeHaver
|
|
4
|
-
module Backends
|
|
5
|
-
# Prism backend using Ruby's built-in Prism parser
|
|
6
|
-
#
|
|
7
|
-
# This backend wraps Prism, Ruby's official parser (stdlib in Ruby 3.4+,
|
|
8
|
-
# available as a gem for 3.2+). Unlike tree-sitter backends which are
|
|
9
|
-
# language-agnostic runtime parsers, Prism is specifically designed for
|
|
10
|
-
# parsing Ruby source code.
|
|
11
|
-
#
|
|
12
|
-
# Prism provides excellent error recovery, detailed location information,
|
|
13
|
-
# and is the future of Ruby parsing (used by CRuby, JRuby, TruffleRuby).
|
|
14
|
-
#
|
|
15
|
-
# @note This backend only parses Ruby source code
|
|
16
|
-
# @see https://github.com/ruby/prism Prism parser
|
|
17
|
-
#
|
|
18
|
-
# @example Basic usage
|
|
19
|
-
# parser = TreeHaver::Parser.new
|
|
20
|
-
# parser.language = TreeHaver::Backends::Prism::Language.ruby
|
|
21
|
-
# tree = parser.parse(ruby_source)
|
|
22
|
-
# root = tree.root_node
|
|
23
|
-
# puts root.type # => "program_node"
|
|
24
|
-
module Prism
|
|
25
|
-
@load_attempted = false
|
|
26
|
-
@loaded = false
|
|
27
|
-
|
|
28
|
-
# Check if the Prism backend is available
|
|
29
|
-
#
|
|
30
|
-
# Attempts to require prism on first call and caches the result.
|
|
31
|
-
# On Ruby 3.4+, Prism is in stdlib. On 3.2-3.3, it's a gem.
|
|
32
|
-
#
|
|
33
|
-
# @return [Boolean] true if prism is available
|
|
34
|
-
# @example
|
|
35
|
-
# if TreeHaver::Backends::Prism.available?
|
|
36
|
-
# puts "Prism backend is ready"
|
|
37
|
-
# end
|
|
38
|
-
class << self
|
|
39
|
-
def available?
|
|
40
|
-
return @loaded if @load_attempted # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
41
|
-
@load_attempted = true # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
42
|
-
begin
|
|
43
|
-
require "prism"
|
|
44
|
-
@loaded = true # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
45
|
-
rescue LoadError
|
|
46
|
-
@loaded = false # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
47
|
-
rescue StandardError
|
|
48
|
-
# :nocov: defensive code - StandardError during require is extremely rare
|
|
49
|
-
@loaded = false # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
50
|
-
# :nocov:
|
|
51
|
-
end
|
|
52
|
-
@loaded # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Reset the load state (primarily for testing)
|
|
56
|
-
#
|
|
57
|
-
# @return [void]
|
|
58
|
-
# @api private
|
|
59
|
-
def reset!
|
|
60
|
-
@load_attempted = false # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
61
|
-
@loaded = false # rubocop:disable ThreadSafety/ClassInstanceVariable
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
# Get capabilities supported by this backend
|
|
65
|
-
#
|
|
66
|
-
# @return [Hash{Symbol => Object}] capability map
|
|
67
|
-
# @example
|
|
68
|
-
# TreeHaver::Backends::Prism.capabilities
|
|
69
|
-
# # => { backend: :prism, query: false, bytes_field: true, incremental: false, ruby_only: true }
|
|
70
|
-
def capabilities
|
|
71
|
-
return {} unless available?
|
|
72
|
-
{
|
|
73
|
-
backend: :prism,
|
|
74
|
-
query: false, # Prism doesn't have tree-sitter-style queries (has pattern matching)
|
|
75
|
-
bytes_field: true, # Prism provides byte offsets via Location
|
|
76
|
-
incremental: false, # Prism doesn't support incremental parsing (yet)
|
|
77
|
-
pure_ruby: false, # Prism has native C extension (but also pure Ruby mode)
|
|
78
|
-
ruby_only: true, # Prism only parses Ruby source code
|
|
79
|
-
error_tolerant: true, # Prism has excellent error recovery
|
|
80
|
-
}
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Prism language wrapper
|
|
85
|
-
#
|
|
86
|
-
# Unlike tree-sitter which supports many languages via grammar files,
|
|
87
|
-
# Prism only parses Ruby. This class exists for API compatibility with
|
|
88
|
-
# other tree_haver backends.
|
|
89
|
-
#
|
|
90
|
-
# @example
|
|
91
|
-
# language = TreeHaver::Backends::Prism::Language.ruby
|
|
92
|
-
# parser.language = language
|
|
93
|
-
class Language < TreeHaver::Base::Language
|
|
94
|
-
# @param name [Symbol] language name (should be :ruby)
|
|
95
|
-
# @param options [Hash] Prism parsing options (e.g., frozen_string_literal, version)
|
|
96
|
-
def initialize(name = :ruby, options: {})
|
|
97
|
-
super(name, backend: :prism, options: options)
|
|
98
|
-
|
|
99
|
-
unless self.name == :ruby
|
|
100
|
-
raise TreeHaver::NotAvailable,
|
|
101
|
-
"Prism only supports Ruby parsing. " \
|
|
102
|
-
"Got language: #{name.inspect}"
|
|
103
|
-
end
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
# Compare languages for equality by options (since name is always :ruby)
|
|
107
|
-
#
|
|
108
|
-
# @param other [Object] object to compare with
|
|
109
|
-
# @return [Integer, nil] -1, 0, 1, or nil if not comparable
|
|
110
|
-
def <=>(other)
|
|
111
|
-
return unless other.is_a?(TreeHaver::Base::Language)
|
|
112
|
-
return unless other.backend == backend
|
|
113
|
-
|
|
114
|
-
options.to_a.sort <=> other.options.to_a.sort
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
class << self
|
|
118
|
-
# Create a Ruby language instance (convenience method)
|
|
119
|
-
#
|
|
120
|
-
# @param options [Hash] Prism parsing options
|
|
121
|
-
# @option options [Boolean] :frozen_string_literal frozen string literal pragma
|
|
122
|
-
# @option options [String] :version Ruby version to parse as (e.g., "3.3.0")
|
|
123
|
-
# @option options [Symbol] :command_line command line option (-e, -n, etc.)
|
|
124
|
-
# @return [Language]
|
|
125
|
-
# @example
|
|
126
|
-
# lang = TreeHaver::Backends::Prism::Language.ruby
|
|
127
|
-
# lang = TreeHaver::Backends::Prism::Language.ruby(frozen_string_literal: true)
|
|
128
|
-
def ruby(options = {})
|
|
129
|
-
new(:ruby, options: options)
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
# Load language from library path (API compatibility)
|
|
133
|
-
#
|
|
134
|
-
# Prism only supports Ruby, so path and symbol parameters are ignored.
|
|
135
|
-
#
|
|
136
|
-
# @param _path [String] Ignored - Prism doesn't load external grammars
|
|
137
|
-
# @param symbol [String, nil] Ignored - Prism only supports Ruby
|
|
138
|
-
# @param name [String, nil] Language name hint (defaults to :ruby)
|
|
139
|
-
# @return [Language] Ruby language
|
|
140
|
-
# @raise [TreeHaver::NotAvailable] if requested language is not Ruby
|
|
141
|
-
def from_library(_path = nil, symbol: nil, name: nil)
|
|
142
|
-
lang_name = name || :ruby
|
|
143
|
-
|
|
144
|
-
unless lang_name == :ruby
|
|
145
|
-
raise TreeHaver::NotAvailable,
|
|
146
|
-
"Prism backend only supports Ruby, not #{lang_name}. " \
|
|
147
|
-
"Use a tree-sitter backend for #{lang_name} support."
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
ruby
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
alias_method :from_path, :from_library
|
|
154
|
-
end
|
|
155
|
-
end
|
|
156
|
-
|
|
157
|
-
# Prism parser wrapper
|
|
158
|
-
#
|
|
159
|
-
# Wraps Prism to provide a tree-sitter-like API for parsing Ruby code.
|
|
160
|
-
class Parser < TreeHaver::Base::Parser
|
|
161
|
-
# Create a new Prism parser instance
|
|
162
|
-
#
|
|
163
|
-
# @raise [TreeHaver::NotAvailable] if prism is not available
|
|
164
|
-
def initialize
|
|
165
|
-
super
|
|
166
|
-
raise TreeHaver::NotAvailable, "prism not available" unless Prism.available?
|
|
167
|
-
@options = {}
|
|
168
|
-
end
|
|
169
|
-
|
|
170
|
-
# Set the language for this parser
|
|
171
|
-
#
|
|
172
|
-
# Note: TreeHaver::Parser unwraps language objects before calling this method.
|
|
173
|
-
# This backend receives the Language wrapper (since Prism::Language stores options).
|
|
174
|
-
#
|
|
175
|
-
# @param lang [Language, Symbol] Prism language (should be :ruby or Language instance)
|
|
176
|
-
# @return [void]
|
|
177
|
-
def language=(lang)
|
|
178
|
-
case lang
|
|
179
|
-
when Language
|
|
180
|
-
@language = lang
|
|
181
|
-
@options = lang.options
|
|
182
|
-
when Symbol, String
|
|
183
|
-
if lang.to_sym == :ruby
|
|
184
|
-
@language = Language.ruby
|
|
185
|
-
@options = {}
|
|
186
|
-
else
|
|
187
|
-
raise ArgumentError,
|
|
188
|
-
"Prism only supports Ruby parsing. Got: #{lang.inspect}"
|
|
189
|
-
end
|
|
190
|
-
else
|
|
191
|
-
raise ArgumentError,
|
|
192
|
-
"Expected Prism::Language or :ruby, got #{lang.class}"
|
|
193
|
-
end
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
# Parse source code
|
|
197
|
-
#
|
|
198
|
-
# @param source [String] the Ruby source code to parse
|
|
199
|
-
# @return [Tree] raw backend tree (wrapping happens in TreeHaver::Parser)
|
|
200
|
-
# @raise [TreeHaver::NotAvailable] if no language is set
|
|
201
|
-
def parse(source)
|
|
202
|
-
raise TreeHaver::NotAvailable, "No language loaded (use parser.language = :ruby)" unless @language
|
|
203
|
-
|
|
204
|
-
# Use Prism.parse with options
|
|
205
|
-
prism_result = ::Prism.parse(source, **@options)
|
|
206
|
-
Tree.new(prism_result, source)
|
|
207
|
-
end
|
|
208
|
-
|
|
209
|
-
# Parse source code (compatibility with tree-sitter API)
|
|
210
|
-
#
|
|
211
|
-
# Prism doesn't support incremental parsing, so old_tree is ignored.
|
|
212
|
-
#
|
|
213
|
-
# @param old_tree [TreeHaver::Tree, nil] ignored (no incremental parsing support)
|
|
214
|
-
# @param source [String] the Ruby source code to parse
|
|
215
|
-
# @return [Tree] raw backend tree (wrapping happens in TreeHaver::Parser)
|
|
216
|
-
def parse_string(old_tree, source) # rubocop:disable Lint/UnusedMethodArgument
|
|
217
|
-
parse(source) # Prism doesn't support incremental parsing
|
|
218
|
-
end
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
# Prism tree wrapper
|
|
222
|
-
#
|
|
223
|
-
# Wraps a Prism::ParseResult to provide tree-sitter-compatible API.
|
|
224
|
-
#
|
|
225
|
-
# @api private
|
|
226
|
-
class Tree < TreeHaver::Base::Tree
|
|
227
|
-
# @return [::Prism::ParseResult] the underlying Prism parse result
|
|
228
|
-
attr_reader :parse_result
|
|
229
|
-
|
|
230
|
-
def initialize(parse_result, source)
|
|
231
|
-
super(parse_result, source: source)
|
|
232
|
-
@parse_result = parse_result
|
|
233
|
-
end
|
|
234
|
-
|
|
235
|
-
# Get the root node of the parse tree
|
|
236
|
-
#
|
|
237
|
-
# @return [Node] wrapped root node
|
|
238
|
-
def root_node
|
|
239
|
-
Node.new(@parse_result.value, source)
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
# Check if the parse had errors
|
|
243
|
-
#
|
|
244
|
-
# @return [Boolean]
|
|
245
|
-
def has_errors?
|
|
246
|
-
@parse_result.failure?
|
|
247
|
-
end
|
|
248
|
-
|
|
249
|
-
# Get parse errors
|
|
250
|
-
#
|
|
251
|
-
# @return [Array<::Prism::ParseError>]
|
|
252
|
-
def errors
|
|
253
|
-
@parse_result.errors
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
# Get parse warnings
|
|
257
|
-
#
|
|
258
|
-
# @return [Array<::Prism::ParseWarning>]
|
|
259
|
-
def warnings
|
|
260
|
-
@parse_result.warnings
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
# Get comments from the parse
|
|
264
|
-
#
|
|
265
|
-
# @return [Array<::Prism::Comment>]
|
|
266
|
-
def comments
|
|
267
|
-
@parse_result.comments
|
|
268
|
-
end
|
|
269
|
-
|
|
270
|
-
# Get magic comments (e.g., frozen_string_literal)
|
|
271
|
-
#
|
|
272
|
-
# @return [Array<::Prism::MagicComment>]
|
|
273
|
-
def magic_comments
|
|
274
|
-
@parse_result.magic_comments
|
|
275
|
-
end
|
|
276
|
-
|
|
277
|
-
# Get data locations (__END__ section)
|
|
278
|
-
#
|
|
279
|
-
# @return [::Prism::Location, nil]
|
|
280
|
-
def data_loc
|
|
281
|
-
@parse_result.data_loc
|
|
282
|
-
end
|
|
283
|
-
end
|
|
284
|
-
|
|
285
|
-
# Prism node wrapper
|
|
286
|
-
#
|
|
287
|
-
# Wraps Prism::Node objects to provide tree-sitter-compatible node API.
|
|
288
|
-
#
|
|
289
|
-
# Prism nodes provide:
|
|
290
|
-
# - type: class name without "Node" suffix (e.g., ProgramNode → "program")
|
|
291
|
-
# - location: ::Prism::Location with start/end offsets and line/column
|
|
292
|
-
# - child_nodes: array of child nodes
|
|
293
|
-
# - Various node-specific accessors
|
|
294
|
-
#
|
|
295
|
-
# @api private
|
|
296
|
-
class Node < TreeHaver::Base::Node
|
|
297
|
-
def initialize(node, source)
|
|
298
|
-
super(node, source: source)
|
|
299
|
-
end
|
|
300
|
-
|
|
301
|
-
# Get node type from Prism class name
|
|
302
|
-
#
|
|
303
|
-
# Converts PrismClassName to tree-sitter-style type string.
|
|
304
|
-
# Example: CallNode → "call_node", ProgramNode → "program_node"
|
|
305
|
-
#
|
|
306
|
-
# @return [String] node type in snake_case
|
|
307
|
-
def type
|
|
308
|
-
return "nil" if inner_node.nil?
|
|
309
|
-
|
|
310
|
-
# Convert class name to snake_case type
|
|
311
|
-
class_name = inner_node.class.name.split("::").last
|
|
312
|
-
class_name.gsub(/([A-Z])/, '_\1').downcase.sub(/^_/, "")
|
|
313
|
-
end
|
|
314
|
-
|
|
315
|
-
# Alias for type (API compatibility)
|
|
316
|
-
# @return [String] node type
|
|
317
|
-
def kind
|
|
318
|
-
type
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
# Get byte offset where the node starts
|
|
322
|
-
#
|
|
323
|
-
# @return [Integer]
|
|
324
|
-
def start_byte
|
|
325
|
-
return 0 if inner_node.nil? || !inner_node.respond_to?(:location)
|
|
326
|
-
loc = inner_node.location
|
|
327
|
-
loc&.start_offset || 0
|
|
328
|
-
end
|
|
329
|
-
|
|
330
|
-
# Get byte offset where the node ends
|
|
331
|
-
#
|
|
332
|
-
# @return [Integer]
|
|
333
|
-
def end_byte
|
|
334
|
-
return 0 if inner_node.nil? || !inner_node.respond_to?(:location)
|
|
335
|
-
loc = inner_node.location
|
|
336
|
-
loc&.end_offset || 0
|
|
337
|
-
end
|
|
338
|
-
|
|
339
|
-
# Get the start position as row/column (0-based)
|
|
340
|
-
#
|
|
341
|
-
# @return [Hash{Symbol => Integer}]
|
|
342
|
-
def start_point
|
|
343
|
-
return {row: 0, column: 0} if inner_node.nil? || !inner_node.respond_to?(:location)
|
|
344
|
-
loc = inner_node.location
|
|
345
|
-
return {row: 0, column: 0} unless loc
|
|
346
|
-
|
|
347
|
-
{row: (loc.start_line - 1), column: loc.start_column}
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
# Get the end position as row/column (0-based)
|
|
351
|
-
#
|
|
352
|
-
# @return [Hash{Symbol => Integer}]
|
|
353
|
-
def end_point
|
|
354
|
-
return {row: 0, column: 0} if inner_node.nil? || !inner_node.respond_to?(:location)
|
|
355
|
-
loc = inner_node.location
|
|
356
|
-
return {row: 0, column: 0} unless loc
|
|
357
|
-
|
|
358
|
-
{row: (loc.end_line - 1), column: loc.end_column}
|
|
359
|
-
end
|
|
360
|
-
|
|
361
|
-
# Get all child nodes
|
|
362
|
-
#
|
|
363
|
-
# @return [Array<Node>] array of wrapped child nodes
|
|
364
|
-
def children
|
|
365
|
-
return [] if inner_node.nil?
|
|
366
|
-
return [] unless inner_node.respond_to?(:child_nodes)
|
|
367
|
-
|
|
368
|
-
inner_node.child_nodes.compact.map { |n| Node.new(n, source) }
|
|
369
|
-
end
|
|
370
|
-
|
|
371
|
-
# Get the text content of this node
|
|
372
|
-
#
|
|
373
|
-
# @return [String]
|
|
374
|
-
def text
|
|
375
|
-
return "" if inner_node.nil?
|
|
376
|
-
|
|
377
|
-
if inner_node.respond_to?(:slice)
|
|
378
|
-
inner_node.slice
|
|
379
|
-
else
|
|
380
|
-
super
|
|
381
|
-
end
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
# Alias for Prism compatibility
|
|
385
|
-
alias_method :slice, :text
|
|
386
|
-
|
|
387
|
-
# Check if this node has errors
|
|
388
|
-
#
|
|
389
|
-
# @return [Boolean]
|
|
390
|
-
def has_error?
|
|
391
|
-
return false if inner_node.nil?
|
|
392
|
-
|
|
393
|
-
# Check if this is an error node type
|
|
394
|
-
return true if type.include?("missing") || type.include?("error")
|
|
395
|
-
|
|
396
|
-
# Check children recursively (Prism error nodes are usually children)
|
|
397
|
-
return false unless inner_node.respond_to?(:child_nodes)
|
|
398
|
-
inner_node.child_nodes.compact.any? { |n| n.class.name.to_s.include?("Missing") }
|
|
399
|
-
end
|
|
400
|
-
|
|
401
|
-
# Check if this node is a "missing" node (error recovery)
|
|
402
|
-
#
|
|
403
|
-
# @return [Boolean]
|
|
404
|
-
def missing?
|
|
405
|
-
return false if inner_node.nil?
|
|
406
|
-
type.include?("missing")
|
|
407
|
-
end
|
|
408
|
-
|
|
409
|
-
# Get a child by field name (Prism node accessor)
|
|
410
|
-
#
|
|
411
|
-
# Prism nodes have specific accessors for their children.
|
|
412
|
-
#
|
|
413
|
-
# @param name [String, Symbol] field/accessor name
|
|
414
|
-
# @return [Node, nil] wrapped child node
|
|
415
|
-
def child_by_field_name(name)
|
|
416
|
-
return if inner_node.nil?
|
|
417
|
-
return unless inner_node.respond_to?(name)
|
|
418
|
-
|
|
419
|
-
result = inner_node.public_send(name)
|
|
420
|
-
return if result.nil?
|
|
421
|
-
|
|
422
|
-
# Wrap if it's a node
|
|
423
|
-
result.is_a?(::Prism::Node) ? Node.new(result, source) : nil
|
|
424
|
-
end
|
|
425
|
-
|
|
426
|
-
alias_method :field, :child_by_field_name
|
|
427
|
-
|
|
428
|
-
# String representation
|
|
429
|
-
#
|
|
430
|
-
# @return [String]
|
|
431
|
-
def to_s
|
|
432
|
-
text
|
|
433
|
-
end
|
|
434
|
-
|
|
435
|
-
# Check if node responds to a method (includes delegation to inner_node)
|
|
436
|
-
#
|
|
437
|
-
# @param method_name [Symbol] method to check
|
|
438
|
-
# @param include_private [Boolean] include private methods
|
|
439
|
-
# @return [Boolean]
|
|
440
|
-
def respond_to_missing?(method_name, include_private = false)
|
|
441
|
-
return false if inner_node.nil?
|
|
442
|
-
inner_node.respond_to?(method_name, include_private) || super
|
|
443
|
-
end
|
|
444
|
-
|
|
445
|
-
# Delegate unknown methods to the underlying Prism node
|
|
446
|
-
#
|
|
447
|
-
# This provides passthrough access for Prism-specific node methods
|
|
448
|
-
# like `receiver`, `message`, `arguments`, etc.
|
|
449
|
-
#
|
|
450
|
-
# @param method_name [Symbol] method to call
|
|
451
|
-
# @param args [Array] arguments to pass
|
|
452
|
-
# @param kwargs [Hash] keyword arguments
|
|
453
|
-
# @param block [Proc] block to pass
|
|
454
|
-
# @return [Object] result from the underlying node
|
|
455
|
-
def method_missing(method_name, *args, **kwargs, &block)
|
|
456
|
-
if inner_node&.respond_to?(method_name)
|
|
457
|
-
inner_node.public_send(method_name, *args, **kwargs, &block)
|
|
458
|
-
else
|
|
459
|
-
super
|
|
460
|
-
end
|
|
461
|
-
end
|
|
462
|
-
end
|
|
463
|
-
|
|
464
|
-
# Register the availability checker for RSpec dependency tags
|
|
465
|
-
TreeHaver::BackendRegistry.register_availability_checker(:prism) do
|
|
466
|
-
available?
|
|
467
|
-
end
|
|
468
|
-
end
|
|
469
|
-
end
|
|
470
|
-
end
|
|
471
|
-
|