synvert-core 1.4.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/main.yml +0 -1
  3. data/.gitignore +0 -5
  4. data/CHANGELOG.md +12 -0
  5. data/Gemfile +0 -3
  6. data/Gemfile.lock +101 -0
  7. data/Guardfile +0 -9
  8. data/README.md +31 -13
  9. data/Rakefile +1 -15
  10. data/lib/synvert/core/engine/erb.rb +1 -1
  11. data/lib/synvert/core/engine.rb +1 -1
  12. data/lib/synvert/core/node_ext.rb +0 -639
  13. data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +20 -17
  14. data/lib/synvert/core/rewriter/condition/if_exist_condition.rb +1 -5
  15. data/lib/synvert/core/rewriter/condition/if_only_exist_condition.rb +1 -1
  16. data/lib/synvert/core/rewriter/condition/unless_exist_condition.rb +1 -5
  17. data/lib/synvert/core/rewriter/condition.rb +5 -1
  18. data/lib/synvert/core/rewriter/instance.rb +91 -140
  19. data/lib/synvert/core/rewriter/scope/query_scope.rb +8 -6
  20. data/lib/synvert/core/rewriter/scope/within_scope.rb +4 -87
  21. data/lib/synvert/core/rewriter.rb +0 -10
  22. data/lib/synvert/core/version.rb +1 -1
  23. data/lib/synvert/core.rb +4 -6
  24. data/spec/synvert/core/engine/erb_spec.rb +3 -3
  25. data/spec/synvert/core/node_ext_spec.rb +0 -965
  26. data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +21 -1
  27. data/spec/synvert/core/rewriter/instance_spec.rb +64 -131
  28. data/spec/synvert/core/rewriter/scope/goto_scope_spec.rb +1 -4
  29. data/spec/synvert/core/rewriter/scope/query_scope_spec.rb +1 -16
  30. data/spec/synvert/core/rewriter/scope/within_scope_spec.rb +22 -13
  31. data/synvert-core-ruby.gemspec +5 -3
  32. metadata +46 -62
  33. data/lib/synvert/core/array_ext.rb +0 -48
  34. data/lib/synvert/core/node_query/compiler/array.rb +0 -34
  35. data/lib/synvert/core/node_query/compiler/attribute.rb +0 -39
  36. data/lib/synvert/core/node_query/compiler/attribute_list.rb +0 -24
  37. data/lib/synvert/core/node_query/compiler/basic_selector.rb +0 -28
  38. data/lib/synvert/core/node_query/compiler/boolean.rb +0 -23
  39. data/lib/synvert/core/node_query/compiler/comparable.rb +0 -86
  40. data/lib/synvert/core/node_query/compiler/dynamic_attribute.rb +0 -51
  41. data/lib/synvert/core/node_query/compiler/expression.rb +0 -41
  42. data/lib/synvert/core/node_query/compiler/float.rb +0 -23
  43. data/lib/synvert/core/node_query/compiler/identifier.rb +0 -41
  44. data/lib/synvert/core/node_query/compiler/integer.rb +0 -23
  45. data/lib/synvert/core/node_query/compiler/invalid_operator_error.rb +0 -7
  46. data/lib/synvert/core/node_query/compiler/nil.rb +0 -23
  47. data/lib/synvert/core/node_query/compiler/parse_error.rb +0 -7
  48. data/lib/synvert/core/node_query/compiler/regexp.rb +0 -37
  49. data/lib/synvert/core/node_query/compiler/selector.rb +0 -113
  50. data/lib/synvert/core/node_query/compiler/string.rb +0 -23
  51. data/lib/synvert/core/node_query/compiler/symbol.rb +0 -23
  52. data/lib/synvert/core/node_query/compiler.rb +0 -25
  53. data/lib/synvert/core/node_query/lexer.rex +0 -99
  54. data/lib/synvert/core/node_query/lexer.rex.rb +0 -299
  55. data/lib/synvert/core/node_query/parser.racc.rb +0 -306
  56. data/lib/synvert/core/node_query/parser.y +0 -60
  57. data/lib/synvert/core/node_query.rb +0 -36
  58. data/lib/synvert/core/rewriter/action/append_action.rb +0 -28
  59. data/lib/synvert/core/rewriter/action/delete_action.rb +0 -34
  60. data/lib/synvert/core/rewriter/action/insert_action.rb +0 -34
  61. data/lib/synvert/core/rewriter/action/insert_after_action.rb +0 -22
  62. data/lib/synvert/core/rewriter/action/prepend_action.rb +0 -44
  63. data/lib/synvert/core/rewriter/action/remove_action.rb +0 -56
  64. data/lib/synvert/core/rewriter/action/replace_action.rb +0 -33
  65. data/lib/synvert/core/rewriter/action/replace_with_action.rb +0 -36
  66. data/lib/synvert/core/rewriter/action/wrap_action.rb +0 -37
  67. data/lib/synvert/core/rewriter/action.rb +0 -102
  68. data/spec/synvert/core/node_query/lexer_spec.rb +0 -580
  69. data/spec/synvert/core/node_query/parser_spec.rb +0 -337
  70. data/spec/synvert/core/rewriter/action/append_action_spec.rb +0 -70
  71. data/spec/synvert/core/rewriter/action/delete_action_spec.rb +0 -26
  72. data/spec/synvert/core/rewriter/action/insert_action_spec.rb +0 -70
  73. data/spec/synvert/core/rewriter/action/insert_after_action_spec.rb +0 -26
  74. data/spec/synvert/core/rewriter/action/prepend_action_spec.rb +0 -175
  75. data/spec/synvert/core/rewriter/action/remove_action_spec.rb +0 -26
  76. data/spec/synvert/core/rewriter/action/replace_action_spec.rb +0 -28
  77. data/spec/synvert/core/rewriter/action/replace_with_action_spec.rb +0 -59
  78. data/spec/synvert/core/rewriter/action/wrap_action_spec.rb +0 -31
  79. 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 < Rewriter::Action
7
+ class Rewriter::ReplaceErbStmtWithExprAction < NodeMutation::Action
8
8
  # Initialize a ReplaceErbStmtWithExprAction.
9
9
  #
10
- # @param instance [Synvert::Core::Rewriter::Instance]
11
- def initialize(instance)
12
- super(instance, nil)
10
+ # @param node [Synvert::Core::Rewriter::Node]
11
+ def initialize(node)
12
+ super(node, nil)
13
13
  end
14
14
 
15
- # The rewritten erb expr code.
15
+ # The new erb expr code.
16
16
  #
17
- # @return [String] rewritten code.
18
- def rewritten_code
19
- @node.loc.expression.source_buffer.source[begin_pos...end_pos]
20
- .sub(Engine::ERUBY_STMT_SPLITTER, '@output_buffer.append= ')
21
- .sub(Engine::ERUBY_STMT_SPLITTER, Engine::ERUBY_EXPR_SPLITTER)
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
- node_begin_pos = @node.loc.expression.begin_pos
29
- while @node.loc.expression.source_buffer.source[node_begin_pos -= 1] == ' '
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
- @begin_pos = node_begin_pos - Engine::ERUBY_STMT_SPLITTER.length + 1
35
+ @start = whitespace_index - Engine::ERUBY_STMT_SPLITTER.length + 1
32
36
 
33
- node_begin_pos = @node.loc.expression.begin_pos
34
- node_begin_pos += @node.loc.expression.source.index 'do'
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
- @end_pos = node_begin_pos
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
- match = false
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,7 +9,7 @@ module Synvert::Core
9
9
  #
10
10
  # @return [Boolean]
11
11
  def match?
12
- @instance.current_node.body.size == 1 && @instance.current_node.body.first.match?(@rules)
12
+ target_node.body.size == 1 && @node_query.match_node?(target_node.body.first)
13
13
  end
14
14
  end
15
15
  end
@@ -9,11 +9,7 @@ module Synvert::Core
9
9
  #
10
10
  # return [Boolean]
11
11
  def match?
12
- match = false
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
- @rules = rules
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
- attr_accessor :current_node, :current_file
78
-
79
- # Current file source
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 query_string [String] query string to find matching ast nodes.
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(query_string, &block)
139
- Rewriter::QueryScope.new(self, query_string, &block).process
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 stop_when_match [Boolean] set if stop when match, default is false
151
- # @option direct [Boolean] set if find direct matching ast nodes, default is false
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
- @actions << Rewriter::AppendAction.new(self, code).process
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
- @actions << Rewriter::PrependAction.new(self, code).process
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
- @actions << Rewriter::InsertAction.new(self, code, at: at, to: to).process
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
- @actions << Rewriter::InsertAfterAction.new(self, code).process
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
- @actions << Rewriter::ReplaceWithAction.new(self, code).process
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
- @actions << Rewriter::ReplaceAction.new(self, *selectors, with: with).process
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
- @actions << Rewriter::RemoveAction.new(self, **options).process
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
- @actions << Rewriter::DeleteAction.new(self, *selectors, **options).process
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
- # @param indent [Integer, nil] number of whitespaces.
372
- def wrap(with:, indent: nil)
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
- begin
401
- puts file_path if Configuration.show_run_process
402
- conflict_actions = []
403
- source = +self.class.file_source(file_path)
404
- ast = self.class.file_ast(file_path)
405
-
406
- @current_file = file_path
407
-
408
- process_with_node(ast) do
409
- instance_eval(&@block)
410
- rescue NoMethodError
411
- puts @current_node.debug_info
412
- raise
413
- end
414
-
415
- if @actions.length > 0
416
- @actions.sort_by! { |action| [action.begin_pos, action.end_pos] }
417
- conflict_actions = get_conflict_actions
418
- @actions.reverse_each do |action|
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
- update_file(file_path, source)
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
- rescue Parser::SyntaxError
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
- # It changes source code from bottom to top, and it can change source code twice at the same time,
432
- # So if there is an overlap between two actions, it removes the conflict actions and operate them in the next loop.
433
- def get_conflict_actions
434
- i = @actions.length - 1
435
- j = i - 1
436
- conflict_actions = []
437
- return if i < 0
438
-
439
- begin_pos = @actions[i].begin_pos
440
- while j > -1
441
- if begin_pos < @actions[j].end_pos
442
- conflict_actions << @actions.delete_at(j)
443
- else
444
- i = j
445
- begin_pos = @actions[i].begin_pos
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
- # It updates a file with new source code.
398
+ # Parse code ast node.
453
399
  #
454
- # @param file_path [String] the file path
455
- # @param source [String] the new source code
456
- def update_file(file_path, source)
457
- self.class.write_file(file_path, source)
458
- @rewriter.add_affected_file(file_path)
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 query_string [String]
9
+ # @param nql [String]
10
+ # @param options [Hash]
10
11
  # @yield run on all matching nodes
11
- def initialize(instance, query_string, &block)
12
+ def initialize(instance, nql, options = {}, &block)
12
13
  super(instance, &block)
13
- @query_string = query_string
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
- NodeQuery::Parser.new.parse(@query_string).query_nodes(current_node).each do |node|
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
- @rules = rules
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
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.4.0'
5
+ VERSION = '1.6.0'
6
6
  end
7
7
  end
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 'ast'
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 'synvert/core/array_ext'
14
- require 'synvert/core/node_ext'
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