DEV Community

Avelyn Hyunjeong Choi
Avelyn Hyunjeong Choi

Posted on

New feature: full file conversion support for .md files using showdown

New feature
New feature of file conversion from .md to .html was implemented using showdown.
You can check out the issue here.

Before
Previous implementations required parsing the .md file first and manually converting some of the .md syntax to .html syntax using regular expressions, as shown below. As you can see, the syntax conversion was fairly limited and did not fully support file conversion between the two formats.

...
export function fileHandler(inputPath: string, cssLink: string, selectedLang: string, outputFolder: string) {
fileHandler(inputPath: string, cssLink: string, selectedLang: st
        if (isTextFile(inputPath)) {
            body = parseTextFileContent(data);
        } else if (isMarkdownFile(inputPath)) {
            body = parseMarkdownFileContent(data);
        } else {
            parseTextFileContent(content: string): string {
        .map((para: string) =>
            `<p>${para.replace(/\r?\n/, ' ')}</p>`)
        .join('\n');
}

// Parses the content of a markdown file
function parseMarkdownFileContent(content: string): string {
    return content
        .replace(/(\r?\n){1}/, ' ') // Aggregate text at gaps of single newlines
        .split(/\r?\n/)
        .filter(line => line?.length > 0) // Remove empty lines
        .map((line: string) => {
            return formatHtmlForMarkdownLine(line)
        })
        .join('\n'); // Join all the generated tags
}

function formatHtmlForMarkdownLine(line: string) {
    return line
        .replace(/^#\s(.+)$/gm, '<h1>$1</h1>') // heading 1
        .replace(/^##\s(.+)$/gm, '<h2>$1</h2>') // heading 2
        .replace(/^###\s(.+)$/gm, '<h3>$1</h3>') // heading 3
        .replace(/^####\s(.+)$/gm, '<h4>$1</h4>') // heading 4
        .replace(/^#####\s(.+)$/gm, '<h5>$1</h5>') // heading 5
        .replace(/^######\s(.+)$/gm, '<h6>$1</h6>') // heading 6
        .replace(/^(?!<h[1-6]>|<ul>|<ol>|<li>|<a>).+$/gm, '<p>$&</p>') // paragraph
        .replace(/\[(.+?)\]\((.+?)\)/g, '<a href=$2>$1</a>') //  link
        .replace(/\*\*(.*?)\*\*/g, '<b>$1</b>') // bold
        .replace(/\*(.*?)\*/g, '<i>$1</i>') // italic
}
Enter fullscreen mode Exit fullscreen mode

After

...
const showdown = require('showdown');
const converter = new showdown.Converter()
let body: string = '';

export function fileHandler(inputPath: string, cssLink: string, selectedLang: string, outputFolder: string) {
fileHandler(inputPath: string, cssLink: string, selectedLang: st
        if (isTextFile(inputPath)) {
            body = parseTextFileContent(data);
        } else if (isMarkdownFile(inputPath)) {
            body = converter.makeHtml(data);
        } else {
            parseTextFileContent(content: string): string {
            .map((para: string) =>
                `<p>${para.replace(/\r?\n/, ' ')}</p>`)
            .join('\n');
}
Enter fullscreen mode Exit fullscreen mode

You can check out the pr for the entire code change.

Inspiration from Docusaurus
Markdown Frontmatter inspired me to dig deeper into the support for .md files. Since Docusaurus employs it to enrich markdown files with metadata, I was thinking why not extend full support for converting from .md to .html, as the current implementation for this purpose is somewhat limited. While Docusaurus did use the Joi library to validate the metadata, I opted to use only the showdown library, as I wasn't planning to add any metadata for now.

You can find the full blog post about the code review I did for Docusaurus here.

Next step
There are several cool features that Docusaurus utilizes, including Search Engine Optimization (SEO), incorporating meta tags in the HTML head, and improved accessibility of generated HTML, among others. I will continue to create issues for other features and submit pull requests for those. If anyone is interested in participating, please ping me in any opened issues. Thank you!

Top comments (0)