Mon Nov 10 2025
Tucker McKnight <tucker@pangolin.lan>
Switching some more things over to the new Repository type Also removed anything that prints out commits in order, as that needs to be re-thought for the new format. So I left some todos in there.
7e40e5b6c81b4a222015b3d5586bc53eebd258c5
93
return reposData[repo].branches[branch].files.filter(file => file.startsWith(dirPath) && file !== dirPath)
93
return reposData.find(current => current.name === repo).branches[branch].fileList.filter(file => file.startsWith(dirPath) && file !== dirPath)
110
eleventyConfig.addFilter("highlightCode", (code, language) => {
110
eleventyConfig.addFilter("highlightCode", (code: string, language: string) => {
186
187
188
189
eleventyConfig.addFilter("isDirectory", (filename, repoName, branchName) => {
const files = reposData[repoName].branches[branchName].files
eleventyConfig.addAsyncFilter("getFileContents", async (repo, branch, filename) => {
const config = reposConfiguration.repos[repo]
186
187
188
189
eleventyConfig.addFilter("isDirectory", (filename: string, repoName: string, branchName: string) => {
const repo = reposData.find(repo => repo.name === repoName)
const files = repo.branches.find(branch => branch.name === branchName).fileList
eleventyConfig.addAsyncFilter("getFileContents", async (repo: string, branch: string, filename: string) => {
216
const config = reposConfiguration.repos[repoName]
216
336
}
336
337
338
339
340
341
342
343
344
},
currentRepo: (data) => reposData.find(repo => {
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
})
362
}
362
363
364
365
366
367
368
369
370
},
currentRepo: (data) => reposData.find(repo => {
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
}),
398
const flatPatchesData = await flatPatches(reposConfiguration)
398
const flatPatchesData = await flatPatches(reposData)
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
if (eleventyConfig?.javascript?.functions?.htmlBaseUrl) {
rssAvailable = true
const feedTemplate = fsImport.readFileSync(`${import.meta.dirname}/templates/feed.njk`).toString()
eleventyConfig.addTemplate(
`repos/feed.njk`,
feedTemplate,
{
pagination: {
data: "branches",
size: 1,
alias: "branch",
},
permalink: (data) => {
const repoName = data.branch.repoName
const branchName = data.branch.branchName
return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches.xml`
},
eleventyExcludeFromCollections: true,
}
)
}
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
// if (eleventyConfig?.javascript?.functions?.htmlBaseUrl) {
// rssAvailable = true
// const feedTemplate = fsImport.readFileSync(`${import.meta.dirname}/templates/feed.njk`).toString()
// eleventyConfig.addTemplate(
// `repos/feed.njk`,
// feedTemplate,
// {
// pagination: {
// data: "branches",
// size: 1,
// alias: "branch",
// },
// permalink: (data) => {
// const repoName = data.branch.repoName
// const branchName = data.branch.branchName
// return `${reposPath}/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/patches.xml`
// },
// eleventyComputed: {
// currentRepo: (data) => reposData.find(repo => {
// 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
// }),
// },
// eleventyExcludeFromCollections: true,
// }
// )
// }
83
84
85
{% for branch in branches %}
{% if branch.repoName == nav.repoName %}
{% endif %}
83
{% for branch in repos[nav.repoName].branches %}
34
"type": "string"
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"max": {
"type": "number"
},
"regex": {
"type": "string"
}
},
"required": [
"regex",
"max"
],
"type": "object"
}
]
52
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
},
"tags": {
"items": {
"anyOf": [
{
"type": "string"
},
{
"additionalProperties": false,
"properties": {
"max": {
"type": "number"
},
"regex": {
"type": "string"
}
},
"required": [
"regex",
"max"
],
"type": "object"
}
]
},
"type": "array"
1
2
3
4
5
export default (repos) => {
cachedBranches = Object.keys(repos).flatMap((repoName) => {
return Object.keys(repos[repoName].branches).map((branchName) => {
branchName,
repoName,
1
2
3
4
5
6
7
import { type Repository } from "./dataTypes.ts"
export default (repos: Array<Repository>) => {
cachedBranches = repos.flatMap((repo) => {
return repo.branches.map((branch) => {
branchName: branch.name,
repoName: repo.name,
51
branchesToPull: Array<string>,
51
52
branchesToPull: Array<string | {regex: string, max: number}>,
tags?: Array<string | {regex: string, max: number}>,
5
description?: string,
5
6
7
fileList: Array<string>,
fileList: Array<string>,
hash: string,
25
26
27
28
29
export type BranchInfo = {
files: Array<string>,
patches: Array<any>
}
25
1
2
3
4
5
6
7
import repos from './repos.ts'
export default (repos) => {
cachedFlatFiles = Object.keys(repos).flatMap((repoName) => {
return Object.keys(repos[repoName].branches).flatMap((branchName) => {
return repos[repoName].branches[branchName].files.map((file) => {
branchName,
repoName,
1
2
3
4
5
6
7
import { type Repository } from "./dataTypes.ts"
export default (repos: Array<Repository>) => {
cachedFlatFiles = repos.flatMap((repo) => {
return repo.branches.flatMap((branch) => {
return branch.fileList.map((file) => {
branchName: branch.name,
repoName: repo.name,
1
2
3
4
5
6
7
8
9
10
export default async (repos) => {
cachedFlatPatches = Object.keys(repos).flatMap((repoName) => {
return Object.keys(repos[repoName].branches).flatMap((branchName) => {
return repos[repoName].branches[branchName].patches.map((patch) => {
return {
patch,
branchName,
repoName,
}
})
1
2
3
4
5
6
import { type Repository } from "./dataTypes.ts"
export default async (repos: Array<Repository>) => {
cachedFlatPatches = repos.flatMap((repo) => {
return repo.branches.flatMap((branch) => {
return [] // todo implement this with new commits format
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
import {type BranchInfo} from './dataTypes.ts'
import repoOperations from './vcses/operations.ts'
import { getBranchInfo } from './vcses/git/operations.ts'
import repoHelpers from './vcses/helpers.ts'
type BranchInfoTuple = [string, BranchInfo]
type BranchObject = {
[key: string]: BranchInfo
}
type RepoObjectTuple = [string, BranchObject]
type RepoObject = {
[key: string]: {
branches: BranchObject,
cloneUrl: string,
}
}
return repoConfig.branchesToPull
const repos: (reposConfig: any) => Promise<RepoObject> = async (reposConfig) => {
const reposTuples: RepoObjectTuple[] = await Promise.all(repoNames.map(async (repoName): Promise<RepoObjectTuple> => {
const vcs = reposConfig.repos[repoName]._type
const branchTuples: BranchInfoTuple[] = await Promise.all(branchNames.map(async (branchName): Promise<BranchInfoTuple> => {
const files = await repoOperations[vcs].getFileList(repoName, branchName, repoLocation)
const patches = await getBranchInfo(branchName, repoLocation)
return [branchName, {
files,
patches,
}]
}))
const branchesObject: BranchObject = {}
for (let branchTuple of branchTuples) {
branchesObject[branchTuple[0]] = branchTuple[1]
return [repoName, branchesObject]
}))
const reposObject: RepoObject = {}
for (let repoTuple of reposTuples) {
const repoName = repoTuple[0]
const repoType = reposConfig.repos[repoName]._type
reposObject[repoName] = {
branches: repoTuple[1],
cloneUrl: repoHelpers[repoType].cloneUrl(reposConfig.baseUrl + (reposConfig.path || ""), repoName)
}
cachedRepos = reposObject
return reposObject
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
type ReposConfiguration,
import { type Repository} from './dataTypes.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
return repoConfig.branchesToPull.map((branch) => {
if (typeof branch === "string") {
return branch
}
else {
return "" // todo
}
})
const repos: (reposConfig: ReposConfiguration) => Promise<Array<Repository>> = async (reposConfig) => {
const repos: Array<Repository> = []
for (const repoName of repoNames) {
const commits: Repository['commits'] = new Map()
for (const branchName of branchNames) {
await addBranchToCommitsMap(branchName, repoLocation, commits)
repos.push({
name: repoName,
branches: branchNames.map((branchName) => {
return {
name: branchName,
head: "", // todo
fileList: [], //todo
}
}),
cloneUrl: "",
defaultBranch: "main",
tags: [],
commits,
})
return repos
38
39
40
41
42
43
44
45
46
47
export const getBranchInfo = async (branchName: string, repoLocation: string) => {
const patches: Map<string, {
name: string,
description: string,
author: string,
date: string,
hash: string,
diffs: ReturnType<Repository['commits']['get']>['diffs'],
}> = new Map()
38
export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise<void> => {
62
62
63
64
65
66
67
// exit early if the commits map already includes this hash
if (commits.has(hash)) {
break
}
75
76
77
78
79
80
81
82
83
84
85
86
const commitMessage = currentPatch.slice(4, diffStart).map(str => str.replace(" ", ""))
const name = commitMessage[0].trim()
const description = commitMessage.slice(1, commitMessage.length - 1).filter((line) => {
patches.set(hash, {
name,
description,
author,
date,
diffs,
return Array.from(patches.values())
export const getFileLastTouchInfo = async (repo, branch, filename, repoLocation) => {
75
76
77
78
79
80
81
82
const commitMessage = currentPatch.slice(4, diffStart).map(str => str.replace(" ", "")).filter((line) => {
commits.set(hash, {
message: commitMessage,
author,
date: new Date(date),
diffs,
parent: "todo",
export const getFileLastTouchInfo = async (repo: string, branch: string, filename: string, repoLocation: string) => {
2
3
import {type BranchInfo} from '../dataTypes.ts'
getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<BranchInfo['files']>,
2
getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<Array<string>>,
1
{% set files = repos[branchInfo.repoName].branches[branchInfo.branchName].files | topLevelFilesOnly('') %}
1
{% set files = currentBranch.fileList | topLevelFilesOnly('') %}
1
2
{% for repoName, options in repos %}
<li><a href="{{reposPath}}/{{repoName | slugify}}/branches/{{reposConfig.repos[repoName].defaultBranch}}">{{repoName}}</a></li>
1
2
{% for repo in repos %}
<li><a href="{{reposPath}}/{{repo.name | slugify}}/branches/{{reposConfig.repos[repo.name].defaultBranch}}">{{repo.name}}</a></li>
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
{% for patch in repos[branch.repoName].branches[branch.branchName].patches | batch(3) | first %}
<div class="card mt-2 mb-4">
<div class="card-body">
<a href="{{reposPath}}/{{branch.repoName | slugify}}/branches/{{branch.branchName | slugify}}/patches/{{patch.hash}}" class="text-primary d-inline-block card-title fs-5">{{patch.name}}</a>
<p class="card-subtitle fs-6 mb-2 text-body-secondary">{{patch.date}}</p>
<p class="card-subtitle fs-6 mb-2 text-body-secondary">{{patch.author}}</p>
<p class="card-text">{{patch.description | truncate(150)}}</p>
</div>
<div class="card-footer">
<button data-hash="{{patch.hash}}" data-vcs="git" class="copy-btn btn btn-sm btn-outline-primary">
{{patch.hash | truncate(8, true, "")}} <i class="bi-copy bi me-1"></i>
</button>
</div>
</div>
{% endfor %}
15