From ef007fb5a4d35bf0a3b1e11e79e458c39ba0a854 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Fri, 25 Mar 2022 09:32:09 +0000 Subject: [PATCH] Fixes parsing of ERB comments without a space The ERB parser we're using misparses 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) Without a space the AST is: s(:erb, s(:indicator, "#"), nil, s(:code, " this should not fail: ' "), nil) The latter AST causes a crash when parsing the `:code` node as Ruby. Works around the issue by transforming the latter AST to the former. Fixes #429 --- lib/i18n/tasks/scanners/erb_ast_processor.rb | 32 +++++++++++++++++++ .../app/views/application/show.html.erb | 2 ++ 2 files changed, 34 insertions(+) diff --git a/lib/i18n/tasks/scanners/erb_ast_processor.rb b/lib/i18n/tasks/scanners/erb_ast_processor.rb index 06316482..82aacef9 100644 --- a/lib/i18n/tasks/scanners/erb_ast_processor.rb +++ b/lib/i18n/tasks/scanners/erb_ast_processor.rb @@ -35,7 +35,10 @@ def on_code(node) node end + # @param node [::Parser::AST::Node] + # @return [::Parser::AST::Node] def handler_missing(node) + node = transform_misparsed_comment(node) node.updated( nil, node.children.map { |child| node?(child) ? process(child) : child } @@ -44,6 +47,35 @@ 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) + # + # 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] + node.updated( + nil, + [nil, nil, code_node.updated(nil, ["##{code_node.children[0]}"]), nil] + ) + end + def node?(node) node.is_a?(::Parser::AST::Node) end diff --git a/spec/fixtures/used_keys/app/views/application/show.html.erb b/spec/fixtures/used_keys/app/views/application/show.html.erb index 990e7b0c..adb9a62e 100644 --- a/spec/fixtures/used_keys/app/views/application/show.html.erb +++ b/spec/fixtures/used_keys/app/views/application/show.html.erb @@ -21,4 +21,6 @@ I18n.t("this_should_not") <%= render Blacklight::Document::CitationComponent.with_collection(@documents) if @documents.present? %> <% end %> + + <%# this should not fail: ' %>