# typed: strict# frozen_string_literal: truemoduleTapioca# @requires_ancestor: ThormoduleConfigHelperextendT::Sig#: Stringattr_reader:command_name#: Thor::CoreExt::HashWithIndifferentAccessattr_reader:defaults#: (?untyped args, ?untyped local_options, ?untyped config) -> voiddefinitialize(args=[],local_options={},config={})# Store current commandcommand=config[:current_command]command_options=config[:command_options]@command_name=command.name#: String@merged_options=nil#: Thor::CoreExt::HashWithIndifferentAccess?@defaults=Thor::CoreExt::HashWithIndifferentAccess.new#: Thor::CoreExt::HashWithIndifferentAccess# Filter command options unless we are handling the help command.# This is so that the defaults are printedfilter_defaults(command_options)unlesscommand_name=="help"superend#: -> Thor::CoreExt::HashWithIndifferentAccessdefoptions@merged_options||=beginoriginal_options=superconfig_options=config_options(original_options)merge_options(defaults,config_options,original_options)endendprivate#: (Hash[Symbol, Thor::Option] options) -> voiddeffilter_defaults(options)options.eachdo|key,option|# Store the value of the current default in our defaults hashdefaults[key]=option.default# Remove the default value from the optionoption.instance_variable_set(:@default,nil)endend#: (Thor::CoreExt::HashWithIndifferentAccess options) -> Thor::CoreExt::HashWithIndifferentAccessdefconfig_options(options)config_file=options[:config]config={}ifFile.exist?(config_file)config=YAML.load_file(config_file,fallback: {})endvalidate_config!(config_file,config)Thor::CoreExt::HashWithIndifferentAccess.new(config[command_name]||{})end#: (String config_file, Hash[untyped, untyped] config) -> voiddefvalidate_config!(config_file,config)# To ensure that this is not re-entered, we mark during validationreturnif@validating_config@validating_config=true#: bool?commands=T.cast(self,Thor).class.commandserrors=config.flat_mapdo|config_key,config_options|command=commands[config_key.to_s]unlesscommandnextbuild_error("unknown key `#{config_key}`")endvalidate_config_options(command.options,config_key,config_options||{})end.compactunlesserrors.empty?raiseThor::Error,build_error_message(config_file,errors)endensure@validating_config=falseend#: (Hash[Symbol, Thor::Option] command_options, String config_key, Hash[untyped, untyped] config_options) -> Array[ConfigError]defvalidate_config_options(command_options,config_key,config_options)config_options.filter_mapdo|config_option_key,config_option_value|command_option=command_options[config_option_key.to_sym]error_msg="unknown option `#{config_option_key}` for key `#{config_key}`"nextbuild_error(error_msg)unlesscommand_optionconfig_option_value_type=caseconfig_option_valuewhenFalseClass,TrueClass:booleanwhenNumeric:numericwhenHash:hashwhenArray:arraywhenString:stringelse:objectenderror_msg="invalid value for option `#{config_option_key}` for key `#{config_key}` - expected "\"`#{command_option.type.capitalize}` but found #{config_option_value_type.capitalize}"nextbuild_error(error_msg)unlessconfig_option_value_type==command_option.typecaseconfig_option_value_typewhen:arrayerror_msg="invalid value for option `#{config_option_key}` for key `#{config_key}` - expected "\"`Array[String]` but found `#{config_option_value}`"nextbuild_error(error_msg)unlessconfig_option_value.all?{|v|v.is_a?(String)}when:hasherror_msg="invalid value for option `#{config_option_key}` for key `#{config_key}` - expected "\"`Hash[String, String]` but found `#{config_option_value}`"values_to_validate=config_option_value.keysvalues_to_validate+=config_option_value.valuesall_strings=values_to_validate.all?{|v|v.is_a?(String)}nextbuild_error(error_msg)unlessall_stringsendendendclassConfigErrorMessagePart<T::Structconst:message,Stringconst:colors,T::Array[Symbol]endclassConfigError<T::Structconst:message_parts,T::Array[ConfigErrorMessagePart]end#: (String msg) -> ConfigErrordefbuild_error(msg)parts=msg.split(/(`[^`]+` ?)/)message_parts=parts.mapdo|part|match=part.match(/`([^`]+)`( ?)/)ifmatchConfigErrorMessagePart.new(message: "#{match[1]}#{match[2]}",colors: [:bold,:blue],)elseConfigErrorMessagePart.new(message: part,colors: [:yellow],)endendConfigError.new(message_parts: message_parts,)end#: (String config_file, Array[ConfigError] errors) -> Stringdefbuild_error_message(config_file,errors)error_messages=errors.mapdo|error|"- "+error.message_parts.mapdo|part|T.unsafe(self).set_color(part.message,*part.colors)end.joinend.join("\n")<<~ERROR#{set_color("\nConfiguration file",:red)}#{set_color(config_file,:blue,:bold)}#{set_color("has the following errors:",:red)}#{error_messages} ERRORend#: (*Thor::CoreExt::HashWithIndifferentAccess? options) -> Thor::CoreExt::HashWithIndifferentAccessdefmerge_options(*options)merged=options.each_with_object({})do|option,result|result.merge!(option||{})do|_,this_val,other_val|ifthis_val.is_a?(Hash)&&other_val.is_a?(Hash)Thor::CoreExt::HashWithIndifferentAccess.new(this_val.merge(other_val))elseother_valendendendThor::CoreExt::HashWithIndifferentAccess.new(merged)endendend