# `Noizu.Tessera.Codegen`
[🔗](https://github.com/the-robot-lives/tessera/blob/v0.2.0/lib/noizu/tessera/codegen.ex#L1)

Code generators over a `Noizu.Tessera.Spec`:

  * `contract_module/1` — the exact `<snake_tag>.contract.generated.mjs`
    text of CONTRACT.md §2 (camelCase keys, deterministic key order),
    written next to the component's `.mjs` at compile time;
  * `cem/1` — a Custom Elements Manifest (schemaVersion `"1.0.0"`) as a
    JSON-encodable map with string keys. Determinism note: the CONTRACT
    module above goes through `Spec.json_literal/1`, which key-sorts maps
    explicitly; the CEM map is encoded by Jason, whose map key order is
    arbitrary but stable within an OTP build — the golden fixture pins
    whatever it produces here, so regenerate goldens rather than assuming
    an order when the CEM shape changes.

Both are pure functions of the spec — the golden fixtures under
`test/fixtures/` pin their exact output.

# `cem`

```elixir
@spec cem([Noizu.Tessera.Spec.t()]) :: map()
```

A Custom Elements Manifest (schemaVersion 1.0.0) covering
`specs`, as a JSON-encodable map with string keys.

Per component declaration: `tagName`, `attributes` (kebab name, type,
required flag, JSON-literal default), `members` (camelCase property fields
with type, `json` flag and JSON-literal default), `events` (name +
camelCase detail schema), `slots`, `cssProperties` (name + default) and
`cssParts` — the last two fed by the spec DSL's `css`/`part` declarations.
Each module carries the §8.3 custom field `tessera: {extensionApi, actions}`
— the extension-api version axis and every declared action name (D2).

# `contract_module`

```elixir
@spec contract_module(Noizu.Tessera.Spec.t()) :: String.t()
```

The `<snake_tag>.contract.generated.mjs` text for a spec, per CONTRACT.md §2.

# `contract_path`

```elixir
@spec contract_path(Noizu.Tessera.Spec.t(), String.t()) :: String.t()
```

Path of the generated contract module for a spec, under `dir`.

Fresh and fresh-tag-derived specs name by `<snake_tag>`; a `tag: :inherit`
takeover layer is keyed by the BASE tag like every other artifact, so its
stem carries the declaring module too (`Extension.snake_stem/1`, §5.8) —
sibling layers never clobber one another's contract.

# `snake_tag`

```elixir
@spec snake_tag(Noizu.Tessera.Spec.t()) :: String.t()
```

snake_case form of the tag (`persona-card` → `persona_card`).

# `write_contract_module`

```elixir
@spec write_contract_module(Noizu.Tessera.Spec.t(), String.t()) ::
  :written | :unchanged | {:error, term()}
```

Writes `contract_module/1` output to `dir/<snake_tag>.contract.generated.mjs`
only when the file's content differs — avoids rebuild loops where writing
the generated file would itself retrigger compilers/watchers.
Returns `:written | :unchanged | {:error, reason}`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
