https://github.com/rlaffers/eslint-plugin-xstate
ESLint plugin to check for common mistakes and enforce good practices when using XState.
https://github.com/rlaffers/eslint-plugin-xstate
eslint-plugin fsm hacktoberfest javascript state-machines statecharts xstate
Last synced: 6 months ago
JSON representation
ESLint plugin to check for common mistakes and enforce good practices when using XState.
- Host: GitHub
- URL: https://github.com/rlaffers/eslint-plugin-xstate
- Owner: rlaffers
- License: mit
- Created: 2021-04-10T10:34:17.000Z (about 5 years ago)
- Default Branch: master
- Last Pushed: 2023-12-16T11:36:19.000Z (over 2 years ago)
- Last Synced: 2025-10-20T17:48:43.712Z (8 months ago)
- Topics: eslint-plugin, fsm, hacktoberfest, javascript, state-machines, statecharts, xstate
- Language: JavaScript
- Homepage:
- Size: 889 KB
- Stars: 49
- Watchers: 3
- Forks: 4
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# eslint-plugin-xstate
ESLint plugin to check for common mistakes and enforce good practices when using [XState library](https://xstate.js.org/).
[](https://npmjs.com/package/eslint-plugin-xstate)
[](https://github.com/rlaffers/eslint-plugin-xstate/actions/workflows/release.yml)
[](https://github.com/prettier/prettier)
[](http://makeapullrequest.com)
## Installation
You'll first need to install [ESLint](http://eslint.org):
```
$ npm i eslint --save-dev
```
Next, install `eslint-plugin-xstate`:
```
$ npm install eslint-plugin-xstate --save-dev
```
## Usage
Add `xstate` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix:
```json
{
"plugins": ["xstate"]
}
```
Then configure the rules you want to use under the rules section.
```json
{
"rules": {
"xstate/spawn-usage": "error",
"xstate/no-infinite-loop": "error",
"xstate/no-imperative-action": "error",
"xstate/no-ondone-outside-compound-state": "error",
"xstate/invoke-usage": "error",
"xstate/entry-exit-action": "error",
"xstate/prefer-always": "error",
"xstate/prefer-predictable-action-arguments": "error",
"xstate/no-misplaced-on-transition": "error",
"xstate/no-invalid-transition-props": "error",
"xstate/no-invalid-state-props": "error",
"xstate/no-invalid-conditional-action": "error",
"xstate/no-async-guard": "error",
"xstate/event-names": ["warn", "macroCase"],
"xstate/state-names": ["warn", "camelCase"],
"xstate/no-inline-implementation": "warn",
"xstate/no-auto-forward": "warn",
"xstate/system-id": "warn"
}
}
```
## Shareable Configurations
This plugin exports a `recommended` configuration which checks for common mistakes. To enable this configuration use the `extends` property in your `.eslintrc.js` config file:
```json
{
"extends": ["plugin:xstate/recommended"]
}
```
There is also an `all` configuration which includes every available rule. It enforces both correct usage and best XState practices.
```json
{
"extends": ["plugin:xstate/all"]
}
```
### XState Version
The default shareable configurations are for XState v5. If you use XState version 4, append `_v4` to the name of the configuration you want to use.
```json
{
"extends": ["plugin:xstate/recommended_v4"]
}
```
```json
{
"extends": ["plugin:xstate/all_v4"]
}
```
If you do not use shareable configs, you need to manually specify the XState version in the ESLint config (defaults to 5):
```json
{
"settings": {
"xstate": {
"version": 4
}
}
}
```
## Supported Rules
### Possible Errors
| Rule | Description | Recommended |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------ | ------------------ |
| [spawn-usage](docs/rules/spawn-usage.md) | Enforce correct usage of `spawn`. **Only for XState v4!** | :heavy_check_mark: |
| [no-infinite-loop](docs/rules/no-infinite-loop.md) | Detect infinite loops with eventless transitions | :heavy_check_mark: |
| [no-imperative-action](docs/rules/no-imperative-action.md) | Forbid using action creators imperatively | :heavy_check_mark: |
| [no-ondone-outside-compound-state](docs/rules/no-ondone-outside-compound-state.md) | Forbid onDone transitions on `atomic`, `history` and `final` nodes | :heavy_check_mark: |
| [invoke-usage](docs/rules/invoke-usage.md) | Enforce correct invocation of services | :heavy_check_mark: |
| [entry-exit-action](docs/rules/entry-exit-action.md) | Forbid invalid declarations of entry/exit actions | :heavy_check_mark: |
| [no-misplaced-on-transition](docs/rules/no-misplaced-on-transition.md) | Forbid invalid declarations of `on` transitions | :heavy_check_mark: |
| [no-invalid-transition-props](docs/rules/no-invalid-transition-props.md) | Forbid invalid properties in transition declarations | :heavy_check_mark: |
| [no-invalid-state-props](docs/rules/no-invalid-state-props.md) | Forbid invalid properties in state node declarations | :heavy_check_mark: |
| [no-async-guard](docs/rules/no-async-guard.md) | Forbid asynchronous guard functions | :heavy_check_mark: |
| [no-invalid-conditional-action](docs/rules/no-invalid-conditional-action.md) | Forbid invalid declarations inside the `choose` action creator | :heavy_check_mark: |
### Best Practices
| Rule | Description | Recommended |
| ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------- | ------------------ |
| [no-inline-implementation](docs/rules/no-inline-implementation.md) | Suggest refactoring guards, actions and services into machine options | |
| [prefer-always](docs/rules/prefer-always.md) | Suggest using the `always` syntax for transient (eventless) transitions | :heavy_check_mark: |
| [prefer-predictable-action-arguments](docs/rules/prefer-predictable-action-arguments.md) | Suggest turning on the `predictableActionArguments` option | :heavy_check_mark: |
| [no-auto-forward](docs/rules/no-auto-forward.md) | Forbid auto-forwarding events to invoked services or spawned actors | |
| [system-id](docs/rules/system-id.md) | Suggest using systemId for invoked or spawned actors | |
### Stylistic Issues
| Rule | Description | Recommended |
| ---------------------------------------- | ------------------------------------------------------------------------ | ----------- |
| [event-names](docs/rules/event-names.md) | Suggest consistent formatting of event names | |
| [state-names](docs/rules/state-names.md) | Suggest consistent formatting of state names and prevent confusing names | |
## Comment Directives
By default, the plugin lints only code within the `createMachine` or `Machine` calls. However, if your machine configuration is imported from another file, you will need to enable this plugin's rules by adding a comment directive to the top of the file:
```js
/* eslint-plugin-xstate-include */
// 💡 This machine config will now be linted too.
export const machine = {
initial: 'active',
context: {},
// etc
}
```