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