diff --git a/README.md b/README.md index ffd4d83dc..460c395f8 100644 --- a/README.md +++ b/README.md @@ -144,7 +144,7 @@ ExDoc supports metadata keys in your documentation. In Elixir, you can add metadata to modules and functions. -For a module, use `@moduledoc`: +For a module, use `@moduledoc`, which is equivalent to adding the annotation to everything inside the module (functions, macros, callbacks, types): ```elixir @moduledoc since: "1.10.0" diff --git a/assets/css/content/general.css b/assets/css/content/general.css index b3f71923f..42425bc5c 100644 --- a/assets/css/content/general.css +++ b/assets/css/content/general.css @@ -93,10 +93,6 @@ font-weight: normal; } -.content-inner h1 .note { - float: right; -} - .content-inner blockquote { border-left: 3px solid var(--blockquoteBorder); position: relative; diff --git a/lib/ex_doc/retriever.ex b/lib/ex_doc/retriever.ex index ba627ed63..9c9ea3788 100644 --- a/lib/ex_doc/retriever.ex +++ b/lib/ex_doc/retriever.ex @@ -197,13 +197,13 @@ defmodule ExDoc.Retriever do groups_for_docs, annotations_for_docs ) do - {:docs_v1, _, _, content_type, _, _, _} = module_data.docs + {:docs_v1, _, _, content_type, _, module_metadata, _} = module_data.docs {{type, name, arity}, anno, signature, doc_content, metadata} = doc_element doc_line = anno_line(anno) annotations = annotations_for_docs.(metadata) ++ - annotations_from_metadata(metadata) ++ function_data.extra_annotations + annotations_from_metadata(metadata, module_metadata) ++ function_data.extra_annotations line = function_data.line || doc_line defaults = get_defaults(name, arity, Map.get(metadata, :defaults, 0)) @@ -270,7 +270,7 @@ defmodule ExDoc.Retriever do defp get_callback(callback, source, groups_for_docs, module_data, annotations_for_docs) do callback_data = module_data.language.callback_data(callback, module_data) - {:docs_v1, _, _, content_type, _, _, _} = module_data.docs + {:docs_v1, _, _, content_type, _, module_metadata, _} = module_data.docs {{kind, name, arity}, anno, _signature, doc, metadata} = callback doc_line = anno_line(anno) @@ -279,7 +279,7 @@ defmodule ExDoc.Retriever do annotations = annotations_for_docs.(metadata) ++ - callback_data.extra_annotations ++ annotations_from_metadata(metadata) + callback_data.extra_annotations ++ annotations_from_metadata(metadata, module_metadata) doc_ast = doc_ast(content_type, doc, file: source.path, line: doc_line + 1) @@ -314,10 +314,10 @@ defmodule ExDoc.Retriever do end defp get_type(type_entry, source, module_data) do - {:docs_v1, _, _, content_type, _, _, _} = module_data.docs + {:docs_v1, _, _, content_type, _, module_metadata, _} = module_data.docs {{_, name, arity}, anno, _signature, doc, metadata} = type_entry doc_line = anno_line(anno) - annotations = annotations_from_metadata(metadata) + annotations = annotations_from_metadata(metadata, module_metadata) type_data = module_data.language.type_data(type_entry, module_data) signature = signature(type_data.signature) @@ -344,17 +344,13 @@ defmodule ExDoc.Retriever do defp signature(list) when is_list(list), do: Enum.join(list, " ") - defp annotations_from_metadata(metadata) do - annotations = [] - - annotations = - if since = metadata[:since] do - ["since #{since}" | annotations] - else - annotations - end - - annotations + defp annotations_from_metadata(metadata, module_metadata) do + # Give precedence to the function/callback/type metadata over the module metadata. + cond do + since = metadata[:since] -> ["since #{since}"] + since = module_metadata[:since] -> ["since #{since}"] + true -> [] + end end defp anno_line(line) when is_integer(line), do: abs(line) diff --git a/test/ex_doc/retriever/elixir_test.exs b/test/ex_doc/retriever/elixir_test.exs index 51984dca6..6c69a5636 100644 --- a/test/ex_doc/retriever/elixir_test.exs +++ b/test/ex_doc/retriever/elixir_test.exs @@ -391,5 +391,34 @@ defmodule ExDoc.Retriever.ElixirTest do assert in_the_middle_2.defaults == [] assert in_the_middle_3.defaults == [] end + + test "if @moduledoc has the :since attribute, it's applied to everything in the module", c do + elixirc(c, ~S""" + defmodule Mod do + @moduledoc since: "1.0.0" + + @type t() :: :ok + + def function(), do: :ok + + defmacro macro(), do: :ok + + @callback cb() :: :ok + end + """) + + assert [%ExDoc.ModuleNode{} = mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + + assert [%ExDoc.TypeNode{id: "t:t/0", annotations: ["since 1.0.0"]}] = mod.typespecs + + assert %ExDoc.FunctionNode{annotations: ["since 1.0.0"]} = + Enum.find(mod.docs, &(&1.id == "c:cb/0")) + + assert %ExDoc.FunctionNode{annotations: ["since 1.0.0"]} = + Enum.find(mod.docs, &(&1.id == "function/0")) + + assert %ExDoc.FunctionNode{annotations: ["since 1.0.0", "macro"]} = + Enum.find(mod.docs, &(&1.id == "macro/0")) + end end end