node_mutation 1.13.2 → 1.15.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 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