Switching some more things over to the new Repository type

7e40e5b6c81b4a222015b3d5586bc53eebd258c5

Tucker McKnight | Mon Nov 10 2025

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.
main.ts:93
Before
93
    return reposData[repo].branches[branch].files.filter(file => file.startsWith(dirPath) && file !== dirPath)
After
93
    return reposData.find(current => current.name === repo).branches[branch].fileList.filter(file => file.startsWith(dirPath) && file !== dirPath)
main.ts:110
Before
110
  eleventyConfig.addFilter("highlightCode", (code, language) => {
After
110
  eleventyConfig.addFilter("highlightCode", (code: string, language: string) => {
main.ts:186
Before
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]
After
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) => {
main.ts:216
Before
216
    const config = reposConfiguration.repos[repoName]
After
216
main.ts:336
Before
336
        }
After
336
        },
        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
        })
main.ts:362
Before
362
        }
After
362
        },
        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
        }),
main.ts:398
Before
398
  const flatPatchesData = await flatPatches(reposConfiguration)
After
398
  const flatPatchesData = await flatPatches(reposData)
main.ts:429
Before
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,
      }
    )
  }
After
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`
  //       },
  //       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,
  //     }
  //   )
  // }
partial_templates/main_top.njk:83
Before
83
84
85
                        {% for branch in branches %}
                        {% if branch.repoName == nav.repoName %}
                        {% endif %}
After
83
84
85
                        {% for branch in repos[nav.repoName].branches %}
schemas/ReposConfiguration.json:34
Before
34
            "type": "string"
After
34
            "anyOf": [
              {
                "type": "string"
              },
              {
                "additionalProperties": false,
                "properties": {
                  "max": {
                    "type": "number"
                  },
                  "regex": {
                    "type": "string"
                  }
                },
                "required": [
                  "regex",
                  "max"
                ],
                "type": "object"
              }
            ]
schemas/ReposConfiguration.json:52
Before
52
After
52
        },
        "tags": {
          "items": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "additionalProperties": false,
                "properties": {
                  "max": {
                    "type": "number"
                  },
                  "regex": {
                    "type": "string"
                  }
                },
                "required": [
                  "regex",
                  "max"
                ],
                "type": "object"
              }
            ]
          },
          "type": "array"
src/branches.ts:1
Before
1
2
3
4
5
export default (repos) => {
  cachedBranches = Object.keys(repos).flatMap((repoName) => {
    return Object.keys(repos[repoName].branches).map((branchName) => {
        branchName,
        repoName,
After
1
2
3
4
5
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,
src/configTypes.ts:51
Before
51
  branchesToPull: Array<string>,
After
51
  branchesToPull: Array<string | {regex: string, max: number}>,
  tags?: Array<string | {regex: string, max: number}>,
src/dataTypes.ts:5
Before
5
    description?: string,
After
5
    fileList: Array<string>,
    fileList: Array<string>,
    hash: string,
src/dataTypes.ts:25
Before
25
26
27
28
29

export type BranchInfo = {
  files: Array<string>,
  patches: Array<any>
}
After
25
26
27
28
29
src/flatFiles.ts:1
Before
1
2
3
4
5
6
7
import repos from &#39;./repos.ts&#39;
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,
After
1
2
3
4
5
6
7
import { type Repository } from &quot;./dataTypes.ts&quot;
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,
src/flatPatches.ts:1
Before
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,
        }
      })
After
1
2
3
4
5
6
7
8
9
10
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
src/repos.ts:1
Before
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&#39;

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&lt;BranchInfoTuple&gt; => {
      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
After
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
  type ReposConfiguration,
import { type Repository} from './dataTypes.ts'
import { addBranchToCommitsMap } from './vcses/git/operations.ts'
  return repoConfig.branchesToPull.map((branch) =&gt; {
    if (typeof branch === "string") {
      return branch
    }
    else {
      return "" // todo
    }
  })
const repos: (reposConfig: ReposConfiguration) => Promise<Array&lt;Repository&gt;> = async (reposConfig) => {
  const repos: Array<Repository> = []

  for (const repoName of repoNames) {
    const commits: Repository[&#39;commits&#39;] = 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
src/vcses/git/operations.ts:38
Before
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'][&#39;get&#39;]&gt;[&#39;diffs'],
  }&gt; = new Map()
After
38
39
40
41
42
43
44
45
46
47
export const addBranchToCommitsMap = async(branchName: string, repoLocation: string, commits: Repository['commits']): Promise&lt;void> => {
src/vcses/git/operations.ts:62
Before
62
After
62

      // exit early if the commits map already includes this hash
      if (commits.has(hash)) {
        break
      }
src/vcses/git/operations.ts:75
Before
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) => {
After
75
76
77
78
79
80
81
82
83
84
85
86
      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) => {
src/vcses/operations.ts:2
Before
2
3
import {type BranchInfo} from '../dataTypes.ts'
    getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<BranchInfo[&#39;files&#39;]>,
After
2
3
    getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<Array&lt;string&gt;>,
templates/files.njk:1
Before
1
    {% set files = repos[branchInfo.repoName].branches[branchInfo.branchName].files | topLevelFilesOnly('') %}
After
1
    {% set files = currentBranch.fileList | topLevelFilesOnly('') %}
templates/index.njk:1
Before
1
2
{% for repoName, options in repos %}
  <li><a href="{{reposPath}}/{{repoName | slugify}}/branches/{{reposConfig.repos[repoName].defaultBranch}}">{{repoName}}</a></li>
After
1
2
{% for repo in repos %}
  <li><a href="{{reposPath}}/{{repo.name | slugify}}/branches/{{reposConfig.repos[repo.name].defaultBranch}}">{{repo.name}}</a></li>
templates/repo.njk:15
Before
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 %}
After
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29