node_mutation 1.10.1 → 1.11.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 +5 -0
- data/Gemfile.lock +1 -1
- data/lib/node_mutation/action/delete_action.rb +1 -1
- data/lib/node_mutation/action/insert_action.rb +8 -2
- data/lib/node_mutation/action/remove_action.rb +46 -16
- data/lib/node_mutation/action.rb +29 -24
- data/lib/node_mutation/parser_adapter.rb +3 -1
- data/lib/node_mutation/version.rb +1 -1
- data/lib/node_mutation.rb +9 -10
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d41515d4be39619d95802e531496159773a1202de61c8fa3c3d269d2a72926da
|
4
|
+
data.tar.gz: 2bd0415eec90cb45cdc2dcfacce1cf6529fcdf9f12e6fcd44054aa273e4c4b0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 656c00012eac7a7b6d2229933fb7e08fd7f0f9a986e90f7db69cc5129097702a2850cdf5494c6f1dae3d6f7da9d0ba642ffd7eb4362517a5c0f465a0d49a52d3
|
7
|
+
data.tar.gz: 4faced52fd71462a10c54970afb4412858c355c96bf8713e132f886535d3a1309aa792bc1f4e946c0549492c351c9750fa3ab1d05c3ecd0fda0d58f84c98427f
|
data/CHANGELOG.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -26,7 +26,7 @@ class NodeMutation::DeleteAction < NodeMutation::Action
|
|
26
26
|
.compact.map(&:start).min
|
27
27
|
@end = @selectors.map { |selector| NodeMutation.adapter.child_node_range(@node, selector) }
|
28
28
|
.compact.map(&:end).max
|
29
|
-
squeeze_spaces
|
30
29
|
remove_comma if @and_comma
|
30
|
+
remove_whitespace
|
31
31
|
end
|
32
32
|
end
|
@@ -8,17 +8,23 @@ class NodeMutation::InsertAction < NodeMutation::Action
|
|
8
8
|
# @param code [String] to be inserted
|
9
9
|
# @param at [String] position to insert, beginning or end
|
10
10
|
# @param to [<nil|String>] name of child node
|
11
|
-
|
11
|
+
# @param and_comma [Boolean] insert extra comma.
|
12
|
+
def initialize(node, code, at: 'end', to: nil, and_comma: false)
|
12
13
|
super(node, code)
|
13
14
|
@at = at
|
14
15
|
@to = to
|
16
|
+
@and_comma = and_comma
|
15
17
|
end
|
16
18
|
|
17
19
|
# The rewritten source code.
|
18
20
|
#
|
19
21
|
# @return [String] rewritten code.
|
20
22
|
def new_code
|
21
|
-
|
23
|
+
if @and_comma
|
24
|
+
@at == 'end' ? ", #{rewritten_source}" : "#{rewritten_source}, "
|
25
|
+
else
|
26
|
+
rewritten_source
|
27
|
+
end
|
22
28
|
end
|
23
29
|
|
24
30
|
private
|
@@ -21,15 +21,13 @@ class NodeMutation::RemoveAction < NodeMutation::Action
|
|
21
21
|
|
22
22
|
# Calculate the begin the end positions.
|
23
23
|
def calculate_position
|
24
|
+
@start = NodeMutation.adapter.get_start(@node)
|
25
|
+
@end = NodeMutation.adapter.get_end(@node)
|
26
|
+
remove_comma if @and_comma
|
27
|
+
remove_whitespace
|
24
28
|
if take_whole_line?
|
25
|
-
|
26
|
-
@end = end_index
|
29
|
+
remove_newline
|
27
30
|
squeeze_lines
|
28
|
-
else
|
29
|
-
@start = NodeMutation.adapter.get_start(@node)
|
30
|
-
@end = NodeMutation.adapter.get_end(@node)
|
31
|
-
squeeze_spaces
|
32
|
-
remove_comma if @and_command
|
33
31
|
end
|
34
32
|
end
|
35
33
|
|
@@ -37,18 +35,50 @@ class NodeMutation::RemoveAction < NodeMutation::Action
|
|
37
35
|
#
|
38
36
|
# @return [Boolean]
|
39
37
|
def take_whole_line?
|
40
|
-
NodeMutation.adapter.get_source(@node) == file_source[
|
38
|
+
NodeMutation.adapter.get_source(@node) == file_source[@start...@end].strip.chomp(',')
|
41
39
|
end
|
42
40
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
41
|
+
def remove_newline
|
42
|
+
leading_count = 1
|
43
|
+
loop do
|
44
|
+
if file_source[@start - leading_count] == "\n"
|
45
|
+
break
|
46
|
+
elsif ["\t", ' '].include?(file_source[@start - leading_count])
|
47
|
+
leading_count += 1
|
48
|
+
else
|
49
|
+
break
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
trailing_count = 0
|
54
|
+
loop do
|
55
|
+
if file_source[@end + trailing_count] == "\n"
|
56
|
+
break
|
57
|
+
elsif ["\t", ' '].include?(file_source[@end + trailing_count])
|
58
|
+
trailing_count += 1
|
59
|
+
else
|
60
|
+
break
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
if file_source[@end + trailing_count] == "\n"
|
65
|
+
@end += trailing_count + 1
|
66
|
+
end
|
67
|
+
|
68
|
+
if file_source[@start - leading_count] == "\n"
|
69
|
+
@start -= leading_count - 1
|
70
|
+
end
|
47
71
|
end
|
48
72
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
73
|
+
def squeeze_lines
|
74
|
+
lines = file_source.split("\n")
|
75
|
+
begin_line = NodeMutation.adapter.get_start_loc(@node).line
|
76
|
+
end_line = NodeMutation.adapter.get_end_loc(@node).line
|
77
|
+
before_line_is_blank = begin_line == 1 || lines[begin_line - 2] == ''
|
78
|
+
after_line_is_blank = lines[end_line] == ''
|
79
|
+
|
80
|
+
if lines.length > 1 && before_line_is_blank && after_line_is_blank
|
81
|
+
@end += "\n".length
|
82
|
+
end
|
53
83
|
end
|
54
84
|
end
|
data/lib/node_mutation/action.rb
CHANGED
@@ -53,23 +53,14 @@ class NodeMutation::Action
|
|
53
53
|
@rewritten_source ||= NodeMutation.adapter.rewritten_source(@node, @code)
|
54
54
|
end
|
55
55
|
|
56
|
-
#
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
end
|
62
|
-
|
63
|
-
# Squeeze empty lines from source code.
|
64
|
-
def squeeze_lines
|
65
|
-
lines = file_source.split("\n")
|
66
|
-
begin_line = NodeMutation.adapter.get_start_loc(@node).line
|
67
|
-
end_line = NodeMutation.adapter.get_end_loc(@node).line
|
68
|
-
before_line_is_blank = begin_line == 1 || lines[begin_line - 2] == ''
|
69
|
-
after_line_is_blank = lines[end_line] == ''
|
56
|
+
# remove unused whitespace.
|
57
|
+
# e.g. `foobar(foo, bar)`, if we remove `foo`, the whitespace should also be removed,
|
58
|
+
# the code should be changed to `foobar(bar)`.
|
59
|
+
def remove_whitespace
|
60
|
+
return unless [' ', '('].include?(file_source[@start - 1])
|
70
61
|
|
71
|
-
|
72
|
-
@end +=
|
62
|
+
while file_source[@end] == ' '
|
63
|
+
@end += 1
|
73
64
|
end
|
74
65
|
end
|
75
66
|
|
@@ -77,14 +68,28 @@ class NodeMutation::Action
|
|
77
68
|
# e.g. `foobar(foo, bar)`, if we remove `foo`, the comma should also be removed,
|
78
69
|
# the code should be changed to `foobar(bar)`.
|
79
70
|
def remove_comma
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
@
|
86
|
-
|
87
|
-
|
71
|
+
leading_count = 1
|
72
|
+
loop do
|
73
|
+
if file_source[@start - leading_count] == ','
|
74
|
+
@start -= leading_count
|
75
|
+
return
|
76
|
+
elsif ["\n", "\r", "\t", ' '].include?(file_source[@start - leading_count])
|
77
|
+
leading_count += 1
|
78
|
+
else
|
79
|
+
break
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
trailing_count = 0
|
84
|
+
loop do
|
85
|
+
if file_source[@end + trailing_count] == ','
|
86
|
+
@end += trailing_count + 1
|
87
|
+
return
|
88
|
+
elsif file_source[@end + trailing_count] == ' '
|
89
|
+
trailing_count += 1
|
90
|
+
else
|
91
|
+
break
|
92
|
+
end
|
88
93
|
end
|
89
94
|
end
|
90
95
|
|
@@ -5,6 +5,8 @@ INDEX_REGEXP = /\A-?\d+\z/
|
|
5
5
|
class NodeMutation::ParserAdapter < NodeMutation::Adapter
|
6
6
|
def get_source(node)
|
7
7
|
if node.is_a?(Array)
|
8
|
+
return "" if node.empty?
|
9
|
+
|
8
10
|
source = file_content(node.first)
|
9
11
|
source[node.first.loc.expression.begin_pos...node.last.loc.expression.end_pos]
|
10
12
|
else
|
@@ -179,7 +181,7 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
|
|
179
181
|
if node.respond_to?(direct_child_name)
|
180
182
|
child_node = node.send(direct_child_name)
|
181
183
|
elsif direct_child_name.include?('(') && direct_child_name.include?(')')
|
182
|
-
child_node =
|
184
|
+
child_node = node.instance_eval(direct_child_name)
|
183
185
|
else
|
184
186
|
raise NodeMutation::MethodNotSupported, "#{direct_child_name} is not supported for #{get_source(node)}"
|
185
187
|
end
|
data/lib/node_mutation.rb
CHANGED
@@ -92,8 +92,7 @@ class NodeMutation
|
|
92
92
|
# Delete source code of the child ast node.
|
93
93
|
# @param node [Node] ast node
|
94
94
|
# @param selectors [Array<Symbol>] selector names of child node.
|
95
|
-
# @param
|
96
|
-
# @option and_comma [Boolean] delete extra comma.
|
95
|
+
# @param and_comma [Boolean] delete extra comma.
|
97
96
|
# @example
|
98
97
|
# source code of the ast node is
|
99
98
|
# FactoryBot.create(...)
|
@@ -101,8 +100,8 @@ class NodeMutation
|
|
101
100
|
# mutation.delete(node, :receiver, :dot)
|
102
101
|
# the source code will be rewritten to
|
103
102
|
# create(...)
|
104
|
-
def delete(node, *selectors,
|
105
|
-
@actions << DeleteAction.new(node, *selectors,
|
103
|
+
def delete(node, *selectors, and_comma: false)
|
104
|
+
@actions << DeleteAction.new(node, *selectors, and_comma: and_comma).process
|
106
105
|
end
|
107
106
|
|
108
107
|
# Insert code to the ast node.
|
@@ -110,6 +109,7 @@ class NodeMutation
|
|
110
109
|
# @param code [String] code need to be inserted.
|
111
110
|
# @param at [String] insert position, beginning or end
|
112
111
|
# @param to [String] where to insert, if it is nil, will insert to current node.
|
112
|
+
# @param and_comma [Boolean] insert extra comma.
|
113
113
|
# @example
|
114
114
|
# source code of the ast node is
|
115
115
|
# open('http://test.com')
|
@@ -117,8 +117,8 @@ class NodeMutation
|
|
117
117
|
# mutation.insert(node, 'URI.', at: 'beginning')
|
118
118
|
# the source code will be rewritten to
|
119
119
|
# URI.open('http://test.com')
|
120
|
-
def insert(node, code, at: 'end', to: nil)
|
121
|
-
@actions << InsertAction.new(node, code, at: at, to: to).process
|
120
|
+
def insert(node, code, at: 'end', to: nil, and_comma: false)
|
121
|
+
@actions << InsertAction.new(node, code, at: at, to: to, and_comma: and_comma).process
|
122
122
|
end
|
123
123
|
|
124
124
|
# Prepend code to the ast node.
|
@@ -142,16 +142,15 @@ class NodeMutation
|
|
142
142
|
|
143
143
|
# Remove source code of the ast node.
|
144
144
|
# @param node [Node] ast node
|
145
|
-
# @param
|
146
|
-
# @option and_comma [Boolean] delete extra comma.
|
145
|
+
# @param and_comma [Boolean] delete extra comma.
|
147
146
|
# @example
|
148
147
|
# source code of the ast node is
|
149
148
|
# puts "test"
|
150
149
|
# then we call
|
151
150
|
# mutation.remove(node)
|
152
151
|
# the source code will be removed
|
153
|
-
def remove(node,
|
154
|
-
@actions << RemoveAction.new(node,
|
152
|
+
def remove(node, and_comma: false)
|
153
|
+
@actions << RemoveAction.new(node, and_comma: and_comma).process
|
155
154
|
end
|
156
155
|
|
157
156
|
# Replace child node of the ast node with new code.
|
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.11.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: 2023-03-
|
11
|
+
date: 2023-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: erubis
|