Skip to content

Codegen & plugin

Codegen turns the JSON contract into a nested Swift enum tree of compile-time-safe constants. Rename a key in JSON → regenerate → the compiler flags every stale reference. That is what eliminates drift on the developer side.

CLI: tandha generate

tandha generate automation-ids.json --output Generated/AutomationID.swift

Given:

{ "login": { "username_field": "login.username_field", "submit_button": "login.submit_button" } }

it produces:

// Generated by tandha — do not edit.
public enum AutomationID {
    public enum login {
        public static let usernameField = "login.username_field"
        public static let submitButton  = "login.submit_button"
    }
}

Options

Option Effect
--output <file> Write to a file (default: stdout)
--root-name <name> Rename the root enum (default: AutomationID)
--access <level> public or internal (default: public)
--no-doc-comments Omit doc comments derived from description / screen

Namespace keys become nested enums; leaf keys become camelCased static let constants. Swift keywords are back-tick escaped, leading digits are sanitized, and description / screen metadata becomes doc comments.

SwiftPM build-tool plugin

Prefer to never run generate by hand? Add the plugin:

.target(
    name: "App",
    plugins: [.plugin(name: "TandhaCodegenPlugin", package: "tandha")]
)

Then drop a file named *.automationids.json into the target's sources — for example Sources/App/app.automationids.json. On every build the plugin regenerates the AutomationID enum and compiles it in. (1)

  1. The generated file lives in the plugin's work directory, not your source tree — there is nothing to check in, and it can never go stale.

Multiple contract files

Both the CLI and the plugin accept several JSON inputs, merged by namespace — split a large contract per screen or per team and they combine into one enum tree.