Packages
ex_doc
0.21.1
0.40.3
0.40.2
0.40.1
0.40.0
0.39.3
0.39.2
0.39.1
0.39.0
0.38.4
0.38.3
0.38.2
0.38.1
0.38.0
0.37.3
0.37.2
0.37.1
0.37.0
0.37.0-rc.2
0.37.0-rc.1
0.37.0-rc.0
0.36.1
0.36.0
0.35.1
0.35.0
0.34.2
0.34.1
0.34.0
0.33.0
0.32.2
0.32.1
0.32.0
0.31.2
0.31.1
0.31.0
0.30.9
0.30.8
0.30.7
0.30.6
0.30.5
0.30.4
0.30.3
0.30.2
0.30.1
0.30.0
0.29.4
0.29.3
0.29.2
0.29.1
0.29.0
0.28.6
0.28.5
0.28.4
0.28.3
0.28.2
0.28.1
0.28.0
0.27.3
0.27.2
0.27.1
0.27.0
0.26.0
0.25.5
0.25.4
0.25.3
0.25.2
0.25.1
0.25.0
0.24.2
0.24.1
0.24.0
0.23.0
0.22.6
0.22.5
0.22.4
0.22.2
0.22.1
0.22.0
0.21.3
0.21.2
0.21.1
0.21.0
0.20.2
0.20.1
0.20.0
0.19.3
0.19.2
0.19.1
0.19.0
0.19.0-rc
0.18.4
0.18.3
0.18.2
0.18.1
0.18.0
retired
0.17.1
0.17.0
retired
0.16.4
0.16.3
0.16.2
0.16.1
0.16.0
0.15.1
0.15.0
0.14.5
0.14.4
0.14.3
0.14.2
0.14.1
0.14.0
0.13.2
0.13.1
0.13.0
0.12.0
0.11.5
0.11.4
0.11.3
0.11.2
0.11.1
0.11.0
0.10.0
0.9.0
0.8.4
0.8.3
0.8.2
0.8.1
0.8.0
0.7.3
0.7.2
0.7.1
0.7.0
0.6.2
0.6.1
0.6.0
0.5.2
0.5.1
ExDoc is a documentation generation tool for Elixir
Current section
Files
Jump to
Current section
Files
lib/ex_doc.ex
defmodule ExDoc do
@moduledoc false
@ex_doc_version Mix.Project.config()[:version]
alias ExDoc.Config
@doc """
Returns the ExDoc version (used in templates).
"""
@spec version :: String.t()
def version, do: @ex_doc_version
@doc """
Generates documentation for the given `project`, `vsn` (version)
and `options`.
"""
@spec generate_docs(String.t(), String.t(), Keyword.t()) :: atom
def generate_docs(project, vsn, options)
when is_binary(project) and is_binary(vsn) and is_list(options) do
config = build_config(project, vsn, options)
if processor = options[:markdown_processor] do
ExDoc.Markdown.put_markdown_processor(processor)
end
if markdown_processor_options = options[:markdown_processor_options] do
ExDoc.Markdown.configure_processor(markdown_processor_options)
end
docs = config.retriever.docs_from_dir(config.source_beam, config)
find_formatter(config.formatter).run(docs, config)
end
# Builds configuration by merging `options`, and normalizing the options.
@spec build_config(String.t(), String.t(), Keyword.t()) :: ExDoc.Config.t()
defp build_config(project, vsn, options) do
options = normalize_options(options)
preconfig = %Config{
project: project,
version: vsn,
main: options[:main],
homepage_url: options[:homepage_url],
source_root: options[:source_root] || File.cwd!()
}
struct(preconfig, options)
end
# Short path for programmatic interface
defp find_formatter(modname) when is_atom(modname), do: modname
defp find_formatter("ExDoc.Formatter." <> _ = name) do
[name]
|> Module.concat()
|> check_formatter_module(name)
end
defp find_formatter(name) do
[ExDoc.Formatter, String.upcase(name)]
|> Module.concat()
|> check_formatter_module(name)
end
defp check_formatter_module(modname, argname) do
if Code.ensure_loaded?(modname) do
modname
else
raise "formatter module #{inspect(argname)} not found"
end
end
# Helpers
defp normalize_options(options) do
pattern =
options[:source_url_pattern] ||
guess_url(options[:source_url], options[:source_ref] || ExDoc.Config.default_source_ref())
options
|> Keyword.put(:source_url_pattern, pattern)
|> normalize_output()
|> normalize_module_nesting_prefixes()
end
defp normalize_output(options) do
if is_binary(options[:output]) do
Keyword.put(options, :output, String.trim_trailing(options[:output], "/"))
else
options
end
end
defp normalize_module_nesting_prefixes(options) do
# sort in descending order to facilitate finding longest match
normalized_prefixes =
options
|> Keyword.get(:nest_modules_by_prefix, [])
|> Enum.map(&inspect/1)
|> Enum.sort()
|> Enum.reverse()
Keyword.put(options, :nest_modules_by_prefix, normalized_prefixes)
end
defp guess_url(url, ref) do
with {:ok, host_with_path} <- http_or_https(url),
{:ok, pattern} <- known_pattern(host_with_path, ref) do
"https://" <> append_slash(host_with_path) <> pattern
else
_ -> url
end
end
defp http_or_https("http://" <> rest),
do: {:ok, rest}
defp http_or_https("https://" <> rest),
do: {:ok, rest}
defp http_or_https(_),
do: :error
defp known_pattern("github.com/" <> _, ref),
do: {:ok, "blob/#{ref}/%{path}#L%{line}"}
defp known_pattern("gitlab.com/" <> _, ref),
do: {:ok, "blob/#{ref}/%{path}#L%{line}"}
defp known_pattern("bitbucket.org/" <> _, ref),
do: {:ok, "src/#{ref}/%{path}#cl-%{line}"}
defp known_pattern(_host_with_path, _ref),
do: :error
defp append_slash(url) do
if :binary.last(url) == ?/, do: url, else: url <> "/"
end
end