# `A2UIAgent.DirectJson.JsonReader`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_agent/lib/a2ui_agent/direct_json/json_reader.ex#L1)

Reads the JSON a model writes, which is often almost JSON.

Both readers accept what a model commonly gets wrong and a strict
decoder rejects: a trailing comma before `]` or `}`, and a raw line
break or tab inside a string. When the text does not read as it is,
they read it again with curly quotes straightened, so a curly quote
inside a string that is otherwise valid JSON is kept.

    iex> A2UIAgent.DirectJson.JsonReader.read(~s([{"a": 1,},]))
    {:ok, [%{"a" => 1}]}

`read_partial_items/3` reads a message list that is still arriving. It
returns the messages read so far, each with whether its text was
complete. An unfinished message is healed where that is safe: an open
object or array is closed, and a string under one of the
`progressive_keys` is cut where the text ends (unless it starts like a
URL, which would name the wrong resource). Under one of the
`whole_item_keys`, an array keeps only its finished items.

    iex> A2UIAgent.DirectJson.JsonReader.read_partial_items(
    ...>   ~s([{"id": "a", "text": "Hel), ["text"])
    [{%{"id" => "a", "text" => "Hel"}, false}]

A `\u` escape of an unpaired surrogate reads as U+FFFD, since an
Elixir string cannot hold a lone surrogate.

# `read`
*since 0.1.0* 

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

Reads the complete JSON document `text`.

# `read_partial_items`
*since 0.1.0* 

```elixir
@spec read_partial_items(String.t(), Enumerable.t(), Enumerable.t()) :: [
  {term(), boolean()}
]
```

Reads a partial JSON array (or a single object) of messages into
`{message, closed?}` pairs. Text that cannot be read gives `[]`.

---

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