From 84185cb3eb99e0f6466931d695a4e22fd68d7048 Mon Sep 17 00:00:00 2001
From: Gustavo Madeira Santana
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
'); -const end = readme.indexOf("
", start); +const block = `${CLAWTRIBUTORS_START}\n${markdownLines.join("\n\n")}\n${CLAWTRIBUTORS_END}`; +const hiddenBlock = buildHiddenReadmeBlock(entries, visibleEntries); +const hiddenRange = findHiddenReadmeRange(currentReadme); +const readmeWithoutMeta = hiddenRange + ? `${currentReadme.slice(0, hiddenRange.start)}${currentReadme.slice(hiddenRange.end)}` + : currentReadme; +const range = findClawtributorsRange(readmeWithoutMeta); -if (start === -1 || end === -1) { +if (!range) { throw new Error("README.md missing clawtributors block"); } -const next = `${readme.slice(0, start)}\n${block}${readme.slice(end)}`;
+const next = `${readmeWithoutMeta.slice(0, range.start)}${block}\n${hiddenBlock}${readmeWithoutMeta.slice(range.end)}`;
writeFileSync(readmePath, next);
-console.log(`Updated README clawtributors: ${entries.length} entries`);
+console.log(
+ `Updated README clawtributors: ${visibleEntries.length} visible (${entries.length - visibleEntries.length} default-avatar entries hidden)`,
+);
console.log(`\nTop 25 by composite score: (commits*2 + PRs*10 + sqrt(LOC)) * tenure`);
console.log(` tenure = 1.0 + (days_since_first_commit / repo_age)^2 * 0.5`);
console.log(
`${"#".padStart(3)} ${"login".padEnd(24)} ${"score".padStart(8)} ${"tenure".padStart(7)} ${"commits".padStart(8)} ${"PRs".padStart(6)} ${"LOC".padStart(10)} first commit`,
);
console.log("-".repeat(85));
-for (const entry of entries.slice(0, 25)) {
+for (const [index, entry] of visibleEntries.slice(0, 25).entries()) {
const login = (entry.login ?? entry.key).slice(0, 24);
const fd = entry.firstCommitDate || "?";
const daysIn =
@@ -316,7 +331,7 @@ for (const entry of entries.slice(0, 25)) {
const tr = Math.min(1, daysIn / repoAgeDays);
const tenure = 1.0 + tr * tr * 0.5;
console.log(
- `${entries.indexOf(entry) + 1}`.padStart(3) +
+ `${index + 1}`.padStart(3) +
` ${login.padEnd(24)} ${entry.score.toFixed(0).padStart(8)} ${tenure.toFixed(2).padStart(6)}x ${String(entry.commits).padStart(8)} ${String(entry.prs).padStart(6)} ${String(entry.lines).padStart(10)} ${fd}`,
);
}
@@ -386,12 +401,15 @@ function normalizeAvatar(url: string): string {
if (!/^https?:/i.test(url)) {
return url;
}
- const lower = url.toLowerCase();
- if (lower.includes("s=") || lower.includes("size=")) {
+ try {
+ const parsed = new URL(url);
+ parsed.searchParams.delete("s");
+ parsed.searchParams.delete("size");
+ parsed.searchParams.set("s", String(AVATAR_SIZE));
+ return parsed.toString();
+ } catch {
return url;
}
- const sep = url.includes("?") ? "&" : "?";
- return `${url}${sep}s=48`;
}
function fetchUser(login: string): User | null {
@@ -418,6 +436,159 @@ function fetchUser(login: string): User | null {
}
}
+function isDefaultGitHubAvatar(login: string): Promise ');
- const end = content.indexOf(" ');
+ const legacyEnd = content.indexOf("]*alt="([^"]+)"[^>]*>/g;
for (const match of block.matchAll(linked)) {
const [, href, src, alt] = match;
@@ -535,6 +717,70 @@ function parseReadmeEntries(
return entries;
}
+function parseHiddenReadmeLogins(content: string): string[] {
+ const range = findHiddenReadmeRange(content);
+ if (!range) {
+ return [];
+ }
+ const block = content.slice(range.start, range.end);
+ return block
+ .split("\n")
+ .map((line) => normalizeLogin(line.trim())?.toLowerCase() ?? null)
+ .filter((login): login is string => Boolean(login));
+}
+
+function buildHiddenReadmeBlock(entries: Entry[], visibleEntries: Entry[]): string {
+ const visibleLogins = new Set(
+ visibleEntries
+ .map((entry) => normalizeLogin(entry.login ?? entry.key)?.toLowerCase() ?? null)
+ .filter((login): login is string => Boolean(login)),
+ );
+ const hiddenLogins = entries
+ .map((entry) => normalizeLogin(entry.login ?? entry.key)?.toLowerCase() ?? null)
+ .filter((login): login is string => Boolean(login))
+ .filter((login) => !visibleLogins.has(login))
+ .toSorted((a, b) => a.localeCompare(b));
+ const notice =
+ "default-avatar-cache: hidden from the rendered wall because these users still use GitHub's default avatar";
+ if (hiddenLogins.length === 0) {
+ return `${CLAWTRIBUTORS_HIDDEN_START}\n${notice}\n${CLAWTRIBUTORS_HIDDEN_END}\n`;
+ }
+ return `${CLAWTRIBUTORS_HIDDEN_START}\n${notice}\n${hiddenLogins.join("\n")}\n${CLAWTRIBUTORS_HIDDEN_END}\n`;
+}
+
+function findClawtributorsRange(content: string): { start: number; end: number } | null {
+ const markerStart = content.indexOf(CLAWTRIBUTORS_START);
+ const markerEnd = content.indexOf(CLAWTRIBUTORS_END, markerStart);
+ if (markerStart !== -1 && markerEnd !== -1) {
+ return {
+ start: markerStart,
+ end: markerEnd + CLAWTRIBUTORS_END.length,
+ };
+ }
+
+ const legacyStart = content.indexOf('