Code generators over a Noizu.Tessera.Spec:
contract_module/1— the exact<snake_tag>.contract.generated.mjstext of CONTRACT.md §2 (camelCase keys, deterministic key order), written next to the component's.mjsat 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 throughSpec.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.
Summary
Functions
A Custom Elements Manifest (schemaVersion 1.0.0) covering
specs, as a JSON-encodable map with string keys.
The <snake_tag>.contract.generated.mjs text for a spec, per CONTRACT.md §2.
Path of the generated contract module for a spec, under dir.
snake_case form of the tag (persona-card → persona_card).
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}.
Functions
@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).
@spec contract_module(Noizu.Tessera.Spec.t()) :: String.t()
The <snake_tag>.contract.generated.mjs text for a spec, per CONTRACT.md §2.
@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.
@spec snake_tag(Noizu.Tessera.Spec.t()) :: String.t()
snake_case form of the tag (persona-card → persona_card).
@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}.