Skip to content

Commit 9770ce7

Browse files
committed
feat: implement node_synopsis function to extract and format documentation synopses for Markdown
1 parent b4a4ba5 commit 9770ce7

File tree

2 files changed

+72
-2
lines changed

2 files changed

+72
-2
lines changed

lib/ex_doc/formatter/markdown/templates.ex

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,57 @@ defmodule ExDoc.Formatter.MARKDOWN.Templates do
5656

5757
def node_doc(_), do: nil
5858

59+
@doc """
60+
Get synopsis for a node, handling both DocAST and string documentation.
61+
Uses DocAST synopsis extraction logic for consistency with HTML formatter.
62+
"""
63+
def node_synopsis(%{doc: doc}) when is_list(doc) do
64+
# For DocAST, extract synopsis DocAST and convert to markdown
65+
case extract_synopsis_ast(doc) do
66+
nil -> nil
67+
synopsis_ast -> ExDoc.DocAST.to_markdown(synopsis_ast)
68+
end
69+
end
70+
71+
def node_synopsis(%{doc: doc}) when is_binary(doc) do
72+
synopsis(doc)
73+
end
74+
75+
def node_synopsis(%{source_doc: %{"en" => source}}) when is_binary(source) do
76+
synopsis(source)
77+
end
78+
79+
def node_synopsis(%{rendered_doc: source}) when is_binary(source) do
80+
synopsis(source)
81+
end
82+
83+
def node_synopsis(%{source_doc: %{"en" => source}}) when is_list(source) do
84+
# For Erlang DocAST, extract synopsis and convert to plain text
85+
case extract_synopsis_ast(source) do
86+
nil -> nil
87+
synopsis_ast -> synopsis_ast |> ExDoc.DocAST.to_markdown() |> extract_plain_text()
88+
end
89+
end
90+
91+
def node_synopsis(_), do: nil
92+
93+
# Extract synopsis as DocAST (similar to ExDoc.DocAST.synopsis but returns AST instead of HTML string)
94+
defp extract_synopsis_ast({:p, _attrs, [_ | _] = inner, _meta}) do
95+
inner =
96+
case Enum.split(inner, -1) do
97+
{pre, [post]} when is_binary(post) ->
98+
pre ++ [String.trim_trailing(post, ":")]
99+
100+
_ ->
101+
inner
102+
end
103+
104+
{:p, [], ExDoc.DocAST.remove_ids(inner), %{}}
105+
end
106+
107+
defp extract_synopsis_ast([head | _]), do: extract_synopsis_ast(head)
108+
defp extract_synopsis_ast(_other), do: nil
109+
59110
defp extract_text_from_doc_ast(ast) when is_list(ast) do
60111
Enum.map_join(ast, "\n\n", &extract_text_from_doc_ast/1)
61112
end
@@ -71,6 +122,25 @@ defmodule ExDoc.Formatter.MARKDOWN.Templates do
71122
defp extract_text_from_doc_ast(text) when is_binary(text), do: text
72123
defp extract_text_from_doc_ast(_), do: ""
73124

125+
# Extract plain text from markdown (similar to the one in markdown.ex but here for templates)
126+
defp extract_plain_text(markdown) when is_binary(markdown) do
127+
markdown
128+
|> String.replace(~r/<[^>]*>/, "")
129+
|> String.replace(~r/\s+/, " ")
130+
|> String.trim()
131+
|> case do
132+
"" ->
133+
nil
134+
135+
text ->
136+
text
137+
|> String.slice(0, 150)
138+
|> then(fn s -> if String.length(s) == 150, do: s <> "...", else: s end)
139+
end
140+
end
141+
142+
defp extract_plain_text(_), do: nil
143+
74144
@doc """
75145
Gets the first paragraph of the documentation of a node. It strips
76146
surrounding white-spaces and trailing `:`.

lib/ex_doc/formatter/markdown/templates/summary_template.eex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88
> <%= h(deprecated) %>
99
<% end %>
1010

11-
<%= if doc = node_doc(node) do %>
12-
<%= synopsis(doc) %>
11+
<%= if synopsis_content = node_synopsis(node) do %>
12+
<%= synopsis_content %>
1313
<% end %>
1414

1515
<% end %>

0 commit comments

Comments
 (0)