node_mutation 1.19.2 → 1.19.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ec537b5f02531d1a6134c09db1be0d0845226a231da01cbda1e9331103a04fb3
4
- data.tar.gz: f5cf6c624b25b08de8ea2f82c46401a3ce530c58720fa47cac11f04445c11894
3
+ metadata.gz: 9058cbdb6c979c921d77499277354922b7488da6315b85b368c8f0c14b7bf27e
4
+ data.tar.gz: 9f64d3bdb87aa025cf6362127a1170a014f28ec2ec7e04d88756bcd50744429e
5
5
  SHA512:
6
- metadata.gz: 7d491e39ed40c9392c0bd4b1ca47cb2d6078756526b85d2ff5a01b9b5c7ec4cf452fe14c502a1066c878a00d532d88152d026e367b67b8c2de6904577e0c3ef0
7
- data.tar.gz: d0946badaef12e2bc7701df604d7186174f72cc74d7dc797e38a82f20e05cfd6c07ea6d677c818bc16db583b735f4ae5652c799b7df2d664463977bd524d7b71
6
+ metadata.gz: c3d8f491d11179cd203167ef7a76b87ea16fdfb0f2454afeb0600d4fb97147a9e237d2f1b86f8432643971b4a00016b1d143813572c49eba0e1d58b58f7c6f81
7
+ data.tar.gz: e1c15e3f180186f28486cc14f3d4ebd0ee132c22d9128058e709d545b2c7bb7dae13529c7b74163427e3bfc3f0bb80eb3b73e74b34e4847ae3c0d0dd955d40e1
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # NodeMutation
2
2
 
3
+ ## 1.19.4 (2023-08-17)
4
+
5
+ * Use `NodeMutation.adapter.get_indent`
6
+
7
+ ## 1.19.3 (2023-07-01)
8
+
9
+ * Rewrite `SyntaxTreeAdapter#child_node_range` to support Binary operator
10
+
3
11
  ## 1.19.2 (2023-06-30)
4
12
 
5
13
  * Support `operator` of `Binary` node in `child_node_range`
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- node_mutation (1.19.2)
4
+ node_mutation (1.19.4)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -34,14 +34,16 @@ GEM
34
34
  notiffany (0.1.3)
35
35
  nenv (~> 0.1)
36
36
  shellany (~> 0.0)
37
- parser (3.2.2.1)
37
+ parser (3.2.2.3)
38
38
  ast (~> 2.4.1)
39
- parser_node_ext (1.1.0)
39
+ racc
40
+ parser_node_ext (1.2.0)
40
41
  parser
41
42
  prettier_print (1.2.1)
42
43
  pry (0.14.1)
43
44
  coderay (~> 1.1)
44
45
  method_source (~> 1.0)
46
+ racc (1.7.1)
45
47
  rake (13.0.6)
46
48
  rb-fsevent (0.11.1)
47
49
  rb-inotify (0.10.1)
@@ -62,7 +64,7 @@ GEM
62
64
  shellany (0.0.1)
63
65
  syntax_tree (6.1.1)
64
66
  prettier_print (>= 1.2.0)
65
- syntax_tree_ext (0.6.1)
67
+ syntax_tree_ext (0.6.3)
66
68
  syntax_tree
67
69
  thor (1.2.1)
68
70
 
@@ -15,53 +15,53 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
15
15
  end
16
16
  end
17
17
 
18
- # It gets the new source code after evaluating the node.
18
+ # Gets the new source code after evaluating the node.
19
19
  # @param node [Parser::AST::Node] The node to evaluate.
20
20
  # @param code [String] The code to evaluate.
21
21
  # @return [String] The new source code.
22
22
  # @example
23
23
  # node = Parser::CurrentRuby.parse('Factory.define :user do; end')
24
- # rewritten_source(node, '{{call.receiver}}').to eq 'Factory'
24
+ # rewritten_source(node, '{{call.receiver}}') # 'Factory'
25
25
  #
26
26
  # # index for node array
27
27
  # node = Parser::CurrentRuby.parse("test(foo, bar)")
28
- # rewritten_source(node, '{{arguments.0}}')).to eq 'foo'
28
+ # rewritten_source(node, '{{arguments.0}}')) # 'foo'
29
29
  #
30
30
  # # {key}_pair for hash node
31
31
  # node = Parser::CurrentRuby.parse("after_commit :do_index, on: :create, if: :indexable?")
32
- # rewritten_source(node, '{{arguments.-1.on_pair}}')).to eq 'on: :create'
32
+ # rewritten_source(node, '{{arguments.-1.on_pair}}')) # 'on: :create'
33
33
  #
34
34
  # # {key}_value for hash node
35
35
  # node = Parser::CurrentRuby.parse("after_commit :do_index, on: :create, if: :indexable?")
36
- # rewritten_source(node, '{{arguments.-1.on_value}}')).to eq ':create'
36
+ # rewritten_source(node, '{{arguments.-1.on_value}}')) # ':create'
37
37
  #
38
38
  # # to_single_quote for str node
39
39
  # node = Parser::CurrentRuby.parse('"foo"')
40
- # rewritten_source(node, 'to_single_quote') => "'foo'"
40
+ # rewritten_source(node, 'to_single_quote') # "'foo'"
41
41
  #
42
42
  # # to_double_quote for str node
43
43
  # node = Parser::CurrentRuby.parse("'foo'")
44
- # rewritten_source(node, 'to_double_quote') => '"foo"'
44
+ # rewritten_source(node, 'to_double_quote') # '"foo"'
45
45
  #
46
46
  # # to_symbol for str node
47
47
  # node = Parser::CurrentRuby.parse("'foo'")
48
- # rewritten_source(node, 'to_symbol') => ':foo'
48
+ # rewritten_source(node, 'to_symbol') # ':foo'
49
49
  #
50
50
  # # to_string for sym node
51
51
  # node = Parser::CurrentRuby.parse(":foo")
52
- # rewritten_source(node, 'to_string') => 'foo'
52
+ # rewritten_source(node, 'to_string') # 'foo'
53
53
  #
54
54
  # # to_lambda_literal for block node
55
55
  # node = Parser::CurrentRuby.parse('lambda { foobar }')
56
- # rewritten_source(node, 'to_lambda_literal') => '-> { foobar }'
56
+ # rewritten_source(node, 'to_lambda_literal') # '-> { foobar }'
57
57
  #
58
58
  # # strip_curly_braces for hash node
59
59
  # node = Parser::CurrentRuby.parse("{ foo: 'bar' }")
60
- # rewritten_source(node, 'strip_curly_braces') => "foo: 'bar'"
60
+ # rewritten_source(node, 'strip_curly_braces') # "foo: 'bar'"
61
61
  #
62
62
  # # wrap_curly_braces for hash node
63
63
  # node = Parser::CurrentRuby.parse("test(foo: 'bar')")
64
- # rewritten_source(node.arguments.first, 'wrap_curly_braces') => "{ foo: 'bar' }"
64
+ # rewritten_source(node.arguments.first, 'wrap_curly_braces') # "{ foo: 'bar' }"
65
65
  def rewritten_source(node, code)
66
66
  code.gsub(/{{(.+?)}}/m) do
67
67
  old_code = Regexp.last_match(1)
@@ -82,7 +82,7 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
82
82
  if lines_count > 1 && lines_count == evaluated.size
83
83
  new_code = []
84
84
  lines.each_with_index { |line, index|
85
- new_code << (index == 0 ? line : line[evaluated.first.indent - 2..-1])
85
+ new_code << (index == 0 ? line : line[NodeMutation.adapter.get_indent(evaluated.first) - NodeMutation.tab_width..-1])
86
86
  }
87
87
  new_code.join("\n")
88
88
  else
@@ -109,40 +109,40 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
109
109
  # @return {NodeMutation::Struct::Range} The range of the child node.
110
110
  # @example
111
111
  # node = Parser::CurrentRuby.parse('Factory.define :user do; end')
112
- # child_node_range(node, 'caller.receiver') => { start: 0, end: 'Factory'.length }
112
+ # child_node_range(node, 'caller.receiver') # { start: 0, end: 'Factory'.length }
113
113
  #
114
114
  # # node array
115
115
  # node = Parser::CurrentRuby.parse('foobar arg1, arg2)')
116
- # child_node_range(node, 'arguments') => { start: 'foobar '.length, end: 'foobar arg1, arg2'.length }
116
+ # child_node_range(node, 'arguments') # { start: 'foobar '.length, end: 'foobar arg1, arg2'.length }
117
117
  #
118
118
  # # index for node array
119
119
  # node = Parser::CurrentRuby.parse('foobar(arg1, arg2)')
120
- # child_node_range(node, 'arguments.-1') => { start: 'foobar(arg1, '.length, end: 'foobar(arg1, arg2'.length }
120
+ # child_node_range(node, 'arguments.-1') # { start: 'foobar(arg1, '.length, end: 'foobar(arg1, arg2'.length }
121
121
  #
122
122
  # # pips for block node
123
123
  # node = Parser::CurrentRuby.parse('Factory.define :user do |user|; end')
124
- # child_node_range(node, 'pipes') => { start: 'Factory.deine :user do '.length, end: 'Factory.define :user do |user|'.length }
124
+ # child_node_range(node, 'pipes') # { start: 'Factory.deine :user do '.length, end: 'Factory.define :user do |user|'.length }
125
125
  #
126
126
  # # parentheses for def and defs node
127
127
  # node = Parser::CurrentRuby.parse('def foo(bar); end')
128
- # child_node_range(node, 'parentheses') => { start: 'def foo'.length, end: 'def foo(bar)'.length }
128
+ # child_node_range(node, 'parentheses') # { start: 'def foo'.length, end: 'def foo(bar)'.length }
129
129
  #
130
130
  # # double_colon for const node
131
131
  # node = Parser::CurrentRuby.parse('Foo::Bar')
132
- # child_node_range(node, 'double_colon') => { start: 'Foo'.length, end: 'Foo::'.length }
132
+ # child_node_range(node, 'double_colon') # { start: 'Foo'.length, end: 'Foo::'.length }
133
133
  #
134
134
  # # self and dot for defs node
135
135
  # node = Parser::CurrentRuby.parse('def self.foo(bar); end')
136
- # child_node_range(node, 'self') => { start: 'def '.length, end: 'def self'.length }
137
- # child_node_range(node, 'dot') => { start: 'def self'.length, end: 'def self.'.length }
136
+ # child_node_range(node, 'self') # { start: 'def '.length, end: 'def self'.length }
137
+ # child_node_range(node, 'dot') # { start: 'def self'.length, end: 'def self.'.length }
138
138
  #
139
139
  # # dot for send and csend node
140
140
  # node = Parser::CurrentRuby.parse('foo.bar(test)')
141
- # child_node_range(node, 'self') => { start: 'foo'.length, end: 'foo.'.length }
141
+ # child_node_range(node, 'self') # { start: 'foo'.length, end: 'foo.'.length }
142
142
  #
143
143
  # # parentheses for send and csend node
144
144
  # node = Parser::CurrentRuby.parse('foo.bar(test)')
145
- # child_node_range(node, 'parentheses') => { start: 'foo.bar'.length, end: 'foo.bar(test)'.length }
145
+ # child_node_range(node, 'parentheses') # { start: 'foo.bar'.length, end: 'foo.bar(test)'.length }
146
146
  def child_node_range(node, child_name)
147
147
  direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
148
148
 
@@ -177,6 +177,7 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
177
177
  end
178
178
  when %i[class name], %i[const name], %i[cvar name], %i[def name], %i[defs name],
179
179
  %i[gvar name], %i[ivar name], %i[lvar name]
180
+
180
181
  NodeMutation::Struct::Range.new(node.loc.name.begin_pos, node.loc.name.end_pos)
181
182
  when %i[const double_colon]
182
183
  NodeMutation::Struct::Range.new(node.loc.double_colon.begin_pos, node.loc.double_colon.end_pos)
@@ -281,7 +282,7 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
281
282
  elsif direct_child_name == 'to_symbol' && node.type == :str
282
283
  child_node = ":#{node.to_value}"
283
284
  elsif direct_child_name == 'to_string' && node.type == :sym
284
- child_node = node.to_value.to_s
285
+ child_node = node.to_value.to_s
285
286
  elsif direct_child_name == 'to_single_quote' && node.type == :str
286
287
  child_node = "'#{node.to_value}'"
287
288
  elsif direct_child_name == 'to_double_quote' && node.type == :str
@@ -18,47 +18,47 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
18
18
  # @return [String] The new source code.
19
19
  # @example
20
20
  # node = SyntaxTree::Parser.new('class Synvert; end').parse.statements.body.first
21
- # rewritten_source(node, '{{constant}}').to eq 'Synvert'
21
+ # rewritten_source(node, '{{constant}}') # 'Synvert'
22
22
  #
23
23
  # # index for node array
24
24
  # node = SyntaxTree::Parser.new("foo.bar(a, b)").parse.statements.body.first
25
- # rewritten_source(node, '{{arguments.arguments.parts.-1}}')).to eq 'b'
25
+ # rewritten_source(node, '{{arguments.arguments.parts.-1}}')) # 'b'
26
26
  #
27
27
  # # {key}_assoc for HashLiteral node
28
28
  # node = SyntaxTree::Parser.new("after_commit :do_index, on: :create, if: :indexable?").parse.statements.body.first
29
- # rewritten_source(node, '{{arguments.parts.-1.on_assoc}}')).to eq 'on: :create'
29
+ # rewritten_source(node, '{{arguments.parts.-1.on_assoc}}')) # 'on: :create'
30
30
  #
31
31
  # # {key}_value for hash node
32
32
  # node = SyntaxTree::Parser.new("after_commit :do_index, on: :create, if: :indexable?").parse.statements.body.first
33
- # rewritten_source(node, '{{arguments.parts.-1.on_value}}')).to eq ':create'
33
+ # rewritten_source(node, '{{arguments.parts.-1.on_value}}')) # ':create'
34
34
  #
35
35
  # # to_single_quote for StringLiteral node
36
36
  # node = SyntaxTree::Parser.new('"foo"').parse.statements.body.first
37
- # rewritten_source(node, 'to_single_quote') => "'foo'"
37
+ # rewritten_source(node, 'to_single_quote') # "'foo'"
38
38
  #
39
39
  # # to_double_quote for StringLiteral node
40
40
  # node = SyntaxTree::Parser.new("'foo'").parse.statements.body.first
41
- # rewritten_source(node, 'to_double_quote') => '"foo"'
41
+ # rewritten_source(node, 'to_double_quote') # '"foo"'
42
42
  #
43
43
  # # to_symbol for StringLiteral node
44
44
  # node = SyntaxTree::Parser.new("'foo'").parse.statements.body.first
45
- # rewritten_source(node, 'to_symbol') => ':foo'
45
+ # rewritten_source(node, 'to_symbol') # ':foo'
46
46
  #
47
47
  # # to_string for SymbolLiteral node
48
48
  # node = SyntaxTree::Parser.new(":foo").parse.statements.body.first
49
- # rewritten_source(node, 'to_string') => 'foo'
49
+ # rewritten_source(node, 'to_string') # 'foo'
50
50
  #
51
51
  # # to_lambda_literal for MethodAddBlock node
52
52
  # node = SyntaxTree::Parser.new('lambda { foobar }').parse.statements.body.first
53
- # rewritten_source(node, 'to_lambda_literal') => '-> { foobar }'
53
+ # rewritten_source(node, 'to_lambda_literal') # '-> { foobar }'
54
54
  #
55
55
  # # strip_curly_braces for HashLiteral node
56
56
  # node = SyntaxTree::Parser.new("{ foo: 'bar' }").parse.statements.body.first
57
- # rewritten_source(node, 'strip_curly_braces') => "foo: 'bar'"
57
+ # rewritten_source(node, 'strip_curly_braces') # "foo: 'bar'"
58
58
  #
59
59
  # # wrap_curly_braces for BareAssocHash node
60
60
  # node = SyntaxTree::Parser.new("test(foo: 'bar')").parse.statements.body.first
61
- # rewritten_source(node.arguments.arguments.parts.first, 'wrap_curly_braces') => "{ foo: 'bar' }"
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
64
64
  old_code = Regexp.last_match(1)
@@ -74,7 +74,7 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
74
74
  if lines_count > 1 && lines_count == evaluated.size
75
75
  new_code = []
76
76
  lines.each_with_index { |line, index|
77
- new_code << (index == 0 ? line : line[evaluated.first.indent - 2..-1])
77
+ new_code << (index == 0 ? line : line[NodeMutation.adapter.get_indent(evaluated.first) - NodeMutation.tab_width..-1])
78
78
  }
79
79
  new_code.join("\n")
80
80
  else
@@ -101,28 +101,42 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
101
101
  # @return {NodeMutation::Struct::Range} The range of the child node.
102
102
  # @example
103
103
  # node = SyntaxTree::Parser.new('foo.bar(test)').parse.statements.body.first
104
- # child_node_range(node, 'receiver') => { start: 0, end: 'foo'.length }
104
+ # child_node_range(node, 'receiver') # { start: 0, end: 'foo'.length }
105
105
  #
106
106
  # # node array
107
107
  # node = SyntaxTree::Parser.new('foo.bar(a, b)').parse.statements.body.first
108
- # child_node_range(node, 'arguments.arguments') => { start: 'foo.bar('.length, end: 'foo.bar(a, b'.length }
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
111
  # node = SyntaxTree::Parser.new('foo.bar(a, b)').parse.statements.body.first
112
- # child_node_range(node, 'arguments.arguments.parts.-1') => { start: 'foo.bar(a, '.length, end: 'foo.bar(a, b'.length }
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
115
  # node = SyntaxTree::Parser.new('foo | bar').parse.statements.body.first
116
- # child_node_range(node, 'operator') => { start: 'foo '.length, end: 'foo |'.length }
116
+ # child_node_range(node, 'operator') # { start: 'foo '.length, end: 'foo |'.length }
117
117
  def child_node_range(node, child_name)
118
- child_node = child_node_by_name(node, child_name)
119
- return nil if child_node.nil?
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_char, child_node.location.end_char)
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
120
135
 
121
- if child_node.is_a?(Array)
122
- return NodeMutation::Struct::Range.new(child_node.first.location.start_char, child_node.last.location.end_char)
136
+ return NodeMutation::Struct::Range.new(child_node.location.start_char, child_node.location.end_char)
123
137
  end
124
138
 
125
- if node.is_a?(SyntaxTree::Binary) && child_name == 'operator'
139
+ if node.is_a?(SyntaxTree::Binary) && child_name.to_sym == :operator
126
140
  start_char = node.left.location.end_char
127
141
  start_char += 1 while node.source[start_char] == ' '
128
142
  end_char = node.right.location.start_char
@@ -130,7 +144,24 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
130
144
  return NodeMutation::Struct::Range.new(start_char, end_char)
131
145
  end
132
146
 
133
- return NodeMutation::Struct::Range.new(child_node.location.start_char, child_node.location.end_char)
147
+ raise NodeMutation::MethodNotSupported,
148
+ "#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
149
+
150
+ child_node = node.send(direct_child_name)
151
+
152
+ return child_node_range(child_node, nested_child_name) if nested_child_name
153
+
154
+ return nil if child_node.nil?
155
+
156
+ if child_node.is_a?(SyntaxTree::Node)
157
+ return(
158
+ NodeMutation::Struct::Range.new(child_node.location.start_char, child_node.location.end_char)
159
+ )
160
+ end
161
+
162
+ return(
163
+ NodeMutation::Struct::Range.new(child_node.first.location.start_char, child_node.last.location.end_char)
164
+ )
134
165
  end
135
166
 
136
167
  def get_start(node, child_name = nil)
@@ -195,7 +226,7 @@ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
195
226
  if node.block.block_var
196
227
  child_node = "->(#{node.block.block_var.params.to_source}) {#{node.block.bodystmt.to_source}}"
197
228
  else
198
- child_node = "-> {#{node.block.bodystmt.to_source }}"
229
+ child_node = "-> {#{node.block.bodystmt.to_source}}"
199
230
  end
200
231
  elsif direct_child_name == 'strip_curly_braces' && node.is_a?(SyntaxTree::HashLiteral)
201
232
  child_node = node.to_source.sub(/^{(.*)}$/) { Regexp.last_match(1).strip }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeMutation
4
- VERSION = "1.19.2"
4
+ VERSION = "1.19.4"
5
5
  end
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.19.2
4
+ version: 1.19.4
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-06-30 00:00:00.000000000 Z
11
+ date: 2023-08-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ast node mutation apis
14
14
  email:
@@ -70,7 +70,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
70
70
  - !ruby/object:Gem::Version
71
71
  version: '0'
72
72
  requirements: []
73
- rubygems_version: 3.4.13
73
+ rubygems_version: 3.4.18
74
74
  signing_key:
75
75
  specification_version: 4
76
76
  summary: ast node mutation apis