node_mutation 1.13.2 → 1.15.0

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: dc332fd8345dc642414853ebc7f92ddf3f4d364c2bd5f5076d5de3a17368ce50
4
- data.tar.gz: 4a5018954b0094f1dea13c4b4f7ce0237e368564b892a57cd680ec88fb062eb1
3
+ metadata.gz: 11054e72fcf35b7caeb2cee67b421206da2f980d4d1f23afa08f9db75f112f75
4
+ data.tar.gz: 4dde234a2f4716b82d042b7d9f094469da04942cdca669c40a7d745f75480b77
5
5
  SHA512:
6
- metadata.gz: f2329f07950c9a97b1cb2729ffc9b617e146a56607476f03c8cb78e3047ebc52358e59ff4e80916e8bf521f4d8ff9e7e5801e2452b414f81ac447590e39ac9e6
7
- data.tar.gz: b97de612f89f6d7e23a20e2bfaed7aa1c0ead95ba868c3535e9575161feb18a35b13a0a75623a814855ce149d7f56676ad1fc76836235ce5e4d8a503dc0147bb
6
+ metadata.gz: 5bfc255f3b2bf599debc4c8d882999d3083f89ec2e9cdb81aa2eb1d4245e65cafb61c9f9ee7db7286b4efddf66b96cb00742696f5215beab1b3cc847c2025b40
7
+ data.tar.gz: 7c9063056156b1ee4accd50ad204040209c55ca096f543ecccc5f66175b1213a5611a4815263058514d81466e440d6cdf36f65c7208d048c48c3f3736e516706
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # NodeMutation
2
2
 
3
+ ## 1.15.0 (2023-04-17)
4
+
5
+ * Add `indent` action
6
+ * Use two `InsertAction` and one `IndentAction` instead of `WrapAction`
7
+ * Drop `ALLOW_INSERT_AT_SAME_POSITION` strategy
8
+
9
+ ## 1.14.0 (2023-04-04)
10
+
11
+ * Add `transform_proc` to transform the actions
12
+ * Allow to write `Action` `start` and `end` attributes
13
+
3
14
  ## 1.13.2 (2023-04-01)
4
15
 
5
16
  * Support `cvar`, `gvar`, `ivar`, and `lvar` name 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.13.2)
4
+ node_mutation (1.15.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -35,18 +35,20 @@ mutation = NodeMutation.new(source)
35
35
  mutation.append node, 'include FactoryGirl::Syntax::Methods'
36
36
  # delete source code of the child ast node
37
37
  mutation.delete node, :dot, :message, and_comma: true
38
+ # indent code
39
+ mutation.indent node, tab_size: 1
38
40
  # insert code to the ast node.
39
41
  mutation.insert node, 'URI.', at: 'beginning'
40
42
  # prepend code to the ast node.
41
43
  mutation.prepend node, '{{arguments.first}}.include FactoryGirl::Syntax::Methods'
42
44
  # remove source code of the ast node
43
- mutation.remove(node: Node)
45
+ mutation.remove node, and_comma: true
44
46
  # replace child node of the ast node with new code
45
47
  mutation.replace node, :message, with: 'test'
46
48
  # replace the ast node with new code
47
49
  mutation.replace_with node, 'create {{arguments}}'
48
- # wrap node within a block, class or module
49
- mutation.wrap node, with: 'module Foo'
50
+ # wrap node with prefix and suffix code
51
+ mutation.wrap node, prefix: 'module Foo', suffix: 'end', newline: true
50
52
  # no operation
51
53
  mutation.noop
52
54
  ```
@@ -81,10 +83,9 @@ It provides 3 strategies to handle conflicts when processing actions:
81
83
 
82
84
  1. `Strategy.KEEP_RUNNING`: keep running and ignore the conflict action.
83
85
  2. `Strategy.THROW_ERROR`: throw error when conflict action is found.
84
- 3. `Strategy.ALLOW_INSERT_AT_SAME_POSITION`: allow insert action at the same position.
85
86
 
86
87
  ```ruby
87
- NodeMutation.configure(strategy: Strategy.KEEP_RUNNING | Strategy.ALLOW_INSERT_AT_SAME_POSITION); // default is Strategy.THROW_ERROR
88
+ NodeMutation.configure(strategy: Strategy.KEEP_RUNNING); // default is Strategy.THROW_ERROR
88
89
  ```
89
90
 
90
91
  ### tab_width
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # IndentAction to indent code.
4
+ class NodeMutation::IndentAction < NodeMutation::Action
5
+ # Initialize a IndentAction.
6
+ #
7
+ # @param node [Node]
8
+ # @param tab_size [Integer] tab size
9
+ def initialize(node, tab_size = 1)
10
+ super(node, nil)
11
+ @tab_size = tab_size
12
+ end
13
+
14
+ # The rewritten source code with proper indent.
15
+ #
16
+ # @return [String] rewritten code.
17
+ def new_code
18
+ source = NodeMutation.adapter.get_source(@node)
19
+ source.each_line.map { |line| ' ' * NodeMutation.tab_width * @tab_size + line }.join
20
+ end
21
+
22
+ private
23
+
24
+ # Calculate the begin the end positions.
25
+ def calculate_position
26
+ @start = NodeMutation.adapter.get_start(@node)
27
+ @end = NodeMutation.adapter.get_end(@node)
28
+ end
29
+ end
@@ -2,11 +2,11 @@
2
2
 
3
3
  # Action defines rewriter action, insert, replace or delete code.
4
4
  class NodeMutation::Action
5
- # @!attribute [r] start
5
+ # @!attribute [rw] start
6
6
  # @return [Integer] start position
7
- # @!attribute [r] end
7
+ # @!attribute [rw] end
8
8
  # @return [Integer] end position
9
- attr_reader :start, :end
9
+ attr_accessor :start, :end
10
10
 
11
11
  # Initialize an action.
12
12
  #
@@ -3,5 +3,4 @@
3
3
  class NodeMutation::Strategy
4
4
  KEEP_RUNNING = 0b1
5
5
  THROW_ERROR = 0b10
6
- ALLOW_INSERT_AT_SAME_POSITION = 0b100
7
6
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeMutation
4
- VERSION = "1.13.2"
4
+ VERSION = "1.15.0"
5
5
  end
data/lib/node_mutation.rb CHANGED
@@ -11,19 +11,25 @@ class NodeMutation
11
11
  autoload :Action, 'node_mutation/action'
12
12
  autoload :AppendAction, 'node_mutation/action/append_action'
13
13
  autoload :DeleteAction, 'node_mutation/action/delete_action'
14
+ autoload :IndentAction, 'node_mutation/action/indent_action'
14
15
  autoload :InsertAction, 'node_mutation/action/insert_action'
15
16
  autoload :RemoveAction, 'node_mutation/action/remove_action'
16
17
  autoload :PrependAction, 'node_mutation/action/prepend_action'
17
18
  autoload :ReplaceAction, 'node_mutation/action/replace_action'
18
19
  autoload :ReplaceWithAction, 'node_mutation/action/replace_with_action'
19
- autoload :WrapAction, 'node_mutation/action/wrap_action'
20
20
  autoload :NoopAction, 'node_mutation/action/noop_action'
21
21
  autoload :Result, 'node_mutation/result'
22
22
  autoload :Strategy, 'node_mutation/strategy'
23
23
  autoload :Struct, 'node_mutation/struct'
24
24
 
25
+ # @!attribute [r] actions
26
+ # @return [Array<NodeMutation::Struct::Action>]
25
27
  attr_reader :actions
26
28
 
29
+ # @!attribute [rw] transform_proc
30
+ # @return [Proc] proc to transfor the actions
31
+ attr_accessor :transform_proc
32
+
27
33
  class << self
28
34
  # Configure NodeMutation
29
35
  # @param [Hash] options options to configure
@@ -182,22 +188,26 @@ class NodeMutation
182
188
  @actions << ReplaceWithAction.new(node, code).process
183
189
  end
184
190
 
185
- # Wrap source code of the ast node with new code.
191
+ # Wrap source code of the ast node with prefix and suffix code.
186
192
  # @param node [Node] ast node
187
- # @param with [String] code need to be wrapped with.
193
+ # @param prefix [String] prefix code need to be wrapped with.
194
+ # @param suffix [String] suffix code need to be wrapped with.
195
+ # @param newline [Boolean] add newline after prefix and before suffix.
188
196
  # @example
189
197
  # source code of the ast node is
190
198
  # class Foobar
191
199
  # end
192
200
  # then we call
193
- # wrap(node, with: 'module Synvert')
201
+ # wrap(node, prefix: 'module Synvert', suffix: 'end', newline: true)
194
202
  # the source code will be rewritten to
195
203
  # module Synvert
196
204
  # class Foobar
197
205
  # end
198
206
  # end
199
- def wrap(node, with:)
200
- @actions << WrapAction.new(node, with: with).process
207
+ def wrap(node, prefix:, suffix:, newline: false)
208
+ @actions << InsertAction.new(node, prefix, at: 'beginning').process
209
+ @actions << InsertAction.new(node, suffix, at: 'end').process
210
+ @actions << IndentAction.new(node).process if newline
201
211
  end
202
212
 
203
213
  # No operation.
@@ -219,6 +229,7 @@ class NodeMutation
219
229
  end
220
230
 
221
231
  source = +@source
232
+ @transform_proc.call(@actions) if @transform_proc
222
233
  @actions.sort_by! { |action| [action.start, action.end] }
223
234
  conflict_actions = get_conflict_actions
224
235
  if conflict_actions.size > 0 && strategy?(Strategy::THROW_ERROR)
@@ -245,6 +256,7 @@ class NodeMutation
245
256
  return NodeMutation::Result.new(affected: false, conflicted: false)
246
257
  end
247
258
 
259
+ @transform_proc.call(@actions) if @transform_proc
248
260
  @actions.sort_by! { |action| [action.start, action.end] }
249
261
  conflict_actions = get_conflict_actions
250
262
  if conflict_actions.size > 0 && strategy?(Strategy::THROW_ERROR)
@@ -269,11 +281,8 @@ class NodeMutation
269
281
  begin_pos = @actions[i].start
270
282
  end_pos = @actions[i].end
271
283
  while j > -1
272
- # if we have two insert actions at same position.
273
- same_position = begin_pos == @actions[j].start && begin_pos == end_pos && @actions[j].start == @actions[j].end
274
284
  # if we have two actions with overlapped range.
275
- overlapped_position = begin_pos < @actions[j].end
276
- if (!strategy?(Strategy::ALLOW_INSERT_AT_SAME_POSITION) && same_position) || overlapped_position
285
+ if begin_pos < @actions[j].end
277
286
  conflict_actions << @actions.delete_at(j)
278
287
  else
279
288
  i = j
@@ -2,6 +2,4 @@ class NodeMutation::Strategy
2
2
  KEEP_RUNNING: Integer
3
3
 
4
4
  THROW_ERROR: Integer
5
-
6
- ALLOW_INSERT_AT_SAME_POSITION: Integer
7
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.13.2
4
+ version: 1.15.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-04-04 00:00:00.000000000 Z
11
+ date: 2023-04-17 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ast node mutation apis
14
14
  email:
@@ -29,13 +29,13 @@ files:
29
29
  - lib/node_mutation/action.rb
30
30
  - lib/node_mutation/action/append_action.rb
31
31
  - lib/node_mutation/action/delete_action.rb
32
+ - lib/node_mutation/action/indent_action.rb
32
33
  - lib/node_mutation/action/insert_action.rb
33
34
  - lib/node_mutation/action/noop_action.rb
34
35
  - lib/node_mutation/action/prepend_action.rb
35
36
  - lib/node_mutation/action/remove_action.rb
36
37
  - lib/node_mutation/action/replace_action.rb
37
38
  - lib/node_mutation/action/replace_with_action.rb
38
- - lib/node_mutation/action/wrap_action.rb
39
39
  - lib/node_mutation/adapter.rb
40
40
  - lib/node_mutation/parser_adapter.rb
41
41
  - lib/node_mutation/result.rb
@@ -69,7 +69,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  requirements: []
72
- rubygems_version: 3.4.6
72
+ rubygems_version: 3.4.10
73
73
  signing_key:
74
74
  specification_version: 4
75
75
  summary: ast node mutation apis
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # WrapAction to wrap node within a block, class or module.
4
- #
5
- # Note: if WrapAction is conflicted with another action (start and end are overlapped),
6
- # we have to put those 2 actions into 2 within_file scopes.
7
- class NodeMutation::WrapAction < NodeMutation::Action
8
- # Initialize a WrapAction.
9
- #
10
- # @param node [Node]
11
- # @param with [String] new code to wrap
12
- def initialize(node, with:)
13
- super(node, with)
14
- @indent = NodeMutation.adapter.get_start_loc(@node).column
15
- end
16
-
17
- # The rewritten source code.
18
- #
19
- # @return [String] rewritten code.
20
- def new_code
21
- "#{@code}\n#{' ' * @indent}" +
22
- NodeMutation.adapter.get_source(@node).split("\n").map { |line| " #{line}" }
23
- .join("\n") +
24
- "\n#{' ' * @indent}end"
25
- end
26
-
27
- private
28
-
29
- # Calculate the begin the end positions.
30
- def calculate_position
31
- @start = NodeMutation.adapter.get_start(@node)
32
- @end = NodeMutation.adapter.get_end(@node)
33
- end
34
- end