or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdparser.mdserializer.mdspecifications.mdutilities.md

parser.mddocs/

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

```