node_mutation 1.22.4 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +9 -6
- data/lib/node_mutation/adapter/prism.rb +242 -0
- data/lib/node_mutation/adapter/syntax_tree.rb +15 -15
- data/lib/node_mutation/version.rb +1 -1
- data/lib/node_mutation.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 667309a875501329f61441ddc89143500b02d87e83be0a6aa324e78438cfd397
|
4
|
+
data.tar.gz: 565be945f6bbfd0976dafb86bb346be696665bd32a72227cf9a4a2d16e75fa45
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed08dbed41c4aa8dce675995a19736ce84877fc0334ab448c04019c7e413204ee2e0c6674ea2d779048962bccbf970990d0b72f89fb7bc17845cb0034b6400ce
|
7
|
+
data.tar.gz: 8488422fbcabd15c24c607c1a2b8229bf3a7be810a2d34f0568ceb79a82cc87ebdd06625ab0d76cf68099fd894a067267fc0dde257f5999aa48a8f0ef1c40346
|
data/CHANGELOG.md
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
node_mutation (1.
|
4
|
+
node_mutation (1.23.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
@@ -34,16 +34,19 @@ GEM
|
|
34
34
|
notiffany (0.1.3)
|
35
35
|
nenv (~> 0.1)
|
36
36
|
shellany (~> 0.0)
|
37
|
-
parser (3.
|
37
|
+
parser (3.3.0.5)
|
38
38
|
ast (~> 2.4.1)
|
39
39
|
racc
|
40
|
-
parser_node_ext (1.2.
|
40
|
+
parser_node_ext (1.2.2)
|
41
41
|
parser
|
42
42
|
prettier_print (1.2.1)
|
43
|
+
prism (0.22.0)
|
44
|
+
prism_ext (0.2.1)
|
45
|
+
prism
|
43
46
|
pry (0.14.1)
|
44
47
|
coderay (~> 1.1)
|
45
48
|
method_source (~> 1.0)
|
46
|
-
racc (1.7.
|
49
|
+
racc (1.7.3)
|
47
50
|
rake (13.0.6)
|
48
51
|
rb-fsevent (0.11.1)
|
49
52
|
rb-inotify (0.10.1)
|
@@ -62,7 +65,7 @@ GEM
|
|
62
65
|
rspec-support (~> 3.11.0)
|
63
66
|
rspec-support (3.11.0)
|
64
67
|
shellany (0.0.1)
|
65
|
-
syntax_tree (6.
|
68
|
+
syntax_tree (6.2.0)
|
66
69
|
prettier_print (>= 1.2.0)
|
67
70
|
syntax_tree_ext (0.6.3)
|
68
71
|
syntax_tree
|
@@ -78,8 +81,8 @@ DEPENDENCIES
|
|
78
81
|
guard
|
79
82
|
guard-rspec
|
80
83
|
node_mutation!
|
81
|
-
parser
|
82
84
|
parser_node_ext
|
85
|
+
prism_ext
|
83
86
|
rake (~> 13.0)
|
84
87
|
rspec (~> 3.0)
|
85
88
|
syntax_tree_ext
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'prism'
|
4
|
+
require 'prism_ext'
|
5
|
+
|
6
|
+
class NodeMutation::PrismAdapter < NodeMutation::Adapter
|
7
|
+
def get_source(node)
|
8
|
+
if node.is_a?(Array)
|
9
|
+
return node.first.source[node.first.location.start_offset...node.last.location.end_offset]
|
10
|
+
end
|
11
|
+
|
12
|
+
node.source[node.location.start_offset...node.location.end_offset]
|
13
|
+
end
|
14
|
+
|
15
|
+
# It gets the new source code after evaluating the node.
|
16
|
+
# @param node [Prism::Node] The node to evaluate.
|
17
|
+
# @param code [String] The code to evaluate.
|
18
|
+
# @return [String] The new source code.
|
19
|
+
# @example
|
20
|
+
# node = Prism.parse('class Synvert; end').value.statements.body.first
|
21
|
+
# rewritten_source(node, '{{constant}}') # 'Synvert'
|
22
|
+
#
|
23
|
+
# # index for node array
|
24
|
+
# node = Prism.parse("foo.bar(a, b)").value.statements.body.first
|
25
|
+
# rewritten_source(node, '{{arguments.arguments.parts.-1}}')) # 'b'
|
26
|
+
#
|
27
|
+
# # {key}_assoc for HashNode node
|
28
|
+
# node = Prism.parse("after_commit :do_index, on: :create, if: :indexable?").value.statements.body.first
|
29
|
+
# rewritten_source(node, '{{arguments.parts.-1.on_assoc}}')) # 'on: :create'
|
30
|
+
#
|
31
|
+
# # {key}_value for hash node
|
32
|
+
# node = Prism.parse("after_commit :do_index, on: :create, if: :indexable?").value.statements.body.first
|
33
|
+
# rewritten_source(node, '{{arguments.parts.-1.on_value}}')) # ':create'
|
34
|
+
#
|
35
|
+
# # to_single_quote for StringNode
|
36
|
+
# node = Prism.parse('"foo"').value.statements.body.first
|
37
|
+
# rewritten_source(node, 'to_single_quote') # "'foo'"
|
38
|
+
#
|
39
|
+
# # to_double_quote for StringNode
|
40
|
+
# node = Prism.parse("'foo'").value.statements.body.first
|
41
|
+
# rewritten_source(node, 'to_double_quote') # '"foo"'
|
42
|
+
#
|
43
|
+
# # to_symbol for StringNode
|
44
|
+
# node = Prism.parse("'foo'").value.statements.body.first
|
45
|
+
# rewritten_source(node, 'to_symbol') # ':foo'
|
46
|
+
#
|
47
|
+
# # to_string for SymbolNode
|
48
|
+
# node = Prism.parse(":foo").value.statements.body.first
|
49
|
+
# rewritten_source(node, 'to_string') # 'foo'
|
50
|
+
#
|
51
|
+
# # to_lambda_literal for CallNode with lambda
|
52
|
+
# node = Prism.parse('lambda { foobar }').value.statements.body.first
|
53
|
+
# rewritten_source(node, 'to_lambda_literal') # '-> { foobar }'
|
54
|
+
#
|
55
|
+
# # strip_curly_braces for HashNode
|
56
|
+
# node = Prism.parse("{ foo: 'bar' }").value.statements.body.first
|
57
|
+
# rewritten_source(node, 'strip_curly_braces') # "foo: 'bar'"
|
58
|
+
#
|
59
|
+
# # wrap_curly_braces for KeywordHashNode
|
60
|
+
# node = Prism.parse("test(foo: 'bar')").value.statements.body.first
|
61
|
+
# rewritten_source(node.arguments.arguments.parts.first, 'wrap_curly_braces') # "{ foo: 'bar' }"
|
62
|
+
def rewritten_source(node, code)
|
63
|
+
code.gsub(/{{(.+?)}}/m) do
|
64
|
+
old_code = Regexp.last_match(1)
|
65
|
+
evaluated = child_node_by_name(node, old_code)
|
66
|
+
case evaluated
|
67
|
+
when Prism::Node
|
68
|
+
get_source(evaluated)
|
69
|
+
when Array
|
70
|
+
if evaluated.size > 0
|
71
|
+
source = get_source(evaluated)
|
72
|
+
lines = source.split "\n"
|
73
|
+
lines_count = lines.length
|
74
|
+
if lines_count > 1 && lines_count == evaluated.size
|
75
|
+
new_code = []
|
76
|
+
lines.each_with_index { |line, index|
|
77
|
+
new_code << (index == 0 ? line : line[get_indent(evaluated.first) - NodeMutation.tab_width..-1])
|
78
|
+
}
|
79
|
+
new_code.join("\n")
|
80
|
+
else
|
81
|
+
source
|
82
|
+
end
|
83
|
+
end
|
84
|
+
when String, Symbol, Integer, Float
|
85
|
+
evaluated
|
86
|
+
when NilClass
|
87
|
+
''
|
88
|
+
else
|
89
|
+
raise "can not parse \"#{code}\""
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def file_source(node)
|
95
|
+
node.source
|
96
|
+
end
|
97
|
+
|
98
|
+
# Get the range of the child node.
|
99
|
+
# @param node [Parser::AST::Node] The node.
|
100
|
+
# @param child_name [String] THe name to find child node.
|
101
|
+
# @return {NodeMutation::Struct::Range} The range of the child node.
|
102
|
+
# @example
|
103
|
+
# node = Prism.parse('foo.bar(test)').value.statements.body.first
|
104
|
+
# child_node_range(node, 'receiver') # { start: 0, end: 'foo'.length }
|
105
|
+
#
|
106
|
+
# # node array
|
107
|
+
# node = Prism.parse('foo.bar(a, b)').value.statements.body.first
|
108
|
+
# child_node_range(node, 'arguments.arguments') # { start: 'foo.bar('.length, end: 'foo.bar(a, b'.length }
|
109
|
+
#
|
110
|
+
# # index for node array
|
111
|
+
# node = Prism.parse('foo.bar(a, b)').value.statements.body.first
|
112
|
+
# child_node_range(node, 'arguments.arguments.parts.-1') # { start: 'foo.bar(a, '.length, end: 'foo.bar(a, b'.length }
|
113
|
+
#
|
114
|
+
# # operator of Binary node
|
115
|
+
# node = Prism.parse('foo | bar').value.statements.body.first
|
116
|
+
# child_node_range(node, 'operator') # { start: 'foo '.length, end: 'foo |'.length }
|
117
|
+
def child_node_range(node, child_name)
|
118
|
+
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
119
|
+
|
120
|
+
if node.is_a?(Array)
|
121
|
+
if direct_child_name =~ INDEX_REGEXP
|
122
|
+
child_node = node[direct_child_name.to_i]
|
123
|
+
raise NodeMutation::MethodNotSupported,
|
124
|
+
"#{direct_child_name} is not supported for #{get_source(node)}" unless child_node
|
125
|
+
return child_node_range(child_node, nested_child_name) if nested_child_name
|
126
|
+
|
127
|
+
return NodeMutation::Struct::Range.new(child_node.location.start_offset, child_node.location.end_offset)
|
128
|
+
end
|
129
|
+
|
130
|
+
raise NodeMutation::MethodNotSupported,
|
131
|
+
"#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
|
132
|
+
|
133
|
+
child_node = node.send(direct_child_name)
|
134
|
+
return child_node_range(child_node, nested_child_name) if nested_child_name
|
135
|
+
|
136
|
+
return NodeMutation::Struct::Range.new(child_node.location.start_offset, child_node.location.end_offset)
|
137
|
+
end
|
138
|
+
|
139
|
+
if node.respond_to?("#{child_name}_loc")
|
140
|
+
node_loc = node.send("#{child_name}_loc")
|
141
|
+
if node_loc
|
142
|
+
NodeMutation::Struct::Range.new(node_loc.start_offset, node_loc.end_offset)
|
143
|
+
end
|
144
|
+
else
|
145
|
+
raise NodeMutation::MethodNotSupported,
|
146
|
+
"#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
|
147
|
+
|
148
|
+
child_node = node.send(direct_child_name)
|
149
|
+
|
150
|
+
return child_node_range(child_node, nested_child_name) if nested_child_name
|
151
|
+
|
152
|
+
return nil if child_node.nil?
|
153
|
+
|
154
|
+
if child_node.is_a?(Prism::Node)
|
155
|
+
return(
|
156
|
+
NodeMutation::Struct::Range.new(child_node.location.start_offset, child_node.location.end_offset)
|
157
|
+
)
|
158
|
+
end
|
159
|
+
|
160
|
+
return(
|
161
|
+
NodeMutation::Struct::Range.new(child_node.first.location.start_offset, child_node.last.location.end_offset)
|
162
|
+
)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
def get_start(node, child_name = nil)
|
167
|
+
node = child_node_by_name(node, child_name) if child_name
|
168
|
+
node.location.start_offset
|
169
|
+
end
|
170
|
+
|
171
|
+
def get_end(node, child_name = nil)
|
172
|
+
node = child_node_by_name(node, child_name) if child_name
|
173
|
+
node.location.end_offset
|
174
|
+
end
|
175
|
+
|
176
|
+
def get_start_loc(node, child_name = nil)
|
177
|
+
node = child_node_by_name(node, child_name) if child_name
|
178
|
+
NodeMutation::Struct::Location.new(node.location.start_line, node.location.start_column)
|
179
|
+
end
|
180
|
+
|
181
|
+
def get_end_loc(node, child_name = nil)
|
182
|
+
node = child_node_by_name(node, child_name) if child_name
|
183
|
+
NodeMutation::Struct::Location.new(node.location.end_line, node.location.end_column)
|
184
|
+
end
|
185
|
+
|
186
|
+
def get_indent(node)
|
187
|
+
node.location.start_column
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def child_node_by_name(node, child_name)
|
193
|
+
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
194
|
+
|
195
|
+
if node.is_a?(Array)
|
196
|
+
if direct_child_name =~ INDEX_REGEXP
|
197
|
+
child_node = node[direct_child_name.to_i]
|
198
|
+
raise NodeMutation::MethodNotSupported,
|
199
|
+
"#{direct_child_name} is not supported for #{get_source(node)}" unless child_node
|
200
|
+
return child_node_by_name(child_node, nested_child_name) if nested_child_name
|
201
|
+
|
202
|
+
return child_node
|
203
|
+
end
|
204
|
+
|
205
|
+
raise NodeMutation::MethodNotSupported,
|
206
|
+
"#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
|
207
|
+
|
208
|
+
child_node = node.send(direct_child_name)
|
209
|
+
return child_node_by_name(child_node, nested_child_name) if nested_child_name
|
210
|
+
|
211
|
+
return child_node
|
212
|
+
end
|
213
|
+
|
214
|
+
if node.respond_to?(direct_child_name)
|
215
|
+
child_node = node.send(direct_child_name)
|
216
|
+
elsif direct_child_name == 'to_symbol' && node.is_a?(Prism::StringNode)
|
217
|
+
child_node = ":#{node.to_value}"
|
218
|
+
elsif direct_child_name == 'to_string' && node.is_a?(Prism::SymbolNode)
|
219
|
+
child_node = node.to_value.to_s
|
220
|
+
elsif direct_child_name == 'to_single_quote' && node.is_a?(Prism::StringNode)
|
221
|
+
child_node = "'#{node.to_value}'"
|
222
|
+
elsif direct_child_name == 'to_double_quote' && node.is_a?(Prism::StringNode)
|
223
|
+
child_node = "\"#{node.to_value}\""
|
224
|
+
elsif direct_child_name == 'to_lambda_literal' && node.is_a?(Prism::CallNode) && node.name == :lambda
|
225
|
+
if node.block.parameters
|
226
|
+
child_node = "->(#{node.block.parameters.parameters.to_source}) { #{node.block.body.to_source} }"
|
227
|
+
else
|
228
|
+
child_node = "-> #{node.block.to_source}"
|
229
|
+
end
|
230
|
+
elsif direct_child_name == 'strip_curly_braces' && node.is_a?(Prism::HashNode)
|
231
|
+
child_node = node.to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip }
|
232
|
+
elsif direct_child_name == 'wrap_curly_braces' && node.is_a?(Prism::KeywordHashNode)
|
233
|
+
child_node = "{ #{node.to_source} }"
|
234
|
+
else
|
235
|
+
raise NodeMutation::MethodNotSupported, "#{direct_child_name} is not supported for #{get_source(node)}"
|
236
|
+
end
|
237
|
+
|
238
|
+
return child_node_by_name(child_node, nested_child_name) if nested_child_name
|
239
|
+
|
240
|
+
child_node
|
241
|
+
end
|
242
|
+
end
|
@@ -17,47 +17,47 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
|
|
17
17
|
# @param code [String] The code to evaluate.
|
18
18
|
# @return [String] The new source code.
|
19
19
|
# @example
|
20
|
-
# node = SyntaxTree
|
20
|
+
# node = SyntaxTree.parse('class Synvert; end').statements.body.first
|
21
21
|
# rewritten_source(node, '{{constant}}') # 'Synvert'
|
22
22
|
#
|
23
23
|
# # index for node array
|
24
|
-
# node = SyntaxTree
|
24
|
+
# node = SyntaxTree.parse("foo.bar(a, b)").statements.body.first
|
25
25
|
# rewritten_source(node, '{{arguments.arguments.parts.-1}}')) # 'b'
|
26
26
|
#
|
27
27
|
# # {key}_assoc for HashLiteral node
|
28
|
-
# node = SyntaxTree
|
28
|
+
# node = SyntaxTree.parse("after_commit :do_index, on: :create, if: :indexable?").statements.body.first
|
29
29
|
# rewritten_source(node, '{{arguments.parts.-1.on_assoc}}')) # 'on: :create'
|
30
30
|
#
|
31
31
|
# # {key}_value for hash node
|
32
|
-
# node = SyntaxTree
|
32
|
+
# node = SyntaxTree.parse("after_commit :do_index, on: :create, if: :indexable?").statements.body.first
|
33
33
|
# rewritten_source(node, '{{arguments.parts.-1.on_value}}')) # ':create'
|
34
34
|
#
|
35
35
|
# # to_single_quote for StringLiteral node
|
36
|
-
# node = SyntaxTree
|
36
|
+
# node = SyntaxTree.parse('"foo"').statements.body.first
|
37
37
|
# rewritten_source(node, 'to_single_quote') # "'foo'"
|
38
38
|
#
|
39
39
|
# # to_double_quote for StringLiteral node
|
40
|
-
# node = SyntaxTree
|
40
|
+
# node = SyntaxTree.parse("'foo'").statements.body.first
|
41
41
|
# rewritten_source(node, 'to_double_quote') # '"foo"'
|
42
42
|
#
|
43
43
|
# # to_symbol for StringLiteral node
|
44
|
-
# node = SyntaxTree
|
44
|
+
# node = SyntaxTree.parse("'foo'").statements.body.first
|
45
45
|
# rewritten_source(node, 'to_symbol') # ':foo'
|
46
46
|
#
|
47
47
|
# # to_string for SymbolLiteral node
|
48
|
-
# node = SyntaxTree
|
48
|
+
# node = SyntaxTree.parse(":foo").statements.body.first
|
49
49
|
# rewritten_source(node, 'to_string') # 'foo'
|
50
50
|
#
|
51
51
|
# # to_lambda_literal for MethodAddBlock node
|
52
|
-
# node = SyntaxTree
|
52
|
+
# node = SyntaxTree.parse('lambda { foobar }').statements.body.first
|
53
53
|
# rewritten_source(node, 'to_lambda_literal') # '-> { foobar }'
|
54
54
|
#
|
55
55
|
# # strip_curly_braces for HashLiteral node
|
56
|
-
# node = SyntaxTree
|
56
|
+
# node = SyntaxTree.parse("{ foo: 'bar' }").statements.body.first
|
57
57
|
# rewritten_source(node, 'strip_curly_braces') # "foo: 'bar'"
|
58
58
|
#
|
59
59
|
# # wrap_curly_braces for BareAssocHash node
|
60
|
-
# node = SyntaxTree
|
60
|
+
# node = SyntaxTree.parse("test(foo: 'bar')").statements.body.first
|
61
61
|
# rewritten_source(node.arguments.arguments.parts.first, 'wrap_curly_braces') # "{ foo: 'bar' }"
|
62
62
|
def rewritten_source(node, code)
|
63
63
|
code.gsub(/{{(.+?)}}/m) do
|
@@ -100,19 +100,19 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
|
|
100
100
|
# @param child_name [String] THe name to find child node.
|
101
101
|
# @return {NodeMutation::Struct::Range} The range of the child node.
|
102
102
|
# @example
|
103
|
-
# node = SyntaxTree
|
103
|
+
# node = SyntaxTree.parse('foo.bar(test)').statements.body.first
|
104
104
|
# child_node_range(node, 'receiver') # { start: 0, end: 'foo'.length }
|
105
105
|
#
|
106
106
|
# # node array
|
107
|
-
# node = SyntaxTree
|
107
|
+
# node = SyntaxTree.parse('foo.bar(a, b)').statements.body.first
|
108
108
|
# child_node_range(node, 'arguments.arguments') # { start: 'foo.bar('.length, end: 'foo.bar(a, b'.length }
|
109
109
|
#
|
110
110
|
# # index for node array
|
111
|
-
# node = SyntaxTree
|
111
|
+
# node = SyntaxTree.parse('foo.bar(a, b)').statements.body.first
|
112
112
|
# child_node_range(node, 'arguments.arguments.parts.-1') # { start: 'foo.bar(a, '.length, end: 'foo.bar(a, b'.length }
|
113
113
|
#
|
114
114
|
# # operator of Binary node
|
115
|
-
# node = SyntaxTree
|
115
|
+
# node = SyntaxTree.parse('foo | bar').statements.body.first
|
116
116
|
# child_node_range(node, 'operator') # { start: 'foo '.length, end: 'foo |'.length }
|
117
117
|
def child_node_range(node, child_name)
|
118
118
|
direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
|
data/lib/node_mutation.rb
CHANGED
@@ -9,6 +9,7 @@ class NodeMutation
|
|
9
9
|
|
10
10
|
autoload :Adapter, "node_mutation/adapter"
|
11
11
|
autoload :ParserAdapter, "node_mutation/adapter/parser"
|
12
|
+
autoload :PrismAdapter, "node_mutation/adapter/prism"
|
12
13
|
autoload :SyntaxTreeAdapter, "node_mutation/adapter/syntax_tree"
|
13
14
|
autoload :Action, 'node_mutation/action'
|
14
15
|
autoload :AppendAction, 'node_mutation/action/append_action'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: node_mutation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.23.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Richard Huang
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-02-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: ast node mutation apis
|
14
14
|
email:
|
@@ -39,6 +39,7 @@ files:
|
|
39
39
|
- lib/node_mutation/action/replace_with_action.rb
|
40
40
|
- lib/node_mutation/adapter.rb
|
41
41
|
- lib/node_mutation/adapter/parser.rb
|
42
|
+
- lib/node_mutation/adapter/prism.rb
|
42
43
|
- lib/node_mutation/adapter/syntax_tree.rb
|
43
44
|
- lib/node_mutation/helper.rb
|
44
45
|
- lib/node_mutation/result.rb
|