defmodule Noizu.Github.Format do @moduledoc """ Hand-maintained, curated views over generated structs. The generated structs under `lib/api/structs/` are full, spec-faithful and permissive — great for fidelity, noisy for display. This module layers the curated `:basic` projections that the original hand-written client exposed via per-struct `format/2` helpers, without touching (or being wiped by) the generator. Unknown shapes pass through unchanged, so `format/2` is always safe to call. Noizu.Github.Format.format(issue) # => %{id: 1, title: ..., ...} Noizu.Github.Format.format(collection, :basic) # => [%{...}, ...] """ alias Noizu.Github.{Issue, Label, SimpleUser, NullableSimpleUser, Collection} @type format :: :basic @doc "Project a generated struct (or list/collection of them) into a curated view." @spec format(term, format) :: term def format(value, format \\ :basic) def format(nil, _format), do: nil def format(list, format) when is_list(list), do: Enum.map(list, &format(&1, format)) # Collections unwrap to their items. def format(%Collection{items: items}, format), do: format(items, format) def format(%{__struct__: mod, items: items}, format) when mod in [ Collection.Issue, Collection.Label, Collection.SimpleUser ], do: format(items, format) def format(%Issue{} = this, :basic) do %{ id: this.number, internal_id: this.id, url: this.html_url, labels: format(this.labels, :basic), title: this.title, body: this.body, state: this.state, reactions: this.reactions, user: format(this.user, :basic), assignee: format(this.assignee, :basic), assignees: format(this.assignees, :basic), milestone: this.milestone, comments: this.comments, created_at: this.created_at, updated_at: this.updated_at, closed_at: this.closed_at } end def format(%SimpleUser{} = this, :basic), do: user_basic(this) def format(%NullableSimpleUser{} = this, :basic), do: user_basic(this) def format(%Label{} = this, :basic), do: %{name: this.name, color: this.color} # `issue.labels` decode to raw maps (the schema's `oneOf[string, object]`). def format(%{name: name} = label, :basic) when is_map(label) and not is_struct(label) do %{name: name, color: Map.get(label, :color)} end def format(other, _format), do: other defp user_basic(user) do %{login: user.login, avatar_url: user.avatar_url, url: user.html_url} end end