snippet
generateTOC
snippet
generateTOC
Last updated January 4th, 2023
Picture the following situation... You've just finished building your blog and you've loaded it with content only to realize that it's missing a table of contents. This is an important user feature as it makes navigating the article easier but you may be wondering how you would implement such a feature.
This helper function allows you to generate a table of contents in the form of a tree -- this is represented as an array of objects. In your front-end code, you could recursively traverse the tree and render out the components to build a visual table of contents.
The Main Objective
The main objective of this helper function is to extract all of the headings from a markdown file string and store the information in a tree structure. It is still left up to you to choose how you want to render the table of contents.
The generateTOC function relies on two helper functions to work correctly
The function takes in a file string and uses regex
to find all the headings in the file string. It matches any element that begins with the #
character and ends with the new line character \n
. It does this for the entire string and returns all the founds elements in a string array.
This function takes in a sub-tree, the current heading, the current slug, and the current level of the header semantic hierarchy. Since this is a recursive function, it first needs to establish a base case --this is done by checking the length of the sub-tree as its subTree
is an array. If we find that the length of the subTree
is 0 then we are going to append the following object to the subTree
.
If the length of the subTree
is not 0 (subTree
is not empty), then we are going to compare the current level (the level that was passed in) to the level of the node in the subTree
. If the current level is greater than the node level in the subTree
then we are going to call the generateTOC
function again. In the case that the current level is not greater than the current node level, we append the following object to the subTree
array.
In the end, we turn an input string into a tree data structure which can be used to build a table of contents.
We go from:
to:
const generateTOC = (fileString) => {
const headingLst = getHeadings(fileString);
let tocTree = [];
for (let i = 0; i < headingLst.length; i++) {
const currHeading = headingLst[i].replace(/#/g, "").trim().toLowerCase();
const currLevel = headingLst[i].match(/#/g)?.length || 1;
const currSlug = currHeading
.replace(/[^a-z0-9 ]/g, "")
.replace(/[ ]/g, "-");
generateTocNode(tocTree, currHeading, currLevel, currSlug);
}
return tocTree;
};
const getHeadings = (fileString) => {
const regex = /#{2}.+\n/g;
const headings = fileString.match(regex) || [];
return headings;
};
const generateTocNode = (subTree, currHeading, currLevel, currSlug) => {
if (subTree.length === 0) {
subTree.push({
name: currHeading,
children: [],
level: currLevel,
slug: currSlug,
});
return;
}
if (currLevel > subTree[subTree.length - 1].level) {
generateTocNode(
subTree[subTree.length - 1].children,
currHeading,
currLevel,
currSlug
);
} else {
subTree.push({
name: currHeading,
children: [],
level: currLevel,
slug: currSlug,
});
return;
}
};
const inputString = `## Heading 2 \n sdrfviodfvnnn dfvnjj dfivn dfjn \n ### Heading 3 -1 \n sdrfviodfvnnn dfvnjj dfivn dfjn \n ### Heading 3-2 \n #### heading 4 \n sdrfviodfvnnn dfvnjj dfivn dfjn \n ## heading 2`;
const output = [
{
name: "heading 2",
children: [
{ name: "heading 3 -1", children: [], level: 3, slug: "heading-3-1" },
{
name: "heading 3-2",
children: [
{ name: "heading 4", children: [], level: 4, slug: "heading-4" },
],
level: 3,
slug: "heading-32",
},
],
level: 2,
slug: "heading-2",
},
];