Welcome to mirror list, hosted at ThFree Co, Russian Federation.

table_of_contents.js « glfm_extensions « gfm « lib « javascripts « assets « app - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 4d2484a657ab5808dc167700996d0f6f7f09ddea (plain)
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
79
80
81
82
83
84
85
import { first, last } from 'lodash';
import { u } from 'unist-builder';
import { visitParents, SKIP, CONTINUE } from 'unist-util-visit-parents';
import {
  TABLE_OF_CONTENTS_DOUBLE_BRACKET_CLOSE_TOKEN,
  TABLE_OF_CONTENTS_DOUBLE_BRACKET_MIDDLE_TOKEN,
  TABLE_OF_CONTENTS_DOUBLE_BRACKET_OPEN_TOKEN,
  TABLE_OF_CONTENTS_SINGLE_BRACKET_TOKEN,
  MDAST_TEXT_NODE,
  MDAST_EMPHASIS_NODE,
  MDAST_PARAGRAPH_NODE,
  GLFM_TABLE_OF_CONTENTS_NODE,
} from '../constants';

const isTOCTextNode = ({ type, value }) =>
  type === MDAST_TEXT_NODE && value === TABLE_OF_CONTENTS_DOUBLE_BRACKET_MIDDLE_TOKEN;

const isTOCEmphasisNode = ({ type, children }) =>
  type === MDAST_EMPHASIS_NODE && children.length === 1 && isTOCTextNode(first(children));

const isTOCDoubleSquareBracketOpenTokenTextNode = ({ type, value }) =>
  type === MDAST_TEXT_NODE && value.trim() === TABLE_OF_CONTENTS_DOUBLE_BRACKET_OPEN_TOKEN;

const isTOCDoubleSquareBracketCloseTokenTextNode = ({ type, value }) =>
  type === MDAST_TEXT_NODE && value.trim() === TABLE_OF_CONTENTS_DOUBLE_BRACKET_CLOSE_TOKEN;

/*
 * Detects table of contents declaration with syntax [[_TOC_]]
 */
const isTableOfContentsDoubleSquareBracketSyntax = ({ children }) => {
  if (children.length !== 3) {
    return false;
  }

  const [firstChild, middleChild, lastChild] = children;

  return (
    isTOCDoubleSquareBracketOpenTokenTextNode(firstChild) &&
    isTOCEmphasisNode(middleChild) &&
    isTOCDoubleSquareBracketCloseTokenTextNode(lastChild)
  );
};

/*
 * Detects table of contents declaration with syntax [TOC]
 */
const isTableOfContentsSingleSquareBracketSyntax = ({ children }) => {
  if (children.length !== 1) {
    return false;
  }

  const [firstChild] = children;
  const { type, value } = firstChild;

  return type === MDAST_TEXT_NODE && value.trim() === TABLE_OF_CONTENTS_SINGLE_BRACKET_TOKEN;
};

const isTableOfContentsNode = (node) =>
  node.type === MDAST_PARAGRAPH_NODE &&
  (isTableOfContentsDoubleSquareBracketSyntax(node) ||
    isTableOfContentsSingleSquareBracketSyntax(node));

export default () => {
  return (tree) => {
    visitParents(tree, (node, ancestors) => {
      const parent = last(ancestors);

      if (!parent) {
        return CONTINUE;
      }

      if (isTableOfContentsNode(node)) {
        const index = parent.children.indexOf(node);

        parent.children[index] = u(GLFM_TABLE_OF_CONTENTS_NODE, {
          position: node.position,
        });
      }

      return SKIP;
    });

    return tree;
  };
};