Showdown Markdown to HTML Converter

repository·master·Indexed 12 days ago

https://github.com/showdownjs/showdown

A JavaScript library that converts Markdown text into HTML, compatible with both client-side (browser) and server-side (Node.js) environments. Version 3.0.0-rc2 supports multiple flavors including GFM, CommonMark, and original Markdown, and provides a CLI for file conversion. It features a flexible API for managing converter options, flavors, and custom extensions.

Tokens
26.6K
Snippets
93
Records
134
Agent score
92%

What's inside Showdown

  1. Introduction to Showdown

    master
    Showdown is a JavaScript library that converts Markdown to HTML. It is designed to be used in both client-side (browser) and server-side (Node.js) environments. It is based on the original Markdown specifications by John Gruber.
  2. How the Showdown event system works

    master

    The event system is the foundation for modern Showdown extensions (specifically listener extensions). As Showdown parses a document, sub-parsers emit events during the conversion process. A listener extension can subscribe to these events to inspect or modify the conversion in flight.

    The lifecycle of an event is as follows:

    1. A sub-parser emits an event (potentially a batch of events).
    2. A listener extension registers for a specific event type.
    3. The extension receives an event object and can modify certain properties to change the sub-parser's behavior or output.
    4. The extension returns the modified event object to the converter.
    5. The converter passes the event object to the next extension in the chain.
  3. Override node rendering in makeMarkdown()

    master

    In makeMarkdown(), you can override how a specific HTML node is converted to Markdown by using the onStart event of its corresponding sub-parser.

    If you set evt.output to a non-empty string within an onStart listener, that string is used as the result and the default rendering of the node is skipped. The matching onEnd event will still run, but the default logic is bypassed. This is the makeMarkdown equivalent of the onCapture behavior in makeHtml.

    // Render every <a> as bare text instead of a Markdown link
    converter.listen('makeMarkdown.links.onStart', function (evt) {
      evt.output = evt.matches.node.textContent;
      return evt;
    });
  4. Understand Showdown List Behavior

    master

    Showdown's list implementation has two specific behaviors to note:

    1. Loose vs Tight Lists: If any list item is separated from another by a blank line, Showdown wraps all items in <p> tags. To avoid this, ensure items are adjacent.
    2. Four-space Indentation: Nested lists require an indentation of four spaces (or one tab) per level. This is consistent with the original spec but differs from GFM/CommonMark. You can relax this using the disableForced4SpacesIndentedSublists option.
    * Item 1
    
    * Item 2 (This will trigger <p> tags for all items in the list)
  5. What GitHub Flavored Markdown (GFM) adds to CommonMark

    master

    The gfm flavor in Showdown is built on top of the commonmark base and adds the following extensions:

    • Tables: Pipe tables with support for per-column alignment.
    • Task lists: Checkboxes using - [ ] and - [x] syntax.
    • Strikethrough: Text decoration using ~~text~~.
    • Autolink literals: Bare URLs are converted to links. Note: Showdown also links <www.…> inside angle brackets, which is a deviation from the standard GFM spec.
    • @-mentions and emoji: Support for mentions and emoji syntax (e.g., :smile:).
    • Footnotes: Support for [^id] references and definitions (also reversible via makeMarkdown).
  6. What the `cmSpec` option covers

    master

    Setting cmSpec to true switches Showdown's block-level and inline parsing from legacy matching to the CommonMark spec. This affects:

    • Emphasis: Uses the CommonMark delimiter-run (flanking) algorithm.
    • Autolinks: Recognizes <scheme:uri> and <email> without entity-encoding, plus <www.…> (Showdown extension).
    • Links & images: Follows spec for balanced-paren, <...> destinations, backslash escapes, and alt-text flattening.
    • Inline raw HTML: Uses strict CommonMark grammar; malformed tags are escaped.
    • HTML blocks: Uses the 7 CommonMark block types.
    • Block quotes: Parses as CommonMark container blocks (handles empty >, splitting at blank lines, and lazy continuation).
    • Lists: Uses a container-block parser (marker/delimiter splitting, ordered start, loose/tight, and indentation-based nesting).
    • Unified inline: Uses a single unified parser with one delimiter stack.
    • Tabs: Expands tabs to 4-column tab stops in block-structure indentation.
    • Containers: Parses leaf blocks (fenced code, HTML blocks, etc.) in the context of their containing block quote or list item.
  7. Select a Markdown syntax flavor

    master

    Showdown supports four different Markdown syntax flavors. You can switch between them using showdown.setFlavor(...) or by passing the corresponding flavor name in the converter options.

    Supported flavors:

    • original: The 2004 John Gruber reference implementation. Smallest feature set.
    • vanilla: Showdown's default behavior. It includes the original spec plus opt-in extras like tables, task lists, and emoji (enabled via options).
    • commonmark: A strict, unambiguous implementation of the CommonMark specification.
    • gfm: GitHub Flavored Markdown. Includes CommonMark plus GitHub-specific extensions like task lists, tables, strikethrough, and @-mentions.

    Note: The vanilla flavor is the default behavior when no flavor is explicitly set.

    // Example of setting a flavor (conceptual usage)
    const converter = new showdown.Converter({ flavor: 'gfm' });
    // OR
    converter.setFlavor('commonmark');
  8. Understand the Event Object and its properties

    master

    When an event is triggered, the listener receives an event object. A key property of this object is matches, which contains the text captured by the sub-parser.

    Note that the structure of matches varies depending on which sub-parser emitted the event. Additionally, some properties within matches are read-only; these are identified by a leading underscore (e.g., _wholeMatch).

    // Example of a blockquote `onCapture` event object
    {
      _wholeMatch: "> some awesome quote",
      blockquote: "some awesome quote"
    }
  9. How extension modes work in Showdown

    master

    Showdown extensions allow you to add custom functionality to the Markdown conversion process. There are two primary modes of operation:

    1. Listener extensions (Recommended): These use the Showdown event system to hook into sub-parsers. They can inspect or modify captures, matches, attributes, and output mid-conversion. This mode provides high precision for complex transformations.
    2. Legacy lang/output extensions (Deprecated): These are older modes that use regex/replace or a filter callback to rewrite text either before parsing (lang) or after parsing (output). While they still function, they are now thin wrappers over document-level events and will trigger a deprecation warning. Use listener extensions for all new development.
  10. Use the `onStart` event to modify sub-parser input

    master

    The onStart event is emitted when a sub-parser starts. It is always called unless the sub-parser is disabled via options.

    When to use: Use this event when you want to change the input passed to the sub-parser.

    Warning: The input property contains the full text that was passed to the converter, not just the fragment relevant to the sub-parser. To pass modified text down the chain, write to the output property.

    // Example of the properties available in onStart
    // { 
    //   input: 'full text string', 
    //   output: 'modified text string', 
    //   regexp: null, 
    //   matches: null, 
    //   attributes: null 
    // }
  11. Understand the Showdown sub-parser event lifecycle

    master

    When converting Markdown to HTML (makehtml), sub-parsers emit events in a strict, sequential order. This lifecycle allows you to intercept, modify, or augment the parsing process at different stages:

    1. onStart: Emitted when the sub-parser begins. Use this to modify the full text passed to the sub-parser before any processing occurs.
    2. onCapture: Emitted when a regex match is successfully found. Use this to modify the sub-parser's behavior, the captured text, or the resulting HTML. Note: It is highly recommended to mutate the matches or attributes objects instead of writing to the output property to avoid breaking the parsing chain.
    3. onHash: Emitted after capture but before the output is hashed. Use this to change the sub-parser's raw output before hashing occurs.
    4. onEnd: Emitted when the sub-parser finishes. Use this to perform final changes to the text after it has been hashed.