# All files / src/lib/markdown-it/plugins markdown-it-alt-frontmatter.ts

97.14% Statements 34/35
90.9% Branches 10/11
100% Functions 3/3
97.14% Lines 34/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    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
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78

    17x

    531x
    531x

    531x
    531x
    531x
    531x
    523x

    8x
    8x
    8x
    24x
    24x

    24x
    24x
    5x
    5x

    19x

    2x

    6x
    1x

    5x
    5x

    5x
    5x
    5x
    5x
    5x
    5x

    24x
    24x

    5x
    5x
    5x

     import MarkdownIt, { Options } from 'markdown-it';
    import StateBlock from 'markdown-it/lib/rules_block/state_block';
    import Token from 'markdown-it/lib/token';
    import Renderer from 'markdown-it/lib/renderer';

    /*
     * This file exports a MarkdownIt plugin that converts YAML-style frontmatter syntax (---)
     * into HTML-style `<frontmatter>` tags.
     * Only if there are two sets of `---` and the content inside contains key-value pairs or blank space.
     */

    /**
     * Markdown-it plugin to parse alternative frontmatter blocks delimited by '---'.
     *
     * This plugin detects blocks anywhere in a Markdown document that begin and end with '---',
     * and contain lines in key-value format (e.g., `key: value`). Blank lines within the block are allowed.
     * If a block is detected, it is rendered as a `<frontmatter>` HTML element containing the block's content.
     */
    export function altFrontmatterPlugin(md: MarkdownIt): void {
      function alt_frontmatter(state: StateBlock, startLine: number, endLine: number): boolean {
        const fmSymbol = '---';
        const keyValueRegex = /^\w+:\s+.*/;

        let lineStart = state.bMarks[startLine] + state.tShift[startLine];
        let lineEnd = state.eMarks[startLine];
        const marker = state.src.slice(lineStart, lineEnd);
        if (marker !== fmSymbol) {
          return false;
        }

        let haveEndMarker = false;
        let nextLine = startLine + 1;
        for (; nextLine < endLine; nextLine += 1) {
          lineStart = state.bMarks[nextLine] + state.tShift[nextLine];
          lineEnd = state.eMarks[nextLine];

          const currLine = state.src.slice(lineStart, lineEnd).trim();
          if (currLine === fmSymbol) {
            haveEndMarker = true;
            break;
          }
          if (!(keyValueRegex.test(currLine) || currLine.length === 0)) {
            // terminates if not key value or blank line.
            return false;
          }
        }

        if (!haveEndMarker) {
          return false;
        }
        // If a fence has heading spaces, they should be removed from its inner block
        const len = state.sCount[startLine];
        state.line = nextLine + (haveEndMarker ? 1 : 0);

        const token: Token = state.push('alt_frontmatter', '', 0);
        token.info = fmSymbol;
        token.content = state.getLines(startLine + 1, nextLine, len, true);
        token.markup = marker;
        token.map = [startLine, state.line];
        return true;
      }

      md.block.ruler.before('fence', 'alt_frontmatter', alt_frontmatter);
      md.renderer.rules.alt_frontmatter = (
        tokens: Token[],
        idx: number,
        options: Options,
        env: any,
        slf: Renderer,
      ) => {
        const token = tokens[idx];
        if (token.type === 'alt_frontmatter' && token.info === '---') {
          return `<frontmatter>\n${token.content}</frontmatter>\n`;
        }
        return slf.renderToken(tokens, idx, options);
      };
    }