Packages
ex_doc
0.37.0-rc.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
alias ExDoc.Utils
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(map) do
if custom_search_data = map[:search_data] do
extra_search_data(map, custom_search_data)
else
{intro, sections} = extract_sections_from_markdown(map.source)
intro_json_item =
encode(
"#{map.id}.html",
map.title,
:extras,
intro
)
section_json_items =
for {header, body} <- sections do
encode(
"#{map.id}.html##{Utils.text_to_id(header)}",
header <> " - #{map.title}",
:extras,
body
)
end
[intro_json_item | section_json_items]
end
end
defp extra_search_data(map, custom_search_data) do
Enum.map(custom_search_data, fn item ->
link =
if item.anchor === "" do
"#{map.id}.html"
else
"#{map.id}.html##{item.anchor}"
end
encode(link, item.title <> " - #{map.id}", item.type, clean_markdown(item.body))
end)
end
defp module(%ExDoc.ModuleNode{} = node) do
{intro, sections} = extract_sections(node.doc_format, node)
module =
encode(
"#{node.id}.html",
node.title,
node.type,
intro
)
module_sections =
for {header, body} <- sections do
encode(
"#{node.id}.html#module-#{Utils.text_to_id(header)}",
header <> " - #{node.title}",
node.type,
body
)
end
docs = Enum.flat_map(node.docs, &node_child(&1, node))
[module] ++ module_sections ++ docs
end
defp node_child(node, module_node) do
{intro, sections} = extract_sections(module_node.doc_format, node)
child =
encode(
"#{module_node.id}.html##{node.id}",
"#{module_node.id}.#{node.name}/#{node.arity}",
node.type,
intro
)
child_sections =
for {header, body} <- sections do
encode(
"#{module_node.id}.html##{node.id}-#{Utils.text_to_id(header)}",
header <> " - #{module_node.id}.#{node.name}/#{node.arity}",
node.type,
body
)
end
[child] ++ child_sections
end
defp encode(ref, title, type, doc) do
%{
ref: URI.encode(ref),
title: title,
type: type,
doc: doc
}
end
defp extract_sections("text/markdown", %{source_doc: %{"en" => doc}}) do
extract_sections_from_markdown(doc)
end
defp extract_sections("application/erlang+html", %{rendered_doc: nil}) do
{nil, []}
end
defp extract_sections("application/erlang+html", %{rendered_doc: doc}) do
{clean_html(doc), []}
end
defp extract_sections(_format, _doc) do
{"", []}
end
defp extract_sections_from_markdown(string) do
[intro | sections] =
Regex.split(~r/(?<!#)###? (?<header>\b.+)/, string, include_captures: true)
sections =
for [header, section] <- Enum.chunk_every(sections, 2) do
header = String.trim_leading(header, "#")
section =
section
|> ExDoc.Utils.strip_tags(" ")
|> drop_ignorable_codeblocks()
|> String.trim()
{clean_markdown(header), section}
end
{clean_markdown(intro), sections}
end
defp clean_markdown(doc) do
doc
|> ExDoc.Utils.strip_tags(" ")
|> String.trim()
end
defp clean_html(doc) do
doc
|> ExDoc.Utils.strip_tags(" ")
|> String.replace(~r/\s+/, " ")
|> String.trim()
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