synvert-core 1.35.4 → 2.0.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: 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.