showdownjs / showdown

A bidirectional Markdown to HTML to Markdown converter written in Javascript
http://www.showdownjs.com/
MIT License
14.19k stars 1.56k forks source link

Support for "reddit" flavor markdown #937

Open DenverCoder1 opened 2 years ago

DenverCoder1 commented 2 years ago

Reddit has some markdown differences and it would be nice to automatically be able to convert Reddit markdown to HTML for displaying on web pages.

Most important differences are the superscript and table syntax.

Other features would be nice but not necessary.

Reddit-specific extensions

Other differences

| **Normal** | **Center** | **Left** | **Right** |
|-|:-:|:-|-:|
| A | B | C | D |

Currently with showdown, this only becomes a table when center is written as :--:, right as --: and left as :-- or --.

| **Normal** | **Center** | **Left** | **Right** |
|--|:--:|:--|--:|
| A | B | C | D |
7. Item 1
2. Item 2
5. Item 3

Expected: image Actual: image

1. Ordered list item 1
2. * Bullet 1 in list item 2
    * Bullet 2 in list item 2
3. List item 3

Expected: image Actual: image


See reference: https://www.reddit.com/wiki/markdown


Current workaround

(This only solves part of the issues)

const mdConverter = new showdown.Converter({
    tables: true,
    simplifiedAutoLink: true,
    literalMidWordUnderscores: true,
    strikethrough: true,
    ghCodeBlocks: true,
    disableForced4SpacesIndentedSublists: true,
});
function redditPostToHTML(original) {
    // fix Reddit tables to have at least two dashes per cell in the alignment row
    let body = original.replace(/(?<=^\s*|\|\s*)(:?)-(:?)(?=\s*\|[-|\s:]*$)/gm, "$1--$2");
    // convert superscripts in the form "^(some text)" or "^text" to <sup>text</sup>
    const multiwordSuperscriptRegex = /\^\((.+?)\)/gm;
    while (multiwordSuperscriptRegex.test(body)) {
        body = body.replace(multiwordSuperscriptRegex, "<sup>$1</sup>");
    }
    const superscriptRegex = /\^(\S+)/gm;
    while (superscriptRegex.test(body)) {
        body = body.replace(superscriptRegex, "<sup>$1</sup>");
    }
    // convert user and subreddit mentions to links (can be /u/, /r/, u/, or r/)
    body = body.replace(/(?<=^|[^\w\/])(\/?)([ur]\/\w+)/gm, "[$1$2](/$2)");
    // add spaces after '>' to keep blockquotes (if it has '>!' ignore since that is spoilertext)
    body = body.replace(/^((?:&gt;|>)+)(?=[^!\s])/gm, function (match, p1) {
        return p1.replace(/&gt;/g, ">") + " ";
    });
    // convert markdown to HTML
    let html = mdConverter.makeHtml(body);
    // convert Reddit spoilertext
    return html.replace(
        /(?<=^|\s|>)&gt;!(.+?)!&lt;(?=$|\s|<)/gm,
        "<span class='md-spoiler-text' title='Reveal spoiler'>$1</span>"
    );
}