0
# Rule System
1
2
Remarkable uses a sophisticated rule-based system for parsing markdown. The system consists of three main parsers (core, block, inline) each with their own set of configurable rules managed by Ruler instances.
3
4
## Capabilities
5
6
### Ruler Class
7
8
The Ruler class manages rule chains and execution order for parsing operations.
9
10
```javascript { .api }
11
/**
12
* Rule manager for organizing and controlling parsing rules
13
*/
14
class Ruler {
15
/** Add rule to the end of chain */
16
push(name: string, fn: RuleFunction, options?: RuleOptions): void;
17
/** Add rule before specified rule */
18
before(beforeName: string, ruleName: string, fn: RuleFunction, options?: RuleOptions): void;
19
/** Add rule after specified rule */
20
after(afterName: string, ruleName: string, fn: RuleFunction, options?: RuleOptions): void;
21
/** Replace rule function */
22
at(name: string, fn: RuleFunction, options?: RuleOptions): void;
23
/** Enable rules by name */
24
enable(names: string | string[], ignoreInvalid?: boolean): string[];
25
/** Disable rules by name */
26
disable(names: string | string[], ignoreInvalid?: boolean): string[];
27
/** Get active rules for chain */
28
getRules(chainName: string): RuleFunction[];
29
}
30
31
interface RuleOptions {
32
/** Alternative rule names this rule can replace */
33
alt?: string[];
34
}
35
36
type RuleFunction = (state: StateCore | StateBlock | StateInline) => boolean | void;
37
```
38
39
**Usage Examples:**
40
41
```javascript
42
import { Remarkable } from "remarkable";
43
44
const md = new Remarkable();
45
46
// Add custom rule to block parser
47
md.block.ruler.push('custom_block', function(state, start, end, silent) {
48
// Custom block parsing logic
49
return false;
50
});
51
52
// Insert rule before 'paragraph'
53
md.block.ruler.before('paragraph', 'custom_before', customRule);
54
55
// Enable/disable rules
56
md.core.ruler.enable(['abbr', 'footnote_tail']);
57
md.inline.ruler.disable(['autolink']);
58
```
59
60
### Core Parser Rules
61
62
Core processing rules that handle document-level operations.
63
64
```javascript { .api }
65
interface CoreRules {
66
/** Process block-level elements */
67
block: RuleFunction;
68
/** Process inline elements within blocks */
69
inline: RuleFunction;
70
/** Resolve link references */
71
references: RuleFunction;
72
/** Apply typographic replacements */
73
replacements: RuleFunction;
74
/** Apply smart quotes */
75
smartquotes: RuleFunction;
76
/** Process abbreviations */
77
abbr: RuleFunction;
78
/** Finalize abbreviation processing */
79
abbr2: RuleFunction;
80
/** Process footnote tails */
81
footnote_tail: RuleFunction;
82
}
83
```
84
85
**Default Core Rule Chain:**
86
1. `block` - Parse block elements
87
2. `inline` - Parse inline elements
88
3. `references` - Resolve references
89
4. `replacements` - Typography replacements
90
5. `smartquotes` - Smart quotes
91
6. `abbr2` - Finalize abbreviations
92
7. `footnote_tail` - Process footnotes
93
94
### Block Parser Rules
95
96
Rules for parsing block-level markdown elements.
97
98
```javascript { .api }
99
interface BlockRules {
100
/** Code blocks (indented) */
101
code: RuleFunction;
102
/** Fenced code blocks */
103
fences: RuleFunction;
104
/** Blockquotes */
105
blockquote: RuleFunction;
106
/** Horizontal rules */
107
hr: RuleFunction;
108
/** Lists (ordered and unordered) */
109
list: RuleFunction;
110
/** Footnote definitions */
111
footnote: RuleFunction;
112
/** ATX headings (# ## ###) */
113
heading: RuleFunction;
114
/** Setext headings (underlined) */
115
lheading: RuleFunction;
116
/** HTML blocks */
117
htmlblock: RuleFunction;
118
/** Tables */
119
table: RuleFunction;
120
/** Definition lists */
121
deflist: RuleFunction;
122
/** Paragraphs */
123
paragraph: RuleFunction;
124
}
125
```
126
127
**Default Block Rule Chain:**
128
1. `code` - Indented code blocks
129
2. `fences` - Fenced code blocks
130
3. `blockquote` - Blockquotes
131
4. `hr` - Horizontal rules
132
5. `list` - Lists
133
6. `footnote` - Footnote definitions
134
7. `heading` - ATX headings
135
8. `lheading` - Setext headings
136
9. `htmlblock` - HTML blocks
137
10. `table` - Tables
138
11. `deflist` - Definition lists
139
12. `paragraph` - Paragraphs
140
141
### Inline Parser Rules
142
143
Rules for parsing inline markdown elements.
144
145
```javascript { .api }
146
interface InlineRules {
147
/** Plain text */
148
text: RuleFunction;
149
/** Line breaks */
150
newline: RuleFunction;
151
/** Escape sequences */
152
escape: RuleFunction;
153
/** Code spans */
154
backticks: RuleFunction;
155
/** Strikethrough */
156
del: RuleFunction;
157
/** Insert/underline */
158
ins: RuleFunction;
159
/** Mark/highlight */
160
mark: RuleFunction;
161
/** Bold and italic */
162
emphasis: RuleFunction;
163
/** Subscript */
164
sub: RuleFunction;
165
/** Superscript */
166
sup: RuleFunction;
167
/** Links and images */
168
links: RuleFunction;
169
/** Inline footnotes */
170
footnote_inline: RuleFunction;
171
/** Footnote references */
172
footnote_ref: RuleFunction;
173
/** Autolinks <url> */
174
autolink: RuleFunction;
175
/** HTML tags */
176
htmltag: RuleFunction;
177
/** HTML entities */
178
entity: RuleFunction;
179
}
180
```
181
182
**Default Inline Rule Chain:**
183
1. `text` - Plain text
184
2. `newline` - Line breaks
185
3. `escape` - Escape sequences
186
4. `backticks` - Code spans
187
5. `del` - Strikethrough
188
6. `ins` - Insert/underline
189
7. `mark` - Mark/highlight
190
8. `emphasis` - Bold/italic
191
9. `sub` - Subscript
192
10. `sup` - Superscript
193
11. `links` - Links and images
194
12. `footnote_inline` - Inline footnotes
195
13. `footnote_ref` - Footnote references
196
14. `autolink` - Autolinks
197
15. `htmltag` - HTML tags
198
16. `entity` - HTML entities
199
200
### Custom Rule Development
201
202
Creating custom parsing rules for extending Remarkable functionality.
203
204
```javascript { .api }
205
/**
206
* State objects passed to rule functions
207
*/
208
interface StateCore {
209
src: string;
210
env: object;
211
options: RemarkableOptions;
212
tokens: Token[];
213
inlineMode: boolean;
214
inline: ParserInline;
215
block: ParserBlock;
216
renderer: Renderer;
217
}
218
219
interface StateBlock {
220
src: string;
221
md: Remarkable;
222
env: object;
223
tokens: Token[];
224
bMarks: number[];
225
eMarks: number[];
226
tShift: number[];
227
sCount: number[];
228
blkIndent: number;
229
line: number;
230
lineMax: number;
231
tight: boolean;
232
parentType: string;
233
ddIndent: number;
234
getLines(begin: number, end: number, indent: number, keepLastLF: boolean): string;
235
isEmpty(line: number): boolean;
236
skipEmptyLines(from: number): number;
237
skipSpaces(pos: number): number;
238
skipChars(pos: number, code: number): number;
239
skipCharsBack(pos: number, code: number, min: number): number;
240
push(token: Token): void;
241
}
242
243
interface StateInline {
244
src: string;
245
env: object;
246
md: Remarkable;
247
tokens: Token[];
248
pos: number;
249
posMax: number;
250
level: number;
251
pending: string;
252
pendingLevel: number;
253
cache: object;
254
delimiters: object[];
255
push(token: Token): void;
256
pushPending(): Token;
257
scanDelims(start: number, canSplitWord: boolean): object;
258
}
259
```
260
261
**Usage Examples:**
262
263
```javascript
264
// Custom block rule for special containers
265
function customContainer(state, start, end, silent) {
266
const marker = ':::';
267
let pos = state.bMarks[start] + state.tShift[start];
268
let max = state.eMarks[start];
269
270
// Check for marker
271
if (pos + marker.length > max) return false;
272
if (state.src.slice(pos, pos + marker.length) !== marker) return false;
273
274
if (silent) return true;
275
276
// Find closing marker
277
let nextLine = start + 1;
278
let found = false;
279
280
while (nextLine < end) {
281
pos = state.bMarks[nextLine] + state.tShift[nextLine];
282
max = state.eMarks[nextLine];
283
284
if (state.src.slice(pos, pos + marker.length) === marker) {
285
found = true;
286
break;
287
}
288
nextLine++;
289
}
290
291
if (!found) return false;
292
293
// Create tokens
294
const token_o = state.push({ type: 'container_open', level: state.level++ });
295
const token_c = state.push({ type: 'container_close', level: --state.level });
296
297
token_o.map = [start, nextLine];
298
token_c.map = [nextLine, nextLine + 1];
299
300
state.line = nextLine + 1;
301
return true;
302
}
303
304
// Add the rule
305
md.block.ruler.before('paragraph', 'container', customContainer);
306
```
307
308
### Rule Configuration
309
310
Configuring which rules are active through presets and manual configuration.
311
312
```javascript { .api }
313
interface PresetConfig {
314
options?: RemarkableOptions;
315
components?: {
316
core?: { rules: string[] };
317
block?: { rules: string[] };
318
inline?: { rules: string[] };
319
};
320
}
321
```
322
323
**Usage Examples:**
324
325
```javascript
326
// Enable specific rules only
327
md.configure({
328
components: {
329
core: { rules: ['block', 'inline'] },
330
block: { rules: ['paragraph', 'heading', 'list'] },
331
inline: { rules: ['text', 'emphasis', 'links'] }
332
}
333
});
334
335
// Enable/disable individual rules
336
md.block.ruler.enable(['table', 'footnote']);
337
md.inline.ruler.disable(['autolink', 'htmltag']);
338
```