aboutsummaryrefslogtreecommitdiff
path: root/src/scraper.ts
diff options
context:
space:
mode:
authorJoe Mou <dev@mou.fo>2026-09-21 22:15:24 -0400
committerJoe Mou <dev@mou.fo>2026-09-25 01:43:53 -0400
commit1514865ec8911c26612e68048f84c6c8be92449d (patch)
tree07a24c2b0536e4fd3b69c1cbc2a424e9ee25aa8a /src/scraper.ts
parentfd1c054c3c10dceb1a8a355c74a0d9e9077aae19 (diff)
Show issue and pull request status and labels in their lists
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/scraper.ts')
-rw-r--r--src/scraper.ts74
1 files changed, 56 insertions, 18 deletions
diff --git a/src/scraper.ts b/src/scraper.ts
index 3670034..19b8318 100644
--- a/src/scraper.ts
+++ b/src/scraper.ts
@@ -50,9 +50,7 @@ interface IssueNode {
state: string;
labels?: {
edges: {
- node: {
- name: string;
- };
+ node: IssueLabelNode;
}[];
};
}
@@ -331,11 +329,20 @@ export interface GitHubBlob extends GitHubNav {
htmlContent: string | null;
}
+export interface IssueLabel {
+ name: string;
+ // GitHub's own hex color for the label, without a leading "#".
+ color: string;
+ description: string | null;
+}
+
interface Issue {
number: number;
title: string;
+ // OPEN or CLOSED for an issue; a pull request is also DRAFT or MERGED.
state: string;
createdAt: string;
+ labels: IssueLabel[];
numReplies?: number;
numPRs?: number;
}
@@ -350,13 +357,6 @@ export interface GitHubPulls extends GitHubCommon {
q?: string;
}
-export interface IssueLabel {
- name: string;
- // GitHub's own hex color for the label, without a leading "#".
- color: string;
- description: string | null;
-}
-
export interface IssueComment {
// What GitHub's permalinks point at, e.g. "issuecomment-3090316111".
anchor: string;
@@ -772,6 +772,35 @@ export async function getGitHubRaw(
return response;
}
+function parseIssueLabel(label: IssueLabelNode): IssueLabel {
+ return { name: label.name, color: label.color, description: label.description ?? null };
+}
+
+// A label in a list row wears its color as the RGB channels GitHub's own CSS
+// mixes with, rather than as the hex its issue payloads carry, and keeps its
+// description in a tooltip pointing back at it.
+function parseRowLabel(label: Element, row: Element): IssueLabel {
+ const style = getAttributeValue(label, "style") ?? "";
+ const channels: number[] = [];
+ for (const channel of ["r", "g", "b"]) {
+ const value = new RegExp(`--label-${channel}:\\s*(\\d+)`).exec(style);
+ if (value) channels.push(parseInt(value[1], 10));
+ }
+
+ const id = getAttributeValue(label, "id");
+ const tooltip = id ? cssSelect.selectOne(`tool-tip[for="${id}"]`, row) : null;
+
+ return {
+ name: getAttributeValue(label, "data-name") ?? textContent(label).trim(),
+ // GitHub's own default gray, for a label whose color it did not spell out.
+ color:
+ channels.length === 3
+ ? channels.map((c) => c.toString(16).padStart(2, "0")).join("")
+ : "ededed",
+ description: tooltip ? textContent(tooltip).trim() || null : null,
+ };
+}
+
export async function getGitHubIssues(
owner: string,
repo: string,
@@ -793,9 +822,15 @@ export async function getGitHubIssues(
}
const issues: Issue[] = issuesQuery.result.data.repository.search.edges.map((edge) => {
- const { number, title, titleHtml, state, createdAt } = edge.node;
+ const { number, title, titleHtml, state, createdAt, labels } = edge.node;
const finalTitle = (title || titleHtml || "").replace(/<[^>]+>/g, "");
- return { number, title: finalTitle, state, createdAt };
+ return {
+ number,
+ title: finalTitle,
+ state,
+ createdAt,
+ labels: (labels?.edges ?? []).map((label) => parseIssueLabel(label.node)),
+ };
});
return { repo: { owner, name: repo }, issues, q };
@@ -814,10 +849,6 @@ function issueAssociation(association: string | undefined): string | null {
return words.charAt(0).toUpperCase() + words.slice(1);
}
-function parseIssueLabel(label: IssueLabelNode): IssueLabel {
- return { name: label.name, color: label.color, description: label.description ?? null };
-}
-
function parseIssueComment(node: IssueTimelineNode): IssueComment {
return {
anchor: node.url?.split("#")[1] ?? "",
@@ -1008,9 +1039,16 @@ export async function getGitHubPulls(
? "MERGED"
: ariaLabel.includes("Closed")
? "CLOSED"
- : "OPEN";
+ : ariaLabel.includes("Draft")
+ ? "DRAFT"
+ : "OPEN";
+
+ const labels: IssueLabel[] = [];
+ for (const label of cssSelect.selectAll("a.IssueLabel", row) as unknown as Element[]) {
+ labels.push(parseRowLabel(label, row));
+ }
- pulls.push({ number, title, state, createdAt });
+ pulls.push({ number, title, state, createdAt, labels });
}
return { repo: { owner, name: repo }, pulls, q };