synvert-core 1.21.3 → 1.21.5

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: 9fcf7cea4b77b429f7d0bcd373edbe41e5ce0fa0efd51c2ce9fc1f489d8d4d2d
4
- data.tar.gz: 66ee39ba9dcc28bc8636ba3489279d62ab8007d276b66d16ec1953b3a030c9e6
3
+ metadata.gz: cb89b1bc2d50d73f656541dc90fb5efad3c5637589a71c1fcba29324244c6539
4
+ data.tar.gz: d14d4b677a1b3f00b913c2baf8a0f6ef1cd8c3630f2c66a6723b891d3a0f2d83
5
5
  SHA512:
6
- metadata.gz: 00b89829cca5269e433078f9634c22d4b52ca1128fbfc74925bc212d5eb31400b79e0c769dde9e2e2fa94442c38902fce68ad6fa58d5ac9daebac6fa9d5d7239
7
- data.tar.gz: fcbc29ce9c8e0057adf91908929e735f3e80931df869dc66c84254a9a546ba66034efb020a67a5143884ad53f39d63a8b53c4b134785ada1fbbc3496f1f037a3
6
+ metadata.gz: 452e3d690d566304b0d2f7dc37aaba39da839eb6151b0720668dcb0b4e49901742172e523de40cca4e83fbb9064e04ad2d7928e6b23eca68bce0984566d10345
7
+ data.tar.gz: 7ac8916b752c005dae8c0bf958161c5b217111cacaf58968c5dd46aa2f7d4641591590fd7185dadffe0e53e63b4d7ec2a55e3ab94ec000617c618e2109f33767
data/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.21.5 (2023-02-15)
4
+
5
+ * Rewrite erb engine, no need to decode
6
+ * Rewrite `ReplaceErbStmtWithExprAction` to insert "=" instead
7
+ * Erb encoded source passed to `node_query`, but not `node_mutation`
8
+
9
+ ## 1.21.4 (2023-02-13)
10
+
11
+ * Do not rescue `NoMethodError` and output debug info
12
+
3
13
  ## 1.21.3 (2023-02-12)
4
14
 
5
15
  * Update `parser_node_ext` to 1.0.0
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- synvert-core (1.21.3)
4
+ synvert-core (1.21.5)
5
5
  activesupport (< 7.0.0)
6
6
  erubis
7
7
  node_mutation (>= 1.9.2)
@@ -4,9 +4,6 @@ require 'erubis'
4
4
 
5
5
  module Synvert::Core
6
6
  module Engine
7
- ERUBY_EXPR_SPLITTER = '; ;'
8
- ERUBY_STMT_SPLITTER = '; ;'
9
-
10
7
  class Erb
11
8
  class << self
12
9
  # convert erb to ruby code.
@@ -14,135 +11,9 @@ module Synvert::Core
14
11
  # @param source [String] erb source code.
15
12
  # @return [String] ruby source code.
16
13
  def encode(source)
17
- Erubis.new(source.gsub('-%>', '%>'), escape: false, trim: false).src
18
- end
19
-
20
- # convert ruby code to erb.
21
- #
22
- # @param source [String] ruby source code.
23
- # @return [String] erb source code.
24
- def decode(source)
25
- source = decode_ruby_stmt(source)
26
- source = decode_ruby_output(source)
27
- source = decode_html_output(source)
28
- source = remove_erubis_buf(source)
29
- end
30
-
31
- private
32
-
33
- def decode_ruby_stmt(source)
34
- source.gsub(/#{ERUBY_STMT_SPLITTER}(.+?)#{ERUBY_STMT_SPLITTER}/mo) { "<%#{Regexp.last_match(1)}%>" }
35
- end
36
-
37
- def decode_ruby_output(source)
38
- source.gsub(/@output_buffer.append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/mo) {
39
- "<%=#{Regexp.last_match(1)}%>"
40
- }.gsub(/@output_buffer.append= (.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/mo) { |m|
41
- "<%=#{m.sub('@output_buffer.append= ', '').sub(ERUBY_EXPR_SPLITTER, '')}%>"
42
- }
43
- end
44
-
45
- def decode_html_output(source)
46
- source.gsub(/@output_buffer.safe_append='(.+?)'.freeze;/m) { reverse_escape_text(Regexp.last_match(1)) }
47
- .gsub(
48
- /@output_buffer.safe_append=\((.+?)\);#{ERUBY_EXPR_SPLITTER}/mo
49
- ) { reverse_escape_text(Regexp.last_match(1)) }
50
- .gsub(
51
- /@output_buffer.safe_append=(.+?)\s+(do|\{)(\s*\|[^|]*\|)?\s*#{ERUBY_EXPR_SPLITTER}/mo
52
- ) { reverse_escape_text(Regexp.last_match(1)) }
53
- end
54
-
55
- def remove_erubis_buf(source)
56
- source
57
- .sub('@output_buffer = output_buffer || ActionView::OutputBuffer.new;', '')
58
- .sub('@output_buffer.to_s', '')
59
- end
60
-
61
- def reverse_escape_text(source)
62
- source.gsub("\\\\", "\\").gsub("\\'", "'")
63
- end
64
- end
65
- end
66
-
67
- # borrowed from rails
68
- class Erubis < ::Erubis::Eruby
69
- BLOCK_EXPR = /\s+(do|\{)(\s*\|[^|]*\|)?\s*\Z/
70
- def add_preamble(src)
71
- @newline_pending = 0
72
- src << '@output_buffer = output_buffer || ActionView::OutputBuffer.new;'
73
- end
74
-
75
- def add_text(src, text)
76
- return if text.empty?
77
-
78
- if text == "\n"
79
- @newline_pending += 1
80
- else
81
- src << "@output_buffer.safe_append='"
82
- src << ("\n" * @newline_pending) if @newline_pending > 0
83
- src << escape_text(text)
84
- src << "'.freeze;"
85
-
86
- @newline_pending = 0
87
- end
88
- end
89
-
90
- # Erubis toggles <%= and <%== behavior when escaping is enabled.
91
- # We override to always treat <%== as escaped.
92
- def add_expr(src, code, indicator)
93
- case indicator
94
- when '=='
95
- add_expr_escaped(src, code)
96
- else
97
- super
98
- end
99
- end
100
-
101
- def add_expr_literal(src, code)
102
- flush_newline_if_pending(src)
103
- if BLOCK_EXPR.match?(code)
104
- src << '@output_buffer.append= ' << code << ERUBY_EXPR_SPLITTER
105
- else
106
- src << '@output_buffer.append=(' << code << ');' << ERUBY_EXPR_SPLITTER
107
- end
108
- end
109
-
110
- def add_expr_escaped(src, code)
111
- flush_newline_if_pending(src)
112
- if BLOCK_EXPR.match?(code)
113
- src << '@output_buffer.safe_append= ' << code << ERUBY_EXPR_SPLITTER
114
- else
115
- src << '@output_buffer.safe_append=(' << code << ');' << ERUBY_EXPR_SPLITTER
116
- end
117
- end
118
-
119
- def add_stmt(src, code)
120
- flush_newline_if_pending(src)
121
- if code != "\n" && code != ''
122
- index =
123
- case code
124
- when /\A(\s*)\r?\n/
125
- Regexp.last_match(1).length
126
- when /\A(\s+)/
127
- Regexp.last_match(1).end_with?(' ') ? Regexp.last_match(1).length - 1 : Regexp.last_match(1).length
128
- else
129
- 0
130
- end
131
- code.insert(index, ERUBY_STMT_SPLITTER)
132
- code.insert(-1, ERUBY_STMT_SPLITTER[0...-1])
133
- end
134
- super
135
- end
136
-
137
- def add_postamble(src)
138
- flush_newline_if_pending(src)
139
- src << '@output_buffer.to_s'
140
- end
141
-
142
- def flush_newline_if_pending(src)
143
- if @newline_pending > 0
144
- src << "@output_buffer.safe_append='#{"\n" * @newline_pending}'.freeze;"
145
- @newline_pending = 0
14
+ source.gsub(/^.*?<%=?/m) { |str| ' ' * str.size }
15
+ .gsub(/%>.*?$/m) { |str| ' ' * str.size }
16
+ .gsub(/%>.*?<%=?/m) { |str| ' ' * str.size }
146
17
  end
147
18
  end
148
19
  end
@@ -16,28 +16,15 @@ module Synvert::Core
16
16
  #
17
17
  # @return [String] new code.
18
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)
19
+ '='
22
20
  end
23
21
 
24
22
  private
25
23
 
26
24
  # Calculate the begin the end positions.
27
25
  def calculate_position
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] == ' '
34
- end
35
- @start = whitespace_index - Engine::ERUBY_STMT_SPLITTER.length + 1
36
-
37
- at_index = node_start + node_source.index('do')
38
- while file_content[at_index += 1] != '@'
39
- end
40
- @end = at_index
26
+ @start = NodeMutation.adapter.get_start(@node) - 1
27
+ @end = @start
41
28
  end
42
29
  end
43
30
  end
@@ -51,14 +51,6 @@ module Synvert::Core
51
51
 
52
52
  process_with_node(node) do
53
53
  instance_eval(&@block)
54
- rescue NoMethodError => e
55
- puts [
56
- "error: #{e.message}",
57
- "file: #{file_path}",
58
- "source: #{source}",
59
- "line: #{current_node.line}"
60
- ].join("\n")
61
- raise
62
54
  end
63
55
 
64
56
  result = @current_mutation.process
@@ -87,14 +79,6 @@ module Synvert::Core
87
79
 
88
80
  process_with_node(node) do
89
81
  instance_eval(&@block)
90
- rescue NoMethodError => e
91
- puts [
92
- "error: #{e.message}",
93
- "file: #{file_path}",
94
- "source: #{source}",
95
- "line: #{current_node.line}"
96
- ].join("\n")
97
- raise
98
82
  end
99
83
 
100
84
  result = @current_mutation.test
@@ -312,7 +296,8 @@ module Synvert::Core
312
296
  # replace_erb_stmt_with_expr
313
297
  # end
314
298
  def replace_erb_stmt_with_expr
315
- @current_mutation.actions << Rewriter::ReplaceErbStmtWithExprAction.new(@current_node).process
299
+ action = Rewriter::ReplaceErbStmtWithExprAction.new(@current_node)
300
+ add_action(action)
316
301
  end
317
302
 
318
303
  # It replaces the whole code of current node.
@@ -437,16 +422,13 @@ module Synvert::Core
437
422
  # @param file_path [String] file path
438
423
  # @return [String] file source
439
424
  def read_source(file_path)
440
- source = File.read(file_path, encoding: 'UTF-8')
441
- source = Engine::Erb.encode(source) if /\.erb$/.match?(file_path)
442
- source
425
+ File.read(file_path, encoding: 'UTF-8')
443
426
  end
444
427
 
445
428
  # Write file source to file.
446
429
  # @param file_path [String] file path
447
430
  # @param source [String] file source
448
431
  def write_source(file_path, source)
449
- source = Engine::Erb.decode(source) if /\.erb/.match?(file_path)
450
432
  File.write(file_path, source.gsub(/ +\n/, "\n"))
451
433
  end
452
434
 
@@ -457,7 +439,7 @@ module Synvert::Core
457
439
  # @return [Node] ast node for file
458
440
  def parse_code(file_path, source)
459
441
  buffer = Parser::Source::Buffer.new file_path
460
- buffer.source = source
442
+ buffer.source = /\.erb/.match?(file_path) ? Engine::Erb.encode(source) : source
461
443
 
462
444
  parser = Parser::CurrentRuby.new
463
445
  parser.reset
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.21.3'
5
+ VERSION = '1.21.5'
6
6
  end
7
7
  end
@@ -6,13 +6,13 @@ module Synvert::Core
6
6
  describe Engine::Erb do
7
7
  it 'encodes / decodes' do
8
8
  source = <<~EOF
9
- <%content_for :head do%>
9
+ <% content_for :head do %>
10
10
  <style>
11
11
  body {
12
12
  background-image: url(<%= asset_path('bg.png') %>);
13
13
  }
14
14
  </style>
15
- <%end%>
15
+ <% end %>
16
16
 
17
17
  <%
18
18
  foo = 'bar'
@@ -34,14 +34,11 @@ module Synvert::Core
34
34
  <% end %>
35
35
  <% end %>
36
36
  EOF
37
- encoded_source = Engine::Erb.encode(source)
38
- buffer = Parser::Source::Buffer.new '(test)'
39
- buffer.source = encoded_source
40
- parser = Parser::CurrentRuby.new
41
- parser.reset
42
- parser.parse buffer
43
-
44
- expect(Engine::Erb.decode(encoded_source)).to eq source
37
+ encoded_lines = Engine::Erb.encode(source).split("\n")
38
+ expect(encoded_lines[0]).to eq ' content_for :head do '
39
+ expect(encoded_lines[1]).to eq " asset_path('bg.png') "
40
+ expect(encoded_lines[-2]).to eq ' end '
41
+ expect(encoded_lines[-1]).to eq ' end '
45
42
  end
46
43
  end
47
44
  end
@@ -8,20 +8,20 @@ module Synvert::Core
8
8
  subject {
9
9
  source = "<% form_for post do |f| %>\n<% end %>"
10
10
  source = Engine::Erb.encode(source)
11
- node = Parser::CurrentRuby.parse(source).children[1]
11
+ node = Parser::CurrentRuby.parse(source).children.first
12
12
  described_class.new(node).process
13
13
  }
14
14
 
15
15
  it 'gets start' do
16
- expect(subject.start).to eq '@output_buffer = output_buffer || ActionView::OutputBuffer.new;'.length
16
+ expect(subject.start).to eq '<%'.length
17
17
  end
18
18
 
19
19
  it 'gets end' do
20
- expect(subject.end).to eq '@output_buffer = output_buffer || ActionView::OutputBuffer.new;; ; form_for post do |f| ; ;'.length
20
+ expect(subject.end).to eq '<%'.length
21
21
  end
22
22
 
23
23
  it 'gets new_code' do
24
- expect(subject.new_code).to eq '@output_buffer.append= form_for post do |f| ; ;'
24
+ expect(subject.new_code).to eq '='
25
25
  end
26
26
  end
27
27
  end
@@ -287,12 +287,32 @@ module Synvert::Core
287
287
  instance.process
288
288
  expect(rewriter.affected_files).to be_include('spec/models/post_spec.rb')
289
289
  end
290
+
291
+ it 'updates erb file' do
292
+ instance =
293
+ Rewriter::Instance.new rewriter, 'app/views/posts/_form.html.erb' do
294
+ with_node type: 'send', receiver: nil, message: 'form_for' do
295
+ replace_erb_stmt_with_expr
296
+ end
297
+ end
298
+ input = <<~EOS
299
+ <% form_for @post do |f| %>
300
+ <% end %>
301
+ EOS
302
+ output = <<~EOS
303
+ <%= form_for @post do |f| %>
304
+ <% end %>
305
+ EOS
306
+ expect(File).to receive(:read).with('./app/views/posts/_form.html.erb', encoding: 'UTF-8').and_return(input)
307
+ expect(File).to receive(:write).with('./app/views/posts/_form.html.erb', output)
308
+ instance.process
309
+ end
290
310
  end
291
311
 
292
312
  describe '#test' do
293
313
  let(:rewriter) { Rewriter.new('foo', 'bar') }
294
314
 
295
- it 'writes new code to file' do
315
+ it 'gets actions if afected' do
296
316
  instance =
297
317
  Rewriter::Instance.new rewriter, 'spec/models/post_spec.rb' do
298
318
  with_node type: 'send', receiver: 'FactoryGirl', message: 'create' do
@@ -315,7 +335,7 @@ module Synvert::Core
315
335
  ]
316
336
  end
317
337
 
318
- it 'does not write if file content is not changed' do
338
+ it 'gets nothing if not affected' do
319
339
  instance =
320
340
  Rewriter::Instance.new rewriter, 'spec/spec_helper.rb' do
321
341
  with_node type: 'block', caller: { receiver: 'RSpec', message: 'configure' } do
@@ -334,6 +354,23 @@ module Synvert::Core
334
354
  expect(result.file_path).to eq 'spec/spec_helper.rb'
335
355
  expect(result.actions).to eq []
336
356
  end
357
+
358
+ it 'updates erb file' do
359
+ instance =
360
+ Rewriter::Instance.new rewriter, 'app/views/posts/_form.html.erb' do
361
+ with_node type: 'send', receiver: nil, message: 'form_for' do
362
+ replace_erb_stmt_with_expr
363
+ end
364
+ end
365
+ input = <<~EOS
366
+ <% form_for @post do |f| %>
367
+ <% end %>
368
+ EOS
369
+ expect(File).to receive(:read).with('./app/views/posts/_form.html.erb', encoding: 'UTF-8').and_return(input)
370
+ result = instance.test
371
+ expect(result.file_path).to eq 'app/views/posts/_form.html.erb'
372
+ expect(result.actions).to eq [OpenStruct.new(start: 2, end: 2, new_code: '=')]
373
+ end
337
374
  end
338
375
 
339
376
  describe '#process_with_node' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: synvert-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.21.3
4
+ version: 1.21.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Huang
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-12 00:00:00.000000000 Z
11
+ date: 2023-02-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport