defmodule Mix.Tasks.Firebird.Inspect do @moduledoc """ Inspect a WASM module and display its exports. ## Usage mix firebird.inspect fixtures/math.wasm mix firebird.inspect fixtures/go_math.wasm --wasi mix firebird.inspect fixtures/math.wasm --generate MyApp.Math mix firebird.inspect fixtures/math.wasm --generate MyApp.Math --style wasm_module ## Options - `--wasi` - Enable WASI support (required for Go/TinyGo modules) - `--generate MODULE` - Generate an Elixir module wrapper - `--style module|wasm_module` - Module style (default: module) """ use Mix.Task @shortdoc "Inspect a WASM module's exports and types" @switches [ wasi: :boolean, generate: :string, style: :string ] @impl Mix.Task def run(args) do Mix.Task.run("app.start") {opts, rest, _} = OptionParser.parse(args, switches: @switches) case rest do [path] -> wasi = Keyword.get(opts, :wasi, false) case Firebird.Inspector.inspect_file(path, wasi: wasi) do {:ok, info} -> if gen_name = Keyword.get(opts, :generate) do style = case Keyword.get(opts, :style, "module") do "wasm_module" -> :wasm_module _ -> :module end code = Firebird.Inspector.generate_module(gen_name, path, wasi: wasi, style: style) Mix.shell().info(code) else print_info(path, info) end {:error, reason} -> Mix.shell().error("Error: #{inspect(reason)}") end _ -> Mix.shell().info(@moduledoc) end end defp print_info(path, info) do Mix.shell().info("🔍 WASM Module: #{path}") Mix.shell().info(" Size: #{info.size_bytes} bytes") Mix.shell().info(" Exports: #{info.export_count} total (#{info.function_count} functions)") Mix.shell().info("") if length(info.functions) > 0 do Mix.shell().info(" Functions:") for f <- info.functions do params = Enum.join(Enum.map(f.params, &to_string/1), ", ") results = Enum.join(Enum.map(f.results, &to_string/1), ", ") sig = "(#{params}) -> #{results}" Mix.shell().info(" #{f.name}#{sig}") end end if length(info.memories) > 0 do Mix.shell().info("") Mix.shell().info(" Memories:") for m <- info.memories do Mix.shell().info(" #{m.name}: #{m.min_pages} pages (#{m.min_pages * 64}KB)") end end if length(info.globals) > 0 do Mix.shell().info("") Mix.shell().info(" Globals:") for g <- info.globals do Mix.shell().info(" #{g.name}: #{g.type} (#{g.mutability})") end end end end