import type { Element, MarkdownExtension, BlockContext, Line } from "@lezer/markdown"; import { parseMixed } from "@lezer/common"; import { yaml } from "@codemirror/legacy-modes/mode/yaml"; import { foldInside, foldNodeProp, StreamLanguage } from "@codemirror/language"; import { styleTags, tags } from "@lezer/highlight"; const frontMatterFence = /^---\s*$/m; export const frontmatter: MarkdownExtension = { defineNodes: [{ name: "Frontmatter", block: true }, "FrontmatterMark"], props: [ styleTags({ Frontmatter: [tags.documentMeta, tags.monospace], FrontmatterMark: tags.processingInstruction }), foldNodeProp.add({ Frontmatter: foldInside, FrontmatterMark: () => null }) ], wrap: parseMixed((node) => { const { parser } = StreamLanguage.define(yaml); if (node.type.name === "Frontmatter") { return { parser, overlay: [{ from: node.from + 4, to: node.to - 4 }] }; } return null; }), parseBlock: [ { name: "Frontmatter", before: "HorizontalRule", parse: (cx: BlockContext, line: Line): boolean => { let end: number | undefined = undefined; const children = new Array(); if (cx.lineStart === 0 && frontMatterFence.test(line.text)) { children.push(cx.elt("FrontmatterMark", 0, 4)); while (cx.nextLine()) { if (frontMatterFence.test(line.text)) { end = cx.lineStart + 4; break; } } if (end !== undefined) { children.push(cx.elt("FrontmatterMark", end - 4, end)); cx.addElement(cx.elt("Frontmatter", 0, end, children)); } return true; } return false; } } ] };