node_mutation 1.21.4 → 1.21.6

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: 4c65f57e5d3c315141ac35863689a5391a5c833a794f2f3768f6a12a735f4523
4
- data.tar.gz: 2b1db51fcffc7f7a77a5151b3ee08e07679f6e1e622d884546968c5a50a25aeb
3
+ metadata.gz: 6ae5572567e82e089eefff7f7f696230a17e77fbf0af051dd3a4a46ad21bf9a8
4
+ data.tar.gz: 8448ddd41dadbee697ee58a2d506bd7832fe9792d601e3a969cdc5b8869651fb
5
5
  SHA512:
6
- metadata.gz: aeba2a1cc46bdd0a501701c78f3a93be88d64009d78fba8d616dfb34813ad137168d1f9b51ca40a7aa5e6c1f486db4a507f7ffe95f5c816c5fbd70b20b7320c9
7
- data.tar.gz: 4be674f5fa1abc12c68c0a2f1464465758c8d07523024cb262218d799a96099baace7b340f27044884c67ffbda7e7bcab2e61404e92d92dc753f7eca01fba2f4
6
+ metadata.gz: 603b93346813a1e4a0e6a2fed2c3fb5a0569f592b69de6d3f580b055ad1cae301c03c1984c50e567612f9b9f32b6fe706cd1c8276691b895d387044349c9fb93
7
+ data.tar.gz: 7c2ac5164feb10bbb01d0f355c831032dbccbdb6a80eb341884dc350f33dc95409cec2ced8ead61862fadde4ae71f2244414a43b4cd42ea23b70dc62f1082566
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # NodeMutation
2
2
 
3
+ ## 1.21.6 (2023-11-20)
4
+
5
+ * Flat and sort actions after filtering actions when processing
6
+
7
+ ## 1.21.5 (2023-11-20)
8
+
9
+ * Rewrite the process and test methods
10
+
3
11
  ## 1.21.4 (2023-10-28)
4
12
 
5
13
  * Update `Adapter` rbs
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- node_mutation (1.21.4)
4
+ node_mutation (1.21.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeMutation
4
- VERSION = "1.21.4"
4
+ VERSION = "1.21.6"
5
5
  end
data/lib/node_mutation.rb CHANGED
@@ -262,20 +262,23 @@ class NodeMutation
262
262
  # if strategy is set to KEEP_RUNNING.
263
263
  # @return {NodeMutation::Result}
264
264
  def process
265
- @actions = flatten_actions(@actions)
266
- if @actions.length == 0
265
+ @actions = optimize_group_actions(@actions)
266
+
267
+ flatten_actions = flat_actions(@actions)
268
+ if flatten_actions.length == 0
267
269
  return NodeMutation::Result.new(affected: false, conflicted: false)
268
270
  end
269
271
 
270
272
  source = +@source
271
273
  @transform_proc.call(@actions) if @transform_proc
272
- sort_actions!(@actions)
273
- conflict_actions = get_conflict_actions(@actions)
274
+ sorted_actions = sort_flatten_actions(flatten_actions)
275
+ conflict_actions = get_conflict_actions(sorted_actions)
274
276
  if conflict_actions.size > 0 && strategy?(Strategy::THROW_ERROR)
275
277
  raise ConflictActionError, "mutation actions are conflicted"
276
278
  end
277
279
 
278
- new_source = rewrite_source(source, @actions)
280
+ actions = sort_flatten_actions(flat_actions(get_filter_actions(conflict_actions)))
281
+ new_source = rewrite_source(source, actions)
279
282
  result = NodeMutation::Result.new(affected: true, conflicted: !conflict_actions.empty?)
280
283
  result.new_source = new_source
281
284
  result
@@ -289,63 +292,79 @@ class NodeMutation
289
292
  # if strategy is set to KEEP_RUNNING.
290
293
  # @return {NodeMutation::Result}
291
294
  def test
292
- @actions = flatten_actions(@actions)
293
- if @actions.length == 0
295
+ @actions = optimize_group_actions(@actions)
296
+
297
+ flatten_actions = flat_actions(@actions)
298
+ if flatten_actions.length == 0
294
299
  return NodeMutation::Result.new(affected: false, conflicted: false)
295
300
  end
296
301
 
297
302
  @transform_proc.call(@actions) if @transform_proc
298
- sort_actions!(@actions)
299
- conflict_actions = get_conflict_actions(@actions)
303
+ sorted_actions = sort_flatten_actions(flatten_actions)
304
+ conflict_actions = get_conflict_actions(sorted_actions)
300
305
  if conflict_actions.size > 0 && strategy?(Strategy::THROW_ERROR)
301
306
  raise ConflictActionError, "mutation actions are conflicted"
302
307
  end
303
308
 
304
309
  result = NodeMutation::Result.new(affected: true, conflicted: !conflict_actions.empty?)
305
- result.actions = @actions.map(&:to_struct)
310
+ actions = sort_actions(get_filter_actions(conflict_actions))
311
+ result.actions = actions.map(&:to_struct)
306
312
  result
307
313
  end
308
314
 
309
315
  private
310
316
 
311
- # It flattens a series of actions by removing any GroupAction
317
+ # Optimizes a list of actions, recursively optimizing any nested group actions.
318
+ # @param actions [Array<NodeMutation::Action>]
319
+ # @return [Array<NodeMutation::Action>] optimized actions
320
+ def optimize_group_actions(actions)
321
+ actions.map do |action|
322
+ if action.is_a?(GroupAction)
323
+ # If the group action contains only one action, replace the group action with that action
324
+ if action.actions.length === 1
325
+ return optimize_group_actions(action.actions)
326
+ end
327
+
328
+ # If the group action contains more than one action, optimize its sub-actions
329
+ action.actions = optimize_group_actions(action.actions)
330
+ end
331
+ action
332
+ end
333
+ end
334
+
335
+ # It flats a series of actions by removing any GroupAction
312
336
  # objects that contain only a single action. This is done recursively.
313
- def flatten_actions(actions)
314
- new_actions = []
337
+ # @param actions [Array<NodeMutation::Action>]
338
+ # @return [Array<NodeMutation::Action>] flatten actions
339
+ def flat_actions(actions)
340
+ flatten_actions = []
315
341
  actions.each do |action|
316
342
  if action.is_a?(GroupAction)
317
- new_actions << flatten_group_action(action)
343
+ flatten_actions += flat_actions(action.actions)
318
344
  else
319
- new_actions << action
345
+ flatten_actions << action
320
346
  end
321
347
  end
322
- new_actions.compact
348
+ flatten_actions
323
349
  end
324
350
 
325
- # It flattens a group action.
326
- def flatten_group_action(action)
327
- if action.actions.empty?
328
- nil
329
- elsif action.actions.size == 1
330
- if action.actions.first.is_a?(GroupAction)
331
- flatten_group_action(action.actions.first)
332
- else
333
- action.actions.first
351
+ # Recusively sort actions by start position and end position.
352
+ # @param actions [Array<NodeMutation::Action>]
353
+ # @return [Array<NodeMutation::Action>] sorted actions
354
+ def sort_actions(actions)
355
+ actions.each do |action|
356
+ if action.is_a?(GroupAction)
357
+ action.actions = sort_actions(action.actions)
334
358
  end
335
- else
336
- action.actions = flatten_actions(action.actions)
337
- action
338
359
  end
360
+ actions.sort_by { |action| [action.start, action.end] }
339
361
  end
340
362
 
341
363
  # Sort actions by start position and end position.
342
364
  # @param actions [Array<NodeMutation::Action>]
343
365
  # @return [Array<NodeMutation::Action>] sorted actions
344
- def sort_actions!(actions)
345
- actions.sort_by! { |action| [action.start, action.end] }
346
- actions.each do |action|
347
- sort_actions!(action.actions) if action.is_a?(GroupAction)
348
- end
366
+ def sort_flatten_actions(flatten_actions)
367
+ flatten_actions.sort_by { |action| [action.start, action.end] }
349
368
  end
350
369
 
351
370
  # Rewrite source code with actions.
@@ -365,6 +384,8 @@ class NodeMutation
365
384
 
366
385
  # It changes source code from bottom to top, and it can change source code twice at the same time,
367
386
  # So if there is an overlap between two actions, it removes the conflict actions and operate them in the next loop.
387
+ # @param actions [Array<NodeMutation::Action>]
388
+ # @return [Array<NodeMutation::Action>] conflict actions
368
389
  def get_conflict_actions(actions)
369
390
  i = actions.length - 1
370
391
  j = i - 1
@@ -376,7 +397,7 @@ class NodeMutation
376
397
  while j > -1
377
398
  # if we have two actions with overlapped range.
378
399
  if begin_pos < actions[j].end
379
- conflict_actions << actions.delete_at(j)
400
+ conflict_actions << actions[j]
380
401
  else
381
402
  i = j
382
403
  begin_pos = actions[i].start
@@ -384,12 +405,22 @@ class NodeMutation
384
405
  end
385
406
  j -= 1
386
407
  end
387
- actions.each do |action|
388
- conflict_actions.concat(get_conflict_actions(action.actions)) if action.is_a?(GroupAction)
389
- end
390
408
  conflict_actions
391
409
  end
392
410
 
411
+ # It filters conflict actions from actions.
412
+ # @param actions [Array<NodeMutation::Action>]
413
+ # @return [Array<NodeMutation::Action>] filtered actions
414
+ def get_filter_actions(conflict_actions)
415
+ @actions.select do |action|
416
+ if action.is_a?(GroupAction)
417
+ action.actions.all? { |child_action| !conflict_actions.include?(child_action) }
418
+ else
419
+ !conflict_actions.include?(action)
420
+ end
421
+ end
422
+ end
423
+
393
424
  def strategy?(strategy)
394
425
  NodeMutation.strategy & strategy == strategy
395
426
  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.21.4
4
+ version: 1.21.6
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-10-28 00:00:00.000000000 Z
11
+ date: 2023-11-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ast node mutation apis
14
14
  email: