aboutsummaryrefslogtreecommitdiff
path: root/src/remark/admonition-title-to-heading-before-toc.js
blob: 65e29d74c9f86705ee50facbb8a1e23cc7dacdd2 (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
86
87
import {visit} from 'unist-util-visit';
import {inspect} from 'unist-util-inspect';

/*
Admonitionのツリー構造
{
  type: 'containerDirective',
  name: 'info',
  attributes: {},
  children: [
    {
      type: 'paragraph',
      data: { directiveLabel: true },
      children: [
        {
          type: 'text',
          value: '#### info title もしHTML等が入ると(ここにaタグを入れると)',
          position: [Object]
        },
        {
          type: 'mdxJsxTextElement',
          name: 'a',
          attributes: [],
          position: [Object],
          data: [Object],
          children: [Array]
        },
        { type: 'text', value: 'このようにタイトル部が別々の要素として配列に入っている。', position: [Object] }
      ],
      position: {
        start: { line: 1347, column: 8, offset: 34053 },
        end: { line: 1347, column: 55, offset: 34100 }
      }
    },
    { type: 'paragraph', children: [Array], position: [Object] },
    ...
  ],
  ...
}
*/
const plugin = (options) => {
  const transformer = async (ast) => {
    let newBeginningText = "";
    const visitor = ((node, index, parent) => {
      if (node.type === 'containerDirective') {
        // :::infoなどに続くタイトル冒頭Text部(冒頭#を含む(もしくは含まない)部分)を取得(:::info ##** )
        // (タイトル全体にはHTML等が含まれる可能性があるため冒頭Text部だけ操作する、残りはシャロ―コピー)
        const beginningText = node.children[0].children[0].value;

        // タイトル冒頭Text部に#が2つ以上連続しているとき
        if(/^##/.test(beginningText)) {
          // タイトル冒頭部から#とそれに続く空白を削除
          newBeginningText = beginningText.replace(/^#+/, '').trim();

          // タイトル部冒頭だけ更新し、残りはシャロ―コピー
          // まずタイトル部全体をシャロ―コピー
          let titleNodes = [...node.children[0].children];

          // 冒頭要素のvalueを更新(ほかはシャロ―コピー)
          const newTitleBeginningNode = {
            ...titleNodes[0],
            value: newBeginningText,
          }
         
          // タイトルノードの冒頭要素だけ更新(ほかはシャロ―コピー)
          const newTitleNodes = [ ...titleNodes ];
          newTitleNodes[0] = newTitleBeginningNode;

          // visitしているcontainerDirectiveの前にheadingノードを追加
          parent.children.splice(index, 0, {
            type: 'heading',
            depth: (beginningText.match(/^##+/) || [''])[0].length, // #の連続数がheadingの深さ
            children: newTitleNodes,
          });
          //  次に検索するのはindexを2つ分飛ばしたノード
          return index + 2;
        }
      }
    });
  
    visit(ast, 'containerDirective', visitor);
  
  };
  return transformer;
};

export default plugin;