All files / markdown / plugins / frontmatter.ts

90.00% Branches 18/20
100.00% Functions 1/1
84.38% Lines 27/32
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
 
 
x20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
x20
x3
x9
x9
x9
x9
x3
x9
x6
x6
x3
x3
x3
x6
 
 
x3
x3
x3
 
 
 
x3
x3
x3
x3
x3
x3
x3
x3
x3





































I



I










// Imports
import type { MarkdownIt } from "../types.ts"
import { parse } from "@std/yaml/parse"

/**
 * Support for frontmatter.
 *
 * Passing `metadata: true` to the markdown rendering method is required to retrieve the frontmatter.
 * The frontmatter is automatically parsed as YAML.
 *
 * ```md
 * ---
 * title: foo
 * ---
 * ```
 * ```ts
 * import { Renderer } from "../renderer.ts"
 *
 * const markdown = new Renderer({ frontmatter: true })
 * const { metadata } = markdown.render("---\ntitle: foo\n---\nbar", { metadata: true })
 * console.log(metadata.frontmatter) // { title: "foo" }
 * ```
 */
export default function frontmatter(engine: MarkdownIt): void {
  engine.block.ruler.before("table", "frontmatter", (state, startLine, endLine, silent) => {
    if ((startLine !== 0) || (state.blkIndent !== 0) || (state.tShift[0] > 0))
      return false
    if (state.src.slice(state.bMarks[0], state.eMarks[0]).trimEnd() !== "---")
      return false
    let close = -1
    for (let line = 1; line < endLine; line++) {
      const text = state.src.slice(state.bMarks[line], state.eMarks[line]).trimEnd()
      if ((text === "---") || (text === "...")) {
        close = line
        break
      }
    }
    if (close < 0)
      return false
    let parsed
    try {
      parsed = parse(state.getLines(1, close, 0, false))
    } catch {
      return false
    }
    if (!silent) {
      const env = state.env as { metadata?: Record<PropertyKey, unknown> }
      env.metadata ??= {}
      env.metadata.frontmatter = parsed
      state.line = close + 1
    }
    return true
  })
}