node_mutation 1.16.0 → 1.17.1

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: 14e76d23c3a0be62554de359db928e7f0e70fe75b6c13ecb0655add5af735333
4
- data.tar.gz: 1777be0d1e8c4044fa175dcc8f9f9e3431283fdf039392cba9f8fe4fd656c676
3
+ metadata.gz: d7b6c582369f095034122ac0dc0d1cafaba27a86049bb80c36b1d8f50dc8876c
4
+ data.tar.gz: d81a61d2316dad6242b81df48b61752459638e44c03935af6f618b006f5fa339
5
5
  SHA512:
6
- metadata.gz: ef64c7156966a2d80c4bf823e0c3330d8934cf52306a9f179bac7105b52c82e78bb9b0d958510165a541fd1fe550b3eec7c7e78eaf3aa7f3207a5b0df1f9e4e3
7
- data.tar.gz: 969399df03dc8e3f5c15e55f37a3664bf0945a41e5ff244542319b8a2c20d6afff54dc3aee72b6b4e6c90c6ce84428b6008d14d3dc81e343c68296e78b387218
6
+ metadata.gz: 3f16a4e2b54ac9820c35e3d0bd31b2d3b6a23a08144e8a2486d8093fea95087e2b75a27924af69908ba4c6c6f88f0bcd56d5a9ea944fbb395ae422b18e0fff2b
7
+ data.tar.gz: e2a1ea1260c204562d957a7d756811c565212e56c6660d7e03c90b15341b03728859fa3158fce7d51ec50ad30cbb7c070606698b548b6f4fa3ca9fe73a27235c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # NodeMutation
2
2
 
3
+ ## 1.17.1 (2023-05-16)
4
+
5
+ * Require `parser` and `syntax_tree` in adapter
6
+
7
+ ## 1.17.0 (2023-05-15)
8
+
9
+ * Add `SyntaxTreeAdapter`
10
+
3
11
  ## 1.16.0 (2023-05-10)
4
12
 
5
13
  * Support {key}_value for a hash node
data/Gemfile CHANGED
@@ -11,5 +11,6 @@ gem "rspec", "~> 3.0"
11
11
 
12
12
  gem "parser"
13
13
  gem "parser_node_ext"
14
+ gem "syntax_tree_ext"
14
15
  gem "guard"
15
16
  gem "guard-rspec"
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- node_mutation (1.16.0)
4
+ node_mutation (1.17.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -34,10 +34,11 @@ GEM
34
34
  notiffany (0.1.3)
35
35
  nenv (~> 0.1)
36
36
  shellany (~> 0.0)
37
- parser (3.2.1.0)
37
+ parser (3.2.2.1)
38
38
  ast (~> 2.4.1)
39
- parser_node_ext (1.0.0)
39
+ parser_node_ext (1.1.0)
40
40
  parser
41
+ prettier_print (1.2.1)
41
42
  pry (0.14.1)
42
43
  coderay (~> 1.1)
43
44
  method_source (~> 1.0)
@@ -59,6 +60,10 @@ GEM
59
60
  rspec-support (~> 3.11.0)
60
61
  rspec-support (3.11.0)
61
62
  shellany (0.0.1)
63
+ syntax_tree (6.1.1)
64
+ prettier_print (>= 1.2.0)
65
+ syntax_tree_ext (0.3.0)
66
+ syntax_tree
62
67
  thor (1.2.1)
63
68
 
64
69
  PLATFORMS
@@ -74,6 +79,7 @@ DEPENDENCIES
74
79
  parser_node_ext
75
80
  rake (~> 13.0)
76
81
  rspec (~> 3.0)
82
+ syntax_tree_ext
77
83
 
78
84
  BUNDLED WITH
79
85
  2.3.7
data/README.md CHANGED
@@ -74,7 +74,7 @@ we define an [Adapter](https://github.com/xinminlabs/node-mutation-ruby/blob/mai
74
74
  if you implement the Adapter interface, you can set it as NodeMutation's adapter.
75
75
 
76
76
  ```ruby
77
- NodeMutation.configure(adapter: ParserAdapter.new) // default is ParserAdapter
77
+ NodeMutation.configure(adapter: SyntaxTreeAdapter.new) // default is ParserAdapter
78
78
  ```
79
79
 
80
80
  ### strategy
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- INDEX_REGEXP = /\A-?\d+\z/
3
+ require 'parser'
4
+ require 'parser_node_ext'
4
5
 
5
6
  class NodeMutation::ParserAdapter < NodeMutation::Adapter
6
7
  def get_source(node)
@@ -111,24 +112,6 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
111
112
  NodeMutation::Struct::Range.new(node.loc.begin.begin_pos, node.loc.end.end_pos)
112
113
  end
113
114
  else
114
- if node.type == :hash && child_name.to_s.end_with?('_pair')
115
- pair_node = node.pairs.find { |pair| pair.key.to_value.to_s == child_name.to_s[0..-6] }
116
- raise NodeMutation::MethodNotSupported,
117
- "#{direct_child_name} is not supported for #{get_source(node)}" unless pair_node
118
- return child_node_range(pair, nested_child_name) if nested_child_name
119
-
120
- return NodeMutation::Struct::Range.new(pair_node.loc.expression.begin_pos, pair_node.loc.expression.end_pos)
121
- end
122
-
123
- if node.type == :hash && child_name.to_s.end_with?('_value')
124
- pair_node = node.pairs.find { |pair| pair.key.to_value.to_s == child_name.to_s[0..-7] }
125
- raise NodeMutation::MethodNotSupported,
126
- "#{direct_child_name} is not supported for #{get_source(node)}" unless pair_node
127
- return child_node_range(pair.value, nested_child_name) if nested_child_name
128
-
129
- return NodeMutation::Struct::Range.new(pair_node.value.loc.expression.begin_pos, pair_node.value.loc.expression.end_pos)
130
- end
131
-
132
115
  raise NodeMutation::MethodNotSupported,
133
116
  "#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
134
117
 
@@ -206,24 +189,6 @@ class NodeMutation::ParserAdapter < NodeMutation::Adapter
206
189
  return child_node
207
190
  end
208
191
 
209
- if node.is_a?(Parser::AST::Node) && node.type == :hash && direct_child_name.end_with?('_pair')
210
- pair_node = node.pairs.find { |pair| pair.key.to_value.to_s == direct_child_name[0..-6] }
211
- raise NodeMutation::MethodNotSupported,
212
- "#{direct_child_name} is not supported for #{get_source(node)}" unless pair_node
213
- return child_node_by_name(pair_node, nested_child_name) if nested_child_name
214
-
215
- return pair_node
216
- end
217
-
218
- if node.is_a?(Parser::AST::Node) && node.type == :hash && direct_child_name.end_with?('_value')
219
- pair_node = node.pairs.find { |pair| pair.key.to_value.to_s == direct_child_name[0..-7] }
220
- raise NodeMutation::MethodNotSupported,
221
- "#{direct_child_name} is not supported for #{get_source(node)}" unless pair_node
222
- return child_node_by_name(pair_node.value, nested_child_name) if nested_child_name
223
-
224
- return pair_node.value
225
- end
226
-
227
192
  if node.respond_to?(direct_child_name)
228
193
  child_node = node.send(direct_child_name)
229
194
  elsif direct_child_name.include?('(') && direct_child_name.include?(')')
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'syntax_tree'
4
+ require 'syntax_tree_ext'
5
+
6
+ class NodeMutation::SyntaxTreeAdapter < NodeMutation::Adapter
7
+ def get_source(node)
8
+ if node.is_a?(Array)
9
+ return node.first.source[node.first.location.start_char...node.last.location.end_char]
10
+ end
11
+
12
+ node.source[node.location.start_char...node.location.end_char]
13
+ end
14
+
15
+ def rewritten_source(node, code)
16
+ code.gsub(/{{(.+?)}}/m) do
17
+ old_code = Regexp.last_match(1)
18
+ evaluated = child_node_by_name(node, old_code)
19
+ case evaluated
20
+ when SyntaxTree::Node
21
+ get_source(evaluated)
22
+ when Array
23
+ if evaluated.size > 0
24
+ source = get_source(evaluated)
25
+ lines = source.split "\n"
26
+ lines_count = lines.length
27
+ if lines_count > 1 && lines_count == evaluated.size
28
+ new_code = []
29
+ lines.each_with_index { |line, index|
30
+ new_code << (index == 0 ? line : line[evaluated.first.indent - 2..-1])
31
+ }
32
+ new_code.join("\n")
33
+ else
34
+ source
35
+ end
36
+ end
37
+ when String, Symbol, Integer, Float
38
+ evaluated
39
+ when NilClass
40
+ ''
41
+ else
42
+ raise "can not parse \"#{code}\""
43
+ end
44
+ end
45
+ end
46
+
47
+ def child_node_range(node, child_name)
48
+ child_node = child_node_by_name(node, child_name)
49
+ return nil if child_node.nil?
50
+
51
+ if child_node.is_a?(Array)
52
+ return NodeMutation::Struct::Range.new(child_node.first.location.start_char, child_node.last.location.end_char)
53
+ end
54
+
55
+ return NodeMutation::Struct::Range.new(child_node.location.start_char, child_node.location.end_char)
56
+ end
57
+
58
+ def get_start(node, child_name = nil)
59
+ node = child_node_by_name(node, child_name) if child_name
60
+ node.location.start_char
61
+ end
62
+
63
+ def get_end(node, child_name = nil)
64
+ node = child_node_by_name(node, child_name) if child_name
65
+ node.location.end_char
66
+ end
67
+
68
+ def get_start_loc(node, child_name = nil)
69
+ node = child_node_by_name(node, child_name) if child_name
70
+ NodeMutation::Struct::Location.new(node.location.start_line, node.location.start_column)
71
+ end
72
+
73
+ def get_end_loc(node, child_name = nil)
74
+ node = child_node_by_name(node, child_name) if child_name
75
+ NodeMutation::Struct::Location.new(node.location.end_line, node.location.end_column)
76
+ end
77
+
78
+ def get_indent(node)
79
+ node.location.start_column
80
+ end
81
+
82
+ private
83
+
84
+ def child_node_by_name(node, child_name)
85
+ direct_child_name, nested_child_name = child_name.to_s.split('.', 2)
86
+
87
+ if node.is_a?(Array)
88
+ if direct_child_name =~ INDEX_REGEXP
89
+ child_node = node[direct_child_name.to_i]
90
+ raise NodeMutation::MethodNotSupported,
91
+ "#{direct_child_name} is not supported for #{get_source(node)}" unless child_node
92
+ return child_node_by_name(child_node, nested_child_name) if nested_child_name
93
+
94
+ return child_node
95
+ end
96
+
97
+ raise NodeMutation::MethodNotSupported,
98
+ "#{direct_child_name} is not supported for #{get_source(node)}" unless node.respond_to?(direct_child_name)
99
+
100
+ child_node = node.send(direct_child_name)
101
+ return child_node_by_name(child_node, nested_child_name) if nested_child_name
102
+
103
+ return child_node
104
+ end
105
+
106
+ if node.respond_to?(direct_child_name)
107
+ child_node = node.send(direct_child_name)
108
+ elsif direct_child_name.include?('(') && direct_child_name.include?(')')
109
+ child_node = node.instance_eval(direct_child_name)
110
+ else
111
+ raise NodeMutation::MethodNotSupported, "#{direct_child_name} is not supported for #{get_source(node)}"
112
+ end
113
+
114
+ return child_node_by_name(child_node, nested_child_name) if nested_child_name
115
+
116
+ child_node
117
+ end
118
+ end
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeMutation::Adapter
4
+ INDEX_REGEXP = /\A-?\d+\z/
5
+
4
6
  # Get source code of the ast node
5
7
  # @param node [Node] ast node
6
8
  # @return [String] source code
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class NodeMutation
4
- VERSION = "1.16.0"
4
+ VERSION = "1.17.1"
5
5
  end
data/lib/node_mutation.rb CHANGED
@@ -7,7 +7,8 @@ class NodeMutation
7
7
  class ConflictActionError < StandardError; end
8
8
 
9
9
  autoload :Adapter, "node_mutation/adapter"
10
- autoload :ParserAdapter, "node_mutation/parser_adapter"
10
+ autoload :ParserAdapter, "node_mutation/adapter/parser"
11
+ autoload :SyntaxTreeAdapter, "node_mutation/adapter/syntax_tree"
11
12
  autoload :Action, 'node_mutation/action'
12
13
  autoload :AppendAction, 'node_mutation/action/append_action'
13
14
  autoload :DeleteAction, 'node_mutation/action/delete_action'
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.16.0
4
+ version: 1.17.1
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-05-10 00:00:00.000000000 Z
11
+ date: 2023-05-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: ast node mutation apis
14
14
  email:
@@ -37,7 +37,8 @@ files:
37
37
  - lib/node_mutation/action/replace_action.rb
38
38
  - lib/node_mutation/action/replace_with_action.rb
39
39
  - lib/node_mutation/adapter.rb
40
- - lib/node_mutation/parser_adapter.rb
40
+ - lib/node_mutation/adapter/parser.rb
41
+ - lib/node_mutation/adapter/syntax_tree.rb
41
42
  - lib/node_mutation/result.rb
42
43
  - lib/node_mutation/strategy.rb
43
44
  - lib/node_mutation/struct.rb