|
2 | 2 |
|
3 | 3 | require "i18n/tasks/scanners/ruby_scanner" |
4 | 4 | require "i18n/tasks/scanners/local_ruby_parser" |
| 5 | +require "i18n/tasks/scanners/occurrence_from_position" |
| 6 | +require "prism" |
5 | 7 |
|
6 | 8 | module I18n::Tasks::Scanners |
7 | | - # Scan for I18n.translate calls in ERB-file better-html and ASTs |
| 9 | + # Scan for I18n.translate calls in ERB-file using regexp and Parser/Prism |
8 | 10 | class ErbAstScanner < RubyScanner |
9 | | - DEFAULT_REGEXP = /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>/m |
| 11 | + include OccurrenceFromPosition |
| 12 | + DEFAULT_REGEXP = /<%(={1,2}|-|\#-?|%)?(.*?)([-=])?%>/m |
10 | 13 |
|
11 | | - def initialize(**args) |
| 14 | + # Parser scanner, method called in RubyScanner |
| 15 | + def ast_parser_parse_file(path) |
| 16 | + @ruby_parser ||= LocalRubyParser.new(ignore_blocks: true) |
12 | 17 | super |
13 | | - @ruby_parser = LocalRubyParser.new(ignore_blocks: true) |
14 | 18 | end |
15 | 19 |
|
16 | 20 | private |
@@ -74,5 +78,59 @@ def root_node(children, buffer) |
74 | 78 | ) |
75 | 79 | ::Parser::AST::Node.new(:erb, children, location: location) |
76 | 80 | end |
| 81 | + |
| 82 | + # Prism scanner, method called in RubyScanner |
| 83 | + def prism_parse_file(path) |
| 84 | + occurrences = [] |
| 85 | + content = File.read(path) |
| 86 | + |
| 87 | + content.scan(DEFAULT_REGEXP) do |indicator, code, _tailch, _rspace| |
| 88 | + match = Regexp.last_match |
| 89 | + character = indicator ? indicator[0] : nil |
| 90 | + start = match.begin(0) + 2 + (character&.size || 0) |
| 91 | + |
| 92 | + case character |
| 93 | + when "=", nil, "-" |
| 94 | + occurrences += process_code(path, code, content, start) |
| 95 | + when "#", "#-" |
| 96 | + occurrences += process_comments(path, code, content, start) |
| 97 | + end |
| 98 | + end |
| 99 | + |
| 100 | + occurrences |
| 101 | + end |
| 102 | + |
| 103 | + def process_code(path, code, content, start) |
| 104 | + return [] if code.strip.empty? # skip empty ERB tags |
| 105 | + |
| 106 | + process_prism_results(path, Prism.parse(code)).map do |key, occurrence| |
| 107 | + [ |
| 108 | + key, |
| 109 | + occurrence_from_position( |
| 110 | + path, |
| 111 | + content, |
| 112 | + start + occurrence.pos, |
| 113 | + raw_key: occurrence.raw_key |
| 114 | + ) |
| 115 | + ] |
| 116 | + end |
| 117 | + end |
| 118 | + |
| 119 | + def process_comments(path, code, content, start) |
| 120 | + return [] if code.strip.empty? |
| 121 | + |
| 122 | + parsed = Prism.parse(code.gsub("i18n-tasks-use ", "#i18n-tasks-use ")) |
| 123 | + process_prism_results(path, parsed).map do |key, occurrence| |
| 124 | + [ |
| 125 | + key, |
| 126 | + occurrence_from_position( |
| 127 | + path, |
| 128 | + content, |
| 129 | + start + (code.index(key) || occurrence.pos), |
| 130 | + raw_key: occurrence.raw_key |
| 131 | + ) |
| 132 | + ] |
| 133 | + end |
| 134 | + end |
77 | 135 | end |
78 | 136 | end |
0 commit comments