From f7aa94f7971e33ac81a872cee19e8f9c3b0911b9 Mon Sep 17 00:00:00 2001 From: Takayuki Kobayashi Date: Sun, 10 Mar 2024 16:06:05 +0900 Subject: [PATCH] Make a function acceptable for :skip_code_autolink_to option --- lib/ex_doc/autolink.ex | 7 ++++--- lib/ex_doc/config.ex | 15 +++++++++++++-- lib/ex_doc/language/erlang.ex | 4 ++-- lib/mix/tasks/docs.ex | 7 ++++--- test/ex_doc/config_test.exs | 24 ++++++++++++++++++++++++ test/ex_doc/language/elixir_test.exs | 5 +---- 6 files changed, 48 insertions(+), 14 deletions(-) diff --git a/lib/ex_doc/autolink.ex b/lib/ex_doc/autolink.ex index dafa639eb..f5b2ed3fc 100644 --- a/lib/ex_doc/autolink.ex +++ b/lib/ex_doc/autolink.ex @@ -26,7 +26,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") + # * `:skip_code_autolink_to` - function that will be called with a term and return a boolean + # whether to skip autolinking to it. # # * `:filtered_modules` - A list of module nodes that were filtered by the retriever # @@ -54,7 +55,7 @@ defmodule ExDoc.Autolink do current_kfa: nil, siblings: [], skip_undefined_reference_warnings_on: [], - skip_code_autolink_to: [], + skip_code_autolink_to: &ExDoc.Config.skip_code_autolink_to/1, force_module_prefix: nil, filtered_modules: [], warnings: :emit @@ -201,7 +202,7 @@ defmodule ExDoc.Autolink do end def url(string, mode, config) do - if Enum.any?(config.skip_code_autolink_to, &(&1 == string)) do + if config.skip_code_autolink_to.(string) do nil else parse_url(string, mode, config) diff --git a/lib/ex_doc/config.ex b/lib/ex_doc/config.ex index f2e2ac0ed..a71a18149 100644 --- a/lib/ex_doc/config.ex +++ b/lib/ex_doc/config.ex @@ -8,6 +8,7 @@ defmodule ExDoc.Config do def before_closing_footer_tag(_), do: "" def before_closing_body_tag(_), do: "" def annotations_for_docs(_), do: [] + def skip_code_autolink_to(_string), do: false defstruct annotations_for_docs: &__MODULE__.annotations_for_docs/1, api_reference: true, @@ -39,7 +40,7 @@ defmodule ExDoc.Config do project: nil, retriever: ExDoc.Retriever, skip_undefined_reference_warnings_on: [], - skip_code_autolink_to: [], + skip_code_autolink_to: &__MODULE__.skip_code_autolink_to/1, source_beam: nil, source_ref: @default_source_ref, source_url: nil, @@ -77,7 +78,7 @@ defmodule ExDoc.Config do project: nil | String.t(), retriever: atom(), skip_undefined_reference_warnings_on: [String.t()], - skip_code_autolink_to: [String.t()], + skip_code_autolink_to: (String.t() -> boolean), source_beam: nil | String.t(), source_ref: nil | String.t(), source_url: nil | String.t(), @@ -102,6 +103,9 @@ defmodule ExDoc.Config do options end + {skip_code_autolink_to, options} = + Keyword.pop(options, :skip_code_autolink_to, &skip_code_autolink_to/1) + {source_url_pattern, options} = Keyword.pop_lazy(options, :source_url_pattern, fn -> guess_url(options[:source_url], options[:source_ref] || @default_source_ref) @@ -116,6 +120,7 @@ defmodule ExDoc.Config do output: normalize_output(output), proglang: normalize_proglang(proglang), project: project, + skip_code_autolink_to: normalize_skip_code_autolink_to(skip_code_autolink_to), source_url_pattern: source_url_pattern, version: vsn } @@ -169,6 +174,12 @@ defmodule ExDoc.Config do defp normalize_filter_modules(fun) when is_function(fun, 2), do: fun + defp normalize_skip_code_autolink_to(strings) when is_list(strings), + do: &(&1 in strings) + + defp normalize_skip_code_autolink_to(fun) when is_function(fun, 1), + do: fun + defp guess_url(url, ref) do with {:ok, host_with_path} <- http_or_https(url), {:ok, pattern} <- known_pattern(host_with_path, ref) do diff --git a/lib/ex_doc/language/erlang.ex b/lib/ex_doc/language/erlang.ex index c21d2b8a5..d4d5f5a89 100644 --- a/lib/ex_doc/language/erlang.ex +++ b/lib/ex_doc/language/erlang.ex @@ -631,7 +631,7 @@ defmodule ExDoc.Language.Erlang do visibility = Refs.get_visibility(ref) cond do - Enum.any?(config.skip_code_autolink_to, &(&1 == "t:#{name}/#{arity}")) -> + config.skip_code_autolink_to.("t:#{name}/#{arity}") -> nil visibility in [:public] -> @@ -657,7 +657,7 @@ defmodule ExDoc.Language.Erlang do visibility = Refs.get_visibility(ref) cond do - Enum.any?(config.skip_code_autolink_to, &(&1 == "t:#{module}:#{name}/#{arity}")) -> + config.skip_code_autolink_to.("t:#{module}:#{name}/#{arity}") -> nil visibility in [:public] -> diff --git a/lib/mix/tasks/docs.ex b/lib/mix/tasks/docs.ex index 40ef255fd..f6ac79c4a 100644 --- a/lib/mix/tasks/docs.ex +++ b/lib/mix/tasks/docs.ex @@ -157,9 +157,10 @@ defmodule Mix.Tasks.Docs do * `:skip_code_autolink_to` - Similar to `:skip_undefined_reference_warnings_on`, this option controls which terms will be skipped by ExDoc when building documentation. - Useful for example if you want to highlight private modules or functions - without warnings (e.g.: `["PrivateModule", "PrivateModule.func/1"]`); - default: `[]`. + Useful for example if you want to highlight private modules or functions without warnings. + This option can be a function from a term to a boolean (e.g.: `&String.match?(&1, ~r/PrivateModule/)` + or a list of terms (e.g.:`["PrivateModule", "PrivateModule.func/1"]`); + default is nothing to be skipped. * `:source_beam` - Path to the beam directory; default: mix's compile path. diff --git a/test/ex_doc/config_test.exs b/test/ex_doc/config_test.exs index df4bc1b99..9b00ddb1b 100644 --- a/test/ex_doc/config_test.exs +++ b/test/ex_doc/config_test.exs @@ -30,4 +30,28 @@ defmodule ExDoc.ConfigTest do assert config.filter_modules.(Foo, %{works: true}) refute config.filter_modules.(Foo, %{works: false}) end + + test "normalizes skip_code_autolink_to" do + config = + ExDoc.Config.build(@project, @version, + skip_code_autolink_to: ["ConfigTest.Hidden", "ConfigTest.Hidden.foo/1"] + ) + + assert config.skip_code_autolink_to.("ConfigTest.Hidden") + assert config.skip_code_autolink_to.("ConfigTest.Hidden.foo/1") + refute config.skip_code_autolink_to.("ConfigTest.Hidden.foo/2") + refute config.skip_code_autolink_to.("ConfigTest.Hidden.bar/1") + refute config.skip_code_autolink_to.("ConfigTest.NotHidden") + + config = + ExDoc.Config.build(@project, @version, + skip_code_autolink_to: &String.match?(&1, ~r/\AConfigTest\.Hidden/) + ) + + assert config.skip_code_autolink_to.("ConfigTest.Hidden") + assert config.skip_code_autolink_to.("ConfigTest.Hidden.foo/1") + assert config.skip_code_autolink_to.("ConfigTest.Hidden.foo/2") + assert config.skip_code_autolink_to.("ConfigTest.Hidden.bar/1") + refute config.skip_code_autolink_to.("ConfigTest.NotHidden") + end end diff --git a/test/ex_doc/language/elixir_test.exs b/test/ex_doc/language/elixir_test.exs index a3a57f5f7..109dbf32f 100644 --- a/test/ex_doc/language/elixir_test.exs +++ b/test/ex_doc/language/elixir_test.exs @@ -425,10 +425,7 @@ defmodule ExDoc.Language.ElixirTest do ]) options = [ - skip_code_autolink_to: [ - "AutolinkTest.Hidden", - "AutolinkTest.Hidden.foo/1" - ] + skip_code_autolink_to: &String.match?(&1, ~r/\AAutolinkTest\.Hidden/) ] assert autolink_doc("`AutolinkTest.Hidden`", options) ==