Skip to content

Commit 6fbb123

Browse files
authored
Add support for phrasing content
Previously, only the textual content of headings was used to generate the entries in the Table of Contents. This lead to a bug (or feature?) where HTML in headings made entries in the TOC appear with literal HTML. mdast has a concept of static phrasing content, which includes all the things that can appear in links. Instead of using just the textual content of a heading, this commit introduces a new behaviour where any static phrasing content, such as HTML, inline code, and emphasis, are copied over into the Table of Contents. Interactive phrasing content (links, link references) are handled by replacing them with their children. See: <https://github.com/syntax-tree/mdast#staticphrasingcontent> Closes GH-56. Closes GH-57. Closes GH-58. Reviewed-by: Christian Murphy <christian.murphy.42@gmail.com> Reviewed-by: Jonathan Haines <jonno.haines@gmail.com>
1 parent 32d2a8f commit 6fbb123

File tree

9 files changed

+442
-26
lines changed

9 files changed

+442
-26
lines changed

lib/contents.js

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
'use strict'
22

3+
var extend = require('extend')
4+
35
module.exports = contents
46

57
var LIST = 'list'
68
var LIST_ITEM = 'listItem'
79
var PARAGRAPH = 'paragraph'
810
var LINK = 'link'
9-
var TEXT = 'text'
11+
var LINK_REFERENCE = 'linkReference'
1012

1113
// Transform a list of heading objects to a markdown list.
1214
function contents(map, tight) {
@@ -42,16 +44,16 @@ function contents(map, tight) {
4244
return table
4345
}
4446

45-
// Insert a `node` into a `parent`.
46-
function insert(node, parent, tight) {
47+
// Insert an entry into `parent`.
48+
function insert(entry, parent, tight) {
4749
var children = parent.children
4850
var length = children.length
4951
var last = children[length - 1]
5052
var isLoose = false
5153
var index
5254
var item
5355

54-
if (node.depth === 1) {
56+
if (entry.depth === 1) {
5557
item = listItem()
5658

5759
item.children.push({
@@ -60,30 +62,30 @@ function insert(node, parent, tight) {
6062
{
6163
type: LINK,
6264
title: null,
63-
url: '#' + node.id,
64-
children: [{type: TEXT, value: node.value}]
65+
url: '#' + entry.id,
66+
children: all(entry.children)
6567
}
6668
]
6769
})
6870

6971
children.push(item)
7072
} else if (last && last.type === LIST_ITEM) {
71-
insert(node, last, tight)
73+
insert(entry, last, tight)
7274
} else if (last && last.type === LIST) {
73-
node.depth--
75+
entry.depth--
7476

75-
insert(node, last, tight)
77+
insert(entry, last, tight)
7678
} else if (parent.type === LIST) {
7779
item = listItem()
7880

79-
insert(node, item, tight)
81+
insert(entry, item, tight)
8082

8183
children.push(item)
8284
} else {
8385
item = list()
84-
node.depth--
86+
entry.depth--
8587

86-
insert(node, item, tight)
88+
insert(entry, item, tight)
8789

8890
children.push(item)
8991
}
@@ -129,6 +131,39 @@ function insert(node, parent, tight) {
129131
}
130132
}
131133

134+
function all(children) {
135+
var result = []
136+
var length = children.length
137+
var index = -1
138+
139+
while (++index < length) {
140+
result = result.concat(one(children[index]))
141+
}
142+
143+
return result
144+
}
145+
146+
function one(node) {
147+
var copy
148+
149+
if (node.type === LINK || node.type === LINK_REFERENCE) {
150+
return all(node.children)
151+
}
152+
153+
copy = extend({}, node)
154+
155+
delete copy.children
156+
delete copy.position
157+
158+
copy = extend(true, {}, copy)
159+
160+
if (node.children) {
161+
copy.children = all(node.children)
162+
}
163+
164+
return copy
165+
}
166+
132167
// Create a list.
133168
function list() {
134169
return {type: LIST, ordered: false, spread: false, children: []}

lib/search.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,11 @@ function search(root, expression, settings) {
6363
}
6464

6565
if (!lookingForToc && value && child.depth <= maxDepth) {
66-
map.push({depth: child.depth, value: value, id: slugs.slug(id || value)})
66+
map.push({
67+
depth: child.depth,
68+
children: child.children,
69+
id: slugs.slug(id || value)
70+
})
6771
}
6872
}
6973
}

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"index.js"
2121
],
2222
"dependencies": {
23+
"extend": "^3.0.2",
2324
"github-slugger": "^1.2.1",
2425
"mdast-util-to-string": "^1.0.5",
2526
"unist-util-is": "^2.1.2",
@@ -32,10 +33,12 @@
3233
"remark": "^10.0.0",
3334
"remark-attr": "^0.8.0",
3435
"remark-cli": "^6.0.0",
36+
"remark-parse": "^6.0.3",
3537
"remark-preset-wooorm": "^4.0.0",
3638
"remark-usage": "^6.1.3",
3739
"tape": "^4.10.1",
3840
"tinyify": "^2.5.0",
41+
"unified": "^7.1.0",
3942
"unist-builder": "^1.0.3",
4043
"xo": "^0.24.0"
4144
},

test/fixtures/normal-attr/config.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"useRemarkAttr": true
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"remarkParseOptions": {
3+
"footnotes": true
4+
}
5+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Text
2+
3+
# *Emphasis*
4+
5+
# **Importance**
6+
7+
# ~~Strikethrough~~
8+
9+
# <i>HTML<i>
10+
11+
# `inline.code()`
12+
13+
# [^a footnote]
14+
15+
# footnote reference [^1]
16+
17+
# ![image](image.png)
18+
19+
# ![image reference][image]
20+
21+
# [link](example.com)
22+
23+
# ![link reference][link]
24+
25+
[^1]: footnote reference
26+
27+
[image]: image.png
28+
29+
[link]: example.com

0 commit comments

Comments
 (0)