From 27c5072511f11afb6b43a21c32a249d352c20ce6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 06:46:44 -0300 Subject: [PATCH 1/6] Return filtered modules --- lib/ex_doc.ex | 4 +- lib/ex_doc/nodes.ex | 6 ++- lib/ex_doc/retriever.ex | 39 ++++++++++++++----- test/ex_doc/formatter/epub/templates_test.exs | 2 +- .../formatter/html/search_data_test.exs | 2 +- test/ex_doc/formatter/html/templates_test.exs | 14 +++---- test/ex_doc/retriever/elixir_test.exs | 28 ++++++------- test/ex_doc/retriever/erlang_test.exs | 12 +++--- test/ex_doc/retriever_test.exs | 27 ++++++------- 9 files changed, 79 insertions(+), 55 deletions(-) diff --git a/lib/ex_doc.ex b/lib/ex_doc.ex index 8ff7f2f9e..298fb83fb 100644 --- a/lib/ex_doc.ex +++ b/lib/ex_doc.ex @@ -21,8 +21,8 @@ defmodule ExDoc do ExDoc.Markdown.put_markdown_processor(processor) end - docs = config.retriever.docs_from_dir(config.source_beam, config) - find_formatter(config.formatter).run(docs, config) + {module_nodes, _filtered_nodes} = config.retriever.docs_from_dir(config.source_beam, config) + find_formatter(config.formatter).run(module_nodes, config) end # Short path for programmatic interface diff --git a/lib/ex_doc/nodes.ex b/lib/ex_doc/nodes.ex index 263ac60ff..195775641 100644 --- a/lib/ex_doc/nodes.ex +++ b/lib/ex_doc/nodes.ex @@ -22,7 +22,8 @@ defmodule ExDoc.ModuleNode do source_url: nil, type: nil, language: nil, - annotations: [] + annotations: [], + metadata: nil @typep annotation :: atom() @@ -46,7 +47,8 @@ defmodule ExDoc.ModuleNode do source_url: String.t() | nil, type: atom(), language: module(), - annotations: [annotation()] + annotations: [annotation()], + metadata: map() } end diff --git a/lib/ex_doc/retriever.ex b/lib/ex_doc/retriever.ex index 59abbb1c0..5be588d0e 100644 --- a/lib/ex_doc/retriever.ex +++ b/lib/ex_doc/retriever.ex @@ -12,8 +12,12 @@ defmodule ExDoc.Retriever do @doc """ Extract documentation from all modules in the specified directory or directories. + + Returns a tuple containing `{modules, filtered}`, using `config.filter_modules` + as a filter criteria. """ - @spec docs_from_dir(Path.t() | [Path.t()], ExDoc.Config.t()) :: [ExDoc.ModuleNode.t()] + @spec docs_from_dir(Path.t() | [Path.t()], ExDoc.Config.t()) :: + {[ExDoc.ModuleNode.t()], [ExDoc.ModuleNode.t()]} def docs_from_dir(dir, config) when is_binary(dir) do files = Path.wildcard(Path.expand("*.beam", dir)) @@ -28,15 +32,32 @@ defmodule ExDoc.Retriever do end @doc """ - Extract documentation from all modules in the list `modules` + Extract documentation from all modules and returns a tuple containing + `{modules, filtered}`, two lists of modules that were extracted and filtered + by `config.filter_modules`, respectively. """ - @spec docs_from_modules([atom], ExDoc.Config.t()) :: [ExDoc.ModuleNode.t()] + @spec docs_from_modules([atom], ExDoc.Config.t()) :: + {[ExDoc.ModuleNode.t()], [ExDoc.ModuleNode.t()]} def docs_from_modules(modules, config) when is_list(modules) do modules - |> Enum.flat_map(&get_module(&1, config)) + |> Enum.reduce({[], []}, fn module_name, {modules, filtered} = acc -> + case get_module(module_name, config) do + {:error, _module} -> + acc + + {:ok, module_node} -> + if config.filter_modules.(module_node.module, module_node.metadata), + do: {[module_node | modules], filtered}, + else: {modules, [module_node | filtered]} + end + end) |> sort_modules(config) end + defp sort_modules({modules, filtered}, config) do + {sort_modules(modules, config), sort_modules(filtered, config)} + end + defp sort_modules(modules, config) when is_list(modules) do Enum.sort_by(modules, fn module -> {GroupMatcher.group_index(config.groups_for_modules, module.group), module.nested_context, @@ -50,14 +71,13 @@ defmodule ExDoc.Retriever do end defp get_module(module, config) do - with {:docs_v1, _, language, _, _, metadata, _} = docs_chunk <- docs_chunk(module), - true <- config.filter_modules.(module, metadata), + with {:docs_v1, _, language, _, _, _metadata, _} = docs_chunk <- docs_chunk(module), {:ok, language} <- ExDoc.Language.get(language, module), %{} = module_data <- language.module_data(module, docs_chunk, config) do - [generate_node(module, module_data, config)] + {:ok, generate_node(module, module_data, config)} else _ -> - [] + {:error, module} end end @@ -142,7 +162,8 @@ defmodule ExDoc.Retriever do source_path: source_path, source_url: source_link(source, module_data.line), language: module_data.language, - annotations: List.wrap(metadata[:tags]) + annotations: List.wrap(metadata[:tags]), + metadata: metadata } end diff --git a/test/ex_doc/formatter/epub/templates_test.exs b/test/ex_doc/formatter/epub/templates_test.exs index 7eed7648c..79bd79d7b 100644 --- a/test/ex_doc/formatter/epub/templates_test.exs +++ b/test/ex_doc/formatter/epub/templates_test.exs @@ -27,7 +27,7 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do defp get_module_page(names, config \\ []) do config = doc_config(config) - mods = ExDoc.Retriever.docs_from_modules(names, config) + {mods, []} = ExDoc.Retriever.docs_from_modules(names, config) [mod | _] = HTML.render_all(mods, ".xhtml", config, highlight_tag: "samp") Templates.module_page(config, mod) end diff --git a/test/ex_doc/formatter/html/search_data_test.exs b/test/ex_doc/formatter/html/search_data_test.exs index 9cfda6fb3..0aaa19319 100644 --- a/test/ex_doc/formatter/html/search_data_test.exs +++ b/test/ex_doc/formatter/html/search_data_test.exs @@ -243,7 +243,7 @@ defmodule ExDoc.Formatter.HTML.SearchDataTest do end defp search_data(modules, config) do - modules = ExDoc.Retriever.docs_from_modules(modules, config) + {modules, []} = ExDoc.Retriever.docs_from_modules(modules, config) ExDoc.Formatter.HTML.run(modules, config) [path] = Path.wildcard(Path.join([config.output, "dist", "search_data-*.js"])) diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index f0912bc07..e19512ab1 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -31,7 +31,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do defp get_module_page(names, context, config \\ []) do config = doc_config(context, config) - mods = ExDoc.Retriever.docs_from_modules(names, config) + {mods, []} = ExDoc.Retriever.docs_from_modules(names, config) [mod | _] = HTML.render_all(mods, ".html", config, []) Templates.module_page(mod, @empty_nodes_map, config) end @@ -264,7 +264,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do test "outputs listing for the given nodes", context do names = [CompiledWithDocs, CompiledWithDocs.Nested] - nodes = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) assert [ %{ @@ -293,7 +293,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do test "outputs deprecated: true if node is deprecated", context do names = [CompiledWithDocs] - nodes = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) path = ["modules", Access.at!(0), "nodeGroups", Access.at!(0), "nodes"] sidebar_functions = get_in(create_sidebar_items(%{modules: nodes}, []), path) @@ -306,7 +306,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do test "outputs deprecated: true if module is deprecated", context do names = [Warnings] - nodes = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context)) assert Enum.any?( create_sidebar_items(%{modules: nodes}, [])["modules"], @@ -315,7 +315,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do end test "outputs nodes grouped based on metadata", context do - nodes = + {nodes, []} = ExDoc.Retriever.docs_from_modules( [CompiledWithDocs, CompiledWithDocs.Nested], doc_config(context, @@ -361,7 +361,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do test "outputs module groups for the given nodes", context do names = [CompiledWithDocs, CompiledWithDocs.Nested] group_mapping = [groups_for_modules: [Group: [CompiledWithDocs]]] - nodes = ExDoc.Retriever.docs_from_modules(names, doc_config(context, group_mapping)) + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, doc_config(context, group_mapping)) assert [ %{"group" => ""}, @@ -420,7 +420,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do test "builds sections out of moduledocs", context do names = [CompiledWithDocs, CompiledWithoutDocs, DuplicateHeadings] config = doc_config(context) - nodes = ExDoc.Retriever.docs_from_modules(names, config) + {nodes, []} = ExDoc.Retriever.docs_from_modules(names, config) nodes = HTML.render_all(nodes, ".html", config, []) [compiled_with_docs, compiled_without_docs, duplicate_headings] = diff --git a/test/ex_doc/retriever/elixir_test.exs b/test/ex_doc/retriever/elixir_test.exs index 6c69a5636..31d8d9f42 100644 --- a/test/ex_doc/retriever/elixir_test.exs +++ b/test/ex_doc/retriever/elixir_test.exs @@ -27,7 +27,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) assert %ExDoc.ModuleNode{ doc_line: 2, @@ -88,7 +88,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) [foo] = mod.docs assert foo.id == "foo/2" @@ -104,7 +104,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) [macro] = mod.docs assert macro.id == "macro/1" @@ -127,7 +127,7 @@ defmodule ExDoc.Retriever.ElixirTest do """) config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"} - [mod] = Retriever.docs_from_modules([Mod], config) + {[mod], []} = Retriever.docs_from_modules([Mod], config) assert mod.type == :behaviour [callback1, macrocallback1, optional_callback1] = mod.docs @@ -176,7 +176,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [impl] = Retriever.docs_from_modules([Impl], %ExDoc.Config{}) + {[impl], []} = Retriever.docs_from_modules([Impl], %ExDoc.Config{}) [callback1, optional_callback1] = impl.docs assert callback1.id == "callback1/0" @@ -202,7 +202,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) [opaque1, type1] = mod.typespecs assert type1.id == "t:type1/0" @@ -233,7 +233,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod, Mod.Atom], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod, Mod.Atom], %ExDoc.Config{}) assert mod.type == :protocol [foo] = mod.docs @@ -248,7 +248,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([MyStruct], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([MyStruct], %ExDoc.Config{}) [my_struct] = mod.docs assert my_struct.id == "__struct__/0" @@ -263,7 +263,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([MyException], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([MyException], %ExDoc.Config{}) assert mod.title == "MyException" assert mod.type == :exception @@ -287,7 +287,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) [downcase, upcase] = mod.docs assert downcase.id == "downcase/1" @@ -308,7 +308,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Signatures], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Signatures], %ExDoc.Config{}) [remote] = mod.docs assert remote.signature == "remote(options)" @@ -327,7 +327,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mix.Tasks.MyTask], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mix.Tasks.MyTask], %ExDoc.Config{}) assert mod.title == "mix my_task" assert mod.type == :task refute mod.group @@ -369,7 +369,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - [mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) overlapping_defaults_2 = Enum.find(mod.docs, &(&1.id == "overlapping_defaults/2")) overlapping_defaults_3 = Enum.find(mod.docs, &(&1.id == "overlapping_defaults/3")) @@ -407,7 +407,7 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - assert [%ExDoc.ModuleNode{} = mod] = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + 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 diff --git a/test/ex_doc/retriever/erlang_test.exs b/test/ex_doc/retriever/erlang_test.exs index 64f7ff9d2..4b2dda494 100644 --- a/test/ex_doc/retriever/erlang_test.exs +++ b/test/ex_doc/retriever/erlang_test.exs @@ -24,7 +24,7 @@ defmodule ExDoc.Retriever.ErlangTest do function2() -> ok. """) - [mod] = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) %ExDoc.ModuleNode{ deprecated: nil, @@ -80,7 +80,7 @@ defmodule ExDoc.Retriever.ErlangTest do -module(mod). """) - assert [_] = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) + assert {[_], []} = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) end test "function with no docs is generated", c do @@ -92,7 +92,7 @@ defmodule ExDoc.Retriever.ErlangTest do f() -> ok. """) - [mod] = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([:mod], %ExDoc.Config{}) assert [_] = mod.docs end @@ -111,7 +111,7 @@ defmodule ExDoc.Retriever.ErlangTest do """) config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"} - [mod] = Retriever.docs_from_modules([:mod], config) + {[mod], []} = Retriever.docs_from_modules([:mod], config) [callback1, optional_callback1] = mod.docs assert callback1.id == "c:callback1/0" @@ -140,7 +140,7 @@ defmodule ExDoc.Retriever.ErlangTest do """) config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"} - [mod] = Retriever.docs_from_modules([:mod], config) + {[mod], []} = Retriever.docs_from_modules([:mod], config) [opaque1, type1] = mod.typespecs assert opaque1.id == "t:opaque1/0" @@ -166,7 +166,7 @@ defmodule ExDoc.Retriever.ErlangTest do docs: false ) - assert Retriever.docs_from_modules([:no_chunk], %ExDoc.Config{}) == [] + assert {[], []} = Retriever.docs_from_modules([:no_chunk], %ExDoc.Config{}) end # TODO diff --git a/test/ex_doc/retriever_test.exs b/test/ex_doc/retriever_test.exs index 802022bba..c2b842bd0 100644 --- a/test/ex_doc/retriever_test.exs +++ b/test/ex_doc/retriever_test.exs @@ -12,7 +12,7 @@ defmodule ExDoc.RetrieverTest do end """) - [mod] = Retriever.docs_from_modules([A], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([A], %ExDoc.Config{}) assert mod.doc == nil end @@ -26,7 +26,7 @@ defmodule ExDoc.RetrieverTest do end """) - [mod] = Retriever.docs_from_modules([A], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([A], %ExDoc.Config{}) [foo] = mod.docs assert foo.id == "foo/0" assert foo.annotations == ["since 1.0.0"] @@ -55,7 +55,7 @@ defmodule ExDoc.RetrieverTest do ] } - [qux, bar, foo, baz] = Retriever.docs_from_modules([Foo, Bar, Baz, Qux], config) + {[qux, bar, foo, baz], []} = Retriever.docs_from_modules([Foo, Bar, Baz, Qux], config) assert %{module: Foo, group: :"Group 1"} = foo assert %{module: Bar, group: :"Group 1"} = bar assert %{module: Baz, group: :"Group 2"} = baz @@ -83,7 +83,7 @@ defmodule ExDoc.RetrieverTest do ] } - [mod] = Retriever.docs_from_modules([A], config) + {[mod], []} = Retriever.docs_from_modules([A], config) [bar, baz, foo] = mod.docs assert %{id: "foo/0", group: :"Group 1"} = foo @@ -101,7 +101,7 @@ defmodule ExDoc.RetrieverTest do end """) - [mod] = + {[mod], []} = Retriever.docs_from_modules([A], %ExDoc.Config{ annotations_for_docs: fn metadata -> if metadata[:foo] do @@ -126,7 +126,7 @@ defmodule ExDoc.RetrieverTest do end """) - [mod] = + {[mod], []} = Retriever.docs_from_modules([A], %ExDoc.Config{ annotations_for_docs: fn metadata -> if metadata[:foo] do @@ -157,7 +157,7 @@ defmodule ExDoc.RetrieverTest do end """) - mods = + {mods, []} = Retriever.docs_from_modules( [Nesting.Prefix.B.A, Nesting.Prefix.B.C], %ExDoc.Config{nest_modules_by_prefix: ["Nesting.Prefix.B"]} @@ -171,7 +171,7 @@ defmodule ExDoc.RetrieverTest do assert Enum.at(mods, 1).nested_context == "Nesting.Prefix.B" assert Enum.at(mods, 1).nested_title == ".C" - [mod] = + {[mod], []} = Retriever.docs_from_modules([Nesting.Prefix.B.B.A], %ExDoc.Config{ nest_modules_by_prefix: ["Nesting.Prefix.B.B.A"] }) @@ -201,10 +201,11 @@ defmodule ExDoc.RetrieverTest do ebin_dir = Path.join(c.tmp_dir, "ebin") config = %ExDoc.Config{filter_modules: fn module, _ -> Atom.to_string(module) =~ "A" end} - [a, a_a] = Retriever.docs_from_dir(ebin_dir, config) - assert a.id == "A" - assert a_a.id == "A.A" + assert { + [%{id: "A"}, %{id: "A.A"}], + [%{id: "B"}] + } = Retriever.docs_from_dir(ebin_dir, config) end test "natural sorting", c do @@ -229,7 +230,7 @@ defmodule ExDoc.RetrieverTest do end """) - [mod] = Retriever.docs_from_modules([NaturallySorted], %ExDoc.Config{}) + {[mod], []} = Retriever.docs_from_modules([NaturallySorted], %ExDoc.Config{}) [function_A_0, function_A_1, function_a_0, function_a_1, function_B_0, function_b_0] = mod.docs @@ -255,7 +256,7 @@ defmodule ExDoc.RetrieverTest do end """) - [module_node] = Retriever.docs_from_modules([NoWhitespaceInSignature], %ExDoc.Config{}) + {[module_node], []} = Retriever.docs_from_modules([NoWhitespaceInSignature], %ExDoc.Config{}) %{docs: [%{signature: signature}]} = module_node assert signature == "callback_name(arg1, integer, %Date{}, term, t)" end From c8310b507e5bee22291c47f382fba5bb446f32c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 06:57:26 -0300 Subject: [PATCH 2/6] fix? --- test/ex_doc_test.exs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/ex_doc_test.exs b/test/ex_doc_test.exs index 85d2da50b..4cefe2f52 100644 --- a/test/ex_doc_test.exs +++ b/test/ex_doc_test.exs @@ -63,7 +63,7 @@ defmodule ExDocTest do source_beam: "beam_dir" ] - {{source_dir, _retr_config}, _config} = ExDoc.generate_docs("Elixir", "1", options) + {source_dir, _config} = ExDoc.generate_docs("Elixir", "1", options) assert source_dir == options[:source_beam] end From c7d5ac6e77e644b3f52dd7e618fe723c5c166468 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 07:17:23 -0300 Subject: [PATCH 3/6] Fixes and add warning --- lib/ex_doc.ex | 4 ++-- lib/ex_doc/autolink.ex | 5 ++++- lib/ex_doc/formatter/epub.ex | 8 +++++-- lib/ex_doc/formatter/html.ex | 21 ++++++++++++++----- lib/ex_doc/language/elixir.ex | 6 +++++- test/ex_doc/formatter/epub/templates_test.exs | 2 +- test/ex_doc/formatter/html/templates_test.exs | 4 ++-- test/ex_doc_test.exs | 2 +- 8 files changed, 37 insertions(+), 15 deletions(-) diff --git a/lib/ex_doc.ex b/lib/ex_doc.ex index 298fb83fb..0f62a351c 100644 --- a/lib/ex_doc.ex +++ b/lib/ex_doc.ex @@ -21,8 +21,8 @@ defmodule ExDoc do ExDoc.Markdown.put_markdown_processor(processor) end - {module_nodes, _filtered_nodes} = config.retriever.docs_from_dir(config.source_beam, config) - find_formatter(config.formatter).run(module_nodes, config) + {module_nodes, filtered_nodes} = config.retriever.docs_from_dir(config.source_beam, config) + find_formatter(config.formatter).run({module_nodes, filtered_nodes}, config) end # Short path for programmatic interface diff --git a/lib/ex_doc/autolink.ex b/lib/ex_doc/autolink.ex index b9005eda5..f75d6e967 100644 --- a/lib/ex_doc/autolink.ex +++ b/lib/ex_doc/autolink.ex @@ -22,6 +22,8 @@ defmodule ExDoc.Autolink do # * `:skip_undefined_reference_warnings_on` - list of modules to skip the warning on # # * `:skip_code_autolink_to` - list of terms that will be skipped when autolinking (e.g: "PrivateModule") + # + # * `:filtered_modules` - A list of module nodes that were filtered by the retriever defstruct [ :current_module, @@ -35,7 +37,8 @@ defmodule ExDoc.Autolink do ext: ".html", siblings: [], skip_undefined_reference_warnings_on: [], - skip_code_autolink_to: [] + skip_code_autolink_to: [], + filtered_modules: [] ] @hexdocs "https://hexdocs.pm/" diff --git a/lib/ex_doc/formatter/epub.ex b/lib/ex_doc/formatter/epub.ex index d8f05e4a9..f81e9ac07 100644 --- a/lib/ex_doc/formatter/epub.ex +++ b/lib/ex_doc/formatter/epub.ex @@ -9,7 +9,11 @@ defmodule ExDoc.Formatter.EPUB do Generate EPUB documentation for the given modules. """ @spec run(list, ExDoc.Config.t()) :: String.t() - def run(project_nodes, config) when is_map(config) do + def run(project_nodes, config) when is_list(project_nodes) and is_map(config) do + run({project_nodes, []}, config) + end + + def run({project_nodes, filtered_modules}, config) when is_map(config) do parent = config.output config = normalize_config(config) @@ -19,7 +23,7 @@ defmodule ExDoc.Formatter.EPUB do &create_output_dir(&1, config) ) - project_nodes = HTML.render_all(project_nodes, ".xhtml", config, highlight_tag: "samp") + project_nodes = HTML.render_all(project_nodes, filtered_modules, ".xhtml", config, highlight_tag: "samp") nodes_map = %{ modules: HTML.filter_list(:module, project_nodes), diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index aab359daf..5ebeb3d32 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -10,15 +10,25 @@ defmodule ExDoc.Formatter.HTML do @doc """ Generate HTML documentation for the given modules. """ - @spec run(list, ExDoc.Config.t()) :: String.t() - def run(project_nodes, config) when is_map(config) do + # TODO: improve this spec + @spec run( + [ExDoc.ModuleNode.t()] + | {[ExDoc.ModuleNode.t()], [ExDoc.ModuleNode.t()]}, + ExDoc.Config.t() + ) :: String.t() + + def run(project_nodes, config) when is_list(project_nodes) and is_map(config) do + run({project_nodes, []}, config) + end + + def run({project_nodes, filtered_modules}, config) when is_map(config) do config = normalize_config(config) config = %{config | output: Path.expand(config.output)} build = Path.join(config.output, ".build") setup_output(config.output, &cleanup_output_dir(&1, config), &create_output_dir(&1, config)) - project_nodes = render_all(project_nodes, ".html", config, []) + project_nodes = render_all(project_nodes, filtered_modules, ".html", config, []) extras = build_extras(config, ".html") # Generate search early on without api reference in extras @@ -64,14 +74,15 @@ defmodule ExDoc.Formatter.HTML do @doc """ Autolinks and renders all docs. """ - def render_all(project_nodes, ext, config, opts) do + def render_all(project_nodes, filtered_modules, ext, config, opts) do base = [ apps: config.apps, deps: config.deps, ext: ext, extras: extra_paths(config), skip_undefined_reference_warnings_on: config.skip_undefined_reference_warnings_on, - skip_code_autolink_to: config.skip_code_autolink_to + skip_code_autolink_to: config.skip_code_autolink_to, + filtered_modules: filtered_modules ] project_nodes diff --git a/lib/ex_doc/language/elixir.ex b/lib/ex_doc/language/elixir.ex index a6636bc03..67459a732 100644 --- a/lib/ex_doc/language/elixir.ex +++ b/lib/ex_doc/language/elixir.ex @@ -783,12 +783,16 @@ defmodule ExDoc.Language.Elixir do (\(.*\)) # Arguments }x - Regex.replace(regex, string, fn _all, call_string, module_string, name_string, rest -> + Regex.replace(regex, string, fn all, call_string, module_string, name_string, rest -> module = string_to_module(module_string) name = String.to_atom(name_string) arity = count_args(rest, 0, 0) original_text = call_string <> "()" + if Enum.any?(config.filtered_modules, &(&1.id == module_string)) do + warn("Typespec references filtered module: #{all}", {config.file, config.line}, config.id) + end + url = if module do remote_url({:type, module, name, arity}, config, original_text) diff --git a/test/ex_doc/formatter/epub/templates_test.exs b/test/ex_doc/formatter/epub/templates_test.exs index 79bd79d7b..0c9f7c300 100644 --- a/test/ex_doc/formatter/epub/templates_test.exs +++ b/test/ex_doc/formatter/epub/templates_test.exs @@ -28,7 +28,7 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do defp get_module_page(names, config \\ []) do config = doc_config(config) {mods, []} = ExDoc.Retriever.docs_from_modules(names, config) - [mod | _] = HTML.render_all(mods, ".xhtml", config, highlight_tag: "samp") + [mod | _] = HTML.render_all(mods, [], ".xhtml", config, highlight_tag: "samp") Templates.module_page(config, mod) end diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs index e19512ab1..7d0188660 100644 --- a/test/ex_doc/formatter/html/templates_test.exs +++ b/test/ex_doc/formatter/html/templates_test.exs @@ -32,7 +32,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do defp get_module_page(names, context, config \\ []) do config = doc_config(context, config) {mods, []} = ExDoc.Retriever.docs_from_modules(names, config) - [mod | _] = HTML.render_all(mods, ".html", config, []) + [mod | _] = HTML.render_all(mods, [], ".html", config, []) Templates.module_page(mod, @empty_nodes_map, config) end @@ -421,7 +421,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do names = [CompiledWithDocs, CompiledWithoutDocs, DuplicateHeadings] config = doc_config(context) {nodes, []} = ExDoc.Retriever.docs_from_modules(names, config) - nodes = HTML.render_all(nodes, ".html", config, []) + nodes = HTML.render_all(nodes, [], ".html", config, []) [compiled_with_docs, compiled_without_docs, duplicate_headings] = create_sidebar_items(%{modules: nodes}, [])["modules"] diff --git a/test/ex_doc_test.exs b/test/ex_doc_test.exs index 4cefe2f52..be412ff31 100644 --- a/test/ex_doc_test.exs +++ b/test/ex_doc_test.exs @@ -63,7 +63,7 @@ defmodule ExDocTest do source_beam: "beam_dir" ] - {source_dir, _config} = ExDoc.generate_docs("Elixir", "1", options) + assert {{source_dir, _retr_config}, _config} = ExDoc.generate_docs("Elixir", "1", options) assert source_dir == options[:source_beam] end From 8205a563903b1f89697367c22f40558cabc7d1aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 07:23:14 -0300 Subject: [PATCH 4/6] Start testing --- test/ex_doc/language/elixir_test.exs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/test/ex_doc/language/elixir_test.exs b/test/ex_doc/language/elixir_test.exs index 91d3d9153..01a635b64 100644 --- a/test/ex_doc/language/elixir_test.exs +++ b/test/ex_doc/language/elixir_test.exs @@ -439,6 +439,16 @@ defmodule ExDoc.Language.ElixirTest do warn(~m"`c:InMemory.unknown/0`") end + test "warning if typespec references filtered module" do + ExDoc.Refs.insert([ + {{:module, AutolinkTest.Keep}, :public}, + {{:function, AutolinkTest.Filtered}, :public}, + {{:type, AutolinkTest.Filtered, :type, 0}, :public} + ]) + + # TODO: testing + end + test "warnings" do ExDoc.Refs.insert([ {{:module, AutolinkTest.Foo}, :public}, From 4072730e43bd67f8cf710f4878657945259c447c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 07:28:55 -0300 Subject: [PATCH 5/6] mix format --- lib/ex_doc/formatter/epub.ex | 3 ++- test/ex_doc/retriever/elixir_test.exs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/ex_doc/formatter/epub.ex b/lib/ex_doc/formatter/epub.ex index f81e9ac07..2d9756e9a 100644 --- a/lib/ex_doc/formatter/epub.ex +++ b/lib/ex_doc/formatter/epub.ex @@ -23,7 +23,8 @@ defmodule ExDoc.Formatter.EPUB do &create_output_dir(&1, config) ) - project_nodes = HTML.render_all(project_nodes, filtered_modules, ".xhtml", config, highlight_tag: "samp") + project_nodes = + HTML.render_all(project_nodes, filtered_modules, ".xhtml", config, highlight_tag: "samp") nodes_map = %{ modules: HTML.filter_list(:module, project_nodes), diff --git a/test/ex_doc/retriever/elixir_test.exs b/test/ex_doc/retriever/elixir_test.exs index 31d8d9f42..21b5088f7 100644 --- a/test/ex_doc/retriever/elixir_test.exs +++ b/test/ex_doc/retriever/elixir_test.exs @@ -407,7 +407,8 @@ defmodule ExDoc.Retriever.ElixirTest do end """) - assert {[%ExDoc.ModuleNode{} = mod], []} = Retriever.docs_from_modules([Mod], %ExDoc.Config{}) + 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 From 6bd086e4715ed151f8a7240de9ffec0febd438b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vin=C3=ADcius=20M=C3=BCller?= Date: Thu, 7 Sep 2023 07:37:03 -0300 Subject: [PATCH 6/6] remove todo --- lib/ex_doc/formatter/html.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/ex_doc/formatter/html.ex b/lib/ex_doc/formatter/html.ex index 5ebeb3d32..c162842d0 100644 --- a/lib/ex_doc/formatter/html.ex +++ b/lib/ex_doc/formatter/html.ex @@ -10,7 +10,6 @@ defmodule ExDoc.Formatter.HTML do @doc """ Generate HTML documentation for the given modules. """ - # TODO: improve this spec @spec run( [ExDoc.ModuleNode.t()] | {[ExDoc.ModuleNode.t()], [ExDoc.ModuleNode.t()]},