or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdparser.mdserializer.mdspecifications.mdutilities.md

serializer.mddocs/

0

# Serializer System

1

2

The serializer system provides state machine functionality for converting ProseMirror document structures into markdown AST. It offers a fluent API for building complex document serialization with extensible node and mark processing.

3

4

## Capabilities

5

6

### SerializerState Class

7

8

The main state machine class for serializing ProseMirror nodes to markdown AST.

9

10

```typescript { .api }

11

/**

12

* State for serializer. Transform prosemirror state into remark AST.

13

*/

14

class SerializerState extends Stack<MarkdownNode, SerializerStackElement> {

15

readonly schema: Schema;

16

17

/**

18

* Create a serializer 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 Serializer function that converts ProseMirror nodes to markdown text

22

*/

23

static create(schema: Schema, remark: RemarkParser): Serializer;

24

25

/**

26

* Open a new node, the next operations will add nodes into that new node until closeNode is called.

27

* @param type - Markdown AST node type to open

28

* @param value - Optional text value for the node

29

* @param props - Optional additional properties for the node

30

* @returns SerializerState instance for chaining

31

*/

32

openNode(type: string, value?: string, props?: JSONRecord): SerializerState;

33

34

/**

35

* Close the current node and push it into the parent node.

36

* @returns SerializerState instance for chaining

37

*/

38

closeNode(): SerializerState;

39

40

/**

41

* Add a node into current node.

42

* @param type - Markdown AST node type to add

43

* @param children - Optional child nodes

44

* @param value - Optional text value for the node

45

* @param props - Optional additional properties for the node

46

* @returns SerializerState instance for chaining

47

*/

48

addNode(type: string, children?: MarkdownNode[], value?: string, props?: JSONRecord): SerializerState;

49

50

/**

51

* Open a new mark, the next nodes added will have that mark.

52

* The mark will be closed automatically.

53

* @param mark - ProseMirror mark instance

54

* @param type - Markdown AST node type for the mark

55

* @param value - Optional text value for the mark

56

* @param props - Optional additional properties for the mark

57

* @returns SerializerState instance for chaining

58

*/

59

withMark(mark: Mark, type: string, value?: string, props?: JSONRecord): SerializerState;

60

61

/**

62

* Close a opened mark.

63

* In most cases you don't need this because marks will be closed automatically.

64

* @param mark - ProseMirror mark instance to close

65

* @returns SerializerState instance for chaining

66

*/

67

closeMark(mark: Mark): SerializerState;

68

69

/**

70

* Give the node or node list back to the state and the state will find a proper runner to handle it.

71

* @param nodes - ProseMirror nodes to process (single node or fragment)

72

* @returns SerializerState instance for chaining

73

*/

74

next(nodes: Node | Fragment): SerializerState;

75

76

/**

77

* Use a remark parser to serialize current AST stored.

78

* @param remark - Remark parser instance

79

* @returns Serialized markdown text

80

*/

81

toString(remark: RemarkParser): string;

82

83

/**

84

* Transform a prosemirror node tree into remark AST.

85

* @param tree - ProseMirror node tree to transform

86

* @returns SerializerState instance for chaining

87

*/

88

run(tree: Node): SerializerState;

89

}

90

```

91

92

**Usage Examples:**

93

94

```typescript

95

import { SerializerState } from "@milkdown/transformer";

96

import { remark } from "remark";

97

import { schema } from "@milkdown/prose/model";

98

99

// Create a serializer

100

const serializer = SerializerState.create(schema, remark());

101

102

// Serialize ProseMirror to markdown

103

const markdown = serializer(prosemirrorDoc);

104

105

// Manual state manipulation

106

const state = new SerializerState(schema);

107

state.openNode('root')

108

.openNode('heading', undefined, { depth: 1 })

109

.addNode('text', undefined, 'Hello World')

110

.closeNode()

111

.openNode('paragraph')

112

.openNode('strong')

113

.addNode('text', undefined, 'bold')

114

.closeNode()

115

.addNode('text', undefined, ' text')

116

.closeNode()

117

.closeNode();

118

119

const markdown = state.toString(remark());

120

```

121

122

### SerializerStackElement Class

123

124

Stack element implementation for serializer state management.

125

126

```typescript { .api }

127

/**

128

* Stack element for serializer state, holds markdown AST nodes during transformation.

129

*/

130

class SerializerStackElement extends StackElement<MarkdownNode> {

131

type: string;

132

children?: MarkdownNode[];

133

value?: string;

134

props: JSONRecord;

135

136

/**

137

* Create a new serializer stack element.

138

* @param type - Markdown AST node type

139

* @param children - Optional child nodes

140

* @param value - Optional text value

141

* @param props - Optional additional properties

142

* @returns New SerializerStackElement instance

143

*/

144

static create(type: string, children?: MarkdownNode[], value?: string, props?: JSONRecord): SerializerStackElement;

145

146

/**

147

* Add nodes to the element's children.

148

* @param node - Node to add

149

* @param rest - Additional nodes to add

150

*/

151

push(node: MarkdownNode, ...rest: MarkdownNode[]): void;

152

153

/**

154

* Remove and return the last node from children.

155

* @returns Last node or undefined if empty

156

*/

157

pop(): MarkdownNode | undefined;

158

}

159

```

160

161

### Serializer Specification Types

162

163

Types for defining custom serialization behavior.

164

165

```typescript { .api }

166

/**

167

* The serializer type which is used to transform prosemirror node into markdown text.

168

*/

169

type Serializer = (content: Node) => string;

170

171

/**

172

* The spec for node serializer in schema.

173

*/

174

interface NodeSerializerSpec {

175

/**

176

* The match function to check if the node is the target node.

177

* @param node - ProseMirror node to check

178

* @returns true if this spec should handle the node

179

*/

180

match: (node: Node) => boolean;

181

182

/**

183

* The runner function to transform the node into markdown text.

184

* Generally, you should call methods in state to add node to state.

185

* @param state - Serializer state for adding nodes

186

* @param node - ProseMirror node to transform

187

*/

188

runner: (state: SerializerState, node: Node) => void;

189

}

190

191

/**

192

* The spec for mark serializer in schema.

193

*/

194

interface MarkSerializerSpec {

195

/**

196

* The match function to check if the mark is the target mark.

197

* @param mark - ProseMirror mark to check

198

* @returns true if this spec should handle the mark

199

*/

200

match: (mark: Mark) => boolean;

201

202

/**

203

* The runner function to transform the mark into markdown text.

204

* Generally, you should call methods in state to add mark to state.

205

* @param state - Serializer state for adding marks

206

* @param mark - ProseMirror mark to transform

207

* @param node - Associated ProseMirror node

208

* @returns Optional boolean to prevent further processing

209

*/

210

runner: (state: SerializerState, mark: Mark, node: Node) => void | boolean;

211

}

212

```

213

214

**Specification Examples:**

215

216

```typescript

217

// Example node serializer spec for paragraphs

218

const paragraphSerializerSpec: NodeSerializerSpec = {

219

match: (node) => node.type.name === 'paragraph',

220

runner: (state, node) => {

221

state

222

.openNode('paragraph')

223

.next(node.content)

224

.closeNode();

225

}

226

};

227

228

// Example mark serializer spec for emphasis

229

const emphasisSerializerSpec: MarkSerializerSpec = {

230

match: (mark) => mark.type.name === 'emphasis',

231

runner: (state, mark, node) => {

232

state.withMark(mark, 'emphasis');

233

}

234

};

235

236

// Example node serializer spec for headings

237

const headingSerializerSpec: NodeSerializerSpec = {

238

match: (node) => node.type.name === 'heading',

239

runner: (state, node) => {

240

state

241

.openNode('heading', undefined, { depth: node.attrs.level })

242

.next(node.content)

243

.closeNode();

244

}

245

};

246

```