This was a tough challenge! There wasn’t any UI development – the task was about behind-the-scenes string processing.
You can find the code updates for the solution on GitHub . Read on for explanations and commentary.
The bulk of this solution is writing a function to extract the headings from an MDX file. The guidelines stated the headings would be designated in the Markdown style , using #
, ##
, ###
, etc – like this:
Markdown headings
Step 1: Write the function to extract headings
To start, I created a new file: src/helpers/headings-helpers.ts to contain a function that would take a string of MDX content and return an array of HeadingData
objects. First, I defined an HeadingData
interface to designate which information each heading will need:
headings-helpers.ts
This will eventually include an id
for the heading DOM element, but that’s for a later workshop.
For extracting the headings, I borrowed heavily from kaf-lamed-beyt’s extract-md-headings code .
This is my function:
headings-helpers.ts
Let’s take a look at the regular expression (on line 5) first:
This is looking for any line that begins with one or more #
characters and then some whitespace.
- the
^
anchors the expression to the beginning of the line #+
means one or more#
characters\s
means a whitespace character
The parentheses around the #+
will “capture” a string with whatever matches within the paretheses — in this case, however many #
characters it finds. We can access that using match[1]
(line 9).
Then we’re looking for the rest of the line:
- the
(.+)
captures one or more non-newline characters (a.
matches anything but a newline). - the
$
anchors the end of the regular expression to the end of the line.
This capture group will contain everything between the space character and the end of the line – in other words, the heading text. That gets read from match[2]
on line 10. The .trim()
trims any whitespace from the ends of the string.
The gm
at the end of the regular expression are flags . g
means keep looking for multiple matches, and m
means to search each line as a separate string.
The rest of the function runs a while loop to keep finding matches using this regular expression, and appends the details of each match to the headings
array – as long as the headings are level 2 or 3, per the specification of this task.
Step 2: Call the function from loadBlogPost
All right, we have a function that extracts headings from an MDX string… but where are we going to get the MDX string? The string is available within the loadBlogPost
function, in src/helpers/file-helpers.ts .
Once we have the content (separated from the frontmatter using gray-matter ), we can feed it into our extractMdxHeadings
function, and then add it to the return value.
before
after
Step 3: Print the headings in the BlogPost component
Finally, destructure headings
from the return value of loadBlogPost
and print the result. This is done in the src/components/BlogPost/BlogPost.tsx file.
before
after
Because BlogPost
is a React Server Component , the console.log
output will be shown in the terminal where you’re running npm run dev
– not in the browser console.