synvert-core 1.35.4 → 2.0.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: 241e9b40114c50b1dec1b86784fde026ed03ac64f2e38e314f00ed1f35a010c5
4
- data.tar.gz: 521fee14550bd2eebb9e26d9aa1928bd4ae51cc43a88692c5337dad7ab32cc11
3
+ metadata.gz: 8e5f40c698306314082157a4b976ff37e9adf84bb81e1915b7ffd319cbac227a
4
+ data.tar.gz: 326fd1445561b81a70c9ed88ccd710c9103985f31e3349dccbc12688734b6630
5
5
  SHA512:
6
- metadata.gz: 206b4e331e89760a0f47376401a48986b0ce2ec7e72d29cc566a93ae9b2341d7298a9738da3b9434c38a66d81b32bd6e109c9f52a0804d2575dcc0a8f46b2254
7
- data.tar.gz: e42ec5540b5b3dab9688ef43d9872132ea8e78c33073aa8567e10dcfb3152e7c50b8d1d639b16d3a0bacd9bc088966fb32c915dfccb045c412b79552e37a3eec
6
+ metadata.gz: a296c2ea8fa640b117d409361dd7148bffaf63bf5ac7e7d90f636a83b40f6d32b2294a3bfd185b86bdc6a242179eed0ebf8325e78e9c6b90965932f97ed8358a
7
+ data.tar.gz: 5bfd5bf3f26f8a13dd595bb4428fa6c6a76a04e4d148cb1b45b286d2a437ca93ba608075edcafa8355f88fec7d7483e19ea0a312157c22bb007d320a0a50fb15
@@ -0,0 +1,5 @@
1
+ {
2
+ "cSpell.words": [
3
+ "synvert"
4
+ ]
5
+ }
data/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 2.0.0 (2024-04-28)
4
+
5
+ * Add instance variable `Instance#current_parser`
6
+ * Add callback and visit ast nodes
7
+
3
8
  ## 1.35.4 (2024-04-25)
4
9
 
5
10
  * Eval snippet on gist.github.com
@@ -166,7 +171,7 @@
166
171
 
167
172
  ## 1.26.3 (2023-05-13)
168
173
 
169
- * Fix haml and slim engine to support attribute and ruby evalidation in the same line
174
+ * Fix haml and slim engine to support attribute and ruby evaluation in the same line
170
175
  * Fix ruby block in multi lins in haml and slim
171
176
 
172
177
  ## 1.26.2 (2023-05-10)
@@ -400,12 +405,12 @@
400
405
  ## 1.2.1 (2022-05-01)
401
406
 
402
407
  * Selector always after a node type in NQL
403
- * Define `pairs` method for `hash` ndoe
408
+ * Define `pairs` method for `hash` node
404
409
 
405
410
  ## 1.2.0 (2022-04-29)
406
411
 
407
412
  * Remove comma in NQL array value
408
- * Parse pseduo class without selector in NQL
413
+ * Parse pseudo class without selector in NQL
409
414
  * Parse multiple goto scope in NQL
410
415
  * Parse `nil?` in NQL
411
416
 
@@ -542,7 +547,7 @@
542
547
 
543
548
  ## 0.44.0 (2021-07-19)
544
549
 
545
- * Return rewrtier after executing snippet
550
+ * Return rewriter after executing snippet
546
551
  * `left_value` and `right_value` support `or_asgn` node
547
552
  * `child_node_range` supports send `parentheses`
548
553
 
@@ -656,7 +661,7 @@
656
661
 
657
662
  ## 0.17.0 (2021-01-29)
658
663
 
659
- * Ignore `gem_spec` check if `Gemfile.lock` does not eixst
664
+ * Ignore `gem_spec` check if `Gemfile.lock` does not exist
660
665
 
661
666
  ## 0.16.0 (2021-01-17)
662
667
 
@@ -714,10 +719,10 @@
714
719
  ## 0.7.0 (2014-09-29)
715
720
 
716
721
  * Add debug info for MethodNotSupported error.
717
- * Add left_value and right_vaue ext to ast node
722
+ * Add left_value and right_value ext to ast node
718
723
  * Add arguments for def and defs nodes
719
724
  * Add name for arg and blockarg nodes
720
- * Remove trailing whitespaces in rewritten code
725
+ * Remove trailing whitespace in rewritten code
721
726
  * Rewriter.available always returns a hash
722
727
  * Support ArgumentsNode in rewritten_source
723
728
 
data/Gemfile.lock CHANGED
@@ -1,10 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- synvert-core (1.35.4)
4
+ synvert-core (2.0.0)
5
5
  activesupport (< 7.0.0)
6
6
  node_mutation (>= 1.24.4)
7
7
  node_query (>= 1.15.2)
8
+ node_visitor (>= 1.0.1)
8
9
  parallel
9
10
  parser
10
11
  parser_node_ext (>= 1.3.2)
@@ -54,11 +55,12 @@ GEM
54
55
  nenv (0.3.0)
55
56
  node_mutation (1.24.4)
56
57
  node_query (1.15.2)
58
+ node_visitor (1.0.1)
57
59
  notiffany (0.1.3)
58
60
  nenv (~> 0.1)
59
61
  shellany (~> 0.0)
60
62
  parallel (1.24.0)
61
- parser (3.3.0.5)
63
+ parser (3.3.1.0)
62
64
  ast (~> 2.4.1)
63
65
  racc
64
66
  parser_node_ext (1.3.2)
data/README.md CHANGED
@@ -6,52 +6,58 @@
6
6
  [![Build Status](https://github.com/synvert-hq/synvert-core-ruby/actions/workflows/main.yml/badge.svg)](https://github.com/synvert-hq/synvert-core-ruby/actions/workflows/main.yml)
7
7
  [![Gem Version](https://img.shields.io/gem/v/synvert-core.svg)](https://rubygems.org/gems/synvert-core)
8
8
 
9
- Synvert core provides a set of DSLs to rewrite ruby code. e.g.
9
+ Synvert core provides a set of DSLs to rewrite (find and replace) ruby code. e.g.
10
10
 
11
11
  ```ruby
12
- Synvert::Rewriter.new 'factory_bot', 'convert_factory_girl_to_factory_bot' do
13
- description <<~EOS
14
- It converts FactoryGirl to FactoryBot
12
+ Synvert::Rewriter.new 'ruby', 'map_and_flatten_to_flat_map' do
13
+ configure(parser: Synvert::PARSER_PARSER)
15
14
 
16
- ```ruby
17
- require 'factory_girl'
18
- require 'factory_girl_rails'
19
- ```
20
-
21
- =>
22
-
23
- ```ruby
24
- require 'factory_bot'
25
- require 'factory_bot_rails'
26
- ```
15
+ description <<~EOS
16
+ It converts `map` and `flatten` to `flat_map`
27
17
 
28
18
  ```ruby
29
- FactoryGirl.create(:user)
30
- FactoryGirl.build(:user)
19
+ enum.map do
20
+ # do something
21
+ end.flatten
31
22
  ```
32
23
 
33
24
  =>
34
25
 
35
26
  ```ruby
36
- FactoryBot.create(:user)
37
- FactoryBot.build(:user)
27
+ enum.flat_map do
28
+ # do something
29
+ end
38
30
  ```
39
31
  EOS
40
32
 
41
- within_files Synvert::RAILS_TEST_FILES do
42
- find_node '.const[name=FactoryGirl]' do
43
- replace_with 'FactoryBot'
33
+ within_files Synvert::ALL_RUBY_FILES + Synvert::ALL_RAKE_FILES do
34
+ find_node '.send [receiver=.block [caller=.send[message=map]]] [message=flatten] [arguments.size=0]' do
35
+ group do
36
+ delete :message, :dot
37
+ replace 'receiver.caller.message', with: 'flat_map'
38
+ end
44
39
  end
40
+ end
41
+ end
42
+ ```
45
43
 
46
- find_node ".send[receiver=nil][message=require][arguments.size=1][arguments.first='factory_girl']" do
47
- replace :arguments, with: "'factory_bot'"
48
- end
44
+ It also supports to add callbacks to visit ast nodes.
49
45
 
50
- with_node type: 'send', receiver: nil, message: 'require', arguments: { size: 1, first: "'factory_girl_rails'" } do
51
- replace :arguments, with: "'factory_bot_rails'"
46
+ ```ruby
47
+ Synvert::Helper.new 'ruby/parse' do |options|
48
+ configure(parser: Synvert::PRISM_PARSER)
49
+
50
+ with_configurations(number_of_workers: 1) do
51
+ class_names = []
52
+ within_file Synvert::ALL_RUBY_FILES do
53
+ add_callback :class_node, at: 'start' do |node|
54
+ class_names << node.name.to_source
55
+ end
52
56
  end
57
+ # class_names is an array of class names
53
58
  end
54
59
  end
60
+
55
61
  ```
56
62
 
57
63
  Want to see more examples, check out [synvert-snippets-ruby](https://github.com/synvert-hq/synvert-snippets-ruby).
@@ -106,9 +112,13 @@ Actions:
106
112
  * [group](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#group-instance_method) - group actions
107
113
  * [add_action](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#add_action-instance_method) - add custom action
108
114
 
115
+ Callbacks:
116
+
117
+ * [add_callback](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#add_callback-instance_method) - add callback when visiting ast nodes
118
+
109
119
  Others:
110
120
 
111
- * [wrap_with_quotes](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#wrap_with_quotes-instance_method) - wrap string code with single or doulbe quotes
121
+ * [wrap_with_quotes](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#wrap_with_quotes-instance_method) - wrap string code with single or double quotes
112
122
  * [add_leading_spaces](https://synvert-hq.github.io/synvert-core-ruby/Synvert/Core/Rewriter/Instance.html#add_leading_spaces-instance_method) - add leading spaces before the string code
113
123
 
114
124
 
@@ -10,7 +10,7 @@ module Synvert::Core
10
10
  # @yield run when condition matches
11
11
  def initialize(instance, nql_or_rules, &block)
12
12
  @instance = instance
13
- @node_query = NodeQuery.new(nql_or_rules, adapter: instance.parser)
13
+ @node_query = NodeQuery.new(nql_or_rules, adapter: instance.current_parser)
14
14
  @block = block
15
15
  end
16
16
 
@@ -22,6 +22,8 @@ module Synvert::Core
22
22
  # @yield block code to find nodes, match conditions and rewrite code.
23
23
  def initialize(rewriter, file_path, &block)
24
24
  @rewriter = rewriter
25
+ @current_parser = @rewriter.parser
26
+ @current_visitor = NodeVisitor.new(adapter: @current_parser)
25
27
  @actions = []
26
28
  @file_path = file_path
27
29
  @block = block
@@ -35,9 +37,11 @@ module Synvert::Core
35
37
 
36
38
  # @!attribute [r] file_path
37
39
  # @return file path
40
+ # @!attribute [r] current_parser
41
+ # @return current parser
38
42
  # @!attribute [rw] current_node
39
43
  # @return current ast node
40
- attr_reader :file_path
44
+ attr_reader :file_path, :current_parser
41
45
  attr_accessor :current_node
42
46
 
43
47
  # Process the instance.
@@ -52,7 +56,7 @@ module Synvert::Core
52
56
  5.times do
53
57
  source = read_source(absolute_file_path)
54
58
  encoded_source = Engine.encode(File.extname(file_path), source)
55
- @current_mutation = NodeMutation.new(source, adapter: @rewriter.parser)
59
+ @current_mutation = NodeMutation.new(source, adapter: @current_parser)
56
60
  @current_mutation.transform_proc = Engine.generate_transform_proc(File.extname(file_path), encoded_source)
57
61
  begin
58
62
  node = parse_code(@file_path, encoded_source)
@@ -61,6 +65,8 @@ module Synvert::Core
61
65
  instance_eval(&@block)
62
66
  end
63
67
 
68
+ @current_visitor.visit(node, self)
69
+
64
70
  result = @current_mutation.process
65
71
  if result.affected?
66
72
  @rewriter.add_affected_file(file_path)
@@ -83,7 +89,7 @@ module Synvert::Core
83
89
  def test
84
90
  absolute_file_path = File.join(Configuration.root_path, file_path)
85
91
  source = read_source(absolute_file_path)
86
- @current_mutation = NodeMutation.new(source, adapter: @rewriter.parser)
92
+ @current_mutation = NodeMutation.new(source, adapter: @current_parser)
87
93
  encoded_source = Engine.encode(File.extname(file_path), source)
88
94
  @current_mutation.transform_proc = Engine.generate_transform_proc(File.extname(file_path), encoded_source)
89
95
  begin
@@ -93,6 +99,8 @@ module Synvert::Core
93
99
  instance_eval(&@block)
94
100
  end
95
101
 
102
+ @current_visitor.visit(node, self)
103
+
96
104
  result = Configuration.test_result == 'new_source' ? @current_mutation.process : @current_mutation.test
97
105
  result.file_path = file_path
98
106
  result
@@ -111,13 +119,6 @@ module Synvert::Core
111
119
  @current_node
112
120
  end
113
121
 
114
- # Get rewriter's parser.
115
- #
116
- # @return [String] parser
117
- def parser
118
- @rewriter.parser
119
- end
120
-
121
122
  # Get current_mutation's adapter.
122
123
  #
123
124
  # @return [NodeMutation::Adapter]
@@ -438,6 +439,18 @@ module Synvert::Core
438
439
  @rewriter.add_warning Rewriter::Warning.new(self, message)
439
440
  end
440
441
 
442
+ # It adds a callback when visiting an ast node.
443
+ # @example
444
+ # add_callback :class, at: 'start' do |node|
445
+ # # do something when visiting class node
446
+ # end
447
+ # @param node_type [Symbol] node type
448
+ # @param at [String] at start or end
449
+ # @yield block code to run when visiting the node
450
+ def add_callback(node_type, at: 'start', &block)
451
+ @current_visitor.add_callback(node_type, at: at, &block)
452
+ end
453
+
441
454
  # Wrap str string with single or doulbe quotes based on Configuration.single_quote.
442
455
  # @param str [String]
443
456
  # @return [String] quoted string
@@ -482,7 +495,7 @@ module Synvert::Core
482
495
  # @param encoded_source [String] encoded source code
483
496
  # @return [Node] ast node for file
484
497
  def parse_code(file_path, encoded_source)
485
- case @rewriter.parser
498
+ case @current_parser
486
499
  when Synvert::SYNTAX_TREE_PARSER
487
500
  parse_code_by_syntax_tree(file_path, encoded_source)
488
501
  when Synvert::PRISM_PARSER
@@ -490,7 +503,7 @@ module Synvert::Core
490
503
  when Synvert::PARSER_PARSER
491
504
  parse_code_by_parser(file_path, encoded_source)
492
505
  else
493
- raise Errors::ParserNotSupported.new("Parser #{@rewriter.parser} not supported")
506
+ raise Errors::ParserNotSupported.new("Parser #{@current_parser} not supported")
494
507
  end
495
508
  end
496
509
 
@@ -14,7 +14,7 @@ module Synvert::Core
14
14
  super(instance, &block)
15
15
 
16
16
  @options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
17
- @node_query = NodeQuery.new(nql_or_rules, adapter: instance.parser)
17
+ @node_query = NodeQuery.new(nql_or_rules, adapter: instance.current_parser)
18
18
  end
19
19
 
20
20
  # Find out the matching nodes.
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.35.4'
5
+ VERSION = '2.0.0'
6
6
  end
7
7
  end
data/lib/synvert/core.rb CHANGED
@@ -5,6 +5,7 @@ require 'active_support'
5
5
  require 'active_support/core_ext'
6
6
  require 'node_query'
7
7
  require 'node_mutation'
8
+ require 'node_visitor'
8
9
 
9
10
  module Synvert
10
11
  module Core
@@ -11,7 +11,7 @@ module Synvert::Core
11
11
  end
12
12
  EOS
13
13
  let(:node) { Parser::CurrentRuby.parse(source) }
14
- let(:instance) { double(current_node: node, parser: :parser) }
14
+ let(:instance) { double(current_node: node, current_parser: :parser) }
15
15
 
16
16
  describe '#process' do
17
17
  it 'call block if match anything' do
@@ -11,7 +11,7 @@ module Synvert::Core
11
11
  end
12
12
  EOS
13
13
  let(:node) { Parser::CurrentRuby.parse(source) }
14
- let(:instance) { double(current_node: node, parser: :parser) }
14
+ let(:instance) { double(current_node: node, current_parser: :parser) }
15
15
 
16
16
  describe '#process' do
17
17
  it 'call block if match anything' do
@@ -264,6 +264,13 @@ module Synvert::Core
264
264
  instance.warn 'foobar'
265
265
  end
266
266
 
267
+ it 'parsers add_callback' do
268
+ instance.instance_variable_set(:@current_visitor, double)
269
+ block = proc {}
270
+ expect(instance.instance_variable_get(:@current_visitor)).to receive(:add_callback).with(:class_node, at: 'start', &block)
271
+ instance.add_callback(:class_node, at: 'start', &block)
272
+ end
273
+
267
274
  it 'adds action' do
268
275
  mutation = NodeMutation.new("", adapter: :parser)
269
276
  instance.instance_variable_set(:@current_mutation, mutation)
@@ -414,6 +421,27 @@ module Synvert::Core
414
421
  expect(File).to receive(:write).with('./app/views/posts/_form.html.slim', output)
415
422
  instance.process
416
423
  end
424
+
425
+ it 'visits with callbacks' do
426
+ names = []
427
+ instance =
428
+ Rewriter::Instance.new rewriter, 'app/models/synvert/user.rb' do
429
+ add_callback :module do |node|
430
+ names << node.name.to_source
431
+ end
432
+ add_callback :class do |node|
433
+ names << node.name.to_source
434
+ end
435
+ end
436
+ expect(File).to receive(:read).with('./app/models/synvert/user.rb', encoding: 'UTF-8').and_return(<<~EOF)
437
+ module Synvert
438
+ class User
439
+ end
440
+ end
441
+ EOF
442
+ instance.process
443
+ expect(names).to eq ['Synvert', 'User']
444
+ end
417
445
  end
418
446
 
419
447
  describe '#test' do
@@ -567,6 +595,27 @@ module Synvert::Core
567
595
  ),
568
596
  ]
569
597
  end
598
+
599
+ it 'visits with callbacks' do
600
+ names = []
601
+ instance =
602
+ Rewriter::Instance.new rewriter, 'app/models/synvert/user.rb' do
603
+ add_callback :module do |node|
604
+ names << node.name.to_source
605
+ end
606
+ add_callback :class do |node|
607
+ names << node.name.to_source
608
+ end
609
+ end
610
+ expect(File).to receive(:read).with('./app/models/synvert/user.rb', encoding: 'UTF-8').and_return(<<~EOF)
611
+ module Synvert
612
+ class User
613
+ end
614
+ end
615
+ EOF
616
+ instance.test
617
+ expect(names).to eq ['Synvert', 'User']
618
+ end
570
619
  end
571
620
 
572
621
  describe '#process_with_node' do
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
22
22
  spec.add_runtime_dependency "activesupport", "< 7.0.0"
23
23
  spec.add_runtime_dependency "node_query", ">= 1.15.2"
24
24
  spec.add_runtime_dependency "node_mutation", ">= 1.24.4"
25
+ spec.add_runtime_dependency "node_visitor", ">= 1.0.1"
25
26
  spec.add_runtime_dependency "parser"
26
27
  spec.add_runtime_dependency "parser_node_ext", ">= 1.3.2"
27
28
  spec.add_runtime_dependency "syntax_tree"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synvert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.35.4
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-25 00:00:00.000000000 Z
11
+ date: 2024-04-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.24.4
55
+ - !ruby/object:Gem::Dependency
56
+ name: node_visitor
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.0.1
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: 1.0.1
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: parser
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -160,6 +174,7 @@ files:
160
174
  - ".github/workflows/main.yml"
161
175
  - ".gitignore"
162
176
  - ".rspec"
177
+ - ".vscode/settings.json"
163
178
  - ".yardopts"
164
179
  - CHANGELOG.md
165
180
  - Gemfile
@@ -234,7 +249,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
249
  - !ruby/object:Gem::Version
235
250
  version: '0'
236
251
  requirements: []
237
- rubygems_version: 3.5.3
252
+ rubygems_version: 3.5.9
238
253
  signing_key:
239
254
  specification_version: 4
240
255
  summary: convert ruby code to better syntax.