Skip to content

Commit

Permalink
ERB-Ast: Do not try to parse erb-comments
Browse files Browse the repository at this point in the history
- Fixes #434
  • Loading branch information
davidwessman authored and glebm committed Apr 1, 2022
1 parent 9461e91 commit 79fe6de
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 50 deletions.
48 changes: 16 additions & 32 deletions lib/i18n/tasks/scanners/erb_ast_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ def on_code(node)
# @param node [::Parser::AST::Node]
# @return [::Parser::AST::Node]
def handler_missing(node)
node = transform_misparsed_comment(node)
node = handle_comment(node)
return if node.nil?

node.updated(
nil,
node.children.map { |child| node?(child) ? process(child) : child }
Expand All @@ -47,40 +49,22 @@ def handler_missing(node)

private

# Works around incorrect handling of comments of the form:
# <%# ... #>
# (no space between % and #)
#
# With a space the AST is:
#
# s(:erb, nil, nil,
# s(:code, " # this should not fail: ' "), nil)
# Convert ERB-comments to ::Parser::Source::Comment and skip processing node
#
# Without a space the AST is:
#
# s(:erb,
# s(:indicator, "#"), nil,
# s(:code, " this should not fail: ' "), nil)
# @param node [::Parser::AST::Node]
# @return [::Parser::AST::Node]
def transform_misparsed_comment(node)
return node unless node.type == :erb && node.children.size == 4 &&
node.children[0]&.type == :indicator && node.children[0].children[0] == "#" &&
node.children[1].nil? &&
node.children[2]&.type == :code &&
node.children[3].nil?
code_node = node.children[2]
# @param node Parser::AST::Node Potential comment node
# @return Parser::AST::Node or nil
def handle_comment(node)
if node.type == :erb && node.children.size == 4 &&
node.children[0]&.type == :indicator && node.children[0].children[0] == '#' &&
node.children[2]&.type == :code

# Prepend # to each line to make it a valid Ruby comment.
code = code_node.children[0].split("\n").map do |line|
next line if line =~ /^\s*#/
"##{line}"
end.join("\n")
# Do not continue parsing this node
comment = node.children[2]
@comments << ::Parser::Source::Comment.new(comment.location.expression)
return
end

node.updated(
nil,
[nil, nil, code_node.updated(nil, [code]), nil]
)
node
end

def node?(node)
Expand Down
37 changes: 37 additions & 0 deletions spec/fixtures/used_keys/app/views/application/comments.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<!-- i18n-tasks-use t('ignore.html.comments') -->
<%= Translate.ignore_html_comment %>
<% # i18n-tasks-use t('ruby.comment.works') %>
<%= Translate.ruby_comment_works %>
<%# i18n-tasks-use t('erb.comment.works') %>
<%= Translate.erb_comment_works %>
<!-- Below are hard to parse ERB. -->
=============================================
=============================================
=============================================
=============================================
<%# Do not fail while parsing these: %>
<%# this should not fail: ' %>
<%# this is a multiline comment
it's totally fine
nothing should fail %>
<% # https://github.com/glebm/i18n-tasks/issues/434 %>

<!-- 32×32 -->
<%#
<!--
bla
bla
bla
bla
bla
bla
-->
%>
9 changes: 1 addition & 8 deletions spec/fixtures/used_keys/app/views/application/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,11 @@ I18n.t("this_should_not")
<h2>
<% # i18n-tasks-use t('activerecord.models.first.one') %>
<%= First.model_name.human(count: 1) %>
<!-- i18n-tasks-use t('activerecord.models.not_a_real_comment.one') -->
<%= NotARealComment.model_name.human %>
</h2>
<h3>
<%= t('with_parameter', parameter: "erb is the best") %>
<%= t 'with_scope', scope: "scope_a.scope_b", default: t(".nested_call") %>
<% # https://github.com/glebm/i18n-tasks/issues/424 %>
<%= link_to(edit_foo_path(foo), title: t(".edit")) do %>
<i class="fa fa-edit icon-fa"></i>
Expand All @@ -21,10 +20,4 @@ I18n.t("this_should_not")
<%= render Blacklight::Document::CitationComponent.with_collection(@documents) if @documents.present? %>
<% end %>
<%# this should not fail: ' %>
<%# this is a multiline comment
it's totally fine
nothing should fail %>
</h3>
65 changes: 55 additions & 10 deletions spec/used_keys_erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 318,
line_num: 11, line_pos: 5,
pos: 202,
line_num: 9, line_pos: 5,
line: " <%= t('with_parameter', parameter: \"erb is the best\") %>",
raw_key: 'with_parameter'
}
Expand All @@ -63,8 +63,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 377,
line_num: 12, line_pos: 5,
pos: 261,
line_num: 10, line_pos: 5,
line: " <%= t 'with_scope', scope: \"scope_a.scope_b\", default: t(\".nested_call\") %>",
raw_key: 'scope_a.scope_b.with_scope'
}
Expand All @@ -79,8 +79,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 429,
line_num: 12, line_pos: 57,
pos: 313,
line_num: 10, line_pos: 57,
line: " <%= t 'with_scope', scope: \"scope_a.scope_b\", default: t(\".nested_call\") %>",
raw_key: '.nested_call'
}
Expand All @@ -95,8 +95,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 548,
line_num: 14, line_pos: 41,
pos: 433,
line_num: 13, line_pos: 41,
line: ' <%= link_to(edit_foo_path(foo), title: t(".edit")) do %>',
raw_key: '.edit'
}
Expand All @@ -111,8 +111,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 770,
line_num: 20, line_pos: 25,
pos: 655,
line_num: 19, line_pos: 25,
line: " <% component.title { t('blacklight.tools.citation') } %>",
raw_key: 'blacklight.tools.citation'
}
Expand All @@ -136,4 +136,49 @@
)
)
end

describe 'comments' do
let(:paths) {
%w[app/views/application/comments.html.erb]
}

it '#used_keys' do
used_keys = task.used_tree
expect(used_keys.size).to eq(1)
leaves = used_keys.leaves.to_a
expect(leaves.size).to eq(2)

expect_node_key_data(
leaves[0],
'ruby.comment.works',
occurrences: make_occurrences(
[
{
path: 'app/views/application/comments.html.erb',
pos: 90,
line_num: 4, line_pos: 2,
line: "<% # i18n-tasks-use t('ruby.comment.works') %>",
raw_key: 'ruby.comment.works'
}
]
)
)

expect_node_key_data(
leaves[1],
'erb.comment.works',
occurrences: make_occurrences(
[
{
path: 'app/views/application/comments.html.erb',
pos: 174,
line_num: 7, line_pos: 4,
line: "<%# i18n-tasks-use t('erb.comment.works') %>",
raw_key: 'erb.comment.works'
}
]
)
)
end
end
end

0 comments on commit 79fe6de

Please sign in to comment.