markdown-exit Documentation

repository·main·Indexed 23 days ago

https://github.com/serkodev/markdown-exit

A TypeScript-first rewrite of markdown-it that provides a CommonMark-compliant parser and renderer. It features async rendering for all rules, strong typings, and a smaller bundle size while maintaining compatibility with the existing markdown-it plugin ecosystem. Includes the @markdown-exit/testgen package for generating tests for markdown parsers.

Tokens
11.7K
Snippets
31
Records
65
Agent score
79%

What's inside markdown-exit

  1. What is markdown-exit?

    main

    markdown-exit is a modern Markdown toolkit consisting of a parser and a renderer. It is fully CommonMark-compliant and built with a TypeScript-first design to provide strong typing and a superior developer experience (DX). It is designed as a drop-in replacement for markdown-it with several key improvements:

    • TypeScript-first: Provides strong types for type-safe development.
    • Async Rendering: Supports asynchronous rendering processes.
    • Optimized Bundle: Tree-shaking friendly with a ~30% smaller bundle size compared to markdown-it.
    • Performance: Improved performance over the original implementation.
    • Compatibility: Compatible with the existing markdown-it plugin ecosystem.
  2. How the plugin ecosystem works in markdown-exit

    main
    markdown-exit uses a plugin system to enable custom syntax and rendering. A major advantage of this toolkit is its compatibility with markdown-it plugins; existing community plugins for markdown-it work out of the box with markdown-exit, making migration straightforward. You can create your own plugins or adopt existing ones from the markdown-it ecosystem.
  3. Implement async render rules in plugins

    main

    Unlike standard markdown-it, markdown-exit supports async rendering. This allows you to implement asynchronous logic (like fetching data or image dimensions) directly within your renderer rules by defining them as async functions.

    import type { MarkdownExit } from 'markdown-exit'
    
    export function pluginSizeImg(md: MarkdownExit) {
      // Example async render rule for images
      md.renderer.rules.image = async (tokens, idx) => {
        const src = tokens[idx].attrGet('src')
        const { width, height } = await fetchImageSize(src)
        return `<img src="${src}" width="${width}" height="${height}" />`
      }
    }
  4. Develop custom markdown-exit plugins

    main

    To develop a plugin, create a function that accepts a MarkdownExit instance. You can manipulate the inline.ruler to add custom inline rules. It is recommended to review the markdown-it architecture and the MarkdownExit class properties for full API details.

    import type { MarkdownExit } from 'markdown-exit'
    
    export function pluginCustom(md: MarkdownExit) {
      // add a custom inline rule after the image rule
      md.inline.ruler.after('image', 'custom_rule', (state, silent) => {
        // ... custom_rule implementation
        return false
      })
    }
  5. Initialize markdown-exit with presets and options

    main

    You can customize the parsing and rendering behavior of markdown-exit during initialization using presets or specific configuration options.

    Presets

    • default: The standard configuration.
    • commonmark: Follows the CommonMark specification.
    • zero: A minimal configuration.

    Options

    For granular control, pass an options object to createMarkdownExit. Common options include:

    • html: Boolean. Enable/disable HTML tags in source.
    • linkify: Boolean. Auto-convert URL text to links.

    Refer to MarkdownExitOptions for the full list of available configuration keys.

    // default
    const md = createMarkdownExit()
    
    // commonmark preset
    const md = createMarkdownExit('commonmark')
    
    // granular options
    const md = createMarkdownExit({
      html: true,
      linkify: true,
    })
  6. Use named imports for tree-shaking in markdown-exit

    main

    For better tree-shaking support, use named imports instead of default imports. You can instantiate the library using the createMarkdownExit factory helper or by using the new keyword with the MarkdownExit class.

    // Recommended: factory helper
    import { createMarkdownExit } from 'markdown-exit'
    const md = createMarkdownExit()
    
    // Alternative: with the `new` keyword
    import { MarkdownExit } from 'markdown-exit'
    const md = new MarkdownExit()
  7. Migrate from markdown-it to markdown-exit

    main

    To migrate from markdown-it to markdown-exit, install markdown-exit and update your import statements. While markdown-exit supports default imports for drop-in compatibility, it is recommended to use named imports to improve tree-shaking efficiency.

    - import MarkdownIt from 'markdown-it'
    + import MarkdownExit from 'markdown-exit'
  8. Basic Usage of markdown-exit

    main

    To use markdown-exit, import createMarkdownExit and initialize it. The resulting instance is compatible with the markdown-it render API and provides a .render() method to convert markdown strings into HTML.

    import { createMarkdownExit } from 'markdown-exit'
    
    const md = createMarkdownExit()
    const html = md.render('# Hello World')
  9. Use async rendering for performance

    main

    If your highlight function or any render rules are asynchronous (e.g., using an async highlighter like Shiki), use renderAsync or renderInlineAsync. This allows multiple asynchronous tasks, such as highlighting multiple code blocks, to be processed in parallel, improving rendering performance.

    import { codeToHtml } from 'shiki'
    
    const md = createMarkdownExit({
      async highlight(code, lang) {
        return await codeToHtml(code, { lang, theme: 'nord' })
      }
    })
    
    const html = await md.renderAsync(markdown)