Class: Oxc::MutationVisitor
- Defined in:
- lib/oxc/mutation_visitor.rb,
sig/oxc/mutation_visitor.rbs
Overview
A visitor that rewrites the source it walked, by recording what to do to a node and splicing the original text at the end. Everything nothing touched survives byte for byte.
class Renamer < Oxc::MutationVisitor
def visit_identifier(node)
replace(node, "renamed") if node["name"] == "count"
end
end
Renamer.new.rewrite("let count = 1") #=> "let renamed = 1"
Defined Under Namespace
Classes: Edit, Invalid, Overlap
Instance Attribute Summary collapse
- #parsed ⇒ Oxc::ParseResult readonly
- #source ⇒ String readonly
Instance Method Summary collapse
-
#apply ⇒ String
: () -> String.
-
#edit(start, finish, text) ⇒ void
: (Integer, Integer, String) -> void.
-
#insert_after(node, text) ⇒ void
: (Oxc::Node, String) -> void.
-
#insert_before(node, text) ⇒ void
: (Oxc::Node, String) -> void.
-
#overlaps?(existing, start, finish) ⇒ Boolean
: (Edit, Integer, Integer) -> bool.
-
#remove(node) ⇒ void
: (Oxc::Node) -> void.
-
#replace(node, text) ⇒ void
: (Oxc::Node, String) -> void.
-
#replaced?(node) ⇒ Boolean
: (Oxc::Node) -> bool.
-
#rewrite(source, verify: true, **options) ⇒ String
: (String, ?verify: bool, **untyped) -> String.
-
#verified(rewritten, options) ⇒ String
: (String, Hash[Symbol, untyped]) -> String.
-
#visit_children(node) ⇒ void
: (Oxc::Node) -> void.
-
#wrap(node, before, after) ⇒ void
: (Oxc::Node, String, String) -> void.
Methods inherited from Visitor
Instance Attribute Details
#parsed ⇒ Oxc::ParseResult (readonly)
27 28 29 |
# File 'lib/oxc/mutation_visitor.rb', line 27 def parsed @parsed end |
#source ⇒ String (readonly)
26 27 28 |
# File 'lib/oxc/mutation_visitor.rb', line 26 def source @source end |
Instance Method Details
#apply ⇒ String
: () -> String
115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/oxc/mutation_visitor.rb', line 115 def apply taken = 0 result = +"" @edits.sort_by { |edit| [edit.start, edit.order] }.each do |edit| result << source.byteslice(taken, edit.start - taken).to_s << edit.text taken = edit.finish end result << source.byteslice(taken..).to_s end |
#edit(start, finish, text) ⇒ void
This method returns an undefined value.
: (Integer, Integer, String) -> void
95 96 97 98 99 100 101 102 103 104 105 |
# File 'lib/oxc/mutation_visitor.rb', line 95 def edit(start, finish, text) @edits.each do |existing| next unless overlaps?(existing, start, finish) raise Overlap, "an edit at #{start}..#{finish} overlaps one at #{existing.start}..#{existing.finish}" end @edits << Edit.new(start: start, finish: finish, text: text, order: @edits.length) nil end |
#insert_after(node, text) ⇒ void
This method returns an undefined value.
: (Oxc::Node, String) -> void
61 62 63 |
# File 'lib/oxc/mutation_visitor.rb', line 61 def insert_after(node, text) edit(node.finish, node.finish, text) end |
#insert_before(node, text) ⇒ void
This method returns an undefined value.
: (Oxc::Node, String) -> void
56 57 58 |
# File 'lib/oxc/mutation_visitor.rb', line 56 def insert_before(node, text) edit(node.start, node.start, text) end |
#overlaps?(existing, start, finish) ⇒ Boolean
: (Edit, Integer, Integer) -> bool
108 109 110 111 112 |
# File 'lib/oxc/mutation_visitor.rb', line 108 def overlaps?(existing, start, finish) return false if existing.start == existing.finish && start == finish start < existing.finish && existing.start < finish end |
#remove(node) ⇒ void
This method returns an undefined value.
: (Oxc::Node) -> void
51 52 53 |
# File 'lib/oxc/mutation_visitor.rb', line 51 def remove(node) replace(node, "") end |
#replace(node, text) ⇒ void
This method returns an undefined value.
: (Oxc::Node, String) -> void
44 45 46 47 48 |
# File 'lib/oxc/mutation_visitor.rb', line 44 def replace(node, text) @replaced << [node.start, node.finish] edit(node.start, node.finish, text) end |
#replaced?(node) ⇒ Boolean
: (Oxc::Node) -> bool
90 91 92 |
# File 'lib/oxc/mutation_visitor.rb', line 90 def replaced?(node) @replaced.any? { |start, finish| node.start >= start && node.finish <= finish } end |
#rewrite(source, verify: true, **options) ⇒ String
: (String, ?verify: bool, **untyped) -> String
30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/oxc/mutation_visitor.rb', line 30 def rewrite(source, verify: true, **) @source = source @edits = [] #: Array[Edit] @replaced = [] #: Array[[Integer, Integer]] @parsed = Oxc.parse(source, **).validate! visit(parsed) rewritten = apply verify ? verified(rewritten, ) : rewritten end |
#verified(rewritten, options) ⇒ String
: (String, Hash[Symbol, untyped]) -> String
81 82 83 84 85 86 87 |
# File 'lib/oxc/mutation_visitor.rb', line 81 def verified(rewritten, ) answer = Oxc.parse(rewritten, **, ast: false) return rewritten unless answer.errors? raise Invalid, "what was rewritten no longer reads as JavaScript: #{answer.errors.first&.}" end |
#visit_children(node) ⇒ void
This method returns an undefined value.
: (Oxc::Node) -> void
72 73 74 75 76 |
# File 'lib/oxc/mutation_visitor.rb', line 72 def visit_children(node) return nil if replaced?(node) super end |
#wrap(node, before, after) ⇒ void
This method returns an undefined value.
: (Oxc::Node, String, String) -> void
66 67 68 69 |
# File 'lib/oxc/mutation_visitor.rb', line 66 def wrap(node, before, after) insert_before(node, before) insert_after(node, after) end |