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
-
.extended(base) ⇒ void
Initialize storage on a format-specific normalizer module.
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) ⇒ void
This method returns an undefined value.
Initialize storage on a format-specific normalizer module.
65 66 67 68 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 65 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.
174 175 176 177 178 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 174 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.
132 133 134 135 136 137 138 139 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 132 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.
193 194 195 196 197 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 193 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.
86 87 88 89 90 91 92 93 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 86 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.
184 185 186 187 188 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 184 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.
109 110 111 112 113 114 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 109 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.
164 165 166 167 168 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 164 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.
156 157 158 159 |
# File 'lib/ast/merge/node_typing/normalizer.rb', line 156 def wrap(node, backend) canonical = canonical_type(node.type, backend) Ast::Merge::NodeTyping.with_merge_type(node, canonical) end |