Module: Ast::Merge::NodeTyping::Normalizer
- Defined in:
- lib/ast/merge/node_typing/normalizer.rb
Overview
Thread-safe backend registration and type normalization for AST merge libraries.
Normalizer provides a shared, thread-safe mechanism for registering backend-specific
node type mappings and normalizing them to canonical types. This enables portable
merge rules across different parsers/backends for the same file format.
Thread Safety
All registration and lookup operations are protected by a mutex to ensure
thread-safe access to the backend mappings. This follows the same pattern
used in TreeHaver::LanguageRegistry and TreeHaver::PathValidator.
Usage Pattern
File-format-specific merge libraries (e.g., toml-merge, markdown-merge) should:
- Create their own NodeTypeNormalizer module
- Include or extend Ast::Merge::NodeTyping::Normalizer
- Define their canonical types and default backend mappings
- Call
configure_normalizerwith their initial mappings
Class Method Summary collapse
Instance Method Summary collapse
-
#backend_registered?(backend) ⇒ Boolean
Check if a backend is registered.
-
#canonical_type(backend_type, backend = nil) ⇒ Symbol?
Get the canonical type for a backend-specific type.
-
#canonical_types ⇒ Array<Symbol>
Get all canonical types across all backends.
-
#configure_normalizer(**mappings) ⇒ void
Configure the normalizer with initial backend mappings.
-
#mappings_for(backend) ⇒ Hash{Symbol => Symbol}?
Get the mappings for a specific backend.
-
#register_backend(backend, mappings) ⇒ void
Register type mappings for a new backend.
-
#registered_backends ⇒ Array<Symbol>
Get all registered backends.
-
#wrap(node, backend) ⇒ Ast::Merge::NodeTyping::Wrapper
Wrap a node with its canonical type as merge_type.
Class Method Details
.extended(base) ⇒ Object
61 62 63 64 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 61 def extended(base) base.instance_variable_set(:@normalizer_mutex, Mutex.new) base.instance_variable_set(:@backend_mappings, {}) end |
Instance Method Details
#backend_registered?(backend) ⇒ Boolean
Check if a backend is registered.
170 171 172 173 174 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 170 def backend_registered?(backend) @normalizer_mutex.synchronize do @backend_mappings.key?(backend.to_sym) end end |
#canonical_type(backend_type, backend = nil) ⇒ Symbol?
Get the canonical type for a backend-specific type.
If no mapping exists, returns the original type unchanged (passthrough).
This allows backend-specific types to pass through for backend-specific
merge rules.
128 129 130 131 132 133 134 135 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 128 def canonical_type(backend_type, backend = nil) return backend_type if backend_type.nil? type_sym = backend_type.to_sym @normalizer_mutex.synchronize do @backend_mappings.dig(backend, type_sym) || type_sym end end |
#canonical_types ⇒ Array<Symbol>
Get all canonical types across all backends.
189 190 191 192 193 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 189 def canonical_types @normalizer_mutex.synchronize do @backend_mappings.values.flat_map(&:values).uniq end end |
#configure_normalizer(**mappings) ⇒ void
This method returns an undefined value.
Configure the normalizer with initial backend mappings.
This should be called once when defining the format-specific normalizer,
providing the default backend mappings. Additional backends can be
registered later via register_backend.
82 83 84 85 86 87 88 89 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 82 def configure_normalizer(**mappings) @normalizer_mutex.synchronize do mappings.each do |backend, type_mappings| @backend_mappings[backend.to_sym] = type_mappings.frozen? ? type_mappings : type_mappings.freeze end end nil end |
#mappings_for(backend) ⇒ Hash{Symbol => Symbol}?
Get the mappings for a specific backend.
180 181 182 183 184 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 180 def mappings_for(backend) @normalizer_mutex.synchronize do @backend_mappings[backend.to_sym] end end |
#register_backend(backend, mappings) ⇒ void
This method returns an undefined value.
Register type mappings for a new backend.
This allows extending the normalizer to support additional parsers
beyond those configured initially. Thread-safe for runtime registration.
105 106 107 108 109 110 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 105 def register_backend(backend, mappings) @normalizer_mutex.synchronize do @backend_mappings[backend.to_sym] = mappings.frozen? ? mappings : mappings.freeze end nil end |
#registered_backends ⇒ Array<Symbol>
Get all registered backends.
160 161 162 163 164 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 160 def registered_backends @normalizer_mutex.synchronize do @backend_mappings.keys end end |
#wrap(node, backend) ⇒ Ast::Merge::NodeTyping::Wrapper
Wrap a node with its canonical type as merge_type.
Uses Ast::Merge::NodeTyping.with_merge_type to create a wrapper
that delegates all methods to the underlying node while adding
a canonical merge_type attribute.
152 153 154 155 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 152 def wrap(node, backend) canonical = canonical_type(node.type, backend) Ast::Merge::NodeTyping.with_merge_type(node, canonical) end |