Spaces:
Sleeping
Sleeping
| import { spawn } from 'node:child_process' | |
| import { promises as fs } from 'node:fs' | |
| import os from 'node:os' | |
| import path from 'node:path' | |
| export type ExportFormat = 'pdf' | 'pptx' | 'html' | |
| export const MIME: Record<ExportFormat, string> = { | |
| pdf: 'application/pdf', | |
| pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation', | |
| html: 'text/html', | |
| } | |
| /** | |
| * Render markdown to a file with marp-cli. PDF/PPTX need headless Chrome (provided in | |
| * the Docker image via CHROME_PATH + CHROME_NO_SANDBOX); HTML needs nothing. | |
| */ | |
| export async function exportDeck(markdown: string, format: ExportFormat): Promise<Buffer> { | |
| const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'marp-')) | |
| const input = path.join(dir, 'deck.md') | |
| const output = path.join(dir, `deck.${format}`) | |
| await fs.writeFile(input, markdown, 'utf8') | |
| try { | |
| const args = [input, '-o', output, '--allow-local-files'] | |
| if (format === 'pdf') args.push('--pdf') | |
| else if (format === 'pptx') args.push('--pptx') | |
| // html is inferred from the .html output extension | |
| await runMarp(args) | |
| return await fs.readFile(output) | |
| } finally { | |
| await fs.rm(dir, { recursive: true, force: true }) | |
| } | |
| } | |
| function runMarp(args: string[]): Promise<void> { | |
| return new Promise((resolve, reject) => { | |
| const bin = path.resolve('node_modules/.bin/marp') | |
| const child = spawn(bin, args, { stdio: ['ignore', 'ignore', 'pipe'] }) | |
| let err = '' | |
| child.stderr.on('data', (d) => { | |
| err += d.toString() | |
| }) | |
| child.on('error', reject) | |
| child.on('close', (code) => | |
| code === 0 ? resolve() : reject(new Error(`marp exited ${code}: ${err.slice(-600)}`)), | |
| ) | |
| }) | |
| } | |