@@ -52,7 +52,7 @@ defmodule ExDoc.Autolink do
5252 :language ,
5353 file: "nofile" ,
5454 apps: [ ] ,
55- extras: [ ] ,
55+ extras: % { } ,
5656 deps: [ ] ,
5757 ext: ".html" ,
5858 current_kfa: nil ,
@@ -214,20 +214,86 @@ defmodule ExDoc.Autolink do
214214 @ builtin_ext [ ".livemd" , ".cheatmd" , ".md" , ".txt" , "" ]
215215
216216 defp build_extra_link ( link , config ) do
217- with % { scheme: nil , host: nil , path: path } = uri <- URI . parse ( link ) ,
218- true <- is_binary ( path ) and path != "" and not ( path =~ ref_regex ( ) ) ,
219- true <- Path . extname ( path ) in @ builtin_ext do
220- if file = config . extras [ Path . basename ( path ) ] do
221- append_fragment ( file <> config . ext , uri . fragment )
222- else
217+ case extra_link_target ( link , config ) do
218+ { :ok , target , fragment } ->
219+ append_fragment ( target <> config . ext , fragment )
220+
221+ { :missing , path } ->
223222 maybe_warn ( config , nil , nil , % { file_path: path , original_text: link } )
224223 nil
225- end
224+
225+ :ignore ->
226+ nil
227+ end
228+ end
229+
230+ defp extra_link_target ( link , config ) do
231+ case parse_extra_link ( link ) do
232+ { :ok , path , fragment } ->
233+ extra_link_target ( path , fragment , config )
234+
235+ { :error , :invalid } ->
236+ :ignore
237+ end
238+ end
239+
240+ defp extra_link_target ( path , fragment , config ) do
241+ case resolve_extra_target ( path , config ) do
242+ nil -> { :missing , path }
243+ target -> { :ok , target , fragment }
244+ end
245+ end
246+
247+ defp parse_extra_link ( link ) do
248+ case URI . parse ( link ) do
249+ % { scheme: nil , host: nil , path: path , fragment: fragment } when is_binary ( path ) ->
250+ if valid_extra_link_path? ( path ) do
251+ { :ok , path , fragment }
252+ else
253+ { :error , :invalid }
254+ end
255+
256+ _ ->
257+ { :error , :invalid }
258+ end
259+ end
260+
261+ defp valid_extra_link_path? ( path ) do
262+ path != "" and not ( path =~ ref_regex ( ) ) and Path . extname ( path ) in @ builtin_ext
263+ end
264+
265+ defp resolve_extra_target ( path , config ) do
266+ if path_qualified_link? ( path ) do
267+ config . extras [ normalize_extra_link_path ( path , config . file ) ]
226268 else
227- _ -> nil
269+ config . extras [ Path . basename ( path ) ]
228270 end
229271 end
230272
273+ defp path_qualified_link? ( path ) , do: path != Path . basename ( path )
274+
275+ defp normalize_extra_link_path ( "/" <> path , _current_file ) do
276+ normalize_extra_link_path_from ( path , File . cwd! ( ) )
277+ end
278+
279+ defp normalize_extra_link_path ( path , current_file ) do
280+ normalize_extra_link_path_from ( path , extra_link_base_dir ( current_file ) )
281+ end
282+
283+ defp normalize_extra_link_path_from ( path , base_dir ) do
284+ path
285+ |> Path . expand ( base_dir )
286+ |> Path . relative_to ( File . cwd! ( ) )
287+ end
288+
289+ defp extra_link_base_dir ( file ) when is_binary ( file ) do
290+ file
291+ |> Path . expand ( File . cwd! ( ) )
292+ |> Path . dirname ( )
293+ end
294+
295+ defp extra_link_base_dir ( _ ) , do: File . cwd! ( )
296+
231297 defp maybe_remove_link ( nil , :custom_link ) do
232298 :remove_link
233299 end
0 commit comments