Skip to content

Commit

Permalink
feat(no-invalid-state-props): modify the rule to accept new xstate@5 …
Browse files Browse the repository at this point in the history
…state props

Newly accepted props: types, output. No longer valid props: activities, tsTypes, schema,
preserveActionOrder, predictableActionArguments, strict, data.
  • Loading branch information
rlaffers committed Aug 14, 2023
1 parent 0637a6f commit 4aecdff
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 59 deletions.
61 changes: 61 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,13 @@ module.exports = {
'no-async-guard': require('./rules/no-async-guard'),
},
configs: {
// Requires: xstate@5
recommended: {
settings: {
xstate: {
version: 5,
},
},
plugins: ['xstate'],
rules: {
'xstate/spawn-usage': 'error',
Expand All @@ -46,7 +52,62 @@ module.exports = {
'xstate/no-async-guard': 'error',
},
},
// Requires: xstate@5
all: {
settings: {
xstate: {
version: 5,
},
},
plugins: ['xstate'],
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/event-names': ['warn', 'macroCase'],
'xstate/state-names': ['warn', 'camelCase'],
'xstate/no-inline-implementation': 'warn',
'xstate/no-auto-forward': 'warn',
'xstate/prefer-always': 'error',
'xstate/no-misplaced-on-transition': 'error',
'xstate/no-invalid-transition-props': 'error',
'xstate/no-invalid-state-props': 'error',
'xstate/no-async-guard': 'error',
},
},
// Requires: xstate@4
recommended_v4: {
settings: {
xstate: {
version: 4,
},
},
plugins: ['xstate'],
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': 'warn',
'xstate/no-misplaced-on-transition': 'error',
'xstate/no-invalid-transition-props': 'error',
'xstate/no-invalid-state-props': 'error',
'xstate/no-async-guard': 'error',
},
},
// Requires: xstate@4
all_v4: {
settings: {
xstate: {
version: 4,
},
},
plugins: ['xstate'],
rules: {
'xstate/spawn-usage': 'error',
Expand Down
146 changes: 98 additions & 48 deletions lib/rules/no-invalid-state-props.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,55 +8,104 @@ const {
hasProperty,
} = require('../utils/predicates')
const { allPass } = require('../utils/combinators')
const getSettings = require('../utils/getSettings')

const validProperties = [
'after',
'always',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'onDone',
'states',
'tags',
'target', // only when type=history
'type',
'data',
'description',
'activities',
]
function isValidStateProperty(property) {
return validProperties.includes(property.key.name)
const validProperties = {
4: [
'after',
'always',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'onDone',
'states',
'tags',
'target', // only when type=history
'type',
'data',
'description',
'activities',
],
5: [
'after',
'always',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'onDone',
'states',
'tags',
'target', // only when type=history
'type',
'description',
'output',
],
}

const validRootProperties = [
'after',
'context',
'description',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'predictableActionArguments',
'preserveActionOrder',
'schema',
'states',
'strict',
'tags',
'target', // only when type=history
'tsTypes',
'type',
]
function isValidRootStateProperty(property) {
return validRootProperties.includes(property.key.name)
function isValidStateProperty(property, version) {
return (
validRootProperties[version] &&
validProperties[version].includes(property.key.name)
)
}

const validRootProperties = {
4: [
'after',
'context',
'description',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'predictableActionArguments',
'preserveActionOrder',
'schema',
'states',
'strict',
'tags',
'target', // only when type=history
'tsTypes',
'type',
],
5: [
'after',
'context',
'description',
'entry',
'exit',
'history', // only when type=history
'id',
'initial',
'invoke',
'meta',
'on',
'states',
'tags',
'target', // only when type=history
'types',
'type',
],
}
function isValidRootStateProperty(property, version) {
return (
validRootProperties[version] &&
validRootProperties[version].includes(property.key.name)
)
}

function hasHistoryTypeProperty(node) {
Expand Down Expand Up @@ -156,6 +205,7 @@ module.exports = {
},

create: function (context) {
const { version } = getSettings(context)
return {
[stateDeclaration]: function (node) {
const isHistoryNode = hasHistoryTypeProperty(node)
Expand Down Expand Up @@ -189,7 +239,7 @@ module.exports = {
return
}

if (!isValidStateProperty(prop)) {
if (!isValidStateProperty(prop, version)) {
context.report({
node: prop,
messageId: 'invalidStateProperty',
Expand Down Expand Up @@ -230,7 +280,7 @@ module.exports = {
return
}

if (!isValidRootStateProperty(prop)) {
if (!isValidRootStateProperty(prop, version)) {
context.report({
node: prop,
messageId: 'invalidRootStateProperty',
Expand Down
19 changes: 19 additions & 0 deletions lib/utils/getSettings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict'

const defaults = {
version: 5
}

const supportedVersions = [4, 5]

module.exports = function getSettings(context) {
const settings = {
...defaults,
...(context.settings ? context.settings.xstate : undefined)
}

if (!supportedVersions.includes(settings.version)) {
throw new Error(`XState version "${settings.version}" is not supported. Check "settings.xstate.version" in your ESLint config.`)
}
return settings
}
Loading

0 comments on commit 4aecdff

Please sign in to comment.