diff --git a/lib/ex_doc/language/elixir.ex b/lib/ex_doc/language/elixir.ex
index 172a5d49d..e64ac42ad 100644
--- a/lib/ex_doc/language/elixir.ex
+++ b/lib/ex_doc/language/elixir.ex
@@ -96,7 +96,7 @@ defmodule ExDoc.Language.Elixir do
# If it is none, then we need to look at underscore.
# TODO: We can remove this on Elixir v1.13 as all underscored are hidden.
defp doc?({{_, name, _}, _, _, :none, _}, _type) do
- hd(Atom.to_charlist(name)) != ?_
+ not match?([?_ | _], Atom.to_charlist(name))
end
# Everything else is hidden.
@@ -559,6 +559,14 @@ defmodule ExDoc.Language.Elixir do
end
defp url(string, mode, config) do
+ if Enum.any?(config.skip_code_autolink_to, &(&1 == string)) do
+ nil
+ else
+ parse_url(string, mode, config)
+ end
+ end
+
+ defp parse_url(string, mode, config) do
case Regex.run(~r{^(.+)/(\d+)$}, string) do
[_, left, right] ->
with {:ok, arity} <- parse_arity(right) do
@@ -775,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/lib/ex_doc/language/erlang.ex b/lib/ex_doc/language/erlang.ex
index 2363813ff..0d1ce48da 100644
--- a/lib/ex_doc/language/erlang.ex
+++ b/lib/ex_doc/language/erlang.ex
@@ -215,6 +215,10 @@ defmodule ExDoc.Language.Erlang do
binary
end
+ defp walk_doc({:code, _attrs, [{:a, _, _, _}], _meta} = ast, _config) do
+ ast
+ end
+
defp walk_doc({:code, attrs, [code], meta} = ast, config) do
{text, url} =
case parse_autolink(code) do
@@ -583,6 +587,10 @@ defmodule ExDoc.Language.Erlang do
{:->, _, [[{name, _, _}], {:any, _, _}]}, acc when name == :... ->
{nil, acc}
+ # record{type :: remote:type/arity}
+ {:field_type, _, [name, {{:., _, [r_mod, r_type]}, _, args}]}, acc ->
+ {name, [{pp({r_mod, r_type}), {r_mod, r_type, length(args)}} | acc]}
+
# #{x :: t()}
{:field_type, _, [name, type]}, acc when is_atom(name) ->
{type, acc}
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/refs.ex b/lib/ex_doc/refs.ex
index 4a7dac33f..b09b3b391 100644
--- a/lib/ex_doc/refs.ex
+++ b/lib/ex_doc/refs.ex
@@ -116,7 +116,7 @@ defmodule ExDoc.Refs do
defguardp has_no_docs(doc) when doc == :none or doc == %{}
- defp starts_with_underscore?(name), do: hd(Atom.to_charlist(name)) == ?_
+ defp starts_with_underscore?(name), do: match?([?_ | _], Atom.to_charlist(name))
defp visibility(:hidden),
do: :hidden
diff --git a/lib/ex_doc/retriever.ex b/lib/ex_doc/retriever.ex
index 59abbb1c0..7a5bcf509 100644
--- a/lib/ex_doc/retriever.ex
+++ b/lib/ex_doc/retriever.ex
@@ -12,29 +12,59 @@ 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))
-
- files
- |> Enum.map(&filename_to_module/1)
- |> docs_from_modules(config)
+ dir
+ |> docs_from_dir({[], []}, config)
+ |> sort_modules(config)
end
def docs_from_dir(dirs, config) when is_list(dirs) do
- Enum.flat_map(dirs, &docs_from_dir(&1, config))
+ dirs
+ |> Enum.reduce({[], []}, &docs_from_dir(&1, &2, config))
|> sort_modules(config)
end
+ defp docs_from_dir(dir, acc, config) do
+ files = Path.wildcard(Path.expand("*.beam", dir))
+
+ files
+ |> Enum.map(&filename_to_module/1)
+ |> docs_from_modules(acc, config)
+ 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))
- |> sort_modules(config)
+ modules |> docs_from_modules({[], []}, config) |> sort_modules(config)
+ end
+
+ defp docs_from_modules(modules, acc, config) do
+ Enum.reduce(modules, acc, 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)
+ 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
@@ -50,14 +80,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 +171,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/lib/mix/tasks/docs.ex b/lib/mix/tasks/docs.ex
index 7712dcb64..5c9e44e6a 100644
--- a/lib/mix/tasks/docs.ex
+++ b/lib/mix/tasks/docs.ex
@@ -10,11 +10,11 @@ defmodule Mix.Tasks.Docs do
## Command line options
* `--canonical`, `-n` - Indicate the preferred URL with
- rel="canonical" link element, defaults to no canonical path
+ `rel="canonical"` link element, defaults to no canonical path
- * `--formatter`, `-f` - Which formatters to use, "html" or
- "epub". This option can be given more than once. By default,
- both html and epub are generated.
+ * `--formatter`, `-f` - Which formatters to use, `html` or
+ `epub`. This option can be given more than once. By default,
+ both `html` and `epub` are generated.
* `--language` - Specifies the language to annotate the
EPUB output in valid [BCP 47](https://tools.ietf.org/html/bcp47)
@@ -24,8 +24,8 @@ defmodule Mix.Tasks.Docs do
* `--output`, `-o` - Output directory for the generated
docs, default: `"doc"`
- * `--proglang` - Chooses the main programming language: "elixir"
- or "erlang"
+ * `--proglang` - Chooses the main programming language: `elixir`
+ or `erlang`
The command line options have higher precedence than the options
specified in your `mix.exs` file below.
@@ -148,6 +148,12 @@ defmodule Mix.Tasks.Docs do
skip the warnings, for a given module/function/callback/type (e.g.: `["Foo", "Bar.baz/0"]`)
or on a given file (e.g.: `["pages/deprecations.md"]`); default: `[]`.
+ * `: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: `[]`.
+
* `:source_beam` - Path to the beam directory; default: mix's compile path.
* `:source_ref` - The branch/commit/tag used for source link inference;
diff --git a/mix.exs b/mix.exs
index ba26772e7..1aed6c84c 100644
--- a/mix.exs
+++ b/mix.exs
@@ -2,7 +2,7 @@ defmodule ExDoc.Mixfile do
use Mix.Project
@source_url "https://github.com/elixir-lang/ex_doc"
- @version "0.30.6"
+ @version "0.30.9"
def project do
[
diff --git a/test/ex_doc/formatter/epub/templates_test.exs b/test/ex_doc/formatter/epub/templates_test.exs
index 7eed7648c..7754c004e 100644
--- a/test/ex_doc/formatter/epub/templates_test.exs
+++ b/test/ex_doc/formatter/epub/templates_test.exs
@@ -27,8 +27,8 @@ 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")
+ {mods, []} = ExDoc.Retriever.docs_from_modules(names, config)
+ [mod | _] = HTML.render_all(mods, [], ".xhtml", config, highlight_tag: "samp")
Templates.module_page(config, mod)
end
@@ -59,11 +59,13 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do
assert content =~ ~r{
CompiledWithDocs [^<]* }
assert content =~ ~r{
\s*CompiledWithDocs\s*}
+ assert content =~ ~s{Summary }
+
assert content =~
- ~r{}ms
+ ~r{.*Example.* }ms
assert content =~
- ~r{}ms
+ ~r{.*Example H3 heading.* }ms
assert content =~
~r{moduledoc.*Example.*CompiledWithDocs \. example .*}ms
@@ -85,8 +87,8 @@ defmodule ExDoc.Formatter.EPUB.TemplatesTest do
]
)
- assert content =~ ~r{id="example-functions".*href="#example-functions".*Example functions}ms
- assert content =~ ~r{id="legacy".*href="#legacy".*Legacy}ms
+ assert content =~ ~r{id="example-functions".*Example functions}ms
+ assert content =~ ~r{id="legacy".*Legacy}ms
assert content =~ ~r{id="example-functions".*id="example/2"}ms
refute content =~ ~r{id="legacy".*id="example/2"}ms
refute content =~ ~r{id="functions".*id="example/2"}ms
diff --git a/test/ex_doc/formatter/epub_io_test.exs b/test/ex_doc/formatter/epub_io_test.exs
deleted file mode 100644
index 086374790..000000000
--- a/test/ex_doc/formatter/epub_io_test.exs
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule ExDoc.Formatter.EPUBIOTest do
- use ExUnit.Case, async: false
-
- @moduletag :tmp_dir
-
- test "succeeds if trying to write into an empty existing directory", %{tmp_dir: tmp_dir} do
- File.mkdir!("#{tmp_dir}/doc")
-
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) == ""
- end
-
- test "warns if trying to write into existing directory with files", %{tmp_dir: tmp_dir} do
- File.mkdir!("#{tmp_dir}/doc")
- File.touch!("#{tmp_dir}/doc/foo.txt")
-
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) =~ "ExDoc is outputting to an existing directory"
-
- # Warn only once
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) == ""
- end
-
- defp generate_docs(tmp_dir) do
- config = [
- app: :foo,
- formatter: "epub",
- output: "#{tmp_dir}/doc",
- source_beam: "#{tmp_dir}/ebin"
- ]
-
- ExDoc.generate_docs("Foo", "1.0.0", config)
- end
-end
diff --git a/test/ex_doc/formatter/html/erlang_test.exs b/test/ex_doc/formatter/html/erlang_test.exs
index d993c9278..92556efc2 100644
--- a/test/ex_doc/formatter/html/erlang_test.exs
+++ b/test/ex_doc/formatter/html/erlang_test.exs
@@ -5,19 +5,13 @@ defmodule ExDoc.Formatter.HTML.ErlangTest do
@moduletag :otp_eep48
@moduletag :tmp_dir
- setup %{tmp_dir: tmp_dir} do
- output = tmp_dir <> "/doc"
- File.mkdir!(output)
- File.touch!("#{output}/.ex_doc")
- end
-
test "smoke test", c do
erlc(c, :foo, ~S"""
%% @doc
%% foo module.
-module(foo).
-export([foo/1, bar/0]).
- -export_type([t/0]).
+ -export_type([t/0, t2/0]).
%% @doc
%% f/0 function.
@@ -29,6 +23,10 @@ defmodule ExDoc.Formatter.HTML.ErlangTest do
-type t() :: atom().
%% t/0 type.
+
+ -record(rec, {k1 :: any(), k2 :: any()}).
+
+ -type t2() :: #rec{k1 :: uri_string:uri_string(), k2 :: uri_string:uri_string() | undefined}.
""")
doc = generate_docs(c)
@@ -38,6 +36,12 @@ defmodule ExDoc.Formatter.HTML.ErlangTest do
assert "-type t() :: atom()." =
doc |> Floki.find("pre:fl-contains('t() :: atom().')") |> Floki.text()
+
+ assert "-type t2() :: #rec{k1 :: uri_string:uri_string(), k2 :: uri_string:uri_string() | undefined}."
+
+ doc
+ |> Floki.find("pre:fl-contains('t2() ::')")
+ |> Floki.text()
end
defp generate_docs(c) do
diff --git a/test/ex_doc/formatter/html/search_data_test.exs b/test/ex_doc/formatter/html/search_data_test.exs
index 9cfda6fb3..a04af1f67 100644
--- a/test/ex_doc/formatter/html/search_data_test.exs
+++ b/test/ex_doc/formatter/html/search_data_test.exs
@@ -4,12 +4,6 @@ defmodule ExDoc.Formatter.HTML.SearchDataTest do
@moduletag :tmp_dir
- setup %{tmp_dir: tmp_dir} do
- output = tmp_dir <> "/doc"
- File.mkdir!(output)
- File.touch!("#{output}/.ex_doc")
- end
-
test "Elixir module", c do
modules =
elixirc(c, ~S'''
@@ -243,9 +237,9 @@ 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)
+ ExDoc.Formatter.HTML.run(modules, [], config)
[path] = Path.wildcard(Path.join([config.output, "dist", "search_data-*.js"]))
"searchData=" <> json = File.read!(path)
Jason.decode!(json)
diff --git a/test/ex_doc/formatter/html/templates_test.exs b/test/ex_doc/formatter/html/templates_test.exs
index f0912bc07..4b6e5d0d7 100644
--- a/test/ex_doc/formatter/html/templates_test.exs
+++ b/test/ex_doc/formatter/html/templates_test.exs
@@ -31,8 +31,8 @@ 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, [])
+ {mods, []} = ExDoc.Retriever.docs_from_modules(names, config)
+ [mod | _] = HTML.render_all(mods, [], ".html", config, [])
Templates.module_page(mod, @empty_nodes_map, config)
end
@@ -47,61 +47,61 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
test "generates headers with hovers" do
assert Templates.link_headings("Foo Bar ") == """
"""
assert Templates.link_headings("Foo \nBar ") == """
"""
assert Templates.link_headings("Bar ") == """
"""
assert Templates.link_headings(" \nBar ") == """
"""
assert Templates.link_headings("Foo ") ==
String.trim_trailing("""
""")
@@ -109,10 +109,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
assert Templates.link_headings("Foo \n ") ==
String.trim_trailing("""
@@ -120,10 +120,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
assert Templates.link_headings("Foo ") == """
"""
end
@@ -131,17 +131,17 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
test "generates headers with unique id's" do
assert Templates.link_headings("Foo \nFoo ") == """
"""
end
@@ -153,10 +153,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
assert Templates.link_headings(admonition_block) == """
"""
@@ -242,9 +242,14 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
tasks: []
})
- assert content =~ ~r{ Modules }
- refute content =~ ~r{
Exceptions }
- refute content =~ ~r{
Mix Tasks }
+ assert content =~
+ ~r{
[\s\n]*[\s\n]*Modules[\s\n]* [\s\n]* }
+
+ assert content =~
+ ~r{}
+
+ refute content =~ ~r{id="tasks-list-tab-button"}
+ refute content =~ ~r{id="tasks-full-list"}
end
test "display built with footer by proglang option", context do
@@ -264,7 +269,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 +298,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 +311,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 +320,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 +366,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,8 +425,8 @@ 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 = HTML.render_all(nodes, ".html", config, [])
+ {nodes, []} = ExDoc.Retriever.docs_from_modules(names, config)
+ nodes = HTML.render_all(nodes, [], ".html", config, [])
[compiled_with_docs, compiled_without_docs, duplicate_headings] =
create_sidebar_items(%{modules: nodes}, [])["modules"]
@@ -471,10 +476,10 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
~r{moduledoc.*Example.*
CompiledWithDocs \. example .*}ms
assert content =~
- ~r{
}ms
+ ~r{
.*.* .* .*Example ☃ Unicode > escaping .* }ms
assert content =~
- ~r{
}ms
+ ~r{
.*.* .* .*Example H3 heading .* }ms
# Summaries
assert content =~ ~r{example/2.*Some example}ms
@@ -567,7 +572,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
content = get_module_page([CompiledWithDocs], context)
assert content =~
- ~r{
}ms
+ ~r{
.*.* .* .*Examples .* }ms
end
test "do not output overlapping functions, causing duplicate IDs", context do
diff --git a/test/ex_doc/formatter/html_io_test.exs b/test/ex_doc/formatter/html_io_test.exs
deleted file mode 100644
index 8da38c2b2..000000000
--- a/test/ex_doc/formatter/html_io_test.exs
+++ /dev/null
@@ -1,38 +0,0 @@
-defmodule ExDoc.Formatter.HtmlIOTest do
- use ExUnit.Case, async: false
-
- @moduletag :tmp_dir
-
- test "succeeds if trying to write into an empty existing directory", %{tmp_dir: tmp_dir} do
- File.mkdir!("#{tmp_dir}/doc")
-
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) == ""
- end
-
- test "warns if trying to write into existing directory with files", %{tmp_dir: tmp_dir} do
- File.mkdir!("#{tmp_dir}/doc")
- File.touch!("#{tmp_dir}/doc/foo.txt")
-
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) =~ "ExDoc is outputting to an existing directory"
-
- # Warn only once
- assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
- generate_docs(tmp_dir)
- end) == ""
- end
-
- defp generate_docs(tmp_dir) do
- config = [
- app: :foo,
- formatter: "html",
- output: "#{tmp_dir}/doc",
- source_beam: "#{tmp_dir}/ebin"
- ]
-
- ExDoc.generate_docs("Foo", "1.0.0", config)
- end
-end
diff --git a/test/ex_doc/formatter/html_test.exs b/test/ex_doc/formatter/html_test.exs
index 03490d5f4..f4e2f7382 100644
--- a/test/ex_doc/formatter/html_test.exs
+++ b/test/ex_doc/formatter/html_test.exs
@@ -6,12 +6,6 @@ defmodule ExDoc.Formatter.HTMLTest do
@moduletag :tmp_dir
- setup %{tmp_dir: tmp_dir} do
- output = tmp_dir <> "/html"
- File.mkdir_p!(output)
- File.touch!(output <> "/.ex_doc")
- end
-
defp read_wildcard!(path) do
[file] = Path.wildcard(path)
File.read!(file)
@@ -365,10 +359,10 @@ defmodule ExDoc.Formatter.HTMLTest do
assert content =~ ~r{
README [^<]* }
assert content =~
- ~r{}ms
+ ~r{}ms
assert content =~
- ~r{
}ms
+ ~r{
.*.* .* .*more > than .* }ms
assert content =~ ~r{
RandomError}
@@ -519,7 +513,7 @@ defmodule ExDoc.Formatter.HTMLTest do
doc_config(context,
extras: [
"test/fixtures/PlainTextFiles.md",
- "test/fixtures/LICENSE": [filename: "linked-license"],
+ {"test/fixtures/LICENSE", filename: "linked-license"},
"test/fixtures/PlainText.txt": [filename: "plain_text"]
]
)
diff --git a/test/ex_doc/language/elixir_test.exs b/test/ex_doc/language/elixir_test.exs
index e0bd260c0..01a635b64 100644
--- a/test/ex_doc/language/elixir_test.exs
+++ b/test/ex_doc/language/elixir_test.exs
@@ -381,6 +381,20 @@ defmodule ExDoc.Language.ElixirTest do
~s[t() :: String.t ()]
end
+ test "skips autolinking if requested" do
+ ExDoc.Refs.insert([
+ {{:module, AutolinkTest.Hidden}, :hidden},
+ {{:function, AutolinkTest.Hidden, :foo, 1}, :hidden}
+ ])
+
+ assert_skip_autolink_no_warn("AutolinkTest.Hidden")
+ assert_skip_autolink_no_warn("AutolinkTest.Hidden.foo/1")
+ end
+
+ defp assert_skip_autolink_no_warn(string) do
+ assert_unchanged(~m(`#{string}`), skip_code_autolink_to: [string])
+ end
+
test "Elixir basic types" do
assert autolink_spec(quote(do: t() :: atom())) ==
~s[t() ::
atom ()]
@@ -425,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},
diff --git a/test/ex_doc/language/erlang_test.exs b/test/ex_doc/language/erlang_test.exs
index 0a986ce37..8a1cc231d 100644
--- a/test/ex_doc/language/erlang_test.exs
+++ b/test/ex_doc/language/erlang_test.exs
@@ -124,6 +124,21 @@ defmodule ExDoc.Language.ErlangTest do
~s|
array:array()|
end
+ test "abstract types - description", c do
+ assert autolink_doc("{@type myList(X). A special kind of lists ...}", c) ==
+ ~s|
myList (X)|
+ end
+
+ test "abstract types - description+dot", c do
+ assert autolink_doc("{@type myList(X, Y).}", c) ==
+ ~s|
myList (X, Y)|
+ end
+
+ test "abstract types - no description", c do
+ assert autolink_doc("{@type myList()}", c) ==
+ ~s|
myList() |
+ end
+
test "bad module", c do
assert ExUnit.CaptureIO.capture_io(:stderr, fn ->
assert autolink_doc("{@link bad}", c) == ~s|
bad|
diff --git a/test/ex_doc/retriever/elixir_test.exs b/test/ex_doc/retriever/elixir_test.exs
index 6c69a5636..21b5088f7 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,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
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..c138c0e07 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,16 @@ 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)
+
+ assert {
+ [%{id: "A"}, %{id: "A.A"}],
+ [%{id: "B"}]
+ } = Retriever.docs_from_dir([ebin_dir], config)
end
test "natural sorting", c do
@@ -229,7 +235,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 +261,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
diff --git a/test/ex_doc_test.exs b/test/ex_doc_test.exs
index 85d2da50b..525b60f70 100644
--- a/test/ex_doc_test.exs
+++ b/test/ex_doc_test.exs
@@ -12,7 +12,7 @@ defmodule ExDocTest do
# Simple formatter that returns whatever is passed into it
defmodule IdentityFormatter do
- def run(modules, config) do
+ def run(modules, _filtered, config) do
{modules, config}
end
end
@@ -63,7 +63,7 @@ defmodule ExDocTest do
source_beam: "beam_dir"
]
- {{source_dir, _retr_config}, _config} = ExDoc.generate_docs("Elixir", "1", options)
+ assert {source_dir, _config} = ExDoc.generate_docs("Elixir", "1", options)
assert source_dir == options[:source_beam]
end
diff --git a/test/test_helper.exs b/test/test_helper.exs
index bf13c7992..9ce5e3e4b 100644
--- a/test/test_helper.exs
+++ b/test/test_helper.exs
@@ -22,10 +22,6 @@ defmodule TestHelper do
def elixirc(context, filename \\ "nofile", code) do
dir = context.tmp_dir
- output_dir = context.tmp_dir <> "/html"
- File.mkdir_p!(output_dir)
- File.write!(output_dir <> "/.ex_doc", "")
-
src_path = Path.join([dir, filename])
src_path |> Path.dirname() |> File.mkdir_p!()
File.write!(src_path, code)