docs(changelog): link problems using short redirects instead of issue URLs

This commit is contained in:
Prad Nukala committed 2026-09-30 18:02:19 -04:00
1 parent 4b8496c113
commit fd57f53d34
2 files changed
+20 -14

No files matched your search

+9 -12
View File
@@ -12,7 +12,9 @@
* release-topics.ts's render() writes: `| #issue | LC n · Name | set | diff | * release-topics.ts's render() writes: `| #issue | LC n · Name | set | diff |
* closed | [py](…) · [docs](…) |`. Only `### Closed …` sections are read, so * closed | [py](…) · [docs](…) |`. Only `### Closed …` sections are read, so
* a release published before open problems were dropped from the body still * a release published before open problems were dropped from the body still
* shows only what finished. * shows only what finished. The row's own `[docs]` link is not used: it is
* frozen at release time (a problem solved before the docs existed has
* none), while the page links each problem by its LC number to its page now.
* *
* Auth: GITHUB_TOKEN when set (deploy.yml passes it), else unauthenticated — * Auth: GITHUB_TOKEN when set (deploy.yml passes it), else unauthenticated —
* one request per 100 releases fits the anonymous limit. A failed request * one request per 100 releases fits the anonymous limit. A failed request
@@ -26,13 +28,13 @@ const KIND = /^(Topic|Review) \d+ — /u;
export interface ReleaseProblem { export interface ReleaseProblem {
issue: number; issue: number;
/** The LeetCode number, the key of the docs `/<num>` short links. */
lc: number;
/** `LC 57 · Insert Interval`. */ /** `LC 57 · Insert Interval`. */
title: string; title: string;
set: string; set: string;
/** `easy` / `medium` / `hard`, the problem's `diff:*` label. */ /** `easy` / `medium` / `hard`, the problem's `diff:*` label. */
difficulty: string; difficulty: string;
/** The problem's `/<num>` docs short link, once it has a page. */
docs?: string;
} }
export interface Release { export interface Release {
@@ -53,15 +55,10 @@ function closedProblems(body: string): ReleaseProblem[] {
for (const line of body.split("\n")) { for (const line of body.split("\n")) {
if (line.startsWith("### ")) closed = line.startsWith("### Closed"); if (line.startsWith("### ")) closed = line.startsWith("### Closed");
if (!closed || !line.startsWith("| #")) continue; if (!closed || !line.startsWith("| #")) continue;
const [issue, title, set, difficulty, , solution] = line.slice(1, -1).split("|").map((cell) => cell.trim()); const [issue, title, set, difficulty] = line.slice(1, -1).split("|").map((cell) => cell.trim());
if (!issue || !title || !set || !difficulty) continue; const lc = title?.match(/^LC (\d+) · /u)?.[1];
problems.push({ if (!issue || !title || !lc || !set || !difficulty) continue;
issue: Number(issue.slice(1)), problems.push({ issue: Number(issue.slice(1)), lc: Number(lc), title, set, difficulty });
title,
set,
difficulty,
docs: solution?.match(/\[docs\]\(([^)]+)\)/u)?.[1],
});
} }
return problems; return problems;
} }
+11 -2
View File
@@ -8,6 +8,8 @@
*/ */
import PageLayout from "blume/components/layout/PageLayout.astro"; import PageLayout from "blume/components/layout/PageLayout.astro";
import data from "blume:data"; import data from "blume:data";
import { withBase } from "blume/components/islands/base-path.ts";
import redirects from "../redirects";
import { readReleases } from "../lib/releases.ts"; import { readReleases } from "../lib/releases.ts";
const { config } = data; const { config } = data;
@@ -19,6 +21,14 @@ const DATE = new Intl.DateTimeFormat("en-US", {
year: "numeric", year: "numeric",
}); });
const issueUrl = (n: number) => `https://github.com/prdlk/leetcode/issues/${n}`; const issueUrl = (n: number) => `https://github.com/prdlk/leetcode/issues/${n}`;
// LC number -> its docs page route, off sync's `/<num>` short links — the
// page itself, not the redirect, so a click is one hop. A problem with no page
// (none yet) links to its issue instead.
const pages = new Map(redirects.map((r) => [Number(r.from.slice(1)), r.to]));
const problemHref = (lc: number, issue: number) => {
const route = pages.get(lc);
return route ? withBase(route) : issueUrl(issue);
};
// The /progress cards' difficulty palette (--chart-1..3 in theme.css), so a // The /progress cards' difficulty palette (--chart-1..3 in theme.css), so a
// Hard reads the same colour here as in the SolvedRing gauge. // Hard reads the same colour here as in the SolvedRing gauge.
const DIFFICULTY: Record<string, { label: string; class: string }> = { const DIFFICULTY: Record<string, { label: string; class: string }> = {
@@ -84,8 +94,7 @@ const description = "Every topic and review the campaign finished, newest first.
<span class="select-none text-border" aria-hidden="true">—</span> <span class="select-none text-border" aria-hidden="true">—</span>
<span class="min-w-0"> <span class="min-w-0">
<span class="mr-2 font-mono text-xs uppercase tracking-wide">{p.set}</span> <span class="mr-2 font-mono text-xs uppercase tracking-wide">{p.set}</span>
{/* The problem's docs page; its issue only until it has one. */} <a class="text-foreground no-underline hover:underline" href={problemHref(p.lc, p.issue)}>
<a class="text-foreground no-underline hover:underline" href={p.docs ?? issueUrl(p.issue)}>
{p.title} {p.title}
</a> </a>
{DIFFICULTY[p.difficulty] && ( {DIFFICULTY[p.difficulty] && (