Noizu.Tessera.Codegen (Noizu.Tessera v0.2.0)

Copy Markdown View Source

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.

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

cem(specs)

@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(spec)

@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(spec, dir)

@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(spec)

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

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

write_contract_module(spec, dir)

@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}.