Change feed.njk to a typescript template

14e3d38c967898d3811831bdf23b9108575439aa

Tucker McKnight <tucker@pangolin.lan> | Sat Jan 03 2026

Change feed.njk to a typescript template

This is the last njk template that needed to be changed over.

Several changes have been made to this template. First, the RSS
plugin isn't expected to be provided by the parent 11ty site anymore.
Instead, this plugin will require the RSS plugin itself.

The dateToRfc3339 function is therefore being imported directly,
instead of being looked for as an eleventyConfig filter.

Some of the other functions dealing with absolute URLs are no longer
being used. This is using its own baseUrl value instead. (May want
to revisit this later, but let's just use baseUrl for now.)
js_templates/feed.ts:0
Before






































⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
After
-1
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
import _ from 'lodash'
import { type Repository } from '../src/dataTypes.ts'
import branches from '../src/branches.ts'
import { dateToRfc3339 } from '@11ty/eleventy-plugin-rss'
import flatPatches from '../src/flatPatches.ts'

export default async (
  eleventyConfig: any,
) => {
  return (data) => {
    const branch: ReturnType<typeof branches>[0] = data.branch
    const currentRepo: Repository = data.currentRepo
    const currentBranch: Repository['branches'][0] = data.currentBranch
    const currentBranchCommits: Awaited<ReturnType<typeof flatPatches>> = data.currentBranchCommits

    const slugify = eleventyConfig.getFilter("slugify")

    return `<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Latest patches in ${branch.branchName}</title>
<link href="${ data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName) + '/commits.xml'}" rel="self" />
<link href="${data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName)}" />
<updated>${dateToRfc3339(currentRepo.commits.get(currentBranch.head).date)}</updated>
<id>${data.reposConfig.baseUrl}</id>
  <author>
    <name>${_.escape(currentRepo.name)} contributors</name>
  </author>
  ${currentBranchCommits.map((commit) => {
    const commitUrl = data.reposConfig.baseUrl + '/repos/' + slugify(branch.repoName) + '/branches/' + slugify(branch.branchName) + '/commits/' + commit.commit.hash
  return `<entry>
    <title>${_.escape(commit.commit.message.split('\n')[0])}</title>
    <author><name>${_.escape(commit.commit.author)}</name></author>
    <link href="${commitUrl}" />
    <updated>${dateToRfc3339(commit.commit.date)}</updated>
    <id>${commitUrl}</id>
    <content type="text">${_.escape(commit.commit.message)}</content>
  </entry>`
  })}
</feed>`
  }
}
main.ts:21
Before
20
21
22
23

24
import indexJsTemplate from './js_templates/index.ts'
import branchesJsTemplate from './js_templates/branches.ts'
import rawJsTemplate from './js_templates/raw.ts'

⁣
const ajv = new Ajv()
const exec = util.promisify(childProcess.exec)
After
20
21
22
23
24
25
import indexJsTemplate from './js_templates/index.ts'
import branchesJsTemplate from './js_templates/branches.ts'
import rawJsTemplate from './js_templates/raw.ts'
import feedJsTemplate from './js_templates/feed.ts'

const ajv = new Ajv()
const exec = util.promisify(childProcess.exec)
main.ts:498
Before
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535

536






537
    }
  )

  // FEED.NJK
  // htmlBaseUrl is a function defined by the 11ty RSS plugin.
  // Skip this virtual template if the 11ty RSS plugin is not being used.
  let rssAvailable = false
  // 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,
  //     }
  //   )
  // }

⁣
  // This is used to show/hide the RSS feed link on the landing page.
⁣
⁣
⁣
⁣
⁣
⁣
  eleventyConfig.addGlobalData('rssAvailable', rssAvailable)
}
After
497
498
499
500






501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523




524

525

526
527
528
529
530
531
532
    }
  )

  // FEED.TS
⁣
⁣
⁣
⁣
⁣
⁣
  eleventyConfig.addTemplate(
    `repos/feed.11ty.js`,
    feedJsTemplate(eleventyConfig),
    {
      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)}/commits.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
        }),
⁣
⁣
⁣
⁣
        currentBranchCommits: (data) => {          return flatPatchesData.filter((patch) => {
⁣
            return patch.branchName === data.branch.branchName
          })
        }
      },
      eleventyExcludeFromCollections: true,
    }
  )
}
make.sh:6
Before
5
6
7
8
9
10
mkdir -p dist/img
cp frontend/top.js dist/frontend/top.js
cp -r frontend/img dist/frontend/img
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
cp -r vendor dist/
After
5
6
7


8
mkdir -p dist/img
cp frontend/top.js dist/frontend/top.js
cp -r frontend/img dist/frontend/img
⁣
⁣
cp -r vendor dist/
package-lock.json:9
Before
8
9
10

11
12
      "version": "0.0.1-alpha.1",
      "license": "ISC",
      "dependencies": {
⁣
        "ajv": "^8.17.1",
        "diff": "^8.0.2",
        "lodash": "^4.17.21"
After
8
9
10
11
12
13
      "version": "0.0.1-alpha.1",
      "license": "ISC",
      "dependencies": {
        "@11ty/eleventy-plugin-rss": "^2.0.4",
        "ajv": "^8.17.1",
        "diff": "^8.0.2",
        "lodash": "^4.17.21"
package-lock.json:24
Before
23
24
25









































26
27
        "webpack-cli": "^6.0.1"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/@discoveryjs/json-ext": {
      "version": "0.6.3",
      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz",
After
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
        "webpack-cli": "^6.0.1"
      }
    },
    "node_modules/@11ty/eleventy-plugin-rss": {
      "version": "2.0.4",
      "resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-rss/-/eleventy-plugin-rss-2.0.4.tgz",
      "integrity": "sha512-LF60sGVlxGTryQe3hTifuzrwF8R7XbrNsM2xfcDcNMSliLN4kmB+7zvoLRySRx0AQDjqhPTAeeeT0ra6/9zHUQ==",
      "dependencies": {
        "@11ty/eleventy-utils": "^2.0.0",
        "@11ty/posthtml-urls": "^1.0.1",
        "debug": "^4.4.0",
        "posthtml": "^0.16.6"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/11ty"
      }
    },
    "node_modules/@11ty/eleventy-utils": {
      "version": "2.0.7",
      "resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-2.0.7.tgz",
      "integrity": "sha512-6QE+duqSQ0GY9rENXYb4iPR4AYGdrFpqnmi59tFp9VrleOl0QSh8VlBr2yd6dlhkdtj7904poZW5PvGr9cMiJQ==",
      "engines": {
        "node": ">=18"
      },
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/11ty"
      }
    },
    "node_modules/@11ty/posthtml-urls": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/@11ty/posthtml-urls/-/posthtml-urls-1.0.2.tgz",
      "integrity": "sha512-0vaV3Wt0surZ+oS1VdKKe0axeeupuM+l7W/Z866WFQwF+dGg2Tc/nmhk/5l74/Y55P8KyImnLN9CdygNw2huHg==",
      "dependencies": {
        "evaluate-value": "^2.0.0",
        "http-equiv-refresh": "^2.0.1",
        "list-to-array": "^1.1.0",
        "parse-srcset": "^1.0.2"
      },
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/@discoveryjs/json-ext": {
      "version": "0.6.3",
      "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.6.3.tgz",
package-lock.json:1054
Before
1053
1054
1055
















1056
1057
        "node": ">= 8"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/detect-libc": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
After
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
        "node": ">= 8"
      }
    },
    "node_modules/debug": {
      "version": "4.4.3",
      "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
      "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
      "dependencies": {
        "ms": "^2.1.3"
      },
      "engines": {
        "node": ">=6.0"
      },
      "peerDependenciesMeta": {
        "supports-color": {
          "optional": true
        }
      }
    },
    "node_modules/detect-libc": {
      "version": "1.0.3",
      "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
package-lock.json:1076
Before
1075
1076
1077



























































1078
1079
        "node": ">=0.3.1"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/eastasianwidth": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
After
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
        "node": ">=0.3.1"
      }
    },
    "node_modules/dom-serializer": {
      "version": "1.4.1",
      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
      "integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
      "dependencies": {
        "domelementtype": "^2.0.1",
        "domhandler": "^4.2.0",
        "entities": "^2.0.0"
      },
      "funding": {
        "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
      }
    },
    "node_modules/dom-serializer/node_modules/entities": {
      "version": "2.2.0",
      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
      }
    },
    "node_modules/domelementtype": {
      "version": "2.3.0",
      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
      "funding": [
        {
          "type": "github",
          "url": "https://github.com/sponsors/fb55"
        }
      ]
    },
    "node_modules/domhandler": {
      "version": "4.3.1",
      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
      "integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
      "dependencies": {
        "domelementtype": "^2.2.0"
      },
      "engines": {
        "node": ">= 4"
      },
      "funding": {
        "url": "https://github.com/fb55/domhandler?sponsor=1"
      }
    },
    "node_modules/domutils": {
      "version": "2.8.0",
      "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
      "integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
      "dependencies": {
        "dom-serializer": "^1.0.1",
        "domelementtype": "^2.2.0",
        "domhandler": "^4.2.0"
      },
      "funding": {
        "url": "https://github.com/fb55/domutils?sponsor=1"
      }
    },
    "node_modules/eastasianwidth": {
      "version": "0.2.0",
      "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
package-lock.json:1192
Before
1191
1192
1193








1194
1195
        "node": ">=4.0"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/events": {
      "version": "3.3.0",
      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
After
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
        "node": ">=4.0"
      }
    },
    "node_modules/evaluate-value": {
      "version": "2.0.0",
      "resolved": "https://registry.npmjs.org/evaluate-value/-/evaluate-value-2.0.0.tgz",
      "integrity": "sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ==",
      "engines": {
        "node": ">= 8"
      }
    },
    "node_modules/events": {
      "version": "3.3.0",
      "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
package-lock.json:1355
Before
1354
1355
1356





































1357
1358
        "node": ">= 0.4"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/immutable": {
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
After
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
        "node": ">= 0.4"
      }
    },
    "node_modules/htmlparser2": {
      "version": "7.2.0",
      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
      "integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
      "funding": [
        "https://github.com/fb55/htmlparser2?sponsor=1",
        {
          "type": "github",
          "url": "https://github.com/sponsors/fb55"
        }
      ],
      "dependencies": {
        "domelementtype": "^2.0.1",
        "domhandler": "^4.2.2",
        "domutils": "^2.8.0",
        "entities": "^3.0.1"
      }
    },
    "node_modules/htmlparser2/node_modules/entities": {
      "version": "3.0.1",
      "resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
      "integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
      "engines": {
        "node": ">=0.12"
      },
      "funding": {
        "url": "https://github.com/fb55/entities?sponsor=1"
      }
    },
    "node_modules/http-equiv-refresh": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/http-equiv-refresh/-/http-equiv-refresh-2.0.1.tgz",
      "integrity": "sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw==",
      "engines": {
        "node": ">= 6"
      }
    },
    "node_modules/immutable": {
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
package-lock.json:1440
Before
1439
1440
1441





1442
1443
        "node": ">=0.10.0"
      }
    },
⁣
⁣
⁣
⁣
⁣
    "node_modules/is-number": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
After
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
        "node": ">=0.10.0"
      }
    },
    "node_modules/is-json": {
      "version": "2.0.1",
      "resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
      "integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA=="
    },
    "node_modules/is-number": {
      "version": "7.0.0",
      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
package-lock.json:1554
Before
1553
1554
1555





1556
1557
        "uc.micro": "^2.0.0"
      }
    },
⁣
⁣
⁣
⁣
⁣
    "node_modules/loader-runner": {
      "version": "4.3.1",
      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
After
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
        "uc.micro": "^2.0.0"
      }
    },
    "node_modules/list-to-array": {
      "version": "1.1.0",
      "resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz",
      "integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g=="
    },
    "node_modules/loader-runner": {
      "version": "4.3.1",
      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.1.tgz",
package-lock.json:1692
Before
1691
1692
1693





1694
1695
        "node": ">=16 || 14 >=14.17"
      }
    },
⁣
⁣
⁣
⁣
⁣
    "node_modules/neo-async": {
      "version": "2.6.2",
      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
After
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
        "node": ">=16 || 14 >=14.17"
      }
    },
    "node_modules/ms": {
      "version": "2.1.3",
      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
      "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
    },
    "node_modules/neo-async": {
      "version": "2.6.2",
      "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
package-lock.json:1767
Before
1766
1767
1768





1769
1770
      "dev": true,
      "license": "BlueOak-1.0.0"
    },
⁣
⁣
⁣
⁣
⁣
    "node_modules/path-exists": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
After
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
      "dev": true,
      "license": "BlueOak-1.0.0"
    },
    "node_modules/parse-srcset": {
      "version": "1.0.2",
      "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
      "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q=="
    },
    "node_modules/path-exists": {
      "version": "4.0.0",
      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
package-lock.json:1843
Before
1842
1843
1844


































1845
1846
        "node": ">=8"
      }
    },
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
    "node_modules/punycode.js": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
After
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
        "node": ">=8"
      }
    },
    "node_modules/posthtml": {
      "version": "0.16.7",
      "resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.7.tgz",
      "integrity": "sha512-7Hc+IvlQ7hlaIfQFZnxlRl0jnpWq2qwibORBhQYIb0QbNtuicc5ZxvKkVT71HJ4Py1wSZ/3VR1r8LfkCtoCzhw==",
      "dependencies": {
        "posthtml-parser": "^0.11.0",
        "posthtml-render": "^3.0.0"
      },
      "engines": {
        "node": ">=12.0.0"
      }
    },
    "node_modules/posthtml-parser": {
      "version": "0.11.0",
      "resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
      "integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
      "dependencies": {
        "htmlparser2": "^7.1.1"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/posthtml-render": {
      "version": "3.0.0",
      "resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
      "integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
      "dependencies": {
        "is-json": "^2.0.1"
      },
      "engines": {
        "node": ">=12"
      }
    },
    "node_modules/punycode.js": {
      "version": "2.3.1",
      "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
package.json:27
Before
26
27
28

29
30
    "webpack-cli": "^6.0.1"
  },
  "dependencies": {
⁣
    "ajv": "^8.17.1",
    "diff": "^8.0.2",
    "lodash": "^4.17.21"
After
26
27
28
29
30
31
    "webpack-cli": "^6.0.1"
  },
  "dependencies": {
    "@11ty/eleventy-plugin-rss": "^2.0.4",
    "ajv": "^8.17.1",
    "diff": "^8.0.2",
    "lodash": "^4.17.21"
partial_templates/main_bottom.njk:1
Before
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
        </div>
      </div>
    </div>
    <script>
      const toggleUnifiedMode = (e) => {
        const diffs = document.getElementById('diffs')
        const afterDiffs = document.querySelectorAll('.diff-right')
        if (e.checked) {
          diffs.classList.add("unified")
          afterDiffs.forEach((elem) => {
            elem.classList.remove('border-start', 'ps-2')
          })
        }
        else {
          diffs.classList.remove("unified")
          afterDiffs.forEach((elem) => {
            elem.classList.add('border-start', 'ps-2')
          })
        }
      }

      const selectBranch = (e) => {
        const values = e.value.split(",")
        window.location = `{{reposPath}}/${values[0]}/branches/${values[1]}/${values[2]}`
      }
    </script>
    <script src="{{reposPath}}/frontend/main-frontend.bundle.js"></script>
  </body>
</html>
After


























⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
partial_templates/main_top.njk:1
Before
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
93
94
95
96
97
98
99
100
<!DOCTYPE html>
<html>
  <head>
    <title>{% if nav.title %}{{nav.title}}{% else %}Repositories{% endif %}</title>
    <script>
      window.jsVars = {};
    
      {% if nav %}
        window.jsVars['baseUrl'] = `{{ repoConfig.repos[nav.repoName].baseUrl | jsonStringify | safe }}`;
    
        window.jsVars['nav'] = {{nav | jsonStringify | safe}};
    
        window.jsVars['cloneDiv'] = `<label class="form-label">HTTPS URL</label>
<div class="input-group d-flex flex-nowrap">
  <span class="clone overflow-hidden input-group-text">
    {% set url = currentRepo.cloneUrl %}
    {{ url }}
  </span>
  <button data-clone-url="{{url}}" class="btn btn-primary" id="clone-button">Copy</button>
</div>`;
    
      {% endif %}
    </script>
    <script src="{{reposPath}}/frontend/top.js"></script>
    <link rel="stylesheet" id="prism-theme" type="text/css" href="{{reposPath}}/vendor/prism.css" />
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-SgOJa3DmI69IUzQ2PVdRZhwQ+dy64/BUtbMJw1MZ8t5HZApcHrRKUc4W0kG879m7" crossorigin="anonymous">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.6/dist/js/bootstrap.bundle.min.js" integrity="sha384-j1CDi7MgGQ12Z7Qab0qlWQ/Qqz24Gc6BM0thvEMVjHnfYGF0rmFCozFSxQBxwHKO" crossorigin="anonymous"></script>
    <link rel="stylesheet" type="text/css" href="{{reposPath}}/vendor/main.css" />
    <meta name="viewport" content="width=device-width, initial-scale=1">
  </head>

  <body>
    <div class="container-lg">
      <div class="row pt-5">
        <div class="col">
          <header>
            <div class="row d-flex justify-content-between pb-3">
              <div class="col-auto">
                <nav class="fs-4">
                  <a href="{% if reposPath == "" %}/{% else %}{{reposPath}}{% endif %}">Repositories</a>{% if nav.repoName %}<span class="text-secondary mx-2">&gt;</span><a href="{{reposPath}}/{{nav.repoName | slugify}}/branches/{{reposConfig.repos[nav.repoName].defaultBranch | slugify}}">{{nav.repoName}}</a>{% endif %}
                </nav>
              </div>
              <div class="col-auto d-flex align-items-center">
                <div class="dropdown">
                  <button class="dropdown-toggle btn" id="dark-mode-switch" type="button" data-bs-toggle="dropdown" aria-expanded="false">
                    <i class="bi bi-brightness-high"></i>
                  </button>
                  <ul class="dropdown-menu">
                    <li><button class="btn" data-theme-pref="light" onclick="toggleDarkMode(this)"><i class="bi bi-brightness-high mx-1"></i>Light</button></li>
                    <li><button class="btn" data-theme-pref="dark" onclick="toggleDarkMode(this)"><i class="bi bi-moon mx-1"></i>Dark</button></li>
                    <li><button class="btn" data-theme-pref="auto" onclick="toggleDarkMode(this)"><i class="bi bi-yin-yang mx-1"></i>Auto</button></li>
                  </ul>
                </div>
              </div>
            </div>
            {% if nav.repoName %}
            <div class="row mb-4">
              <div class="col-12 col-md order-2 order-md-1 pe-0">
                <nav class="nav-tabs">
                  <ul class="nav">
                    <li class="nav-item">
                      <a class="nav-link {% if navTab == "landing" %}active{% endif %}" href="{{reposPath}}/{{nav.repoName | slugify}}/branches/{{nav.branchName | slugify}}">Landing Page</a>
                    </li>
                    <li class="nav-item">
                      <a class="nav-link {% if navTab == "files" %}active{% endif %}" href="{{reposPath}}/{{nav.repoName | slugify}}/branches/{{nav.branchName | slugify}}/files">Files</a>
                    </li>
                    <li class="nav-item">
                      <a class="nav-link {% if navTab == "patches" %}active{% endif %}" href="{{reposPath}}/{{nav.repoName | slugify}}/branches/{{nav.branchName | slugify}}/patches/page1">Changes</a>
                    </li>
                    <li class="nav-item">
                      <a class="nav-link {% if navTab == "branches" %}active{% endif %}" href="{{reposPath}}/{{nav.repoName | slugify}}/branches/{{nav.branchName | slugify}}/list">Branches</a>
                    </li>
                  </ul>
                </nav>
              </div>
              <div class="col-12 col-md-auto order-1 order-md-2 pb-2 pb-md-0 mb-2 mb-md-0 border-bottom">
                <div class="row">
                  <div class="col-auto px-2">
                    <button type="button" id="clone-popover-btn" class="btn btn-sm btn-primary" data-bs-toggle="popover" data-bs-placement="bottom">Clone <i class="bi bi-caret-down-fill"></i></button>
                  </div>
                  <div class="col-auto px-2">
                    <div class="input-group input-group-sm">
                      <span class="input-group-text">Branch</span>
                      <select class="form-select" onchange="selectBranch(this)" aria-label="Repository branch selector">
                        {% for branch in currentRepo.branches %}
                        <option value="{{currentRepo.name | slugify}},{{branch.name | slugify}},{{nav.path}}" {% if branch.name == nav.branchName %}selected{% endif %}>{{branch.name}}</option>
                        {% endfor %}
                      </select>
                    </div>
                  </div>
                </div>
              </div>
            </div>
            {% endif %}
          </header>
        </div>
      </div>
    </div>
    <div class="container-{% if width == "full"%}fluid{% else %}lg{% endif %}">
      <div class="row">
        <div class="col">
After



































































































⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
templates/feed.njk:1
Before
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="{{ page.lang }}">
  <title>Latest patches in {{branch.branchName}}</title>
  <link href="{{ ('/repos/' + (branch.repoName | slugify) + '/branches/' + (branch.branchName | slugify) + '/patches.xml')| htmlBaseUrl(reposConfig.baseUrl) }}" rel="self" />
  <link href="{{ ('/repos/' + (branch.repoName | slugify) + '/branches/' + (branch.branchName | slugify)) | htmlBaseUrl(reposConfig.baseUrl) }}" />
  {% set lastPatch = repos[branch.repoName].branches[branch.branchName].patches | last %}
  <updated>{{ lastPatch.date | toDateObj | dateToRfc3339 }}</updated>
  <id>{{ reposConfig.baseUrl | addPathPrefixToFullUrl }}</id>
  <author>
    <name>{{branch.repoName}} contributors</name>
  </author>
  {%- for patch in repos[branch.repoName].branches[branch.branchName].patches | reverse %}
  {%- set absolutePostUrl %}{{ ('/repos/' + (branch.repoName | slugify) + '/branches/' + (branch.branchName | slugify) + '/patches/' + patch.hash) | htmlBaseUrl(reposConfig.baseUrl) }}{% endset %}
  <entry>
    <title>{{ patch.name }}</title>
    <author><name>{{ patch.author }}</name></author>
    <link href="{{ absolutePostUrl }}" />
    <updated>{{ patch.date | toDateObj | dateToRfc3339 }}</updated>
    <id>{{ absolutePostUrl }}</id>
    <content type="html">{{ patch.description | renderTransforms({}, reposConfig.baseUrl) }}</content>
  </entry>
  {%- endfor %}
</feed>
After




















⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣
⁣