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 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 ToC marker.
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 plugin
49
+ * @returns The transformer function
45
50
  */
46
51
  declare const rehypeCustomToc: Plugin<[RehypeCustomTocOptions], Root>;
47
52
  export default rehypeCustomToc;
48
- export type { RehypeCustomTocOptions, RehypeCustomTocTemplate };
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 (!["h1", "h2", "h3", "h4", "h5", "h6"].includes(node.tagName))
85
+ if (!isHeading(node))
47
86
  return;
48
- const text = toText(node).trim();
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 plugin
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.7",
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",