Build a Markdown to HTML Converter

Hi everyone. Stuck on this exercise:
Build a Markdown to HTML Converter: Build a Markdown to HTML Converter | freeCodeCamp.org

I am testing the input itself and I pass the tests, but I’m not sure if I am not doing it in the most efficient method, or if something else is tripping up passing the test. Any help is appreciated.

Here is the HTML:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Markdown to HTML Converter</title>
    <link rel="stylesheet" href="styles.css">
</head>

<body>
    <h1>Markdown to HTML Converter</h1>
    <div id="container">
        <div class="container">
            <h2>Markdown Input:</h2>
            <textarea id="markdown-input" placeholder="Enter your markdown here..."></textarea>
        </div>
        <div class="container">
            <h2>Raw HTML Output:</h2>
            <div id="html-output"></div>
        </div>
        <div class="container">
            <h2>HTML Preview:</h2>
            <div id="preview"></div>
        </div>
    </div>
<script src="script.js"></script>
</body>

</html>

Here is the CSS:

@import url('https://fonts.googleapis.com/css?family=Inter&display=swap');

* {
     box-sizing: border-box;
}
 body {
     font-family: Inter, sans-serif;
     font-size: 18px;
     padding: 20px;
     background-color: #FDFDFD;
}

img {
    max-width: 100%;
}

 #markdown-input {
     width: 100%;
     height: 200px;
     font-family: Inter, sans-serif;
     font-size: 18px;
}
 #html-output, #preview {
     min-height: 200px;
     display: inline-block;
     width: 100%;
     border: 1px solid #ccc;
     padding: 10px;
     margin: auto;
     background-color: #f9f9f9;
}
 @media (min-width: 600px) {
     #markdown-input, #html-output, #preview {
         min-height: 200px;
         margin: 0;
    }
     #container {
         display: flex;
         justify-content: space-evenly;
         gap: 10px;
    }
}

And here is my JavaScript:

const userInput = document.getElementById("markdown-input");
const htmlOutput = document.getElementById("html-output");
const htmlPreview = document.getElementById("preview");

// regex for strong text
  const strongOpen = /[*_]{2}(?![\s$])/g;
  const strongClose = /(?<=<strong>.+)[*_]{2}/g;

// regex for italic text
  const italicOpen = /(?<=[^A-Za-z0-9])[*_]{1}/g;
  const italicClose = /(?<=<em>.+)[*_]{1}/g;

const convertMarkdown = (line) => {
  if(line == "") { // checks for spaces in between lines
    return `\n`;
  } else if(line.match(/^\s?#{1,3}\s.+$/g)) { // checks for headers
    let headerLevelNum = line.match(/#/g).length;
    let capturedHeaderText = line.match(/(?<=^\s?#{1,3}\s).+$/g);
    return `<h${headerLevelNum}>${capturedHeaderText}</h${headerLevelNum}>`;
  } else if(line.match(/^\s?>\s.+$/g)) { // checks for blockquotes
    let capturedQuote = line.match(/(?<=^\s?>\s).+$/g);
    return `<blockquote>${capturedQuote}</blockquote>`;
  } else if(line.match(/!\[.+\]\(.+\)/g)) { // checks for images
    let capturedImgText = line.match(/(?<=!\[)[^\]]+/g);
    let capturedImgSrc = line.match(/(?<=\()[^\)]+/g);
    return `<img src="${capturedImgSrc}" alt="${capturedImgText}">`;
  } else if(line.match(/\[.+\]\(.+\)/g)) { // checks for links
    let capturedLinkText = line.match(/(?<=\[)[^\]]+/g);
    let capturedLinkUrl = line.match(/(?<=\()[^\)]+/g);
    return `<a href="${capturedLinkUrl}">${capturedLinkText}</a>`;
  } else {
    return line // replaces strong text and italic text, if present
      .replace(strongOpen, `<strong>`)
      .replace(strongClose, `</strong>`)
      .replace(italicOpen, `<em>`)
      .replace(italicClose, `</em>`);
  } 
};

// event listener
userInput.addEventListener('input', () => {
  let input = userInput.value; // get user input
  let output = ""; // declares output string
  let inputLines = input.split('\n'); // splits input into lines
  inputLines.forEach((line) => {
    output += convertMarkdown(line); // for each line returned text is added to string
  });
  htmlOutput.innerText = output; // displays html as code
  htmlPreview.innerHTML = output; // displays html as html
});

Hi @manubaq

Two hashes are converting the h1 element to h2.

Happy coding

Thanks, finally got it right!

const userInput = document.getElementById("markdown-input");
const htmlOutput = document.getElementById("html-output");
const htmlPreview = document.getElementById("preview");

// regex for strong text
  const strongOpen = /(?<![A-Za-z0-9*])[*_]{2}(?![\s$])/g;
  const strongClose = /(?<=<strong>.+)[*_]{2}/g;

// regex for italic text
  const italicOpen = /(?<![A-Za-z0-9*])[*_]{1}/g;
  const italicClose = /(?<=<em>.+)[*_]{1}/g;

const italicPattern = /[*_]{1}.+[*_]{1}/g;
const italicPatternText = /(?<=[*_]{1}).+(?=[*_]{1})/g;
const strongPattern = /[*_]{2}.+[*_]{2}/g;
const strongPatternText = /(?<=[*_]{2}).+(?=[*_]{2})/g;
const h1Pattern = /^#\s[^#]+[^\s|^#]|\s?#\s[^#]+[^\s|^#]/g;
const h2Pattern = /^##\s[^#]+[^\s|^#]|\s?##\s[^#]+[^\s|^#]/g;
const h3Pattern = /^###\s[^#]+[^\s|^#]|\s?###\s[^#]+[^\s|^#]/g;
const blockquotePattern = /^>\s[^>]+[^\s|^#]|\s?>\s[^>]+[^\s|^#]/g;
const imagePattern = /!\[.+\]\(.+\)/g;
const linkPattern = /\[.+\]\(.+\)/g;

// receives user input as string and returns string with strongs converted to HTML
const strongsConverter = (input) => {
  let outputArr = []; // creates arr to add lines of converted input
  let inputArr = input.split("\n"); // splits input string into array of lines
  inputArr.forEach((line) => {
    if(strongPattern.test(line)) {
      let strongText = line.match(strongPatternText);
      let newLine = line.replace(strongPattern, `<strong>${strongText}</strong>`);
      outputArr.push(newLine);
    } else {
      outputArr.push(line);
    }
  });
  let outputStr = outputArr.join("\n");
  return outputStr;
};

const italicsConverter = (input) => {
  let outputArr = []; // creates arr to add lines of converted input
  let inputArr = input.split("\n"); // splits input string into array of lines
  inputArr.forEach((line) => {
    if(italicPattern.test(line)) {
      let italicText = line.match(italicPatternText);
      let newLine = line.replace(italicPattern, `<em>${italicText}</em>`);
      outputArr.push(newLine);
    } else {
      outputArr.push(line); // check why it doesnt output to outputArr
    }
  });
  let outputStr = outputArr.join("\n");
  return outputStr;
}

const convertMarkdown = () => {
  let originalInput = userInput.value; // get user input value string
  let inputStrongs = strongsConverter(originalInput);
  let inputItalics = italicsConverter(inputStrongs);
  let input = inputItalics.split("\n"); // gets converted user input, splits into lines 
  let outputArr = []; // creates empty array to add converted lines
  input.forEach((line) => {
    if(line == "") { // checks for spaces in between lines
      outputArr.push("");
    } else if(line.match(/^\s?#{1,3}\s.+$/g)) { // checks for headers
      let headerLevelNum = line.match(/(?<=^\s?#?#?)#/g).length;
      let capturedHeaderText = line.match(/(?<=^\s?#{1,3}\s).+$/g);
      outputArr.push(`<h${headerLevelNum}>${capturedHeaderText}</h${headerLevelNum}>`);
    } else if(line.match(/^\s?>\s.+$/g)) { // checks for blockquotes
      let capturedQuote = line.match(/(?<=^\s?>\s).+$/g);
      outputArr.push(`<blockquote>${capturedQuote}</blockquote>`);
    } else if(line.match(/!\[.+\]\(.+\)/g)) { // checks for images
      let capturedImgText = line.match(/(?<=!\[)[^\]]+/g);
      let capturedImgSrc = line.match(/(?<=\()[^\)]+/g);
      outputArr.push(`<img src="${capturedImgSrc}" alt="${capturedImgText}">`);
    } else if(line.match(/\[.+\]\(.+\)/g)) { // checks for links
      let capturedLinkText = line.match(/(?<=\[)[^\]]+/g);
      let capturedLinkUrl = line.match(/(?<=\()[^\)]+/g);
      outputArr.push(`<a href="${capturedLinkUrl}">${capturedLinkText}</a>`);
    } else {
      outputArr.push(line);
    }
  });
  return outputArr.join("\n");
};

// event listener
userInput.addEventListener('input', () => {
  let output = convertMarkdown();
  htmlOutput.innerText = output; // displays html as code
  htmlPreview.innerHTML = output; // displays html as html
});