import type { RemarkPlugin } from "@astrojs/markdown-remark"; import { mkdtempSync, readFileSync, writeFileSync } from "node:fs"; import { visit } from "unist-util-visit"; import { join, resolve, dirname } from "node:path"; import { spawnSync } from "node:child_process"; import { tmpdir } from "node:os"; import { readdir, copyFile } from "node:fs/promises"; const remarkTypst: RemarkPlugin = () => { const tmp = mkdtempSync(join(tmpdir(), "typst")); let ctr = 0; return async (tree, { history }) => { const path: string = resolve(history[history.length - 1]!); const dir = dirname(path); // Copy all the .typ files in the dir for (const file of await readdir(dir)) { console.log("checking", file); if (file.endsWith(".typ")) { const src = resolve(join(dir, file)); const dst = resolve(join(tmp, file)); console.log("copying", src, dst); await copyFile(src, dst); } } visit( tree, (node) => node.type === "code" && node.lang === "typst", (node, index, parent) => { const doc = resolve(join(tmp, `${ctr}.typ`)); const docOut = resolve(join(tmp, `${ctr}.svg`)); ctr += 1; writeFileSync(doc, node.value); const result = spawnSync("typst", [ "compile", "--format", "svg", doc, docOut, ]); console.log("OUTPUT", result.stderr.toString()); const svgOut = readFileSync(docOut); node.type = "html"; node.value = `
${svgOut.toString()}
`; }, ); }; }; export default remarkTypst;