High-performance Markdown parser with full CommonMark support, syntax extensions, and configurable rule systems.
npx @tessl/cli install tessl/npm-remarkable@2.0.0Remarkable is a high-performance Markdown parser with full CommonMark compliance and extensive syntax extensions. It provides a modular architecture with configurable rule systems for block parsing, inline parsing, and rendering, supporting advanced features like footnotes, tables, strikethrough, and typographic enhancements.
npm install remarkableimport { Remarkable, utils } from "remarkable";
import { linkify } from "remarkable/linkify";For CommonJS:
const { Remarkable, utils } = require("remarkable");
const { linkify } = require("remarkable/linkify");For UMD (browser):
const { Remarkable, linkify, utils } = window.remarkable;import { Remarkable } from "remarkable";
// Create parser with default preset
const md = new Remarkable();
// Parse markdown to HTML
const html = md.render('# Hello World\n\nThis is **bold** text.');
// Output: <h1>Hello World</h1><p>This is <strong>bold</strong> text.</p>
// Use preset with options
const mdFull = new Remarkable('full', {
html: true,
typographer: true,
breaks: true
});
const result = mdFull.render('# Title\n\nText with "smart quotes" and...');Remarkable is built around several key components:
Main parser functionality for converting markdown to HTML with configurable presets and options.
class Remarkable {
constructor(preset?: string, options?: RemarkableOptions);
render(markdown: string, env?: object): string;
parse(markdown: string, env?: object): Token[];
renderInline(markdown: string, env?: object): string;
parseInline(markdown: string, env?: object): Token[];
set(options: RemarkableOptions): void;
configure(presets: PresetConfig): void;
use(plugin: PluginFunction, options?: object): Remarkable;
// Parser components access
core: ParserCore;
block: ParserBlock;
inline: ParserInline;
renderer: Renderer;
ruler: Ruler;
options: RemarkableOptions;
}
interface RemarkableOptions {
html?: boolean;
xhtmlOut?: boolean;
breaks?: boolean;
langPrefix?: string;
linkTarget?: string;
typographer?: boolean;
quotes?: string;
highlight?: (str: string, lang: string) => string;
maxNesting?: number;
}Advanced rule management and preset configuration for customizing parser behavior.
interface PresetConfig {
options?: RemarkableOptions;
components?: {
core?: { rules: string[] };
block?: { rules: string[] };
inline?: { rules: string[] };
};
}
class Ruler {
push(name: string, fn: RuleFunction, options?: RuleOptions): void;
before(beforeName: string, ruleName: string, fn: RuleFunction, options?: RuleOptions): void;
after(afterName: string, ruleName: string, fn: RuleFunction, options?: RuleOptions): void;
at(name: string, fn: RuleFunction, options?: RuleOptions): void;
enable(names: string | string[], ignoreInvalid?: boolean): string[];
disable(names: string | string[], ignoreInvalid?: boolean): string[];
getRules(chainName: string): RuleFunction[];
}Customizable HTML rendering system with extensible rule-based output generation.
class Renderer {
render(tokens: Token[], options: RemarkableOptions, env: object): string;
renderInline(tokens: Token[], options: RemarkableOptions, env: object): string;
rules: RendererRules;
getBreak: (tokens: Token[], idx: number) => string;
}
interface RendererRules {
[ruleName: string]: (tokens: Token[], idx: number, options: RemarkableOptions, env: object, renderer: Renderer) => string;
}Optional plugin for automatic URL and email detection and conversion to links.
function linkify(md: Remarkable): void;Helper functions for custom rule development and text processing.
interface Utils {
isString(obj: any): boolean;
has(object: object, key: string): boolean;
assign(target: object, ...sources: object[]): object;
unescapeMd(str: string): string;
replaceEntities(str: string): string;
escapeHtml(str: string): string;
}interface Token {
type: string;
tag?: string;
attrs?: Array<[string, string]>;
map?: [number, number];
nesting?: number;
level?: number;
children?: Token[];
content?: string;
markup?: string;
info?: string;
meta?: any;
block?: boolean;
hidden?: boolean;
// Token attribute methods
attrGet(name: string): string | null;
attrSet(name: string, value: string): void;
attrPush(attr: [string, string]): void;
attrJoin(name: string, value: string): void;
}
type RuleFunction = (state: StateCore | StateBlock | StateInline) => boolean | void;
type PluginFunction = (md: Remarkable, options?: object) => void;
interface RuleOptions {
alt?: string[];
}
// Parser component interfaces
interface ParserCore {
ruler: Ruler;
process(state: StateCore): void;
}
interface ParserBlock {
ruler: Ruler;
tokenize(state: StateBlock, startLine: number, endLine: number): void;
parse(str: string, options: RemarkableOptions, env: object, outTokens: Token[]): void;
}
interface ParserInline {
ruler: Ruler;
validateLink: (url: string) => boolean;
skipToken(state: StateInline): void;
tokenize(state: StateInline): void;
parse(str: string, options: RemarkableOptions, env: object, outTokens: Token[]): void;
}
// State interfaces for rule development
interface StateCore {
src: string;
env: object;
options: RemarkableOptions;
tokens: Token[];
inlineMode: boolean;
inline: ParserInline;
block: ParserBlock;
renderer: Renderer;
}
interface StateBlock {
src: string;
md: Remarkable;
env: object;
tokens: Token[];
bMarks: number[];
eMarks: number[];
tShift: number[];
sCount: number[];
blkIndent: number;
line: number;
lineMax: number;
tight: boolean;
parentType: string;
ddIndent: number;
getLines(begin: number, end: number, indent: number, keepLastLF: boolean): string;
isEmpty(line: number): boolean;
skipEmptyLines(from: number): number;
skipSpaces(pos: number): number;
skipChars(pos: number, code: number): number;
skipCharsBack(pos: number, code: number, min: number): number;
push(token: Token): void;
}
interface StateInline {
src: string;
env: object;
md: Remarkable;
tokens: Token[];
pos: number;
posMax: number;
level: number;
pending: string;
pendingLevel: number;
cache: object;
delimiters: object[];
push(token: Token): void;
pushPending(): Token;
scanDelims(start: number, canSplitWord: boolean): object;
cacheGet(pos: number): number;
cacheSet(pos: number, value: number): void;
}