rehype-custom-toc 1.0.7 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -1
- package/dist/index.d.ts +7 -2
- package/dist/index.js +43 -5
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ npm install rehype-custom-toc
|
|
|
12
12
|
|
|
13
13
|
The table of contents will be inserted at the location of the `<!-- toc -->` comment or at the beginning of the file if no comment is found.
|
|
14
14
|
|
|
15
|
-
When parsing HTML with rehype, the `<!-- toc -->` comment is preserved as-is, but when converting from Markdown you need to convert Markdown comments to HTML comments (as shown below with `remark-comment`) so rehype-custom-toc can detect the
|
|
15
|
+
When parsing HTML with rehype, the `<!-- toc -->` comment is preserved as-is, but when converting from Markdown you need to convert Markdown comments to HTML comments (as shown below with `remark-comment`) so rehype-custom-toc can detect the TOC marker.
|
|
16
16
|
|
|
17
17
|
```typescript
|
|
18
18
|
import remarkComment from "remark-comment";
|
|
@@ -93,6 +93,43 @@ The above code will output the following (formatted for readability):
|
|
|
93
93
|
<h3 id="subsection-11">Subsection 1.1</h3>
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
### Add IDs to headings without a TOC
|
|
97
|
+
|
|
98
|
+
You can import `rehypeSlugger` from `rehype-custom-toc` and use it as a standalone plugin to add slugs to headings without generating a table of contents. This is useful if you want to add IDs to headings but don't want a TOC.
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
import remarkParse from "remark-parse";
|
|
102
|
+
import remarkRehype from "remark-rehype";
|
|
103
|
+
import { rehypeSlugger } from "rehype-custom-toc";
|
|
104
|
+
import rehypeStringify from "rehype-stringify";
|
|
105
|
+
import { unified } from "unified";
|
|
106
|
+
|
|
107
|
+
const processor = unified().use(remarkParse).use(remarkRehype).use(rehypeSlugger).use(rehypeStringify);
|
|
108
|
+
|
|
109
|
+
const markdown = `
|
|
110
|
+
# Title
|
|
111
|
+
|
|
112
|
+
This is a sample markdown paragraph.
|
|
113
|
+
|
|
114
|
+
## Section 1
|
|
115
|
+
|
|
116
|
+
### Subsection 1.1
|
|
117
|
+
`;
|
|
118
|
+
|
|
119
|
+
processor.process(markdown).then((result) => {
|
|
120
|
+
console.log(result.toString());
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The above code will output the following (formatted for readability):
|
|
125
|
+
|
|
126
|
+
```html
|
|
127
|
+
<h1 id="title">Title</h1>
|
|
128
|
+
<p>This is a sample markdown paragraph.</p>
|
|
129
|
+
<h2 id="section-1">Section 1</h2>
|
|
130
|
+
<h3 id="subsection-11">Subsection 1.1</h3>
|
|
131
|
+
```
|
|
132
|
+
|
|
96
133
|
## Options
|
|
97
134
|
|
|
98
135
|
### `template`
|
package/dist/index.d.ts
CHANGED
|
@@ -38,11 +38,16 @@ interface RehypeCustomTocOptions {
|
|
|
38
38
|
*/
|
|
39
39
|
ordered?: boolean;
|
|
40
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Rehype plugin to add slugs to headings in the HAST tree.
|
|
43
|
+
* @returns The transformer function
|
|
44
|
+
*/
|
|
45
|
+
declare const rehypeSlugger: Plugin<[], Root>;
|
|
41
46
|
/**
|
|
42
47
|
* Rehype plugin to generate a table of contents.
|
|
43
48
|
* @param userOptions Options for the plugin
|
|
44
|
-
* @returns The
|
|
49
|
+
* @returns The transformer function
|
|
45
50
|
*/
|
|
46
51
|
declare const rehypeCustomToc: Plugin<[RehypeCustomTocOptions], Root>;
|
|
47
52
|
export default rehypeCustomToc;
|
|
48
|
-
export type
|
|
53
|
+
export { type RehypeCustomTocOptions, type RehypeCustomTocTemplate, rehypeSlugger };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,45 @@ const DEFAULT_OPTIONS = {
|
|
|
26
26
|
ordered: false,
|
|
27
27
|
template: defaultTemplate
|
|
28
28
|
};
|
|
29
|
+
/**
|
|
30
|
+
* Checks if a node is a heading element.
|
|
31
|
+
* @param node The node to check
|
|
32
|
+
* @returns True if the node is a heading element, false otherwise
|
|
33
|
+
*/
|
|
34
|
+
const isHeading = (node) => ["h1", "h2", "h3", "h4", "h5", "h6"].includes(node.tagName);
|
|
35
|
+
/**
|
|
36
|
+
* Adds an ID to a heading element and extracts its text.
|
|
37
|
+
* @param node The heading element
|
|
38
|
+
* @param slugger The GitHubSlugger instance
|
|
39
|
+
* @returns An object containing the slug and text of the heading
|
|
40
|
+
*/
|
|
41
|
+
const addIdToHeading = (node, slugger) => {
|
|
42
|
+
const text = toText(node).trim();
|
|
43
|
+
// Empty-string ids should be replaced with a generated slug
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
|
45
|
+
const slug = node.properties.id || slugger.slug(text);
|
|
46
|
+
node.properties.id = slug;
|
|
47
|
+
return { slug, text };
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Rehype plugin to add slugs to headings in the HAST tree.
|
|
51
|
+
* @returns The transformer function
|
|
52
|
+
*/
|
|
53
|
+
const rehypeSlugger = () => {
|
|
54
|
+
/**
|
|
55
|
+
* The transformer function for the plugin.
|
|
56
|
+
* @param tree The HAST tree
|
|
57
|
+
*/
|
|
58
|
+
const transformer = (tree) => {
|
|
59
|
+
const slugger = new GitHubSlugger();
|
|
60
|
+
visit(tree, "element", (node) => {
|
|
61
|
+
if (!isHeading(node))
|
|
62
|
+
return;
|
|
63
|
+
addIdToHeading(node, slugger);
|
|
64
|
+
});
|
|
65
|
+
};
|
|
66
|
+
return transformer;
|
|
67
|
+
};
|
|
29
68
|
/**
|
|
30
69
|
* Generate the table of contents from the headings data.
|
|
31
70
|
* @param tree The HAST tree
|
|
@@ -43,11 +82,9 @@ const generateToc = (tree, options) => {
|
|
|
43
82
|
const headings = [];
|
|
44
83
|
const slugger = new GitHubSlugger();
|
|
45
84
|
visit(tree, "element", (node) => {
|
|
46
|
-
if (!
|
|
85
|
+
if (!isHeading(node))
|
|
47
86
|
return;
|
|
48
|
-
const text =
|
|
49
|
-
const slug = node.properties["id"] || slugger.slug(text);
|
|
50
|
-
node.properties["id"] = slug;
|
|
87
|
+
const { slug, text } = addIdToHeading(node, slugger);
|
|
51
88
|
// eslint-disable-next-line no-magic-numbers
|
|
52
89
|
const depth = parseInt(node.tagName.slice(1), 10);
|
|
53
90
|
headings.push({
|
|
@@ -100,7 +137,7 @@ const generateToc = (tree, options) => {
|
|
|
100
137
|
/**
|
|
101
138
|
* Rehype plugin to generate a table of contents.
|
|
102
139
|
* @param userOptions Options for the plugin
|
|
103
|
-
* @returns The
|
|
140
|
+
* @returns The transformer function
|
|
104
141
|
*/
|
|
105
142
|
const rehypeCustomToc = (userOptions) => {
|
|
106
143
|
const options = { ...DEFAULT_OPTIONS, ...userOptions };
|
|
@@ -139,3 +176,4 @@ const rehypeCustomToc = (userOptions) => {
|
|
|
139
176
|
return transformer;
|
|
140
177
|
};
|
|
141
178
|
export default rehypeCustomToc;
|
|
179
|
+
export { rehypeSlugger };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rehype-custom-toc",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "rehype plugin to generate a customizable table of contents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"rehype",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"cross-env": "^10.1.0",
|
|
59
59
|
"eslint": "^10.0.0",
|
|
60
60
|
"prettier": "^3.7.4",
|
|
61
|
+
"rehype-parse": "^9.0.1",
|
|
61
62
|
"rehype-stringify": "^10.0.1",
|
|
62
63
|
"remark-comment": "^1.0.0",
|
|
63
64
|
"remark-parse": "^11.0.0",
|