Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Erb-scanner: Replaces better_html with regex #545

Merged
merged 1 commit into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
## Unreleased

* ErbAst-parser now only used for `*.html.erb`-files, not e.g. `*.js.erb`
* ERB AST-scanner now uses regex instead of better_html to allow
parsing files other than HTML.

## v1.0.13

Expand Down
1 change: 0 additions & 1 deletion i18n-tasks.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ Gem::Specification.new do |s|

s.add_dependency 'activesupport', '>= 4.0.2'
s.add_dependency 'ast', '>= 2.1.0'
s.add_dependency 'better_html', '>= 1.0', '< 3.0'
s.add_dependency 'erubi'
s.add_dependency 'highline', '>= 2.0.0'
s.add_dependency 'i18n'
Expand Down
74 changes: 0 additions & 74 deletions lib/i18n/tasks/scanners/erb_ast_processor.rb

This file was deleted.

80 changes: 55 additions & 25 deletions lib/i18n/tasks/scanners/erb_ast_scanner.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# frozen_string_literal: true

require 'i18n/tasks/scanners/ruby_ast_scanner'
require 'i18n/tasks/scanners/erb_ast_processor'
require 'better_html/errors'
require 'better_html/parser'
require 'i18n/tasks/scanners/local_ruby_parser'

module I18n::Tasks::Scanners
# Scan for I18n.translate calls in ERB-file better-html and ASTs
class ErbAstScanner < RubyAstScanner
DEFAULT_REGEXP = /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>/m.freeze

def initialize(**args)
super(**args)
@erb_ast_processor = ErbAstProcessor.new
@ruby_parser = LocalRubyParser.new(ignore_blocks: true)
end

private
Expand All @@ -20,29 +20,59 @@ def initialize(**args)
# @param path Path to file to parse
# @return [{Parser::AST::Node}, [Parser::Source::Comment]]
def path_to_ast_and_comments(path)
parser = BetterHtml::Parser.new(make_buffer(path))
ast = convert_better_html(parser.ast)
@erb_ast_processor.process_and_extract_comments(ast)
comments = []
buffer = make_buffer(path)

children = []
buffer
.source
.scan(DEFAULT_REGEXP) do |indicator, code, tailch, _rspace|
match = Regexp.last_match
character = indicator ? indicator[0] : nil

start = match.begin(0) + 2 + (character&.size || 0)
stop = match.end(0) - 2 - (tailch&.size || 0)

case character
when '=', nil, '-'
parsed, parsed_comments = handle_code(buffer, code, start, stop)
comments.concat(parsed_comments)
children << parsed unless parsed.nil?
when '#', '#-'
comments << handle_comment(buffer, start, stop)
end
end

[root_node(children, buffer), comments]
end

# Convert BetterHtml nodes to Parser::AST::Node
#
# @param node BetterHtml::Parser::AST::Node
# @return Parser::AST::Node
def convert_better_html(node)
definition = Parser::Source::Map::Definition.new(
node.location.begin,
node.location.begin,
node.location.begin,
node.location.end
)
Parser::AST::Node.new(
node.type,
node.children.map { |child| child.is_a?(BetterHtml::AST::Node) ? convert_better_html(child) : child },
{
location: definition
}
)
def handle_code(buffer, code, start, stop)
range = ::Parser::Source::Range.new(buffer, start, stop)
location =
Parser::Source::Map::Definition.new(
range.begin,
range.begin,
range.begin,
range.end
)
@ruby_parser.parse(code, location: location)
end

def handle_comment(buffer, start, stop)
range = ::Parser::Source::Range.new(buffer, start, stop)
::Parser::Source::Comment.new(range)
end

def root_node(children, buffer)
range = ::Parser::Source::Range.new(buffer, 0, buffer.source.size)
location =
Parser::Source::Map::Definition.new(
range.begin,
range.begin,
range.begin,
range.end
)
::Parser::AST::Node.new(:erb, children, location: location)
end
end
end
68 changes: 34 additions & 34 deletions spec/used_keys_erb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 17,
line_num: 1, line_pos: 17,
pos: 18,
line_num: 1, line_pos: 18,
line: "<div id=first><%= t('a') %></div>",
raw_key: 'a'
},
Expand All @@ -56,8 +56,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 184,
line_num: 7, line_pos: 5,
pos: 185,
line_num: 7, line_pos: 6,
line: ' <%= MeetingNote.model_name.human(count: 1) %>',
raw_key: 'activerecord.models.meeting_note'
}
Expand All @@ -72,8 +72,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 232,
line_num: 8, line_pos: 5,
pos: 233,
line_num: 8, line_pos: 6,
line: ' <%= AgendaItem.human_attribute_name(:title) %>',
raw_key: 'activerecord.attributes.agenda_item.title'
}
Expand All @@ -88,8 +88,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 292,
line_num: 11, line_pos: 5,
pos: 293,
line_num: 11, line_pos: 6,
line: " <%= t('with_parameter', parameter: \"erb is the best\") %>",
raw_key: 'with_parameter'
}
Expand All @@ -104,8 +104,8 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 351,
line_num: 12, line_pos: 5,
pos: 352,
line_num: 12, line_pos: 6,
line: " <%= t 'with_scope', scope: \"scope_a.scope_b\", default: t(\".nested_call\") %>",
raw_key: 'scope_a.scope_b.with_scope'
}
Expand Down Expand Up @@ -168,9 +168,9 @@
[
{
path: 'app/views/application/show.html.erb',
pos: 88,
line_num: 5, line_pos: 4,
line: " <% # i18n-tasks-use t('comment.absolute.attribute') %>",
pos: 147,
line_num: 6, line_pos: 6,
line: ' <%= Translate.absolute.attribute %>',
raw_key: 'comment.absolute.attribute'
}
]
Expand All @@ -196,9 +196,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 90,
line_num: 4, line_pos: 2,
line: "<% # i18n-tasks-use t('ruby.comment.works') %>",
pos: 139,
line_num: 5, line_pos: 4,
line: '<%= Translate.ruby_comment_works %>',
raw_key: 'ruby.comment.works'
}
]
Expand All @@ -212,9 +212,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 174,
line_num: 7, line_pos: 4,
line: "<%# i18n-tasks-use t('erb.comment.works') %>",
pos: 221,
line_num: 8, line_pos: 4,
line: '<%= Translate.erb_comment_works %>',
raw_key: 'erb.comment.works'
}
]
Expand All @@ -228,9 +228,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 255,
line_num: 10, line_pos: 2,
line: "<%# i18n-tasks-use t('erb_multi.comment.line1')",
pos: 352,
line_num: 12, line_pos: 4,
line: '<%= t("erb_multi.comment.#{type}") %>', # rubocop:disable Lint/InterpolationCheck
raw_key: 'erb_multi.comment.line1'
}
]
Expand All @@ -245,9 +245,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 255,
line_num: 10, line_pos: 2,
line: "<%# i18n-tasks-use t('erb_multi.comment.line1')",
pos: 352,
line_num: 12, line_pos: 4,
line: '<%= t("erb_multi.comment.#{type}") %>', # rubocop:disable Lint/InterpolationCheck
raw_key: 'erb_multi.comment.line2'
}
]
Expand All @@ -261,9 +261,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 389,
line_num: 14, line_pos: 2,
line: '<%#-',
pos: 498,
line_num: 17, line_pos: 4,
line: '<%= t("erb_multi_dash.comment.#{type}") %>', # rubocop:disable Lint/InterpolationCheck
raw_key: 'erb_multi_dash.comment.line1'
}
]
Expand All @@ -277,9 +277,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 389,
line_num: 14, line_pos: 2,
line: '<%#-',
pos: 498,
line_num: 17, line_pos: 4,
line: '<%= t("erb_multi_dash.comment.#{type}") %>', # rubocop:disable Lint/InterpolationCheck
raw_key: 'erb_multi_dash.comment.line2'
}
]
Expand All @@ -293,9 +293,9 @@
[
{
path: 'app/views/application/comments.html.erb',
pos: 540,
line_num: 19, line_pos: 2,
line: '<%',
pos: 642,
line_num: 22, line_pos: 4,
line: '<%= t("ruby_multi.comment.#{type}") %>', # rubocop:disable Lint/InterpolationCheck
raw_key: 'ruby_multi.comment.line1'
}
]
Expand Down