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

SPIKE (`spike/elixir-to-lit`): `~TSR` element-template parsing and lit-html
emission (docs/notes/spike-elixir-to-lit.md §template-parser).

Two lexers produce the SAME token stream, and one tree-ifier builds the
tree (`parse/1`):

  * **Hologram path** — when Hologram 0.10.1 is compiled into the path, the
    markup is tokenized by `Hologram.Template.Parser.parse_markup/1` (a
    public, documented, pure function on an `@moduledoc false` module —
    de-facto internal-but-callable; see the notes for the stability
    discussion). Its flat parsed-tag stream is converted 1:1 into the
    subset token stream below.
  * **Minimal path** — a hand-rolled lexer for exactly the subset (plain
    elements, static/interpolated attributes, `{expr}`, `{%if}/{%else}/{/if}`,
    `{%for pat <- expr}/{/for}`, `$event={:action[, params]}`,
    `{%region :name}/{%endregion}`, `{%super%}`), used when Hologram is
    absent so spec-only consumers (npm/UMD packaging without a Hologram
    host) still compile.

Region-bearing markup ALWAYS lexes through the minimal lexer on both hosts
(brief 2d, T1-1): Hologram's `parse_markup` does not know `{%region%}`, so
`lex/1` forces the minimal path whenever the markup mentions a region or the
`{%super%}` marker — one token stream, one tree shape, on every host.

Token stream (the shared subset):

    {:start_tag, tag, attrs} | {:self_closing_tag, tag, attrs} | {:end_tag, tag}
    {:text, s} | {:expr, ast}
    {:if_start, ast} | :else | :if_end
    {:for_start, var, coll_ast} | :for_end
    {:region_start, name} | :region_end | :super

    attrs :: [{name, {:static, s} | {:parts, [{:text, s} | {:expr, expr_string}]}}
              | {:"$event", dom_event, binding_src}
              | {:"$bool", name, {:static, s} | {:parts, [...]}}]

`?attr={expr}` (Lit boolean attribute binding) shares the `{:"$bool", …}`
form across both lexers; `<slot>…</slot>` (non-void, fallback content) is
supported under both lexers — the Hologram path renames slot tags through
a reserved placeholder because Hologram's parser treats `<slot>` as void.

Tree shape:

    {:element, tag, attrs, children} | {:text, s} | {:expr, ast}
    {:if, ast, children, else_children} | {:for, var, coll_ast, children}
    {:fragment, children}

`to_lit_render/2` emits a Lit `render()` body as nested `html` template
literals.

# `compile_region_methods`

```elixir
@spec compile_region_methods(term(), Noizu.Tessera.Component.Expr.t()) :: [
  %{name: atom(), js: String.t()}
]
```

Compile the default region bodies of a template tree into method fragments
`%{name: atom, js: "html`...`"}` (the derived render() references them via
`${this.__region_<name>()}`). Duplicate region names raise a CompileError.

# `compile_region_override`

```elixir
@spec compile_region_override(atom(), term(), Noizu.Tessera.Component.Expr.t()) :: %{
  name: atom(),
  js: String.t()
}
```

Compile one `slot_template :name` override body. `{%super%}` inside the body
lowers to `super.__region_<name>()` (the base default fragment at that point
in the chain).

# `lexer`

```elixir
@spec lexer() :: :hologram | :minimal
```

Which lexer `parse/1` uses right now.

# `lexer_for`

```elixir
@spec lexer_for(String.t()) :: :hologram | :minimal
```

Which lexer `parse/1` will use for THIS markup (brief 2d / T1-1): region
markup always lexes `:minimal` — Hologram's parser does not know
`{%region :name}`/`{%endregion}`/`{%super%}` — everything else follows the
host (`:hologram` when the dep is present).

# `minimal_lex`

```elixir
@spec minimal_lex(String.t()) :: {:ok, list()} | {:error, String.t()}
```

Minimal lexer for exactly the subset (used when Hologram is not loaded).

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, term()} | {:error, String.t()}
```

Parse markup into the subset tree. Uses Hologram's template parser when
compiled in, otherwise the minimal lexer. Returns `{:ok, tree}` or
`{:error, message}` (message names the construct).

# `regions`

```elixir
@spec regions(term()) :: [%{name: atom(), nested: [atom()]}]
```

Declared regions of a parsed tree, preorder (outer before inner), as
`%{name: atom, nested: [atom]}` where `nested` lists every region name
appearing anywhere inside the region's body.

# `to_lit_render`

```elixir
@spec to_lit_render(term(), Noizu.Tessera.Component.Expr.t()) :: String.t()
```

Emit the JavaScript expression for a Lit `render()` body (without the
leading `return`). `ctx` is a `Noizu.Tessera.Component.Expr` context.

# `treeify`

```elixir
@spec treeify(list(), list(), list()) :: {:ok, term()} | {:error, String.t()}
```

Tree-ify the shared token stream. Frames: `{:elem, {tag, attrs, children}}`,
`{:if, {ast, then, else}}`, `{:else, {ast, then, else}}`,
`{:for, {var, coll, children}}`. Top-level nodes accumulate in `top`.

---

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