Parse, inspect, transform, and serialize content through syntax trees
—
Comprehensive plugin architecture supporting parsers, transformers, compilers, and presets with flexible configuration management and reconfiguration capabilities.
Configures the processor with plugins, presets, or plugin lists.
/**
* Configure processor with plugins, presets, or plugin lists
* @param value - Plugin, preset, or list of plugins
* @param parameters - Plugin options and parameters
* @returns Processor instance for chaining
* @throws Error on frozen processor or invalid plugin types
*/
use(value: Pluggable, ...parameters: unknown[]): Processor;
// Overloaded signatures for specific types
use(plugin: Plugin, ...parameters: unknown[]): Processor;
use(preset: Preset): Processor;
use(list: PluggableList): Processor;
use(value: null | undefined): Processor; // No-opUsage Examples:
import { unified } from "unified";
const processor = unified()
// Single plugin
.use(somePlugin)
// Plugin with options
.use(somePlugin, { option: "value" })
// Plugin array
.use([plugin1, plugin2])
// Plugin tuples with options
.use([
[plugin1, { setting: true }],
[plugin2, "parameter", { more: "options" }]
])
// Preset
.use({
plugins: [plugin1, plugin2],
settings: { key: "value" }
});Later calls to use() with the same plugin will merge or replace configuration.
const processor = unified()
// Initial configuration
.use(somePlugin, { x: true, y: true })
// Reconfigure same plugin (merges objects)
.use(somePlugin, { y: false, z: true });
// Result: { x: true, y: false, z: true }
// Non-object parameters are replaced
processor
.use(somePlugin, "initial")
.use(somePlugin, "replaced"); // "initial" is replaced with "replaced"Control plugin activation with boolean parameters.
const processor = unified()
.use(somePlugin, false) // Disable plugin
.use(somePlugin, true) // Enable with no options
.use(somePlugin, {}); // Enable with empty optionsPlugins that configure the processor's parser function.
/**
* Parser function that converts text to syntax tree
* @param document - Input text to parse
* @param file - VFile context with metadata
* @returns Syntax tree (Node)
*/
type Parser<Tree extends Node = Node> = (
document: string,
file: VFile
) => Tree;
// Parser plugin example
function parserPlugin() {
// 'this' refers to the processor
this.parser = (document: string, file: VFile) => {
// Parse document and return syntax tree
return parsedTree;
};
}Usage:
import { unified } from "unified";
function myParser() {
this.parser = (document, file) => {
// Custom parsing logic
return { type: "root", children: [] };
};
}
const processor = unified().use(myParser);
const tree = processor.parse("content");Plugins that configure the processor's compiler function.
/**
* Compiler function that converts syntax tree to output
* @param tree - Syntax tree to compile
* @param file - VFile context with metadata
* @returns Compiled result (string, Uint8Array, or custom type)
*/
type Compiler<Tree extends Node = Node, Result = Value> = (
tree: Tree,
file: VFile
) => Result;
// Compiler plugin example
function compilerPlugin() {
this.compiler = (tree: Node, file: VFile) => {
// Compile tree and return result
return compiledOutput;
};
}Usage:
function myCompiler() {
this.compiler = (tree, file) => {
// Custom compilation logic
return "compiled output";
};
}
const processor = unified()
.use(myParser)
.use(myCompiler);
const result = processor.processSync("content");Plugins that return transformer functions to modify syntax trees.
/**
* Transformer function that modifies syntax trees
* @param tree - Input syntax tree
* @param file - VFile context with metadata
* @param next - Callback for async operations (optional)
* @returns Modified tree, error, promise, or void
*/
type Transformer<Input extends Node = Node, Output extends Node = Input> = (
tree: Input,
file: VFile,
next?: TransformCallback<Output>
) => Output | Error | Promise<Output> | void;
// Transformer plugin example
function transformerPlugin(options = {}) {
return function transformer(tree, file) {
// Transform tree based on options
// Return modified tree, or void for no changes
return modifiedTree;
};
}Usage Examples:
// Synchronous transformer
function syncTransformer() {
return (tree, file) => {
// Modify tree synchronously
tree.children.forEach(child => {
if (child.type === "heading") {
child.data = { level: child.depth };
}
});
return tree; // or return nothing for in-place modification
};
}
// Asynchronous transformer with promises
function asyncTransformer() {
return async (tree, file) => {
// Async operations
const result = await someAsyncOperation(tree);
return result;
};
}
// Callback-based transformer
function callbackTransformer() {
return (tree, file, next) => {
someAsyncOperation(tree, (error, result) => {
next(error, result);
});
};
}
const processor = unified()
.use(someParser)
.use(syncTransformer)
.use(asyncTransformer)
.use(callbackTransformer)
.use(someCompiler);Plugins can accept configuration options as parameters.
function configurablePlugin(options = {}) {
const settings = {
enabled: true,
prefix: "default",
...options
};
return function transformer(tree, file) {
if (!settings.enabled) return;
// Use settings in transformation
// ...
};
}
// Usage
processor.use(configurablePlugin, {
enabled: true,
prefix: "custom"
});Plugins have access to the processor instance via this context.
function contextAwarePlugin() {
// Access processor data
const existingData = this.data();
// Set processor data
this.data("key", "value");
// Access other processor properties
console.log("Frozen:", this.frozen);
return function transformer(tree, file) {
// Transformer logic
};
}Collections of plugins and settings that can be shared and reused.
/**
* Preset containing plugins and settings
*/
interface Preset {
/** List of plugins to apply */
plugins?: PluggableList;
/** Settings to merge into processor data */
settings?: Settings;
}Usage Examples:
// Define a preset
const myPreset = {
plugins: [
plugin1,
[plugin2, { option: "value" }],
plugin3
],
settings: {
commonSetting: true,
sharedValue: "preset-config"
}
};
// Use preset
const processor = unified().use(myPreset);
// Preset with conditional plugins
const conditionalPreset = {
plugins: [
basePlugin,
process.env.NODE_ENV === "development" ? debugPlugin : null,
[optimizationPlugin, { level: 2 }]
].filter(Boolean),
settings: {
debug: process.env.NODE_ENV === "development"
}
};Functions that return plugin configurations based on parameters.
function createPlugin(type, options = {}) {
if (type === "parser") {
return function parserPlugin() {
this.parser = (doc, file) => customParse(doc, options);
};
} else if (type === "transformer") {
return function transformerPlugin() {
return (tree, file) => customTransform(tree, options);
};
}
}
// Usage
processor
.use(createPlugin("parser", { strict: true }))
.use(createPlugin("transformer", { optimize: true }));Plugins that adapt behavior based on context or configuration.
function conditionalPlugin(condition, plugin, options) {
return function conditionalWrapper() {
if (condition) {
return plugin.call(this, options);
}
// Return nothing - no-op plugin
};
}
// Usage
processor.use(conditionalPlugin(
process.env.NODE_ENV === "production",
optimizePlugin,
{ level: "aggressive" }
));"Expected usable value, not \{value}`"`"Expected usable value but received an empty preset""Cannot call \use` on a frozen processor"`plugins and/or settings propertiesInstall with Tessl CLI
npx tessl i tessl/npm-unified