Class: Rigor::Plugin::NodeRuleWalk
- Inherits:
-
Object
- Object
- Rigor::Plugin::NodeRuleWalk
- Defined in:
- lib/rigor/plugin/node_rule_walk.rb
Overview
ADR-52 WD4 — one engine-owned AST walk per file for node rules.
Before this, every plugin that declared a Base.node_rule walked the file’s AST itself (‘Base#node_rule_diagnostics` →`Source::NodeWalker.each_with_ancestors`), so a project with N node-rule plugins paid N walks per file. This folds them into a single walk that dispatches each visited node to every matching `(plugin, rule)` pair.
Behaviour is preserved exactly so the diagnostics stay byte-identical (the WD6 gate):
-
Each plugin’s ‘node_file_context` block runs once per file, before any of its rules fire, `instance_exec`’d on that plugin —same as the per-plugin walk.
-
One frozen NodeContext is built per node, lazily, only when at least one rule matches it. Because it wraps only the ancestors it is safe to share across plugins for the same node.
-
Each rule block is ‘instance_exec`’d on its own plugin instance with the same five arguments ‘(node, scope, path, file_context, context)`.
-
A plugin whose context block or any rule block raises has its whole node-rule contribution isolated — the walk records the error against that plugin and continues, matching the runner’s per-plugin rescue around the old ‘#node_rule_diagnostics` call.
-
Diagnostics are bucketed per plugin and returned in the registry order the runner already iterates, so emission order is unchanged (plugin-major, not node-major) — order preservation is what keeps the gate byte-identical in this slice.
The result is an ordered Array of Result, one per node-rule plugin (registry order). ‘Result#error` is non-nil iff that plugin’s context or a rule block raised, in which case ‘#diagnostics` is empty; the runner turns the error into the same per-plugin `runtime-error` envelope it produced before.
Defined Under Namespace
Classes: Result
Instance Method Summary collapse
-
#diagnostics_for_file(path:, scope:, root:) ⇒ Object
Walk ‘root` once, dispatching every node to each matching `(plugin, rule)`.
- #empty? ⇒ Boolean
-
#initialize(plugins) ⇒ NodeRuleWalk
constructor
Plugins that declare at least one ‘node_rule`, paired with their frozen rule list, in registry order.
Constructor Details
#initialize(plugins) ⇒ NodeRuleWalk
Plugins that declare at least one ‘node_rule`, paired with their frozen rule list, in registry order. Built once per run and reused for every file.
52 53 54 55 56 57 58 |
# File 'lib/rigor/plugin/node_rule_walk.rb', line 52 def initialize(plugins) @entries = plugins.filter_map do |plugin| rules = plugin.class.node_rules rules.empty? ? nil : [plugin, rules] end.freeze freeze end |
Instance Method Details
#diagnostics_for_file(path:, scope:, root:) ⇒ Object
Walk ‘root` once, dispatching every node to each matching `(plugin, rule)`. Returns an Array of Result in plugin (registry) order. `root` nil yields one empty Result per plugin.
67 68 69 70 71 72 73 |
# File 'lib/rigor/plugin/node_rule_walk.rb', line 67 def diagnostics_for_file(path:, scope:, root:) return @entries.map { |plugin, _| Result.new(plugin, [], nil) } if root.nil? states = @entries.map { |plugin, rules| State.new(plugin, rules, scope, root) } walk(path, scope, root, states) states.map(&:result) end |
#empty? ⇒ Boolean
60 61 62 |
# File 'lib/rigor/plugin/node_rule_walk.rb', line 60 def empty? @entries.empty? end |