Skip to content

Commit 9771c14

Browse files
authored
Correctly link otp apps not in deps to erlang.org (#1861)
1 parent 9e3f220 commit 9771c14

File tree

2 files changed

+63
-39
lines changed

2 files changed

+63
-39
lines changed

lib/ex_doc/autolink.ex

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ defmodule ExDoc.Autolink do
6262

6363
@hexdocs "https://hexdocs.pm/"
6464
@otpdocs "https://www.erlang.org/doc/man/"
65+
@otpappdocs "https://www.erlang.org/doc/apps/"
6566

6667
def app_module_url(tool, module, anchor \\ nil, config)
6768

@@ -121,50 +122,45 @@ defmodule ExDoc.Autolink do
121122
end
122123

123124
defp app(module) do
124-
{_, app} = app_info(module)
125-
app
125+
case :code.which(module) do
126+
:preloaded ->
127+
:erts
128+
129+
maybe_path ->
130+
case :application.get_application(module) do
131+
{:ok, app} ->
132+
app
133+
134+
_ ->
135+
with true <- is_list(maybe_path),
136+
[_, "ebin", app, "lib" | _] <- maybe_path |> Path.split() |> Enum.reverse() do
137+
String.split(app, "-") |> hd() |> String.to_atom()
138+
else
139+
_ -> nil
140+
end
141+
end
142+
end
126143
end
127144

128145
@doc false
129146
def tool(module, config) do
130147
if match?("Elixir." <> _, Atom.to_string(module)) do
131148
:ex_doc
132149
else
133-
{otp, app} = app_info(module)
150+
app = app(module)
134151
apps = Enum.uniq(config.apps ++ Keyword.keys(config.deps))
135152

136-
if otp == true and app not in apps do
153+
if is_app_otp(app) and app not in apps do
137154
:otp
138155
else
139156
:ex_doc
140157
end
141158
end
142159
end
143160

144-
defp app_info(module) do
145-
case :code.which(module) do
146-
:preloaded ->
147-
{true, :erts}
148-
149-
maybe_path ->
150-
otp? = is_list(maybe_path) and List.starts_with?(maybe_path, :code.lib_dir())
151-
152-
app =
153-
case :application.get_application(module) do
154-
{:ok, app} ->
155-
app
156-
157-
_ ->
158-
with true <- is_list(maybe_path),
159-
[_, "ebin", app, "lib" | _] <- maybe_path |> Path.split() |> Enum.reverse() do
160-
String.split(app, "-") |> Enum.at(0) |> String.to_atom()
161-
else
162-
_ -> nil
163-
end
164-
end
165-
166-
{otp?, app}
167-
end
161+
defp is_app_otp(app) do
162+
maybe_lib_dir_path = :code.lib_dir(app)
163+
is_list(maybe_lib_dir_path) and List.starts_with?(maybe_lib_dir_path, :code.root_dir())
168164
end
169165

170166
def maybe_warn(config, ref, visibility, metadata) do
@@ -302,16 +298,27 @@ defmodule ExDoc.Autolink do
302298
{extra, "#" <> anchor}
303299
end
304300

301+
app = String.to_atom(app)
302+
305303
config.deps
306-
|> Keyword.get_lazy(String.to_atom(app), fn ->
307-
maybe_warn(
308-
config,
309-
"documentation references \"e:#{string}\" but #{app} cannot be found in deps.",
310-
nil,
311-
%{}
312-
)
313-
314-
@hexdocs <> "#{app}"
304+
|> Keyword.get_lazy(app, fn ->
305+
if Application.ensure_loaded(app) != :ok do
306+
maybe_warn(
307+
config,
308+
"documentation references \"e:#{string}\" but #{app} cannot be found.",
309+
nil,
310+
%{}
311+
)
312+
end
313+
314+
prefix =
315+
cond do
316+
app in config.apps -> ""
317+
is_app_otp(app) -> @otpappdocs
318+
true -> @hexdocs
319+
end
320+
321+
prefix <> "#{app}"
315322
end)
316323
|> String.trim_trailing("/")
317324
|> Kernel.<>("/" <> convert_extra_extension(extra, config) <> anchor)

test/ex_doc/language/erlang_test.exs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,23 @@ defmodule ExDoc.Language.ErlangTest do
399399
~s|<a href="https://foolib.com/extra.xhtml">extra</a>|
400400
end
401401

402+
test "linking to extra otp docs works", c do
403+
assert autolink_doc(
404+
"[Unicode usage](`e:stdlib:unicode_usage.md`)",
405+
c
406+
) ==
407+
~s|<a href="https://www.erlang.org/doc/apps/stdlib/unicode_usage.html">Unicode usage</a>|
408+
end
409+
410+
test "linking to extra umbrella docs works", c do
411+
assert autolink_doc(
412+
"[Unicode usage](`e:stdlib:unicode_usage.md`)",
413+
c,
414+
apps: [:stdlib]
415+
) ==
416+
~s|<a href="stdlib/unicode_usage.html">Unicode usage</a>|
417+
end
418+
402419
test "anchor", c do
403420
assert autolink_doc("[Foo](#baz)", c) ==
404421
~s|<a href="#baz">Foo</a>|
@@ -485,7 +502,7 @@ defmodule ExDoc.Language.ErlangTest do
485502
end,
486503
line: nil
487504
) =~
488-
~r/documentation references "e:barlib:extra.md" but barlib cannot be found in deps/
505+
~r/documentation references "e:barlib:extra.md" but barlib cannot be found/
489506
end
490507

491508
test "linking to unknown application with anchor does not work", c do
@@ -496,7 +513,7 @@ defmodule ExDoc.Language.ErlangTest do
496513
end,
497514
line: nil
498515
) =~
499-
~r/documentation references "e:barlib:extra.md#anchor" but barlib cannot be found in deps/
516+
~r/documentation references "e:barlib:extra.md#anchor" but barlib cannot be found/
500517
end
501518

502519
test "filtered module", c do

0 commit comments

Comments
 (0)