synvert-core 1.4.0 → 1.6.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.
- checksums.yaml +4 -4
- data/.github/workflows/main.yml +0 -1
- data/.gitignore +0 -5
- data/CHANGELOG.md +12 -0
- data/Gemfile +0 -3
- data/Gemfile.lock +101 -0
- data/Guardfile +0 -9
- data/README.md +31 -13
- data/Rakefile +1 -15
- data/lib/synvert/core/engine/erb.rb +1 -1
- data/lib/synvert/core/engine.rb +1 -1
- data/lib/synvert/core/node_ext.rb +0 -639
- data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
- data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -5
- data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +1 -1
- data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -5
- data/lib/synvert/core/rewriter/condition.rb +5 -1
- data/lib/synvert/core/rewriter/instance.rb +91 -140
- data/lib/synvert/core/rewriter/scope/query_scope.rb +8 -6
- data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -87
- data/lib/synvert/core/rewriter.rb +0 -10
- data/lib/synvert/core/version.rb +1 -1
- data/lib/synvert/core.rb +4 -6
- data/spec/synvert/core/engine/erb_spec.rb +3 -3
- data/spec/synvert/core/node_ext_spec.rb +0 -965
- data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
- data/spec/synvert/core/rewriter/instance_spec.rb +64 -131
- data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
- data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -16
- data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +22 -13
- data/synvert-core-ruby.gemspec +5 -3
- metadata +46 -62
- data/lib/synvert/core/array_ext.rb +0 -48
- data/lib/synvert/core/node_query/compiler/array.rb +0 -34
- data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
- data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
- data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
- data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
- data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
- data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
- data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
- data/lib/synvert/core/node_query/compiler/float.rb +0 -23
- data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
- data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
- data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
- data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
- data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
- data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
- data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
- data/lib/synvert/core/node_query/compiler/string.rb +0 -23
- data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
- data/lib/synvert/core/node_query/compiler.rb +0 -25
- data/lib/synvert/core/node_query/lexer.rex +0 -99
- data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
- data/lib/synvert/core/node_query/parser.racc.rb +0 -306
- data/lib/synvert/core/node_query/parser.y +0 -60
- data/lib/synvert/core/node_query.rb +0 -36
- data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
- data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
- data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
- data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
- data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
- data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
- data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
- data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
- data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
- data/lib/synvert/core/rewriter/action.rb +0 -102
- data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
- data/spec/synvert/core/node_query/parser_spec.rb +0 -337
- data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
- data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
- data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
- data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
- data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
- data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
- data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
- data/spec/synvert/core/rewriter/action_spec.rb +0 -14
@@ -4,37 +4,40 @@ module Synvert::Core
|
|
4
4
|
# ReplaceErbStmtWithExprAction to replace erb stmt code to expr,
|
5
5
|
# @example
|
6
6
|
# e.g. <% form_for ... %> => <%= form_for ... %>.
|
7
|
-
class Rewriter::ReplaceErbStmtWithExprAction <
|
7
|
+
class Rewriter::ReplaceErbStmtWithExprAction < NodeMutation::Action
|
8
8
|
# Initialize a ReplaceErbStmtWithExprAction.
|
9
9
|
#
|
10
|
-
# @param
|
11
|
-
def initialize(
|
12
|
-
super(
|
10
|
+
# @param node [Synvert::Core::Rewriter::Node]
|
11
|
+
def initialize(node)
|
12
|
+
super(node, nil)
|
13
13
|
end
|
14
14
|
|
15
|
-
# The
|
15
|
+
# The new erb expr code.
|
16
16
|
#
|
17
|
-
# @return [String]
|
18
|
-
def
|
19
|
-
@node
|
20
|
-
|
21
|
-
|
17
|
+
# @return [String] new code.
|
18
|
+
def new_code
|
19
|
+
NodeMutation.adapter.file_content(@node)[@start...@end]
|
20
|
+
.sub(Engine::ERUBY_STMT_SPLITTER, '@output_buffer.append= ')
|
21
|
+
.sub(Engine::ERUBY_STMT_SPLITTER, Engine::ERUBY_EXPR_SPLITTER)
|
22
22
|
end
|
23
23
|
|
24
24
|
private
|
25
25
|
|
26
26
|
# Calculate the begin the end positions.
|
27
27
|
def calculate_position
|
28
|
-
|
29
|
-
|
28
|
+
node_start = NodeMutation.adapter.get_start(@node)
|
29
|
+
node_source = NodeMutation.adapter.get_source(@node)
|
30
|
+
file_content = NodeMutation.adapter.file_content(@node)
|
31
|
+
|
32
|
+
whitespace_index = node_start
|
33
|
+
while file_content[whitespace_index -= 1] == ' '
|
30
34
|
end
|
31
|
-
@
|
35
|
+
@start = whitespace_index - Engine::ERUBY_STMT_SPLITTER.length + 1
|
32
36
|
|
33
|
-
|
34
|
-
|
35
|
-
while @node.loc.expression.source_buffer.source[node_begin_pos += 1] != '@'
|
37
|
+
at_index = node_start + node_source.index('do')
|
38
|
+
while file_content[at_index += 1] != '@'
|
36
39
|
end
|
37
|
-
@
|
40
|
+
@end = at_index
|
38
41
|
end
|
39
42
|
end
|
40
43
|
end
|
@@ -9,11 +9,7 @@ module Synvert::Core
|
|
9
9
|
#
|
10
10
|
# @return [Boolean]
|
11
11
|
def match?
|
12
|
-
|
13
|
-
@instance.current_node.recursive_children do |child_node|
|
14
|
-
match ||= child_node&.match?(@rules)
|
15
|
-
end
|
16
|
-
match
|
12
|
+
@node_query.query_nodes(target_node, including_self: false, stop_at_first_match: true).size > 0
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
@@ -9,11 +9,7 @@ module Synvert::Core
|
|
9
9
|
#
|
10
10
|
# return [Boolean]
|
11
11
|
def match?
|
12
|
-
|
13
|
-
@instance.current_node.recursive_children do |child_node|
|
14
|
-
match ||= child_node&.match?(@rules)
|
15
|
-
end
|
16
|
-
!match
|
12
|
+
@node_query.query_nodes(target_node, including_self: false, stop_at_first_match: true).size == 0
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
@@ -10,7 +10,7 @@ module Synvert::Core
|
|
10
10
|
# @yield run when condition matches
|
11
11
|
def initialize(instance, rules, &block)
|
12
12
|
@instance = instance
|
13
|
-
@
|
13
|
+
@node_query = NodeQuery.new(rules)
|
14
14
|
@block = block
|
15
15
|
end
|
16
16
|
|
@@ -27,5 +27,9 @@ module Synvert::Core
|
|
27
27
|
def match?
|
28
28
|
raise NotImplementedError, 'must be implemented by subclasses'
|
29
29
|
end
|
30
|
+
|
31
|
+
def target_node
|
32
|
+
@instance.current_node
|
33
|
+
end
|
30
34
|
end
|
31
35
|
end
|
@@ -20,66 +20,13 @@ module Synvert::Core
|
|
20
20
|
rewriter.helpers.each { |helper| singleton_class.send(:define_method, helper[:name], &helper[:block]) }
|
21
21
|
end
|
22
22
|
|
23
|
-
class << self
|
24
|
-
# Get file source.
|
25
|
-
#
|
26
|
-
# @param file_path [String] file path
|
27
|
-
# @return [String] file source
|
28
|
-
def file_source(file_path)
|
29
|
-
@file_source ||= {}
|
30
|
-
@file_source[file_path] ||=
|
31
|
-
begin
|
32
|
-
source = File.read(file_path, encoding: 'UTF-8')
|
33
|
-
source = Engine::ERB.encode(source) if /\.erb$/.match?(file_path)
|
34
|
-
source
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# Get file ast.
|
39
|
-
#
|
40
|
-
# @param file_path [String] file path
|
41
|
-
# @return [String] ast node for file
|
42
|
-
def file_ast(file_path)
|
43
|
-
@file_ast ||= {}
|
44
|
-
@file_ast[file_path] ||=
|
45
|
-
begin
|
46
|
-
buffer = Parser::Source::Buffer.new file_path
|
47
|
-
buffer.source = file_source(file_path)
|
48
|
-
|
49
|
-
parser = Parser::CurrentRuby.new
|
50
|
-
parser.reset
|
51
|
-
parser.parse buffer
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
# Write source to file and remove cached file source and ast.
|
56
|
-
#
|
57
|
-
# @param file_path [String] file path
|
58
|
-
# @param source [String] file source
|
59
|
-
def write_file(file_path, source)
|
60
|
-
source = Engine::ERB.decode(source) if /\.erb/.match?(file_path)
|
61
|
-
File.write(file_path, source.gsub(/ +\n/, "\n"))
|
62
|
-
@file_source[file_path] = nil
|
63
|
-
@file_ast[file_path] = nil
|
64
|
-
end
|
65
|
-
|
66
|
-
# Reset file source and ast.
|
67
|
-
def reset
|
68
|
-
@file_source = {}
|
69
|
-
@file_ast = {}
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
23
|
# @!attribute [rw] current_node
|
74
24
|
# @return current parsing node
|
75
25
|
# @!attribute [rw] current_file
|
76
26
|
# @return current filename
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
def file_source
|
81
|
-
self.class.file_source(current_file)
|
82
|
-
end
|
27
|
+
# @!attribute [rw] current_mutation
|
28
|
+
# @return current mutation
|
29
|
+
attr_accessor :current_node, :current_file, :current_mutation
|
83
30
|
|
84
31
|
# Process the instance.
|
85
32
|
# It finds specified files, for each file, it executes the block code, rewrites the original code,
|
@@ -132,11 +79,13 @@ module Synvert::Core
|
|
132
79
|
# # matches FactoryBot.create(:user)
|
133
80
|
# find_node '.send[receiver=FactoryBot][message=create][arguments.size=1]' do
|
134
81
|
# end
|
135
|
-
# @param
|
82
|
+
# @param nql [String] node query language to find matching ast nodes.
|
136
83
|
# @yield run on the matching nodes.
|
137
84
|
# @raise [Synvert::Core::NodeQuery::Compiler::ParseError] if query string is invalid.
|
138
|
-
def find_node(
|
139
|
-
Rewriter::QueryScope.new(self,
|
85
|
+
def find_node(nql, options = {}, &block)
|
86
|
+
Rewriter::QueryScope.new(self, nql, options, &block).process
|
87
|
+
rescue NodeQueryLexer::ScanError, Racc::ParseError => e
|
88
|
+
raise NodeQuery::Compiler::ParseError, "Invalid query string: #{nql}"
|
140
89
|
end
|
141
90
|
|
142
91
|
# Parse +within_node+ dsl, it creates a {Synvert::Core::Rewriter::WithinScope} to recursively find matching ast nodes,
|
@@ -147,12 +96,11 @@ module Synvert::Core
|
|
147
96
|
# end
|
148
97
|
# @param rules [Hash] rules to find mathing ast nodes.
|
149
98
|
# @param options [Hash] optional
|
150
|
-
# @option
|
151
|
-
# @option
|
99
|
+
# @option including_self [Boolean] set if query the current node, default is true
|
100
|
+
# @option stop_at_first_match [Boolean] set if stop at first match, default is false
|
101
|
+
# @option recursive [Boolean] set if recursively query child nodes, default is true
|
152
102
|
# @yield run on the matching nodes.
|
153
103
|
def within_node(rules, options = {}, &block)
|
154
|
-
options[:stop_when_match] ||= false
|
155
|
-
options[:direct] ||= false
|
156
104
|
Rewriter::WithinScope.new(self, rules, options, &block).process
|
157
105
|
end
|
158
106
|
|
@@ -231,7 +179,7 @@ module Synvert::Core
|
|
231
179
|
# end
|
232
180
|
# @param code [String] code need to be appended.
|
233
181
|
def append(code)
|
234
|
-
@
|
182
|
+
@current_mutation.append(@current_node, code)
|
235
183
|
end
|
236
184
|
|
237
185
|
# Parse +prepend+ dsl, it creates a {Synvert::Core::Rewriter::PrependAction} to
|
@@ -250,7 +198,7 @@ module Synvert::Core
|
|
250
198
|
# end
|
251
199
|
# @param code [String] code need to be prepended.
|
252
200
|
def prepend(code)
|
253
|
-
@
|
201
|
+
@current_mutation.prepend(@current_node, code)
|
254
202
|
end
|
255
203
|
|
256
204
|
# Parse +insert+ dsl, it creates a {Synvert::Core::Rewriter::InsertAction} to insert code.
|
@@ -265,7 +213,7 @@ module Synvert::Core
|
|
265
213
|
# @param at [String] insert position, beginning or end
|
266
214
|
# @param to [String] where to insert, if it is nil, will insert to current node.
|
267
215
|
def insert(code, at: 'end', to: nil)
|
268
|
-
@
|
216
|
+
@current_mutation.insert(@current_node, code, at: at, to: to)
|
269
217
|
end
|
270
218
|
|
271
219
|
# Parse +insert_after+ dsl, it creates a {Synvert::Core::Rewriter::InsertAfterAction} to
|
@@ -280,7 +228,22 @@ module Synvert::Core
|
|
280
228
|
# end
|
281
229
|
# @param code [String] code need to be inserted.
|
282
230
|
def insert_after(code)
|
283
|
-
@
|
231
|
+
@current_mutation.insert_after(@current_node, code)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Parse +replace_erb_stmt_with_expr+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceErbStmtWithExprAction} to
|
235
|
+
# replace erb stmt code to expr code.
|
236
|
+
# @example
|
237
|
+
# # <% form_for post do |f| %>
|
238
|
+
# # <% end %>
|
239
|
+
# # =>
|
240
|
+
# # <%= form_for post do |f| %>
|
241
|
+
# # <% end %>
|
242
|
+
# with_node type: 'block', caller: { type: 'send', receiver: nil, message: 'form_for' } do
|
243
|
+
# replace_erb_stmt_with_expr
|
244
|
+
# end
|
245
|
+
def replace_erb_stmt_with_expr
|
246
|
+
@current_mutation.actions << Rewriter::ReplaceErbStmtWithExprAction.new(@current_node).process
|
284
247
|
end
|
285
248
|
|
286
249
|
# Parse +replace_with+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceWithAction} to
|
@@ -294,7 +257,7 @@ module Synvert::Core
|
|
294
257
|
# end
|
295
258
|
# @param code [String] code need to be replaced with.
|
296
259
|
def replace_with(code)
|
297
|
-
@
|
260
|
+
@current_mutation.replace_with(@current_node, code)
|
298
261
|
end
|
299
262
|
|
300
263
|
# Parse +replace+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceAction} to
|
@@ -310,22 +273,7 @@ module Synvert::Core
|
|
310
273
|
# @param selectors [Array<Symbol>] selector names of child node.
|
311
274
|
# @param with [String] code need to be replaced with.
|
312
275
|
def replace(*selectors, with:)
|
313
|
-
@
|
314
|
-
end
|
315
|
-
|
316
|
-
# Parse +replace_erb_stmt_with_expr+ dsl, it creates a {Synvert::Core::Rewriter::ReplaceErbStmtWithExprAction} to
|
317
|
-
# replace erb stmt code to expr code.
|
318
|
-
# @example
|
319
|
-
# # <% form_for post do |f| %>
|
320
|
-
# # <% end %>
|
321
|
-
# # =>
|
322
|
-
# # <%= form_for post do |f| %>
|
323
|
-
# # <% end %>
|
324
|
-
# with_node type: 'block', caller: { type: 'send', receiver: nil, message: 'form_for' } do
|
325
|
-
# replace_erb_stmt_with_expr
|
326
|
-
# end
|
327
|
-
def replace_erb_stmt_with_expr
|
328
|
-
@actions << Rewriter::ReplaceErbStmtWithExprAction.new(self).process
|
276
|
+
@current_mutation.replace(@current_node, *selectors, with: with)
|
329
277
|
end
|
330
278
|
|
331
279
|
# Parse +remove+ dsl, it creates a {Synvert::Core::Rewriter::RemoveAction} to remove current node.
|
@@ -336,7 +284,7 @@ module Synvert::Core
|
|
336
284
|
# @param options [Hash] options.
|
337
285
|
# @option and_comma [Boolean] delete extra comma.
|
338
286
|
def remove(**options)
|
339
|
-
@
|
287
|
+
@current_mutation.remove(@current_node, **options)
|
340
288
|
end
|
341
289
|
|
342
290
|
# Parse +delete+ dsl, it creates a {Synvert::Core::Rewriter::DeleteAction} to delete child nodes.
|
@@ -351,7 +299,7 @@ module Synvert::Core
|
|
351
299
|
# @param options [Hash]
|
352
300
|
# @option and_comma [Boolean] delete extra comma.
|
353
301
|
def delete(*selectors, **options)
|
354
|
-
@
|
302
|
+
@current_mutation.delete(@current_node, *selectors, **options)
|
355
303
|
end
|
356
304
|
|
357
305
|
# Parse +wrap+ dsl, it creates a {Synvert::Core::Rewriter::WrapAction} to
|
@@ -368,9 +316,8 @@ module Synvert::Core
|
|
368
316
|
# wrap with: 'module Synvert'
|
369
317
|
# end
|
370
318
|
# @param with [String] code need to be wrapped with.
|
371
|
-
|
372
|
-
|
373
|
-
@actions << Rewriter::WrapAction.new(self, with: with, indent: indent).process
|
319
|
+
def wrap(with:)
|
320
|
+
@current_mutation.wrap(@current_node, with: with)
|
374
321
|
end
|
375
322
|
|
376
323
|
# Parse +warn+ dsl, it creates a {Synvert::Core::Rewriter::Warning} to save warning message.
|
@@ -397,65 +344,69 @@ module Synvert::Core
|
|
397
344
|
#
|
398
345
|
# @param file_path [String]
|
399
346
|
def process_file(file_path)
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
source[action.begin_pos...action.end_pos] = action.rewritten_code
|
347
|
+
puts file_path if Configuration.show_run_process
|
348
|
+
|
349
|
+
@current_file = file_path
|
350
|
+
while true
|
351
|
+
source = read_source(file_path)
|
352
|
+
@current_mutation = NodeMutation.new(source)
|
353
|
+
begin
|
354
|
+
node = parse_code(file_path, source)
|
355
|
+
|
356
|
+
process_with_node(node) do
|
357
|
+
instance_eval(&@block)
|
358
|
+
rescue NoMethodError => e
|
359
|
+
puts [
|
360
|
+
"error: #{e.message}",
|
361
|
+
"file: #{file_path}",
|
362
|
+
"source: #{source}",
|
363
|
+
"line: #{current_node.line}"
|
364
|
+
].join("\n")
|
365
|
+
raise
|
420
366
|
end
|
421
|
-
@actions = []
|
422
367
|
|
423
|
-
|
368
|
+
result = @current_mutation.process
|
369
|
+
if result.affected?
|
370
|
+
@rewriter.add_affected_file(file_path)
|
371
|
+
write_source(file_path, result.new_source)
|
372
|
+
end
|
373
|
+
break unless result.conflicted?
|
374
|
+
rescue Parser::SyntaxError
|
375
|
+
puts "[Warn] file #{file_path} was not parsed correctly."
|
376
|
+
# do nothing, iterate next file
|
424
377
|
end
|
425
|
-
|
426
|
-
puts "[Warn] file #{file_path} was not parsed correctly."
|
427
|
-
# do nothing, iterate next file
|
428
|
-
end while !conflict_actions.empty?
|
378
|
+
end
|
429
379
|
end
|
430
380
|
|
431
|
-
#
|
432
|
-
#
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
end
|
447
|
-
j -= 1
|
448
|
-
end
|
449
|
-
conflict_actions
|
381
|
+
# Read file source.
|
382
|
+
# @param file_path [String] file path
|
383
|
+
# @return [String] file source
|
384
|
+
def read_source(file_path)
|
385
|
+
source = File.read(file_path, encoding: 'UTF-8')
|
386
|
+
source = Engine::Erb.encode(source) if /\.erb$/.match?(file_path)
|
387
|
+
source
|
388
|
+
end
|
389
|
+
|
390
|
+
# Write file source to file.
|
391
|
+
# @param file_path [String] file path
|
392
|
+
# @param source [String] file source
|
393
|
+
def write_source(file_path, source)
|
394
|
+
source = Engine::Erb.decode(source) if /\.erb/.match?(file_path)
|
395
|
+
File.write(file_path, source.gsub(/ +\n/, "\n"))
|
450
396
|
end
|
451
397
|
|
452
|
-
#
|
398
|
+
# Parse code ast node.
|
453
399
|
#
|
454
|
-
# @param file_path [String]
|
455
|
-
# @param
|
456
|
-
|
457
|
-
|
458
|
-
|
400
|
+
# @param file_path [String] file path
|
401
|
+
# @param file_path [String] file path
|
402
|
+
# @return [Node] ast node for file
|
403
|
+
def parse_code(file_path, source)
|
404
|
+
buffer = Parser::Source::Buffer.new file_path
|
405
|
+
buffer.source = source
|
406
|
+
|
407
|
+
parser = Parser::CurrentRuby.new
|
408
|
+
parser.reset
|
409
|
+
parser.parse buffer
|
459
410
|
end
|
460
411
|
end
|
461
412
|
end
|
@@ -6,11 +6,14 @@ module Synvert::Core
|
|
6
6
|
# Initialize a QueryScope.
|
7
7
|
#
|
8
8
|
# @param instance [Synvert::Core::Rewriter::Instance]
|
9
|
-
# @param
|
9
|
+
# @param nql [String]
|
10
|
+
# @param options [Hash]
|
10
11
|
# @yield run on all matching nodes
|
11
|
-
def initialize(instance,
|
12
|
+
def initialize(instance, nql, options = {}, &block)
|
12
13
|
super(instance, &block)
|
13
|
-
|
14
|
+
|
15
|
+
@options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
16
|
+
@node_query = NodeQuery.new(nql)
|
14
17
|
end
|
15
18
|
|
16
19
|
# Find out the matching nodes.
|
@@ -22,15 +25,14 @@ module Synvert::Core
|
|
22
25
|
current_node = @instance.current_node
|
23
26
|
return unless current_node
|
24
27
|
|
28
|
+
matching_nodes = @node_query.query_nodes(current_node, @options)
|
25
29
|
@instance.process_with_node(current_node) do
|
26
|
-
|
30
|
+
matching_nodes.each do |node|
|
27
31
|
@instance.process_with_node(node) do
|
28
32
|
@instance.instance_eval(&@block)
|
29
33
|
end
|
30
34
|
end
|
31
35
|
end
|
32
|
-
rescue NodeQuery::Lexer::ScanError, Racc::ParseError => e
|
33
|
-
raise NodeQuery::Compiler::ParseError, "Invalid query string: #{@query_string}"
|
34
36
|
end
|
35
37
|
end
|
36
38
|
end
|
@@ -11,8 +11,9 @@ module Synvert::Core
|
|
11
11
|
# @yield run on all matching nodes
|
12
12
|
def initialize(instance, rules, options = {}, &block)
|
13
13
|
super(instance, &block)
|
14
|
-
|
15
|
-
@options = options
|
14
|
+
|
15
|
+
@options = { including_self: true, stop_at_first_match: false, recursive: true }.merge(options)
|
16
|
+
@node_query = NodeQuery.new(rules)
|
16
17
|
end
|
17
18
|
|
18
19
|
# Find out the matching nodes.
|
@@ -22,14 +23,7 @@ module Synvert::Core
|
|
22
23
|
current_node = @instance.current_node
|
23
24
|
return unless current_node
|
24
25
|
|
25
|
-
matching_nodes =
|
26
|
-
if @options[:direct]
|
27
|
-
find_direct_matching_nodes(current_node)
|
28
|
-
elsif @options[:stop_when_match]
|
29
|
-
find_matching_nodes(current_node)
|
30
|
-
else
|
31
|
-
find_recursive_matching_nodes(current_node)
|
32
|
-
end
|
26
|
+
matching_nodes = @node_query.query_nodes(current_node, @options)
|
33
27
|
@instance.process_with_node current_node do
|
34
28
|
matching_nodes.each do |matching_node|
|
35
29
|
@instance.process_with_node matching_node do
|
@@ -38,82 +32,5 @@ module Synvert::Core
|
|
38
32
|
end
|
39
33
|
end
|
40
34
|
end
|
41
|
-
|
42
|
-
private
|
43
|
-
|
44
|
-
# Find the matching nodes only in current or direct children.
|
45
|
-
#
|
46
|
-
# @param current_node [Parser::AST::Node]
|
47
|
-
def find_direct_matching_nodes(current_node)
|
48
|
-
matching_nodes = []
|
49
|
-
if current_node.is_a?(Parser::AST::Node)
|
50
|
-
if current_node.type == :begin
|
51
|
-
current_node.children.each do |child_node|
|
52
|
-
matching_nodes << child_node if child_node.match?(@rules)
|
53
|
-
end
|
54
|
-
elsif current_node.match?(@rules)
|
55
|
-
matching_nodes << current_node
|
56
|
-
end
|
57
|
-
else
|
58
|
-
current_node.each do |child_node|
|
59
|
-
matching_nodes << child_node if child_node.match?(@rules)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
matching_nodes
|
63
|
-
end
|
64
|
-
|
65
|
-
# Find matching nodes in all recursive children.
|
66
|
-
#
|
67
|
-
# @param current_node [Parser::AST::Node]
|
68
|
-
def find_recursive_matching_nodes(current_node)
|
69
|
-
matching_nodes = []
|
70
|
-
if current_node.is_a?(Parser::AST::Node)
|
71
|
-
matching_nodes << current_node if current_node.match?(@rules)
|
72
|
-
current_node.recursive_children do |child_node|
|
73
|
-
matching_nodes << child_node if child_node.match?(@rules)
|
74
|
-
end
|
75
|
-
else
|
76
|
-
current_node.each do |node|
|
77
|
-
matching_nodes << node if node.match?(@rules)
|
78
|
-
node.recursive_children do |child_node|
|
79
|
-
matching_nodes << child_node if child_node.match?(@rules)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
matching_nodes
|
84
|
-
end
|
85
|
-
|
86
|
-
# Find matching nodes in recursive children but do not continue on matching nodes.
|
87
|
-
#
|
88
|
-
# @param current_node [Parser::AST::Node]
|
89
|
-
def find_matching_nodes(current_node)
|
90
|
-
matching_nodes = []
|
91
|
-
if current_node.is_a?(Parser::AST::Node)
|
92
|
-
if current_node.match?(@rules)
|
93
|
-
matching_nodes << current_node
|
94
|
-
return matching_nodes
|
95
|
-
end
|
96
|
-
current_node.recursive_children do |child_node|
|
97
|
-
if child_node.match?(@rules)
|
98
|
-
matching_nodes << child_node
|
99
|
-
next :stop
|
100
|
-
end
|
101
|
-
end
|
102
|
-
else
|
103
|
-
current_node.each do |node|
|
104
|
-
if node.match?(@rules)
|
105
|
-
matching_nodes << node
|
106
|
-
next
|
107
|
-
end
|
108
|
-
node.recursive_children do |child_node|
|
109
|
-
if child_node.match?(@rules)
|
110
|
-
matching_nodes << child_node
|
111
|
-
next :stop
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
matching_nodes
|
117
|
-
end
|
118
35
|
end
|
119
36
|
end
|
@@ -8,17 +8,7 @@ module Synvert::Core
|
|
8
8
|
# One Rewriter checks if the depndency version matches, and it can contain one or many {Synvert::Core::Rewriter::Instance},
|
9
9
|
# which define the behavior what files and what codes to detect and rewrite to what code.
|
10
10
|
class Rewriter
|
11
|
-
autoload :Action, 'synvert/core/rewriter/action'
|
12
|
-
autoload :AppendAction, 'synvert/core/rewriter/action/append_action'
|
13
|
-
autoload :DeleteAction, 'synvert/core/rewriter/action/delete_action'
|
14
|
-
autoload :InsertAction, 'synvert/core/rewriter/action/insert_action'
|
15
|
-
autoload :InsertAfterAction, 'synvert/core/rewriter/action/insert_after_action'
|
16
|
-
autoload :RemoveAction, 'synvert/core/rewriter/action/remove_action'
|
17
|
-
autoload :PrependAction, 'synvert/core/rewriter/action/prepend_action'
|
18
|
-
autoload :ReplaceAction, 'synvert/core/rewriter/action/replace_action'
|
19
11
|
autoload :ReplaceErbStmtWithExprAction, 'synvert/core/rewriter/action/replace_erb_stmt_with_expr_action'
|
20
|
-
autoload :ReplaceWithAction, 'synvert/core/rewriter/action/replace_with_action'
|
21
|
-
autoload :WrapAction, 'synvert/core/rewriter/action/wrap_action'
|
22
12
|
|
23
13
|
autoload :Warning, 'synvert/core/rewriter/warning'
|
24
14
|
|
data/lib/synvert/core/version.rb
CHANGED
data/lib/synvert/core.rb
CHANGED
@@ -4,14 +4,13 @@ require 'synvert/core/version'
|
|
4
4
|
require 'bundler'
|
5
5
|
require 'parser'
|
6
6
|
require 'parser/current'
|
7
|
-
require '
|
7
|
+
require 'parser_node_ext'
|
8
|
+
require_relative './core/node_ext'
|
8
9
|
require 'active_support'
|
9
|
-
require 'active_support/core_ext/object'
|
10
|
-
require 'active_support/core_ext/array'
|
11
10
|
require 'erubis'
|
12
11
|
require 'set'
|
13
|
-
require '
|
14
|
-
require '
|
12
|
+
require 'node_query'
|
13
|
+
require 'node_mutation'
|
15
14
|
|
16
15
|
module Synvert
|
17
16
|
module Core
|
@@ -20,7 +19,6 @@ module Synvert
|
|
20
19
|
autoload :Engine, 'synvert/core/engine'
|
21
20
|
autoload :RewriterNotFound, 'synvert/core/exceptions'
|
22
21
|
autoload :MethodNotSupported, 'synvert/core/exceptions'
|
23
|
-
autoload :NodeQuery, 'synvert/core/node_query'
|
24
22
|
end
|
25
23
|
end
|
26
24
|
|