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); }, );