Tucker McKnight <tucker@pangolin.lan> | Sun Mar 01 2026
Change references of "branches" to "rels", allow for tags, too "rels" refers to a branch _or_ a tag. Flattened data lists (flatPatches, flatFiles, and branches.ts (now flatRels.ts)) should specify which type of rel each of their entries is. Pages now have the rel type (branch or tag) in their permalink instead of always being hard-coded to /branches/.
8 9 10 11 12 13 14 15
const nav = NavHelper(reposConfig, slugify, data.branchInfo.repoName, data.branchInfo.branchName)
const branchesWithWorkInProgress = data.branches.filter(branch => branch.ahead > 0)
const branchesFullyMerged = data.branches.filter(branch => branch.ahead === 0)
return branch.repoName === data.branchInfo.repoName ?
href: `${data.reposPath}/${slugify(branch.repoName)}/branches/${slugify(branch.branchName)}/branches`
}, branch.branchName),
branch.branchName === data.branchInfo.branchName
branch.branchName === data.reposConfig.repos[branch.repoName].defaultBranch8 9 10 11 12 13 14 15
const nav = NavHelper(reposConfig, slugify, data.flatRel.repoName, data.flatRel.relName)
const branchesWithWorkInProgress = data.flatRels.filter(rel => rel.type === "branch" && rel.ahead > 0)
const branchesFullyMerged = data.flatRels.filter(rel => rel.type === "branch" && rel.ahead === 0)
return branch.repoName === data.flatRel.repoName ?
href: `${data.reposPath}/${slugify(branch.repoName)}/branches/${slugify(branch.relName)}/branches`
}, branch.relName),
branch.relName === data.flatRel.relName
branch.relName === data.reposConfig.repos[branch.repoName].defaultBranch7 8 9
const pagesJustForBranch = eleventyConfig.getFilter("pagesJustForBranch")
const nav = NavHelper(reposConfig, slugify, data.patchPage.repoName, data.patchPage.branchName)
m('span', {class: "font-monospace me-2"}, data.patchPage.branchName),7 8 9
const pagesJustForRel = eleventyConfig.getFilter("pagesJustForRel")
const nav = NavHelper(reposConfig, slugify, data.patchPage.repoName, data.patchPage.relName)
m('span', {class: "font-monospace me-2"}, data.patchPage.relName),34 35 36
pagesJustForBranch(
data.patchPage.branchName
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/branches/${data.patchPage.branchName}/commits/page${pageObj.pageNumber}`34 35 36
pagesJustForRel(
data.patchPage.relName,
data.patchPage.type,
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/${data.patchPage.type}/${data.patchPage.relName}/commits/page${pageObj.pageNumber}`56
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/branches/${slugify(data.patchPage.branchName)}/commits/${commit.hash}`,56
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/${data.patchPage.type}/${slugify(data.patchPage.relName)}/commits/${commit.hash}`,67 68 69
pagesJustForBranch(
data.patchPage.branchName
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/branches/${data.patchPage.branchName}/commits/page${pageObj.pageNumber}`67 68 69
pagesJustForRel(
data.patchPage.relName,
data.patchPage.type,
href: `${data.reposPath}/${slugify(data.patchPage.repoName)}/${data.patchPage.type}/${data.patchPage.relName}/commits/page${pageObj.pageNumber}`11 12 13
const branch: Repository['branches'][0] = data.currentBranch
const nav = NavHelper(reposConfig, slugify, repo.name, branch.name)
date: repo.commits.get(branch.head).date.toISOString(),11 12 13
const rel: Repository['branches'][0] = data.currentRel
const nav = NavHelper(reposConfig, slugify, repo.name, rel.name)
date: repo.commits.get(branch.sha).date.toISOString(),39
window.currentBranch = "${branch.name}";39
window.currentBranch = "${rel.name}";71
}, branch.name),71
}, rel.name),95
branchesListItems(branchesWithHrefs, repo.defaultBranch, branch.name, 'date')95
branchesListItems(branchesWithHrefs, repo.defaultBranch, rel.name, 'date')1
import branches from '../src/branches.ts'1
import getFlatRels from '../src/flatRels.ts'9 10 11 12 13 14 15 16 17
const branch: ReturnType<typeof branches>[0] = data.branch
const currentBranch: Repository['branches'][0] = data.currentBranch
const currentBranchCommits: Awaited<ReturnType<typeof flatPatches>> = data.currentBranchCommits
m('title', `Latest patches in ${branch.branchName}`),
m.trust(`<link href="${ data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName) + '/commits.xml'}" rel="self" />`),
m.trust(`<link href="${data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName)}" />`),
m('updated', dateToRfc3339(currentRepo.commits.get(currentBranch.head).date)),
currentBranchCommits.map((commit) => {
const commitUrl = data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName) + '/commits/' + commit.commit.hash9 10 11 12 13 14 15 16 17
const flatRel: ReturnType<typeof getFlatRels>[0] = data.flatRel
const currentRel: Repository['branches'][0] = data.currentRel
const currentRelCommits: Awaited<ReturnType<typeof flatPatches>> = data.currentRelCommits
m('title', `Latest patches in ${flatRel.relName}`),
m.trust(`<link href="${ data.reposConfig.baseUrl + '/repos/' + slugify(flatRel.repoName) + `/${flatRel.type}/` + slugify(flatRel.relName) + '/commits.xml'}" rel="self" />`),
m.trust(`<link href="${data.reposConfig.baseUrl + '/repos/' + slugify(flatRel.repoName) + `/${flatRel.type}/` + slugify(flatRel.relName)}" />`),
m('updated', dateToRfc3339(currentRepo.commits.get(currentRel.sha).date)),
currentRelCommits.map((commit) => {
const commitUrl = data.reposConfig.baseUrl + '/repos/' + slugify(flatRel.repoName) + `/${flatRel.type}/` + slugify(flatRel.relName) + '/commits/' + commit.commit.hash15
const currentBranch: Branch = data.currentBranch15
const currentRel: Branch = data.currentRel96
currentBranch.fileList.get(fileInfo.file).fileInfo.contents96
currentRel.fileList.get(fileInfo.file).fileInfo.contents116
lineNumbers(currentBranch.fileList.get(fileInfo.file).fileInfo.contents).map((lineNumber) => {116
lineNumbers(currentRel.fileList.get(fileInfo.file).fileInfo.contents).map((lineNumber) => {125 126
currentBranch.fileList.get(fileInfo.file).fileInfo.blameLines.map((annotation) => {
currentBranch.fileList.get(fileInfo.file).fileInfo.contents,125 126
currentRel.fileList.get(fileInfo.file).fileInfo.blameLines.map((annotation) => {
currentRel.fileList.get(fileInfo.file).fileInfo.contents,3
const branch: Repository['branches'][0] = data.currentBranch3
const branch: Repository['branches'][0] = data.currentRel14
m('span', {class: "font-monospace"}, data.branchInfo.branchName)14
m('span', {class: "font-monospace"}, data.flatRel.relName)27
href: `${data.reposPath}/${slugify(data.branchInfo.repoName)}/branches/${slugify(data.branchInfo.branchName)}/files/${27
href: `${data.reposPath}/${slugify(data.flatRel.repoName)}/branches/${slugify(data.flatRel.relName)}/files/${3
const branch: Branch = data.currentBranch3
const branch: Branch = data.currentRel5 6 7 8
const branch: Repository['branches'][0] = data.currentBranch
const latestCommit = repo.commits.get(branch.head)
const nav = NavHelper(reposConfig, slugify, repo.name, branch.name)
const languageCounts = Array.from(branch.fileList.keys()).reduce((counts, currentFile) => {5 6 7 8
const rel: Repository['branches'][0] | Repository['tags'][0] = data.currentRel
const latestCommit = repo.commits.get(rel.sha)
const nav = NavHelper(reposConfig, slugify, repo.name, rel.name)
const languageCounts = Array.from(rel.fileList.keys()).reduce((counts, currentFile) => {31
const total = Array.from(branch.fileList.keys()).length31
const total = Array.from(rel.fileList.keys()).length46
const readmeContent = await renderContentIfAvailable(await getReadMe(repo.name, branch.name), branch.name)46
const readmeContent = await renderContentIfAvailable(await getReadMe(repo.name, rel.name), rel.name)2
import branches from './src/branches.ts'2
import getFlatRels from './src/flatRels.ts'88 89
const branchesData = branches(reposData)
eleventyConfig.addGlobalData("branches", branchesData)88 89
const flatRels = getFlatRels(reposData)
eleventyConfig.addGlobalData("flatRels", flatRels)253 254
eleventyConfig.addFilter("pagesJustForBranch", (pages: Array<PatchPage>, repoName: string, branchName: string) => {
return pages.filter(page => page.repoName === repoName && page.branchName === branchName)253 254
eleventyConfig.addFilter("pagesJustForRel", (pages: Array<PatchPage>, repoName: string, relName: string, relType: "branch" | "tag") => {
return pages.filter(page => page.repoName === repoName && page.relName === relName && page.type === relType)295 296 297 298 299 300 301 302 303 304 305 306 307
data: "branches",
alias: "branchInfo",
const repoName = data.branchInfo.repoName
const branchName = data.branchInfo.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/branches/`
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
return repo.name === data.branchInfo.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName
}).branches.find(branch => {
return branch.name === data.branchInfo.branchName295 296 297 298 299 300 301 302 303 304 305 306 307
data: "flatRels",
alias: "flatRel",
const repoName = data.flatRel.repoName
const relName = data.flatRel.relName
const relType = data.flatRel.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/branches/`
repoName: (data) => data.flatRel.repoName,
relName: (data) => data.flatRel.relName,
return repo.name === data.flatRel.repoName
currentRel: (data) => {
const relType = data.flatRel.type === "branch" ? "branches" : "tags"
const currentRepo = reposData.find(repo => {
return repo.name === data.flatRel.repoName
})
return currentRepo[relType].find(rel => {
return rel.name === data.flatRel.relName
})
}338
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/files/${data.fileInfo.file.split('/').map((filePart) => filePart.split('.').map((subPart) => eleventyConfig.getFilter("slugify")(subPart)).join('.')).join('/')}.html`338
const relType = data.fileInfo.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(branchName)}/files/${data.fileInfo.file.split('/').map((filePart) => filePart.split('.').map((subPart) => eleventyConfig.getFilter("slugify")(subPart)).join('.')).join('/')}.html`349
currentBranch: (data) => reposData.find(repo => {349
currentRel: (data) => reposData.find(repo => {374 375
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/raw/${data.fileInfo.file.split('.').map(filePart => eleventyConfig.getFilter("slugify")(filePart)).join('.')}`
currentBranch: (data) => reposData.find(repo => {374 375
const relType = data.fileInfo.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(branchName)}/raw/${data.fileInfo.file.split('.').map(filePart => eleventyConfig.getFilter("slugify")(filePart)).join('.')}`
currentRel: (data) => reposData.find(repo => {392 393 394 395 396 397 398 399 400 401 402 403 404
data: "branches",
alias: "branchInfo",
const repoName = data.branchInfo.repoName
const branchName = data.branchInfo.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/files/`
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
return repo.name === data.branchInfo.repoName
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.branchInfo.repoName
}).branches.find(branch => {
return branch.name === data.branchInfo.branchName
})392 393 394 395 396 397 398 399 400 401 402 403 404
data: "flatRels",
alias: "flatRel",
const repoName = data.flatRel.repoName
const relName = data.flatRel.relName
const relType = data.flatRel.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/files/`
repoName: (data) => data.flatRel.repoName,
relName: (data) => data.flatRel.relName,
return repo.name === data.flatRel.repoName
currentRel: (data) => {
const relType = data.flatRel.type === "branch" ? "branches" : "tags"
return reposData.find(repo => {
return repo.name === data.flatRel.repoName
})[relType].find(rel => {
return rel.name === data.flatRel.relName
})
}426 427 428 429 430 431 432 433 434 435 436 437 438 439
data: "branches",
alias: "branch",
const repoName = data.branch.repoName
const branchName = data.branch.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/`
repoName: (data) => data.branch.repoName,
branchName: (data) => data.branch.branchName,
path: (data) => '', // ask about why empty string here shows up as a function
return repo.name === data.branch.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.branch.repoName
}).branches.find(branch => {
return branch.name === data.branch.branchName426 427 428 429 430 431 432 433 434 435 436 437 438 439
data: "flatRels",
alias: "flatRel",
const repoName = data.flatRel.repoName
const relName = data.flatRel.relName
const relType = data.flatRel.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/`
repoName: (data) => data.flatRel.repoName,
relName: (data) => data.flatRel.relName,
path: (data) => '', // TODO: ask about why empty string here shows up as a function
return repo.name === data.flatRel.repoName
currentRel: (data) => {
const relType = data.flatRel.type === "branch" ? "branches" : "tags"
return reposData.find(repo => {
return repo.name === data.flatRel.repoName
})[relType].find(rel => {
return rel.name === data.flatRel.relName
})
}457
`repos/patches.11ty.js`,457
`repos/commits.11ty.js`,468 469 470 471 472 473 474 475
const branchName = data.patchPage.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/commits/page${data.patchPage.pageNumber}/`
branchName: (data) => data.patchPage.branchName,
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.patchPage.repoName
}).branches.find(branch => {
return branch.name === data.patchPage.branchName
}),468 469 470 471 472 473 474 475
const relName = data.patchPage.relName
const relType = data.patchPage.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/commits/page${data.patchPage.pageNumber}/`
relName: (data) => data.patchPage.relName,
currentRel: (data) => {
const relType = data.patchPage.type === "branch" ? "branches" : "tags"
return reposData.find(repo => {
return repo.name === data.patchPage.repoName
})[relType].find(rel => {
return rel.name === data.patchPage.relName
})
}504 505 506 507 508 509 510 511
const branchName = data.patchInfo.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/commits/${data.patchInfo.commit.hash}/`
branchName: (data) => data.patchInfo.branchName,
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.patchInfo.repoName
}).branches.find(branch => {
return branch.name === data.patchInfo.branchName
}),504 505 506 507 508 509 510 511
const relName = data.patchInfo.relName
const relType = data.patchInfo.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/commits/${data.patchInfo.commit.hash}/`
relName: (data) => data.patchInfo.relName,
currentRel: (data) => {
const relType = data.patchInfo.type === "branch" ? "branches" : "tags"
return reposData.find(repo => {
return repo.name === data.patchInfo.repoName
})[relType].find(rel => {
return rel.name === data.patchInfo.relName
})
},532 533 534 535 536 537 538 539 540 541 542 543 544
data: "branches",
alias: "branch",
const repoName = data.branch.repoName
const branchName = data.branch.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/commits.xml`
return repo.name === data.branch.repoName
}),
currentBranch: (data) => reposData.find(repo => {
return repo.name === data.branch.repoName
}).branches.find(branch => {
return branch.name === data.branch.branchName
currentBranchCommits: (data) => {
return patch.branchName === data.branch.branchName532 533 534 535 536 537 538 539 540 541 542 543 544
data: "flatRels",
alias: "flatRel",
const repoName = data.flatRel.repoName
const relName = data.flatRel.relName
const relType = data.flatRel.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${relType}/${eleventyConfig.getFilter("slugify")(relName)}/commits.xml`
return repo.name === data.flatRel.repoName
currentRel: (data) => {
const relType = data.flatRel.type === "branch" ? "branches" : "tags"
return reposData.find(repo => {
return repo.name === data.flatRel.repoName
})[relType].find(rel => {
return rel.name === data.flatRel.relName
})
},
currentRelCommits: (data) => {
return patch.relName === data.flatRel.relName1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
import { type Repository } from "./dataTypes.ts"
let cachedBranches: Array<{
branchName: string,
repoName: string,
}> | null = null
export default (repos: Array<Repository>) => {
if (cachedBranches !== null) { return cachedBranches }
cachedBranches = repos.flatMap((repo) => {
return repo.branches.map((branch) => {
const result = {
branchName: branch.name,
repoName: repo.name,
compareTo: branch.compareTo,
ahead: branch.ahead,
behind: branch.behind,
}
if (branch.description) { result['description'] = branch.description }
return result
})
})
return cachedBranches
}1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
17
head: string,17
sha: string,3
branchName: string,3
relName: string,
type: "branch" | "tag",13 14 15
return repo.branches.flatMap((branch) => {
let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(branch.head)
branchName: branch.name13 14 15
const branches = repo.branches.flatMap((branch) => {
let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(branch.sha)
type: "branch",
relName: branch.name29
29
const tags = repo.tags.flatMap((tag) => {
const flatPatches: Array<FlatPatchRecord> = []
let currentCommit: ReturnType<Repository['commits']['get']> = repo.commits.get(tag.sha)
while (currentCommit !== undefined) {
flatPatches.push({
type: "tag",
commit: currentCommit,
repoName: repo.name,
relName: tag.name,
})
currentCommit = repo.commits.get(currentCommit.parent)
}
return flatPatches
})
return [...branches, ...tags]0
0
import { type Repository } from "./dataTypes.ts"
type BranchEntry = {
relName: string,
type: "branch",
repoName: string,
compareTo: string,
ahead: number,
behind: number,
}
type TagEntry = {
relName: string,
type: "tag",
repoName: string,
}
let cachedRels: Array<BranchEntry | TagEntry> | null = null
export default (repos: Array<Repository>) => {
if (cachedRels !== null) { return cachedRels }
cachedRels = repos.flatMap((repo) => {
const branches: Array<BranchEntry> = repo.branches.map((branch) => {
const result: BranchEntry = {
relName: branch.name,
type: "branch",
repoName: repo.name,
compareTo: branch.compareTo,
ahead: branch.ahead,
behind: branch.behind,
}
if (branch.description) { result['description'] = branch.description }
return result
})
const tags: Array<TagEntry> = repo.tags.map((tag) => {
return {
relName: tag.name,
type: "tag",
repoName: repo.name,
}
})
return [...branches, ...tags]
})
return cachedRels
}3
branchName: string,3
relName: string,
type: "branch" | "tag",21 22 23
&& page.branchName == patch.branchName
const pageNumber = paginatedPatches.filter(page => (page.repoName === patch.repoName && page.branchName === patch.branchName)).length + 1
branchName: patch.branchName,21 22 23
&& page.relName == patch.relName
&& page.type == patch.type
const pageNumber = paginatedPatches.filter(page => (
page.repoName === patch.repoName
&& page.relName === patch.relName
&& page.type === patch.type
)).length + 1
relName: patch.relName,
type: patch.type,162
head: branchHead,162
sha: branchHead,190 191
let currentCommit = commits.get(compareToBranch.head)
currentCommit = commits.get(branch.head)190 191
let currentCommit = commits.get(compareToBranch.sha)
currentCommit = commits.get(branch.sha)