Tucker McKnight
wip: moving from separate site repo to plugin
0
0
dist
node_modules
0
0
import fsImport from 'fs'
import util from 'util'
import childProcess from 'child_process'
import repos from './src/repos.ts'
import branches from './src/branches.ts'
import flatFiles from './src/flatFiles.ts'
import {getLocation} from './src/helpers.ts'
import repoOperations from './src/vcses/operations.ts'
const exec = util.promisify(childProcess.exec)
export default async (eleventyConfig, reposConfiguration) => {
// TODO: check if the render plugin is available and throw an error otherwise
// TODO: check if the highlight function is available
// TODO: throw an error if reposConfiguration is undefined
const reposData = await repos(reposConfiguration)
eleventyConfig.addFilter("getFileName", (filePath) => {
const pathParts = filePath.split("/")
return pathParts[pathParts.length - 1]
})
eleventyConfig.addFilter("getDirectoryContents", (repo, branch, dirPath) => {
return reposData[repo].branches[branch].files.filter(file => file.startsWith(dirPath) && file !== dirPath)
})
eleventyConfig.addFilter("getRelativePath", (currentDir, fullFilePath) => {
return fullFilePath.replace(`${currentDir}/`, "")
})
eleventyConfig.addFilter("lineNumbers", (code) => {
const numLines = code.split('\n').length
const lineNumbers = []
for (let i = 1; i <= numLines; i++) {
lineNumbers.push(i)
}
return lineNumbers
})
eleventyConfig.addFilter("highlightCode", (code, language) => {
return eleventyConfig.javascript.functions.highlight(language, code)
})
eleventyConfig.addFilter("languageExtension", (filename, repoName) => {
let extension = filename.split(".")
extension = extension[extension.length - 1]
const extensionsConfig = reposConfiguration.repos[repoName].languageExtensions
return extensionsConfig && extensionsConfig[extension] ? extensionsConfig[extension] : extension
})
eleventyConfig.addFilter("topLevelFilesOnly", (files, currentLevel) => {
const onlyUnique = (value, index, array) => {
return array.findIndex(test => test.name === value.name) === index;
}
const currentLevelDirLength = currentLevel.split('/').length
const topLevels: Array<string> = []
files.forEach((file) => {
if (file.startsWith(currentLevel)) {
const parts = file.split("/").filter(part => part !== ".")
topLevels.push(parts.slice(0, currentLevelDirLength).join('/'))
}
})
const withNameAndDirAttrs = topLevels.map((file) => {
// is a directory if the entire filename, plus a slash, is contained inside of any
// other file
const isDirectory: boolean = files.some((testFile) => {
return testFile.startsWith(file + '/') && (testFile !== file)
})
return {name: file.replace(currentLevel, ''), fullPath: file, isDirectory}
})
const sortedByDirectory = withNameAndDirAttrs.filter(onlyUnique).toSorted((a, b) => {
if (a.isDirectory && b.isDirectory) {
return 0
}
if (a.isDirectory && !b.isDirectory) {
return -1
}
return 1
})
return sortedByDirectory
})
eleventyConfig.addAsyncFilter("getFileLastTouchInfo", async (repo, branch, filename) => {
const ignoreExtensions = ['.png', '.jpg']
if (ignoreExtensions.some(extension => filename.endsWith(extension))) {
return ""
}
const config = reposConfiguration.repos[repo]
const location = getLocation(reposConfiguration, branch, repo)
return repoOperations[config._type].getFileLastTouchInfo(repo, branch, filename, location)
})
eleventyConfig.addAsyncFilter("isDirectory", async(filename, repoName, branchName) => {
const files = reposData[repoName].branches[branchName].files
const isDirectory = files.some((testFile) => {
return testFile.startsWith(filename + '/') && (testFile !== filename)
})
return isDirectory
})
eleventyConfig.addAsyncFilter("getFileContents", async (repo, branch, filename) => {
const location = getLocation(reposConfiguration, branch, repo)
let command = ''
const config = reposConfiguration.repos[repo]
if (config._type === "git") {
command = `git show ${branch}:${filename}`
}
else if (config._type === "darcs") {
command = `darcs show contents ${filename}`
}
const res = await exec(`(cd ${location} && ${command})`)
return res.stdout
})
eleventyConfig.addAsyncFilter("getReadMe", async (repoName, branchName) => {
const location = getLocation(reposConfiguration, branchName, repoName)
const config = reposConfiguration.repos[repoName]
let command = ''
if (config._type === "git") {
command = `git show ${branchName}:README.md`
}
else if (config._type === "darcs") {
command = `darcs show contents README.md`
}
try {
const res = await exec(`(cd ${location} && ${command})`)
return res.stdout
} catch {
return ""
}
})
eleventyConfig.addFilter("jsonStringify", data => JSON.stringify(data))
const topLayoutPartial = fsImport.readFileSync(`${__dirname}/partial_templates/main_top.njk`).toString()
const bottomLayoutPartial = fsImport.readFileSync(`${__dirname}/partial_templates/main_bottom.njk`).toString()
// INDEX.NJK
const indexTemplate = fsImport.readFileSync(`${__dirname}/templates/index.njk`).toString()
eleventyConfig.addTemplate(
'repos/index.njk',
topLayoutPartial + indexTemplate + bottomLayoutPartial,
{
permalink: "repos/index.html",
}
)
// BRANCHES.NJK
const branchesTemplate = fsImport.readFileSync(`${__dirname}/templates/branches.njk`).toString()
const branchesData = branches(reposData)
eleventyConfig.addTemplate(
'repos/branches.njk',
topLayoutPartial + branchesTemplate + bottomLayoutPartial,
{
pagination: {
data: "branches",
size: 1,
alias: "branchInfo",
},
branches: branchesData,
permalink: (data) => {
const repoName = data.branchInfo.repoName
const branchName = data.branchInfo.branchName
return `repos/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/list/`
},
eleventyComputed: {
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
}
},
navTab: "branches",
}
)
// FILE.NJK
const fileTemplate = fsImport.readFileSync(`${__dirname}/templates/file.njk`).toString()
const flatFilesData = flatFiles(reposData)
eleventyConfig.addTemplate(
'repos/file.njk',
topLayoutPartial + fileTemplate + bottomLayoutPartial,
{
pagination: {
data: "flatFiles",
size: 1,
alias: "fileInfo",
},
flatFiles: flatFilesData,
permalink: (data) => {
const repoName = data.fileInfo.repoName
const branchName = data.fileInfo.branchName
return `repos/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/files/${eleventyConfig.getFilter("slugify")(data.fileInfo.file)}.html`
},
eleventyComputed: {
nav: {
repoName: (data) => data.fileInfo.repoName,
branchName: (data) => data.fileInfo.branchName,
}
},
navTab: "files",
}
)
// FILES.NJK
const filesTemplate = fsImport.readFileSync(`${__dirname}/templates/files.njk`).toString()
eleventyConfig.addTemplate(
'repos/files.njk',
topLayoutPartial + filesTemplate + bottomLayoutPartial,
{
pagination: {
data: "branches",
size: 1,
alias: "branchInfo",
},
branches: branchesData,
permalink: (data) => {
const repoName = data.branchInfo.repoName
const branchName = data.branchInfo.branchName
return `repos/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/files/`
},
eleventyComputed: {
nav: {
repoName: (data) => data.branchInfo.repoName,
branchName: (data) => data.branchInfo.branchName,
}
},
navTab: "files",
}
)
// REPO.NJK
const repoTemplate = fsImport.readFileSync(`${__dirname}/templates/repo.njk`).toString()
eleventyConfig.addTemplate(
'repos/repo.njk',
topLayoutPartial + repoTemplate + bottomLayoutPartial,
{
pagination: {
data: "branches",
size: 1,
alias: "branch",
},
branches: branchesData,
permalink: (data) => {
const repoName = data.branch.repoName
const branchName = data.branch.branchName
return `repos/${eleventyConfig.getFilter("slugify")(repoName)}/branches/${eleventyConfig.getFilter("slugify")(branchName)}/`
},
eleventyComputed: {
nav: {
repoName: (data) => data.branch.repoName,
branchName: (data) => data.branch.branchName,
}
},
navTab: "landing",
}
)
eleventyConfig.addGlobalData("repos", reposData)
eleventyConfig.addGlobalData("reposConfig", reposConfiguration)
}
0
0
#!/bin/bash
rm -R dist
mkdir dist
mkdir dist/templates
mkdir dist/partial_templates
cp templates/*.njk dist/templates
cp partial_templates/*.njk dist/partial_templates
0
0
{
"name": "eleventy-plugin",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "eleventy-plugin",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"diff": "^8.0.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"@types/node": "^24.0.7",
"typescript": "^5.8.3"
}
},
"node_modules/@11ty/dependency-tree": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@11ty/dependency-tree/-/dependency-tree-4.0.0.tgz",
"integrity": "sha512-PTOnwM8Xt+GdJmwRKg4pZ8EKAgGoK7pedZBfNSOChXu8MYk2FdEsxdJYecX4t62owpGw3xK60q9TQv/5JI59jw==",
"license": "MIT",
"dependencies": {
"@11ty/eleventy-utils": "^2.0.1"
}
},
"node_modules/@11ty/dependency-tree-esm": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/@11ty/dependency-tree-esm/-/dependency-tree-esm-2.0.0.tgz",
"integrity": "sha512-+4ySOON4aEAiyAGuH6XQJtxpGSpo6nibfG01krgix00sqjhman2+UaDUopq6Ksv8/jBB3hqkhsHe3fDE4z8rbA==",
"license": "MIT",
"dependencies": {
"@11ty/eleventy-utils": "^2.0.1",
"acorn": "^8.14.0",
"dependency-graph": "^1.0.0",
"normalize-path": "^3.0.0"
}
},
"node_modules/@11ty/eleventy": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-3.1.2.tgz",
"integrity": "sha512-IcsDlbXnBf8cHzbM1YBv3JcTyLB35EK88QexmVyFdVJVgUU6bh9g687rpxryJirHzo06PuwnYaEEdVZQfIgRGg==",
"license": "MIT",
"dependencies": {
"@11ty/dependency-tree": "^4.0.0",
"@11ty/dependency-tree-esm": "^2.0.0",
"@11ty/eleventy-dev-server": "^2.0.8",
"@11ty/eleventy-plugin-bundle": "^3.0.6",
"@11ty/eleventy-utils": "^2.0.7",
"@11ty/lodash-custom": "^4.17.21",
"@11ty/posthtml-urls": "^1.0.1",
"@11ty/recursive-copy": "^4.0.2",
"@sindresorhus/slugify": "^2.2.1",
"bcp-47-normalize": "^2.3.0",
"chokidar": "^3.6.0",
"debug": "^4.4.1",
"dependency-graph": "^1.0.0",
"entities": "^6.0.1",
"filesize": "^10.1.6",
"gray-matter": "^4.0.3",
"iso-639-1": "^3.1.5",
"js-yaml": "^4.1.0",
"kleur": "^4.1.5",
"liquidjs": "^10.21.1",
"luxon": "^3.6.1",
"markdown-it": "^14.1.0",
"minimist": "^1.2.8",
"moo": "^0.5.2",
"node-retrieve-globals": "^6.0.1",
"nunjucks": "^3.2.4",
"picomatch": "^4.0.2",
"please-upgrade-node": "^3.2.0",
"posthtml": "^0.16.6",
"posthtml-match-helper": "^2.0.3",
"semver": "^7.7.2",
"slugify": "^1.6.6",
"tinyglobby": "^0.2.14"
},
"bin": {
"eleventy": "cmd.cjs"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/eleventy-dev-server": {
"version": "2.0.8",
"resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-2.0.8.tgz",
"integrity": "sha512-15oC5M1DQlCaOMUq4limKRYmWiGecDaGwryr7fTE/oM9Ix8siqMvWi+I8VjsfrGr+iViDvWcH/TVI6D12d93mA==",
"license": "MIT",
"dependencies": {
"@11ty/eleventy-utils": "^2.0.1",
"chokidar": "^3.6.0",
"debug": "^4.4.0",
"finalhandler": "^1.3.1",
"mime": "^3.0.0",
"minimist": "^1.2.8",
"morphdom": "^2.7.4",
"please-upgrade-node": "^3.2.0",
"send": "^1.1.0",
"ssri": "^11.0.0",
"urlpattern-polyfill": "^10.0.0",
"ws": "^8.18.1"
},
"bin": {
"eleventy-dev-server": "cmd.js"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/eleventy-plugin-bundle": {
"version": "3.0.6",
"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.6.tgz",
"integrity": "sha512-wlEIMa1SEe6HE6ZyREEnPQiTw72337a2MPkyn0D1IzrqHrKU9euB17mv27LnnnyKvMJamCCqtU0985F5yyDL8g==",
"license": "MIT",
"dependencies": {
"@11ty/eleventy-utils": "^2.0.2",
"debug": "^4.4.0",
"posthtml-match-helper": "^2.0.3"
},
"engines": {
"node": ">=18"
},
"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==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/lodash-custom": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz",
"integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==",
"license": "MIT",
"engines": {
"node": ">=14"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/11ty"
}
},
"node_modules/@11ty/posthtml-urls": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@11ty/posthtml-urls/-/posthtml-urls-1.0.1.tgz",
"integrity": "sha512-6EFN/yYSxC/OzYXpq4gXDyDMlX/W+2MgCvvoxf11X1z76bqkqFJ8eep5RiBWfGT5j0323a1pwpelcJJdR46MCw==",
"license": "MIT",
"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/@11ty/recursive-copy": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@11ty/recursive-copy/-/recursive-copy-4.0.2.tgz",
"integrity": "sha512-174nFXxL/6KcYbLYpra+q3nDbfKxLxRTNVY1atq2M1pYYiPfHse++3IFNl8mjPFsd7y2qQjxLORzIjHMjL3NDQ==",
"license": "ISC",
"dependencies": {
"errno": "^1.0.0",
"junk": "^3.1.0",
"maximatch": "^0.1.0",
"slash": "^3.0.0"
},
"engines": {
"node": ">=18"
}
},
"node_modules/@sindresorhus/slugify": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
"integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==",
"license": "MIT",
"dependencies": {
"@sindresorhus/transliterate": "^1.0.0",
"escape-string-regexp": "^5.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@sindresorhus/transliterate": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz",
"integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==",
"license": "MIT",
"dependencies": {
"escape-string-regexp": "^5.0.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@types/node": {
"version": "24.0.7",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.7.tgz",
"integrity": "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": "~7.8.0"
}
},
"node_modules/a-sync-waterfall": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
"license": "MIT"
},
"node_modules/acorn": {
"version": "8.15.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/anymatch/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
"license": "Python-2.0"
},
"node_modules/array-differ": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
"integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
"license": "MIT",
"dependencies": {
"array-uniq": "^1.0.1"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
"integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/asap": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
"license": "MIT"
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"license": "MIT"
},
"node_modules/bcp-47": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
"integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
"license": "MIT",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-alphanumerical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/bcp-47-match": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
"integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/bcp-47-normalize": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/bcp-47-normalize/-/bcp-47-normalize-2.3.0.tgz",
"integrity": "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==",
"license": "MIT",
"dependencies": {
"bcp-47": "^2.0.0",
"bcp-47-match": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/brace-expansion": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
},
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/commander": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
"license": "MIT",
"engines": {
"node": ">=14"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"license": "MIT"
},
"node_modules/debug": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
"license": "MIT",
"dependencies": {
"ms": "^2.1.3"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/dependency-graph": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
"integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==",
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/diff": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.2.tgz",
"integrity": "sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==",
"license": "BSD-3-Clause",
"engines": {
"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==",
"license": "MIT",
"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==",
"license": "BSD-2-Clause",
"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"
}
],
"license": "BSD-2-Clause"
},
"node_modules/domhandler": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
"license": "BSD-2-Clause",
"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==",
"license": "BSD-2-Clause",
"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/ee-first": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
"license": "MIT"
},
"node_modules/encodeurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/entities": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz",
"integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/errno": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/errno/-/errno-1.0.0.tgz",
"integrity": "sha512-3zV5mFS1E8/1bPxt/B0xxzI1snsg3uSCIh6Zo1qKg6iMw93hzPANk9oBFzSFBFrwuVoQuE3rLoouAUfwOAj1wQ==",
"license": "MIT",
"dependencies": {
"prr": "~1.0.1"
},
"bin": {
"errno": "cli.js"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
"license": "MIT"
},
"node_modules/escape-string-regexp": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/esm-import-transformer": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/esm-import-transformer/-/esm-import-transformer-3.0.5.tgz",
"integrity": "sha512-1GKLvfuMnnpI75l8c6sHoz0L3Z872xL5akGuBudgqTDPv4Vy6f2Ec7jEMKTxlqWl/3kSvNbHELeimJtnqgYniw==",
"license": "MIT",
"dependencies": {
"acorn": "^8.15.0"
}
},
"node_modules/esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"license": "BSD-2-Clause",
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
},
"engines": {
"node": ">=4"
}
},
"node_modules/etag": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"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==",
"license": "MIT",
"engines": {
"node": ">= 8"
}
},
"node_modules/extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==",
"license": "MIT",
"dependencies": {
"is-extendable": "^0.1.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
"license": "MIT",
"engines": {
"node": ">=12.0.0"
},
"peerDependencies": {
"picomatch": "^3 || ^4"
},
"peerDependenciesMeta": {
"picomatch": {
"optional": true
}
}
},
"node_modules/filesize": {
"version": "10.1.6",
"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
"integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
"license": "BSD-3-Clause",
"engines": {
"node": ">= 10.4.0"
}
},
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/finalhandler": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
"license": "MIT",
"dependencies": {
"debug": "2.6.9",
"encodeurl": "~2.0.0",
"escape-html": "~1.0.3",
"on-finished": "2.4.1",
"parseurl": "~1.3.3",
"statuses": "2.0.1",
"unpipe": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/finalhandler/node_modules/debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"license": "MIT",
"dependencies": {
"ms": "2.0.0"
}
},
"node_modules/finalhandler/node_modules/ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
"license": "MIT"
},
"node_modules/fresh": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz",
"integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/gray-matter": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"license": "MIT",
"dependencies": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
"section-matter": "^1.0.0",
"strip-bom-string": "^1.0.0"
},
"engines": {
"node": ">=6.0"
}
},
"node_modules/gray-matter/node_modules/argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"license": "MIT",
"dependencies": {
"sprintf-js": "~1.0.2"
}
},
"node_modules/gray-matter/node_modules/js-yaml": {
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"license": "MIT",
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"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"
}
],
"license": "MIT",
"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==",
"license": "BSD-2-Clause",
"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==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"license": "MIT",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/is-alphabetical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-alphanumerical": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
"license": "MIT",
"dependencies": {
"is-alphabetical": "^2.0.0",
"is-decimal": "^2.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-decimal": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/is-glob": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
},
"engines": {
"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==",
"license": "ISC"
},
"node_modules/is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"license": "MIT",
"engines": {
"node": ">=0.12.0"
}
},
"node_modules/iso-639-1": {
"version": "3.1.5",
"resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.5.tgz",
"integrity": "sha512-gXkz5+KN7HrG0Q5UGqSMO2qB9AsbEeyLP54kF1YrMsIxmu+g4BdB7rflReZTSTZGpfj8wywu6pfPBCylPIzGQA==",
"license": "MIT",
"engines": {
"node": ">=6.0"
}
},
"node_modules/js-yaml": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1"
},
"bin": {
"js-yaml": "bin/js-yaml.js"
}
},
"node_modules/junk": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/junk/-/junk-3.1.0.tgz",
"integrity": "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/kleur": {
"version": "4.1.5",
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/linkify-it": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
"license": "MIT",
"dependencies": {
"uc.micro": "^2.0.0"
}
},
"node_modules/liquidjs": {
"version": "10.21.1",
"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.21.1.tgz",
"integrity": "sha512-NZXmCwv3RG5nire3fmIn9HsOyJX3vo+ptp0yaXUHAMzSNBhx74Hm+dAGJvscUA6lNqbLuYfXgNavRQ9UbUJhQQ==",
"license": "MIT",
"dependencies": {
"commander": "^10.0.0"
},
"bin": {
"liquid": "bin/liquid.js",
"liquidjs": "bin/liquid.js"
},
"engines": {
"node": ">=14"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/liquidjs"
}
},
"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==",
"license": "MIT"
},
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/luxon": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.1.tgz",
"integrity": "sha512-RkRWjA926cTvz5rAb1BqyWkKbbjzCGchDUIKMCUvNi17j6f6j8uHGDV82Aqcqtzd+icoYpELmG3ksgGiFNNcNg==",
"license": "MIT",
"engines": {
"node": ">=12"
}
},
"node_modules/markdown-it": {
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
"license": "MIT",
"dependencies": {
"argparse": "^2.0.1",
"entities": "^4.4.0",
"linkify-it": "^5.0.0",
"mdurl": "^2.0.0",
"punycode.js": "^2.3.1",
"uc.micro": "^2.1.0"
},
"bin": {
"markdown-it": "bin/markdown-it.mjs"
}
},
"node_modules/markdown-it/node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/maximatch": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
"integrity": "sha512-9ORVtDUFk4u/NFfo0vG/ND/z7UQCVZBL539YW0+U1I7H1BkZwizcPx5foFv7LCPcBnm2U6RjFnQOsIvN4/Vm2A==",
"license": "MIT",
"dependencies": {
"array-differ": "^1.0.0",
"array-union": "^1.0.1",
"arrify": "^1.0.0",
"minimatch": "^3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/mdurl": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
"license": "MIT"
},
"node_modules/mime": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
"license": "MIT",
"bin": {
"mime": "cli.js"
},
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/mime-db": {
"version": "1.54.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
"license": "MIT",
"dependencies": {
"mime-db": "^1.54.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/minipass": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
"license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/moo": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
"license": "BSD-3-Clause"
},
"node_modules/morphdom": {
"version": "2.7.7",
"resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.7.tgz",
"integrity": "sha512-04GmsiBcalrSCNmzfo+UjU8tt3PhZJKzcOy+r1FlGA7/zri8wre3I1WkYN9PT3sIeIKfW9bpyElA+VzOg2E24g==",
"license": "MIT"
},
"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==",
"license": "MIT"
},
"node_modules/node-retrieve-globals": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-6.0.1.tgz",
"integrity": "sha512-j0DeFuZ/Wg3VlklfbxUgZF/mdHMTEiEipBb3q0SpMMbHaV3AVfoUQF8UGxh1s/yjqO0TgRZd4Pi/x2yRqoQ4Eg==",
"license": "MIT",
"dependencies": {
"acorn": "^8.14.1",
"acorn-walk": "^8.3.4",
"esm-import-transformer": "^3.0.3"
}
},
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/nunjucks": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz",
"integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
"license": "BSD-2-Clause",
"dependencies": {
"a-sync-waterfall": "^1.0.0",
"asap": "^2.0.3",
"commander": "^5.1.0"
},
"bin": {
"nunjucks-precompile": "bin/precompile"
},
"engines": {
"node": ">= 6.9.0"
},
"peerDependencies": {
"chokidar": "^3.3.0"
},
"peerDependenciesMeta": {
"chokidar": {
"optional": true
}
}
},
"node_modules/nunjucks/node_modules/commander": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
"license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/on-finished": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
"license": "MIT",
"dependencies": {
"ee-first": "1.1.1"
},
"engines": {
"node": ">= 0.8"
}
},
"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==",
"license": "MIT"
},
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"license": "MIT",
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/please-upgrade-node": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
"integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
"license": "MIT",
"dependencies": {
"semver-compare": "^1.0.0"
}
},
"node_modules/posthtml": {
"version": "0.16.6",
"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
"integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
"license": "MIT",
"dependencies": {
"posthtml-parser": "^0.11.0",
"posthtml-render": "^3.0.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/posthtml-match-helper": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/posthtml-match-helper/-/posthtml-match-helper-2.0.3.tgz",
"integrity": "sha512-p9oJgTdMF2dyd7WE54QI1LvpBIkNkbSiiECKezNnDVYhGhD1AaOnAkw0Uh0y5TW+OHO8iBdSqnd8Wkpb6iUqmw==",
"license": "MIT",
"engines": {
"node": ">=18"
},
"peerDependencies": {
"posthtml": "^0.16.6"
}
},
"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==",
"license": "MIT",
"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==",
"license": "MIT",
"dependencies": {
"is-json": "^2.0.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/prr": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
"license": "MIT"
},
"node_modules/punycode.js": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/range-parser": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": {
"node": ">=8.10.0"
}
},
"node_modules/readdirp/node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"license": "MIT",
"engines": {
"node": ">=8.6"
},
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
},
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"license": "MIT",
"dependencies": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/semver": {
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
"integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/semver-compare": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
"license": "MIT"
},
"node_modules/send": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz",
"integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==",
"license": "MIT",
"dependencies": {
"debug": "^4.3.5",
"encodeurl": "^2.0.0",
"escape-html": "^1.0.3",
"etag": "^1.8.1",
"fresh": "^2.0.0",
"http-errors": "^2.0.0",
"mime-types": "^3.0.1",
"ms": "^2.1.3",
"on-finished": "^2.4.1",
"range-parser": "^1.2.1",
"statuses": "^2.0.1"
},
"engines": {
"node": ">= 18"
}
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
"license": "ISC"
},
"node_modules/slash": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/slugify": {
"version": "1.6.6",
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
"license": "MIT",
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
"node_modules/ssri": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/ssri/-/ssri-11.0.0.tgz",
"integrity": "sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw==",
"license": "ISC",
"dependencies": {
"minipass": "^7.0.3"
},
"engines": {
"node": "^16.14.0 || >=18.0.0"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/tinyglobby": {
"version": "0.2.14",
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
"integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
"license": "MIT",
"dependencies": {
"fdir": "^6.4.4",
"picomatch": "^4.0.2"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"url": "https://github.com/sponsors/SuperchupuDev"
}
},
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
},
"engines": {
"node": ">=8.0"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"license": "MIT",
"engines": {
"node": ">=0.6"
}
},
"node_modules/typescript": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/uc.micro": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
"license": "MIT"
},
"node_modules/undici-types": {
"version": "7.8.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz",
"integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==",
"dev": true,
"license": "MIT"
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/urlpattern-polyfill": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.1.0.tgz",
"integrity": "sha512-IGjKp/o0NL3Bso1PymYURCJxMPNAf/ILOpendP9f5B6e1rTJgdgiOvgfoT8VxCAdY+Wisb9uhGaJJf3yZ2V9nw==",
"license": "MIT"
},
"node_modules/ws": {
"version": "8.18.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"engines": {
"node": ">=10.0.0"
},
"peerDependencies": {
"bufferutil": "^4.0.1",
"utf-8-validate": ">=5.0.2"
},
"peerDependenciesMeta": {
"bufferutil": {
"optional": true
},
"utf-8-validate": {
"optional": true
}
}
}
}
}
0
0
{
"name": "eleventy-plugin",
"version": "1.0.0",
"main": "dist/main.js",
"scripts": {
"build": "./make.sh && npx tsc"
},
"keywords": [],
"author": "",
"license": "ISC",
"description": "",
"devDependencies": {
"@types/node": "^24.0.7",
"typescript": "^5.8.3"
},
"dependencies": {
"@11ty/eleventy": "^3.1.2",
"diff": "^8.0.2",
"lodash": "^4.17.21"
}
}
0
0
</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 = `/repos/${values[0]}/branches/${values[1]}/${values[2]}`
}
</script>
<script src="/static/main.js"></script>
</body>
</html>
0
0
<!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'] = `{%- if reposConfig.repos[nav.repoName]._type == "darcs" -%}{% set url = repos[nav.repoName].cloneUrl + (nav.branchName | slugify) %}
<label class="form-label">HTTPS URL</label>
<div class="input-group d-flex flex-nowrap">
<span class="clone overflow-hidden input-group-text">
{{ url }}
</span>
<button data-clone-url="{{url}}" class="btn btn-primary" id="clone-button">Copy</button>
</div>{%- elif reposConfig.repos[nav.repoName]._type == "git" -%}<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 = repos[nav.repoName].cloneUrl %}
{{ url }}
</span>
<button data-clone-url="{{url}}" class="btn btn-primary" id="clone-button">Copy</button>
</div>
{%- endif -%}`;
{% endif %}
</script>
<script src="/static/top.js"></script>
<link rel="stylesheet" id="prism-theme" type="text/css" href="/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="/static/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="/">Repositories</a>{% if nav.repoName %}<span class="text-secondary mx-2">></span><a href="/repos/{{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="/repos/{{nav.repoName | slugify}}/branches/{{nav.branchName}}">Landing Page</a>
</li>
<li class="nav-item">
<a class="nav-link {% if navTab == "files" %}active{% endif %}" href="/repos/{{nav.repoName | slugify}}/branches/{{nav.branchName}}/files">Files</a>
</li>
<li class="nav-item">
<a class="nav-link {% if navTab == "patches" %}active{% endif %}" href="/repos/{{nav.repoName | slugify}}/branches/{{nav.branchName}}/patches/page1">Changes</a>
</li>
<li class="nav-item">
<a class="nav-link {% if navTab == "branches" %}active{% endif %}" href="/repos/{{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 branches %}
{% if branch.repoName == nav.repoName %}
<option value="{{branch.repoName | slugify}},{{branch.branchName | slugify}},{{nav.path}}" {% if branch.branchName == nav.branchName %}selected{% endif %}>{{branch.branchName}}</option>
{% endif %}
{% 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">
0
0
let cachedBranches = null
export default (repos) => {
if (cachedBranches !== null) { return cachedBranches }
cachedBranches = Object.keys(repos).flatMap((repoName) => {
return Object.keys(repos[repoName].branches).map((branchName) => {
return {
branchName,
repoName,
}
})
})
return cachedBranches
}
0
0
/**
* The ReposConfiguration object contains information about your local repositories,
* like their name and location on your local filesystem. Add repositories to this
* configuration object to make a static site for them.
*
* This static site generator works with both git and darcs repositories. Because of the
* differences between these two version control systems, the configuration for them
* looks a little different. Both types of configuration objects can be nested underneath
* the {@link ReposConfiguration.repos} key.
*
* You will also need to set the {@link ReposConfiguration.baseUrl} to the URL of your
* live website.
* @example
* const config: ReposConfiguration = {
* repos: {
* "My Darcs Project": {
* _type: "darcs",
* baseUrl: "https://repos.tuckerm.us",
* defaultBranch: 'main',
* branches: {
* 'main': {
* location: "/home/alice/projects/my_darcs_project",
* description: "Main branch of this project."
* },
* 'drafts': {
* location: "/home/alice/projects/my_darcs_project_drafts/",
* description: "Some things that are a work in progress",
* },
* },
* languageExtensions: {
* "njk": "html",
* },
* },
* },
* }
*/
type ReposConfiguration = {
repos: {
/** An object containing the configuration for your repositories.
* Each key in this object is a repository name, and the value has several
* config options for that repository. The required config options describe
* the path to the repository and which branches should be pulled. See the specific
* definitions of {@link GitConfig} and {@link DarcsConfig} for more details
* about what goes in these configuration objects.
*/
[repoName: string]: GitConfig | DarcsConfig
},
/**
* The root URL where this website will be. E.g.: https://blog.example.com/repos.
* This URL will be used when a clone or pull command is being shown on your site.
* @example baseUrl: "https://repos.tuckerm.us"
*/
baseUrl: string,
}
type GitConfig = {
_type: "git",
/* The absolute path to the repository.
* @example location: "/home/alice/projects/git_repo"
*/
location: string,
description?: string,
defaultBranch: string,
branchesToPull: Array<string>,
languageExtensions?: {
[fileExtension: string]: string
}
}
/**
* A configuration object for a darcs repository.
*
* @example
* "My Darcs Project": {
* _type: "darcs",
* baseUrl: "https://repos.tuckerm.us",
* defaultBranch: 'main',
* branches: {
* 'main': {
* location: "/home/alice/projects/my_darcs_project",
* description: "Main branch of this project."
* },
* 'drafts': {
* location: "/home/alice/projects/my_darcs_project_drafts/",
* description: "Some things that are a work in progress",
* },
* },
* languageExtensions: {
* "njk": "html",
* },
* }
*/
type DarcsConfig = {
/** Must be set to `"darcs"`. */
_type: "darcs",
/**
* The name of the default branch. Should match one of the keys in {@link DarcsConfig.branches}.
* @example defaultBranch: "main"
* */
defaultBranch: string,
/** The branches of this repository to generate pages for. Since darcs doesn't have
* branches in the same way that other VCSs do, a "branch" in this case is an entirely
* separate repository. So, these "branches" are more like repos that are grouped under
* the same project name. That is why you need to specify a separate location for each
* branch.
* @example
* branches: {
* main: {
* location: "/home/alice/projects/my-project/main",
* description: "The main release branch of this project."
* },
* drafts: {
* location: "/home/alice/projects/my-project/drafts",
* description: "Undeployed works-in-progress for this project."
* }
* }
*/
branches: {
/**
* Each key in this object will be the name that is used for that branch.
*/
[branchName: string]: {
/**
* The absolute path to the repository for this branch.
* @example location: "/home/alice/projects/darcs_repo_main"
*/
location: string,
/**
* A description of this branch. You may want to clarify what this branch is used for here.
*/
description?: string,
}
},
/**
* If your repository has any uncommon file extensions that should be treated like a different
* type of file, list them here. If you include `{njk: "html"}` here, that will tell the
* syntax highlighter to highlight an `njk` file like an `html` file. The key is the file
* extension in your code, and the value is the file extension that the syntax highlighter
* will know about.
* @example
* languageExtensions: {
* njk: "html",
* jss: "js",
* madeupformat: "txt"
* }
*/
languageExtensions?: {
[fileExtension: string]: string
}
}
export {
ReposConfiguration,
GitConfig,
DarcsConfig,
}
0
0
export type BranchInfo = {
files: Array<string>,
patches: Array<any>
}
0
0
import repos from './repos.ts'
let cachedFlatFiles = null
export default (repos) => {
if (cachedFlatFiles !== null) { return cachedFlatFiles }
cachedFlatFiles = Object.keys(repos).flatMap((repoName) => {
return Object.keys(repos[repoName].branches).flatMap((branchName) => {
return repos[repoName].branches[branchName].files.map((file) => {
return {
file,
branchName,
repoName,
}
})
})
})
return cachedFlatFiles
}
0
0
import _ from 'lodash'
import * as Diff from 'diff'
type NavValues = {
repoName: string | ((data: any) => string),
branchName: string | ((data: any) => string),
path: string | ((data: any) => string),
title: string | ((data: any) => string),
}
type Hunk = {
file: string,
lineNumber: number,
previousText: string,
afterText: string,
}
type DiffInfo = {
file: string,
lineNumber: number,
previousText: string,
afterText: string,
}
const getGitDiffsFromPatchText = (patchText: string): Array<DiffInfo> => {
const lines = patchText.split("\n")
const hunks: Array<Hunk> = []
let previousHunk = -1
const filenameRegex = RegExp(/diff --git a\/(.*?) b\/(.*?)/)
const lineNumberRegex = RegExp(/@@ -(.*?)[,| ].*/)
let previousFilename = ''
let currentFilename = ''
let skipFourStartingAt = -1
lines.forEach((line, index) => {
if (line.startsWith("diff")) {
previousFilename = currentFilename
currentFilename = line.match(filenameRegex)[1]
if (previousHunk !== -1) {
skipFourStartingAt = index
}
}
if (line.startsWith("@@") || index == lines.length - 1) {
if (previousHunk === -1) {
previousHunk = index
return
}
let hunkEndIndex = index + 1
if (skipFourStartingAt !== -1 && skipFourStartingAt < hunkEndIndex) {
hunkEndIndex = skipFourStartingAt
skipFourStartingAt = -1
}
const lastHunk = lines.slice(previousHunk, hunkEndIndex)
let lastHunkBefore = lastHunk.filter(line => line.startsWith("-")).map(str => str.replace("-", "")).join("\n")
let lastHunkAfter = lastHunk.filter(line => line.startsWith("+")).map(str => str.replace("+", "")).join("\n")
lastHunkBefore = _.escape(lastHunkBefore)
lastHunkAfter = _.escape(lastHunkAfter)
const changeObject = Diff.diffWordsWithSpace(lastHunkBefore, lastHunkAfter)
let previousText = ""
let afterText = ""
changeObject.forEach((obj) => {
if (!obj.added && !obj.removed) {
previousText = previousText + obj.value
afterText = afterText + obj.value
}
if (obj.added) {
afterText = afterText + "<mark>" + obj.value + "</mark>"
}
if (obj.removed) {
previousText = previousText + "<mark>" + obj.value + "</mark>"
}
})
hunks.push({
file: previousFilename !== '' ? previousFilename : currentFilename,
lineNumber: parseInt(lines[previousHunk].match(lineNumberRegex)[1]),
previousText,
afterText,
})
previousFilename = ''
previousHunk = index
}
})
return hunks
}
/** @hidden */
const getDarcsDiffsFromPatchText = (patchText: string): Array<DiffInfo> => {
const lines = patchText.split("\n")
const hunks: Array<Hunk> = []
let previousHunk = -1
lines.forEach((line, index) => {
if (line.startsWith("hunk") || index === lines.length - 1) {
if (previousHunk === -1) {
previousHunk = index
return
}
// get diff from previous hunk to this next one
const lastHunk = lines.slice(previousHunk, index + 1) // slice is non-inclusive for the end argument
let lastHunkBefore = lastHunk.filter(line => line.startsWith("-")).map(str => str.replace("-", "")).join("\n")
let lastHunkAfter = lastHunk.filter(line => line.startsWith("+")).map(str => str.replace("+", "")).join("\n")
lastHunkBefore = _.escape(lastHunkBefore)
lastHunkAfter = _.escape(lastHunkAfter)
let filename = lines[previousHunk].replace("hunk ./", "")
const changeObject = Diff.diffWords(lastHunkBefore, lastHunkAfter)
let previousText = ""
let afterText = ""
changeObject.forEach((obj) => {
if (!obj.added && !obj.removed) {
previousText = previousText + obj.value
afterText = afterText + obj.value
}
if (obj.added) {
afterText = afterText + "<mark>" + obj.value + "</mark>"
}
if (obj.removed) {
previousText = previousText + "<mark>" + obj.value + "</mark>"
}
})
const regex = RegExp(/(.*) ([0-9]+)$/)
const matches = filename.match(regex)
const file = matches[1]
const lineNumber: number = parseInt(matches[2])
hunks.push({
file,
lineNumber,
previousText,
afterText,
})
previousHunk = index
}
})
return hunks
}
const getLocation = (reposConfig: any, branchName: string, repoName: string): string => {
const config = reposConfig.repos[repoName]
if (config._type === "darcs") {
return config.branches[branchName].location
}
else if (config._type === "git") {
return config.location
}
}
export {
NavValues,
getDarcsDiffsFromPatchText,
getGitDiffsFromPatchText,
getLocation,
}
0
0
import {
type DarcsConfig,
type GitConfig,
} from './configTypes.ts'
import {type BranchInfo} from './dataTypes.ts'
import repoOperations from './vcses/operations.ts'
import { getLocation} from './helpers.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,
}
}
const getBranchNames = (repoConfig: DarcsConfig | GitConfig): Array<string> => {
if (repoConfig._type === 'darcs') {
return Object.keys(repoConfig.branches)
}
else if (repoConfig._type === 'git') {
return repoConfig.branchesToPull
}
}
let cachedRepos = null
const repos: (reposConfig: any) => Promise<RepoObject> = async (reposConfig) => {
if (cachedRepos !== null) { return cachedRepos }
const repoNames = Object.keys(reposConfig.repos)
const reposTuples: RepoObjectTuple[] = await Promise.all(repoNames.map(async (repoName): Promise<RepoObjectTuple> => {
const vcs = reposConfig.repos[repoName]._type
const branchNames = getBranchNames(reposConfig.repos[repoName])
const branchTuples: BranchInfoTuple[] = await Promise.all(branchNames.map(async (branchName): Promise<BranchInfoTuple> => {
const repoLocation = getLocation(reposConfig, branchName, repoName)
const files = await repoOperations[vcs].getFileList(repoName, branchName, repoLocation)
const patches = await repoOperations[vcs].getBranchInfo(repoName, 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, repoName)
}
}
cachedRepos = reposObject
return reposObject
}
export default repos
0
0
export default {
cloneUrl: (baseUrl: string, repoName: string) => {
return `${baseUrl}/repos/${repoName.toLowerCase().replaceAll(" ", "-")}/branches/`
}
}
0
0
import util from 'util'
import childProcess from 'child_process'
const exec = util.promisify(childProcess.exec)
import {getDarcsDiffsFromPatchText} from '../../helpers.ts'
export const getFileList = async(repoName: string, branchName: string, repoLocation: string) => {
const command = "darcs show files"
const result = await exec(`(cd ${repoLocation} && ${command})`)
const files = result.stdout.split("\n").filter(item => item.length > 0 && item != ".")
return files
}
export const getBranchInfo = async (repoName: string, branchName: string, repoLocation: string) => {
const patches = new Map()
const totalPatchesCountRes = await exec(`(cd ${repoLocation} && darcs log --count)`)
const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
let hunkRegex = RegExp(/^ *hunk /)
// Get 100 patches at a time and parse those
for (let i = 1; i <= totalPatchesCount; i = i + 100) {
let patchesSubsetRes = await exec(`(cd ${repoLocation} && darcs log --index=${i}-${i+100} -v)`)
let patchesSubset = patchesSubsetRes.stdout.split("\n")
do {
const nextPatchStart = patchesSubset.findIndex((line, index) => {
return (index > 0 && line.startsWith("patch ")) || index === patchesSubset.length - 1
})
const isEndOfFile = nextPatchStart === patchesSubset.length - 1
const currentPatch = patchesSubset.slice(0, isEndOfFile ? nextPatchStart : nextPatchStart - 1)
patchesSubset = patchesSubset.slice(nextPatchStart)
const hash = currentPatch[0].replace("patch ", "").trim()
const author = currentPatch[1].replace("Author: ", "").trim()
const date = currentPatch[2].replace("Date: ", "").trim()
const name = currentPatch[3].replace(" * ", "").trim()
const diffStart = currentPatch.findIndex((line) => {
return line.match(hunkRegex)
})
const description = currentPatch.slice(5, diffStart).map(str => str.replace(" ", "")).join("\n").trim()
const diffs = getDarcsDiffsFromPatchText(currentPatch.slice(diffStart).map(str => str.trimStart()).join("\n"))
patches.set(hash, {
name,
description,
author,
date,
hash,
diffs,
})
} while (patchesSubset.length > 1)
}
return Array.from(patches.values())
}
export const getFileLastTouchInfo = async (repoName: string, branchName: string, filename: string, repoLocation: string) => {
const command = `darcs annotate --machine-readable ${filename}`
const res = await exec(`(cd ${repoLocation} && ${command})`)
const output = res.stdout
const outputLines = output.split("\n").map((line) => {
return line.split(' ')[0]
})
return outputLines.map((line) => {
return {sha: line, author: ''}
})
}
0
0
export default {
cloneUrl: (baseUrl: string, repoName: string) => {
return `${baseUrl}/repos/${repoName.toLowerCase().replaceAll(" ", "-")}.git`
}
}
0
0
import util from 'util'
import childProcess from 'child_process'
const exec = util.promisify(childProcess.exec)
import { getGitDiffsFromPatchText} from '../../helpers.ts'
export const getFileList = async (repoName: string, branchName: string, repoLocation: string) => {
const command = `git ls-tree -r --name-only ${branchName}`
const result = await exec(`(cd ${repoLocation} && ${command})`)
let files = result.stdout.split("\n").filter(item => item.length > 0 && item != ".")
// TODO: this could be better. This is adding each sub-path of a file to a set, so that
// we don't wind up with repeats, and then converting that back into an array. E.g. if
// we have two files:
// - posts/blog/one.md
// - posts/blog/two.md
// this will add the following to the set:
// posts, posts/blog, posts/blog/one.md, posts, posts/blog, posts/blog/two.md
// The repeats will be omitted because it's a Set, and the resulting array will
// be [posts, posts/blog, posts/blog/one.md, posts/blog/two.md].
// This is because it's convenient to have the directories show up as their own "file"
// in the file list, even though git doesn't treat them that way.
const fileSet: Set<string> = new Set()
files.forEach((file) => {
const fileParts = file.split("/")
const allPathsInFile = fileParts.reduce((accumulator, currentValue, index) => {
// Skip the first iteration, we have already added it as the initialValue
if (index === 0) { return accumulator }
accumulator.push(accumulator[accumulator.length - 1] + '/' + currentValue)
return accumulator
}, [fileParts[0]])
allPathsInFile.forEach((path) => {
fileSet.add(path)
})
})
return Array.from(fileSet)
}
export const getBranchInfo = async (repoName: string, branchName: string, repoLocation: string) => {
const patches = new Map()
const totalPatchesCountRes = await exec(`(cd ${repoLocation} && git rev-list --count ${branchName})`)
const totalPatchesCount = parseInt(totalPatchesCountRes.stdout)
for (let i = 0; i < totalPatchesCount; i = i + 10) {
const gitLogSubsetRes = await exec(`(cd ${repoLocation} && git log ${branchName} -p -n 10 --skip ${i})`)
let gitLogSubset = gitLogSubsetRes.stdout.split("\n")
do {
const nextPatchStart = gitLogSubset.findIndex((line, index) => {
return (index > 0 && line.startsWith("commit ")) || index === gitLogSubset.length - 1
})
const isEndOfFile = nextPatchStart === gitLogSubset.length - 1
const currentPatch = gitLogSubset.slice(0, isEndOfFile ? nextPatchStart : nextPatchStart - 1)
gitLogSubset = gitLogSubset.slice(nextPatchStart)
const hash = currentPatch[0].replace("commit ", "").trim()
const author = currentPatch[1].replace("Author: ", "").trim()
const date = currentPatch[2].replace("Date: ", "").trim()
const diffStart = currentPatch.findIndex((line) => {
return line.startsWith("diff ")
})
// Git log is indent four spaces by default -- remove those.
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) => {
// git log --porcelain output adds these "Ignore-this:" lines and I'm not sure what they are
return !line.startsWith('Ignore-this: ')
}).join("\n").trim()
const diffs = getGitDiffsFromPatchText(currentPatch.slice(diffStart).join("\n"))
patches.set(hash, {
name,
description,
author,
date,
hash,
diffs,
})
} while (gitLogSubset.length > 1)
}
return Array.from(patches.values())
}
export const getFileLastTouchInfo = async (repo, branch, filename, repoLocation) => {
const regex = RegExp(".* [0-9]+ [0-9]+")
const command = `git blame --porcelain ${branch} ${filename}`
const res = await exec(`(cd ${repoLocation} && ${command})`)
const output = res.stdout
const outputLines = output.split("\n")
const initialValue: Array<Array<string>> = [[outputLines[0]]]
const chunked = outputLines.reduce((accumulator, currentLine, currentIndex) => {
// skip the first iteration since we already gave it initialValue
if (currentIndex == 0) { return accumulator }
if (currentLine.match(regex)) {
accumulator.push([currentLine])
return accumulator
}
else {
accumulator[accumulator.length - 1].push(currentLine)
return accumulator
}
}, initialValue)
let currentAuthor = ''
let authorsAndShasByLine = []
chunked.forEach((chunk) => {
let shaAndLineNumberParts = chunk[0].split(' ')
let line = parseInt(shaAndLineNumberParts[2])
let sha = shaAndLineNumberParts[0]
if (chunk[1] && chunk[1].startsWith('author ')) {
currentAuthor = chunk[1].replace('author ', '')
}
authorsAndShasByLine[line - 1] = {sha, author: currentAuthor}
})
return authorsAndShasByLine
}
0
0
import gitHelpers from './git/helpers.ts'
import darcsHelpers from './darcs/helpers.ts'
export default {
git: gitHelpers,
darcs: darcsHelpers
}
0
0
import {
getBranchInfo as getGitBranchInfo,
getFileList as getGitFileList,
getFileLastTouchInfo as getGitFileLastTouchInfo,
} from './git/operations.ts'
import {
getBranchInfo as getDarcsBranchInfo,
getFileList as getDarcsFileList,
getFileLastTouchInfo as getDarcsFileLastTouchInfo,
} from './darcs/operations.ts'
import {type BranchInfo} from '../dataTypes.ts'
type RepoOperationsType = {
[vcs: string]: {
getBranchInfo: (repoName: string, branchName: string, repoLocation: string) => Promise<BranchInfo['patches']>,
getFileList: (repoName: string, branchName: string, repoLocation: string) => Promise<BranchInfo['files']>,
getFileLastTouchInfo: (repoName: string, branchName: string, filename: string, repoLocation: string) => Promise<Array<{sha: string, author: string}>>,
}
}
const repoOperations: RepoOperationsType = {
git: {
getBranchInfo: getGitBranchInfo,
getFileList: getGitFileList,
getFileLastTouchInfo: getGitFileLastTouchInfo,
},
darcs: {
getBranchInfo: getDarcsBranchInfo,
getFileList: getDarcsFileList,
getFileLastTouchInfo: getDarcsFileLastTouchInfo,
}
}
export default repoOperations
0
0
<ul>
{% for branch in branches %}
{% set description = reposConfig.repos[branch.repoName].branches[branch.branchName].description %}
{% if branch.repoName == branchInfo.repoName %}
<li><a href="/repos/{{branch.repoName | slugify}}/branches/{{branch.branchName | slugify}}">{{branch.branchName}}</a>{% if branch.branchName == branchInfo.branchName %} (current){% endif %}{% if description %} - {{ description }}{% endif %}</li>
{% endif %}
{% endfor %}
</ul>
0
0
<h3>{{fileInfo.file | getFileName}}</h3>
{% if fileInfo.file | isDirectory(fileInfo.repoName, fileInfo.branchName) %}
<ul class="list-group">
{% set dirs = fileInfo.repoName | getDirectoryContents(fileInfo.branchName, fileInfo.file) | topLevelFilesOnly(fileInfo.file + '/') %}
{% for dir in dirs %}
<li class="list-group-item">
{% if dir.isDirectory %}
<i class="bi bi-folder-fill"></i>
{% else %}
<i class="bi bi-file-earmark"></i>
{% endif %}
<a href="/repos/{{fileInfo.repoName | slugify}}/branches/{{fileInfo.branchName | slugify}}/files/{{dir.fullPath | slugify}}.html">{{fileInfo.file | getRelativePath(dir.name)}}</a>
</li>
{% endfor %}
</ul>
{% else %}
<div class="row py-2">
<div class="col">
<div class="form-check form-switch">
<input class="form-check-input" type="checkbox" role="switch" id="showLastTouch">
<label class="form-check-label" for="showLastTouch">Show last line change</label>
</div>
</div>
</div>
<div class="row">
<div class="col-auto border-end">
{% set fileContents = fileInfo.repoName | getFileContents(fileInfo.branchName, fileInfo.file) %}
<code style="white-space: pre;"><pre class="language-text">
{%- for lineNumber in fileContents | lineNumbers -%}
{{ lineNumber }}
{% endfor -%}</pre></code>
</div>
<div id="annotations" class="col-auto d-none">
{% set annotations = fileInfo.repoName | getFileLastTouchInfo(fileInfo.branchName, fileInfo.file) %}
<code style="white-space: pre;"><pre class="language-text">
{%- for annotation in annotations -%}
<a href="/repos/{{fileInfo.repoName | slugify}}/branches/{{fileInfo.branchName | slugify}}/patches/{{annotation.sha}}">{{ (annotation.sha | truncate(6, true, '')) }}</a> {{ annotation.author }}
{% endfor -%}
</pre></code>
</div>
<div class="col overflow-scroll">
<code>
{{- fileContents | highlightCode((fileInfo.file | languageExtension(fileInfo.repoName))) | safe }}
</code>
</div>
</div>
{% endif %}
<script type="text/javascript">
const toggleLastTouch = (event) => {
const isOn = event.target.checked
const annotations = document.getElementById("annotations")
if (isOn) {
annotations.classList.remove("d-none")
} else {
annotations.classList.add("d-none")
}
}
document.getElementById("showLastTouch")?.addEventListener('click', toggleLastTouch)
</script>
0
0
<div class="row">
<div class="col">
<ul class="list-group">
{% set files = repos[branchInfo.repoName].branches[branchInfo.branchName].files | topLevelFilesOnly('') %}
{% for file in files %}
<li class="list-group-item">
{% if file.isDirectory %}
<i class="bi bi-folder-fill"></i>
{% else %}
<i class="bi bi-file-earmark"></i>
{% endif %}
<a href="/repos/{{branchInfo.repoName | slugify}}/branches/{{branchInfo.branchName | slugify}}/files/{{file.fullPath | slugify}}.html">{{file.name}}</a>
</li>
{% endfor %}
</ul>
</div>
</div>
0
0
<ul>
{% for repoName, options in repos %}
<li><a href="/repos/{{repoName | slugify}}/branches/{{reposConfig.repos[repoName].defaultBranch}}">{{repoName}}</a></li>
{% endfor %}
</ul>
0
0
<div class="row">
<div class="col-md-8 col-sm-12 order-md-1 order-sm-2">
{{ branch.repoName | getReadMe(branch.branchName) | renderContent("md") | safe }}
</div>
<div class="col-md-4 col-sm-12 order-md-2 order-sm-1">
<div class="row">
<div class="col">
<div class="row align-items-center">
<div class="col-auto">
<h2 class="fs-6 my-0">Recent patches in {{branch.branchName}}</h2>
</div>
<div class="col-auto">
<a href="/repos/{{ branch.repoName | slugify }}/branches/{{ branch.branchName | slugify }}/patches.xml" class="initialism">RSS<i class="bi bi-rss-fill ms-2" style="color: orange;"></i></a>
</div>
</div>
{% 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="/repos/{{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">
{% if reposConfig.repos[branch.repoName]._type == "darcs" %}
<button data-hash="{{patch.hash}}" data-vcs="darcs" class="copy-btn btn btn-sm btn-outline-primary ms-2">
<i class="bi-copy bi me-1"></i>darcs pull {{patch.hash | truncate(6, true, "")}}
</button>
{% elif reposConfig.repos[branch.repoName]._type == "git" %}
<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>
{% endif %}
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</div>
0
0
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"rewriteRelativeImportExtensions": true,
"noImplicitAny": false,
"module": "nodenext",
"target": "es2017",
"lib": ["es2023", "dom"],
"allowJs": true,
"outDir": "dist"
},
"include": ["**/*.ts"],
"exclude": [
"dist/**/*",
"ts/frontend/**/*",
],
}