-- changelog-ids Soupault Plugin -- SPDX-FileCopyrightText: 2026 toastal -- SPDX-License-Identifier: MPL-2.0 -- -- Gives each CHANGELOG version entry a shareable fragment id: h2s whose -- text starts with X.Y.Z (e.g. “2.1.0 (2026-10-02)”) get id="X.Y.Z". -- Docutils only emits meaningless section-1/section-2 ids, which are left -- alone. Runs on /changelog/ only; non-version h2s are untouched, and -- h2s that already carry an id keep it. Plugin.require_version("5.0.0") function url_path() local url = page_url url = Regex.replace(url, "^[a-z]+://[^/]+", "") if url == "" then url = "/" elseif not String.starts_with(url, "/") then url = "/" .. url end return url end path = url_path() if path == "/changelog" or path == "/changelog/" then headings = HTML.select(page, "section#Content > section > h2") if Table.is_empty(headings) then Log.warning(format("No version sections found in “%s”", page_file)) end seen = {} local idx = 1 while headings[idx] do local h2 = headings[idx] text = String.trim(HTML.strip_tags(h2)) if not Value.is_nil(Regex.match(text, "^[0-9]+\\.[0-9]+\\.[0-9]+")) then chunks = Regex.split(text, " ") version = chunks[1] if not Value.is_nil(seen[version]) then Log.warning(format("Duplicate CHANGELOG version “%s”, keeping first id", version)) else seen[version] = 1 existing = HTML.get_attribute(h2, "id") if Value.is_string(existing) and existing ~= "" then Log.warning(format("CHANGELOG h2 already has id “%s”, keeping it", existing)) else HTML.set_attribute(h2, "id", version) end end end idx = idx + 1 end end