Add biome and fix typos

This commit is contained in:
Jade Ellis
2024-09-15 18:07:41 +01:00
parent 9522e043a1
commit 76de8f4137
27 changed files with 223 additions and 102 deletions
+30
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"
}
}
}
+8 -8
View File
@@ -76,7 +76,7 @@ import { grammars } from 'tm-grammars'
* @param {string} name * @param {string} name
*/ */
function getGrammar(name) { function getGrammar(name) {
let metadata = grammars.find((grammar) => grammar.name == name) const metadata = grammars.find((grammar) => grammar.name == name)
if (!metadata) { if (!metadata) {
throw "Grammar not found" throw "Grammar not found"
} }
@@ -112,18 +112,18 @@ function buildNestedHeadings(headings) {
/** /**
* @type {{level: number, title: string, children: unknown}[]} * @type {{level: number, title: string, children: unknown}[]}
*/ */
let result = []; const result = [];
let stack = [{ level: 0, children: result }]; const stack = [{ level: 0, children: result }];
for (let heading of headings) { for (const heading of headings) {
while ( while (
stack.length > 1 && stack.length > 1 &&
heading.level <= stack[stack.length - 1].level heading.level <= stack[stack.length - 1].level
) { ) {
stack.pop(); stack.pop();
} }
let parent = stack[stack.length - 1]; const parent = stack[stack.length - 1];
let newHeading = { const newHeading = {
...heading, ...heading,
children: [], children: [],
level: heading.level, level: heading.level,
@@ -151,7 +151,7 @@ function add_toc_remark(opts) {
vFile.data.flattenedHeadings = []; vFile.data.flattenedHeadings = [];
visit(tree, 'heading', (node) => { visit(tree, 'heading', (node) => {
let title = mdast_tree_to_string(node); const title = mdast_tree_to_string(node);
vFile.data.flattenedHeadings.push({ vFile.data.flattenedHeadings.push({
level: node.depth, level: node.depth,
title, title,
@@ -263,7 +263,7 @@ function vite_images_rehype(opts) {
}); });
visit(tree, { tagName: "Components.img" }, (node) => { visit(tree, { tagName: "Components.img" }, (node) => {
let url = node.properties.src; 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"; url = (url.includes("?") ? url + "&" : url + "?") + "url";
node.properties.src = `{${transformUrl(url)}}` node.properties.src = `{${transformUrl(url)}}`
+3 -1
View File
@@ -6,9 +6,11 @@
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "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": { "devDependencies": {
"@biomejs/biome": "1.9.0",
"@bitmachina/highlighter": "1.0.0-alpha.6", "@bitmachina/highlighter": "1.0.0-alpha.6",
"@fontsource/fira-mono": "^5.0.14", "@fontsource/fira-mono": "^5.0.14",
"@json-feed-types/1_1": "^1.0.2", "@json-feed-types/1_1": "^1.0.2",
-2
View File
@@ -13,5 +13,3 @@ declare global {
} }
} }
} }
export {};
+1 -1
View File
@@ -39,7 +39,7 @@ export const handle: Handle = async (input) => {
}), }),
async ({ event, resolve }) => { async ({ event, resolve }) => {
const response = await resolve(event); const response = await resolve(event);
let csp = response.headers.get("Content-Security-Policy"); const csp = response.headers.get("Content-Security-Policy");
if (csp) { if (csp) {
response.headers.set("Content-Security-Policy", csp.replace("script-src", "script-src 'nonce-" + sentryNonce + "'")); response.headers.set("Content-Security-Policy", csp.replace("script-src", "script-src 'nonce-" + sentryNonce + "'"));
} }
+2 -2
View File
@@ -1,13 +1,13 @@
<script lang="ts"> <script lang="ts">
import TocItem from "./TocItem.svelte"; import TocItem from "./TocItem.svelte";
let className = "toc"; const className = "toc";
type FlatHeading = { level: number; title: string }; type FlatHeading = { level: number; title: string };
export let headings: nestedListNode[]; export let headings: nestedListNode[];
// creates a `class` property, even // creates a `class` property, even
// though it is a reserved word // though it is a reserved word
export { className as class }; export { className as class };
export let listType = "ul"; export const listType = "ul";
let open = false; let open = false;
/** @type {import('./$types').Snapshot<string>} */ /** @type {import('./$types').Snapshot<string>} */
+1 -1
View File
@@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
export let node: nestedListNode; export let node: nestedListNode;
export let listType = "ul" export const listType = "ul"
</script> </script>
<li class="toc-item {"toc-item-" + node.level}"> <li class="toc-item {"toc-item-" + node.level}">
@@ -6,7 +6,7 @@
// export let align // export let align
// export let small: boolean; // export let small: boolean;
// console.log("imgcmp", thumb); // console.log("imgcmp", thumb);
let className = ""; const className = "";
export { className as class }; export { className as class };
let loaded = false let loaded = false
// console.log(thumb) // console.log(thumb)
+1 -1
View File
@@ -1,6 +1,6 @@
import { writable } from 'svelte/store' 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') export const theme = writable(query?.matches ? 'dark' : 'light')
+5 -5
View File
@@ -1,5 +1,5 @@
import type { MinifyOptions, MinifyOutput } from "terser"; import type { MinifyOptions, MinifyOutput } from "terser";
import { recieveMessageData, sendMessageData } from "./util"; import { receiveMessageData, sendMessageData } from "./util";
const is_browser = typeof window !== "undefined"; const is_browser = typeof window !== "undefined";
export function init() { export function init() {
@@ -7,7 +7,7 @@ export function init() {
let worker: SharedWorker; let worker: SharedWorker;
let currentId = 0; let currentId = 0;
let terserModule: typeof import("terser"); 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 { return {
minify: async function minify(files: string | string[] | { minify: async function minify(files: string | string[] | {
[file: 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 = new SharedWorker(new URL('./terserWorker.ts', import.meta.url), { type: "module" })
worker.port.onmessage = (e: MessageEvent<any>) => { worker.port.onmessage = (e: MessageEvent<any>) => {
// invoke the promise's resolve() or reject() depending on whether there was an error. // 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 // ... 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) => { return new Promise((resolve, reject) => {
promises[++currentId] = [resolve, reject]; promises[++currentId] = [resolve, reject];
let data = { const data = {
[sendMessageData.MessageId]: currentId, [sendMessageData.MessageId]: currentId,
[sendMessageData.Parameters]: [files, options [sendMessageData.Parameters]: [files, options
] ]
@@ -1,24 +1,24 @@
import { minify, type MinifyOptions } from "terser"; import { minify, type MinifyOptions } from "terser";
import { recieveMessageTypes, sendMessageData } from "./util"; import { receiveMessageTypes, sendMessageData } from "./util";
/// <reference lib="sharedworker " /> /// <reference lib="sharedworker " />
declare var self: SharedWorkerGlobalScope; declare var self: SharedWorkerGlobalScope;
self.onconnect = function (event) { self.onconnect = (event) => {
const port = event.ports[0]; const port = event.ports[0];
port.onmessage = function (e: MessageEvent<{ port.onmessage = (e: MessageEvent<{
[sendMessageData.MessageId]: number, [sendMessageData.MessageId]: number,
[sendMessageData.Parameters]: [string | string[] | { [sendMessageData.Parameters]: [string | string[] | {
[file: string]: string; [file: string]: string;
}, MinifyOptions? }, MinifyOptions?
] ]
}>) { }>) => {
minify(...e.data[sendMessageData.Parameters]).then( minify(...e.data[sendMessageData.Parameters]).then(
// success handler - callback(id, SUCCESS(0), result) // success handler - callback(id, SUCCESS(0), result)
// if `d` is transferable transfer zero-copy // if `d` is transferable transfer zero-copy
d => { d => {
port.postMessage([e.data[0], recieveMessageTypes.RESOLVE, d], port.postMessage([e.data[0], receiveMessageTypes.RESOLVE, d],
// @ts-ignore // @ts-ignore
[d].filter(x => ( [d].filter(x => (
(x instanceof ArrayBuffer) || (x instanceof ArrayBuffer) ||
@@ -27,7 +27,7 @@ self.onconnect = function (event) {
))); )));
}, },
// error handler - callback(id, ERROR(1), error) // error handler - callback(id, ERROR(1), error)
er => { postMessage([e.data[0], recieveMessageTypes.REJECT, '' + er]); } er => { postMessage([e.data[0], receiveMessageTypes.REJECT, '' + er]); }
); );
}; };
+19 -19
View File
@@ -1,9 +1,9 @@
export type FunctionMap = { [x: string]: Function } export type FunctionMap = { [x: string]: Function }
export enum sendMessageData { export enum sendMessageData {
MessageId, MessageId = 0,
Function, Function = 1,
Parameters Parameters = 2
} }
export interface sendMessageMap <T> { export interface sendMessageMap <T> {
@@ -12,27 +12,27 @@ export interface sendMessageMap <T> {
[sendMessageData.Parameters]: T[], [sendMessageData.Parameters]: T[],
} }
export enum recieveMessageTypes { export enum receiveMessageTypes {
RESOLVE, // OK RESOLVE = 0, // OK
REJECT // ERROR REJECT = 1 // ERROR
} }
export enum recieveMessageData { export enum receiveMessageData {
MessageId, MessageId = 0,
MessageType, MessageType = 1,
Return Return = 2
} }
export interface recieveMessageMap <T> { export interface receiveMessageMap <T> {
[recieveMessageData.MessageId]: number, [receiveMessageData.MessageId]: number,
[recieveMessageData.MessageType]: recieveMessageTypes, [receiveMessageData.MessageType]: receiveMessageTypes,
[recieveMessageData.Return]: T, [receiveMessageData.Return]: T,
} }
// // worker // // worker
// import { recieveMessageTypes, type FunctionMap } from "./util"; // import { receiveMessageTypes, type FunctionMap } from "./util";
// function makeMessageHandler(functions: FunctionMap) { // function makeMessageHandler(functions: FunctionMap) {
@@ -44,20 +44,20 @@ export interface recieveMessageMap <T> {
// // success handler - callback(id, SUCCESS(0), result) // // success handler - callback(id, SUCCESS(0), result)
// // if `d` is transferable transfer zero-copy // // if `d` is transferable transfer zero-copy
// d => { // 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 ArrayBuffer) ||
// (x instanceof MessagePort) || // (x instanceof MessagePort) ||
// (self.ImageBitmap && x instanceof ImageBitmap) // (self.ImageBitmap && x instanceof ImageBitmap)
// ))); // )));
// }, // },
// // error handler - callback(id, ERROR(1), error) // // error handler - callback(id, ERROR(1), error)
// er => { postMessage([e.data[0], recieveMessageTypes.ERROR, '' + er]); } // er => { postMessage([e.data[0], receiveMessageTypes.ERROR, '' + er]); }
// ); // );
// } // }
// } // }
// // host // // 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) { // function makeHostHandler(worker: Worker) {
@@ -72,7 +72,7 @@ export interface recieveMessageMap <T> {
// * status - 0 for success, 1 for failure // * status - 0 for success, 1 for failure
// * result - the result or error, depending on `status` // * 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. // // invoke the promise's resolve() or reject() depending on whether there was an error.
// promises[e.data[0]][e.data[1]](e.data[2]); // promises[e.data[0]][e.data[1]](e.data[2]);
@@ -13,20 +13,20 @@
restore: (v: string) => (value = v), restore: (v: string) => (value = v),
}; };
let minify = init().minify; const minify = init().minify;
let value = ""; let value = "";
let output = ""; let output = "";
let options: Config = {}; let options: Config = {};
async function process(str: string) { async function process(str: string) {
options = await parseMeta(str); options = await parseMeta(str);
let res = await bookmarkify(str, options, minify); const res = await bookmarkify(str, options, minify);
if (typeof res == "string") { if (typeof res == "string") {
output = res; output = res;
} }
} }
let contentAttributes = { "aria-label": "Bookmarklet editor" }; const contentAttributes = { "aria-label": "Bookmarklet editor" };
$: progress = process(value); $: progress = process(value);
</script> </script>
@@ -2,9 +2,9 @@
// import MagicString from "magic-string"; // import MagicString from "magic-string";
import { Parser } from "acorn"; 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 { configSchema } from "./config.schema";
import type { Config } from "./config"; import type { Config } from "./config";
@@ -18,14 +18,14 @@ export async function bookmarkify(code: string, options: Config, minify: (files:
if (options.script) { if (options.script) {
options.script = options.script.reverse(); options.script = options.script.reverse();
options.script.forEach(s => { options.script.forEach(s => {
let { path, opts } = extractOptions(s); const { path, opts } = extractOptions(s);
code = loadScript(code, path, opts.loadOnce); code = loadScript(code, path, opts.loadOnce);
}); });
} }
if (options.style) { if (options.style) {
options.style.forEach(s => { options.style.forEach(s => {
let { path, opts } = extractOptions(s); const { path, opts } = extractOptions(s);
code = loadStyle(path, opts.loadOnce) + code; 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> { export async function parseMeta(str: string): Promise<Config> {
enum MetaState { enum MetaState {
PreOpen, PreOpen = 0,
Opened, Opened = 1,
Closed Closed = 2
} }
let state: MetaState = MetaState.PreOpen let state: MetaState = MetaState.PreOpen
@@ -53,7 +53,7 @@ export async function parseMeta(str: string): Promise<Config> {
const openMetadata = /==bookmarklet==/gim; const openMetadata = /==bookmarklet==/gim;
const closeMetadata = /==\/bookmarklet==/gim; const closeMetadata = /==\/bookmarklet==/gim;
const metaLine = /^[\s]*@([^\s]+)\s+(.*)$/gim; const metaLine = /^[\s]*@([^\s]+)\s+(.*)$/gim;
let options: Config = {}; const options: Config = {};
Parser.parse(str, { Parser.parse(str, {
ecmaVersion: "latest", ecmaVersion: "latest",
@@ -62,7 +62,7 @@ export async function parseMeta(str: string): Promise<Config> {
closeMetadata.lastIndex = 0; closeMetadata.lastIndex = 0;
metaLine.lastIndex = 0; metaLine.lastIndex = 0;
if (state == MetaState.PreOpen) { if (state == MetaState.PreOpen) {
let res = openMetadata.exec(text) const res = openMetadata.exec(text)
if (res !== null) { if (res !== null) {
state = MetaState.Opened state = MetaState.Opened
closeMetadata.lastIndex = openMetadata.lastIndex; 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) { while (state == MetaState.Opened && (res = metaLine.exec(text)) !== null) {
closeMetadata.lastIndex = metaLine.lastIndex; closeMetadata.lastIndex = metaLine.lastIndex;
// console.log(str.slice(start + 2 + (metaLine.lastIndex - res[0].length), start + 2 + metaLine.lastIndex )) // console.log(str.slice(start + 2 + (metaLine.lastIndex - res[0].length), start + 2 + metaLine.lastIndex ))
let k = res[1]; const k = res[1];
let v = res[2]; const v = res[2];
if (k) { if (k) {
if (configSchema.properties[k]?.type == "array") { if (configSchema.properties[k]?.type == "array") {
options[k] = options[k] || []; options[k] = options[k] || [];
@@ -90,7 +90,7 @@ export async function parseMeta(str: string): Promise<Config> {
} }
if (state == MetaState.Opened) { if (state == MetaState.Opened) {
let endRes = closeMetadata.exec(text) const endRes = closeMetadata.exec(text)
if (endRes !== null) { if (endRes !== null) {
state = MetaState.Closed; state = MetaState.Closed;
@@ -110,7 +110,7 @@ export async function parseMeta(str: string): Promise<Config> {
function loadScript(code: string, path: string, loadOnce: boolean) { function loadScript(code: string, path: string, loadOnce: boolean) {
loadOnce = !!loadOnce; 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 ` return `
function callback(){ function callback(){
${code} ${code}
@@ -136,7 +136,7 @@ function loadScript(code: string, path: string, loadOnce: boolean) {
function loadStyle(path: string, loadOnce: boolean) { function loadStyle(path: string, loadOnce: boolean) {
loadOnce = !!loadOnce; 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 ` return `
if (!${loadOnce} || !document.getElementById("${id}")) { if (!${loadOnce} || !document.getElementById("${id}")) {
var link = document.createElement("link"); 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`. // 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. // 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 m
let splitAfter = 0; let splitAfter = 0;
while ((m = matcher.exec(path)) !== null) { while ((m = matcher.exec(path)) !== null) {
splitAfter = matcher.lastIndex; 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]); opts[opt[0]] = opt[1] === undefined ? true : _fuzzyParse(opt[1]);
// break // break
} }
@@ -11,7 +11,7 @@
restore: (v: string) => (value = v), restore: (v: string) => (value = v),
}; };
let minify = init().minify; const minify = init().minify;
let value = ""; let value = "";
let output = ""; let output = "";
@@ -20,7 +20,7 @@
output = ""; output = "";
return; return;
} }
let result = await minify(str); const result = await minify(str);
if (typeof result.code == "string") { if (typeof result.code == "string") {
output = result.code; output = result.code;
} else { } else {
@@ -28,7 +28,7 @@
} }
} }
let contentAttributes = { "aria-label": "Javascript editor" }; const contentAttributes = { "aria-label": "Javascript editor" };
$: progress = process(value); $: progress = process(value);
</script> </script>
+1 -1
View File
@@ -9,7 +9,7 @@
const title = `${status}: ${message}`; const title = `${status}: ${message}`;
let sentryElement: HTMLDivElement; let sentryElement: HTMLDivElement;
let openForm = () => {}; let openForm = () => {};
let online = typeof navigator !== 'undefined' ? navigator.onLine : true; const online = typeof navigator !== 'undefined' ? navigator.onLine : true;
onMount(async () => { onMount(async () => {
const feedback = Sentry.getFeedback({ const feedback = Sentry.getFeedback({
el: sentryElement, el: sentryElement,
@@ -29,15 +29,15 @@ const accounts = [
].map(i => i.toLowerCase()) ].map(i => i.toLowerCase())
export async function GET({ url }: RequestEvent) { export async function GET({ url }: RequestEvent) {
// export const GET = async ({ url }) => { // export const GET = async ({ url }) => {
let resource = url.searchParams.get("resource"); const resource = url.searchParams.get("resource");
if (resource?.split(":")[0] !== "acct") { if (resource?.split(":")[0] !== "acct") {
let res = new Response("", { status: 404 }) const res = new Response("", { status: 404 })
return res; return res;
} }
let account = resource?.split(":")[1] const account = resource?.split(":")[1]
if (!accounts.includes(account.toLowerCase()) && !account.toLowerCase().endsWith("@jade.ellis.link")) { if (!accounts.includes(account.toLowerCase()) && !account.toLowerCase().endsWith("@jade.ellis.link")) {
if (resource?.split(":")[0] !== "acct") { if (resource?.split(":")[0] !== "acct") {
let res = new Response("", { status: 404 }) const res = new Response("", { status: 404 })
return res; return res;
} }
} }
@@ -75,6 +75,6 @@ export async function GET({ url }: RequestEvent) {
] ]
} }
// const isMe = (user.toLowerCase() == EMAIL.toLowerCase()) ? true : false; // 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; return res;
} }
@@ -5,7 +5,7 @@
import type { WithContext, Thing } from "schema-dts"; import type { WithContext, Thing } from "schema-dts";
export let data; export let data;
let { pages } = data; const { pages } = data;
const jsonLd = { const jsonLd = {
"@context": "https://schema.org", "@context": "https://schema.org",
@@ -11,7 +11,7 @@ import { error } from '@sveltejs/kit'
/** @type {import('./$types').PageServerLoad} */ /** @type {import('./$types').PageServerLoad} */
export async function load({ params }) { export async function load({ params }) {
const { slug } = 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) { if (dateParts.length > 3) {
throw error(404, 'Post not found (bad date)') throw error(404, 'Post not found (bad date)')
} }
@@ -25,7 +25,7 @@ export async function load({ params }) {
const page = pages const page = pages
.filter((post) => slug === post.slug) .filter((post) => slug === post.slug)
.filter((post) => { .filter((post) => {
let date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) && (!dateParts[1] || date.getMonth()+1 == dateParts[1]) &&
@@ -21,7 +21,7 @@
ratio?: number, ratio?: number,
width?: number, width?: number,
): URL { ): 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("slug", slug);
url.searchParams.set("date", date); url.searchParams.set("date", date);
if (ratio) { if (ratio) {
@@ -39,7 +39,7 @@
$: handleWebShare; $: handleWebShare;
const handleWebShare = async () => { const handleWebShare = async () => {
try { try {
let url = new URL(canonical); const url = new URL(canonical);
url.searchParams.set("utm_medium", "share"); url.searchParams.set("utm_medium", "share");
await navigator.share({ await navigator.share({
title: data.post.title, title: data.post.title,
@@ -14,14 +14,14 @@ import { error } from '@sveltejs/kit'
// export const prerender = true; // export const prerender = true;
export async function GET({ params, url}) { 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) { if (dateParts.length > 3) {
throw error(404, 'Feed not found (bad date)') throw error(404, 'Feed not found (bad date)')
} }
const selectedPages = dateParts.length ? pages const selectedPages = dateParts.length ? pages
.filter((post) => { .filter((post) => {
let date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) && (!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 postUrl = SITE_URL + "/blog/" + post.canonical
// const postHtml = // const postHtml =
const summary = post.description; const summary = post.description;
let item: typeof feed.items[number] = { const item: typeof feed.items[number] = {
id: post.postUrl, id: post.postUrl,
title, title,
url: postUrl, url: postUrl,
@@ -15,7 +15,7 @@ import { error } from '@sveltejs/kit'
// export const prerender = true; // export const prerender = true;
export async function GET({ url, params }) { 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) { if (dateParts.length > 3) {
throw error(404, 'Feed not found (bad date)') throw error(404, 'Feed not found (bad date)')
} }
@@ -23,7 +23,7 @@ export async function GET({ url, params }) {
const selectedPages = dateParts.length ? pages const selectedPages = dateParts.length ? pages
.filter((post) => { .filter((post) => {
console.log("filtering") console.log("filtering")
let date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth()+1 == dateParts[1]) && (!dateParts[1] || date.getMonth()+1 == dateParts[1]) &&
@@ -24,7 +24,7 @@ export async function GET({ url, request }) {
// First, get the information about the post // 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 // We have the slug and date of the post, which we can use to look up the post
const slug = url.searchParams.get('slug') 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) { if (dateParts && dateParts.length > 3) {
throw error(404, 'Post not found (bad date)') 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) => slug === post.slug)
.filter((post) => { .filter((post) => {
if (dateParts) { if (dateParts) {
let date = new Date(post.date) const date = new Date(post.date)
return ( return (
(!dateParts[0] || date.getFullYear() == dateParts[0]) && (!dateParts[0] || date.getFullYear() == dateParts[0]) &&
(!dateParts[1] || date.getMonth() + 1 == dateParts[1]) && (!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 // 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 // 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 // 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 // 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 // This means we don't even have to have the image cached in memory
if (received_etag == cache_key) { 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 the image is not cached, generate the image and cache it
if (!cache.has(cache_key)) { if (!cache.has(cache_key)) {
// First, render the HTML / JSX-based template // First, render the HTML / JSX-based template
let template = h("div", { const template = h("div", {
style: { style: {
display: 'flex', display: 'flex',
height: '100%', height: '100%',
+5 -5
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*/ 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 })) export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Blogs/*.md', { eager: true }))
.map(([filepath, post]) => { .map(([filepath, post]) => {
let path = parse(filepath); const path = parse(filepath);
let title = path.name.replace(dateRegex, "") const title = path.name.replace(dateRegex, "")
// @ts-ignore // @ts-ignore
// let {year, month, day}: { year: string, month: string, day: string } = path.name.match(dateRegex)?.groups; // let {year, month, day}: { year: string, month: string, day: string } = path.name.match(dateRegex)?.groups;
// console.log(year, month, day) // console.log(year, month, day)
let date = path.name.match(dateRegex)[1]; const date = path.name.match(dateRegex)[1];
let datePath = date.replaceAll("-", "/") const datePath = date.replaceAll("-", "/")
let slug = slugify(title, { lower: true }) const slug = slugify(title, { lower: true })
return { return {
title, title,
date, date,
@@ -6,7 +6,7 @@ const cache = new TTLCache({ max: 10000, ttl: 1000 })
import type { Endpoints } from "@octokit/types"; 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} */ /** @type {import('./$types').PageServerLoad} */
export async function load({ params }) { 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 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 (repo) {
if (!cache.has(repo)) { if (!cache.has(repo)) {
// console.log("cache miss") // console.log("cache miss")
ghReleaseData = await fetch("https://api.github.com/repos/" + repo + "/releases/latest").then(async (res) => { ghReleaseData = await fetch("https://api.github.com/repos/" + repo + "/releases/latest").then(async (res) => {
let json = await res.json() const json = await res.json()
let ttl = (parse(res.headers.get("cache-control") || undefined)?.maxAge || 60) * 1000 const ttl = (parse(res.headers.get("cache-control") || undefined)?.maxAge || 60) * 1000
cache.set(repo, json, { ttl }) cache.set(repo, json, { ttl })
return json return json
}) })
@@ -11,8 +11,8 @@ if (browser) {
export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true })) export const pages = Object.entries(import.meta.glob('/node_modules/Notes/Projects/*.md', { eager: true }))
.map(([filepath, post]) => { .map(([filepath, post]) => {
let path = parse(filepath); const path = parse(filepath);
let slug = slugify(path.name, { lower: true }) const slug = slugify(path.name, { lower: true })
return { return {
title: path.name, title: path.name,
// @ts-ignore // @ts-ignore
+91
View File
@@ -177,6 +177,9 @@ importers:
specifier: ^3.1.1 specifier: ^3.1.1
version: 3.1.1 version: 3.1.1
devDependencies: devDependencies:
'@biomejs/biome':
specifier: 1.9.0
version: 1.9.0
'@bitmachina/highlighter': '@bitmachina/highlighter':
specifier: 1.0.0-alpha.6 specifier: 1.0.0-alpha.6
version: 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==} resolution: {integrity: sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==}
engines: {node: '>=6.9.0'} 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': '@bitmachina/highlighter@1.0.0-alpha.6':
resolution: {integrity: sha512-f3KLy64cZnO58GuRswbk/oo3rKoRXz0zE3JtpCrIHr/RmT3gjBH8O1CeKxBdfx3fWvdnrGfEkkHSKBHRbf6/dw==} resolution: {integrity: sha512-f3KLy64cZnO58GuRswbk/oo3rKoRXz0zE3JtpCrIHr/RmT3gjBH8O1CeKxBdfx3fWvdnrGfEkkHSKBHRbf6/dw==}
@@ -4291,6 +4347,41 @@ snapshots:
'@babel/helper-validator-identifier': 7.24.7 '@babel/helper-validator-identifier': 7.24.7
to-fast-properties: 2.0.0 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': '@bitmachina/highlighter@1.0.0-alpha.6':
dependencies: dependencies:
hast-util-to-string: 2.0.0 hast-util-to-string: 2.0.0