Skip to main content
Rodney Lab parse down Github banner

Rodney Lab logo

parsedown

Light touch Markdown parsing into HTML written in Rust. Generates WASM and can be used with Deno Fresh.

  • adds an id and anchor link to each h2 heading for easy linking,
  • adds pretty punctuation,
  • uses html5ever for HTML manipulation and pulldown-cmark for Markdown parsing.

Compile WASM (see next section instead if working with Deno)

  1. Clone the project and change into the project directory. Then run these commands:
cargo install wasm-pack # skip if you already have it installed
wasm-pack build --target web
  1. Copy the generated pkg folder into your JavaScript or TypeScript project.
  2. Import and use the code in one of your project source files:
  • Parse Markdown to HTML
import init, {
  markdown_to_html,
  markdown_to_plaintext,
  mjml_to_html,
} from "pkg/parsedown.js";

await init();

// alternative if top level await is not available
(async () => {
  await init();
})();

const { errors, headings, html, statistics } = await markdown_to_html(
  `
## πŸ‘‹πŸ½ Hello You

* alpha
* beta
`,
  {},
);

/*
errors: "undefined"

headings: [{
  heading: "πŸ‘‹πŸ½ Hello You",
  id: "wave-skin-tone-4-hello-you",
}]

html: `<h2 id="wave-skin-tone-4-hello-you">πŸ‘‹πŸ½ Hello You <a href="#wave-skin-tone-4-hello-you" class="heading-anchor">#</a></h2>
<ul>
<li>alpha</li>
<li>beta</li>
</ul>
`

statistics: {
  reading_time: 1, // in minutes
  word_count: 4
}
*/
  • Parse Markdown to Plain Text
import init, {
  markdown_to_html,
  markdown_to_plaintext,
  mjml_to_html,
} from "pkg/parsedown.js";

await init();

const plaintext = markdown_to_plaintext(
  `
## πŸ‘‹πŸ½ Hello You

* alpha
* beta

[Example Link](https://example.com/)
`,
  {},
);

/*
plaintext: `πŸ‘‹πŸ½ Hello You

- alpha

- beta

Example Link (https://example.com/)
`
*/
  • Parse MJML (email template) to HTML
import init, {
  markdown_to_html,
  markdown_to_plaintext,
  mjml_to_html,
} from "pkg/parsedown.js";

await init();

const html = await mjml_to_html("<mjml></mjml>");

/*
plaintext: `<!doctype html><html xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office"><head><title></title><!--[if !mso]><!--><meta http-equiv="X-UA-Compatible" content="IE=edge"><!--<![endif]--><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1">
<style type="text/css">
#outlook a { padding: 0; }
body { margin: 0; padding: 0; -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
table, td { border-collapse: collapse; mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
img { border: 0; height: auto; line-height: 100%; outline: none; text-decoration: none; -ms-interpolation-mode: bicubic; }
p { display: block; margin: 13px 0; }
</style>
<!--[if mso]>
<noscript>
<xml>
<o:OfficeDocumentSettings>
  <o:AllowPNG/>
  <o:PixelsPerInch>96</o:PixelsPerInch>
</o:OfficeDocumentSettings>
</xml>
</noscript>
<![endif]-->
<!--[if lte mso 11]>
<style type="text/css">
.mj-outlook-group-fix { width:100% !important; }
</style>
<![endif]-->
</head><body></body></html>`
*/

You must call init once before using any of the other functions.

Compile WASM in Deno project

If you are working in Deno, you will probably find the wasmbuild package useful.

  1. Add a wasmbuild task to you deno.json file:
{
  "tasks": {
    // ...TRUNCATED
    "wasmbuild": "deno run -A https://deno.land/x/wasmbuild@0.10.2/main.ts"
  }
  // TRUNCATED...
}
  1. Run deno task wasmbuild --init to initialise wasmbuild in your project. This will create a skeleton WASM project with an rs_lib directory.

  2. Clone this repo and replace the contents of the rs_lib/src directory in your project with the contents of this repo’s src directory. Also replace rs_lib/Cargo.toml with Cargo.toml from this repo.

  3. Run the deno task wasmbuild command. This will generate JavaScript code and WASM modules from the Rust source code. In particular, there should now be lib/rs_lib_bg.wasm and lib/rs_lib.generated.js files in your project.

  4. You can now use the library functions in your JavaScript or TypeScript code. Usage is only slightly different from the descriptions above.

    • You can import the functions from lib/rs_lib.generated.js:
    import {
      instantiate,
      markdown_to_html,
      markdown_to_plaintext,
      mjml_to_html,
    } from "@/lib/rs_lib.generated.js";
    • Before using any of the functions call instantiate:
    await instantiate();
    • The functions will now work as above:
    const { errors, headings, html, statistics } = await markdown_to_html(
      `
    ## πŸ‘‹πŸ½ Hello You
    
    * alpha
    * beta
     `,
      {},
    );
    
    const plaintext = markdown_to_plaintext(
      `
    ## πŸ‘‹πŸ½ Hello You
    
    * alpha
    * beta
    
    [Example Link](https://example.com/)
    `,
      {},
    );
    
    const html = mjml_to_html("<mjml></mjml>");

πŸ—ΊοΈ Roadmap

  • add text readability statistics (Gunning Fog index for example)

☎️ Reach Out

Feel free to jump into the Rodney Lab matrix chat room.