synvert-core 1.4.0 → 1.5.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.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -4
  3. data/CHANGELOG.md +6 -0
  4. data/Gemfile +0 -3
  5. data/Guardfile +0 -9
  6. data/README.md +30 -12
  7. data/Rakefile +1 -15
  8. data/lib/synvert/core/engine/erb.rb +1 -1
  9. data/lib/synvert/core/engine.rb +1 -1
  10. data/lib/synvert/core/node_ext.rb +0 -466
  11. data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
  12. data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -1
  13. data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -1
  14. data/lib/synvert/core/rewriter/instance.rb +83 -133
  15. data/lib/synvert/core/rewriter/scope/query_scope.rb +2 -2
  16. data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -4
  17. data/lib/synvert/core/rewriter.rb +0 -10
  18. data/lib/synvert/core/version.rb +1 -1
  19. data/lib/synvert/core.rb +4 -6
  20. data/spec/synvert/core/engine/erb_spec.rb +3 -3
  21. data/spec/synvert/core/node_ext_spec.rb +0 -795
  22. data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
  23. data/spec/synvert/core/rewriter/instance_spec.rb +47 -115
  24. data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
  25. data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -4
  26. data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +1 -4
  27. data/synvert-core-ruby.gemspec +4 -2
  28. metadata +44 -61
  29. data/lib/synvert/core/array_ext.rb +0 -48
  30. data/lib/synvert/core/node_query/compiler/array.rb +0 -34
  31. data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
  32. data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
  33. data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
  34. data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
  35. data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
  36. data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
  37. data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
  38. data/lib/synvert/core/node_query/compiler/float.rb +0 -23
  39. data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
  40. data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
  41. data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
  42. data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
  43. data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
  44. data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
  45. data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
  46. data/lib/synvert/core/node_query/compiler/string.rb +0 -23
  47. data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
  48. data/lib/synvert/core/node_query/compiler.rb +0 -25
  49. data/lib/synvert/core/node_query/lexer.rex +0 -99
  50. data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
  51. data/lib/synvert/core/node_query/parser.racc.rb +0 -306
  52. data/lib/synvert/core/node_query/parser.y +0 -60
  53. data/lib/synvert/core/node_query.rb +0 -36
  54. data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
  55. data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
  56. data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
  57. data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
  58. data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
  59. data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
  60. data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
  61. data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
  62. data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
  63. data/lib/synvert/core/rewriter/action.rb +0 -102
  64. data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
  65. data/spec/synvert/core/node_query/parser_spec.rb +0 -337
  66. data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
  67. data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
  68. data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
  69. data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
  70. data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
  71. data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
  72. data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
  73. data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
  74. data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
  75. data/spec/synvert/core/rewriter/action_spec.rb +0 -14
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # AppendAction appends code to the bottom of node body.
5
- class Rewriter::AppendAction < Rewriter::Action
6
- private
7
-
8
- END_LENGTH = "\nend".length
9
-
10
- # Calculate the begin the end positions.
11
- def calculate_position
12
- @begin_pos = :begin == @node.type ? @node.loc.expression.end_pos : @node.loc.expression.end_pos - @node.column - END_LENGTH
13
- @end_pos = @begin_pos
14
- end
15
-
16
- # Indent of the node.
17
- #
18
- # @param node [Parser::AST::Node]
19
- # @return [String] n times whitesphace
20
- def indent(node)
21
- if %i[block class def defs].include? node.type
22
- ' ' * (node.column + DEFAULT_INDENT)
23
- else
24
- ' ' * node.column
25
- end
26
- end
27
- end
28
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # DeleteAction deletes child nodes.
5
- class Rewriter::DeleteAction < Rewriter::Action
6
- # Initialize a DeleteAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param selectors [Array<Symbol, String>] used to select child nodes
10
- # @option and_comma [Boolean] delete extra comma.
11
- def initialize(instance, *selectors, and_comma: false)
12
- super(instance, nil)
13
- @selectors = selectors
14
- @and_comma = and_comma
15
- end
16
-
17
- # The rewritten code, always empty string.
18
- def rewritten_code
19
- ''
20
- end
21
-
22
- private
23
-
24
- # Calculate the begin and end positions.
25
- def calculate_position
26
- @begin_pos = @selectors.map { |selector| @node.child_node_range(selector) }
27
- .compact.map(&:begin_pos).min
28
- @end_pos = @selectors.map { |selector| @node.child_node_range(selector) }
29
- .compact.map(&:end_pos).max
30
- squeeze_spaces
31
- remove_comma if @and_comma
32
- end
33
- end
34
- end
@@ -1,34 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # InsertAction to add code to the node.
5
- class Rewriter::InsertAction < Rewriter::Action
6
- # Initialize an InsertAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param code [String] to be inserted
10
- # @param at [String] position to insert, beginning or end
11
- # @param to [<Symbol|String>] name of child node
12
- def initialize(instance, code, at: 'end', to: nil)
13
- super(instance, code)
14
- @at = at
15
- @to = to
16
- end
17
-
18
- # The rewritten source code.
19
- #
20
- # @return [String] rewritten code.
21
- def rewritten_code
22
- rewritten_source
23
- end
24
-
25
- private
26
-
27
- # Calculate the begin and end positions.
28
- def calculate_position
29
- node_range = @to ? @node.child_node_range(@to) : @node.loc.expression
30
- @begin_pos = @at == 'end' ? node_range.end_pos : node_range.begin_pos
31
- @end_pos = @begin_pos
32
- end
33
- end
34
- end
@@ -1,22 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # InsertAfterAction to insert code next to the node.
5
- class Rewriter::InsertAfterAction < Rewriter::Action
6
- private
7
-
8
- # Calculate the begin and end positions.
9
- def calculate_position
10
- @begin_pos = @node.loc.expression.end_pos
11
- @end_pos = @begin_pos
12
- end
13
-
14
- # Indent of the node.
15
- #
16
- # @param node [Parser::AST::Node]
17
- # @return [String] n times whitesphace
18
- def indent(node)
19
- ' ' * node.column
20
- end
21
- end
22
- end
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # PrependAction to prepend code to the top of node body.
5
- class Rewriter::PrependAction < Rewriter::Action
6
- private
7
-
8
- DO_LENGTH = ' do'.length
9
-
10
- # Calculate the begin and end positions.
11
- def calculate_position
12
- @begin_pos =
13
- case @node.type
14
- when :block
15
- if @node.children[1].children.empty?
16
- @node.children[0].loc.expression.end_pos + DO_LENGTH
17
- else
18
- @node.children[1].loc.expression.end_pos
19
- end
20
- when :class
21
- @node.children[1] ? @node.children[1].loc.expression.end_pos : @node.children[0].loc.expression.end_pos
22
- when :def
23
- @node.children[1].empty? ? @node.loc.name.end_pos : @node.children[1].loc.expression.end_pos
24
- when :defs
25
- @node.children[2].empty? ? @node.loc.name.end_pos : @node.children[2].loc.expression.end_pos
26
- else
27
- @node.children.last.loc.expression.end_pos
28
- end
29
- @end_pos = @begin_pos
30
- end
31
-
32
- # Indent of the node.
33
- #
34
- # @param node [Parser::AST::Node]
35
- # @return [String] n times whitesphace
36
- def indent(node)
37
- if %i[block class def defs].include?(node.type)
38
- ' ' * (node.column + DEFAULT_INDENT)
39
- else
40
- ' ' * node.column
41
- end
42
- end
43
- end
44
- end
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # RemoveAction to remove current node.
5
- class Rewriter::RemoveAction < Rewriter::Action
6
- # Initialize a RemoveAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::RemoveAction]
9
- # @param options [Hash] options.
10
- # @option and_comma [Boolean] delete extra comma.
11
- def initialize(instance, and_comma: false)
12
- super(instance, nil)
13
- @and_comma = and_comma
14
- end
15
-
16
- # The rewritten code, always empty string.
17
- def rewritten_code
18
- ''
19
- end
20
-
21
- private
22
-
23
- # Calculate the begin the end positions.
24
- def calculate_position
25
- if take_whole_line?
26
- @begin_pos = start_index
27
- @end_pos = end_index
28
- squeeze_lines
29
- else
30
- @begin_pos = @node.loc.expression.begin_pos
31
- @end_pos = @node.loc.expression.end_pos
32
- squeeze_spaces
33
- remove_comma if @and_command
34
- end
35
- end
36
-
37
- # Check if the source code of current node takes the whole line.
38
- #
39
- # @return [Boolean]
40
- def take_whole_line?
41
- @node.to_source == file_source[start_index...end_index].strip
42
- end
43
-
44
- # Get the start position of the line
45
- def start_index
46
- index = file_source[0..@node.loc.expression.begin_pos].rindex("\n")
47
- index ? index + "\n".length : @node.loc.expression.begin_pos
48
- end
49
-
50
- # Get the end position of the line
51
- def end_index
52
- index = file_source[@node.loc.expression.end_pos..-1].index("\n")
53
- index ? @node.loc.expression.end_pos + index + "\n".length : @node.loc.expression.end_pos
54
- end
55
- end
56
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # ReplaceAction to replace child node with code.
5
- class Rewriter::ReplaceAction < Rewriter::Action
6
- # Initailize a ReplaceAction.
7
- #
8
- # @param instance [Synvert::Core::Rewriter::Instance]
9
- # @param selectors [Array<Symbol|String>] used to select child nodes
10
- # @param with [String] the new code
11
- def initialize(instance, *selectors, with:)
12
- super(instance, with)
13
- @selectors = selectors
14
- end
15
-
16
- # The rewritten source code.
17
- #
18
- # @return [String] rewritten code.
19
- def rewritten_code
20
- rewritten_source
21
- end
22
-
23
- private
24
-
25
- # Calculate the begin the end positions.
26
- def calculate_position
27
- @begin_pos = @selectors.map { |selector| @node.child_node_range(selector).begin_pos }
28
- .min
29
- @end_pos = @selectors.map { |selector| @node.child_node_range(selector).end_pos }
30
- .max
31
- end
32
- end
33
- end
@@ -1,36 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # ReplaceWithAction to replace code.
5
- class Rewriter::ReplaceWithAction < Rewriter::Action
6
- # The rewritten source code with proper indent.
7
- #
8
- # @return [String] rewritten code.
9
- def rewritten_code
10
- if rewritten_source.include?("\n")
11
- new_code = []
12
- rewritten_source.split("\n").each_with_index do |line, index|
13
- new_code << (index == 0 ? line : indent + line)
14
- end
15
- new_code.join("\n")
16
- else
17
- rewritten_source
18
- end
19
- end
20
-
21
- private
22
-
23
- # Calculate the begin the end positions.
24
- def calculate_position
25
- @begin_pos = @node.loc.expression.begin_pos
26
- @end_pos = @node.loc.expression.end_pos
27
- end
28
-
29
- # Indent of the node
30
- #
31
- # @return [String] n times whitesphace
32
- def indent
33
- ' ' * @node.column
34
- end
35
- end
36
- end
@@ -1,37 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # WrapAction to warp node within a block, class or module.
5
- #
6
- # Note: if WrapAction is conflicted with another action (begin_pos and end_pos are overlapped),
7
- # we have to put those 2 actions into 2 within_file scopes.
8
- class Rewriter::WrapAction < Rewriter::Action
9
- # Initialize a WrapAction.
10
- #
11
- # @param instance [Synvert::Core::Rewriter::WrapAction]
12
- # @param with [String] new code to wrap
13
- # @param indent [Integer, nil] number of whitespaces
14
- def initialize(instance, with:, indent: nil)
15
- super(instance, with)
16
- @indent = indent || @node.column
17
- end
18
-
19
- # The rewritten source code.
20
- #
21
- # @return [String] rewritten code.
22
- def rewritten_code
23
- "#{@code}\n#{' ' * @indent}" +
24
- @node.to_source.split("\n").map { |line| " #{line}" }
25
- .join("\n") +
26
- "\n#{' ' * @indent}end"
27
- end
28
-
29
- private
30
-
31
- # Calculate the begin the end positions.
32
- def calculate_position
33
- @begin_pos = @node.loc.expression.begin_pos
34
- @end_pos = @node.loc.expression.end_pos
35
- end
36
- end
37
- end
@@ -1,102 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Synvert::Core
4
- # Action defines rewriter action, insert, replace or delete code.
5
- class Rewriter::Action
6
- DEFAULT_INDENT = 2
7
-
8
- # @!attribute [r] begin_pos
9
- # @return [Integer] begin position
10
- # @!attribute [r] end_pos
11
- # @return [Integer] end position
12
- attr_reader :begin_pos, :end_pos
13
-
14
- # Initialize an action.
15
- #
16
- # @param instance [Synvert::Core::Rewriter::Instance]
17
- # @param code [String] new code to insert, replace or delete.
18
- def initialize(instance, code)
19
- @instance = instance
20
- @code = code
21
- @node = @instance.current_node
22
- end
23
-
24
- # Calculate begin and end positions, and return self.
25
- #
26
- # @return [Synvert::Core::Rewriter::Action] self
27
- def process
28
- calculate_position
29
- self
30
- end
31
-
32
- # The rewritten source code with proper indent.
33
- #
34
- # @return [String] rewritten code.
35
- def rewritten_code
36
- if rewritten_source.split("\n").length > 1
37
- "\n\n" + rewritten_source.split("\n").map { |line| indent(@node) + line }
38
- .join("\n")
39
- else
40
- "\n" + indent(@node) + rewritten_source
41
- end
42
- end
43
-
44
- protected
45
-
46
- # Calculate the begin the end positions.
47
- #
48
- # @abstract
49
- def calculate_position
50
- raise NotImplementedError, 'must be implemented by subclasses'
51
- end
52
-
53
- # The rewritten source code.
54
- #
55
- # @return [String] rewritten source code.
56
- def rewritten_source
57
- @rewritten_source ||= @node.rewritten_source(@code)
58
- end
59
-
60
- # Squeeze spaces from source code.
61
- def squeeze_spaces
62
- if file_source[@begin_pos - 1] == ' ' && file_source[@end_pos] == ' '
63
- @begin_pos -= 1
64
- end
65
- end
66
-
67
- # Squeeze empty lines from source code.
68
- def squeeze_lines
69
- lines = file_source.split("\n")
70
- begin_line = @node.loc.expression.first_line
71
- end_line = @node.loc.expression.last_line
72
- before_line_is_blank = begin_line == 1 || lines[begin_line - 2] == ''
73
- after_line_is_blank = lines[end_line] == ''
74
-
75
- if lines.length > 1 && before_line_is_blank && after_line_is_blank
76
- @end_pos += "\n".length
77
- end
78
- end
79
-
80
- # Remove unused comma.
81
- # e.g. `foobar(foo, bar)`, if we remove `foo`, the comma should also be removed,
82
- # the code should be changed to `foobar(bar)`.
83
- def remove_comma
84
- if ',' == file_source[@begin_pos - 1]
85
- @begin_pos -= 1
86
- elsif ', ' == file_source[@begin_pos - 2, 2]
87
- @begin_pos -= 2
88
- elsif ', ' == file_source[@end_pos, 2]
89
- @end_pos += 2
90
- elsif ',' == file_source[@end_pos]
91
- @end_pos += 1
92
- end
93
- end
94
-
95
- # Return file source.
96
- #
97
- # @return [String]
98
- def file_source
99
- @file_source ||= @instance.file_source
100
- end
101
- end
102
- end