From 697b6e2ad4be267ea88e41e801e1f24e59d4b535 Mon Sep 17 00:00:00 2001 From: EnixCoda Date: Wed, 3 Dec 2025 22:02:15 +0800 Subject: [PATCH] feat: support GitHub new pull request files page --- .../GitHub/getPullRequestTreeData.ts | 88 ++++++++++++++++--- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/src/platforms/GitHub/getPullRequestTreeData.ts b/src/platforms/GitHub/getPullRequestTreeData.ts index 470882e..920a797 100644 --- a/src/platforms/GitHub/getPullRequestTreeData.ts +++ b/src/platforms/GitHub/getPullRequestTreeData.ts @@ -37,19 +37,8 @@ export async function getPullRequestTreeData( pullId, isInPullFilesPage() ? document : undefined, ) - // query all elements at once to make getFileElementHash run faster - const elementsHavePath = docs.map(doc => doc.querySelectorAll(`[data-path]`)) - const map = new Map() - for (const group of elementsHavePath) { - for (let i = 0; i < group.length; i++) { - const element = group[i] - const id = element.parentElement?.id - if (id) { - const path = element.getAttribute('data-path') - if (path) map.set(path, id) - } - } - } + + const fileHashMap = resolveFileHashMap(docs) const url = new URL(sanitizedLocation.href) url.pathname = `/${userName}/${repoName}/pull/${pullId}/files` @@ -65,7 +54,7 @@ export async function getPullRequestTreeData( raw_url: rawLink, blob_url: permalink, }) => { - url.hash = map.get(filename) || '' + url.hash = fileHashMap.get(filename) || '' return { path: filename || '', type: 'blob', @@ -93,6 +82,77 @@ const GITHUB_API_RESPONSE_LENGTH_LIMIT = 3000 const GITHUB_API_RESPONSE_MAX_SIZE_PER_PAGE = 100 const MAX_PAGE = Math.ceil(GITHUB_API_RESPONSE_LENGTH_LIMIT / GITHUB_API_RESPONSE_MAX_SIZE_PER_PAGE) +function resolveFileHashMap(docs: Document[]) { + const mapFromEmbeddedJSON = docs + .map( + doc => + doc.querySelector('script[data-target="react-app.embeddedData"]')?.textContent ?? + JSON.stringify({}), + ) + .map(element => { + try { + type PartialReactAppEmbeddedData = { + payload: { + pullRequestsFilesRoute: { + diffSummaries: [ + { + changeType: 'MODIFIED' + highestAnnotationLevel: null + isCodeowner: null + isManifestFile: boolean + isSymlink: boolean + isVendored: boolean + linesAdded: number + linesChanged: number + linesDeleted: number + markedAsViewed: boolean + path: string + pathDigest: string + }, + ] + } + } + } + return JSON.parse(element) as PartialReactAppEmbeddedData + } catch (error) { + return null + } + }) + .map(json => { + try { + return json?.payload.pullRequestsFilesRoute.diffSummaries + } catch (error) { + return null + } + }) + .reduce((map, curr) => { + curr?.forEach(({ path, pathDigest }) => { + map.set(path, 'diff-' + pathDigest) + }) + return map + }, new Map()) + + if (mapFromEmbeddedJSON.size > 0) { + return mapFromEmbeddedJSON + } + + // query all elements at once to make getFileElementHash run faster + const elementsHavePath = docs.map(doc => doc.querySelectorAll(`[data-path]`)) + const map = new Map() + for (const group of elementsHavePath) { + for (let i = 0; i < group.length; i++) { + const element = group[i] + const id = element.parentElement?.id + if (id) { + const path = element.getAttribute('data-path') + if (path) map.set(path, id) + } + } + } + + return map +} + async function safeGetPullRequestTreeData( { userName, repoName }: Pick, pullId: string,