|
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<Element>(); |
|
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; |
|
} |
|
} |
|
] |
|
}; |
|
|