102 lines
2.3 KiB
TypeScript
102 lines
2.3 KiB
TypeScript
import {
|
|
createDocument,
|
|
getDocument,
|
|
getDocuments,
|
|
transformDocument,
|
|
} from "@lib/documents.ts";
|
|
import { Root } from "https://esm.sh/remark-frontmatter@4.0.1";
|
|
import { getThumbhash } from "@lib/cache/image.ts";
|
|
|
|
type Resource = {
|
|
name: string;
|
|
id: string;
|
|
meta: {
|
|
image?: string;
|
|
author?: string;
|
|
thumbnail?: string;
|
|
};
|
|
};
|
|
|
|
export async function addThumbnailToResource<T = Resource>(
|
|
res: T,
|
|
): Promise<T> {
|
|
const imageUrl = res?.meta?.image;
|
|
if (!imageUrl) return res;
|
|
const thumbhash = await getThumbhash({ url: imageUrl });
|
|
if (!thumbhash) return res;
|
|
return {
|
|
...res,
|
|
meta: {
|
|
...res?.meta,
|
|
thumbnail: thumbhash,
|
|
},
|
|
};
|
|
}
|
|
|
|
export function createCrud<T>(
|
|
{ prefix, parse, render, hasThumbnails = false }: {
|
|
prefix: string;
|
|
hasThumbnails?: boolean;
|
|
render?: (doc: T) => string;
|
|
parse: (doc: string, id: string) => T;
|
|
},
|
|
) {
|
|
function pathFromId(id: string) {
|
|
return `${prefix}${id.replaceAll(":", "")}.md`;
|
|
}
|
|
|
|
async function read(id: string) {
|
|
const path = pathFromId(id);
|
|
const content = await getDocument(path);
|
|
const res = parse(content, id);
|
|
|
|
if (hasThumbnails) {
|
|
return addThumbnailToResource(res);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
function create(id: string, content: string | ArrayBuffer | T) {
|
|
const path = pathFromId(id);
|
|
if (
|
|
typeof content === "string" || content instanceof ArrayBuffer
|
|
) {
|
|
return createDocument(path, content);
|
|
}
|
|
|
|
if (render) {
|
|
return createDocument(path, render(content));
|
|
}
|
|
|
|
throw new Error("No renderer defined for " + prefix + " CRUD");
|
|
}
|
|
|
|
async function update(id: string, updater: (r: Root) => Root) {
|
|
const path = pathFromId(id);
|
|
const content = await getDocument(path);
|
|
const newDoc = transformDocument(content, updater);
|
|
await createDocument(path, newDoc);
|
|
}
|
|
|
|
async function readAll() {
|
|
const allDocuments = await getDocuments();
|
|
return Promise.all(
|
|
allDocuments.filter((d) => {
|
|
return d.name.startsWith(prefix) &&
|
|
d.contentType === "text/markdown" &&
|
|
!d.name.endsWith("index.md");
|
|
}).map((doc) => {
|
|
const id = doc.name.replace(prefix, "").replace(/\.md$/, "");
|
|
return read(id);
|
|
}),
|
|
);
|
|
}
|
|
|
|
return {
|
|
read,
|
|
readAll,
|
|
create,
|
|
update,
|
|
};
|
|
}
|