Skip to content

Commit b5384ef

Browse files
authored
Add support for nominal types (#1963)
This PR adds support for `-nominal` to be used in the same way as `-type`. Without this change, OTP's CI can't build documentation for nominal types.
1 parent 1a5a3c9 commit b5384ef

File tree

6 files changed

+37
-8
lines changed

6 files changed

+37
-8
lines changed

lib/ex_doc/language.ex

+2-2
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ defmodule ExDoc.Language do
110110
111111
The map has the following keys:
112112
113-
* `:type` - `:type` or `:opaque`
113+
* `:type` - `:type` or `:opaque` or `:nominal`
114114
115115
* `:source_line` - the line where the code is located
116116
@@ -122,7 +122,7 @@ defmodule ExDoc.Language do
122122
"""
123123
@callback type_data(entry :: tuple(), spec :: term()) ::
124124
%{
125-
type: :type | :opaque,
125+
type: :type | :opaque | :nominal,
126126
source_line: non_neg_integer(),
127127
source_file: String.t() | nil,
128128
signature: [binary()],

lib/ex_doc/language/source.ex

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,13 +53,13 @@ defmodule ExDoc.Language.Source do
5353
end)
5454
|> Map.new()
5555

56-
# Expand records in all specs, callbacks, types and opaques
56+
# Expand records in all specs, callbacks, types, opaques and nominals
5757
filtermap_ast(abst_code, nil, fn
5858
{:attribute, anno, kind, {mfa, ast}} when kind in [:spec, :callback] ->
5959
ast = Enum.map(ast, &expand_records(&1, records))
6060
{:attribute, anno, kind, {mfa, ast}}
6161

62-
{:attribute, anno, type, {name, ast, args}} when type in [:opaque, :type] ->
62+
{:attribute, anno, type, {name, ast, args}} when type in [:opaque, :nominal, :type] ->
6363
{:attribute, anno, type, {name, expand_records(ast, records), args}}
6464

6565
otherwise ->
@@ -194,7 +194,7 @@ defmodule ExDoc.Language.Source do
194194
def fetch_type!(module_data, name, arity) do
195195
find_ast(module_data.private.abst_code, module_data.source_basedir, fn
196196
{:attribute, anno, type, {^name, _, args} = spec} = attr ->
197-
if type in [:opaque, :type] and length(args) == arity do
197+
if type in [:nominal, :opaque, :type] and length(args) == arity do
198198
%{
199199
type: type,
200200
spec: spec,

lib/ex_doc/refs.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ defmodule ExDoc.Refs do
106106
[{{:module, module}, :limited}] ++
107107
to_refs(exports(module), module, :function) ++
108108
to_refs(callbacks(module), module, :callback) ++
109-
to_refs(types(module, [:type, :opaque]), module, :type)
109+
to_refs(types(module, [:type, :opaque, :nominal]), module, :type)
110110
else
111111
_ ->
112112
[{{:module, module}, :undefined}]

lib/ex_doc/retriever.ex

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ defmodule ExDoc.Retriever do
138138
groups_for_docs =
139139
config.groups_for_docs ++
140140
[
141-
Types: &(&1[:kind] in [:type, :opaque]),
141+
Types: &(&1[:kind] in [:type, :opaque, :nominal]),
142142
Callbacks: &(&1[:kind] in [:callback, :macrocallback]),
143143
Functions: fn _ -> true end
144144
]

test/ex_doc/language/erlang_test.exs

+5
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,11 @@ defmodule ExDoc.Language.ErlangTest do
728728
~s|foo(X, Y)|
729729
end
730730

731+
test "nominal", c do
732+
assert autolink_spec("-nominal foo() :: t().", c) ==
733+
~s|foo() :: <a href="#t:t/0">t</a>().|
734+
end
735+
731736
test "tuple", c do
732737
assert autolink_spec(~S"-spec foo() -> {ok, t()}.", c) ==
733738
~s|foo() -> {ok, <a href="#t:t/0">t</a>()}.|

test/ex_doc/retriever/erlang_test.exs

+25-1
Original file line numberDiff line numberDiff line change
@@ -286,11 +286,14 @@ defmodule ExDoc.Retriever.ErlangTest do
286286
287287
-doc("opaque1/0 docs.").
288288
-opaque opaque1() :: atom().
289+
290+
-doc("nominal1/0 docs.").
291+
-nominal nominal1() :: atom().
289292
""")
290293

291294
config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"}
292295
{[mod], []} = Retriever.docs_from_modules([:mod], config)
293-
[equiv_type1, opaque1, type1] = mod.typespecs
296+
[equiv_type1, opaque1, nominal1, type1] = mod.typespecs
294297

295298
assert opaque1.id == "t:opaque1/0"
296299
assert opaque1.type == :opaque
@@ -301,6 +304,15 @@ defmodule ExDoc.Retriever.ErlangTest do
301304
assert opaque1.spec |> Erlang.autolink_spec(current_kfa: {:type, :opaque1, 0}) ==
302305
"opaque1()"
303306

307+
assert nominal1.id == "t:nominal1/0"
308+
assert nominal1.type == :nominal
309+
assert nominal1.group == :Types
310+
assert nominal1.signature == "nominal1()"
311+
assert nominal1.doc |> DocAST.to_string() =~ "nominal1/0 docs."
312+
313+
assert nominal1.spec |> Erlang.autolink_spec(current_kfa: {:type, :nominal1, 0}) ==
314+
"nominal1() :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:atom/0\">atom</a>()."
315+
304316
assert type1.id == "t:type1/0"
305317
assert type1.type == :type
306318
assert type1.group == :Types
@@ -484,6 +496,9 @@ defmodule ExDoc.Retriever.ErlangTest do
484496
485497
-opaque opaque1() :: atom().
486498
%% opaque1/0 docs.
499+
500+
-nominal nominal1() :: atom().
501+
%% -doc("nominal1/0 docs.").
487502
""")
488503

489504
config = %ExDoc.Config{source_url_pattern: "%{path}:%{line}"}
@@ -498,6 +513,15 @@ defmodule ExDoc.Retriever.ErlangTest do
498513
assert opaque1.spec |> Erlang.autolink_spec(current_kfa: {:type, :opaque1, 0}) ==
499514
"opaque1()"
500515

516+
assert nominal1.id == "t:nominal1/0"
517+
assert nominal1.type == :nominal
518+
assert nominal1.group == :Types
519+
assert nominal1.signature == "nominal1/0"
520+
assert nominal1.doc |> DocAST.to_string() =~ "nominal1/0 docs."
521+
522+
assert nominal1.spec |> Erlang.autolink_spec(current_kfa: {:type, :nominal1, 0}) ==
523+
"nominal1() :: <a href=\"https://www.erlang.org/doc/apps/erts/erlang.html#t:atom/0\">atom</a>()."
524+
501525
assert type1.id == "t:type1/0"
502526
assert type1.type == :type
503527
assert type1.signature == "type1/0"

0 commit comments

Comments
 (0)