Add biome and fix typos

This commit is contained in:
Jade Ellis 2024-09-15 18:07:41 +01:00
parent 9522e043a1
commit 76de8f4137
No known key found for this signature in database
GPG key ID: 8705A2A3EBF77BD2
27 changed files with 223 additions and 102 deletions

View file

@ -0,0 +1,30 @@
{
"$schema": "https://biomejs.dev/schemas/1.9.0/schema.json",
"vcs": {
"enabled": true,
"clientKind": "git",
"useIgnoreFile": true
},
"files": {
"ignoreUnknown": false,
"ignore": []
},
"formatter": {
"enabled": true,
"indentStyle": "tab"
},
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"javascript": {
"formatter": {
"quoteStyle": "double"
}
}
}

View file

@ -76,7 +76,7 @@ import { grammars } from 'tm-grammars'
* @param {string} name
*/
function getGrammar(name) {
let metadata = grammars.find((grammar) => grammar.name == name)
const metadata = grammars.find((grammar) => grammar.name == name)
if (!metadata) {
throw "Grammar not found"
}
@ -112,18 +112,18 @@ function buildNestedHeadings(headings) {
/**
* @type {{level: number, title: string, children: unknown}[]}
*/
let result = [];
let stack = [{ level: 0, children: result }];
const result = [];
const stack = [{ level: 0, children: result }];
for (let heading of headings) {
for (const heading of headings) {
while (
stack.length > 1 &&
heading.level <= stack[stack.length - 1].level
) {
stack.pop();
}
let parent = stack[stack.length - 1];
let newHeading = {
const parent = stack[stack.length - 1];
const newHeading = {
...heading,
children: [],
level: heading.level,
@ -151,7 +151,7 @@ function add_toc_remark(opts) {
vFile.data.flattenedHeadings = [];
visit(tree, 'heading', (node) => {
let title = mdast_tree_to_string(node);
const title = mdast_tree_to_string(node);
vFile.data.flattenedHeadings.push({
level: node.depth,
title,
@ -263,7 +263,7 @@ function vite_images_rehype(opts) {
});
visit(tree, { tagName: "Components.img" }, (node) => {
let url = node.properties.src;
let thumb = (url.includes("?") ? url + "&" : url + "?") + "thumb";
const thumb = (url.includes("?") ? url + "&" : url + "?") + "thumb";
url = (url.includes("?") ? url + "&" : url + "?") + "url";
node.properties.src = `{${transformUrl(url)}}`

View file

@ -6,9 +6,11 @@
"build": "vite build",
"preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"fix": "biome lint --write . && biome format --write . && biome check . --write"
},
"devDependencies": {
"@biomejs/biome": "1.9.0",
"@bitmachina/highlighter": "1.0.0-alpha.6",
"@fontsource/fira-mono": "^5.0.14",
"@json-feed-types/1_1": "^1.0.2",

View file

@ -13,5 +13,3 @@ declare global {
}
}
}
export {};

View file

@ -39,7 +39,7 @@ export const handle: Handle = async (input) => {
}),
async ({ event, resolve }) => {
const response = await resolve(event);
let csp = response.headers.get("Content-Security-Policy");
const csp = response.headers.get("Content-Security-Policy");
if (csp) {
response.headers.set("Content-Security-Policy", csp.replace("script-src", "script-src 'nonce-" + sentryNonce + "'"));
}

View file

@ -1,13 +1,13 @@
<script lang="ts">
import TocItem from "./TocItem.svelte";
let className = "toc";
const className = "toc";
type FlatHeading = { level: number; title: string };
export let headings: nestedListNode[];
// creates a `class` property, even
// though it is a reserved word
export { className as class };
export let listType = "ul";
export const listType = "ul";
let open = false;
/** @type {import('./$types').Snapshot<string>} */

View file

@ -1,7 +1,7 @@
<script lang="ts">
export let node: nestedListNode;
export let listType = "ul"
export const listType = "ul"
</script>
<li class="toc-item {"toc-item-" + node.level}">

View file

@ -6,7 +6,7 @@
// export let align
// export let small: boolean;
// console.log("imgcmp", thumb);
let className = "";
const className = "";
export { className as class };
let loaded = false
// console.log(thumb)

View file

@ -1,6 +1,6 @@
import { writable } from 'svelte/store'
let query = typeof window != "undefined" ? window?.matchMedia('(prefers-color-scheme: dark)') : undefined
const query = typeof window != "undefined" ? window?.matchMedia('(prefers-color-scheme: dark)') : undefined
export const theme = writable(query?.matches ? 'dark' : 'light')

View file

@ -1,5 +1,5 @@
import type { MinifyOptions, MinifyOutput } from "terser";
import { recieveMessageData, sendMessageData } from "./util";
import { receiveMessageData, sendMessageData } from "./util";
const is_browser = typeof window !== "undefined";
export function init() {
@ -7,7 +7,7 @@ export function init() {
let worker: SharedWorker;
let currentId = 0;
let terserModule: typeof import("terser");
let promises: { [id: number]: [(value: MinifyOutput | PromiseLike<MinifyOutput>) => void, (reason?: any) => void] } = {};
const promises: { [id: number]: [(value: MinifyOutput | PromiseLike<MinifyOutput>) => void, (reason?: any) => void] } = {};
return {
minify: async function minify(files: string | string[] | {
[file: string]: string;
@ -18,10 +18,10 @@ export function init() {
worker = new SharedWorker(new URL('./terserWorker.ts', import.meta.url), { type: "module" })
worker.port.onmessage = (e: MessageEvent<any>) => {
// invoke the promise's resolve() or reject() depending on whether there was an error.
promises[e.data[recieveMessageData.MessageId]][e.data[recieveMessageData.MessageType]](e.data[recieveMessageData.Return]);
promises[e.data[receiveMessageData.MessageId]][e.data[receiveMessageData.MessageType]](e.data[receiveMessageData.Return]);
// ... then delete the promise controller
delete promises[e.data[recieveMessageData.MessageId]];
delete promises[e.data[receiveMessageData.MessageId]];
}
}
@ -29,7 +29,7 @@ export function init() {
return new Promise((resolve, reject) => {
promises[++currentId] = [resolve, reject];
let data = {
const data = {
[sendMessageData.MessageId]: currentId,
[sendMessageData.Parameters]: [files, options
]

View file

@ -1,24 +1,24 @@
import { minify, type MinifyOptions } from "terser";
import { recieveMessageTypes, sendMessageData } from "./util";
import { receiveMessageTypes, sendMessageData } from "./util";
/// <reference lib="sharedworker " />
declare var self: SharedWorkerGlobalScope;
self.onconnect = function (event) {
self.onconnect = (event) => {
const port = event.ports[0];
port.onmessage = function (e: MessageEvent<{
port.onmessage = (e: MessageEvent<{
[sendMessageData.MessageId]: number,
[sendMessageData.Parameters]: [string | string[] | {
[file: string]: string;
}, MinifyOptions?
]
}>) {
}>) => {
minify(...e.data[sendMessageData.Parameters]).then(
// success handler - callback(id, SUCCESS(0), result)
// if `d` is transferable transfer zero-copy
d => {
port.postMessage([e.data[0], recieveMessageTypes.RESOLVE, d],
port.postMessage([e.data[0], receiveMessageTypes.RESOLVE, d],
// @ts-ignore
[d].filter(x => (
(x instanceof ArrayBuffer) ||
@ -27,7 +27,7 @@ self.onconnect = function (event) {
)));
},
// error handler - callback(id, ERROR(1), error)
er => { postMessage([e.data[0], recieveMessageTypes.REJECT, '' + er]); }
er => { postMessage([e.data[0], receiveMessageTypes.REJECT, '' + er]); }
);
};

View file

@ -1,9 +1,9 @@
export type FunctionMap = { [x: string]: Function }
export enum sendMessageData {
MessageId,
Function,
Parameters
MessageId = 0,
Function = 1,
Parameters = 2
}
export interface sendMessageMap <T> {
@ -12,27 +12,27 @@ export interface sendMessageMap <T> {
[sendMessageData.Parameters]: T[],
}
export enum recieveMessageTypes {
RESOLVE, // OK
REJECT // ERROR
export enum receiveMessageTypes {
RESOLVE = 0, // OK
REJECT = 1 // ERROR
}
export enum recieveMessageData {
MessageId,
MessageType,
Return
export enum receiveMessageData {
MessageId = 0,
MessageType = 1,
Return = 2
}
export interface recieveMessageMap <T> {
[recieveMessageData.MessageId]: number,
[recieveMessageData.MessageType]: recieveMessageTypes,
[recieveMessageData.Return]: T,
export interface receiveMessageMap <T> {
[receiveMessageData.MessageId]: number,
[receiveMessageData.MessageType]: receiveMessageTypes,
[receiveMessageData.Return]: T,
}
// // worker
// import { recieveMessageTypes, type FunctionMap } from "./util";
// import { receiveMessageTypes, type FunctionMap } from "./util";
// function makeMessageHandler(functions: FunctionMap) {
@ -44,20 +44,20 @@ export interface recieveMessageMap <T> {
// // success handler - callback(id, SUCCESS(0), result)
// // if `d` is transferable transfer zero-copy
// d => {
// postMessage([e.data[0], recieveMessageTypes.SUCCESS, d], [d].filter(x => (
// postMessage([e.data[0], receiveMessageTypes.SUCCESS, d], [d].filter(x => (
// (x instanceof ArrayBuffer) ||
// (x instanceof MessagePort) ||
// (self.ImageBitmap && x instanceof ImageBitmap)
// )));
// },
// // error handler - callback(id, ERROR(1), error)
// er => { postMessage([e.data[0], recieveMessageTypes.ERROR, '' + er]); }
// er => { postMessage([e.data[0], receiveMessageTypes.ERROR, '' + er]); }
// );
// }
// }
// // host
// import { recieveMessageData, recieveMessageTypes, sendMessageData, type recieveMessageMap, type sendMessageMap } from "./util";
// import { receiveMessageData, receiveMessageTypes, sendMessageData, type receiveMessageMap, type sendMessageMap } from "./util";
// function makeHostHandler(worker: Worker) {
@ -72,7 +72,7 @@ export interface recieveMessageMap <T> {
// * status - 0 for success, 1 for failure
// * result - the result or error, depending on `status`
// */
// worker.onmessage = (e: MessageEvent<recieveMessageMap>) => {
// worker.onmessage = (e: MessageEvent<receiveMessageMap>) => {
// // invoke the promise's resolve() or reject() depending on whether there was an error.
// promises[e.data[0]][e.data[1]](e.data[2]);

View file

@ -13,20 +13,20 @@
restore: (v: string) => (value = v),
};
let minify = init().minify;
const minify = init().minify;
let value = "";
let output = "";
let options: Config = {};
async function process(str: string) {
options = await parseMeta(str);
let res = await bookmarkify(str, options, minify);
const res = await bookmarkify(str, options, minify);
if (typeof res == "string") {
output = res;
}
}
let contentAttributes = { "aria-label": "Bookmarklet editor" };
const contentAttributes = { "aria-label": "Bookmarklet editor" };
$: progress = process(value);
</script>

View file

@ -2,9 +2,9 @@
// import MagicString from "magic-string";
import { Parser } from "acorn";
import { type MinifyOptions, type MinifyOutput } from "terser";
import type { MinifyOptions, MinifyOutput } from "terser";
let sourceMap = false;
const sourceMap = false;
import { configSchema } from "./config.schema";
import type { Config } from "./config";
@ -18,14 +18,14 @@ export async function bookmarkify(code: string, options: Config, minify: (files:
if (options.script) {
options.script = options.script.reverse();
options.script.forEach(s => {
let { path, opts } = extractOptions(s);
const { path, opts } = extractOptions(s);
code = loadScript(code, path, opts.loadOnce);
});
}
if (options.style) {
options.style.forEach(s => {
let { path, opts } = extractOptions(s);
const { path, opts } = extractOptions(s);
code = loadStyle(path, opts.loadOnce) + code;
});
}
@ -43,9 +43,9 @@ export async function bookmarkify(code: string, options: Config, minify: (files:
export async function parseMeta(str: string): Promise<Config> {
enum MetaState {
PreOpen,
Opened,
Closed
PreOpen = 0,
Opened = 1,
Closed = 2
}
let state: MetaState = MetaState.PreOpen
@ -53,7 +53,7 @@ export async function parseMeta(str: string): Promise<Config> {
const openMetadata = /==bookmarklet==/gim;
const closeMetadata = /==\/bookmarklet==/gim;
const metaLine = /^[\s]*@([^\s]+)\s+(.*)$/gim;
let options: Config = {};
const options: Config = {};
Parser.parse(str, {
ecmaVersion: "latest",
@ -62,7 +62,7 @@ export async function parseMeta(str: string): Promise<Config> {
closeMetadata.lastIndex = 0;
metaLine.lastIndex = 0;
if (state == MetaState.PreOpen) {
let res = openMetadata.exec(text)
const res = openMetadata.exec(text)
if (res !== null) {
state = MetaState.Opened
closeMetadata.lastIndex = openMetadata.lastIndex;
@ -75,8 +75,8 @@ export async function parseMeta(str: string): Promise<Config> {
while (state == MetaState.Opened && (res = metaLine.exec(text)) !== null) {
closeMetadata.lastIndex = metaLine.lastIndex;
// console.log(str.slice(start + 2 + (metaLine.lastIndex - res[0].length), start + 2 + metaLine.lastIndex ))
let k = res[1];
let v = res[2];
const k = res[1];
const v = res[2];
if (k) {
if (configSchema.properties[k]?.type == "array") {
options[k] = options[k] || [];
@ -90,7 +90,7 @@ export async function parseMeta(str: string): Promise<Config> {
}
if (state == MetaState.Opened) {
let endRes = closeMetadata.exec(text)
const endRes = closeMetadata.exec(text)
if (endRes !== null) {
state = MetaState.Closed;
@ -110,7 +110,7 @@ export async function parseMeta(str: string): Promise<Config> {
function loadScript(code: string, path: string, loadOnce: boolean) {
loadOnce = !!loadOnce;
let id = `bookmarklet__script_${cyrb53(path).toString(36).substring(0, 7)}`;
const id = `bookmarklet__script_${cyrb53(path).toString(36).substring(0, 7)}`;
return `
function callback(){
${code}
@ -136,7 +136,7 @@ function loadScript(code: string, path: string, loadOnce: boolean) {
function loadStyle(path: string, loadOnce: boolean) {
loadOnce = !!loadOnce;
let id = `bookmarklet__style_${cyrb53(path).toString(36).substring(0, 7)}`;
const id = `bookmarklet__style_${cyrb53(path).toString(36).substring(0, 7)}`;
return `
if (!${loadOnce} || !document.getElementById("${id}")) {
var link = document.createElement("link");
@ -178,16 +178,16 @@ function extractOptions(path: string) {
// If there is no `=`, then the value of the option defaults to `true`.
// Values get converted via JSON.parse if possible, o/w they're a string.
//
let opts: { [x: string]: any } = {};
const opts: { [x: string]: any } = {};
let matcher = /^(\![^\s]+)\s+/g
const matcher = /^(\![^\s]+)\s+/g
let m
let splitAfter = 0;
while ((m = matcher.exec(path)) !== null) {
splitAfter = matcher.lastIndex;
let opt = m[1].substring(1).split('=');
const opt = m[1].substring(1).split('=');
opts[opt[0]] = opt[1] === undefined ? true : _fuzzyParse(opt[1]);
// break
}

View file

@ -11,7 +11,7 @@
restore: (v: string) => (value = v),
};
let minify = init().minify;
const minify = init().minify;
let value = "";
let output = "";
@ -20,7 +20,7 @@
output = "";
return;
}
let result = await minify(str);
const result = await minify(str);
if (typeof result.code == "string") {
output = result.code;
} else {
@ -28,7 +28,7 @@
}
}
let contentAttributes = { "aria-label": "Javascript editor" };
const contentAttributes = { "aria-label": "Javascript editor" };
$: progress = process(value);
</script>

View file

@ -9,7 +9,7 @@
const title = `${status}: ${message}`;
let sentryElement: HTMLDivElement;
let openForm = () => {};
let online = typeof navigator !== 'undefined' ? navigator.onLine : true;
const online = typeof navigator !== 'undefined' ? navigator.onLine : true;
onMount(async () => {
const feedback = Sentry.getFeedback({
el: sentryElement,

View file

@ -29,15 +29,15 @@ const accounts = [
].map(i => i.toLowerCase())
export async function GET({ url }: RequestEvent) {
// export const GET = async ({ url }) => {
let resource = url.searchParams.get("resource");
const resource = url.searchParams.get("resource");
if (resource?.split(":")[0] !== "acct") {
let res = new Response("", { status: 404 })
const res = new Response("", { status: 404 })
return res;
}
let account = resource?.split(":")[1]
const account = resource?.split(":")[1]
if (!accounts.includes(account.toLowerCase()) && !account.toLowerCase().endsWith("@jade.ellis.link")) {
if (resource?.split(":")[0] !== "acct") {
let res = new Response("", { status: 404 })
const res = new Response("", { status: 404 })
return res;
}
}
@ -75,6 +75,6 @@ export async function GET({ url }: RequestEvent) {
]
}
// const isMe = (user.toLowerCase() == EMAIL.toLowerCase()) ? true : false;
let res = new Response(JSON.stringify(webFinger), { headers: { "content-type": "application/jrd+json" }, status: 200 })
const res = new Response(JSON.stringify(webFinger), { headers: { "content-type": "application/jrd+json" }, status: 200 })
return res;
}

View file

@ -5,7 +5,7 @@
import type { WithContext, Thing } from "schema-dts";
export let data;
let { pages } = data;
const { pages } = data;
const jsonLd = {
"@context": "https://schema.org",

View file

@ -11,7 +11,7 @@ import { error } from '@sveltejs/kit'
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
const { slug } = params
let dateParts = params.date.split(/[\/-]/).map((p) => parseInt(p, 10))
const dateParts = params.date.split(/[\/-]/).map((p) => Number.parseInt(p, 10))
if (dateParts.length > 3) {
throw error(404, 'Post not found (bad date)')
}
@ -25,7 +25,7 @@ export async function load({ params }) {
const page = pages
.filter((post) => slug === post.slug)
.filter((post) => {
let date = new Date(post.date)
const date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) &&

View file

@ -21,7 +21,7 @@
ratio?: number,
width?: number,
): URL {
let url = new URL(SITE_URL + "/blog/image");
const url = new URL(SITE_URL + "/blog/image");
url.searchParams.set("slug", slug);
url.searchParams.set("date", date);
if (ratio) {
@ -39,7 +39,7 @@
$: handleWebShare;
const handleWebShare = async () => {
try {
let url = new URL(canonical);
const url = new URL(canonical);
url.searchParams.set("utm_medium", "share");
await navigator.share({
title: data.post.title,

View file

@ -14,14 +14,14 @@ import { error } from '@sveltejs/kit'
// export const prerender = true;
export async function GET({ params, url}) {
let dateParts = params.date.split(/[\/-]/).filter((s)=>s.length !== 0).map((p) => parseInt(p, 10))
const dateParts = params.date.split(/[\/-]/).filter((s)=>s.length !== 0).map((p) => Number.parseInt(p, 10))
if (dateParts.length > 3) {
throw error(404, 'Feed not found (bad date)')
}
const selectedPages = dateParts.length ? pages
.filter((post) => {
let date = new Date(post.date)
const date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) &&
@ -57,7 +57,7 @@ async function getJsonFeed(selfUrl: string, pages: any[]): Promise<string> {
const postUrl = SITE_URL + "/blog/" + post.canonical
// const postHtml =
const summary = post.description;
let item: typeof feed.items[number] = {
const item: typeof feed.items[number] = {
id: post.postUrl,
title,
url: postUrl,

View file

@ -15,7 +15,7 @@ import { error } from '@sveltejs/kit'
// export const prerender = true;
export async function GET({ url, params }) {
let dateParts = params.date.split(/[\/-]/).filter((s)=>s.length !== 0).map((p) => parseInt(p, 10))
const dateParts = params.date.split(/[\/-]/).filter((s)=>s.length !== 0).map((p) => Number.parseInt(p, 10))
if (dateParts.length > 3) {
throw error(404, 'Feed not found (bad date)')
}
@ -23,7 +23,7 @@ export async function GET({ url, params }) {
const selectedPages = dateParts.length ? pages
.filter((post) => {
console.log("filtering")
let date = new Date(post.date)
const date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) &&

View file

@ -24,7 +24,7 @@ export async function GET({ url, request }) {
// First, get the information about the post
// We have the slug and date of the post, which we can use to look up the post
const slug = url.searchParams.get('slug')
let dateParts = url.searchParams.get('date')?.split(/[\/-]/)?.map((p: string) => parseInt(p, 10))
const dateParts = url.searchParams.get('date')?.split(/[\/-]/)?.map((p: string) => Number.parseInt(p, 10))
if (dateParts && dateParts.length > 3) {
throw error(404, 'Post not found (bad date)')
}
@ -43,7 +43,7 @@ export async function GET({ url, request }) {
.filter((post) => slug === post.slug)
.filter((post) => {
if (dateParts) {
let date = new Date(post.date)
const date = new Date(post.date)
return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth() + 1 == dateParts[1]) &&
@ -59,9 +59,9 @@ export async function GET({ url, request }) {
// Generate a cache key based on the post's canonical URL, reading time, width, and ratio
// Caching the image based on this key ensures that the image is not regenerated every time
// The cache key is also used for browser caching
let cache_key = fnv.hash(page.canonical + "\x00" + page.readingTime.text + "\x00" + width + "\x00" + ratio).str()
const cache_key = fnv.hash(page.canonical + "\x00" + page.readingTime.text + "\x00" + width + "\x00" + ratio).str()
let received_etag = request.headers.get("if-none-match");
const received_etag = request.headers.get("if-none-match");
// If the client has a cached version of the image, return a 304 Not Modified response, indicating that the image has not changed
// This means we don't even have to have the image cached in memory
if (received_etag == cache_key) {
@ -71,7 +71,7 @@ export async function GET({ url, request }) {
// If the image is not cached, generate the image and cache it
if (!cache.has(cache_key)) {
// First, render the HTML / JSX-based template
let template = h("div", {
const template = h("div", {
style: {
display: 'flex',
height: '100%',

View file

@ -67,16 +67,16 @@ if (browser) {
const dateRegex = /^((?<year>\d{4})-(?<month>[0][1-9]|1[0-2])-(?<day>[0][1-9]|[1-2]\d|3[01]))\s*/
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Blogs/*.md', { eager: true }))
.map(([filepath, post]) => {
let path = parse(filepath);
let title = path.name.replace(dateRegex, "")
const path = parse(filepath);
const title = path.name.replace(dateRegex, "")
// @ts-ignore
// let {year, month, day}: { year: string, month: string, day: string } = path.name.match(dateRegex)?.groups;
// console.log(year, month, day)
let date = path.name.match(dateRegex)[1];
let datePath = date.replaceAll("-", "/")
let slug = slugify(title, { lower: true })
const date = path.name.match(dateRegex)[1];
const datePath = date.replaceAll("-", "/")
const slug = slugify(title, { lower: true })
return {
title,
date,

View file

@ -6,7 +6,7 @@ const cache = new TTLCache({ max: 10000, ttl: 1000 })
import type { Endpoints } from "@octokit/types";
let repoRegex = new RegExp("https?://github\.com/(?<repo>[a-zA-Z0-9]+/[a-zA-Z0-9]+)/?")
const repoRegex = /https?:\/\/github\.com\/(?<repo>[a-zA-Z0-9]+\/[a-zA-Z0-9]+)\/?/
/** @type {import('./$types').PageServerLoad} */
export async function load({ params }) {
@ -21,13 +21,13 @@ export async function load({ params }) {
let ghReleaseData: Endpoints["GET /repos/{owner}/{repo}/releases/latest"]["response"]["data"] | undefined;
let repo = (page.repo as string).match(repoRegex)?.groups?.repo
const repo = (page.repo as string).match(repoRegex)?.groups?.repo
if (repo) {
if (!cache.has(repo)) {
// console.log("cache miss")
ghReleaseData = await fetch("https://api.github.com/repos/" + repo + "/releases/latest").then(async (res) => {
let json = await res.json()
let ttl = (parse(res.headers.get("cache-control") || undefined)?.maxAge || 60) * 1000
const json = await res.json()
const ttl = (parse(res.headers.get("cache-control") || undefined)?.maxAge || 60) * 1000
cache.set(repo, json, { ttl })
return json
})

View file

@ -11,8 +11,8 @@ if (browser) {
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true }))
.map(([filepath, post]) => {
let path = parse(filepath);
let slug = slugify(path.name, { lower: true })
const path = parse(filepath);
const slug = slugify(path.name, { lower: true })
return {
title: path.name,
// @ts-ignore

91
pnpm-lock.yaml generated
View file

@ -177,6 +177,9 @@ importers:
specifier: ^3.1.1
version: 3.1.1
devDependencies:
'@biomejs/biome':
specifier: 1.9.0
version: 1.9.0
'@bitmachina/highlighter':
specifier: 1.0.0-alpha.6
version: 1.0.0-alpha.6
@ -477,6 +480,59 @@ packages:
resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==}
engines: {node: '>=6.9.0'}
'@biomejs/biome@1.9.0':
resolution: {integrity: sha512-NlWh2F1wbxB3O/wE+aohGL0BziTS6e+6+dyFvpdeqLsbQZY7EsiklFb9W5Xs41U4vEmY7ANgdNp+oVDij6sQdA==}
engines: {node: '>=14.21.3'}
hasBin: true
'@biomejs/cli-darwin-arm64@1.9.0':
resolution: {integrity: sha512-2w9v/NRtYSmodx5QWQ49OGcyGKSECdWKbzc7n532Iq5sBhkKk996fd19icT6BuL54f01KFKRCRibAW+A2rg1Kw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [darwin]
'@biomejs/cli-darwin-x64@1.9.0':
resolution: {integrity: sha512-fBVt8jJQi0zX0SJ1C+tdzUbRpuX/07sgtBXEhunWRkPjdi6W/2S1sYHQ1wKn4OKiRAKfHM2Cf2FNO7hQvY61dA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [darwin]
'@biomejs/cli-linux-arm64-musl@1.9.0':
resolution: {integrity: sha512-Jy84mZ4vcppdmWMgQWOCfd8qIVC/vHmlaS5gy7GXkdWlBKSQ56YxEXTU58MHTbZ16LwJQpK2IulqRCC/rqWLBA==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-arm64@1.9.0':
resolution: {integrity: sha512-l8U2lcqsl9yKPP5WUdIrKH//C1pWyM2cSUfcTBn6GSvXmsSjBNEdGSdM4Wfne777Oe/9ONaD1Ga53U2HksHHLw==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [linux]
'@biomejs/cli-linux-x64-musl@1.9.0':
resolution: {integrity: sha512-N3enoFoIrkB6qJWyYfTiYmFdB1R/Mrij1dd1xBHqxxCKZY9GRkEswRX3F1Uqzo5T+9Iu8nAQobDqI/ygicYy/Q==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-linux-x64@1.9.0':
resolution: {integrity: sha512-8jAzjrrJTj510pwq4aVs7ZKkOvEy1D+nzl9DKvrPh4TOyUw5Ie+0EDwXGE2RAkCKHkGNOQBZ78WtIdsATgz5sA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [linux]
'@biomejs/cli-win32-arm64@1.9.0':
resolution: {integrity: sha512-AIjwJTGfdWGMRluSQ9pDB29nzce077dfHh0/HMqzztKzgD3spyuo2R9VoaFpbR0hLHPWEH6g6OxxDO7hfkXNkQ==}
engines: {node: '>=14.21.3'}
cpu: [arm64]
os: [win32]
'@biomejs/cli-win32-x64@1.9.0':
resolution: {integrity: sha512-4/4wTjNSoyNkm1SzcUaStDx46baX1VJRXtUoeEHjX9LfedR5N3qwZz5KfrRUnCd2fl5bmXK1CwMqKBkoF6zEiA==}
engines: {node: '>=14.21.3'}
cpu: [x64]
os: [win32]
'@bitmachina/highlighter@1.0.0-alpha.6':
resolution: {integrity: sha512-f3KLy64cZnO58GuRswbk/oo3rKoRXz0zE3JtpCrIHr/RmT3gjBH8O1CeKxBdfx3fWvdnrGfEkkHSKBHRbf6/dw==}
@ -4291,6 +4347,41 @@ snapshots:
'@babel/helper-validator-identifier': 7.24.7
to-fast-properties: 2.0.0
'@biomejs/biome@1.9.0':
optionalDependencies:
'@biomejs/cli-darwin-arm64': 1.9.0
'@biomejs/cli-darwin-x64': 1.9.0
'@biomejs/cli-linux-arm64': 1.9.0
'@biomejs/cli-linux-arm64-musl': 1.9.0
'@biomejs/cli-linux-x64': 1.9.0
'@biomejs/cli-linux-x64-musl': 1.9.0
'@biomejs/cli-win32-arm64': 1.9.0
'@biomejs/cli-win32-x64': 1.9.0
'@biomejs/cli-darwin-arm64@1.9.0':
optional: true
'@biomejs/cli-darwin-x64@1.9.0':
optional: true
'@biomejs/cli-linux-arm64-musl@1.9.0':
optional: true
'@biomejs/cli-linux-arm64@1.9.0':
optional: true
'@biomejs/cli-linux-x64-musl@1.9.0':
optional: true
'@biomejs/cli-linux-x64@1.9.0':
optional: true
'@biomejs/cli-win32-arm64@1.9.0':
optional: true
'@biomejs/cli-win32-x64@1.9.0':
optional: true
'@bitmachina/highlighter@1.0.0-alpha.6':
dependencies:
hast-util-to-string: 2.0.0