synvert-core 1.21.4 → 1.21.5

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: 3ffea2bd16746fbf2e7fffe597c4b9a6996e9b8eb3ca2442a9afe1716440e625
4
- data.tar.gz: bb894317de6b8e8457f945bb62f8f0d6904b161c6ade75666403e3ca9e901771
3
+ metadata.gz: cb89b1bc2d50d73f656541dc90fb5efad3c5637589a71c1fcba29324244c6539
4
+ data.tar.gz: d14d4b677a1b3f00b913c2baf8a0f6ef1cd8c3630f2c66a6723b891d3a0f2d83
5
5
  SHA512:
6
- metadata.gz: 52f123ef58bcd08859bb0639303e50a06d7d5f62e078824cf89e54413ca98ef555dc460da2df00cbe5c76470f73c1fe3b7136c37448e1d74697d573409da4738
7
- data.tar.gz: 1123a15c06c6dd61bc8d84ceed412ca61ff15feef50257771701c2a1b1e504b56a00eda9b7f1c798fb0767f86da7dcf979b9570a38a5cb7f7e4f06858a13de60
6
+ metadata.gz: 452e3d690d566304b0d2f7dc37aaba39da839eb6151b0720668dcb0b4e49901742172e523de40cca4e83fbb9064e04ad2d7928e6b23eca68bce0984566d10345
7
+ data.tar.gz: 7ac8916b752c005dae8c0bf958161c5b217111cacaf58968c5dd46aa2f7d4641591590fd7185dadffe0e53e63b4d7ec2a55e3ab94ec000617c618e2109f33767
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
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
+
3
9
  ## 1.21.4 (2023-02-13)
4
10
 
5
11
  * Do not rescue `NoMethodError` and output debug info
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- synvert-core (1.21.4)
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
@@ -296,7 +296,8 @@ module Synvert::Core
296
296
  # replace_erb_stmt_with_expr
297
297
  # end
298
298
  def replace_erb_stmt_with_expr
299
- @current_mutation.actions << Rewriter::ReplaceErbStmtWithExprAction.new(@current_node).process
299
+ action = Rewriter::ReplaceErbStmtWithExprAction.new(@current_node)
300
+ add_action(action)
300
301
  end
301
302
 
302
303
  # It replaces the whole code of current node.
@@ -421,16 +422,13 @@ module Synvert::Core
421
422
  # @param file_path [String] file path
422
423
  # @return [String] file source
423
424
  def read_source(file_path)
424
- source = File.read(file_path, encoding: 'UTF-8')
425
- source = Engine::Erb.encode(source) if /\.erb$/.match?(file_path)
426
- source
425
+ File.read(file_path, encoding: 'UTF-8')
427
426
  end
428
427
 
429
428
  # Write file source to file.
430
429
  # @param file_path [String] file path
431
430
  # @param source [String] file source
432
431
  def write_source(file_path, source)
433
- source = Engine::Erb.decode(source) if /\.erb/.match?(file_path)
434
432
  File.write(file_path, source.gsub(/ +\n/, "\n"))
435
433
  end
436
434
 
@@ -441,7 +439,7 @@ module Synvert::Core
441
439
  # @return [Node] ast node for file
442
440
  def parse_code(file_path, source)
443
441
  buffer = Parser::Source::Buffer.new file_path
444
- buffer.source = source
442
+ buffer.source = /\.erb/.match?(file_path) ? Engine::Erb.encode(source) : source
445
443
 
446
444
  parser = Parser::CurrentRuby.new
447
445
  parser.reset
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Synvert
4
4
  module Core
5
- VERSION = '1.21.4'
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.4
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-13 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