synvert-core 0.63.1 → 1.0.1
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 +4 -4
- data/.github/workflows/main.yml +1 -1
- data/.gitignore +4 -0
- data/CHANGELOG.md +9 -1
- data/Guardfile +11 -2
- data/README.md +74 -34
- data/Rakefile +15 -1
- data/lib/synvert/core/array_ext.rb +41 -0
- data/lib/synvert/core/configuration.rb +12 -0
- data/lib/synvert/core/engine/erb.rb +9 -8
- data/lib/synvert/core/exceptions.rb +0 -4
- data/lib/synvert/core/node_ext.rb +232 -128
- data/lib/synvert/core/node_query/compiler/array.rb +34 -0
- data/lib/synvert/core/node_query/compiler/attribute.rb +51 -0
- data/lib/synvert/core/node_query/compiler/attribute_list.rb +24 -0
- data/lib/synvert/core/node_query/compiler/boolean.rb +23 -0
- data/lib/synvert/core/node_query/compiler/comparable.rb +79 -0
- data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +51 -0
- data/lib/synvert/core/node_query/compiler/expression.rb +88 -0
- data/lib/synvert/core/node_query/compiler/float.rb +23 -0
- data/lib/synvert/core/node_query/compiler/identifier.rb +41 -0
- data/lib/synvert/core/node_query/compiler/integer.rb +23 -0
- data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +7 -0
- data/lib/synvert/core/node_query/compiler/nil.rb +23 -0
- data/lib/synvert/core/node_query/compiler/parse_error.rb +7 -0
- data/lib/synvert/core/node_query/compiler/regexp.rb +37 -0
- data/lib/synvert/core/node_query/compiler/selector.rb +51 -0
- data/lib/synvert/core/node_query/compiler/string.rb +34 -0
- data/lib/synvert/core/node_query/compiler/symbol.rb +23 -0
- data/lib/synvert/core/node_query/compiler.rb +24 -0
- data/lib/synvert/core/node_query/lexer.rex +96 -0
- data/lib/synvert/core/node_query/lexer.rex.rb +293 -0
- data/lib/synvert/core/node_query/parser.racc.rb +518 -0
- data/lib/synvert/core/node_query/parser.y +84 -0
- data/lib/synvert/core/node_query.rb +36 -0
- data/lib/synvert/core/rewriter/action/append_action.rb +4 -3
- data/lib/synvert/core/rewriter/action/delete_action.rb +17 -8
- data/lib/synvert/core/rewriter/action/insert_action.rb +16 -7
- data/lib/synvert/core/rewriter/action/insert_after_action.rb +3 -2
- data/lib/synvert/core/rewriter/action/prepend_action.rb +3 -2
- data/lib/synvert/core/rewriter/action/remove_action.rb +16 -10
- data/lib/synvert/core/rewriter/action/replace_action.rb +15 -5
- data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +18 -11
- data/lib/synvert/core/rewriter/action/replace_with_action.rb +6 -5
- data/lib/synvert/core/rewriter/action/wrap_action.rb +16 -7
- data/lib/synvert/core/rewriter/action.rb +22 -10
- data/lib/synvert/core/rewriter/any_value.rb +1 -0
- data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +4 -0
- data/lib/synvert/core/rewriter/condition.rb +11 -3
- data/lib/synvert/core/rewriter/gem_spec.rb +6 -3
- data/lib/synvert/core/rewriter/helper.rb +7 -4
- data/lib/synvert/core/rewriter/instance.rb +217 -104
- data/lib/synvert/core/rewriter/ruby_version.rb +4 -4
- data/lib/synvert/core/rewriter/scope/goto_scope.rb +5 -6
- data/lib/synvert/core/rewriter/scope/query_scope.rb +36 -0
- data/lib/synvert/core/rewriter/scope/within_scope.rb +10 -5
- data/lib/synvert/core/rewriter/scope.rb +8 -0
- data/lib/synvert/core/rewriter/warning.rb +1 -1
- data/lib/synvert/core/rewriter.rb +91 -43
- data/lib/synvert/core/version.rb +1 -1
- data/lib/synvert/core.rb +22 -6
- data/spec/synvert/core/engine/erb_spec.rb +2 -2
- data/spec/synvert/core/node_ext_spec.rb +36 -12
- data/spec/synvert/core/node_query/lexer_spec.rb +512 -0
- data/spec/synvert/core/node_query/parser_spec.rb +270 -0
- data/spec/synvert/core/rewriter/action_spec.rb +0 -4
- data/spec/synvert/core/rewriter/condition/if_only_exist_condition_spec.rb +1 -6
- data/spec/synvert/core/rewriter/gem_spec_spec.rb +1 -1
- data/spec/synvert/core/rewriter/helper_spec.rb +4 -1
- data/spec/synvert/core/rewriter/instance_spec.rb +31 -20
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +74 -0
- data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +12 -9
- data/spec/synvert/core/rewriter_spec.rb +4 -2
- data/synvert-core-ruby.gemspec +7 -2
- metadata +91 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f889cb977b7bf6e847bdeeac011ee0d23210ae8db7a0652e8c00d5d98c72a701
|
4
|
+
data.tar.gz: 46d220401cc8c9c0422428c2915862148b4ad8dc236f637ed52dbc45207de742
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 926df3dd8aa3689938e90c530fb432e0703cff2f89f35f46950b3630eb98b8da6de0e0d5eb75c5c24262f3712400d4570ac05abd5ebbbe6c6954d6c997048432
|
7
|
+
data.tar.gz: 321fb626763ca31e6156c462bb6846ce73d00639a620b0b7048b024fbe50d14f63f6d3209e3a534b0475c29c29e74dcf0a7c204f14ad0927244bd5cbb157b3d6
|
data/.github/workflows/main.yml
CHANGED
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,16 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
-
## 0.
|
3
|
+
## 1.0.0 (2022-04-25)
|
4
|
+
|
5
|
+
* Introduce new node query language
|
6
|
+
* Drop ruby 2.5 support
|
7
|
+
|
8
|
+
## 0.64.0 (2022-04-02)
|
4
9
|
|
5
10
|
* Read absolute path of Gemfile.lock
|
11
|
+
* Remove unused `Node#to_s`
|
12
|
+
* Yardoc comments
|
13
|
+
* Drop `within_direct_node(rules)`, use `within_node(rules, { direct: true })` instead
|
6
14
|
|
7
15
|
## 0.63.0 (2022-02-26)
|
8
16
|
|
data/Guardfile
CHANGED
@@ -2,6 +2,15 @@
|
|
2
2
|
|
3
3
|
guard :rspec, cmd: 'bundle exec rspec' do
|
4
4
|
watch(%r{^spec/.+_spec\.rb$})
|
5
|
-
watch(%r{^lib/(.+)\.rb$})
|
6
|
-
watch('
|
5
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
6
|
+
watch('lib/synvert/core/node_query/lexer.rex.rb') { 'spec/synvert/core/node_query/lexer_spec.rb' }
|
7
|
+
watch('lib/synvert/core/node_query/compiler.rb') { 'spec/synvert/core/node_query/parser_spec.rb' }
|
8
|
+
watch(%r{^lib/synvert/core/node_query/compiler/.*\.rb$}) { 'spec/synvert/core/node_query/parser_spec.rb' }
|
9
|
+
watch('lib/synvert/core/node_query/parser.racc.rb') { 'spec/synvert/core/node_query/parser_spec.rb' }
|
10
|
+
watch('spec/spec_helper.rb') { "spec" }
|
11
|
+
end
|
12
|
+
|
13
|
+
guard :rake, task: 'generate' do
|
14
|
+
watch('lib/synvert/core/node_query/lexer.rex')
|
15
|
+
watch('lib/synvert/core/node_query/parser.y')
|
7
16
|
end
|
data/README.md
CHANGED
@@ -2,39 +2,79 @@
|
|
2
2
|
|
3
3
|
<img src="https://synvert.xinminlabs.com/img/logo_96.png" alt="logo" width="32" height="32" />
|
4
4
|
|
5
|
+
[](https://awesomecode.io/repos/xinminlabs/synvert-core-ruby)
|
5
6
|

|
6
|
-
[](http://badge.fury.io/rb/synvert-core)
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
[
|
40
|
-
|
8
|
+
Synvert core provides a set of DSLs to rewrite ruby code. e.g.
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
Synvert::Rewriter.new 'ruby', 'map_and_flatten_to_flat_map' do
|
12
|
+
description <<~EOS
|
13
|
+
It converts `map` and `flatten` to `flat_map`
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
enum.map do
|
17
|
+
# do something
|
18
|
+
end.flatten
|
19
|
+
```
|
20
|
+
|
21
|
+
=>
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
enum.flat_map do
|
25
|
+
# do something
|
26
|
+
end
|
27
|
+
```
|
28
|
+
EOS
|
29
|
+
|
30
|
+
within_files Synvert::ALL_RUBY_FILES do
|
31
|
+
with_node type: 'send', receiver: { type: 'block', caller: { type: 'send', message: 'map' } }, message: 'flatten', arguments: { size: 0 } do
|
32
|
+
delete :message, :dot
|
33
|
+
replace 'receiver.caller.message', with: 'flat_map'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
39
|
+
Want to see more examples, check out [synvert-snippets-ruby](https://github.com/xinminlabs/synvert-snippets-ruby).
|
40
|
+
|
41
|
+
Want to use the CLI, check out [synvert-ruby](https://github.com/xinminlabs/synvert-ruby).
|
42
|
+
|
43
|
+
DSLs are as follows
|
44
|
+
|
45
|
+
* [description](./Synvert/Core/Rewriter.html#description-instance_method) - set description of the rewriter
|
46
|
+
* [if_ruby](./Synvert/Core/Rewriter.html#if_ruby-instance_method) - check if ruby version is greater than or equal to the specified ruby version
|
47
|
+
* [if_gem](./Synvert/Core/Rewriter.html#if_gem-instance_method) - compare version of specified gem
|
48
|
+
* [within_files](./Synvert/Core/Rewriter.html#within_files-instance_method) - find specified files
|
49
|
+
* [within_file](./Synvert/Core/Rewriter.html#within_file-instance_method) - alias to within_files
|
50
|
+
* [add_file](./Synvert/Core/Rewriter.html#add_file-instance_method) - add a new file
|
51
|
+
* [remove_file](./Synvert/Core/Rewriter.html#remove_file-instance_method) - remove a file
|
52
|
+
* [helper_method](./Synvert/Core/Rewriter.html#helper_method-instance_method) - define a helper method
|
53
|
+
* [add_snippet](./Synvert/Core/Rewriter.html#add_snippet-instance_method) - call another rewriter
|
54
|
+
* [todo](./Synvert/Core/Rewriter.html#todo-instance_method) - set todo
|
55
|
+
* [redo_until_no_change](./Synvert/Core/Rewriter.html#redo_until_no_change-instance_method) - run the snippet until no change
|
56
|
+
|
57
|
+
Scopes:
|
58
|
+
|
59
|
+
* [within_node](./Synvert/Core/Rewriter/Instance.html#within_node-instance_method) - recursively find matching ast nodes
|
60
|
+
* [with_node](./Synvert/Core/Rewriter/Instance.html#with_node-instance_method) - alias to within_node
|
61
|
+
* [goto_node](./Synvert/Core/Rewriter/Instance.html#goto_node-instance_method) - go to a child node
|
62
|
+
|
63
|
+
Conditions:
|
64
|
+
|
65
|
+
* [if_exist_node](./Synvert/Core/Rewriter/Instance.html#if_exist_node-instance_method) - check if matching node exist in the child nodes
|
66
|
+
* [unless_exist_node](./Synvert/Core/Rewriter/Instance.html#unless_exist_node-instance_method) - check if matching node doesn't exist in the child nodes
|
67
|
+
* [if_only_exist_node](./Synvert/Core/Rewriter/Instance.html#if_only_exist_node-instance_method) - check if current node has only one child node and the child node matches rules
|
68
|
+
|
69
|
+
Actions:
|
70
|
+
|
71
|
+
* [append](./Synvert/Core/Rewriter/Instance.html#append-instance_method) - append the code to the bottom of current node body
|
72
|
+
* [prepend](./Synvert/Core/Rewriter/Instance.html#prepend-instance_method) - prepend the code to the bottom of current node body
|
73
|
+
* [insert](./Synvert/Core/Rewriter/Instance.html#insert-instance_method) - insert code
|
74
|
+
* [insert_after](./Synvert/Core/Rewriter/Instance.html#insert_after-instance_method) - insert the code next to the current node
|
75
|
+
* [replace](./Synvert/Core/Rewriter/Instance.html#replace-instance_method) - replace the code of specified child nodes
|
76
|
+
* [delete](./Synvert/Core/Rewriter/Instance.html#delete-instance_method) - delete the code specified child nodes
|
77
|
+
* [wrap](./Synvert/Core/Rewriter/Instance.html#wrap-instance_method) - wrap the current node with code
|
78
|
+
* [replace_with](./Synvert/Core/Rewriter/Instance.html#replace_with-instance_method) - replace the whole code of current node
|
79
|
+
* [warn](./Synvert/Core/Rewriter/Instance.html#warn-instance_method) - warn message
|
80
|
+
* [replace_erb_stmt_with_expr](./Synvert/Core/Rewriter/Instance.html#replace_erb_stmt_with_expr-instance_method) - replace erb stmt code to expr code
|
data/Rakefile
CHANGED
@@ -2,7 +2,21 @@
|
|
2
2
|
|
3
3
|
require "bundler/gem_tasks"
|
4
4
|
require 'rspec/core/rake_task'
|
5
|
-
|
6
5
|
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
require 'oedipus_lex'
|
7
|
+
Rake.application.rake_require "oedipus_lex"
|
8
|
+
|
9
|
+
file "lib/synvert/core/node_query/lexer.rex.rb" => "lib/synvert/core/node_query/lexer.rex"
|
10
|
+
file "lib/synvert/core/node_query/parser.racc.rb" => "lib/synvert/core/node_query/parser.y"
|
11
|
+
|
12
|
+
task :lexer => "lib/synvert/core/node_query/lexer.rex.rb"
|
13
|
+
task :parser => "lib/synvert/core/node_query/parser.racc.rb"
|
14
|
+
task :generate => [:lexer, :parser]
|
15
|
+
|
16
|
+
rule '.racc.rb' => '.y' do |t|
|
17
|
+
cmd = "bundle exec racc -l -v -o #{t.name} #{t.source}"
|
18
|
+
sh cmd
|
19
|
+
end
|
7
20
|
|
8
21
|
task :default => :spec
|
22
|
+
task :spec => :generate
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Extend Array.
|
4
|
+
class Array
|
5
|
+
# Get child node by the name.
|
6
|
+
#
|
7
|
+
# @param child_name [String] name of child node.
|
8
|
+
# @return [Parser::AST::Node] the child node.
|
9
|
+
def child_node_by_name(child_name)
|
10
|
+
direct_child_name, nested_child_name = child_name.split('.', 2)
|
11
|
+
child_direct_child_node = direct_child_name =~ /\A\d+\z/ ? self[direct_child_name.to_i - 1] : self.send(direct_child_name)
|
12
|
+
return child_direct_child_node.child_node_by_name(nested_child_name) if nested_child_name
|
13
|
+
return child_direct_child_node if child_direct_child_node
|
14
|
+
|
15
|
+
raise Synvert::Core::MethodNotSupported,
|
16
|
+
"child_node_by_name is not handled for #{map(&:debug_info).join("\n")}, child_name: #{child_name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Get the source range of child node.
|
20
|
+
#
|
21
|
+
# @param child_name [String] name of child node.
|
22
|
+
# @return [Parser::Source::Range] source range of child node.
|
23
|
+
def child_node_range(child_name)
|
24
|
+
direct_child_name, nested_child_name = child_name.split('.', 2)
|
25
|
+
child_direct_child_node = direct_child_name =~ /\A\d+\z/ ? self[direct_child_name.to_i - 1] : self.send(direct_child_name)
|
26
|
+
if nested_child_name
|
27
|
+
return child_direct_child_node.child_node_range(nested_child_name)
|
28
|
+
elsif child_direct_child_node
|
29
|
+
return (
|
30
|
+
Parser::Source::Range.new(
|
31
|
+
'(string)',
|
32
|
+
child_direct_child_node.loc.expression.begin_pos,
|
33
|
+
child_direct_child_node.loc.expression.end_pos
|
34
|
+
)
|
35
|
+
)
|
36
|
+
else
|
37
|
+
raise Synvert::Core::MethodNotSupported,
|
38
|
+
"child_node_range is not handled for #{map(&:debug_info).join("\n")}, child_name: #{child_name}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -4,16 +4,28 @@ module Synvert::Core
|
|
4
4
|
# Synvert global configuration.
|
5
5
|
class Configuration
|
6
6
|
class << self
|
7
|
+
# @!attribute [w] path
|
8
|
+
# @!attribute [w] skip_files
|
9
|
+
# @!attribute [w] show_run_process
|
7
10
|
attr_writer :path, :skip_files, :show_run_process
|
8
11
|
|
12
|
+
# Get the path.
|
13
|
+
#
|
14
|
+
# @return [String] default is '.'
|
9
15
|
def path
|
10
16
|
@path || '.'
|
11
17
|
end
|
12
18
|
|
19
|
+
# Get a list of skip files.
|
20
|
+
#
|
21
|
+
# @return [Array<String>] default is [].
|
13
22
|
def skip_files
|
14
23
|
@skip_files || []
|
15
24
|
end
|
16
25
|
|
26
|
+
# Check if show run process.
|
27
|
+
#
|
28
|
+
# @return [Boolean] default is false
|
17
29
|
def show_run_process
|
18
30
|
@show_run_process || false
|
19
31
|
end
|
@@ -43,11 +43,13 @@ module Synvert::Core
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def decode_html_output(source)
|
46
|
-
source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text(Regexp.last_match(1)) }
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text(Regexp.last_match(1)) }
|
47
|
+
.gsub(
|
48
|
+
/@output_buffer.safe_append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/mo
|
49
|
+
) { reverse_escape_text(Regexp.last_match(1)) }
|
50
|
+
.gsub(
|
51
|
+
/@output_buffer.safe_append=(.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/mo
|
52
|
+
) { reverse_escape_text(Regexp.last_match(1)) }
|
51
53
|
end
|
52
54
|
|
53
55
|
def remove_erubis_buf(source)
|
@@ -64,6 +66,7 @@ module Synvert::Core
|
|
64
66
|
|
65
67
|
# borrowed from rails
|
66
68
|
class Erubis < ::Erubis::Eruby
|
69
|
+
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
67
70
|
def add_preamble(src)
|
68
71
|
@newline_pending = 0
|
69
72
|
src << '@output_buffer = output_buffer || ActionView::OutputBuffer.new;'
|
@@ -76,7 +79,7 @@ module Synvert::Core
|
|
76
79
|
@newline_pending += 1
|
77
80
|
else
|
78
81
|
src << "@output_buffer.safe_append='"
|
79
|
-
src << "\n" * @newline_pending if @newline_pending > 0
|
82
|
+
src << ("\n" * @newline_pending) if @newline_pending > 0
|
80
83
|
src << escape_text(text)
|
81
84
|
src << "'.freeze;"
|
82
85
|
|
@@ -95,8 +98,6 @@ module Synvert::Core
|
|
95
98
|
end
|
96
99
|
end
|
97
100
|
|
98
|
-
BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
|
99
|
-
|
100
101
|
def add_expr_literal(src, code)
|
101
102
|
flush_newline_if_pending(src)
|
102
103
|
if BLOCK_EXPR.match?(code)
|