module

Hwaro::Utils::PermalinkResolver

Constants

DATE_TOKEN_HINT = "Add a date to the page's front matter, set an explicit `path`, or remove date tokens from the pattern."
EMBEDDED_VALID_TOKEN = Regex.new(":(?:#{VALID_TOKENS.join("|")})\\b")

A KNOWN token buried inside a larger segment (post-:slug). Matched anywhere because such a segment is not expandable — see validate_pattern! — and both callers below have to see it in order to reject it.

Restricted to VALID_TOKENS, and closed with \b, because a colon is perfectly legal inside a URL path segment: a plain directory remap like "notes" = "/wiki/pros:cons/" (or /docs/faq:slugs/) contains no hwaro token at all, and matching any :identifier here made the compound-segment check fire on it and abort the build with a config error on config that published fine.

TOKEN_ANYWHERE = /\A:[A-Za-z_][A-Za-z0-9_]*/

A segment that OPENS with :name — the shape an author writes when they mean a token, whether or not the name is spelled correctly. This is what keeps /:tokne/ a reportable typo instead of a directory literally named :tokne. The name must start with a letter or _ so an ordinary directory target that happens to contain a colon before a digit (2024:2025) stays a plain remap.

VALID_TOKENS = ["year", "month", "day", "slug", "title", "section", "filename"] of ::String

Tokens accepted inside a [permalinks] pattern value. Each token must be a whole /-separated segment (e.g. /:year/:slug/).

WHOLE_SEGMENT_TOKEN = /\A:[A-Za-z_][A-Za-z0-9_]*\z/

The only shape expand_pattern can actually substitute: a segment that is nothing but one token.

Instance methods

pattern?(target : String) : Bool

True when the [permalinks] target contains a :token, i.e. it is a Hugo-style pattern rather than a directory remap.

Source
resolve_url(relative_path : String, config : Models::Config | Nil, *, slug : String | Nil, custom_path : String | Nil, language : String | Nil, date : Time | Nil, title : String, version : Models::VersionConfig | Nil = nil) : String

Compute the canonical site-relative URL for a content file.

Precedence: explicit path front matter (custom_path) wins outright; otherwise the language prefix for non-default languages is emitted BEFORE the pattern/remap output (/ko/2026/03/05/…), then the first matching [permalinks] rule applies (pattern expansion for leaf pages, directory remap otherwise), and the result is normalized to a leading- and trailing-slash directory URL.

A date-token pattern on a dateless page raises HWARO_E_CONTENT. Callers that can't yet know whether the page will publish (the parse fan-out runs before cascades and draft/expiry filtering) use resolve_url_lenient and defer the error to after filtering.

Source
resolve_url_lenient(relative_path : String, config : Models::Config | Nil, *, slug : String | Nil, custom_path : String | Nil, language : String | Nil, date : Time | Nil, title : String, version : Models::VersionConfig | Nil = nil) : Tuple(String, String | Nil)

Like resolve_url, but a date-token pattern on a dateless page falls back to the default directory URL and REPORTS the problem in the second tuple slot instead of raising — so a draft or headless page the build is about to discard can't abort the whole build over a URL it never publishes.

Source
validate_pattern!(rule_key : String, target : String) : Nil

Validate every :token in a pattern against VALID_TOKENS, and require each one to be a whole /-separated segment. Raises a classified config error so hwaro build exits with the stable config exit code instead of silently emitting literal :tokne path segments.

Source