Skip to content

Commit

Permalink
Merge branch 'next'
Browse files Browse the repository at this point in the history
  • Loading branch information
rlaffers committed Dec 16, 2023
2 parents d9ed4eb + eef513c commit 9988c15
Show file tree
Hide file tree
Showing 64 changed files with 12,097 additions and 1,083 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@
"env": {
"node": true,
"jest": true
}
},
"parserOptions": {
"ecmaVersion": 2021
},
"plugins": ["node"]
}
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ on:
push:
branches:
- master
- next

permissions:
contents: read # for checkout
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.17.0
20.9.0
62 changes: 55 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@ Then configure the rules you want to use under the rules section.
"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/no-auto-forward": "warn",
"xstate/system-id": "warn"
}
}
```
Expand All @@ -73,13 +76,41 @@ There is also an `all` configuration which includes every available rule. It enf
}
```

### 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` | :heavy_check_mark: |
| [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: |
Expand All @@ -89,18 +120,35 @@ There is also an `all` configuration which includes every available rule. It enf
| [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: |
| [no-auto-forward](docs/rules/no-auto-forward.md) | Forbid auto-forwarding events to invoked services or spawned actors | |
| 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
}
```
2 changes: 1 addition & 1 deletion docs/rules/event-names.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ While the XState library neither enforces nor recommends any particular format f
- camelCase
- regular expression

The default MACRO*CASE for event names is an \_unofficial* convention, typically used within the XState community.
The default MACRO*CASE for event names is an *unofficial\* convention, typically used within the XState community.

Examples of **incorrect** code for this rule:

Expand Down
46 changes: 33 additions & 13 deletions docs/rules/no-async-guard.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

## Rule Details

Async functions return a promise which is a truthy value. Therefore, async guard functions always pass. Transitions guarded by such functions will always be taken as if no `cond` was specified.
Async functions return a promise which is a truthy value. Therefore, async guard functions always pass. Transitions guarded by such functions will always be taken as if no `cond` (XState v4) or `guard` (XState v5) was specified.

Examples of **incorrect** code for this rule:

```javascript
// ❌ async guard in an event transition
// ❌ async guard in an event transition (XState v4)
createMachine({
on: {
EVENT: {
Expand All @@ -19,37 +19,47 @@ createMachine({
},
})

// ❌ async guard in an onDone transition
// ❌ async guard in an event transition (XState v5)
createMachine({
on: {
EVENT: {
guard: async () => {},
target: 'active',
},
},
})

// ❌ async guard in an onDone transition (XState v5)
createMachine({
states: {
active: {
invoke: {
src: 'myService',
onDone: {
cond: async function () {},
guard: async function () {},
target: 'finished',
},
},
},
},
})

// ❌ async guard in the choose action creator
// ❌ async guard in the choose action creator (XState v5)
createMachine({
entry: choose([
{
cond: async () => {},
guard: async () => {},
actions: 'myAction',
},
]),
})

// ❌ async guards in machine options
// ❌ async guards in machine options (XState v5)
createMachine(
{
on: {
EVENT: {
cond: 'myGuard',
guard: 'myGuard',
target: 'active',
},
},
Expand All @@ -67,7 +77,7 @@ createMachine(
Examples of **correct** code for this rule:

```javascript
// ✅ guard is synchronous
// ✅ guard is synchronous (XState v4)
createMachine({
on: {
EVENT: {
Expand All @@ -77,27 +87,37 @@ createMachine({
},
})

// ✅ guard is synchronous
// ✅ guard is synchronous (XState v5)
createMachine({
on: {
EVENT: {
guard: () => {},
target: 'active',
},
},
})

// ✅ guard is synchronous (XState v5)
createMachine({
states: {
active: {
invoke: {
src: 'myService',
onDone: {
cond: function () {},
guard: function () {},
target: 'finished',
},
},
},
},
})

// ✅ all guards in machine options are synchronous
// ✅ all guards in machine options are synchronous (XState v5)
createMachine(
{
on: {
EVENT: {
cond: 'myGuard',
guard: 'myGuard',
target: 'active',
},
},
Expand Down
4 changes: 3 additions & 1 deletion docs/rules/no-auto-forward.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Prefer sending events explicitly to child actors/services.

Avoid blindly forwarding all events to invoked services or spawned actors - it may lead to unexpected behavior or infinite loops. The official documentation [suggests sending events explicitly](https://xstate.js.org/docs/guides/communication.html#the-invoke-property) with the [`forwardTo`](https://xstate.js.org/docs/guides/actions.html#forward-to-action) or `send` action creators.

**XState v5 removed the `autoForward` option. This rule will report errors if `autoForward` is used with XState v5.**

Examples of **incorrect** code for this rule:

```javascript
Expand Down Expand Up @@ -33,7 +35,7 @@ createMachine({
})
```

Examples of **correct** code for this rule:
Examples of **correct** code for this rule (XState v4 only):

```javascript
// ✅ no auto-forward
Expand Down
Loading

0 comments on commit 9988c15

Please sign in to comment.