MobDev.Plugin.Scaffold (mob_dev v0.7.9)

Copy Markdown View Source

Pure templates + name conversions behind mix mob.new_plugin.

Inputs are a snake_case plugin name (e.g. "mob_demo_widget") and a tier (0–4). Output is a list of {relative_path, content_string} pairs the Mix task writes to disk. All conversions live here so the task stays thin and the templates are unit-testable without filesystem I/O.

Templates mirror the on-device-verified prototypes (mob_palette_demo t0, mob_demo_haptic_extras t1, mob_demo_signature_pad t2, mob_demo_kv_browser t3, mob_demo_subapp t4) so a freshly scaffolded plugin compiles + activates by the same path the prototypes already prove.

Summary

Functions

Resolves the mob version requirement for a freshly scaffolded plugin.

Returns the file list for a given tier + name. Each entry is {relative_path, content}. relative_path is relative to the plugin's root directory.

Builds the "~> MAJOR.MINOR.PATCH" requirement for a scaffolded plugin's :mob_dev dep from a concrete version: at least the mob_dev that scaffolded it (whose signing the generated release workflow relies on), within its minor. nil yields the compiled fallback.

Builds a "~> MAJOR.MINOR" mob version requirement from a concrete version.

Converts "mob_demo_widget" → "MobDemoWidget".

Name of the GitHub repo secret the release workflow signs with.

Validates a plugin name (must be a snake_case atom-friendly identifier).

Validates a tier (0 through 4).

Types

file()

@type file() :: {Path.t(), String.t()}

tier()

@type tier() :: 0 | 1 | 2 | 3 | 4

Functions

detect_mob_dev_requirement()

@spec detect_mob_dev_requirement() :: String.t()

mob_dev_requirement/1 for the running mob_dev. Impure, like detect_mob_requirement/0.

detect_mob_requirement()

@spec detect_mob_requirement() :: String.t()

Resolves the mob version requirement for a freshly scaffolded plugin.

Prefers the version of :mob actually resolved in the current project (so a plugin scaffolded inside a mob 0.7.x app pins "~> 0.7"), falling back to the compiled @fallback_mob_requirement when mob isn't loadable (scaffolding standalone). Impure — the Mix task calls this and threads the result into files_for/3; the templates themselves stay pure.

files_for(tier, name, mob_req \\ "~> 0.7", mob_dev_req \\ "~> 0.7.3")

@spec files_for(tier(), String.t(), String.t(), String.t()) :: [file()]

Returns the file list for a given tier + name. Each entry is {relative_path, content}. relative_path is relative to the plugin's root directory.

mob_req is the mob version requirement to embed in the generated mix.exs and manifest; defaults to @fallback_mob_requirement. The Mix task passes detect_mob_requirement/0 so a scaffolded plugin pins the mob it's being generated against. mob_dev_req is the same for the dev-only :mob_dev dep of a manifest-bearing plugin.

Tiers 1–4 ship a manifest, so hosts verify a signature over it. Those also get the signing release setup (signing_files/1): a .gitignore that keeps priv/mob_plugin.sig out of git, package files: that ship all of priv/, and .github/workflows/release.yml, which signs in CI right before mix hex.publish, so the published package carries a fresh v2 signature over exactly what ships. Tier 0 has nothing to sign.

mob_dev_requirement(version)

@spec mob_dev_requirement(String.t() | Version.t() | nil) :: String.t()

Builds the "~> MAJOR.MINOR.PATCH" requirement for a scaffolded plugin's :mob_dev dep from a concrete version: at least the mob_dev that scaffolded it (whose signing the generated release workflow relies on), within its minor. nil yields the compiled fallback.

mob_requirement(version)

@spec mob_requirement(String.t() | Version.t() | nil) :: String.t()

Builds a "~> MAJOR.MINOR" mob version requirement from a concrete version.

nil (mob not detectable) yields the compiled @fallback_mob_requirement. Pure so the derivation is unit-testable independent of what's installed.

module_name(name)

@spec module_name(String.t()) :: String.t()

Converts "mob_demo_widget" → "MobDemoWidget".

sign_key_secret()

@spec sign_key_secret() :: String.t()

Name of the GitHub repo secret the release workflow signs with.

validate_name(name)

@spec validate_name(String.t()) :: :ok | {:error, String.t()}

Validates a plugin name (must be a snake_case atom-friendly identifier).

validate_tier(t)

@spec validate_tier(integer()) :: :ok | {:error, String.t()}

Validates a tier (0 through 4).