node_mutation 1.16.0 → 1.17.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 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