website
git clone https://git.pyrossh.dev/website
木 Personal website of pyrossh. Built with astrojs, shiki, vite.
54662a2
— pyrossh
2026-11-05T19:45:56+05:30
Omit lockfile and generated diffs from commit pages
- src/_data/repoCommits.js +40 -4
- tests/pages.test.js +10 -0
src/_data/repoCommits.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import path from "node:path";
|
|
1
2
|
import { html as renderDiffHtml, parse as parseDiff } from "diff2html";
|
|
2
3
|
import { readCache, writeCache } from "../_helpers/dataCache.js";
|
|
3
4
|
import { discoverLocalRepos, getCommitDiff, getHeadSha } from "../_helpers/gitRepos.js";
|
|
@@ -16,14 +17,49 @@ const CONCURRENCY = 8;
|
|
|
16
17
|
const MAX_DIFF_SIZE = 300 * 1024;
|
|
17
18
|
const DIFF_TOO_LARGE_HTML = '<p class="diff-too-large">This diff is too large to display.</p>';
|
|
18
19
|
|
|
20
|
+
// Machine-written files nobody reads as a diff. Dropped before the size check
|
|
21
|
+
// so a big lockfile change can't hide the hand-written changes beside it.
|
|
22
|
+
const LOCKFILES = new Set([
|
|
23
|
+
"bun.lock",
|
|
24
|
+
"bun.lockb",
|
|
25
|
+
"Cargo.lock",
|
|
26
|
+
"Gemfile.lock",
|
|
27
|
+
"go.sum",
|
|
28
|
+
"package-lock.json",
|
|
29
|
+
"pnpm-lock.yaml",
|
|
30
|
+
"Podfile.lock",
|
|
31
|
+
"pubspec.lock",
|
|
32
|
+
"uv.lock",
|
|
33
|
+
"yarn.lock",
|
|
34
|
+
]);
|
|
35
|
+
// plum's tree-sitter output.
|
|
36
|
+
const isGeneratedFile = (filePath) => filePath === "src/parser.c" || LOCKFILES.has(path.basename(filePath));
|
|
37
|
+
|
|
38
|
+
const escapeHtml = (text) => text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
39
|
+
|
|
40
|
+
const omitGeneratedFiles = (patch) => {
|
|
41
|
+
const kept = [];
|
|
42
|
+
const omitted = [];
|
|
43
|
+
for (const section of patch.split(/^(?=diff --git )/m)) {
|
|
44
|
+
const filePath = section.match(/^diff --git a\/.+ b\/(.+)$/m)?.[1];
|
|
45
|
+
if (filePath && isGeneratedFile(filePath)) omitted.push(filePath);
|
|
46
|
+
else kept.push(section);
|
|
47
|
+
}
|
|
48
|
+
return { patch: kept.join(""), omitted };
|
|
49
|
+
};
|
|
50
|
+
|
|
19
51
|
const toDiffHtml = (diffText) => {
|
|
20
52
|
const idx = diffText.indexOf("diff --git");
|
|
53
|
+
if (idx < 0) return "";
|
|
21
|
-
const patch
|
|
54
|
+
const { patch, omitted } = omitGeneratedFiles(diffText.slice(idx));
|
|
55
|
+
const note = omitted.length
|
|
56
|
+
? `<p class="diff-omitted">Generated files not shown: ${omitted.map(escapeHtml).join(", ")}</p>`
|
|
57
|
+
: "";
|
|
22
|
-
if (!patch.trim()) return
|
|
58
|
+
if (!patch.trim()) return note;
|
|
23
|
-
if (patch.length > MAX_DIFF_SIZE) return DIFF_TOO_LARGE_HTML;
|
|
59
|
+
if (patch.length > MAX_DIFF_SIZE) return note + DIFF_TOO_LARGE_HTML;
|
|
24
60
|
try {
|
|
25
61
|
const json = parseDiff(patch);
|
|
26
|
-
return renderDiffHtml(json, { drawFileList: true, matching: "lines" });
|
|
62
|
+
return note + renderDiffHtml(json, { drawFileList: true, matching: "lines" });
|
|
27
63
|
} catch {
|
|
28
64
|
return "";
|
|
29
65
|
}
|
tests/pages.test.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { after, before, describe, test } from "node:test";
|
|
2
2
|
import assert from "node:assert/strict";
|
|
3
|
+
import { execFileSync } from "node:child_process";
|
|
3
4
|
import path from "node:path";
|
|
4
5
|
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { chromium } from "playwright";
|
|
@@ -180,6 +181,15 @@ describe("repo pages", () => {
|
|
|
180
181
|
assert.equal(await page.locator(".nav a.active-tab").textContent(), "Commits");
|
|
181
182
|
});
|
|
182
183
|
|
|
184
|
+
test("commit pages name lockfiles instead of rendering their diffs", async () => {
|
|
185
|
+
const hash = execFileSync("git", ["log", "-1", "--diff-filter=M", "--format=%H", "--", "package-lock.json"], {
|
|
186
|
+
encoding: "utf8",
|
|
187
|
+
}).trim();
|
|
188
|
+
await goto(`/repos/${repoId}/commits/${hash}/`);
|
|
189
|
+
assert.match(await page.locator(".diff-omitted").textContent(), /package-lock\.json/);
|
|
190
|
+
assert.equal(await page.locator(".d2h-file-name", { hasText: "package-lock.json" }).count(), 0);
|
|
191
|
+
});
|
|
192
|
+
|
|
183
193
|
test("repo files index renders the tree and a default file", async () => {
|
|
184
194
|
const response = await goto(`/repos/${repoId}/files/`);
|
|
185
195
|
assert.equal(response.status(), 200);
|