Skip to content

Commit d6ee5b4

Browse files
committed
Dogfood JSONCodec for icon parsing
1 parent 09664e4 commit d6ee5b4

3 files changed

Lines changed: 64 additions & 94 deletions

File tree

lib/iconify/icon.ex

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,22 @@ defmodule Iconify.Icon do
33
Represents a single normalized Iconify icon.
44
"""
55

6+
use JSONCodec, case: :camel, fast_path: :json
7+
68
@derive Jason.Encoder
9+
defstruct [
10+
:name,
11+
:body,
12+
width: 16,
13+
height: 16,
14+
left: 0,
15+
top: 0,
16+
rotate: 0,
17+
h_flip: false,
18+
v_flip: false,
19+
hidden: false
20+
]
21+
722
@type t :: %__MODULE__{
823
name: String.t(),
924
body: String.t(),
@@ -17,19 +32,11 @@ defmodule Iconify.Icon do
1732
hidden: boolean()
1833
}
1934

20-
@enforce_keys [:name, :body]
21-
defstruct [
22-
:name,
23-
:body,
24-
width: 16,
25-
height: 16,
26-
left: 0,
27-
top: 0,
28-
rotate: 0,
29-
h_flip: false,
30-
v_flip: false,
31-
hidden: false
32-
]
35+
codec(:rotate, transform: :normalize_rotate)
36+
37+
@doc false
38+
def normalize_rotate(value) when is_integer(value), do: Integer.mod(value, 4)
39+
def normalize_rotate(_value), do: 0
3340

3441
@doc """
3542
Returns the viewBox string for this icon.

lib/iconify/set.ex

Lines changed: 43 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,11 @@ defmodule Iconify.Set do
33
Represents an Iconify icon set (collection of icons with a common prefix).
44
"""
55

6+
use JSONCodec, case: :camel, fast_path: :json
7+
68
alias Iconify.Icon
79

810
@derive Jason.Encoder
9-
@type t :: %__MODULE__{
10-
prefix: String.t(),
11-
icons: %{String.t() => Icon.t()},
12-
aliases: %{String.t() => map()},
13-
width: pos_integer(),
14-
height: pos_integer(),
15-
left: integer(),
16-
top: integer(),
17-
provider: String.t() | nil,
18-
info: map() | nil,
19-
chars: map() | nil,
20-
categories: map() | nil,
21-
themes: map() | nil,
22-
prefixes: map() | nil,
23-
suffixes: map() | nil,
24-
last_modified: integer() | nil,
25-
not_found: [String.t()]
26-
}
27-
28-
@enforce_keys [:prefix]
2911
defstruct [
3012
:prefix,
3113
icons: %{},
@@ -45,27 +27,46 @@ defmodule Iconify.Set do
4527
not_found: []
4628
]
4729

48-
@keys [
49-
:prefix,
50-
:icons,
51-
:aliases,
52-
:width,
53-
:height,
54-
:left,
55-
:top,
56-
:provider,
57-
:info,
58-
:chars,
59-
:categories,
60-
:themes,
61-
:prefixes,
62-
:suffixes,
63-
:last_modified,
64-
:not_found
65-
]
30+
@type t :: %__MODULE__{
31+
prefix: String.t(),
32+
icons: %{String.t() => Icon.t()},
33+
aliases: %{String.t() => map()},
34+
width: pos_integer(),
35+
height: pos_integer(),
36+
left: integer(),
37+
top: integer(),
38+
provider: String.t() | nil,
39+
info: map() | nil,
40+
chars: map() | nil,
41+
categories: map() | nil,
42+
themes: map() | nil,
43+
prefixes: map() | nil,
44+
suffixes: map() | nil,
45+
last_modified: integer() | nil,
46+
not_found: [String.t()]
47+
}
48+
49+
codec(:icons, values: :icon_value)
50+
codec(:aliases, values: :alias_value)
51+
codec(:not_found, as: "not_found")
6652

6753
@alias_keys [:parent, :left, :top, :width, :height, :rotate, :h_flip, :v_flip, :hidden]
6854

55+
@doc false
56+
def icon_value(name, data, source) do
57+
source
58+
|> icon_defaults()
59+
|> Map.merge(data)
60+
|> Map.put("name", name)
61+
end
62+
63+
@doc false
64+
def alias_value(_name, data, _source) do
65+
data
66+
|> normalize_map()
67+
|> Map.take(@alias_keys)
68+
end
69+
6970
@doc """
7071
Loads an icon set from a JSON file.
7172
"""
@@ -102,21 +103,7 @@ defmodule Iconify.Set do
102103
"""
103104
@spec parse_data(map()) :: {:ok, t()} | {:error, term()}
104105
def parse_data(data) when is_map(data) do
105-
data = normalize_map(data)
106-
defaults = Map.take(data, [:left, :top, :width, :height, :rotate, :h_flip, :v_flip])
107-
108-
set =
109-
struct!(
110-
__MODULE__,
111-
data
112-
|> Map.take(@keys)
113-
|> Map.put(:icons, parse_icons(data, defaults))
114-
|> Map.put(:aliases, parse_aliases(data))
115-
)
116-
117-
{:ok, set}
118-
rescue
119-
exception -> {:error, exception}
106+
from_map(data)
120107
end
121108

122109
@doc """
@@ -173,32 +160,6 @@ defmodule Iconify.Set do
173160
map_size(icons)
174161
end
175162

176-
defp parse_icons(data, defaults) do
177-
data
178-
|> Map.get(:icons, %{})
179-
|> Map.new(fn {name, icon_data} ->
180-
{name, build_icon(name, icon_data, defaults)}
181-
end)
182-
end
183-
184-
defp build_icon(name, data, defaults) do
185-
attrs =
186-
defaults
187-
|> Map.merge(normalize_map(data))
188-
|> Map.put(:name, name)
189-
|> Map.update(:rotate, 0, &normalize_rotate/1)
190-
191-
struct!(Icon, attrs)
192-
end
193-
194-
defp parse_aliases(data) do
195-
data
196-
|> Map.get(:aliases, %{})
197-
|> Map.new(fn {name, alias_data} ->
198-
{name, alias_data |> normalize_map() |> Map.take(@alias_keys)}
199-
end)
200-
end
201-
202163
defp resolve_icon(set, name, seen) do
203164
cond do
204165
MapSet.member?(seen, name) ->
@@ -244,8 +205,9 @@ defmodule Iconify.Set do
244205

245206
defp xor(left, right), do: !!left != !!right
246207

247-
defp normalize_rotate(value) when is_integer(value), do: Integer.mod(value, 4)
248-
defp normalize_rotate(_), do: 0
208+
defp icon_defaults(data) do
209+
Map.take(data, ["left", "top", "width", "height", "rotate", "hFlip", "vFlip"])
210+
end
249211

250212
defp normalize_map(map) do
251213
Map.new(map, fn {key, value} -> {normalize_key(key), value} end)

mix.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ defmodule Iconify.MixProject do
2828
defp deps do
2929
[
3030
{:jason, "~> 1.4"},
31+
{:json_codec, path: "../json_codec"},
3132
{:req, "~> 0.5"},
3233
{:credo, "~> 1.7", only: [:dev, :test], runtime: false},
3334
{:reach, "~> 2.0", only: [:dev, :test], runtime: false},

0 commit comments

Comments
 (0)