Skip to content

Commit 566e6f4

Browse files
authored
Add :default_group_for_doc (#1978)
1 parent 550d9b7 commit 566e6f4

File tree

13 files changed

+235
-140
lines changed

13 files changed

+235
-140
lines changed

lib/ex_doc/config.ex

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ defmodule ExDoc.Config do
33

44
# Defaults
55
@default_source_ref "main"
6+
def default_group_for_doc(metadata), do: metadata[:group]
67
def filter_modules(_module, _metadata), do: true
78
def before_closing_head_tag(_), do: ""
89
def before_closing_footer_tag(_), do: ""
@@ -21,6 +22,7 @@ defmodule ExDoc.Config do
2122
before_closing_head_tag: &__MODULE__.before_closing_head_tag/1,
2223
canonical: nil,
2324
cover: nil,
25+
default_group_for_doc: &__MODULE__.default_group_for_doc/1,
2426
deps: [],
2527
extra_section: nil,
2628
extras: [],
@@ -63,15 +65,16 @@ defmodule ExDoc.Config do
6365
before_closing_head_tag: (atom() -> String.t()) | mfa() | map(),
6466
canonical: nil | String.t(),
6567
cover: nil | Path.t(),
68+
default_group_for_doc: (keyword() -> String.t() | nil),
6669
deps: [{ebin_path :: String.t(), doc_url :: String.t()}],
6770
extra_section: nil | String.t(),
6871
extras: list(),
6972
filter_modules: (module, map -> boolean),
7073
formatter: nil | String.t(),
7174
formatters: [String.t()],
72-
groups_for_extras: keyword(),
73-
groups_for_docs: keyword((keyword() -> boolean)),
74-
groups_for_modules: keyword(),
75+
groups_for_extras: [{binary(), term()}],
76+
groups_for_docs: [{binary(), (keyword() -> boolean)}],
77+
groups_for_modules: [{binary(), term()}],
7578
homepage_url: nil | String.t(),
7679
language: String.t(),
7780
logo: nil | Path.t(),
@@ -96,7 +99,6 @@ defmodule ExDoc.Config do
9699
@spec build(String.t(), String.t(), Keyword.t()) :: ExDoc.Config.t()
97100
def build(project, vsn, options) do
98101
{output, options} = Keyword.pop(options, :output, "./doc")
99-
{groups_for_modules, options} = Keyword.pop(options, :groups_for_modules, [])
100102
{nest_modules_by_prefix, options} = Keyword.pop(options, :nest_modules_by_prefix, [])
101103
{proglang, options} = Keyword.pop(options, :proglang, :elixir)
102104
{filter_modules, options} = Keyword.pop(options, :filter_modules, &filter_modules/2)
@@ -109,6 +111,10 @@ defmodule ExDoc.Config do
109111
options
110112
end
111113

114+
{groups_for_docs, options} = Keyword.pop(options, :groups_for_docs, [])
115+
{groups_for_extras, options} = Keyword.pop(options, :groups_for_extras, [])
116+
{groups_for_modules, options} = Keyword.pop(options, :groups_for_modules, [])
117+
112118
{skip_undefined_reference_warnings_on, options} =
113119
Keyword.pop(
114120
options,
@@ -126,7 +132,13 @@ defmodule ExDoc.Config do
126132

127133
preconfig = %__MODULE__{
128134
filter_modules: normalize_filter_modules(filter_modules),
129-
groups_for_modules: normalize_groups_for_modules(groups_for_modules),
135+
groups_for_docs: normalize_groups(groups_for_docs),
136+
groups_for_extras: normalize_groups(groups_for_extras),
137+
groups_for_modules:
138+
normalize_groups(
139+
# TODO: The default module groups must be returned by the language
140+
groups_for_modules ++ [Deprecated: &deprecated?/1, Exceptions: &exception?/1]
141+
),
130142
homepage_url: options[:homepage_url],
131143
main: options[:main],
132144
nest_modules_by_prefix: normalize_nest_modules_by_prefix(nest_modules_by_prefix),
@@ -159,12 +171,8 @@ defmodule ExDoc.Config do
159171
raise ArgumentError, "#{inspect(proglang)} is not supported"
160172
end
161173

162-
# TODO: The default module groups must be returned by the language
163-
defp normalize_groups_for_modules(groups_for_modules) do
164-
default_groups = [Deprecated: &deprecated?/1, Exceptions: &exception?/1]
165-
166-
groups_for_modules ++
167-
Enum.reject(default_groups, fn {k, _} -> Keyword.has_key?(groups_for_modules, k) end)
174+
defp normalize_groups(groups) do
175+
for {k, v} <- groups, do: {to_string(k), v}
168176
end
169177

170178
defp deprecated?(metadata), do: metadata[:deprecated] != nil

lib/ex_doc/formatter/html.ex

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ defmodule ExDoc.Formatter.HTML do
381381
if ids_count[extra.id] > 1, do: {disambiguate_id(extra, idx), idx + 1}, else: {extra, idx}
382382
end)
383383
|> elem(0)
384-
|> Enum.sort_by(fn extra -> GroupMatcher.group_index(groups, extra.group) end)
384+
|> Enum.sort_by(fn extra -> GroupMatcher.index(groups, extra.group) end)
385385
end
386386

387387
def generate_redirects(config, ext) do

lib/ex_doc/formatter/html/templates.ex

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -203,13 +203,12 @@ defmodule ExDoc.Formatter.HTML.Templates do
203203
end
204204

205205
def module_summary(module_node) do
206-
entries = docs_groups(module_node.docs_groups, module_node.docs ++ module_node.typespecs)
207-
208-
Enum.reject(entries, fn {_type, nodes} -> nodes == [] end)
209-
end
210-
211-
defp docs_groups(groups, docs) do
212-
for group <- groups, do: {group, Enum.filter(docs, &(&1.group == group))}
206+
# TODO: Maybe it should be moved to retriever and it already returned grouped metadata
207+
ExDoc.GroupMatcher.group_by(
208+
module_node.docs_groups,
209+
module_node.docs ++ module_node.typespecs,
210+
& &1.group
211+
)
213212
end
214213

215214
defp logo_path(%{logo: nil}), do: nil

lib/ex_doc/group_matcher.ex

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,38 @@ defmodule ExDoc.GroupMatcher do
88
@doc """
99
Finds the index of a given group.
1010
"""
11-
def group_index(groups, group) do
11+
def index(groups, group) do
1212
Enum.find_index(groups, fn {k, _v} -> k == group end) || -1
1313
end
1414

15+
@doc """
16+
Group the following entries and while preserving the order in `groups`.
17+
"""
18+
def group_by(groups, entries, by) do
19+
entries = Enum.group_by(entries, by)
20+
21+
{groups, leftovers} =
22+
Enum.flat_map_reduce(groups, entries, fn group, grouped_nodes ->
23+
case Map.pop(grouped_nodes, group, []) do
24+
{[], grouped_nodes} -> {[], grouped_nodes}
25+
{entries, grouped_nodes} -> {[{group, entries}], grouped_nodes}
26+
end
27+
end)
28+
29+
groups ++ Enum.sort(leftovers)
30+
end
31+
1532
@doc """
1633
Finds a matching group for the given function.
1734
"""
18-
@spec match_function(group_patterns, map) :: atom() | nil
19-
def match_function(group_patterns, metadata) do
20-
match_group_patterns(group_patterns, fn pattern -> pattern.(metadata) end)
35+
def match_doc(group_patterns, callback, default, metadata) do
36+
match_group_patterns(group_patterns, fn pattern -> pattern.(metadata) end) ||
37+
callback.(metadata) || default
2138
end
2239

2340
@doc """
2441
Finds a matching group for the given module name, id, and metadata.
2542
"""
26-
@spec match_module(group_patterns, module, binary, map) :: atom() | nil
2743
def match_module(group_patterns, module, id, metadata) do
2844
match_group_patterns(group_patterns, fn pattern ->
2945
case pattern do
@@ -38,7 +54,6 @@ defmodule ExDoc.GroupMatcher do
3854
@doc """
3955
Finds a matching group for the given extra filename
4056
"""
41-
@spec match_extra(group_patterns, binary) :: atom() | nil
4257
def match_extra(group_patterns, filename) do
4358
match_group_patterns(group_patterns, fn pattern ->
4459
case pattern do

lib/ex_doc/language.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,10 @@ defmodule ExDoc.Language do
4949
@doc """
5050
Returns a map with module information.
5151
"""
52-
@callback module_data(module(), tuple(), ExDoc.Config.t()) :: module_data() | :skip
52+
@callback module_data(module(), tuple(), ExDoc.Config.t()) :: module_data() | false
5353

5454
@doc """
55-
Returns a map with function information or an atom `:skip`.
55+
Returns a map with function information or `false`.
5656
5757
The map has the following keys:
5858
@@ -78,7 +78,7 @@ defmodule ExDoc.Language do
7878
doc_fallback: (... -> ExDoc.DocAST.t()) | nil,
7979
extra_annotations: [String.t()]
8080
}
81-
| :skip
81+
| false
8282

8383
@doc """
8484
Returns a map with callback information.

lib/ex_doc/language/elixir.ex

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule ExDoc.Language.Elixir do
88

99
@impl true
1010
@spec module_data(atom, any, any) ::
11-
:skip
11+
false
1212
| %{
1313
callback_types: [:callback, ...],
1414
docs: any,
@@ -34,7 +34,7 @@ defmodule ExDoc.Language.Elixir do
3434

3535
cond do
3636
skip ->
37-
:skip
37+
false
3838

3939
abst_code = Source.get_abstract_code(module) ->
4040
title = module_title(module, type)
@@ -73,7 +73,7 @@ defmodule ExDoc.Language.Elixir do
7373
[]
7474
)
7575

76-
:skip
76+
false
7777
end
7878
end
7979

@@ -84,7 +84,7 @@ defmodule ExDoc.Language.Elixir do
8484
if doc?(entry, module_data.type) do
8585
function_data(kind, name, arity, anno, metadata, module_data)
8686
else
87-
:skip
87+
false
8888
end
8989
end
9090

lib/ex_doc/language/erlang.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ defmodule ExDoc.Language.Erlang do
88

99
@impl true
1010
@spec module_data(atom, any, any) ::
11-
:skip
11+
false
1212
| %{
1313
callback_types: [:callback, ...],
1414
docs: any,
@@ -54,7 +54,7 @@ defmodule ExDoc.Language.Erlang do
5454
}
5555
else
5656
ExDoc.Utils.warn("skipping docs for module #{inspect(module)}, reason: :no_debug_info", [])
57-
:skip
57+
false
5858
end
5959
end
6060

@@ -68,7 +68,7 @@ defmodule ExDoc.Language.Erlang do
6868
function_exported?(module_data.module, name, arity) do
6969
function_data(name, arity, doc_content, module_data, metadata)
7070
else
71-
:skip
71+
false
7272
end
7373
end
7474

0 commit comments

Comments
 (0)