synvert-core 1.21.4 → 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 +4 -4
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/lib/synvert/core/engine/erb.rb +3 -132
- data/lib/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action.rb +3 -16
- data/lib/synvert/core/rewriter/instance.rb +4 -6
- data/lib/synvert/core/version.rb +1 -1
- data/spec/synvert/core/engine/erb_spec.rb +7 -10
- data/spec/synvert/core/rewriter/action/replace_erb_stmt_with_expr_action_spec.rb +4 -4
- data/spec/synvert/core/rewriter/instance_spec.rb +39 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb89b1bc2d50d73f656541dc90fb5efad3c5637589a71c1fcba29324244c6539
|
4
|
+
data.tar.gz: d14d4b677a1b3f00b913c2baf8a0f6ef1cd8c3630f2c66a6723b891d3a0f2d83
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
@@ -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
|
-
|
18
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
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
|
-
|
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
|
-
|
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
|
data/lib/synvert/core/version.rb
CHANGED
@@ -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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
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
|
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 '
|
16
|
+
expect(subject.start).to eq '<%'.length
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'gets end' do
|
20
|
-
expect(subject.end).to eq '
|
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 '
|
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 '
|
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 '
|
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
|
+
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-
|
11
|
+
date: 2023-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|