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
The module is hosted on deno.x, and you can import directly into your TypeScript project (no need to touch WASM or Rust source). See the later sections below if you want to compile the WASM yourself.
- Parse Markdown to HTML
import {
markdownToHtml,
markdownToPlaintext,
mjmlToHtml,
} from "https://deno.land/x/parsedown@1.4.3/mod.ts";
const { errors, headings, html, statistics } = await markdownToHtml(
`
## 👋🏽 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
}
*/
const { html } = await markdownToHtml(
"Nobody likes maple in their apple flavoured Snapple.",
{ searchTerm: "apple" },
);
html:
`<p>Nobody likes maple in their <mark id="search-match">apple</mark> flavoured Sn<mark>apple</mark></p>`;
Note the id
added to the first search match. You can use this to scroll the
first match into view.
- Parse Markdown to Plain Text
import {
markdownToHtml,
markdownToPlaintext,
mjmlToHtml,
} from "https://deno.land/x/parsedown@1.4.3/mod.ts";
const plaintext = await markdownToPlaintext(
`
## 👋🏽 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 {
markdownToHtml,
markdownToPlaintext,
mjmlToHtml,
} from "https://deno.land/x/parsedown@1.4.3/mod.ts";
const html = await mjmlToHtml("<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>`
*/
Method above is tested with Deno, you only need to compile the WASM yourself if you have issues in other runtimes or are customizing the Rust source code for your own needs.
- 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
- Copy the generated
pkg
folder into your JavaScript or TypeScript project. - Import and use the code in one of your project source files (expected output is as shown in previous section):
- 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
`,
{},
);
- 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/)
`,
{},
);
- 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>");
You must call init
once before using any of the other functions.
If you are working in Deno, you will probably find the wasmbuild
package
useful.
- Add a
wasmbuild
task to yourdeno.json
file:
{
"tasks": {
// ...TRUNCATED
"wasmbuild": "deno run -A https://deno.land/x/wasmbuild@0.10.2/main.ts"
}
// TRUNCATED...
}
-
Run
deno task wasmbuild new
to initializewasmbuild
in your project. This will create a skeleton WASM project with anrs_lib
directory. -
Clone this repo and replace the contents of the
rs_lib/src
directory in your project with the contents of this repo’ssrc
directory. Also replacers_lib/Cargo.toml
withCargo.toml
from this repo. -
Run the
deno task wasmbuild
command. This will generate JavaScript code and WASM modules from the Rust source code. In particular, there should now belib/rs_lib_bg.wasm
andlib/rs_lib.generated.js
files in your project. -
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>");
- You can import the functions from
- add text readability statistics (Gunning Fog index, for example)
Feel free to jump into the Rodney Lab matrix chat room.