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"], getRenderFunction: async (config) => { return async (entry) => ({ html: entry.body ?? '', frontmatter: entry.data, }); }, 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 - 1) .join("\n") try { data = { ...data, ...parseYaml(frontmatter, {schema: "yaml-1.1"}), } } catch (e) { console.debug( "Failed to parse YAML frontmatter in gemtext:", e, ) } } const body = lines.slice(bodyStartLineIndex).join("\n") const slug = typeof data["slug"] === "string" ? data["slug"] : fileURLToPath(fileUrl).slice( fileURLToPath(fileUrl).lastIndexOf("/") + 1, ) return { data, rawData: frontmatter, body, slug, } }, }) params.updateConfig({ vite: { plugins: [gemtextVitePlugin(config)], }, }) }, }, } }