Review URL-synchronized issue search

src/issue-search-state.tsTypeScript
@@ -0,0 +1,33 @@
1+export type IssueStatus = "open" | "closed" | "all";
2+
3+export interface IssueSearchState {
4+ query: string;
5+ status: IssueStatus;
6+ page: number;
7+}
8+
9+function readPage(value: string | null): number {
10+ const page = Number(value);
11+ return Number.isInteger(page) && page > 0 ? page : 1;
12+}
13+
14+function readStatus(value: string | null): IssueStatus {
15+ return value === "closed" || value === "all" ? value : "open";
16+}
17+
18+export function readIssueSearchState(url: URL): IssueSearchState {
19+ return {
20+ query: url.searchParams.get("q") ?? "",
21+ status: readStatus(url.searchParams.get("status")),
22+ page: readPage(url.searchParams.get("page")),
23+ };
24+}
25+
26+export function buildIssueSearchUrl(baseUrl: URL, state: IssueSearchState): string {
27+ const search = new URLSearchParams();
28+ if (state.query) search.set("q", state.query);
29+ search.set("status", state.status);
30+ search.set("page", String(state.page));
31+
32+ return `${baseUrl.pathname}?${search.toString()}`;
33+}