Skip to main content

Plugin

Each plugin is an npm module with a name in the format of textlint-plugin-<plugin-name>. For example, @textlint/textlint-plugin-markdown is a textlint plugin.

Processor

Plugin has a Processor that is required.

// index.js
export default {
Processor: require("./YourProcessor")
};

Processor class defined pre/post process of the file and available file types.

textlint support .txt and .md by default. These are implemented as Processor plugin.

Processor class example code:

// TextProcessor.js
import { parse } from "txt-to-ast";
export default class TextProcessor {
constructor(options = {}) {
this.options = options;
// support "extension" option
this.extensions = options.extensions ? options.extensions : [];
}
// available ".ext" list
// user can add own custom extension as "extensions" option
availableExtensions() {
return [".txt", ".text"].concat(this.extensions);
}
// define pre/post process
// in other words, parse and generate process
processor(ext) {
return {
preProcess(text, filePath) {
// parsed result is an AST object
// AST is consist of TxtNode
// https://github.com/textlint/textlint/blob/master/docs/txtnode.md
return parse(text);
},
postProcess(messages, filePath) {
return {
messages,
filePath: filePath ? filePath : "<text>"
};
}
};
}
}

Processor class should implement these methods.

availableExtensions(): string[]

It should return supported extension name list.

Notes:

textlint versions 10 and above support static availableExtensions(): string[]. The static method is deprecated in textlint@11. you should implement availableExtensions() method as instance method.

processor(ext)

processor() method should return an object that have preProcess and postProcess method.

preProcess(text, filePath)

preProcess method should return TxtParentNode object or { text: string, ast: TxtParentNode } object. Also, preProcess method can return Promise<TxtParentNode> | Promise<{ text: string, ast: TxtParentNode }>. If you want to parse text asynchronous, please return an Promise object.

TxtParentNode object is an Abstract Syntax Tree (AST) of the text.

You should check the AST using @textlint/ast-tester.

import { test, isTxtAST } from "@textlint/ast-tester";
// your implement
import yourParse from "your-parser";
// recommenced: test much pattern test
const AST = yourParse("This is text");

// Validate AST
test(AST); // if the AST is invalid, then throw Error

isTxtAST(AST); // true or false

If you want to know TxtParentNode, see TxtAST interface documents.

text format

Target file(text format) -> AST(by your plugin) for Target file

If your plugin handle text format, you can just return a TxtParentNode object.

class ExampleProcessor {
availableExtensions() {
return [".example"];
}

processor() {
return {
preProcess() {
return AST_OBJECT;
},
postProcess(messages, filePath) {
return {
filePath: filePath || "<example>",
messages
};
}
};
}
}
binary format

Target file(binary format) -> Intermediate text(by your plugin) -> AST(by your plugin) for Intermediate text

If your plugin handle intermediate text, you should return a { text: string, ast: TxtParentNode } object.

textlint can not handle a binary format, and your plugin should return intermediate text for your AST.

class BinaryExampleProcessor {
availableExtensions() {
return [".binary-example"];
}

processor() {
return {
preProcess() {
return {
text: PASUDUE_TEXT,
ast: AST_OBJECT
};
},
postProcess(messages, filePath) {
return {
filePath: filePath || "<example>",
messages
};
}
};
}
}

For more details, see https://github.com/textlint/textlint/issues/649

postProcess(messages, filePath)

postProcess method should return { messages, filePath }. Also, postProcess method can return Promise<{ messages, filePath }>.

filePath argument may be undefined when text was input from stdin.

Plugin configuration

You can use Processor plugin in the same way a plugin.

{
"plugins": [
"<Processor Plugin>"
]
}

options

You can pass options to your plugin from .textlintrc.json.

{
"plugins": {
"pluginName": processorOption
}
}

You can receive the processorOption via constructor arguments.

export default class YourProcessor {
constructor(options) {
this.options = options; // <= processorOption!
}
// ...
}

📝 Processor's option value is {} (empty object) by default. If not set plugin's option in .textlintrc.json, textlint pass {} as options.

export default class YourProcessor {
constructor(options) {
this.options = options; // {}
}
// ...
}

Publishing

If you want to publish your textlint plugin, see following documents.

Package name convention

textlint plugin package naming should have textlint-plugin- prefix.

  • textlint-plugin-<name>
  • @scope/textlint-plugin-<name>

Example: @textlint/textlint-plugin-markdown

textlint user use it by setting following:

{
"plugins": {
"@textlint/markdown": true
}
}

Also, textlint user can set options to the plugin.

{
"plugins": {
"@textlint/markdown": {
"extensions": [".custom-ext"]
}
}
}

Keywords

You should add textlintplugin to npm's keywords

{
"name": "textlint-plugin-format-name",
"keywords": [
"textlintplugin"
]
}

Plugin Example

(limited) XML plugin

For more plugins, See Processor Plugin List.

Built-in plugin

textlint has built-in plugins