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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/lib/tree_haver/backend_context.rb +28 -0
  4. data/lib/tree_haver/backend_registry.rb +19 -432
  5. data/lib/tree_haver/contracts.rb +460 -0
  6. data/lib/tree_haver/kaitai_backend.rb +30 -0
  7. data/lib/tree_haver/language_pack.rb +190 -0
  8. data/lib/tree_haver/peg_backends.rb +76 -0
  9. data/lib/tree_haver/version.rb +1 -12
  10. data/lib/tree_haver.rb +7 -1316
  11. data.tar.gz.sig +0 -0
  12. metadata +34 -245
  13. metadata.gz.sig +0 -0
  14. data/CHANGELOG.md +0 -1366
  15. data/CITATION.cff +0 -20
  16. data/CODE_OF_CONDUCT.md +0 -134
  17. data/CONTRIBUTING.md +0 -359
  18. data/FUNDING.md +0 -74
  19. data/LICENSE.txt +0 -21
  20. data/README.md +0 -2347
  21. data/REEK +0 -0
  22. data/RUBOCOP.md +0 -71
  23. data/SECURITY.md +0 -21
  24. data/lib/tree_haver/backend_api.rb +0 -349
  25. data/lib/tree_haver/backends/citrus.rb +0 -487
  26. data/lib/tree_haver/backends/ffi.rb +0 -1009
  27. data/lib/tree_haver/backends/java.rb +0 -893
  28. data/lib/tree_haver/backends/mri.rb +0 -362
  29. data/lib/tree_haver/backends/parslet.rb +0 -560
  30. data/lib/tree_haver/backends/prism.rb +0 -471
  31. data/lib/tree_haver/backends/psych.rb +0 -375
  32. data/lib/tree_haver/backends/rust.rb +0 -239
  33. data/lib/tree_haver/base/language.rb +0 -98
  34. data/lib/tree_haver/base/node.rb +0 -322
  35. data/lib/tree_haver/base/parser.rb +0 -24
  36. data/lib/tree_haver/base/point.rb +0 -48
  37. data/lib/tree_haver/base/tree.rb +0 -128
  38. data/lib/tree_haver/base.rb +0 -12
  39. data/lib/tree_haver/citrus_grammar_finder.rb +0 -218
  40. data/lib/tree_haver/compat.rb +0 -43
  41. data/lib/tree_haver/grammar_finder.rb +0 -374
  42. data/lib/tree_haver/language.rb +0 -295
  43. data/lib/tree_haver/language_registry.rb +0 -190
  44. data/lib/tree_haver/library_path_utils.rb +0 -80
  45. data/lib/tree_haver/node.rb +0 -579
  46. data/lib/tree_haver/parser.rb +0 -438
  47. data/lib/tree_haver/parslet_grammar_finder.rb +0 -224
  48. data/lib/tree_haver/path_validator.rb +0 -353
  49. data/lib/tree_haver/point.rb +0 -27
  50. data/lib/tree_haver/rspec/dependency_tags.rb +0 -1392
  51. data/lib/tree_haver/rspec/testable_node.rb +0 -217
  52. data/lib/tree_haver/rspec.rb +0 -33
  53. data/lib/tree_haver/tree.rb +0 -258
  54. data/sig/tree_haver/backends.rbs +0 -352
  55. data/sig/tree_haver/grammar_finder.rbs +0 -29
  56. data/sig/tree_haver/path_validator.rbs +0 -32
  57. data/sig/tree_haver.rbs +0 -234
data/REEK DELETED
File without changes
data/RUBOCOP.md DELETED
@@ -1,71 +0,0 @@
1
- # RuboCop Usage Guide
2
-
3
- ## Overview
4
-
5
- A tale of two RuboCop plugin gems.
6
-
7
- ### RuboCop Gradual
8
-
9
- This project uses `rubocop_gradual` instead of vanilla RuboCop for code style checking. The `rubocop_gradual` tool allows for gradual adoption of RuboCop rules by tracking violations in a lock file.
10
-
11
- ### RuboCop LTS
12
-
13
- This project uses `rubocop-lts` to ensure, on a best-effort basis, compatibility with Ruby >= 1.9.2.
14
- RuboCop rules are meticulously configured by the `rubocop-lts` family of gems to ensure that a project is compatible with a specific version of Ruby. See: https://rubocop-lts.gitlab.io for more.
15
-
16
- ## Checking RuboCop Violations
17
-
18
- To check for RuboCop violations in this project, always use:
19
-
20
- ```bash
21
- bundle exec rake rubocop_gradual:check
22
- ```
23
-
24
- **Do not use** the standard RuboCop commands like:
25
- - `bundle exec rubocop`
26
- - `rubocop`
27
-
28
- ## Understanding the Lock File
29
-
30
- The `.rubocop_gradual.lock` file tracks all current RuboCop violations in the project. This allows the team to:
31
-
32
- 1. Prevent new violations while gradually fixing existing ones
33
- 2. Track progress on code style improvements
34
- 3. Ensure CI builds don't fail due to pre-existing violations
35
-
36
- ## Common Commands
37
-
38
- - **Check violations**
39
- - `bundle exec rake rubocop_gradual`
40
- - `bundle exec rake rubocop_gradual:check`
41
- - **(Safe) Autocorrect violations, and update lockfile if no new violations**
42
- - `bundle exec rake rubocop_gradual:autocorrect`
43
- - **Force update the lock file (w/o autocorrect) to match violations present in code**
44
- - `bundle exec rake rubocop_gradual:force_update`
45
-
46
- ## Workflow
47
-
48
- 1. Before submitting a PR, run `bundle exec rake rubocop_gradual:autocorrect`
49
- a. or just the default `bundle exec rake`, as autocorrection is a pre-requisite of the default task.
50
- 2. If there are new violations, either:
51
- - Fix them in your code
52
- - Run `bundle exec rake rubocop_gradual:force_update` to update the lock file (only for violations you can't fix immediately)
53
- 3. Commit the updated `.rubocop_gradual.lock` file along with your changes
54
-
55
- ## Never add inline RuboCop disables
56
-
57
- Do not add inline `rubocop:disable` / `rubocop:enable` comments anywhere in the codebase (including specs, except when following the few existing `rubocop:disable` patterns for a rule already being disabled elsewhere in the code). We handle exceptions in two supported ways:
58
-
59
- - Permanent/structural exceptions: prefer adjusting the RuboCop configuration (e.g., in `.rubocop.yml`) to exclude a rule for a path or file pattern when it makes sense project-wide.
60
- - Temporary exceptions while improving code: record the current violations in `.rubocop_gradual.lock` via the gradual workflow:
61
- - `bundle exec rake rubocop_gradual:autocorrect` (preferred; will autocorrect what it can and update the lock only if no new violations were introduced)
62
- - If needed, `bundle exec rake rubocop_gradual:force_update` (as a last resort when you cannot fix the newly reported violations immediately)
63
-
64
- In general, treat the rules as guidance to follow; fix violations rather than ignore them. For example, RSpec conventions in this project expect `described_class` to be used in specs that target a specific class under test.
65
-
66
- ## Benefits of rubocop_gradual
67
-
68
- - Allows incremental adoption of code style rules
69
- - Prevents CI failures due to pre-existing violations
70
- - Provides a clear record of code style debt
71
- - Enables focused efforts on improving code quality over time
data/SECURITY.md DELETED
@@ -1,21 +0,0 @@
1
- # Security Policy
2
-
3
- ## Supported Versions
4
-
5
- | Version | Supported |
6
- |----------|-----------|
7
- | 5.latest | ✅ |
8
-
9
- ## Security contact information
10
-
11
- To report a security vulnerability, please use the
12
- [Tidelift security contact](https://tidelift.com/security).
13
- Tidelift will coordinate the fix and disclosure.
14
-
15
- ## Additional Support
16
-
17
- If you are interested in support for versions older than the latest release,
18
- please consider sponsoring the project / maintainer @ https://liberapay.com/pboling/donate,
19
- or find other sponsorship links in the [README].
20
-
21
- [README]: README.md
@@ -1,349 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module TreeHaver
4
- # Backend API contract definitions and validation
5
- #
6
- # This module defines the expected API surface for TreeHaver backends.
7
- # Each backend must provide Parser, Language, Tree, and Node classes/objects
8
- # that conform to these interfaces.
9
- #
10
- # == Architecture
11
- #
12
- # TreeHaver backends fall into two categories:
13
- #
14
- # 1. **Raw backends** (MRI, FFI, Rust) - Return raw tree-sitter objects
15
- # (e.g., ::TreeSitter::Node). TreeHaver::Node wraps these and provides
16
- # a unified API via method delegation.
17
- #
18
- # 2. **Wrapper backends** (Java, Citrus, Prism, Psych, Commonmarker, Markly) -
19
- # Return their own wrapper objects that must implement the expected API
20
- # directly, since TreeHaver::Node will delegate to them.
21
- #
22
- # == Usage
23
- #
24
- # # Validate a backend's API compliance
25
- # TreeHaver::BackendAPI.validate!(backend_module)
26
- #
27
- # # Check specific class compliance
28
- # TreeHaver::BackendAPI.validate_node!(node_instance)
29
- #
30
- module BackendAPI
31
- # Required methods for Language class/instances
32
- #
33
- # All backends MUST implement `from_library` for API consistency.
34
- # Language-specific backends (Psych, Prism, Commonmarker, Markly) should
35
- # implement `from_library` to accept (and ignore) path/symbol parameters,
36
- # returning their single supported language.
37
- #
38
- # This ensures `TreeHaver.parser_for(:yaml)` works regardless of backend -
39
- # tree-sitter backends load the YAML grammar, while Psych returns its
40
- # built-in YAML support.
41
- #
42
- # Convenience methods (yaml, ruby, markdown) are OPTIONAL and only make
43
- # sense on backends that only support one language family.
44
- LANGUAGE_CLASS_METHODS = %i[
45
- from_library
46
- ].freeze
47
-
48
- # Optional convenience methods for language-specific backends
49
- # These are NOT required - they're just shortcuts for single-language backends
50
- LANGUAGE_OPTIONAL_CLASS_METHODS = %i[
51
- yaml
52
- ruby
53
- markdown
54
- ].freeze
55
-
56
- LANGUAGE_INSTANCE_METHODS = %i[
57
- backend
58
- ].freeze
59
-
60
- # Required methods for Parser class/instances
61
- PARSER_CLASS_METHODS = %i[
62
- new
63
- ].freeze
64
-
65
- PARSER_INSTANCE_METHODS = %i[
66
- language=
67
- parse
68
- ].freeze
69
-
70
- # Optional Parser methods (for incremental parsing)
71
- PARSER_OPTIONAL_METHODS = %i[
72
- parse_string
73
- ].freeze
74
-
75
- # Required methods for Tree instances
76
- # Note: Tree is returned by Parser#parse, not instantiated directly
77
- TREE_INSTANCE_METHODS = %i[
78
- root_node
79
- ].freeze
80
-
81
- # Optional Tree methods (for incremental parsing)
82
- TREE_OPTIONAL_METHODS = %i[
83
- edit
84
- ].freeze
85
-
86
- # Required methods for Node instances returned by wrapper backends
87
- # These are the methods TreeHaver::Node delegates to inner_node
88
- #
89
- # Raw backends (MRI, FFI, Rust) return tree-sitter native nodes which
90
- # have their own API. TreeHaver::Node handles the translation.
91
- #
92
- # Wrapper backends (Java, Citrus, etc.) must implement these methods
93
- # on their Node class since TreeHaver::Node delegates to them.
94
- NODE_INSTANCE_METHODS = %i[
95
- type
96
- child_count
97
- child
98
- start_byte
99
- end_byte
100
- ].freeze
101
-
102
- # Optional Node methods - should return nil if not supported
103
- NODE_OPTIONAL_METHODS = %i[
104
- parent
105
- next_sibling
106
- prev_sibling
107
- named?
108
- has_error?
109
- missing?
110
- text
111
- child_by_field_name
112
- start_point
113
- end_point
114
- ].freeze
115
-
116
- # Methods that have common aliases across backends
117
- NODE_ALIASES = {
118
- type: %i[kind],
119
- named?: %i[is_named? is_named],
120
- has_error?: %i[has_error],
121
- missing?: %i[is_missing? is_missing],
122
- next_sibling: %i[next_named_sibling],
123
- prev_sibling: %i[previous_sibling previous_named_sibling prev_named_sibling],
124
- }.freeze
125
-
126
- class << self
127
- # Validate a backend module for API compliance
128
- #
129
- # @param backend_module [Module] The backend module (e.g., TreeHaver::Backends::Java)
130
- # @param strict [Boolean] If true, raise on missing optional methods
131
- # @return [Hash] Validation results with :valid, :errors, :warnings keys
132
- def validate(backend_module, strict: false)
133
- results = {
134
- valid: true,
135
- errors: [],
136
- warnings: [],
137
- capabilities: {},
138
- }
139
-
140
- # Check module-level methods
141
- validate_module_methods(backend_module, results)
142
-
143
- # Check Language class
144
- if backend_module.const_defined?(:Language)
145
- validate_language(backend_module::Language, results)
146
- else
147
- results[:errors] << "Missing Language class"
148
- results[:valid] = false
149
- end
150
-
151
- # Check Parser class
152
- if backend_module.const_defined?(:Parser)
153
- validate_parser(backend_module::Parser, results)
154
- else
155
- results[:errors] << "Missing Parser class"
156
- results[:valid] = false
157
- end
158
-
159
- # Check Tree class if present (some backends return raw trees)
160
- if backend_module.const_defined?(:Tree)
161
- validate_tree(backend_module::Tree, results)
162
- else
163
- results[:warnings] << "No Tree class (backend returns raw trees)"
164
- end
165
-
166
- # Check Node class if present (wrapper backends)
167
- if backend_module.const_defined?(:Node)
168
- validate_node_class(backend_module::Node, results, strict: strict)
169
- else
170
- results[:warnings] << "No Node class (backend returns raw nodes, TreeHaver::Node will wrap)"
171
- end
172
-
173
- # Fail on warnings in strict mode
174
- if strict && results[:warnings].any?
175
- results[:valid] = false
176
- end
177
-
178
- results
179
- end
180
-
181
- # Validate and raise on failure
182
- #
183
- # @param backend_module [Module] The backend module to validate
184
- # @param strict [Boolean] If true, treat warnings as errors
185
- # @raise [TreeHaver::Error] if validation fails
186
- # @return [Hash] Validation results if valid
187
- def validate!(backend_module, strict: false)
188
- results = validate(backend_module, strict: strict)
189
- unless results[:valid]
190
- raise TreeHaver::Error,
191
- "Backend #{backend_module.name} API validation failed:\n " \
192
- "Errors: #{results[:errors].join(", ")}\n " \
193
- "Warnings: #{results[:warnings].join(", ")}"
194
- end
195
- results
196
- end
197
-
198
- # Validate a Node instance for API compliance
199
- #
200
- # @param node [Object] A node instance to validate
201
- # @return [Hash] Validation results
202
- def validate_node_instance(node)
203
- results = {
204
- valid: true,
205
- errors: [],
206
- warnings: [],
207
- supported_methods: [],
208
- unsupported_methods: [],
209
- }
210
-
211
- # Check required methods
212
- NODE_INSTANCE_METHODS.each do |method|
213
- if responds_to_with_aliases?(node, method)
214
- results[:supported_methods] << method
215
- else
216
- results[:errors] << "Missing required method: #{method}"
217
- results[:valid] = false
218
- end
219
- end
220
-
221
- # Check optional methods
222
- NODE_OPTIONAL_METHODS.each do |method|
223
- if responds_to_with_aliases?(node, method)
224
- results[:supported_methods] << method
225
- else
226
- results[:unsupported_methods] << method
227
- results[:warnings] << "Missing optional method: #{method}"
228
- end
229
- end
230
-
231
- results
232
- end
233
-
234
- private
235
-
236
- def validate_module_methods(mod, results)
237
- unless mod.singleton_class.method_defined?(:available?)
238
- results[:errors] << "Missing module method: available?"
239
- results[:valid] = false
240
- end
241
-
242
- unless mod.singleton_class.method_defined?(:capabilities)
243
- results[:warnings] << "Missing module method: capabilities"
244
- end
245
- end
246
-
247
- def validate_language(klass, results)
248
- # from_library is REQUIRED for all backends
249
- # Language-specific backends should implement it to ignore path/symbol
250
- # and return their single language (for API consistency)
251
- unless klass.singleton_class.method_defined?(:from_library)
252
- results[:errors] << "Language missing required class method: from_library"
253
- results[:valid] = false
254
- end
255
-
256
- # Check for optional convenience methods
257
- optional_methods = LANGUAGE_OPTIONAL_CLASS_METHODS.select { |m| klass.singleton_class.method_defined?(m) }
258
- if optional_methods.any?
259
- results[:capabilities][:language_shortcuts] = optional_methods
260
- end
261
-
262
- results[:capabilities][:language] = {
263
- class_methods: LANGUAGE_CLASS_METHODS.select { |m| klass.singleton_class.method_defined?(m) } +
264
- optional_methods,
265
- }
266
- end
267
-
268
- def validate_parser(klass, results)
269
- PARSER_CLASS_METHODS.each do |method|
270
- unless klass.singleton_class.method_defined?(method)
271
- results[:errors] << "Parser missing class method: #{method}"
272
- results[:valid] = false
273
- end
274
- end
275
-
276
- # Check instance methods by inspecting the class
277
- PARSER_INSTANCE_METHODS.each do |method|
278
- unless klass.method_defined?(method) || klass.private_method_defined?(method)
279
- results[:errors] << "Parser missing instance method: #{method}"
280
- results[:valid] = false
281
- end
282
- end
283
-
284
- PARSER_OPTIONAL_METHODS.each do |method|
285
- unless klass.method_defined?(method)
286
- results[:warnings] << "Parser missing optional method: #{method}"
287
- end
288
- end
289
- end
290
-
291
- def validate_tree(klass, results)
292
- TREE_INSTANCE_METHODS.each do |method|
293
- unless klass.method_defined?(method)
294
- results[:errors] << "Tree missing instance method: #{method}"
295
- results[:valid] = false
296
- end
297
- end
298
-
299
- TREE_OPTIONAL_METHODS.each do |method|
300
- unless klass.method_defined?(method)
301
- results[:warnings] << "Tree missing optional method: #{method}"
302
- end
303
- end
304
- end
305
-
306
- def validate_node_class(klass, results, strict: false)
307
- NODE_INSTANCE_METHODS.each do |method|
308
- unless has_method_or_alias?(klass, method)
309
- results[:errors] << "Node missing required method: #{method}"
310
- results[:valid] = false
311
- end
312
- end
313
-
314
- NODE_OPTIONAL_METHODS.each do |method|
315
- unless has_method_or_alias?(klass, method)
316
- msg = "Node missing optional method: #{method}"
317
- if strict
318
- results[:errors] << msg
319
- results[:valid] = false
320
- else
321
- results[:warnings] << msg
322
- end
323
- end
324
- end
325
-
326
- results[:capabilities][:node] = {
327
- required: NODE_INSTANCE_METHODS.select { |m| has_method_or_alias?(klass, m) },
328
- optional: NODE_OPTIONAL_METHODS.select { |m| has_method_or_alias?(klass, m) },
329
- }
330
- end
331
-
332
- def has_method_or_alias?(klass, method)
333
- return true if klass.method_defined?(method)
334
-
335
- # Check aliases
336
- aliases = NODE_ALIASES[method] || []
337
- aliases.any? { |alt| klass.method_defined?(alt) }
338
- end
339
-
340
- def responds_to_with_aliases?(obj, method)
341
- return true if obj.respond_to?(method)
342
-
343
- # Check aliases
344
- aliases = NODE_ALIASES[method] || []
345
- aliases.any? { |alt| obj.respond_to?(alt) }
346
- end
347
- end
348
- end
349
- end