Module: TreeHaver::BackendAPI
- Defined in:
- lib/tree_haver/backend_api.rb
Overview
Backend API contract definitions and validation
This module defines the expected API surface for TreeHaver backends. Each backend must provide Parser, Language, Tree, and Node classes/objects that conform to these interfaces.
Architecture
TreeHaver backends fall into two categories:
-
**Raw backends** (MRI, FFI, Rust) - Return raw tree-sitter objects (e.g., ::TreeSitter::Node). TreeHaver::Node wraps these and provides a unified API via method delegation.
-
**Wrapper backends** (Java, Citrus, Prism, Psych, Commonmarker, Markly) - Return their own wrapper objects that must implement the expected API directly, since TreeHaver::Node will delegate to them.
Usage
# Validate a backend's API compliance
TreeHaver::BackendAPI.validate!(backend_module)
# Check specific class compliance
TreeHaver::BackendAPI.validate_node!(node_instance)
Constant Summary collapse
- LANGUAGE_CLASS_METHODS =
Required methods for Language class/instances
All backends MUST implement
from_libraryfor API consistency. Language-specific backends (Psych, Prism, Commonmarker, Markly) should implementfrom_libraryto accept (and ignore) path/symbol parameters, returning their single supported language.This ensures ‘TreeHaver.parser_for(:yaml)` works regardless of backend - tree-sitter backends load the YAML grammar, while Psych returns its built-in YAML support.
Convenience methods (yaml, ruby, markdown) are OPTIONAL and only make sense on backends that only support one language family.
i[ from_library ].freeze
- LANGUAGE_OPTIONAL_CLASS_METHODS =
Optional convenience methods for language-specific backends These are NOT required - they’re just shortcuts for single-language backends
i[ yaml ruby markdown ].freeze
- LANGUAGE_INSTANCE_METHODS =
i[ backend ].freeze
- PARSER_CLASS_METHODS =
Required methods for Parser class/instances
i[ new ].freeze
- PARSER_INSTANCE_METHODS =
i[ language= parse ].freeze
- PARSER_OPTIONAL_METHODS =
Optional Parser methods (for incremental parsing)
i[ parse_string ].freeze
- TREE_INSTANCE_METHODS =
Required methods for Tree instances Note: Tree is returned by Parser#parse, not instantiated directly
i[ root_node ].freeze
- TREE_OPTIONAL_METHODS =
Optional Tree methods (for incremental parsing)
i[ edit ].freeze
- NODE_INSTANCE_METHODS =
Required methods for Node instances returned by wrapper backends These are the methods TreeHaver::Node delegates to inner_node
Raw backends (MRI, FFI, Rust) return tree-sitter native nodes which have their own API. TreeHaver::Node handles the translation.
Wrapper backends (Java, Citrus, etc.) must implement these methods on their Node class since TreeHaver::Node delegates to them.
i[ type child_count child start_byte end_byte ].freeze
- NODE_OPTIONAL_METHODS =
Optional Node methods - should return nil if not supported
i[ parent next_sibling prev_sibling named? has_error? missing? text child_by_field_name start_point end_point ].freeze
- NODE_ALIASES =
Methods that have common aliases across backends
{ type: i[kind], named?: i[is_named? is_named], has_error?: i[has_error], missing?: i[is_missing? is_missing], next_sibling: i[next_named_sibling], prev_sibling: i[previous_sibling previous_named_sibling prev_named_sibling], }.freeze
Class Method Summary collapse
-
.validate(backend_module, strict: false) ⇒ Hash
Validate a backend module for API compliance.
-
.validate!(backend_module, strict: false) ⇒ Hash
Validate and raise on failure.
-
.validate_node_instance(node) ⇒ Hash
Validate a Node instance for API compliance.
Class Method Details
.validate(backend_module, strict: false) ⇒ Hash
Validate a backend module for API compliance
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/tree_haver/backend_api.rb', line 132 def validate(backend_module, strict: false) results = { valid: true, errors: [], warnings: [], capabilities: {}, } # Check module-level methods validate_module_methods(backend_module, results) # Check Language class if backend_module.const_defined?(:Language) validate_language(backend_module::Language, results) else results[:errors] << "Missing Language class" results[:valid] = false end # Check Parser class if backend_module.const_defined?(:Parser) validate_parser(backend_module::Parser, results) else results[:errors] << "Missing Parser class" results[:valid] = false end # Check Tree class if present (some backends return raw trees) if backend_module.const_defined?(:Tree) validate_tree(backend_module::Tree, results) else results[:warnings] << "No Tree class (backend returns raw trees)" end # Check Node class if present (wrapper backends) if backend_module.const_defined?(:Node) validate_node_class(backend_module::Node, results, strict: strict) else results[:warnings] << "No Node class (backend returns raw nodes, TreeHaver::Node will wrap)" end # Fail on warnings in strict mode if strict && results[:warnings].any? results[:valid] = false end results end |
.validate!(backend_module, strict: false) ⇒ Hash
Validate and raise on failure
187 188 189 190 191 192 193 194 195 196 |
# File 'lib/tree_haver/backend_api.rb', line 187 def validate!(backend_module, strict: false) results = validate(backend_module, strict: strict) unless results[:valid] raise TreeHaver::Error, "Backend #{backend_module.name} API validation failed:\n " \ "Errors: #{results[:errors].join(", ")}\n " \ "Warnings: #{results[:warnings].join(", ")}" end results end |
.validate_node_instance(node) ⇒ Hash
Validate a Node instance for API compliance
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 |
# File 'lib/tree_haver/backend_api.rb', line 202 def validate_node_instance(node) results = { valid: true, errors: [], warnings: [], supported_methods: [], unsupported_methods: [], } # Check required methods NODE_INSTANCE_METHODS.each do |method| if responds_to_with_aliases?(node, method) results[:supported_methods] << method else results[:errors] << "Missing required method: #{method}" results[:valid] = false end end # Check optional methods NODE_OPTIONAL_METHODS.each do |method| if responds_to_with_aliases?(node, method) results[:supported_methods] << method else results[:unsupported_methods] << method results[:warnings] << "Missing optional method: #{method}" end end results end |