Skip to content

oops-rs/numi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

164 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Numi logo

Numi

Numi is a blazingly fast CLI for generating code from Apple project resources. It turns asset catalogs, localization files, and file lists into generated accessors and helpers using built-in or custom templates.

Install

cargo install numi

The installed binary is named numi.

What Numi Does

  • reads .xcassets and generates image and color accessors
  • reads .strings and .xcstrings and generates localization helpers
  • reads files inputs and generates file-oriented helpers
  • renders built-in templates or custom Minijinja templates
  • supports workspace orchestration when a repo has multiple numi.toml files

Numi is built for deterministic generation workflows: check in the outputs you want, regenerate them locally, and verify them in CI with numi check.

Quick Start

Initialize a starter config in your project:

numi init

Generate code:

numi generate

Check whether committed generated files are up to date:

numi check

Workspace orchestration is also available when a repo has multiple numi.toml files:

numi generate --workspace
numi check --workspace

Minimal Config

Numi uses numi.toml as its config filename.

version = 1

[defaults]
access_level = "internal"

[defaults.bundle]
mode = "module"

[jobs.assets]
output = "Generated/Assets.swift"

[[jobs.assets.inputs]]
type = "xcassets"
path = "Resources/Assets.xcassets"

[jobs.assets.template.builtin]
language = "swift"
name = "swiftui-assets"

[jobs.l10n]
output = "Generated/L10n.swift"

[[jobs.l10n.inputs]]
type = "strings"
path = "Resources/Localization"

[jobs.l10n.template.builtin]
language = "swift"
name = "l10n"

You can also point localization generation at .xcstrings:

[jobs.l10n]
output = "Generated/L10n.swift"

[[jobs.l10n.inputs]]
type = "xcstrings"
path = "Resources/Localization"

[jobs.l10n.template.builtin]
language = "swift"
name = "l10n"

The starter config shipped with numi init lives in docs/examples/starter-numi.toml.

The same shape also works for Objective-C built-ins when you want an ObjC output:

[jobs.assets.template.builtin]
language = "objc"
name = "assets"

Commands

numi generate

  • discovers the nearest manifest unless --config is passed
  • uses the nearest local numi.toml first
  • runs one config for [jobs] manifests and the whole workspace for [workspace] manifests
  • generates outputs for all named jobs, or only selected jobs when --job is repeated
  • prints non-fatal warnings to stderr
  • may reuse cached parser outputs when inputs are unchanged

numi check

  • computes what generate would write without modifying files
  • exits 0 when outputs are current
  • exits 2 when outputs are stale
  • prints warnings to stderr without turning the run into a failure

numi dump-context

  • prints the exact JSON context a job template receives
  • only supports single-config ([jobs]) manifests and rejects workspace manifests
  • is the fastest way to debug or author custom templates

numi config locate

  • prints the resolved config path

numi config print

  • prints the resolved config with defaults materialized
  • only supports single-config ([jobs]) manifests and rejects workspace manifests

Built-In Templates

Numi currently ships these built-in templates:

  • Swift:
    • language = "swift", name = "swiftui-assets"
    • language = "swift", name = "l10n"
    • language = "swift", name = "files"
  • Objective-C:
    • language = "objc", name = "assets"
    • language = "objc", name = "l10n"
    • language = "objc", name = "files"

Fonts are supported in the template context and in custom-template workflows, but the first public release does not ship a dedicated built-in Swift template for fonts.

Current Limitations

  • .xcstrings plural and device-specific variations are skipped with warnings
  • the shipped l10n template currently emits simple no-argument accessors even when placeholder metadata is present in template context

Workspace Manifests

Repos with more than one numi.toml can orchestrate them from a repo-level numi.toml:

version = 1

[workspace]
members = ["AppUI", "Core"]

[workspace.defaults.jobs.assets.template.builtin]
language = "objc"

[workspace.member_overrides.Core]
jobs = ["assets"]

Then each member job can keep only the built-in name:

[jobs.assets.template.builtin]
name = "assets"

Workspace members are directory roots, not config-file paths. From the repo root, plain numi generate and numi check use that nearest workspace numi.toml automatically. From inside a member directory, add --workspace when you want the ancestor workspace instead of the local member manifest. Workspace defaults can provide template.builtin.language, but each job still needs to pick its own built-in name.

Custom Templates

Custom templates use Minijinja:

[jobs.l10n.template]
path = "Templates/l10n.jinja"

Numi supports {% include %} from:

  • the including template's local directory
  • the config-root search path

If the same include path exists in both places, Numi errors instead of guessing.

Start custom-template work with:

numi dump-context --job l10n

The stable context contract is documented in docs/context-schema.md.

Development

Useful local commands:

cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace

crates.io release notes for the workspace live in docs/crates-io-release.md.

About

A blazingly fast CLI for generating code from Apple project resources

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors