import type {AstroIntegration, ContentEntryType, HookParameters} from "astro" import {fileURLToPath} from "url" import gemtextVitePlugin from "./vitePlugin.js" import { parse as parseYaml } from "yaml"; /** Gemtext configuration options */ export interface GemtextConfig { /** Absolute import path to the layout to use for all gemtext pages. * If not provided, HMR and the Astro toolbar will not work. (default: none) */ layout?: string /** The format to use for the page title. Can be one of: * - `first-heading`: The first heading in the document will be used as the title. (default) * - `filename`: The filename of the document will be used as the title. */ titleFormat?: "first-heading" | "filename" } type SetupHookParams = HookParameters<"astro:config:setup"> & { // `addPageExtension` and `contentEntryType` are not a public APIs // Add type defs here addPageExtension: (extension: string) => void addContentEntryType: (contentEntryType: ContentEntryType) => void } export default function gemtext(config: GemtextConfig = {}): AstroIntegration { if (!config.titleFormat) { config.titleFormat = "first-heading" } return { name: "astro-gemtext", hooks: { "astro:config:setup": async (_params) => { const params = _params as SetupHookParams params.addPageExtension('.gmi') params.addContentEntryType({ extensions: ['.gmi'], getEntryInfo: async ({ fileUrl, contents }) => { const lines = contents.split('\n'); let data: Record = {}; let frontmatter = ''; let bodyStartLineIndex = 0; if (lines.at(0) === '---' && lines.lastIndexOf('---') > 0) { bodyStartLineIndex = lines.indexOf('---', 1) + 1; frontmatter = lines.slice(1, bodyStartLineIndex).join('\n'); try { data = { ...data, ...parseYaml(frontmatter, { schema: 'yaml-1.1' }) }; } catch { } } return { data, rawData: frontmatter, body: lines.slice(bodyStartLineIndex).join('\n'), slug: typeof data['slug'] === 'string' ? data['slug'] : fileUrl.pathname, }; }, }) params.updateConfig({ vite: { plugins: [gemtextVitePlugin(config)], }, }) }, }, } }