Files
astro-gemtext/src/vitePlugin.ts
T

65 lines
1.9 KiB
TypeScript

import {HTMLRenderer, parse} from "gemtext"
import path from "path"
import {pathToFileURL} from "url"
import type {Plugin} from "vite"
import {ext, type GemtextConfig} from "./index.js"
function transform(code: string, id: string, config: GemtextConfig) {
const result = parse(code)
let title
if (config.titleFormat === "first-heading") {
for (const node of result.data) {
if (node._ === 4) {
title = node.text
break
}
}
} else if (config.titleFormat === "filename") {
title = path.basename(id)
}
const html = result.generate(HTMLRenderer)
return `
import {
createComponent,
render,
renderComponent,
unescapeHTML,
} from "astro/runtime/server/index.js";
import { Fragment, jsx as h } from "astro/jsx-runtime";
${config.layout ? `import Layout from ${JSON.stringify(config.layout)};` : ""}
export const name = "TypstComponent";
export const html = ${JSON.stringify(html)};
export const frontmatter = undefined;
export const file = ${JSON.stringify(id)};
export const url = ${JSON.stringify(pathToFileURL(id))};
export function compiledContent() {
return html;
}
export function getHeadings() {
return undefined;
}
export async function Content() {
const content = h(Fragment, {"set:html": html});
${config.layout ? `return h(Layout, {title: ${JSON.stringify(title)}, children: content});` : ""}
${!config.layout ? `return content;` : ""}
}
export default Content;
`
}
export default function gemtextVitePlugin(config: GemtextConfig): Plugin {
// let server: ViteDevServer
return {
name: "astro-gemtext",
enforce: "pre",
transform(code, id) {
if (!id.endsWith(`.${ext}`)) return
return {
code: transform(code, id, config),
map: null,
}
},
}
}