# `MishkaDocument.Address`
[🔗](https://github.com/mishka-group/mishka_document/blob/v0.0.1/lib/mishka_document/address.ex#L5)

A document's own address — where it is read when its admin gives it one, `/chelekom/docs` — and
where each of its pages is read under it.

A document with no address is read under the documentation's base by its slug, as it always was:
`/docs/<slug>`, its pages `/docs/<slug>/<page>`. One with an address is read there and nowhere
else: `/chelekom/docs`, its pages `/chelekom/docs/<page>`, and `/docs/chelekom` is a missing
page, as any slug that names no document there is.

A page's own part of the address is the slugs of the pages it is filed under, then its own:
`headless/switch` is the page `switch` filed under `headless`. A slug is unique among the pages
that share its parent, so the same name may be used under two parents — `/chelekom/docs/tabs` and
`/chelekom/docs/headless/tabs` are two pages.

A version's front page (`front_page`, a page at the top) is drawn at the document's own address:
its own part of the address is empty, so `/chelekom/docs` is that page, `/chelekom/docs/<its slug>`
is a missing page, and the pages filed under it sit directly under the document's address.

A group (`group_heading`) is only a heading in the contents: it has no address at all, and the
pages filed under it are addressed as if it were not there — `breadcrumb` under the group
`navigation` is `/chelekom/docs/breadcrumb`, and `/chelekom/docs/navigation` is a missing page.

A group with a page of its own (`group_page`) is read at its own slug — `/chelekom/docs/navigation`
— as any page is, and the pages filed under it still leave its slug out: `breadcrumb` stays
`/chelekom/docs/breadcrumb`. `group_page` on a page that is not a group changes nothing.

An address is a site path: segments of lower-case letters, digits and dashes, and `:lang` at most
once, where the site's language goes, as in a page's path. The rules live here because the
document, its pages, the head and the sitemap all read them, and must agree.

# `addressed?`

```elixir
@spec addressed?(map()) :: boolean()
```

Whether a page has an address: any page but a group with no page of its own.

# `check`

```elixir
@spec check(String.t()) :: :ok | {:error, :not_a_path | :in_docs_base}
```

`:ok` for a stored address the site can answer, else `{:error, reason}`: `:not_a_path`, or
`:in_docs_base` for one under the base the documents with no address are read in.

# `front_page?`

```elixir
@spec front_page?(map()) :: boolean()
```

Whether a page is its version's front page, drawn at its document's own address.

# `group?`

```elixir
@spec group?(map()) :: boolean()
```

Whether a page is a group: a heading in the contents whose slug the pages under it leave out of
their address.

# `group_page?`

```elixir
@spec group_page?(map()) :: boolean()
```

Whether a page is a group with a page of its own, read at its own slug.

# `language?`

```elixir
@spec language?(String.t()) :: boolean()
```

Whether an address holds the site's language.

# `normalize`

```elixir
@spec normalize(term()) :: String.t() | nil
```

The address as it is stored: trimmed, lower case, one leading slash and no trailing one. `nil` for
nothing at all, and a value that is not a path is handed back as it was, for `check/1` to refuse.

    normalize(" /Chelekom/Docs/ ") #=> "/chelekom/docs"
    normalize("")                   #=> nil

# `of_page`

```elixir
@spec of_page(term()) :: String.t() | nil
```

The address a page at `page_path` serves — the page path itself, or the path a `*section` capture
closes — and `nil` for any other kind of path.

    of_page("/chelekom/docs/*section") #=> "/chelekom/docs"

# `overlap?`

```elixir
@spec overlap?(String.t(), String.t()) :: boolean()
```

Whether one address holds the other — the same, or one under the other — so one document's pages
would answer at the other's: `/chelekom/docs` and `/chelekom/docs/headless` overlap.

# `page_at`

```elixir
@spec page_at([map()], [String.t()] | String.t()) :: map() | nil
```

The page among `sections` whose own part of the address is `segments` — `["headless", "switch"]`,
or the `"headless/switch"` a `*section` capture holds — or `nil`. Nothing asked, `[]` or `""`, is
the front page, when they hold one. A group is the page at an address only when it has a page of
its own.

# `page_paths`

```elixir
@spec page_paths(String.t()) :: %{document: String.t(), page: String.t()}
```

The two page paths a document at `address` is read at: its front page, and every page of it.

# `paths`

```elixir
@spec paths([map()]) :: %{optional(term()) =&gt; [String.t()]}
```

Every page's own part of its address among `sections` — the pages of one version a reader is
shown, each with its `id`, `slug`, `parent_section_id`, `front_page`, `group_heading` and
`group_page` — as `%{id => ["headless", "switch"]}`, and `[]` for the front page. A group with no
page of its own has none, and is not in it.

A page is under its parent when that parent is among them and walking up from it reaches the top;
otherwise it is at the top. That is the rule the documentation's blocks draw the contents by, so a
page's address is where the reader finds it.

# `section_path`

```elixir
@spec section_path(map(), (map() -&gt; map() | nil)) :: [String.t()]
```

A page's own part of its address, root first: the slugs of the pages it is drawn under, then its
own, a front page's and a group's left out — `[]` for the front page itself. A group with a page of
its own keeps its own slug in its own address, and only there. `parent_of` answers the parent each
page is drawn under, or `nil` at the top — which may not be the parent it names, when that one is
not published. A parent chain deeper than twenty, which only a loop makes, stops there.

# `segments`

```elixir
@spec segments(String.t()) :: [String.t()]
```

The segments of an address, `:lang` among them.

# `version_query`

```elixir
@spec version_query(map(), [map()]) :: %{optional(String.t()) =&gt; String.t()} | nil
```

The query a reader reaches `version` at among its document's published `versions`
(`version_shown/2`): `%{}` for the one shown when none is asked, `%{"v" => version_number}` for
another, and `nil` for one no `?v=` reaches — not among them, or sharing its number with a newer
one. Versions are told apart by their `id`.

# `version_shown`

```elixir
@spec version_shown([map()], String.t() | nil) :: map() | nil
```

The version a reader is shown among a document's published `versions`, each with its
`version_number`, `is_latest_for_version`, `published_at` and `inserted_at`: the one `asked` names
(`?v=`), else the one marked latest, else the newest published. `nil` when there is none.

---

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