or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration-management.mdindex.mdplugin-system.mdprocessing-pipeline.md

plugin-system.mddocs/

0

# Plugin System

1

2

Comprehensive plugin architecture supporting parsers, transformers, compilers, and presets with flexible configuration management and reconfiguration capabilities.

3

4

## Capabilities

5

6

### Use Method

7

8

Configures the processor with plugins, presets, or plugin lists.

9

10

```typescript { .api }

11

/**

12

* Configure processor with plugins, presets, or plugin lists

13

* @param value - Plugin, preset, or list of plugins

14

* @param parameters - Plugin options and parameters

15

* @returns Processor instance for chaining

16

* @throws Error on frozen processor or invalid plugin types

17

*/

18

use(value: Pluggable, ...parameters: unknown[]): Processor;

19

20

// Overloaded signatures for specific types

21

use(plugin: Plugin, ...parameters: unknown[]): Processor;

22

use(preset: Preset): Processor;

23

use(list: PluggableList): Processor;

24

use(value: null | undefined): Processor; // No-op

25

```

26

27

**Usage Examples:**

28

29

```javascript

30

import { unified } from "unified";

31

32

const processor = unified()

33

// Single plugin

34

.use(somePlugin)

35

36

// Plugin with options

37

.use(somePlugin, { option: "value" })

38

39

// Plugin array

40

.use([plugin1, plugin2])

41

42

// Plugin tuples with options

43

.use([

44

[plugin1, { setting: true }],

45

[plugin2, "parameter", { more: "options" }]

46

])

47

48

// Preset

49

.use({

50

plugins: [plugin1, plugin2],

51

settings: { key: "value" }

52

});

53

```

54

55

### Plugin Reconfiguration

56

57

Later calls to `use()` with the same plugin will merge or replace configuration.

58

59

```javascript

60

const processor = unified()

61

// Initial configuration

62

.use(somePlugin, { x: true, y: true })

63

64

// Reconfigure same plugin (merges objects)

65

.use(somePlugin, { y: false, z: true });

66

// Result: { x: true, y: false, z: true }

67

68

// Non-object parameters are replaced

69

processor

70

.use(somePlugin, "initial")

71

.use(somePlugin, "replaced"); // "initial" is replaced with "replaced"

72

```

73

74

### Plugin Enabling/Disabling

75

76

Control plugin activation with boolean parameters.

77

78

```javascript

79

const processor = unified()

80

.use(somePlugin, false) // Disable plugin

81

.use(somePlugin, true) // Enable with no options

82

.use(somePlugin, {}); // Enable with empty options

83

```

84

85

## Plugin Types

86

87

### Parser Plugins

88

89

Plugins that configure the processor's parser function.

90

91

```typescript { .api }

92

/**

93

* Parser function that converts text to syntax tree

94

* @param document - Input text to parse

95

* @param file - VFile context with metadata

96

* @returns Syntax tree (Node)

97

*/

98

type Parser<Tree extends Node = Node> = (

99

document: string,

100

file: VFile

101

) => Tree;

102

103

// Parser plugin example

104

function parserPlugin() {

105

// 'this' refers to the processor

106

this.parser = (document: string, file: VFile) => {

107

// Parse document and return syntax tree

108

return parsedTree;

109

};

110

}

111

```

112

113

**Usage:**

114

115

```javascript

116

import { unified } from "unified";

117

118

function myParser() {

119

this.parser = (document, file) => {

120

// Custom parsing logic

121

return { type: "root", children: [] };

122

};

123

}

124

125

const processor = unified().use(myParser);

126

const tree = processor.parse("content");

127

```

128

129

### Compiler Plugins

130

131

Plugins that configure the processor's compiler function.

132

133

```typescript { .api }

134

/**

135

* Compiler function that converts syntax tree to output

136

* @param tree - Syntax tree to compile

137

* @param file - VFile context with metadata

138

* @returns Compiled result (string, Uint8Array, or custom type)

139

*/

140

type Compiler<Tree extends Node = Node, Result = Value> = (

141

tree: Tree,

142

file: VFile

143

) => Result;

144

145

// Compiler plugin example

146

function compilerPlugin() {

147

this.compiler = (tree: Node, file: VFile) => {

148

// Compile tree and return result

149

return compiledOutput;

150

};

151

}

152

```

153

154

**Usage:**

155

156

```javascript

157

function myCompiler() {

158

this.compiler = (tree, file) => {

159

// Custom compilation logic

160

return "compiled output";

161

};

162

}

163

164

const processor = unified()

165

.use(myParser)

166

.use(myCompiler);

167

168

const result = processor.processSync("content");

169

```

170

171

### Transformer Plugins

172

173

Plugins that return transformer functions to modify syntax trees.

174

175

```typescript { .api }

176

/**

177

* Transformer function that modifies syntax trees

178

* @param tree - Input syntax tree

179

* @param file - VFile context with metadata

180

* @param next - Callback for async operations (optional)

181

* @returns Modified tree, error, promise, or void

182

*/

183

type Transformer<Input extends Node = Node, Output extends Node = Input> = (

184

tree: Input,

185

file: VFile,

186

next?: TransformCallback<Output>

187

) => Output | Error | Promise<Output> | void;

188

189

// Transformer plugin example

190

function transformerPlugin(options = {}) {

191

return function transformer(tree, file) {

192

// Transform tree based on options

193

// Return modified tree, or void for no changes

194

return modifiedTree;

195

};

196

}

197

```

198

199

**Usage Examples:**

200

201

```javascript

202

// Synchronous transformer

203

function syncTransformer() {

204

return (tree, file) => {

205

// Modify tree synchronously

206

tree.children.forEach(child => {

207

if (child.type === "heading") {

208

child.data = { level: child.depth };

209

}

210

});

211

return tree; // or return nothing for in-place modification

212

};

213

}

214

215

// Asynchronous transformer with promises

216

function asyncTransformer() {

217

return async (tree, file) => {

218

// Async operations

219

const result = await someAsyncOperation(tree);

220

return result;

221

};

222

}

223

224

// Callback-based transformer

225

function callbackTransformer() {

226

return (tree, file, next) => {

227

someAsyncOperation(tree, (error, result) => {

228

next(error, result);

229

});

230

};

231

}

232

233

const processor = unified()

234

.use(someParser)

235

.use(syncTransformer)

236

.use(asyncTransformer)

237

.use(callbackTransformer)

238

.use(someCompiler);

239

```

240

241

## Plugin Configuration

242

243

### Plugin Options

244

245

Plugins can accept configuration options as parameters.

246

247

```javascript

248

function configurablePlugin(options = {}) {

249

const settings = {

250

enabled: true,

251

prefix: "default",

252

...options

253

};

254

255

return function transformer(tree, file) {

256

if (!settings.enabled) return;

257

258

// Use settings in transformation

259

// ...

260

};

261

}

262

263

// Usage

264

processor.use(configurablePlugin, {

265

enabled: true,

266

prefix: "custom"

267

});

268

```

269

270

### Plugin Context

271

272

Plugins have access to the processor instance via `this` context.

273

274

```javascript

275

function contextAwarePlugin() {

276

// Access processor data

277

const existingData = this.data();

278

279

// Set processor data

280

this.data("key", "value");

281

282

// Access other processor properties

283

console.log("Frozen:", this.frozen);

284

285

return function transformer(tree, file) {

286

// Transformer logic

287

};

288

}

289

```

290

291

## Presets

292

293

Collections of plugins and settings that can be shared and reused.

294

295

```typescript { .api }

296

/**

297

* Preset containing plugins and settings

298

*/

299

interface Preset {

300

/** List of plugins to apply */

301

plugins?: PluggableList;

302

/** Settings to merge into processor data */

303

settings?: Settings;

304

}

305

```

306

307

**Usage Examples:**

308

309

```javascript

310

// Define a preset

311

const myPreset = {

312

plugins: [

313

plugin1,

314

[plugin2, { option: "value" }],

315

plugin3

316

],

317

settings: {

318

commonSetting: true,

319

sharedValue: "preset-config"

320

}

321

};

322

323

// Use preset

324

const processor = unified().use(myPreset);

325

326

// Preset with conditional plugins

327

const conditionalPreset = {

328

plugins: [

329

basePlugin,

330

process.env.NODE_ENV === "development" ? debugPlugin : null,

331

[optimizationPlugin, { level: 2 }]

332

].filter(Boolean),

333

settings: {

334

debug: process.env.NODE_ENV === "development"

335

}

336

};

337

```

338

339

## Advanced Plugin Patterns

340

341

### Plugin Factories

342

343

Functions that return plugin configurations based on parameters.

344

345

```javascript

346

function createPlugin(type, options = {}) {

347

if (type === "parser") {

348

return function parserPlugin() {

349

this.parser = (doc, file) => customParse(doc, options);

350

};

351

} else if (type === "transformer") {

352

return function transformerPlugin() {

353

return (tree, file) => customTransform(tree, options);

354

};

355

}

356

}

357

358

// Usage

359

processor

360

.use(createPlugin("parser", { strict: true }))

361

.use(createPlugin("transformer", { optimize: true }));

362

```

363

364

### Conditional Plugins

365

366

Plugins that adapt behavior based on context or configuration.

367

368

```javascript

369

function conditionalPlugin(condition, plugin, options) {

370

return function conditionalWrapper() {

371

if (condition) {

372

return plugin.call(this, options);

373

}

374

// Return nothing - no-op plugin

375

};

376

}

377

378

// Usage

379

processor.use(conditionalPlugin(

380

process.env.NODE_ENV === "production",

381

optimizePlugin,

382

{ level: "aggressive" }

383

));

384

```

385

386

## Error Handling

387

388

### Plugin Errors

389

- Invalid plugin types: `"Expected usable value, not \`{value}\`"`

390

- Empty presets: `"Expected usable value but received an empty preset"`

391

- Frozen processor: `"Cannot call \`use\` on a frozen processor"`

392

393

### Transformer Errors

394

- Returned errors are propagated through the pipeline

395

- Promise rejections are handled appropriately

396

- Callback errors are passed to completion handlers

397

398

### Plugin Validation

399

- Plugins must be functions, objects (presets), or arrays

400

- Preset objects require `plugins` and/or `settings` properties

401

- Plugin arrays must contain valid pluggable values