From 1a6fc98c60d1344330c32dd2ef6c7ec844bdafc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philip=20M=C3=BCller?= Date: Mon, 18 Mar 2024 18:58:33 +0000 Subject: [PATCH] proposed cleaner solution --- lib/packwerk.rb | 1 + lib/packwerk/references_from_file.rb | 68 ++++++++++++++++------------ lib/packwerk/run_context.rb | 18 +++++++- 3 files changed, 56 insertions(+), 31 deletions(-) diff --git a/lib/packwerk.rb b/lib/packwerk.rb index 39023d1ca..765de3efe 100644 --- a/lib/packwerk.rb +++ b/lib/packwerk.rb @@ -32,6 +32,7 @@ module Packwerk autoload :Reference autoload :ReferenceOffense autoload :Validator + autoload :ReferencesFromFile module OutputStyles extend ActiveSupport::Autoload diff --git a/lib/packwerk/references_from_file.rb b/lib/packwerk/references_from_file.rb index 85da18473..8f6b76ab1 100644 --- a/lib/packwerk/references_from_file.rb +++ b/lib/packwerk/references_from_file.rb @@ -1,35 +1,45 @@ -# typed: false +# typed: strict # frozen_string_literal: true module Packwerk - # Extracts all static constant references between Ruby files. - # Reuses the packwerk configuration. - # Hackishly hooks into packwerk internals. - class ReferencesFromFile - def initialize(config = Configuration.from_path) - @config = config - # RunContext is a `private_constant` of `Packwerk` - @run_context = RunContext.from_configuration(@config) - end - - def list_all(relative_file_paths: []) - # FilesForProcessing is a `private_constant` of `Packwerk` - files = FilesForProcessing.fetch(relative_file_paths:, configuration: @config).files - - files.map { |file| list(file) }.flatten(1) + # Extracts all static constant references between Ruby files. + class ReferencesFromFile + extend T::Sig + + class FileParserError < RuntimeError + extend T::Sig + + sig { params(file: String, offenses: T::Array[Packwerk::Offense]).void } + def initialize(file:, offenses:) + super("Errors while parsing #{file}: #{offenses.map(&:to_s).join("\n")}") end - - def list(relative_file) - file_processor = @run_context.send(:file_processor) - context_provider = @run_context.send(:context_provider) - - unresolved_references = file_processor.call(relative_file).unresolved_references - - # ReferenceExtractor is a `private_constant` of `Packwerk` - ReferenceExtractor.get_fully_qualified_references_from( - unresolved_references, - context_provider - ) + end + + sig { params(config: Packwerk::Configuration).void } + def initialize(config = Configuration.from_path) + @config = config + @run_context = T.let(RunContext.from_configuration(@config), RunContext) + end + + sig { params(relative_file_paths: T::Array[String]).returns(T::Array[Packwerk::Reference]) } + def list_all(relative_file_paths: []) + files(relative_file_paths: relative_file_paths).map { |file| list(file) }.flatten(1) + end + + sig { params(relative_file: String).returns(T::Array[Packwerk::Reference]) } + def list(relative_file) + references_result = @run_context.references_from_file(relative_file:) + + if references_result.file_offenses.present? + raise FileParserError.new(file: relative_file, offenses: references_result.file_offenses) end + + references_result.references + end + + sig { params(relative_file_paths: T::Array[String]).returns(T::Set[String]) } + def files(relative_file_paths: []) + FilesForProcessing.fetch(relative_file_paths: relative_file_paths, configuration: @config).files end - end \ No newline at end of file + end +end diff --git a/lib/packwerk/run_context.rb b/lib/packwerk/run_context.rb index 8dae554a1..636a016ac 100644 --- a/lib/packwerk/run_context.rb +++ b/lib/packwerk/run_context.rb @@ -75,15 +75,29 @@ def initialize( sig { params(relative_file: String).returns(T::Array[Packwerk::Offense]) } def process_file(relative_file:) + reference_checker = ReferenceChecking::ReferenceChecker.new(@checkers) + + references_result = references_from_file(relative_file: relative_file) + + references_result.file_offenses + + references_result.references.flat_map { |reference| reference_checker.call(reference) } + end + + class FileReferencesResult < T::Struct + const :references, T::Array[Packwerk::Reference] + const :file_offenses, T::Array[Packwerk::Offense] + end + + sig { params(relative_file: String).returns(FileReferencesResult) } + def references_from_file(relative_file:) processed_file = file_processor.call(relative_file) references = ReferenceExtractor.get_fully_qualified_references_from( processed_file.unresolved_references, context_provider ) - reference_checker = ReferenceChecking::ReferenceChecker.new(@checkers) - processed_file.offenses + references.flat_map { |reference| reference_checker.call(reference) } + FileReferencesResult.new(references: references, file_offenses: processed_file.offenses) end sig { returns(PackageSet) }