Skip to content

Commit

Permalink
PrismParser: Contextual parsing for Rails
Browse files Browse the repository at this point in the history
  • Loading branch information
davidwessman committed Jun 6, 2024
1 parent 9852a3f commit ac7c37e
Show file tree
Hide file tree
Showing 8 changed files with 1,331 additions and 7 deletions.
72 changes: 72 additions & 0 deletions lib/i18n/tasks/scanners/prism_scanner.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

require_relative 'file_scanner'
require_relative 'ruby_ast_scanner'

module I18n::Tasks::Scanners
class PrismScanner < FileScanner
def initialize(**args)
unless RAILS_VISITOR || RUBY_VISITOR
warn(
'Please make sure `prism` is available to use this feature. Fallback to Ruby AST Scanner.'
)
end

@visitor_class =
args.dig(:config, :rails_visitor) ? RAILS_VISITOR : RUBY_VISITOR

@fallback = RubyAstScanner.new(**args)
super
end

protected

# Extract all occurrences of translate calls from the file at the given path.
#
# @return [Array<[key, Results::KeyOccurrence]>] each occurrence found in the file
def scan_file(path)
return @fallback.send(:scan_file, path) if @visitor_class.nil?

process_prism_parse_result(
path,
PARSER.parse_file(path).value,
PARSER.parse_file_comments(path)
)
rescue Exception => e # rubocop:disable Lint/RescueException
raise(
::I18n::Tasks::CommandError.new(
e,
"Error scanning #{path}: #{e.message}"
)
)
end

def process_prism_parse_result(path, parsed, comments = nil)
return @fallback.send(:scan_file, path) if RUBY_VISITOR.skip_prism_comment?(comments)

visitor = @visitor_class.new(comments: comments)
nodes = parsed.accept(visitor)

nodes
.filter_map do |node|
next node.occurrences(path) if node.is_a?(I18n::Tasks::Scanners::PrismScanners::TranslationNode)
next unless node.respond_to?(:translation_nodes)

node.translation_nodes.flat_map { |n| n.occurrences(path) }
end
.flatten(1)
end

begin
require 'prism'
require_relative 'prism_scanners/rails_visitor'
require_relative 'prism_scanners/visitor'
PARSER = Prism
RUBY_VISITOR = I18n::Tasks::Scanners::PrismScanners::Visitor
RAILS_VISITOR = I18n::Tasks::Scanners::PrismScanners::RailsVisitor
rescue LoadError
PARSER = nil
VISITOR = nil
end
end
end
Loading

0 comments on commit ac7c37e

Please sign in to comment.