<commit_before>---
id: rule
title: Creating Rules
---

textlint's AST(Abstract Syntax Tree) is defined at the page.

- [txtnode.md](./txtnode.md)
    - If you want to know AST of a text, use [Online Parsing Demo](./txtnode.md#online-parsing-demo)

Each rule are represented by an object with some properties.
The properties are equivalent to AST node types from TxtNode.

The basic source code format for a rule is:

```js
/**
 * @param {RuleContext} context
 */
export default function (context) {
    // rule object
    return {
        [context.Syntax.Document](node) {},

        [context.Syntax.Paragraph](node) {},

        [context.Syntax.Str](node) {
            const text = context.getSource(node);
            if (/found wrong use-case/.test(text)) {
                // report error
                context.report(node, new context.RuleError("Found wrong"));
            }
        },

        [context.Syntax.Break](node) {}
    };
}
```

If your rule wants to know when an `Str` node is found in the AST, then add a method called `context.Syntax.Str`, such as:

```js
// ES2015+
export default function (context) {
    const { Syntax } = context;
    return {
        [Syntax.Str](node) {
            // this method is called
        }
    };
}
// or ES5
module.exports = function (context) {
    const exports = {};
    exports[context.Syntax.Str] = function (node) {
        // this method is called
    };
    return exports;
};
```

By default, the method matching a node name is called during the traversal when the node is first encountered(This is called **Enter**), on the way down the AST.

You can also specify to visit the node on the other side of the traversal, as it comes back up the tree(This is called **Leave**), but adding `Exit` to the end of the node type, such as:

```js
export default function (context) {
    return {
        // Str:exit
        [context.Syntax.StrExit](node) {
            // this method is called
        }
    };
}
```

Note: textlint@11.1.1+ support `*Exit` constant value like `Syntax.DocumentExit`.
In textlint@11.1.0<=, you had to write `[Syntax.Document + ":exit"]`.

[visualize-txt-traverse](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse") help you better understand this traversing.

[![gif visualize-txt-traverse](https://gyazo.com/155c68f0f9ff35e0a549d655a787c01e.gif)](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse")

[AST explorer for textlint](https://textlint.github.io/astexplorer/ "AST explorer for textlint") help you better understand [TxtAST](./txtnode.md).

[![ast-explorer fork](assets/ast-explorer.png)](https://textlint.github.io/astexplorer/)


**Related information:**

- [azu/visualize-txt-traverse](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse")
- [packages/@textlint/ast-traverse](https://github.com/textlint/textlint/tree/master/packages/@textlint/ast-traverse "packages/@textlint/ast-traverse")
- [estools/estraverse](https://github.com/estools/estraverse "estools/estraverse")

## RuleContext API

RuleContext object has following property:

- `Syntax.*` 
    - This is const values of [TxtNode type](./txtnode.md).
    - e.g.) `context.Syntax.Str`
    - [packages/@textlint/ast-node-types/src/index.ts](https://github.com/textlint/textlint/blob/master/packages/%40textlint/ast-node-types/src/index.ts)
- `report(<node>, <ruleError>): void`
    - This method is a method that reports a message from one of the rules.
    - e.g.) `context.report(node, new context.RuleError("found rule error"));`
- `getSource(<node>): string`
    - This method is a method gets the source code for the given node.
    - e.g.) `context.getSource(node); // => "text"`
- `getFilePath(): string | undefined`
    - This method return file path that is linting target.
    - e.g.) `context.getFilePath(): // => /path/to/file.md or undefined` 
- `getConfigBaseDir(): string | undefined`
    - New in [9.0.0](https://github.com/textlint/textlint/releases/tag/textlint%409.0.0 "9.0.0")
    - Available [@textlint/get-config-base-dir](https://github.com/textlint/get-config-base-dir "@textlint/get-config-base-dir") polyfill for backward compatibility
    - This method return config base directory path that is the place of `.textlintrc`
    - e.g.) `/path/to/dir/.textlintrc`
    - `getConfigBaseDir()` return `"/path/to/dir/"`.
- `fixer`
    - This is creator object of fix command.
    - See [How to create Fixable Rule?](./rule-fixable.md) for more details
- `locator`
    - New in [12.2.0](https://github.com/textlint/textlint/releases/tag/v12.2.0)
    - This utility provide range methods for `padding` property to `RuleError`
    - See [RuleError](#RuleError) for more details

## RuleError

`RuleError` is an Error object for reporting.
Use it with `report` function.

- `report(node, new RuleError(<message>))`
  - report new error
  - textlint show the `<mesage>` against `node`'s range. 
- `report(node, new RuleError(<message>, { padding }))`
  - report new error with `padding`.
  - textlint show the `<mesage>` against `node`'s range + `padding`.
  - You can control correct error range by `padding` property of `RuleError`

Example: report the `Str` node that is typo.

```
This is typo.
^^^^^^^^^^^^^
      |
  Found a typo.
```

```js
export default function (context) {
    const { Syntax, report, RuleError, getSource } = context;
    return {
        [Syntax.Str](node) {
            // get source code of this `node`
            const text = getSource(node);
            if (/typo/.test(text)) {
                // report error
                report(node, new RuleError("Found a typo"));
            }
        }
    };
}
```

Example: report `typo` string that is typo using `padding`

```
This is typo.
        ^^^^
          |
        Found a typo.
```

```js
export default function (context) {
    const { Syntax, report, RuleError, getSource, locator } = context;
    return {
        [Syntax.Str](node) {
            // get source code of this `node`
            const text = getSource(node);
            const match = text.match(/typo/);
            if (match) {
                // report error with padding
                // node's start + padding's range
                // As a result, report the error that is [node.range[0] + typo.index, node.range[1] + typo.index + type.length]
                report(
                    node,
                    new RuleError("Found a typo", {
                        padding: locator.range([match.index, match.index + match[0].length])
                    })
                );
            }
        }
    };
}
```

The `context.locator` object has the following methods:

-`locator.at(index)` - return padding value that is relative index from node's start index.
  - The `index` value is 0-based value
  - This method is alias to `locator.range([index, index + 1])`
-`locator.range([startIndex, endIndex])` - return padding value that is relative range from node's start index
  - Each `index` value is 0-based value
-`locator.loc({ start: { line, column }, end: { line, column })` - return padding value that is relative location from node's start loc
  - :memo: This `line` and `column` is relative value. It is not absolute value. So, These are 0-based value.

:memo: `context.locator` object in introduced in [v12.2.0](https://github.com/textlint/textlint/releases/tag/v12.2.0).

```ts
export type TextlintRulePaddingLocator = {
    /**
     * at's index is 0-based value.
     * It is alias to `range([index, index + 1])`
     * @param index relative index from node's start position
     */
    at(index: number): TextlintRuleErrorPaddingLocation;
    /**<commit_msg>Update rule.md<commit_after>---
id: rule
title: Creating Rules
---

textlint's AST(Abstract Syntax Tree) is defined at the page.

- [txtnode.md](./txtnode.md)
    - If you want to know AST of a text, use [Online Parsing Demo](./txtnode.md#online-parsing-demo)

Each rule are represented by an object with some properties.
The properties are equivalent to AST node types from TxtNode.

The basic source code format for a rule is:

```js
/**
 * @param {RuleContext} context
 */
export default function (context) {
    // rule object
    return {
        [context.Syntax.Document](node) {},

        [context.Syntax.Paragraph](node) {},

        [context.Syntax.Str](node) {
            const text = context.getSource(node);
            if (/found wrong use-case/.test(text)) {
                // report error
                context.report(node, new context.RuleError("Found wrong"));
            }
        },

        [context.Syntax.Break](node) {}
    };
}
```

If your rule wants to know when an `Str` node is found in the AST, then add a method called `context.Syntax.Str`, such as:

```js
// ES2015+
export default function (context) {
    const { Syntax } = context;
    return {
        [Syntax.Str](node) {
            // this method is called
        }
    };
}
// or ES5
module.exports = function (context) {
    const exports = {};
    exports[context.Syntax.Str] = function (node) {
        // this method is called
    };
    return exports;
};
```

By default, the method matching a node name is called during the traversal when the node is first encountered(This is called **Enter**), on the way down the AST.

You can also specify to visit the node on the other side of the traversal, as it comes back up the tree(This is called **Leave**), but adding `Exit` to the end of the node type, such as:

```js
export default function (context) {
    return {
        // Str:exit
        [context.Syntax.StrExit](node) {
            // this method is called
        }
    };
}
```

Note: textlint@11.1.1+ support `*Exit` constant value like `Syntax.DocumentExit`.
In textlint@11.1.0<=, you had to write `[Syntax.Document + ":exit"]`.

[visualize-txt-traverse](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse") help you better understand this traversing.

[![gif visualize-txt-traverse](https://gyazo.com/155c68f0f9ff35e0a549d655a787c01e.gif)](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse")

[AST explorer for textlint](https://textlint.github.io/astexplorer/ "AST explorer for textlint") help you better understand [TxtAST](./txtnode.md).

[![ast-explorer fork](assets/ast-explorer.png)](https://textlint.github.io/astexplorer/)


**Related information:**

- [azu/visualize-txt-traverse](https://github.com/azu/visualize-txt-traverse "azu/visualize-txt-traverse")
- [packages/@textlint/ast-traverse](https://github.com/textlint/textlint/tree/master/packages/@textlint/ast-traverse "packages/@textlint/ast-traverse")
- [estools/estraverse](https://github.com/estools/estraverse "estools/estraverse")

## RuleContext API

RuleContext object has following property:

- `Syntax.*` 
    - This is const values of [TxtNode type](./txtnode.md).
    - e.g.) `context.Syntax.Str`
    - [packages/@textlint/ast-node-types/src/index.ts](https://github.com/textlint/textlint/blob/master/packages/%40textlint/ast-node-types/src/index.ts)
- `report(<node>, <ruleError>): void`
    - This method is a method that reports a message from one of the rules.
    - e.g.) `context.report(node, new context.RuleError("found rule error"));`
- `getSource(<node>): string`
    - This method is a method gets the source code for the given node.
    - e.g.) `context.getSource(node); // => "text"`
- `getFilePath(): string | undefined`
    - This method return file path that is linting target.
    - e.g.) `context.getFilePath(): // => /path/to/file.md or undefined` 
- `getConfigBaseDir(): string | undefined`
    - New in [9.0.0](https://github.com/textlint/textlint/releases/tag/textlint%409.0.0 "9.0.0")
    - Available [@textlint/get-config-base-dir](https://github.com/textlint/get-config-base-dir "@textlint/get-config-base-dir") polyfill for backward compatibility
    - This method return config base directory path that is the place of `.textlintrc`
    - e.g.) `/path/to/dir/.textlintrc`
    - `getConfigBaseDir()` return `"/path/to/dir/"`.
- `fixer`
    - This is creator object of fix command.
    - See [How to create Fixable Rule?](./rule-fixable.md) for more details
- `locator`
    - New in [12.2.0](https://github.com/textlint/textlint/releases/tag/v12.2.0)
    - This utility provide range methods for `padding` property to `RuleError`
    - See [RuleError](#RuleError) for more details

## RuleError

`RuleError` is an Error object for reporting.
Use it with `report` function.

- `report(node, new RuleError(<message>))`
  - report new error
  - textlint show the `<mesage>` against `node`'s range. 
- `report(node, new RuleError(<message>, { padding }))`
  - report new error with `padding`.
  - textlint show the `<mesage>` against `node`'s range + `padding`.
  - You can control correct error range by `padding` property of `RuleError`

Example: report the `Str` node that is typo.

```
This is typo.
^^^^^^^^^^^^^
      |
  Found a typo.
```

```js
export default function (context) {
    const { Syntax, report, RuleError, getSource } = context;
    return {
        [Syntax.Str](node) {
            // get source code of this `node`
            const text = getSource(node);
            if (/typo/.test(text)) {
                // report error
                report(node, new RuleError("Found a typo"));
            }
        }
    };
}
```

Example: report `typo` string that is typo using `padding`

```
This is typo.
        ^^^^
          |
        Found a typo.
```

```js
export default function (context) {
    const { Syntax, report, RuleError, getSource, locator } = context;
    return {
        [Syntax.Str](node) {
            // get source code of this `node`
            const text = getSource(node);
            const match = text.match(/typo/);
            if (match) {
                // report error with padding
                // node's start + padding's range
                // As a result, report the error that is [node.range[0] + typo.index, node.range[1] + typo.index + type.length]
                report(
                    node,
                    new RuleError("Found a typo", {
                        padding: locator.range([match.index, match.index + match[0].length])
                    })
                );
            }
        }
    };
}
```

The `context.locator` object has the following methods:

- `locator.at(index)` - return padding value that is relative index from node's start index.
  - The `index` value is 0-based value
  - This method is alias to `locator.range([index, index + 1])`
- `locator.range([startIndex, endIndex])` - return padding value that is relative range from node's start index
  - Each `index` value is 0-based value
- `locator.loc({ start: { line, column }, end: { line, column })` - return padding value that is relative location from node's start loc
  - :memo: This `line` and `column` is relative value. It is not absolute value. So, These are 0-based value.

:memo: `context.locator` object in introduced in [v12.2.0](https://github.com/textlint/textlint/releases/tag/v12.2.0).

```ts
export type TextlintRulePaddingLocator = {
    /**
     * at's index is 0-based value.
     * It is alias to `range([index, index + 1])`
     * @param index relative index from node's start position
     */
    at(index: number): TextlintRuleErrorPaddingLocation;
    /**
{'fraction_non_alphanumeric': 0.14011952708847603, 'fraction_numerical': 0.009354293880732754, 'mean_word_length': 2.7421001458434615, 'pattern_counts': {'":': 2, '<': 19, '<?xml version=': 0, '>': 21, 'https://': 26, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4685760', 'n_tokens_mistral': 4890, 'n_tokens_neox': 4655, 'n_words': 1413}