# frozen_string_literal: true require 'pathname' require_relative 'configuration_converter' require_relative 'schema_validator' require_relative '../errors/config_file_error' module Reek module Configuration # # ConfigurationFileFinder is responsible for finding Reek's configuration. # # There are 3 ways of passing `reek` a configuration file: # 1. Using the cli "-c" switch # 2. Having a file .reek.yml either in your current working # directory or in a parent directory # 3. Having a file .reek.yml in your HOME directory # # The order in which ConfigurationFileFinder tries to find such a # configuration file is exactly like above. module ConfigurationFileFinder DEFAULT_FILE_NAME = '.reek.yml' class << self include ConfigurationValidator # # Finds and loads a configuration file from a given path. # # @return [Hash] # def find_and_load(path: nil) load_from_file(find(path: path)) end # # Tries to find a configuration file via: # * given path (e.g. via cli switch) # * ascending down from the current directory # * looking into the home directory # # @return [File|nil] # # @quality :reek:ControlParameter def find(path: nil, current: Pathname.pwd, home: Pathname.new(Dir.home)) path || find_by_dir(current) || find_in_dir(home) end # # Loads a configuration file from a given path. # Raises on invalid data. # # @param path [String] # @return [Hash] # # @quality :reek:TooManyStatements { max_statements: 6 } def load_from_file(path) return {} unless path begin configuration = YAML.load_file(path) || {} SchemaValidator.new(configuration).validate rescue StandardError => error raise Errors::ConfigFileError, "Invalid configuration file #{path}, error is #{error}" end ConfigurationConverter.new(configuration).convert end private # # Recursively traverse directories down to find a configuration file. # # @return [File|nil] # def find_by_dir(start) start.ascend do |dir| file = find_in_dir(dir) return file if file end end # # Checks a given directory for a configuration file and returns it. # # @return [File|nil] # # @quality :reek:FeatureEnvy def find_in_dir(dir) file = dir + DEFAULT_FILE_NAME file if file.file? end end end end end