defmodule Firebird.Phoenix.Scaffold do @moduledoc """ Generates a complete Phoenix WASM application scaffold. Creates a ready-to-run project that uses Firebird's WASM-accelerated Phoenix components for HTTP request handling. ## Generated Structure my_app/ ├── lib/ │ ├── my_app/ │ │ ├── application.ex # OTP Application with Phoenix WASM supervisor │ │ ├── router.ex # Route definitions using RouterDSL │ │ ├── controllers/ │ │ │ ├── page_controller.ex │ │ │ └── user_controller.ex │ │ └── templates/ │ │ ├── layout.html.eex │ │ └── page/ │ │ └── index.html.eex │ └── my_app.ex # Main module ├── test/ │ ├── test_helper.exs │ └── my_app/ │ └── router_test.exs ├── config/ │ └── config.exs └── mix.exs """ @doc """ Generate a Phoenix WASM application scaffold. ## Parameters - `app_name` - Application name (e.g., "my_app") - `opts` - Options: - `:path` - Output directory (default: current dir + app_name) - `:module` - Module name (default: camelized app_name) ## Returns - `{:ok, path}` - Scaffold generated at path - `{:error, reason}` - Generation failed """ @spec generate(String.t(), keyword()) :: {:ok, String.t()} | {:error, term()} def generate(app_name, opts \\ []) do module_name = Keyword.get(opts, :module, Macro.camelize(app_name)) base_path = Keyword.get(opts, :path, Path.join(File.cwd!(), app_name)) files = [ {"mix.exs", mix_exs(app_name, module_name)}, {"lib/#{app_name}.ex", main_module(module_name)}, {"lib/#{app_name}/application.ex", application(module_name)}, {"lib/#{app_name}/router.ex", router(module_name)}, {"lib/#{app_name}/controllers/page_controller.ex", page_controller(module_name)}, {"lib/#{app_name}/controllers/user_controller.ex", user_controller(module_name)}, {"lib/#{app_name}/templates/layout.html.eex", layout_template()}, {"lib/#{app_name}/templates/page/index.html.eex", page_index_template()}, {"test/test_helper.exs", test_helper()}, {"test/#{app_name}/router_test.exs", router_test(module_name)}, {"config/config.exs", config(app_name)}, {"README.md", readme(app_name, module_name)} ] Enum.each(files, fn {rel_path, content} -> full_path = Path.join(base_path, rel_path) File.mkdir_p!(Path.dirname(full_path)) File.write!(full_path, content) end) {:ok, base_path} end defp mix_exs(app_name, module_name) do """ defmodule #{module_name}.MixProject do use Mix.Project def project do [ app: :#{app_name}, version: "0.1.0", elixir: "~> 1.14", start_permanent: Mix.env() == :prod, deps: deps() ] end def application do [ extra_applications: [:logger], mod: {#{module_name}.Application, []} ] end defp deps do [ {:firebird, "~> 0.1.0"}, {:jason, "~> 1.4"} ] end end """ end defp main_module(module_name) do """ defmodule #{module_name} do @moduledoc \"\"\" #{module_name} - A Phoenix WASM application powered by Firebird. \"\"\" end """ end defp application(module_name) do """ defmodule #{module_name}.Application do use Application @impl true def start(_type, _args) do children = [ {Firebird.Phoenix.Application, name: :phoenix_wasm} ] opts = [strategy: :one_for_one, name: #{module_name}.Supervisor] Supervisor.start_link(children, opts) end end """ end defp router(module_name) do """ defmodule #{module_name}.Router do use Firebird.Phoenix.RouterDSL pipeline :browser do plug "put_secure_headers" plug "accept:text/html" end pipeline :api do plug "accept:application/json" plug "cors:*" end scope "/" do get "/", "PageController.index" get "/about", "PageController.about" end scope "/api", :api do resources "/users", "UserController" end @doc \"\"\" Define action handlers for route dispatch. \"\"\" def actions do %{ "PageController.index" => {200, "text/html", "

Welcome to #{module_name}

"}, "PageController.about" => {200, "text/html", "

About

"}, "UserController.index" => {200, "application/json", "[]"}, "UserController.show" => {200, "application/json", ~s({"id":"{{id}}"})}, "UserController.create" => {201, "application/json", ~s({"status":"created"})}, "UserController.update" => {200, "application/json", ~s({"id":"{{id}}","status":"updated"})}, "UserController.delete" => {204, "text/plain", ""} } end @doc \"\"\" Handle a request using the WASM router and endpoint. \"\"\" def handle_request(method, path) do Firebird.Phoenix.Application.process_request(:phoenix_wasm, method: method, path: path, routes: routes(), actions: actions() ) end end """ end defp page_controller(module_name) do """ defmodule #{module_name}.PageController do @moduledoc "Handles page requests." def index(_params) do {200, "text/html", "

Welcome to #{module_name}!

"} end def about(_params) do {200, "text/html", "

About #{module_name}

Powered by Firebird WASM

"} end end """ end defp user_controller(module_name) do """ defmodule #{module_name}.UserController do @moduledoc "Handles user API requests." def index(_params) do {200, "application/json", ~s([{"id":"1","name":"Alice"},{"id":"2","name":"Bob"}])} end def show(%{"id" => id}) do {200, "application/json", ~s({"id":"#{"\#{id}"}","name":"User #{"\#{id}}"}"})} end def create(_params) do {201, "application/json", ~s({"status":"created"})} end def update(%{"id" => id}) do {200, "application/json", ~s({"id":"#{"\#{id}"}","status":"updated"})} end def delete(_params) do {204, "text/plain", ""} end end """ end defp layout_template do """ <%= @title %>
<%= @inner_content %>
""" end defp page_index_template do """

Welcome!

This application is powered by Firebird Phoenix WASM.

All request processing uses WebAssembly modules for:

""" end defp test_helper do """ ExUnit.start() """ end defp router_test(module_name) do """ defmodule #{module_name}.RouterTest do use ExUnit.Case import Firebird.Phoenix.Testing test "routes are defined" do routes = #{module_name}.Router.routes() assert length(routes) > 0 end test "pipelines are defined" do pipelines = #{module_name}.Router.pipelines() assert Map.has_key?(pipelines, :browser) assert Map.has_key?(pipelines, :api) end test "actions are defined" do actions = #{module_name}.Router.actions() assert Map.has_key?(actions, "PageController.index") assert Map.has_key?(actions, "UserController.show") end end """ end defp config(app_name) do """ import Config config :#{app_name}, phoenix_wasm: [ components: [:router, :template, :plug, :endpoint, :json] ] config :logger, level: :info """ end defp readme(_app_name, module_name) do """ # #{module_name} A Phoenix WASM application powered by [Firebird](https://github.com/hdresearch/firebird). ## Getting Started ```bash mix deps.get mix test ``` ## Architecture This application uses Firebird's WASM-accelerated Phoenix components: - **Router** (`#{module_name}.Router`) - Route definitions using Firebird DSL - **Endpoint** - WASM-based request lifecycle processing - **Controllers** - Action handlers for each route - **Templates** - EEx templates compiled to WASM-compatible format ## API Routes | Method | Path | Handler | |--------|------|---------| #{Enum.map_join(["GET /", "GET /about", "GET /api/users", "GET /api/users/:id", "POST /api/users", "PUT /api/users/:id", "DELETE /api/users/:id"], "\n", fn route -> [method, path] = String.split(route, " ", parts: 2) "| #{method} | #{path} | Auto-dispatched |" end)} ## Usage ```elixir # Handle a request {:ok, resp} = #{module_name}.Router.handle_request("GET", "/api/users/42") resp.status # => 200 resp.body # => {"id":"42"} ``` """ end end