0
# Parser System
1
2
The parser system provides state machine functionality for converting markdown AST into ProseMirror document structures. It offers a fluent API for building complex document transformations with extensible node and mark processing.
3
4
## Capabilities
5
6
### ParserState Class
7
8
The main state machine class for parsing markdown AST to ProseMirror nodes.
9
10
```typescript { .api }
11
/**
12
* A state machine for parser. Transform remark AST into prosemirror state.
13
*/
14
class ParserState extends Stack<Node, ParserStackElement> {
15
readonly schema: Schema;
16
17
/**
18
* Create a parser from schema and remark instance.
19
* @param schema - ProseMirror schema defining available nodes and marks
20
* @param remark - Remark parser instance for processing markdown
21
* @returns Parser function that converts markdown text to ProseMirror nodes
22
*/
23
static create(schema: Schema, remark: RemarkParser): Parser;
24
25
/**
26
* Inject root node for prosemirror state.
27
* @param node - Markdown AST node to process
28
* @param nodeType - ProseMirror node type for the root
29
* @param attrs - Optional attributes for the root node
30
* @returns ParserState instance for chaining
31
*/
32
injectRoot(node: MarkdownNode, nodeType: NodeType, attrs?: Attrs): ParserState;
33
34
/**
35
* Open a new node, the next operations will add nodes into that new node until closeNode is called.
36
* @param nodeType - ProseMirror node type to open
37
* @param attrs - Optional attributes for the node
38
* @returns ParserState instance for chaining
39
*/
40
openNode(nodeType: NodeType, attrs?: Attrs): ParserState;
41
42
/**
43
* Close the current node and push it into the parent node.
44
* @returns ParserState instance for chaining
45
*/
46
closeNode(): ParserState;
47
48
/**
49
* Add a node into current node.
50
* @param nodeType - ProseMirror node type to add
51
* @param attrs - Optional attributes for the node
52
* @param content - Optional child nodes
53
* @returns ParserState instance for chaining
54
*/
55
addNode(nodeType: NodeType, attrs?: Attrs, content?: Node[]): ParserState;
56
57
/**
58
* Open a new mark, the next nodes added will have that mark.
59
* @param markType - ProseMirror mark type to open
60
* @param attrs - Optional attributes for the mark
61
* @returns ParserState instance for chaining
62
*/
63
openMark(markType: MarkType, attrs?: Attrs): ParserState;
64
65
/**
66
* Close a opened mark.
67
* @param markType - ProseMirror mark type to close
68
* @returns ParserState instance for chaining
69
*/
70
closeMark(markType: MarkType): ParserState;
71
72
/**
73
* Add a text node into current node.
74
* @param text - Text content to add
75
* @returns ParserState instance for chaining
76
*/
77
addText(text: string): ParserState;
78
79
/**
80
* Give the node or node list back to the state and the state will find a proper runner to handle it.
81
* @param nodes - Markdown nodes to process (single node or array)
82
* @returns ParserState instance for chaining
83
*/
84
next(nodes?: MarkdownNode | MarkdownNode[]): ParserState;
85
86
/**
87
* Build the current state into a ProseMirror document.
88
* @returns The final ProseMirror document node
89
*/
90
toDoc(): Node;
91
92
/**
93
* Transform a markdown string into prosemirror state.
94
* @param remark - Remark parser instance
95
* @param markdown - Markdown text to parse
96
* @returns ParserState instance for chaining
97
*/
98
run(remark: RemarkParser, markdown: string): ParserState;
99
}
100
```
101
102
**Usage Examples:**
103
104
```typescript
105
import { ParserState } from "@milkdown/transformer";
106
import { remark } from "remark";
107
import { schema } from "@milkdown/prose/model";
108
109
// Create a parser
110
const parser = ParserState.create(schema, remark());
111
112
// Parse markdown to ProseMirror
113
const doc = parser("# Hello World\n\nThis is **bold** text.");
114
115
// Manual state manipulation
116
const state = new ParserState(schema);
117
state.openNode(schema.nodes.doc)
118
.openNode(schema.nodes.heading, { level: 1 })
119
.addText("Hello World")
120
.closeNode()
121
.openNode(schema.nodes.paragraph)
122
.openMark(schema.marks.strong)
123
.addText("bold")
124
.closeMark(schema.marks.strong)
125
.addText(" text")
126
.closeNode()
127
.closeNode();
128
129
const doc = state.toDoc();
130
```
131
132
### ParserStackElement Class
133
134
Stack element implementation for parser state management.
135
136
```typescript { .api }
137
/**
138
* Stack element for parser state, holds ProseMirror nodes during transformation.
139
*/
140
class ParserStackElement extends StackElement<Node> {
141
type: NodeType;
142
content: Node[];
143
attrs?: Attrs;
144
145
/**
146
* Create a new parser stack element.
147
* @param type - ProseMirror node type
148
* @param content - Array of child nodes
149
* @param attrs - Optional node attributes
150
* @returns New ParserStackElement instance
151
*/
152
static create(type: NodeType, content: Node[], attrs?: Attrs): ParserStackElement;
153
154
/**
155
* Add nodes to the element's content.
156
* @param node - Node to add
157
* @param rest - Additional nodes to add
158
*/
159
push(node: Node, ...rest: Node[]): void;
160
161
/**
162
* Remove and return the last node from content.
163
* @returns Last node or undefined if empty
164
*/
165
pop(): Node | undefined;
166
}
167
```
168
169
### Parser Specification Types
170
171
Types for defining custom parsing behavior.
172
173
```typescript { .api }
174
/**
175
* The parser type which is used to transform markdown text into prosemirror node.
176
*/
177
type Parser = (text: string) => Node;
178
179
/**
180
* The spec for node parser in schema.
181
*/
182
interface NodeParserSpec {
183
/**
184
* The match function to check if the node is the target node.
185
* @param node - Markdown AST node to check
186
* @returns true if this spec should handle the node
187
*/
188
match: (node: MarkdownNode) => boolean;
189
190
/**
191
* The runner function to transform the node into prosemirror node.
192
* Generally, you should call methods in state to add node to state.
193
* @param state - Parser state for adding nodes
194
* @param node - Markdown AST node to transform
195
* @param proseType - Target ProseMirror node type
196
*/
197
runner: (state: ParserState, node: MarkdownNode, proseType: NodeType) => void;
198
}
199
200
/**
201
* The spec for mark parser in schema.
202
*/
203
interface MarkParserSpec {
204
/**
205
* The match function to check if the node is the target mark.
206
* @param node - Markdown AST node to check
207
* @returns true if this spec should handle the node
208
*/
209
match: (node: MarkdownNode) => boolean;
210
211
/**
212
* The runner function to transform the node into prosemirror mark.
213
* Generally, you should call methods in state to add mark to state.
214
* @param state - Parser state for adding marks
215
* @param node - Markdown AST node to transform
216
* @param proseType - Target ProseMirror mark type
217
*/
218
runner: (state: ParserState, node: MarkdownNode, proseType: MarkType) => void;
219
}
220
```
221
222
**Specification Examples:**
223
224
```typescript
225
// Example node parser spec for paragraphs
226
const paragraphParserSpec: NodeParserSpec = {
227
match: (node) => node.type === 'paragraph',
228
runner: (state, node, type) => {
229
state
230
.openNode(type)
231
.next(node.children)
232
.closeNode();
233
}
234
};
235
236
// Example mark parser spec for emphasis
237
const emphasisParserSpec: MarkParserSpec = {
238
match: (node) => node.type === 'emphasis',
239
runner: (state, node, type) => {
240
state
241
.openMark(type)
242
.next(node.children)
243
.closeMark(type);
244
}
245
};
246
```