# `MishkaChelekom.DemoAssignsExtractor`
[🔗](https://github.com/mishka-group/mishka_chelekom/blob/v0.0.9/lib/mishka_chelekom/demo_assigns_extractor.ex#L1)

Extract initial-render assigns from a demo `<comp>_live.ex` file.

Walks the companion `mount/3` body via Sourceror, finds every
`assign/2` and `assign/3` call, and tries to evaluate the value
expression at export time. Successful evaluations are kept as Elixir
terms; unsafe / unsupported expressions are dropped with a build-time
warning so the eventual JSON only carries data the consumer (CMS)
can serialize and consume without `Code.eval_string/1`.

## Returned shape

    {%{posts: %{total: 10, active: 1}, csp_nonce: nil, …},
     [
       {"code_1", :unsupported_expression},
       {"seo_tags", :unsafe_call}
     ]}

Skip rules are deliberately conservative — anything that looks like
IO / DB / process state / unbound module call is skipped:

  * Function captures (`&fun/1`)
  * Calls into modules we don't whitelist
  * `~p"..."` route helpers (the verified-routes macro requires a
    router context that the export environment doesn't have)
  * `Phoenix.LiveView.JS` struct literals (we keep them — JS is
    whitelisted because it's pure data)

# `extraction_result`

```elixir
@type extraction_result() ::
  {map(), [{atom(), :unsupported_expression | :unsafe_call | :raised}]}
```

# `extract_from_file`

```elixir
@spec extract_from_file(Path.t()) :: extraction_result()
```

Read the file at `path` and return `{assigns_map, skipped_entries}`.
Missing files yield `{%{}, []}`.

# `extract_from_source`

```elixir
@spec extract_from_source(String.t()) :: extraction_result()
```

---

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