Merge remote-tracking branch 'remotes/origin/develop' into 1505-threads-federation
[akkoma] / lib / pleroma / docs / generator.ex
1 defmodule Pleroma.Docs.Generator do
2 @callback process(keyword()) :: {:ok, String.t()}
3
4 @spec process(module(), keyword()) :: {:ok, String.t()}
5 def process(implementation, descriptions) do
6 implementation.process(descriptions)
7 end
8
9 @spec list_modules_in_dir(String.t(), String.t()) :: [module()]
10 def list_modules_in_dir(dir, start) do
11 with {:ok, files} <- File.ls(dir) do
12 files
13 |> Enum.filter(&String.ends_with?(&1, ".ex"))
14 |> Enum.map(fn filename ->
15 module = filename |> String.trim_trailing(".ex") |> Macro.camelize()
16 String.to_atom(start <> module)
17 end)
18 end
19 end
20
21 @doc """
22 Converts:
23 - atoms to strings with leading `:`
24 - module names to strings, without leading `Elixir.`
25 - add humanized labels to `keys` if label is not defined, e.g. `:instance` -> `Instance`
26 """
27 @spec convert_to_strings([map()]) :: [map()]
28 def convert_to_strings(descriptions) do
29 Enum.map(descriptions, &format_entity(&1))
30 end
31
32 defp format_entity(entity) do
33 entity
34 |> format_key()
35 |> Map.put(:group, atom_to_string(entity[:group]))
36 |> format_children()
37 end
38
39 defp format_key(%{key: key} = entity) do
40 entity
41 |> Map.put(:key, atom_to_string(key))
42 |> Map.put(:label, entity[:label] || humanize(key))
43 end
44
45 defp format_key(%{group: group} = entity) do
46 Map.put(entity, :label, entity[:label] || humanize(group))
47 end
48
49 defp format_key(entity), do: entity
50
51 defp format_children(%{children: children} = entity) do
52 Map.put(entity, :children, Enum.map(children, &format_child(&1)))
53 end
54
55 defp format_children(entity), do: entity
56
57 defp format_child(%{suggestions: suggestions} = entity) do
58 entity
59 |> Map.put(:suggestions, format_suggestions(suggestions))
60 |> format_key()
61 |> format_group()
62 |> format_children()
63 end
64
65 defp format_child(entity) do
66 entity
67 |> format_key()
68 |> format_group()
69 |> format_children()
70 end
71
72 defp format_group(%{group: group} = entity) do
73 Map.put(entity, :group, format_suggestion(group))
74 end
75
76 defp format_group(entity), do: entity
77
78 defp atom_to_string(entity) when is_binary(entity), do: entity
79
80 defp atom_to_string(entity) when is_atom(entity), do: inspect(entity)
81
82 defp humanize(entity) do
83 string = inspect(entity)
84
85 if String.starts_with?(string, ":"),
86 do: Phoenix.Naming.humanize(entity),
87 else: string
88 end
89
90 defp format_suggestions([]), do: []
91
92 defp format_suggestions([suggestion | tail]) do
93 [format_suggestion(suggestion) | format_suggestions(tail)]
94 end
95
96 defp format_suggestion(entity) when is_atom(entity) do
97 atom_to_string(entity)
98 end
99
100 defp format_suggestion([head | tail] = entity) when is_list(entity) do
101 [format_suggestion(head) | format_suggestions(tail)]
102 end
103
104 defp format_suggestion(entity) when is_tuple(entity) do
105 format_suggestions(Tuple.to_list(entity)) |> List.to_tuple()
106 end
107
108 defp format_suggestion(entity), do: entity
109 end
110
111 defimpl Jason.Encoder, for: Tuple do
112 def encode(tuple, opts), do: Jason.Encode.list(Tuple.to_list(tuple), opts)
113 end
114
115 defimpl Jason.Encoder, for: [Regex, Function] do
116 def encode(term, opts), do: Jason.Encode.string(inspect(term), opts)
117 end
118
119 defimpl String.Chars, for: Regex do
120 def to_string(term), do: inspect(term)
121 end