Skip to content

Commit f7e8523

Browse files
authored
Ensure default groups for docs are sorted alphabetically (#2132)
1 parent e85d853 commit f7e8523

File tree

4 files changed

+58
-9
lines changed

4 files changed

+58
-9
lines changed

lib/ex_doc/nodes.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ defmodule ExDoc.DocNode do
9191
end
9292

9393
defmodule ExDoc.DocGroupNode do
94+
@moduledoc false
9495
defstruct title: nil, description: nil, doc: nil, docs: []
9596

9697
@type t :: %__MODULE__{

lib/ex_doc/retriever.ex

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,10 @@ defmodule ExDoc.Retriever do
285285
defp get_docs_groups(module_groups, nodes_groups, doc_nodes) do
286286
module_groups = Enum.map(module_groups, &normalize_group/1)
287287

288-
# Doc nodes already have normalized groups
289288
nodes_groups_descriptions = Map.new(nodes_groups, &{&1.title, &1.description})
290289

290+
# Doc nodes already have normalized groups
291+
nodes_groups = ExDoc.Utils.natural_sort_by(nodes_groups, & &1.title)
291292
normal_groups = module_groups ++ nodes_groups
292293
nodes_by_group_title = Enum.group_by(doc_nodes, & &1.group)
293294

lib/mix/tasks/docs.ex

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,15 +296,18 @@ defmodule Mix.Tasks.Docs do
296296
### Grouping functions, types, and callbacks
297297
298298
Types, functions, and callbacks inside a module can also be organized in groups.
299-
By default, ExDoc respects the `:group` metadata field:
299+
300+
#### Group metadata
301+
302+
By default, ExDoc respects the `:group` metadata field to dertermine in which
303+
group an element belongs:
300304
301305
@doc group: "Queries"
302306
def get_by(schema, fields)
303307
304308
The function above will be automatically listed under the "Queries" section in
305309
the sidebar. The benefit of using `:group` is that it can also be used by tools
306-
such as IEx during autocompletion. These groups are then ordered alphabetically
307-
in the sidebar.
310+
such as IEx during autocompletion. These groups are then displayed in the sidebar.
308311
309312
It is also possible to tell ExDoc to either enrich the group metadata or lookup a
310313
different field via the `:default_group_for_doc` configuration. The default is:
@@ -322,9 +325,8 @@ defmodule Mix.Tasks.Docs do
322325
end
323326
end
324327
325-
Whenever using the `:group` key, the groups will be ordered alphabetically.
326-
If you also want control over the group order, you can also use the `:groups_for_docs`
327-
which works similarly as the one for modules/extra pages.
328+
Finally, you can also use the `:groups_for_docs` which works similarly as the
329+
one for modules/extra pages.
328330
329331
`:groups_for_docs` is a keyword list of group titles and filtering functions
330332
that receive the documentation metadata and must return a boolean.
@@ -358,6 +360,51 @@ defmodule Mix.Tasks.Docs do
358360
then falls back to the appropriate "Functions", "Types" or "Callbacks"
359361
section respectively.
360362
363+
#### Group descriptions
364+
365+
It is possible to display a description for each group under its respective section
366+
in a module's page. This helps to better explain what is the intended usage of each
367+
group elements instead of describing everything in the displayed `@moduledoc`.
368+
369+
Descriptions can be provided as `@moduledoc` metadata. Groups without descriptions are
370+
also supported to define group ordering.
371+
372+
@moduledoc groups: [
373+
"Main API",
374+
%{title: "Helpers", description: "Functions shared with other modules."}
375+
]
376+
377+
Descriptions can also be given in the `:default_group_for_doc` configuration:
378+
379+
default_group_for_doc: fn metadata ->
380+
csae metadata[:group] do
381+
:main_api -> "Main API"
382+
:helpers -> [title: "Helpers", description: "Functions shared with other modules."]
383+
_ -> nil
384+
end
385+
end
386+
387+
Keyword lists or maps are supported in either case.
388+
389+
When using `:groups_for_docs`, if all the elements for a given group are matched then the
390+
`:default_group_for_doc` is never invoked and ExDoc will not know about the description.
391+
In that case, the description should be provided in the `@moduledoc` `:groups` metadata.
392+
393+
Whenever using the `:group` key, the groups will be ordered alphabetically.
394+
If you also want control over the group order, you can also use the `:groups_for_docs`
395+
which works similarly as the one for modules/extra pages.
396+
397+
#### Group ordering
398+
399+
Groups in the sidebar and main page body are ordered according to the following
400+
rules:
401+
402+
* First, groups defined as `@moduledoc groups: [...]` in the given order.
403+
* Then groups defined as keys in the `:groups_for_docs` configuration.
404+
* Then default groups: Types, Callbacks and Functions.
405+
* Finally, other groups returned by `:default_group_for_doc` by alphabetical
406+
order.
407+
361408
## Meta-tags configuration
362409
363410
It is also possible to configure some of ExDoc behaviour using meta tags.

test/ex_doc/retriever_test.exs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ defmodule ExDoc.RetrieverTest do
7878

7979
config = %ExDoc.Config{}
8080
{[mod], []} = Retriever.docs_from_modules([A], config)
81-
[%{docs: [bar]}, %{docs: [baz]}, %{docs: [foo]}] = mod.docs_groups
81+
[%{docs: [foo]}, %{docs: [bar]}, %{docs: [baz]}] = mod.docs_groups
8282

8383
assert %{id: "c:foo/0", group: "a"} = foo
8484
assert %{id: "bar/0", group: "b"} = bar
@@ -101,7 +101,7 @@ defmodule ExDoc.RetrieverTest do
101101

102102
config = %ExDoc.Config{group_for_doc: & &1[:semi_group]}
103103
{[mod], []} = Retriever.docs_from_modules([A], config)
104-
[%{docs: [bar]}, %{docs: [baz]}, %{docs: [foo]}] = mod.docs_groups
104+
[%{docs: [foo]}, %{docs: [bar]}, %{docs: [baz]}] = mod.docs_groups
105105

106106
assert %{id: "c:foo/0", group: "a"} = foo
107107
assert %{id: "bar/0", group: "b"} = bar

0 commit comments

Comments
 (0)