Tucker McKnight <tucker@pangolin.lan> | Sun Jun 28 2026
Make sure directories are included in the pagination date for files.ts Also some URL fixes and changing the width of the boxes on the index page. Directories are now found in a separate function call from files, so that they can be added to the pagination data on the files page (since every directory should have its own HTML page for files), but omitted from the raw.ts page (since only actual files need the raw output).
31 32 33 34 35 36
m('div', {class: "col"},
m('h3', [
m('span', {class: "bezel-gray p-1 my-1 d-inline-block"},
m('a', {href: `${data.reposPath}/${fileInfo.repoName}/${fileInfo.type}/${fileInfo.refName}/files`}, './')
),
fileInfo.file.split('/').map((dir, index, arr) => {
if (index === arr.length - 1) {31 32 33 34 35 36
m('div', {class: "col"},
m('h3', [
m('span', {class: "bezel-gray p-1 my-1 d-inline-block"},
m('a', {href: `${data.reposPath}/${slugify(fileInfo.repoName)}/${fileInfo.type}/${slugify(fileInfo.refName)}/files`}, './')
),
fileInfo.file.split('/').map((dir, index, arr) => {
if (index === arr.length - 1) {40 41 42 43 44 45 46 47 48 49 50 51 52
else {
return m('span', {class: "bezel-gray p-1 my-1 d-inline-block"}, [
m('a', {
href: `${data.reposPath}/${fileInfo.repoName}/${fileInfo.type}/${fileInfo.refName}/files/${arr.slice(0, index + 1).map((part) => slugify(part)).join('/')}.html`}, `${dir}/`)
])
}
})
])
)
),
(isDirectory(fileInfo.file, fileInfo.repoName, fileInfo.refName, fileInfo.type) ?
m('div', {class: "row"},
m('div', {class: "col"},
m('ul', {class: "list-group"},40 41 42 43 44 45 46 47 48 49 50 51 52
else {
return m('span', {class: "bezel-gray p-1 my-1 d-inline-block"}, [
m('a', {
href: `${data.reposPath}/${slugify(fileInfo.repoName)}/${fileInfo.type}/${slugify(fileInfo.refName)}/files/${arr.slice(0, index + 1).map((part) => slugify(part)).join('/')}`}, `${dir}/`)
])
}
})
])
)
),
(fileInfo.isDirectory ?
m('div', {class: "row"},
m('div', {class: "col"},
m('ul', {class: "list-group"},59 60 61 62 63 64
return pathPart.split('.').map((subPart) => {
return slugify(subPart)
}).join('.')
}).join('/')}.html`},
getRelativePath(fileInfo.file, dir.name)
)
])59 60 61 62 63 64
return pathPart.split('.').map((subPart) => {
return slugify(subPart)
}).join('.')
}).join('/')}`},
getRelativePath(fileInfo.file, dir.name)
)
])12 13 14 15 16 17
m('div', {class: "row d-flex flex-wrap"},
data.repos.map((repo) => {
return (
m('div', {class: "col", style: "flex-basis: 50%; max-width: 50%;"},
m('div', {class: "my-2 card bezel-gray flex-grow-1"},
m('div', {class: "card-header"},
m('a', {class: "card-title fs-5", href: `${data.reposPath}/${slugify(repo.name)}`}, repo.name)12 13 14 15 16 17
m('div', {class: "row d-flex flex-wrap"},
data.repos.map((repo) => {
return (
m('div', {class: "col", style: "flex-basis: 30rem;"},
m('div', {class: "my-2 card bezel-gray flex-grow-1"},
m('div', {class: "card-header"},
m('a', {class: "card-title fs-5", href: `${data.reposPath}/${slugify(repo.name)}`}, repo.name)2 3 4 5 6 7
import childProcess from 'child_process'
import {repos, getBranchesAndTags} from './src/repos.ts'
import getFlatRefs from './src/flatRefs.ts'
import flatFiles from './src/flatFiles.ts'
import flatPatches from './src/flatPatches.ts'
import paginatedPatches, {type PatchPage} from './src/paginatedPatches.ts'
import {getLocation} from './src/helpers.ts'2 3 4 5 6 7
import childProcess from 'child_process'
import {repos, getBranchesAndTags} from './src/repos.ts'
import getFlatRefs from './src/flatRefs.ts'
import { flatFiles, flatDirectories } from './src/flatFiles.ts'
import flatPatches from './src/flatPatches.ts'
import paginatedPatches, {type PatchPage} from './src/paginatedPatches.ts'
import {getLocation} from './src/helpers.ts'264 265 266 267 268 269 270 271 272 273 274 275 276 277 278
return sortedByDirectory
})
eleventyConfig.addFilter("isDirectory", (filename: string, repoName: string, refName: string, refType: 'branch' | 'tag') => {
const repo = reposData.find(repo => repo.name === repoName)
const refKey = refType === 'branch' ? 'branches' : 'tags'
const files = repo[refKey].find(ref => ref.name === refName).fileList
const isDirectory = Array.from(files.keys()).some((testFile) => {
return testFile.startsWith(filename + '/') && (testFile !== filename)
})
return isDirectory
})
eleventyConfig.addFilter("pagesJustForRef", (pages: Array<PatchPage>, repoName: string, refName: string, refType: "branch" | "tag") => {
return pages.filter(page => page.repoName === repoName && page.refName === refName && page.type === refType)
})264 265 266 267 268
return sortedByDirectory
})
eleventyConfig.addFilter("pagesJustForRef", (pages: Array<PatchPage>, repoName: string, refName: string, refType: "branch" | "tag") => {
return pages.filter(page => page.repoName === repoName && page.refName === refName && page.type === refType)
})388 389 390 391 392
// FILE.TS
const flatFilesData = flatFiles(reposData)
eleventyConfig.addTemplate(
'repos/file.11ty.js',
commonPage(fileJsTemplate, reposConfiguration, eleventyConfig),388 389 390 391 392 393 394
// FILE.TS
const flatFilesData = flatFiles(reposData)
const flatDirectoriesData = flatDirectories(reposData)
eleventyConfig.addTemplate(
'repos/file.11ty.js',
commonPage(fileJsTemplate, reposConfiguration, eleventyConfig),397 398 399 400 401 402
size: 1,
alias: "fileInfo",
},
flatFiles: flatFilesData,
permalink: (data) => {
const repoName = data.fileInfo.repoName
const refName = data.fileInfo.refName397 398 399 400 401 402
size: 1,
alias: "fileInfo",
},
flatFiles: flatFilesData.concat(flatDirectoriesData),
permalink: (data) => {
const repoName = data.fileInfo.repoName
const refName = data.fileInfo.refName444 445 446 447 448 449
const repoName = data.fileInfo.repoName
const refName = data.fileInfo.refName
const refType = data.fileInfo.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${refType}/${eleventyConfig.getFilter("slugify")(refName)}/raw/${data.fileInfo.file.split('.').map(filePart => eleventyConfig.getFilter("slugify")(filePart)).join('.')}`
},
eleventyComputed: {
currentRepo: (data) => reposData.find(repo => {444 445 446 447 448 449
const repoName = data.fileInfo.repoName
const refName = data.fileInfo.refName
const refType = data.fileInfo.type
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/${refType}/${eleventyConfig.getFilter("slugify")(refName)}/raw/${data.fileInfo.file.split('/').map((filePart) => filePart.split('.').map((subPart) => eleventyConfig.getFilter("slugify")(subPart)).join('.')).join('/')}`
},
eleventyComputed: {
currentRepo: (data) => reposData.find(repo => {0 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 27 28 29 30 31 32 33 34
import { type Repository } from "./dataTypes.ts"
let cachedFlatFiles: Array<FlatFileEntry> | null = null
export type FlatFileEntry = {
file: string,
refName: string,
repoName: string,
type: 'branch' | 'tag',
}
export default (repos: Array<Repository>) : Array<FlatFileEntry> => {
if (cachedFlatFiles !== null) { return cachedFlatFiles }
const itemsFromRefFileList: (ref: Repository['tags'][0], repoName: string, refType: 'branch' | 'tag') => Array<FlatFileEntry> = (ref, repoName, refType) => {
return Array.from(ref.fileList.keys()).map((file) => {
return {
file,
refName: ref.name,
repoName: repoName,
type: refType,
}
})
}
const branches: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.branches.flatMap(branch => itemsFromRefFileList(branch, repo.name, 'branch'))
})
const tags: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.tags.flatMap(tag => itemsFromRefFileList(tag, repo.name, 'tag'))
})
cachedFlatFiles = [...branches, ...tags]
return cachedFlatFiles
}0 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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
import { type Repository } from "./dataTypes.ts"
let cachedFlatFiles: Array<FlatFileEntry> | null = null
export type FlatFileEntry = {
file: string,
refName: string,
repoName: string,
type: 'branch' | 'tag',
isDirectory: boolean,
}
const dirsFromRefFileList: (
ref: Repository['tags'][0],
repoName: string,
refType: 'branch' | 'tag'
) => Array<FlatFileEntry> = (ref, repoName, refType) => {
const filesAndDirs = new Set<string>()
for (const file of ref.fileList) {
const fileParts = file.split('/')
// Iterate through fileParts except for the last part, which will be
// the file name. Since we just want dirs here, we can ignore that.
const filePartsWithoutEnd = fileParts.slice(0, fileParts.length - 1)
for (const [index, _val] of filePartsWithoutEnd.entries()) {
const path = fileParts.slice(0, filePartsWithoutEnd.length - index).join('/')
if (filesAndDirs.has(path)) {
break
} else {
filesAndDirs.add(path)
}
}
}
return Array.from(filesAndDirs).map((file) => {
return {
file,
refName: ref.name,
repoName: repoName,
type: refType,
isDirectory: true,
}
})
}
const filesFromRefFileList: (
ref: Repository['tags'][0],
repoName: string,
refType: 'branch' | 'tag'
) => Array<FlatFileEntry> = (ref, repoName, refType) => {
return Array.from(ref.fileList).map((file) => {
return {
file,
refName: ref.name,
repoName: repoName,
type: refType,
isDirectory: false,
}
})
}
const flatFiles = (repos: Array<Repository>) : Array<FlatFileEntry> => {
if (cachedFlatFiles !== null) { return cachedFlatFiles }
const branches: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.branches.flatMap(branch => filesFromRefFileList(branch, repo.name, 'branch'))
})
const tags: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.tags.flatMap(tag => filesFromRefFileList(tag, repo.name, 'tag'))
})
cachedFlatFiles = [...branches, ...tags]
return cachedFlatFiles
}
const flatDirectories = (repos: Array<Repository>) : Array<FlatFileEntry> => {
const branches: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.branches.flatMap(branch => dirsFromRefFileList(branch, repo.name, 'branch'))
})
const tags: FlatFileEntry[] = repos.flatMap((repo) => {
return repo.tags.flatMap(tag => dirsFromRefFileList(tag, repo.name, 'tag'))
})
return [...branches, ...tags]
}
export {
flatFiles,
flatDirectories,
}13 14 15 16 17 18
if (cachedFlatPatches !== null) { return cachedFlatPatches }
const itemsForRef: (
ref: Repository['tags'][0], refType: 'branch' | 'tag', repo: Repository
) => Array<FlatPatchRecord> = (ref, refType, repo) => {
const flatPatches: Array<FlatPatchRecord> = []
let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(ref.sha)13 14 15 16 17 18 19 20
if (cachedFlatPatches !== null) { return cachedFlatPatches }
const itemsForRef: (
ref: Repository['tags'][0],
refType: 'branch' | 'tag',
repo: Repository
) => Array<FlatPatchRecord> = (ref, refType, repo) => {
const flatPatches: Array<FlatPatchRecord> = []
let currentCommit: ReturnType<Repository['commits']['get']> | undefined = repo.commits.get(ref.sha)