lib/tapioca/cli.rb in tapioca-0.4.27 vs lib/tapioca/cli.rb in tapioca-0.5.0

- old
+ new

@@ -1,8 +1,262 @@ # typed: true # frozen_string_literal: true -require 'thor' +require "thor" module Tapioca - module Cli; end + class Cli < Thor + include(Thor::Actions) + + class_option :outdir, + aliases: ["--out", "-o"], + banner: "directory", + desc: "The output directory for generated RBI files" + class_option :generate_command, + aliases: ["--cmd", "-c"], + banner: "command", + desc: "The command to run to regenerate RBI files" + class_option :file_header, + type: :boolean, + default: true, + desc: "Add a \"This file is generated\" header on top of each generated RBI file" + class_option :verbose, + aliases: ["-V"], + type: :boolean, + default: false, + desc: "Verbose output for debugging purposes" + + map T.unsafe(["--version", "-v"] => :__print_version) + + desc "init", "initializes folder structure" + def init + create_config + create_post_require + generate_binstub + end + + desc "require", "generate the list of files to be required by tapioca" + def require + Tapioca.silence_warnings do + generator.build_requires + end + end + + desc "todo", "generate the list of unresolved constants" + def todo + Tapioca.silence_warnings do + generator.build_todos + end + end + + desc "dsl [constant...]", "generate RBIs for dynamic methods" + option :generators, + type: :array, + aliases: ["--gen", "-g"], + banner: "generator [generator ...]", + desc: "Only run supplied DSL generators" + option :exclude_generators, + type: :array, + banner: "generator [generator ...]", + desc: "Exclude supplied DSL generators" + option :verify, + type: :boolean, + default: false, + desc: "Verifies RBIs are up-to-date" + option :quiet, + aliases: ["-q"], + type: :boolean, + desc: "Supresses file creation output" + def dsl(*constants) + Tapioca.silence_warnings do + generator.build_dsl( + constants, + should_verify: options[:verify], + quiet: options[:quiet], + verbose: options[:verbose] + ) + end + end + + desc "gem [gem...]", "generate RBIs from gems" + option :all, + type: :boolean, + default: false, + desc: "Regenerate RBI files for all gems" + option :prerequire, + aliases: ["--pre", "-b"], + banner: "file", + desc: "A file to be required before Bundler.require is called" + option :postrequire, + aliases: ["--post", "-a"], + banner: "file", + desc: "A file to be required after Bundler.require is called" + option :exclude, + aliases: ["-x"], + type: :array, + banner: "gem [gem ...]", + desc: "Excludes the given gem(s) from RBI generation" + option :typed_overrides, + aliases: ["--typed", "-t"], + type: :hash, + banner: "gem:level [gem:level ...]", + desc: "Overrides for typed sigils for generated gem RBIs" + option :verify, + type: :boolean, + default: false, + desc: "Verifies RBIs are up-to-date" + def gem(*gems) + Tapioca.silence_warnings do + all = options[:all] + verify = options[:verify] + + raise MalformattedArgumentError, "Options '--all' and '--verify' are mutually exclusive" if all && verify + + unless gems.empty? + raise MalformattedArgumentError, "Option '--all' must be provided without any other arguments" if all + raise MalformattedArgumentError, "Option '--verify' must be provided without any other arguments" if verify + end + + if gems.empty? && !all + generator.sync_rbis_with_gemfile(should_verify: verify) + else + generator.build_gem_rbis(all ? [] : gems) + end + end + end + + desc "generate [gem...]", "DEPRECATED: generate RBIs from gems" + option :prerequire, + aliases: ["--pre", "-b"], + banner: "file", + desc: "A file to be required before Bundler.require is called" + option :postrequire, + aliases: ["--post", "-a"], + banner: "file", + desc: "A file to be required after Bundler.require is called" + option :exclude, + aliases: ["-x"], + type: :array, + banner: "gem [gem ...]", + desc: "Excludes the given gem(s) from RBI generation" + option :typed_overrides, + aliases: ["--typed", "-t"], + type: :hash, + banner: "gem:level [gem:level ...]", + desc: "Overrides for typed sigils for generated gem RBIs" + def generate(*gems) + gem_names = if gems.empty? + "--all" + else + gems.join(" ") + end + deprecation_message = <<~MSG + DEPRECATION: The `generate` command will be removed in a future release. + + Start using `bin/tapioca gem #{gem_names}` instead. + MSG + + say(deprecation_message, :red) + say("") + + Tapioca.silence_warnings do + generator.build_gem_rbis(gems) + end + + say("") + say(deprecation_message, :red) + end + + desc "sync", "DEPRECATED: sync RBIs to Gemfile" + option :prerequire, + aliases: ["--pre", "-b"], + banner: "file", + desc: "A file to be required before Bundler.require is called" + option :postrequire, + aliases: ["--post", "-a"], + banner: "file", + desc: "A file to be required after Bundler.require is called" + option :exclude, + aliases: ["-x"], + type: :array, + banner: "gem [gem ...]", + desc: "Excludes the given gem(s) from RBI generation" + option :typed_overrides, + aliases: ["--typed", "-t"], + type: :hash, + banner: "gem:level [gem:level ...]", + desc: "Overrides for typed sigils for generated gem RBIs" + option :verify, + type: :boolean, + default: false, + desc: "Verifies RBIs are up-to-date" + def sync + deprecation_message = <<~MSG + DEPRECATION: The `sync` command will be removed in a future release. + + Start using `bin/tapioca gem` instead. + MSG + + say(deprecation_message, :red) + say("") + + Tapioca.silence_warnings do + generator.sync_rbis_with_gemfile(should_verify: options[:verify]) + end + + say("") + say(deprecation_message, :red) + end + + desc "--version, -v", "show version" + def __print_version + puts "Tapioca v#{Tapioca::VERSION}" + end + + private + + def create_config + create_file(Config::SORBET_CONFIG, skip: true) do + <<~CONTENT + --dir + . + CONTENT + end + end + + def create_post_require + create_file(Config::DEFAULT_POSTREQUIRE, skip: true) do + <<~CONTENT + # typed: true + # frozen_string_literal: true + + # Add your extra requires here (`tapioca require` can be used to boostrap this list) + CONTENT + end + end + + def generate_binstub + bin_stub_exists = File.exist?("bin/tapioca") + installer = Bundler::Installer.new(Bundler.root, Bundler.definition) + spec = Bundler.definition.specs.find { |s| s.name == "tapioca" } + installer.generate_bundler_executable_stubs(spec, { force: true }) + if bin_stub_exists + shell.say_status(:force, "bin/tapioca", :yellow) + else + shell.say_status(:create, "bin/tapioca", :green) + end + end + + no_commands do + def self.exit_on_failure? + true + end + + def generator + current_command = T.must(current_command_chain.first) + @generator ||= Generator.new( + ConfigBuilder.from_options(current_command, options) + ) + end + end + end end