Last active
October 4, 2021 18:00
-
-
Save BrandonClapp/3655520fa8ba2eaf64ebe26634d592d1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Simple Markdown Parser | |
// Write a function that accepts a string containing a simplified | |
// version of markdown-formatted text, and returns a string | |
// containing the corresponding HTML text. We only need to support | |
// headers, paragraphs, and unordered lists. | |
// For example, this markdown: | |
// # This is a title! | |
// ## This is a subheader | |
// This is a paragraph. | |
// It spans two lines. | |
// This is a separate paragraph. And next is a list: | |
// - One | |
// - Two | |
// - Three | |
// would yield this HTML: | |
// <html> | |
// <body> | |
// <h1>This is a title!</h1> | |
// <h2>This is a subheader</h2> | |
// <p>This is a paragraph. It spans two lines.</p> | |
// <p>This is a separate paragraph. And next is a list:</p> | |
// <ul> | |
// <li>One</li> | |
// <li>Two</li> | |
// <li>Three</li> | |
// </ul> | |
// </body> | |
// </html> | |
function parseHeaders(line: string) { | |
if (line.startsWith('######')) { | |
const element = line.replace('######', ''); | |
const parts = `<h6>${element.trim()}</h6>`; | |
return parts; | |
} | |
if (line.startsWith('#####')) { | |
const element = line.replace('#####', ''); | |
const parts = `<h5>${element.trim()}</h5>`; | |
return parts; | |
} | |
if (line.startsWith('####')) { | |
const element = line.replace('####', ''); | |
const parts = `<h4>${element.trim()}</h4>`; | |
return parts; | |
} | |
if (line.startsWith('###')) { | |
const element = line.replace('###', ''); | |
const parts = `<h3>${element.trim()}</h3>`; | |
return parts; | |
} | |
if (line.startsWith('##')) { | |
const element = line.replace('##', ''); | |
const parts = `<h2>${element.trim()}</h2>`; | |
return parts; | |
} | |
if (line.startsWith('#')) { | |
const element = line.replace('#', ''); | |
const parts = `<h1>${element.trim()}</h1>`; | |
return parts; | |
} | |
} | |
function parse(input: string) { | |
const elements: Array<string> = input.split('\n'); | |
let stack = []; | |
const lines = []; | |
let inListMode = false; | |
let inParaMode = false; | |
// note, this only works for paragraphs | |
for (let element of elements) { | |
// header detection | |
const isHeader = element.startsWith('#'); | |
if (isHeader) { | |
lines.push(parseHeaders(element)); | |
} | |
// List Items | |
const isListItem = element.startsWith('-'); | |
if (isListItem) { | |
if (inListMode) { | |
stack.push(element); | |
} else { | |
inListMode = true; | |
stack.push(element); | |
continue | |
} | |
} else { | |
inListMode = false; | |
} | |
// we're no longer in list mode, so let's compile it | |
// and then add the compiled result to the lines array. | |
if (!inListMode && !inParaMode && stack.length > 0) { | |
const listItemsHtml = stack.map(line => { | |
return `<li>${line.replace('- ', '')}</li>` | |
}).join(' '); | |
// compile the list | |
lines.push(`<ul>${listItemsHtml}</ul>`); | |
stack = []; // Done with this mode, clear the stack. | |
} | |
// Paragraphs | |
const isParagraph = (content: string) => { | |
return !content.startsWith('#') && !content.startsWith('-') && content !== ''; | |
} | |
if (isParagraph(element)) { | |
// Let's add the element to the stack. | |
if (inParaMode) { | |
stack.push(element); | |
} else { | |
inParaMode = true; | |
stack.push(element); | |
continue; | |
} | |
} else { | |
inParaMode = false; | |
} | |
// Compile the paragraphs | |
if (!inListMode && !inParaMode && stack.length > 0) { | |
// Compile paragraphs | |
const parasHtml = ['<p>', ...stack, '</p>'].join(' ') | |
// compile the list | |
lines.push(parasHtml); | |
stack = []; // Done with this mode, clear the stack. | |
} | |
} | |
return ` | |
<html> | |
<body> | |
${lines.join('\n')} | |
</body> | |
</html> | |
`; | |
} | |
const output = parse(` | |
###### This is an h6 | |
# This is a title! | |
## This is a subheader | |
### This is h3 | |
#### This is h4 | |
This is a paragraph. | |
It spans two lines. | |
This is a separate paragraph. And next is a list: | |
- One | |
- Two | |
- Three | |
And another paragraph | |
`); | |
console.log('output', output); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment