obsidian-limitless-plugin/actors/lifelogs/write.ts
Graham Barber 985383e6a5
feat: initial version
Working proof-of-concept
2025-03-22 18:09:31 -07:00

59 lines
1.8 KiB
TypeScript

import { fromPromise } from "xstate";
import { TFile, Vault } from "obsidian";
import { format, parse } from "@formkit/tempo";
import { ContentNode, Lifelog } from "./query.ts";
interface WriteInput {
vault: Vault;
lifelog: Lifelog;
rootDir: string;
}
// We could just use the markdown output, but the heading levels
// are one unit too high, and we don't need the timestamp links
function formatContentBlock(content: ContentNode): string {
let markdown = "";
if (content.type.startsWith("heading")) {
const [, level] = content.type.split("heading");
const levelNum = Number(level);
markdown += `${"#".repeat(levelNum + 1)} ${content.content}`;
} else if (content.type === "blockquote") {
markdown += `> ${content.speakerName}: ${content.content}`;
}
for (const node of content?.children ?? []) {
markdown += `\n\n${formatContentBlock(node)}`;
}
return markdown;
}
export const writeLifelog = fromPromise(
async ({ input }: { input: WriteInput }) => {
const { vault, lifelog, rootDir } = input;
const start = parse(lifelog.startTime);
const markdown = lifelog.contents.reduce((str, content) => {
return str + `\n\n${formatContentBlock(content)}`;
}, "");
const folder = `${rootDir}/${format(start, "YYYY-MM")}`;
const file = `${format(start, "DD")}.md`;
const dir = vault.getAbstractFileByPath(folder);
if (dir === null) {
await vault.createFolder(folder);
}
const abstract = vault.getAbstractFileByPath(`${folder}/${file}`);
if (abstract instanceof TFile) {
await vault.append(abstract, markdown);
} else {
const page = `# ${format(start, "YYYY-MM-DD")}\n\n${markdown}`;
await vault.create(`${folder}/${file}`, page);
}
return parse(lifelog.endTime);
},
);