CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-remarkable

High-performance Markdown parser with full CommonMark support, syntax extensions, and configurable rule systems.

Pending
Overview
Eval results
Files

rendering.mddocs/

Rendering System

The Remarkable rendering system converts parsed tokens into HTML output through a customizable rule-based renderer. Each token type has a corresponding rendering rule that can be modified or replaced.

Capabilities

Renderer Class

The main renderer class that converts tokens to HTML.

/**
 * HTML renderer with customizable rule-based output generation
 */
class Renderer {
  /** Render tokens to HTML */
  render(tokens: Token[], options: RemarkableOptions, env: object): string;
  /** Render inline tokens to HTML */
  renderInline(tokens: Token[], options: RemarkableOptions, env: object): string;
  /** Collection of rendering rules */
  rules: RendererRules;
  /** Helper function for generating line breaks */
  getBreak: (tokens: Token[], idx: number) => string;
}

interface RendererRules {
  [ruleName: string]: RendererRule;
}

type RendererRule = (
  tokens: Token[],
  idx: number,
  options: RemarkableOptions,
  env: object,
  renderer: Renderer
) => string;

Usage Examples:

import { Remarkable } from "remarkable";

const md = new Remarkable();

// Access renderer
const renderer = md.renderer;

// Render tokens directly
const tokens = md.parse('# Hello World');
const html = renderer.render(tokens, md.options, {});

Default Rendering Rules

Built-in rendering rules for all standard markdown elements.

interface DefaultRenderingRules {
  // Block elements
  blockquote_open: RendererRule;
  blockquote_close: RendererRule;
  code: RendererRule;
  fence: RendererRule;
  heading_open: RendererRule;
  heading_close: RendererRule;
  hr: RendererRule;
  list_item_open: RendererRule;
  list_item_close: RendererRule;
  ordered_list_open: RendererRule;
  ordered_list_close: RendererRule;
  bullet_list_open: RendererRule;
  bullet_list_close: RendererRule;
  paragraph_open: RendererRule;
  paragraph_close: RendererRule;
  
  // Inline elements
  text: RendererRule;
  code_inline: RendererRule;
  em_open: RendererRule;
  em_close: RendererRule;
  strong_open: RendererRule;
  strong_close: RendererRule;
  del_open: RendererRule;
  del_close: RendererRule;
  ins_open: RendererRule;
  ins_close: RendererRule;
  mark_open: RendererRule;
  mark_close: RendererRule;
  sub: RendererRule;
  sup: RendererRule;
  
  // Links and images
  link_open: RendererRule;
  link_close: RendererRule;
  image: RendererRule;
  
  // Tables
  table_open: RendererRule;
  table_close: RendererRule;
  thead_open: RendererRule;
  thead_close: RendererRule;
  tbody_open: RendererRule;
  tbody_close: RendererRule;
  tr_open: RendererRule;
  tr_close: RendererRule;
  th_open: RendererRule;
  th_close: RendererRule;
  td_open: RendererRule;
  td_close: RendererRule;
  
  // HTML
  htmlblock: RendererRule;
  htmltag: RendererRule;
  
  // Special
  softbreak: RendererRule;
  hardbreak: RendererRule;
}

Custom Rendering Rules

Modifying or replacing rendering rules for custom output.

/**
 * Signature for custom rendering rules
 */
type CustomRendererRule = (
  tokens: Token[],
  idx: number,
  options: RemarkableOptions,
  env: object,
  renderer: Renderer
) => string;

Usage Examples:

const md = new Remarkable();

// Custom heading rule with anchors
md.renderer.rules.heading_open = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  const level = token.hLevel;
  const next = tokens[idx + 1];
  
  // Generate ID from heading text
  let id = '';
  if (next && next.type === 'inline') {
    id = next.content.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]/g, '');
  }
  
  return `<h${level} id="${id}">`;
};

// Custom code block with line numbers
md.renderer.rules.fence = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  const lang = token.info ? ` class="language-${token.info}"` : '';
  const lines = token.content.split('\n');
  
  let result = '<pre><code' + lang + '>\n';
  lines.forEach((line, i) => {
    result += `<span class="line-number">${i + 1}</span>${escapeHtml(line)}\n`;
  });
  result += '</code></pre>\n';
  
  return result;
};

// Custom image rule with lazy loading
md.renderer.rules.image = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  const src = token.attrGet('src');
  const alt = token.content;
  const title = token.attrGet('title');
  
  let result = '<img loading="lazy"';
  result += ` src="${escapeHtml(src)}"`;
  result += ` alt="${escapeHtml(alt)}"`;
  if (title) {
    result += ` title="${escapeHtml(title)}"`;
  }
  result += ' />';
  
  return result;
};

Token Structure

Understanding token structure for custom rendering rules.

interface Token {
  /** Token type (e.g., 'paragraph_open', 'text', 'strong_open') */
  type: string;
  /** HTML tag name for the token */
  tag?: string;
  /** HTML attributes as [name, value] pairs */
  attrs?: Array<[string, string]>;
  /** Source line mapping [start, end] */
  map?: [number, number];
  /** Nesting level change: 1 (open), -1 (close), 0 (self-close) */
  nesting?: number;
  /** Current nesting level */
  level?: number;
  /** Child tokens for container tokens */
  children?: Token[];
  /** Text content for text tokens */
  content?: string;
  /** Markup characters that created this token */
  markup?: string;
  /** Additional info (e.g., language for code blocks) */
  info?: string;
  /** Arbitrary metadata */
  meta?: any;
  /** True for block-level tokens */
  block?: boolean;
  /** True if token should not be rendered */
  hidden?: boolean;
  
  // Helper methods for token attributes
  attrGet(name: string): string | null;
  attrSet(name: string, value: string): void;
  attrPush(attr: [string, string]): void;
  attrJoin(name: string, value: string): void;
}

Usage Examples:

// Working with token attributes
function customLinkRule(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  
  // Get existing attributes
  const href = token.attrGet('href');
  const title = token.attrGet('title');
  
  // Modify attributes
  if (href && href.startsWith('http')) {
    token.attrSet('target', '_blank');
    token.attrSet('rel', 'noopener noreferrer');
  }
  
  // Render with modified attributes
  let result = '<a';
  if (token.attrs) {
    token.attrs.forEach(([name, value]) => {
      result += ` ${name}="${escapeHtml(value)}"`;
    });
  }
  result += '>';
  
  return result;
}

Output Customization

Advanced techniques for customizing HTML output.

/**
 * Helper function for generating line breaks after block elements
 */
function getBreak(tokens: Token[], idx: number): string;

Usage Examples:

// Custom wrapper for all paragraphs
md.renderer.rules.paragraph_open = function(tokens, idx, options, env, renderer) {
  return '<div class="paragraph-wrapper"><p>';
};

md.renderer.rules.paragraph_close = function(tokens, idx, options, env, renderer) {
  return '</p></div>' + renderer.getBreak(tokens, idx);
};

// Add custom CSS classes based on content
md.renderer.rules.blockquote_open = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  let className = 'blockquote';
  
  // Check if next tokens contain specific patterns
  const nextTokens = tokens.slice(idx + 1);
  const hasWarning = nextTokens.some(t => 
    t.type === 'text' && t.content.toLowerCase().includes('warning')
  );
  
  if (hasWarning) {
    className += ' warning';
  }
  
  return `<blockquote class="${className}">`;
};

// Custom table rendering with Bootstrap classes
md.renderer.rules.table_open = function() {
  return '<div class="table-responsive"><table class="table table-striped">\n';
};

md.renderer.rules.table_close = function() {
  return '</table></div>\n';
};

Template Systems Integration

Integrating with template systems and frameworks.

Usage Examples:

// React component integration
md.renderer.rules.image = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  const src = token.attrGet('src');
  const alt = token.content;
  
  // Return React component syntax
  return `<ImageComponent src="${src}" alt="${alt}" />`;
};

// Vue component integration
md.renderer.rules.fence = function(tokens, idx, options, env, renderer) {
  const token = tokens[idx];
  const lang = token.info;
  const code = token.content;
  
  if (lang === 'vue-demo') {
    return `<VueDemo code="${escapeForAttribute(code)}" />`;
  }
  
  // Fallback to default code rendering
  return defaultFenceRule(tokens, idx, options, env, renderer);
};

Install with Tessl CLI

npx tessl i tessl/npm-remarkable

docs

core-parser.md

index.md

linkify.md

rendering.md

rule-system.md

utilities.md

tile.json