Skip to content

Commit

Permalink
Remove "Specs" heading and render full typespecs (#1455)
Browse files Browse the repository at this point in the history
  • Loading branch information
Odaeus authored Mar 10, 2022
1 parent 6ba40a7 commit 28ff9a3
Show file tree
Hide file tree
Showing 11 changed files with 45 additions and 8 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,8 @@ The easiest way to test changes to ExDoc is to locally rebuild the app and its o
4. Run `mix lint` to check if the Elixir and JavaScript files are properly formatted.
You can run `mix fix` to let the JavaScript linter and Elixir formatter fix the code automatically before submitting your pull request

Note that Node 17 or later is not supported due to [API breaking changes with Webpack](https://github.com/webpack/webpack/issues/14532).

## License

ExDoc source code is released under [Apache 2 License](LICENSE). The generated contents, however, are under different licenses based on projects used to help render HTML, including CSS, JS, and other assets.
Expand Down
6 changes: 4 additions & 2 deletions assets/less/content/functions.less
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,6 @@
}

.specs {
padding: 1em;

pre {
font-family: @monoFontFamily;
font-size: 0.9em;
Expand All @@ -69,6 +67,10 @@
margin: 0;
padding: 0;
}

.attribute {
color: @mediumGray;
}
}

.docstring {
Expand Down
4 changes: 4 additions & 0 deletions assets/less/night/content/functions.less
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@
color: @nightTextBody;
}

.specs .attribute {
color: @nightMediumGray;
}

div.deprecated {
background-color: @nightDeprecated;
}
9 changes: 8 additions & 1 deletion lib/ex_doc/formatter/html/templates.ex
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ defmodule ExDoc.Formatter.HTML.Templates do
nil
end

@doc """
Format the attribute type used to define the spec of the given `node`.
"""
def format_spec_attribute(module, node) do
module.language.format_spec_attribute(node)
end

@doc """
Get defaults clauses.
"""
Expand Down Expand Up @@ -297,7 +304,7 @@ defmodule ExDoc.Formatter.HTML.Templates do
end

templates = [
detail_template: [:node, :_module],
detail_template: [:node, :module],
footer_template: [:config, :node],
head_template: [:config, :page],
module_template: [:config, :module, :summary, :nodes_map],
Expand Down
3 changes: 1 addition & 2 deletions lib/ex_doc/formatter/html/templates/detail_template.eex
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,9 @@

<section class="docstring">
<%= if specs = get_specs(node) do %>
<h2>Specs</h2>
<div class="specs">
<%= for spec <- specs do %>
<pre translate="no"><%= spec %></pre>
<pre translate="no"><span class="attribute"><%= format_spec_attribute(module, node) %></span> <%= spec %></pre>
<% end %>
</div>
<% end %>
Expand Down
5 changes: 5 additions & 0 deletions lib/ex_doc/language.ex
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ defmodule ExDoc.Language do
opts: keyword()
}

@doc """
Return an attribute in the canonical representation.
"""
@callback format_spec_attribute(%ExDoc.FunctionNode{} | %ExDoc.TypeNode{}) :: String.t()

def get(:elixir, _module), do: {:ok, ExDoc.Language.Elixir}
def get(:erlang, _module), do: {:ok, ExDoc.Language.Erlang}

Expand Down
6 changes: 6 additions & 0 deletions lib/ex_doc/language/elixir.ex
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,12 @@ defmodule ExDoc.Language.Elixir do
}
end

@impl true
def format_spec_attribute(%ExDoc.TypeNode{type: type}), do: "@#{type}"
def format_spec_attribute(%ExDoc.FunctionNode{type: :callback}), do: "@callback"
def format_spec_attribute(%ExDoc.FunctionNode{type: :macrocallback}), do: "@macrocallback"
def format_spec_attribute(%ExDoc.FunctionNode{}), do: "@spec"

## Module Helpers

defp nesting_info(title, prefixes) do
Expand Down
5 changes: 5 additions & 0 deletions lib/ex_doc/language/erlang.ex
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,11 @@ defmodule ExDoc.Language.Erlang do
}
end

@impl true
def format_spec_attribute(%ExDoc.TypeNode{type: type}), do: "-#{type}"
def format_spec_attribute(%ExDoc.FunctionNode{type: :callback}), do: "-callback"
def format_spec_attribute(%ExDoc.FunctionNode{}), do: "-spec"

## Shared between Erlang & Elixir

@doc false
Expand Down
6 changes: 4 additions & 2 deletions test/ex_doc/formatter/html/erlang_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ defmodule ExDoc.Formatter.HTML.ErlangTest do

doc = generate_docs(c)

assert [_] = Floki.find(doc, "pre:fl-contains('foo(atom()) -> atom().')")
assert "-spec foo(atom()) -> atom()." =
doc |> Floki.find("pre:fl-contains('foo(atom())')") |> Floki.text()

assert [_] = Floki.find(doc, "pre:fl-contains('t() :: atom().')")
assert "-type t() :: atom()." =
doc |> Floki.find("pre:fl-contains('t() :: atom().')") |> Floki.text()
end

defp generate_docs(c) do
Expand Down
6 changes: 5 additions & 1 deletion test/ex_doc/formatter/html/templates_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -418,7 +418,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
integer = ~s[<a href="https://hexdocs.pm/elixir/typespecs.html#basic-types">integer</a>()]

public_html =
~S[public(t) :: {t, ] <>
~S[<span class="attribute">@type</span> public(t) :: {t, ] <>
~s[<a href="https://hexdocs.pm/elixir/String.html#t:t/0">String.t</a>(), ] <>
~S[<a href="TypesAndSpecs.Sub.html#t:t/0">TypesAndSpecs.Sub.t</a>(), ] <>
~S[<a href="#t:opaque/0">opaque</a>(), :ok | :error}]
Expand All @@ -428,13 +428,15 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do
assert content =~ public_html
refute content =~ ~s[<strong>private\(t\)]
assert content =~ ~s[A public type]
assert content =~ ~s[<span class="attribute">@spec</span> add(]
assert content =~ ~s[add(#{integer}, <a href="#t:opaque/0">opaque</a>()) :: #{integer}]
refute content =~ ~s[minus(#{integer}, #{integer}) :: #{integer}]

assert content =~
~s[Basic type: <a href=\"https://hexdocs.pm/elixir/typespecs.html#basic-types\"><code class=\"inline\">atom/0</code></a>.]

assert content =~ ~r{opaque/0.*<span class="note">\(opaque\)</span>}ms
assert content =~ ~r{<span class="attribute">@opaque</span> opaque}
end

test "outputs summaries" do
Expand Down Expand Up @@ -482,6 +484,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do

assert content =~ ~r{Callbacks}
assert content =~ ~r{<section class="detail" id="c:hello/1">}
assert content =~ ~s[<span class="attribute">@callback</span> hello(]
assert content =~ ~s[hello(%URI{})]
assert content =~ ~s[greet(arg1)]

Expand All @@ -492,6 +495,7 @@ defmodule ExDoc.Formatter.HTML.TemplatesTest do

assert content =~ ~r{Callbacks}
assert content =~ ~r{<section class="detail" id="c:bye/1">}
assert content =~ ~s[<span class="attribute">@macrocallback</span> bye(]
end

## PROTOCOLS
Expand Down
1 change: 1 addition & 0 deletions test/ex_doc/retriever/erlang_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ defmodule ExDoc.Retriever.ErlangTest do
function_groups: [:Callbacks, :Functions],
group: nil,
id: "mod",
language: ExDoc.Language.Erlang,
module: :mod,
nested_context: nil,
nested_title: nil,
Expand Down

0 comments on commit 28ff9a3

Please sign in to comment.