UNPKG

2.06 kBJavaScriptView Raw
1'use strict'
2
3module.exports = search
4
5var toString = require('mdast-util-to-string')
6var visit = require('unist-util-visit')
7var is = require('unist-util-is')
8var slugs = require('github-slugger')()
9
10var HEADING = 'heading'
11
12// Search a node for a location.
13function search(root, expression, settings) {
14 var length = root.children.length
15 var depth = null
16 var lookingForToc = expression !== null
17 var maxDepth = settings.maxDepth || 6
18 var parents = settings.parents || root
19 var map = []
20 var headingIndex
21 var closingIndex
22
23 if (!lookingForToc) {
24 headingIndex = -1
25 }
26
27 slugs.reset()
28
29 // Visit all headings in `root`. We `slug` all headings (to account for
30 // duplicates), but only create a TOC from top-level headings.
31 visit(root, HEADING, onheading)
32
33 if (headingIndex && !closingIndex) {
34 closingIndex = length + 1
35 }
36
37 if (headingIndex === undefined) {
38 headingIndex = -1
39 closingIndex = -1
40 map = []
41 }
42
43 return {index: headingIndex, endIndex: closingIndex, map: map}
44
45 function onheading(child, index, parent) {
46 var value = toString(child)
47 var id = child.data && child.data.hProperties && child.data.hProperties.id
48
49 if (!is(parents, parent)) {
50 return
51 }
52
53 if (lookingForToc) {
54 if (isClosingHeading(child, depth)) {
55 closingIndex = index
56 lookingForToc = false
57 }
58
59 if (isOpeningHeading(child, depth, expression)) {
60 headingIndex = index + 1
61 depth = child.depth
62 }
63 }
64
65 if (!lookingForToc && value && child.depth <= maxDepth) {
66 map.push({
67 depth: child.depth,
68 children: child.children,
69 id: slugs.slug(id || value)
70 })
71 }
72 }
73}
74
75// Check if `node` is the main heading.
76function isOpeningHeading(node, depth, expression) {
77 return (
78 depth === null &&
79 node &&
80 node.type === HEADING &&
81 expression.test(toString(node))
82 )
83}
84
85// Check if `node` is the next heading.
86function isClosingHeading(node, depth) {
87 return depth && node && node.type === HEADING && node.depth <= depth
88}