Current section

Files

Jump to
mob mix.exs
Raw

mix.exs

defmodule Mob.MixProject do
use Mix.Project
def project do
[
app: :mob,
version: "0.7.0",
elixir: "~> 1.19",
start_permanent: Mix.env() == :prod,
elixirc_paths: elixirc_paths(Mix.env()),
compilers: compilers(Mix.env()) ++ Mix.compilers(),
deps: deps(),
unused: [
ignore: [
# GenServer / behaviour callbacks (mix_unused can't see them).
{:_, :init, 1},
{:_, :handle_call, 3},
{:_, :handle_cast, 2},
{:_, :handle_info, 2},
{:_, :handle_continue, 2},
{:_, :terminate, 2},
{:_, :code_change, 3},
# Mob's public render-tree API — every component module exposes
# render/1 callable from app code. mix_unused sees no internal
# caller because it lives in user apps.
{~r/^Mob\..+/, :render, 1},
# Screen lifecycle callbacks dispatched by the Mob.Screen
# GenServer wrapper.
{~r/^Mob\..+/, :mount, 3},
{~r/^Mob\..+/, :on_start, 0},
{~r/^Mob\..+/, :on_resume, 1},
# Screen state persistence — generated by `use Mob.Screen, vsn: N`.
{~r/^Mob\..+/, :__mob_vsn__, 0},
{~r/^Mob\..+/, :__mob_persist__, 0},
{~r/^Mob\..+/, :dump_state, 1},
{~r/^Mob\..+/, :load_state, 2},
{~r/^Mob\..+/, :screen_key, 1},
# NIF stub functions in src/mob_nif.erl (apply'd via load_nif).
{:mob_nif, :_, :_},
# Mob.Test diagnostic API surface — IEx-driven, no internal
# caller in mob itself.
{~r/^Mob\.Test$/, :_, :_},
# Theme accessors — used by user apps via Mob.Theme.<name>.
{~r/^Mob\.Theme\..+/, :_, :_}
]
],
description: "BEAM-on-device mobile framework for Elixir",
source_url: "https://github.com/genericjam/mob",
homepage_url: "https://hexdocs.pm/mob",
package: package(),
docs: docs()
]
end
def application do
[
# :public_key is needed by Mob.Certs at runtime; Elixir 1.19+ strips
# unused OTP applications from the code path, so it must be declared
# here even though mob doesn't *start* it directly.
extra_applications: [:logger, :public_key]
]
end
# Two hexdocs-only injections: (1) classify unstyled <pre><code> blocks as
# Elixir so they get syntax-highlighted, and (2) render ```mermaid fenced
# blocks as SVG (ex_doc has no built-in mermaid support; GitHub renders
# them natively, so READMEs work there without this).
defp before_closing_body_tag(:html) do
"""
<script>
// Default unstyled code blocks to Elixir highlighting.
document.querySelectorAll("pre code").forEach(el => {
if (!el.className) el.className = "language-elixir";
});
</script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
<script>
document.addEventListener("DOMContentLoaded", function () {
mermaid.initialize({ startOnLoad: false });
let id = 0;
for (const codeEl of document.querySelectorAll("pre code.mermaid")) {
const preEl = codeEl.closest("pre");
const graphEl = document.createElement("div");
const graphId = "mermaid-graph-" + id++;
mermaid.render(graphId, codeEl.textContent).then(({ svg, bindFunctions }) => {
graphEl.innerHTML = svg;
if (bindFunctions) bindFunctions(graphEl);
preEl.replaceWith(graphEl);
});
}
});
</script>
"""
end
defp before_closing_body_tag(_), do: ""
defp docs do
[
main: "readme",
before_closing_body_tag: &before_closing_body_tag/1,
logo: "assets/logo/logo_full_color.png",
source_url: "https://github.com/genericjam/mob",
source_url_pattern: "https://github.com/genericjam/mob/blob/master/%{path}#L%{line}",
extras: [
"README.md": [title: "Mob"],
"CHANGELOG.md": [title: "Changelog"],
"MOB_PLUGINS.md": [title: "Plugins — Manifest Reference"],
"MOB_PLUGIN_SECURITY.md": [title: "Plugins — Security & Trust"],
"MOB_STYLES.md": [title: "Styles — Manifest Reference"],
"guides/why_beam.md": [title: "Why the BEAM?"],
"guides/getting_started.md": [title: "Getting Started"],
"guides/packages.md": [title: "First-Party Packages"],
"guides/architecture.md": [title: "Architecture & Prior Art"],
"guides/screen_lifecycle.md": [title: "Screen Lifecycle"],
"guides/events.md": [title: "Events"],
"guides/event_model.md": [title: "Event Model"],
"guides/background_execution.md": [title: "Background Execution"],
"guides/components.md": [title: "Components"],
"guides/styling.md": [title: "Styling & Native Rendering"],
"guides/theming.md": [title: "Theming"],
"guides/navigation.md": [title: "Navigation"],
"guides/device_capabilities.md": [title: "Device Capabilities"],
"guides/mobile_surface_matrix.md": [title: "Mobile Surface Matrix"],
"guides/permissions.md": [title: "Permissions"],
"guides/native_extensions.md": [title: "Native Extensions (NIFs, features)"],
"guides/plugins.md": [title: "Writing a Plugin"],
"guides/dns_on_ios.md": [title: "DNS on iOS"],
"guides/push_notifications.md": [title: "Push Notifications"],
"guides/data.md": [title: "Data & Persistence"],
"guides/testing.md": [title: "Testing"],
"guides/tooling.md": [title: "Tooling & Formatting"],
"guides/publishing.md": [title: "Publishing to App Store / TestFlight"],
"guides/troubleshooting.md": [title: "Troubleshooting"],
"guides/support_matrix.md": [title: "Device Support Matrix"],
"guides/liveview.md": [title: "LiveView Mode"],
"guides/ios_physical_device.md": [title: "iOS Physical Devices"],
"guides/agentic_coding.md": [title: "Agentic Coding"]
],
groups_for_extras: [
Guides: ~r/guides\/.*/,
Plugins: ["MOB_PLUGINS.md", "MOB_PLUGIN_SECURITY.md", "MOB_STYLES.md"]
],
groups_for_modules: [
Core: [Mob, Mob.App, Mob.Screen, Mob.ScreenState, Mob.Socket, Mob.State],
UI: [
Mob.UI,
Mob.Style,
Mob.Renderer,
Mob.Composite,
Mob.Theme,
Mob.Theme.Light,
Mob.Theme.Dark,
Mob.Theme.Adaptive
],
Navigation: [Mob.Nav.Registry],
Plugins: [Mob.Plugins, Mob.Plugins.Supervisor, Mob.Plugins.Lifecycle],
"Device APIs": [
Mob.Haptic,
Mob.Clipboard,
Mob.Share,
Mob.Permissions,
Mob.Files,
Mob.Audio,
Mob.Motion
],
"Testing & Debugging": [Mob.Test],
Tooling: [Mob.Formatter],
Internals: [Mob.Dist, Mob.NativeLogger, Mob.List, Mob.Sigil]
]
]
end
defp elixirc_paths(:test), do: ["lib", "test/onboarding", "test/onboarding/support"]
defp elixirc_paths(_), do: ["lib"]
defp package do
[
licenses: ["MIT"],
links: %{"GitHub" => "https://github.com/genericjam/mob"},
files: ~w(
lib src priv
android ios assets
mix.exs mix.lock
README.md CHANGELOG.md LICENSE
)
]
end
defp deps do
[
# HTML/HEEx template engine — same one Phoenix uses
# {:phoenix_live_view, "~> 1.0", optional: true}, # add when HEEx rendering lands
{:nimble_parsec, "~> 1.0"},
{:ex_doc, "~> 0.34", only: :dev, runtime: false},
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
{:jump_credo_checks, "~> 0.1.0", only: [:dev, :test], runtime: false},
# ex_slop — Credo check that catches AI-generated Elixir patterns
# (blanket rescue, narrator-style docs, redundant Enum chains, etc).
# Wired in via .credo.exs as `{ExSlop, []}` in the enabled list.
{:ex_slop, "~> 0.4", only: [:dev, :test], runtime: false},
{:erlfmt, "~> 1.8", only: :dev, runtime: false},
# mix_audit — CVE scan over mix.lock against the Erlef advisory feed.
# Invocation note: `mix deps.audit` alone fails with
# `YamlElixir.read_from_file/1 is undefined` because mix_audit doesn't
# ensure_all_started its yaml_elixir transitive dep before parsing
# the advisory files. CI works around this with `mix do app.start +
# deps.audit` (the app.start prefix starts the host app, which
# transitively starts yaml_elixir via the runtime tree).
{:mix_audit, "~> 2.1", only: [:dev, :test], runtime: false},
# Known Elixir 1.20-rc.4 dep warning (cosmetic, dev-only):
# lib/mix_unused/filter.ex:61 — `_.._ inside match is deprecated`.
# No upstream fix shipped yet (0.4.1 is latest, from 2024). Bump
# this version + drop this comment once mix_unused ships a 1.20-clean
# release.
{:mix_unused, "~> 0.4", only: :dev, runtime: false},
{:ecto_sqlite3, "~> 0.18", only: :test}
]
end
# `:unused` only runs in dev. Keeps test/CI logs clean.
defp compilers(:dev), do: [:unused]
defp compilers(_), do: []
end