firehose/blogex/lib/blogex/link_error.ex
Firehose Bot ab7a520e9e Add compile-time link validation for blog post internal links
- Add Blogex.LinkValidator module to validate /blog/{id}/{slug} semantics
- Add Blogex.LinkError exception with actionable error messages
- Integrate validation into Blogex.Blog via @before_compile callback
- Add unit tests (34) and integration tests (4) for link validation
- Add test fixtures (valid/invalid posts) in blogex/priv/blog/test/

Closes: validate-internal-link-semantics-in-blog-post-markdown-bodies-at-compile-time-h3hb
Closes: define-link-semantic-validation-logic-in-blogex-7syv
Closes: write-tests-for-link-semantic-validation-y30h
Closes: integrate-link-validation-into-blogexblog-compile-time-macro-1205
2026-05-07 11:56:54 +01:00

54 lines
1.3 KiB
Elixir

defmodule Blogex.LinkError do
@moduledoc """
Exception raised when a blog post contains invalid internal links.
Raised at compile time by `Blogex.Blog` when `LinkValidator` finds
semantic errors in post body links.
## Fields
* `:blog` — the blog identifier atom (e.g., `:engineering`)
* `:post_id` — the post slug/id that contains the invalid link
* `:errors` — list of `{line, link, reason, post_id}` tuples
## Example
raise Blogex.LinkError,
blog: :engineering,
post_id: "my-post",
errors: [
{1, "/blog/unknown/broken", "unknown blog ID: unknown", post_id: "my-post"}
]
"""
defexception blog: nil, post_id: nil, errors: []
@type t :: %__MODULE__{
blog: atom(),
post_id: String.t() | nil,
errors: [{integer(), String.t(), String.t(), keyword()}]
}
@impl true
def message(%__MODULE__{blog: blog, post_id: post_id, errors: errors}) do
post_label =
case post_id do
nil -> ""
id -> " (post: #{id})"
end
errors_list =
errors
|> Enum.map(fn {line, link, reason, _meta} ->
" line #{line}: #{link}#{reason}"
end)
|> Enum.join("\n")
"""
invalid internal blog links in #{blog}#{post_label}
#{errors_list}
"""
end
end