lib/mix/tasks/print_block.ex

defmodule Mix.Tasks.PrintBlock do
  @moduledoc """
  打印指定模块转换为 Block 结构的结果

  ## 使用方式

      mix print_block Module.Name [--indent 2]

  ## 选项

    * `--indent` - 缩进空格数量,默认为 2

  ## 示例

      mix print_block Enum
      mix print_block Test.Support.Math --indent 4
  """

  use Mix.Task
  alias CodemapEx.Helper.Ast

  @shortdoc "打印指定模块的 Block 结构"
  def run(args) do
    {opts, module_names, _} =
      OptionParser.parse(args,
        strict: [indent: :integer],
        aliases: [i: :indent]
      )

    indent_size = Keyword.get(opts, :indent, 2)

    case module_names do
      [] ->
        Mix.raise("请提供一个模块名称,例如:mix print_block Enum")

      [module_name | _] ->
        module =
          try do
            String.to_existing_atom("Elixir." <> module_name)
          rescue
            ArgumentError ->
              parts = String.split(module_name, ".")

              try do
                Module.concat(parts)
              rescue
                ArgumentError ->
                  Mix.raise("模块 #{module_name} 不存在或无法解析")
              end
          end

        try do
          # 将模块转换为 AST
          ast = Ast.module_to_ast(module)

          # 将 AST 转换为 Block 结构
          block = Ast.ast_to_block(ast)

          # 打印 Block 结构
          print_block(block, indent_size)
        rescue
          error ->
            Mix.raise("无法处理模块 #{module_name}: #{inspect(error)}")
        end
    end
  end

  # 打印 Block 结构
  defp print_block(block, indent_size) do
    opts = [pretty: true, width: 80, indent: indent_size, structs: false]
    IO.puts(inspect(block, opts))
  end
end