Packages
earmark
1.3.6
1.5.0-pre1
retired
1.5.0-pre
retired
1.4.49
retired
1.4.48
retired
1.4.47
retired
1.4.46
retired
1.4.45
retired
1.4.44
retired
1.4.43
retired
1.4.42
retired
1.4.41
retired
1.4.40
retired
1.4.39
retired
1.4.38
retired
1.4.37
retired
1.4.36
retired
1.4.35
retired
1.4.34
retired
1.4.33
retired
1.4.32
retired
1.4.31
retired
1.4.30
retired
1.4.29
retired
1.4.28
retired
1.4.27
retired
1.4.26
retired
1.4.25
retired
1.4.24
retired
1.4.23
retired
1.4.22
retired
1.4.21
retired
1.4.20
retired
1.4.19
retired
1.4.18
retired
1.4.17
retired
1.4.16
retired
1.4.16-pre2
retired
1.4.16-pre1
retired
1.4.16-pre
retired
1.4.15
retired
1.4.14
retired
1.4.13
retired
1.4.12
retired
1.4.10
retired
1.4.9
retired
1.4.8
retired
1.4.7
retired
1.4.6
retired
1.4.5
retired
1.4.4
retired
1.4.3
retired
1.4.2
retired
1.4.1
retired
1.4.0
retired
1.3.6
retired
1.3.5
retired
1.3.4
retired
1.3.3
retired
1.3.2
retired
1.3.1
retired
1.3.0
retired
1.2.6
retired
1.2.5
retired
1.2.4
retired
1.2.3
retired
1.2.2
retired
1.2.1
retired
1.2.0
retired
1.1.1
retired
1.1.0
retired
1.0.3
retired
1.0.2
retired
1.0.1
retired
1.0.0
retired
0.2.1
retired
0.2.0
retired
0.1.19
retired
0.1.18
retired
0.1.17
retired
0.1.16
retired
0.1.15
retired
0.1.14
retired
0.1.13
retired
0.1.12
retired
0.1.10
retired
0.1.9
retired
0.1.8
retired
0.1.7
retired
0.1.6
retired
0.1.5
retired
0.1.4
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
Earmark is a pure-Elixir Markdown converter. It is intended to be used as a library (just call Earmark.as_html), but can also be used as a command-line tool (run mix escript.build first). Output generation is pluggable.
Retired package: Deprecated - Earmark is no longer maintained. Migrate to a replacement, for example MDEx (https://hex.pm/packages/mdex).
Current section
Files
Jump to
Current section
Files
tasks/readme.exs
defmodule Mix.Tasks.Readme do
use Mix.Task
@shortdoc "Build README.md from README.template by including module docs"
@moduledoc """
README.md is generated from README.template by expanding the following special
lines, all triggered by the regex `~r{\A%\w+}` where:
* `%toc` creates the Table Of Contents section
* `%moduledoc module` inserts the corresponding moduledoc
* `%functiondoc function` inserts the corresponding functiondoc
As the `README.md` is now regenerated every time no markers are needed in the `README.md` anymore,
however to be able to trace the origin of any part that needs to changed appropriate comments
are inserted anyway.
"""
def run([]) do
Mix.Task.run "compile", []
File.read!("README.template")
|> String.split("\n")
|> expand_docs([])
|> extract_tocs({[], []})
|> write_lines_to_readme_md()
end
defp expand_docs( lines, result )
defp expand_docs( [], result ), do: result
defp expand_docs( ["%toc" | rest], result), do: expand_docs(rest, ["%toc" | result])
defp expand_docs( ["%" <> line | rest], result), do: expand_docs(rest, [add_doc(line) | result])
defp expand_docs( [line | rest], result ), do: expand_docs(rest, [line | result])
defp extract_tocs(lines, result)
defp extract_tocs([], {lines, _}), do: lines
defp extract_tocs([ hl2 = "## " <> title | before ], { body, tocs }),
do: extract_tocs(before, { [hl2 | body], [make_toc_entry( title) | tocs] })
defp extract_tocs([ "%toc" | before ], {body, tocs}),
do: extract_tocs(before, { [make_toc_string(tocs) | body], [] })
defp extract_tocs( [line | before], {body, tocs}),
do: extract_tocs(before, {[line|body], tocs})
defp add_doc(line) do
[ "<!-- BEGIN inserted #{line} -->",
line
|> String.split()
|> doc_for(),
"<!-- END inserted #{line} -->" ]
|> Enum.join("\n")
end
defp doc_for(["moduledoc", name]) do
module = String.to_atom("Elixir." <> name)
docs = case Code.ensure_loaded(module) do
{:module, _} ->
if function_exported?(module, :__info__, 1) do
{:docs_v1, _, :elixir, _, %{"en" => module_doc}, _, _} = Code.fetch_docs(module)
module_doc
# case Code.get_docs(module, :moduledoc) do
# {_, docs} when is_binary(docs) ->
# docs
# _ -> nil
# end
else
nil
end
_ -> nil
end
docs # || "No module documentation available for #{name}\n"
end
defp doc_for(["functiondoc", name]) do
names = String.split(name, ".")
[ func | modules ] = Enum.reverse(names)
module = ["Elixir" | Enum.reverse(modules)] |> Enum.join(".") |> String.to_atom()
[ function_name, arity ] = String.split(func, "/")
function_name = String.to_atom(function_name)
{arity, _} = Integer.parse(arity)
markdown = case Code.ensure_loaded(module) do
{:module, _} ->
if function_exported?(module, :__info__, 1) do
{:docs_v1, _, :elixir, _, _, _, docs} = Code.fetch_docs(module)
Enum.find_value(docs, &find_function_doc(&1, function_name, arity))
else
nil
end
_ -> nil
end
markdown || "No function documentation available for #{name}\n"
end
defp find_function_doc(doctuple, function_name, arity) do
case doctuple do
{{:function, ^function_name, ^arity}, _anno, _sign, %{"en" => doc}, _metadata} -> doc
_ -> nil
end
end
defp make_h2_anchor(title), do: title |> String.downcase() |> String.replace(~r{\s+}, "-")
defp make_toc_entry(title), do: "* [#{title}](##{make_h2_anchor(title)})"
defp make_toc_string(tocs),
do:
[ "<!-- BEGIN generated TOC -->",
tocs |> Enum.join("\n"),
"<!-- END generated TOC -->"
] |> Enum.join("\n")
defp write_lines_to_readme_md(lines) do
lines
|> Enum.join("\n")
|> write_string_to_readme_md()
end
defp write_string_to_readme_md(content) do
IO.puts :stderr,
(case File.write("README.md", content) do
:ok -> "README.md regenerated"
{:error, reason} ->
"README.md: #{:file.format_error(reason)}"
end)
end
end
# SPDX-License-Identifier: Apache-2.0