# typed: strict# frozen_string_literal: truemoduleSpoomclassContext# Sorbet features for a contextmoduleSorbetextendT::SigextendT::Helpersrequires_ancestor{Context}# Run `bundle exec srb` in this context directorysig{params(arg: String,sorbet_bin: T.nilable(String),capture_err: T::Boolean).returns(ExecResult)}defsrb(*arg,sorbet_bin: nil,capture_err: true)res=ifsorbet_binexec("#{sorbet_bin}#{arg.join(" ")}",capture_err: capture_err)elsebundle_exec("srb #{arg.join(" ")}",capture_err: capture_err)endcaseres.exit_codewhenSpoom::Sorbet::KILLED_CODEraiseSpoom::Sorbet::Error::Killed.new("Sorbet was killed.",res)whenSpoom::Sorbet::SEGFAULT_CODEraiseSpoom::Sorbet::Error::Segfault.new("Sorbet segfaulted.",res)endresendsig{params(arg: String,sorbet_bin: T.nilable(String),capture_err: T::Boolean).returns(ExecResult)}defsrb_tc(*arg,sorbet_bin: nil,capture_err: true)arg.prepend("tc")unlesssorbet_binT.unsafe(self).srb(*arg,sorbet_bin: sorbet_bin,capture_err: capture_err)endsigdoparams(arg: String,sorbet_bin: T.nilable(String),capture_err: T::Boolean,).returns(T.nilable(T::Hash[String,Integer]))enddefsrb_metrics(*arg,sorbet_bin: nil,capture_err: true)metrics_file="metrics.tmp"T.unsafe(self).srb_tc("--metrics-file",metrics_file,*arg,sorbet_bin: sorbet_bin,capture_err: capture_err,)returnunlessfile?(metrics_file)metrics_path=absolute_path_to(metrics_file)metrics=Spoom::Sorbet::MetricsParser.parse_file(metrics_path)remove!(metrics_file)metricsend# List all files typechecked by Sorbet from its `config`sig{params(with_config: T.nilable(Spoom::Sorbet::Config),include_rbis: T::Boolean).returns(T::Array[String])}defsrb_files(with_config: nil,include_rbis: true)config=with_config||sorbet_configallowed_extensions=config.allowed_extensionsallowed_extensions=Spoom::Sorbet::Config::DEFAULT_ALLOWED_EXTENSIONSifallowed_extensions.empty?allowed_extensions-=[".rbi"]unlessinclude_rbisexcluded_patterns=config.ignore.mapdo|string|# We need to simulate the behavior of Sorbet's `--ignore` flag.## From Sorbet docs on `--ignore`:# > Ignores input files that contain the given string in their paths (relative to the input path passed to# > Sorbet). Strings beginning with / match against the prefix of these relative paths; others are substring# > matchs. Matches must be against whole folder and file names, so `foo` matches `/foo/bar.rb` and# > `/bar/foo/baz.rb` but not `/foo.rb` or `/foo2/bar.rb`.string=ifstring.start_with?("/")# Strings beginning with / match against the prefix of these relative pathsFile.join(absolute_path,string)else# Others are substring matchsFile.join(absolute_path,"**",string)end# Matches must be against whole folder and file names"#{string.delete_suffix("/")}{,/**}"endcollector=FileCollector.new(allow_extensions: allowed_extensions,exclude_patterns: excluded_patterns)collector.visit_paths(config.paths.map{|path|absolute_path_to(path)})collector.files.map{|file|file.delete_prefix("#{absolute_path}/")}.sortend# List all files typechecked by Sorbet from its `config` that matches `strictness`sigdoparams(strictness: String,with_config: T.nilable(Spoom::Sorbet::Config),include_rbis: T::Boolean,).returns(T::Array[String])enddefsrb_files_with_strictness(strictness,with_config: nil,include_rbis: true)srb_files(with_config: with_config,include_rbis: include_rbis).select{|file|read_file_strictness(file)==strictness}endsig{params(arg: String,sorbet_bin: T.nilable(String),capture_err: T::Boolean).returns(T.nilable(String))}defsrb_version(*arg,sorbet_bin: nil,capture_err: true)res=T.unsafe(self).srb_tc("--no-config","--version",*arg,sorbet_bin: sorbet_bin,capture_err: capture_err)returnunlessres.statusres.out.split(" ")[2]end# Does this context has a `sorbet/config` file?sig{returns(T::Boolean)}defhas_sorbet_config?file?(Spoom::Sorbet::CONFIG_PATH)endsig{returns(Spoom::Sorbet::Config)}defsorbet_configSpoom::Sorbet::Config.parse_string(read_sorbet_config)end# Read the contents of `sorbet/config` in this context directorysig{returns(String)}defread_sorbet_configread(Spoom::Sorbet::CONFIG_PATH)end# Set the `contents` of `sorbet/config` in this context directorysig{params(contents: String,append: T::Boolean).void}defwrite_sorbet_config!(contents,append: false)write!(Spoom::Sorbet::CONFIG_PATH,contents,append: append)end# Read the strictness sigil from the file at `relative_path` (returns `nil` if no sigil)sig{params(relative_path: String).returns(T.nilable(String))}defread_file_strictness(relative_path)Spoom::Sorbet::Sigils.file_strictness(absolute_path_to(relative_path))end# Get the commit introducing the `sorbet/config` filesig{returns(T.nilable(Spoom::Git::Commit))}defsorbet_intro_commitres=git_log("--diff-filter=A --format='%h %at' -1 -- sorbet/config")returnunlessres.statusout=res.out.stripreturnifout.empty?Spoom::Git::Commit.parse_line(out)end# Get the commit removing the `sorbet/config` filesig{returns(T.nilable(Spoom::Git::Commit))}defsorbet_removal_commitres=git_log("--diff-filter=D --format='%h %at' -1 -- sorbet/config")returnunlessres.statusout=res.out.stripreturnifout.empty?Spoom::Git::Commit.parse_line(out)endendendend