Packages
ex_doc
0.38.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/formatter/html/search_data.ex
defmodule ExDoc.Formatter.HTML.SearchData do
@moduledoc false
def create(nodes, extras, proglang) do
items = Enum.flat_map(nodes, &module/1) ++ Enum.flat_map(extras, &extra/1)
data = %{
items: items,
content_type: "text/markdown",
proglang: proglang,
producer: %{
name: "ex_doc",
version: to_string(Application.spec(:ex_doc)[:vsn])
}
}
["searchData=" | ExDoc.Utils.to_json(data)]
end
defp extra(%{url: _}), do: []
defp extra(%{search_data: search_data} = map) when is_list(search_data) do
Enum.map(search_data, fn item ->
link =
if item.anchor === "" do
"#{URI.encode(map.id)}.html"
else
"#{URI.encode(map.id)}.html##{URI.encode(item.anchor)}"
end
encode(link, item.title <> " - #{map.id}", item.type, clean_markdown(item.body))
end)
end
defp extra(map) do
page = URI.encode(map.id) <> ".html"
{intro, sections} = extract_sections_from_markdown(map.source, "")
intro = encode(page, map.title, :extras, intro)
[intro | render_sections(sections, page, map.title, :extras)]
end
defp module(%ExDoc.ModuleNode{} = node) do
page = URI.encode(node.id) <> ".html"
{intro, sections} = extract_sections(node.source_format, node, "module-")
module = encode(page, node.title, node.type, intro)
docs = Enum.flat_map(node.docs, &node_child(&1, node, page))
[module] ++ render_sections(sections, page, node.title, node.type) ++ docs
end
defp node_child(node, module_node, page) do
title = "#{module_node.id}.#{node.name}/#{node.arity}"
{intro, sections} = extract_sections(module_node.source_format, node, node.id <> "-")
child = encode("#{page}##{URI.encode(node.id)}", title, node.type, intro)
[child | render_sections(sections, page, title, node.type)]
end
defp encode(ref, title, type, doc) do
%{ref: ref, title: title, type: type, doc: doc}
end
defp extract_sections("text/markdown", %{source_doc: %{"en" => doc}}, prefix) do
extract_sections_from_markdown(doc, prefix)
end
defp extract_sections(_format, %{doc: nil}, _prefix) do
{"", []}
end
defp extract_sections(_format, %{doc: doc}, _prefix) do
{ExDoc.DocAST.text(doc, " "), []}
end
defp extract_sections_from_markdown(string, prefix) do
[intro | headers_sections] =
Regex.split(~r/(?<!#)###? (?<header>\b.+)/, string, include_captures: true)
{headers, sections} =
headers_sections
|> Enum.chunk_every(2)
|> Enum.map(fn [header, section] -> {header, section} end)
|> Enum.unzip()
# Now convert the headers into a single markdown document
header_tags =
headers
|> Enum.join("\n\n")
|> ExDoc.Markdown.to_ast()
|> ExDoc.DocAST.add_ids_to_headers([:h2, :h3], prefix)
sections =
Enum.zip_with(header_tags, sections, fn {_, attrs, inner, _}, section ->
{ExDoc.DocAST.text(inner), Keyword.fetch!(attrs, :id), clean_markdown(section)}
end)
{clean_markdown(intro), sections}
end
defp clean_markdown(text) do
text
|> ExDoc.Utils.strip_tags(" ")
|> drop_ignorable_codeblocks()
|> String.trim()
end
defp render_sections(sections, page, title, type) do
for {header, anchor, body} <- sections do
encode("#{page}##{anchor}", header <> " - " <> title, type, body)
end
end
@ignored_codeblocks ~w[vega-lite]
defp drop_ignorable_codeblocks(section) do
block_names = Enum.join(@ignored_codeblocks, "|")
String.replace(section, ~r/^```(?:#{block_names})\n(?:[\s\S]*?)```$/m, "")
end
end