Skip to content

Commit

Permalink
fixup! [New] Symmetric useState hook variable names
Browse files Browse the repository at this point in the history
  • Loading branch information
duncanbeevers committed Apr 21, 2021
1 parent 99fd001 commit 2bfe443
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 34 deletions.
14 changes: 14 additions & 0 deletions docs/rules/hook-use-state.md
Expand Up @@ -9,15 +9,29 @@ This rule checks whether the value and setter variables destructured from a `Rea
Examples of **incorrect** code for this rule:

```js
import React from 'react';
const useStateResult = React.useState();
```

```js
import { useState } from 'react';
const useStateResult = useState();
```

```js
import React from 'react';
const [color, updateColor] = React.useState();
```

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


```js
import { useState } from 'react';
const [color, setColor] = useState();
```

```js
import React from 'react';
const [color, setColor] = React.useState();
```
26 changes: 23 additions & 3 deletions lib/rules/hook-use-state.js
Expand Up @@ -32,19 +32,24 @@ module.exports = {
},

create(context) {
let isReactImported = false;
let reactUseStateLocal;

return {
CallExpression(node) {
const isReactUseStateCall = (
node.callee.type === 'MemberExpression'
isReactImported
&& node.callee.type === 'MemberExpression'
&& node.callee.object.type === 'Identifier'
&& node.callee.object.name === 'React'
&& node.callee.property.type === 'Identifier'
&& node.callee.property.name === 'useState'
);

const isUseStateCall = (
node.callee.type === 'Identifier'
&& node.callee.name === 'useState'
reactUseStateLocal
&& node.callee.type === 'Identifier'
&& node.callee.name === reactUseStateLocal
);

// Ignore unless this is a useState() or React.useState() call.
Expand Down Expand Up @@ -95,6 +100,21 @@ module.exports = {
) : undefined
});
}
},
ImportDeclaration(node) {
isReactImported = node.source.type === 'Literal' && node.source.value === 'react';
const reactUseStateSpecifier = isReactImported
? node.specifiers.find(
(specifier) => (
specifier.type === 'ImportSpecifier'
&& specifier.imported.name === 'useState'
)
)
: undefined;

reactUseStateLocal = reactUseStateSpecifier
? reactUseStateSpecifier.local.name
: undefined;
}
};
}
Expand Down
110 changes: 79 additions & 31 deletions tests/lib/rules/hook-use-state.js
Expand Up @@ -27,142 +27,190 @@ const ruleTester = new RuleTester({
const tests = {
valid: [
{
code: 'const [color, setColor] = useState()'
code: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [color, setColor] = useState(\'#ffffff\')'
code: `import { useState } from 'react';
const [color, setColor] = useState('#ffffff')`
},
{
code: 'const [color, setColor] = React.useState()'
code: `import { useState } from 'react';
const [color, setColor] = React.useState()`
},
{
code: 'const [color1, setColor1] = useState()'
code: `import { useState } from 'react';
const [color1, setColor1] = useState()`
},
{
code: 'const [color, setColor] = useState<string>()',
code: 'const result = useState()'
},
{
code: `import { useRef } from 'react';
const result = useState()`
},
{
code: 'const result = React.useState()'
},
{
code: `import { useState } from 'react';
const [color, setColor] = useState<string>()`,
parser: parsers.TYPESCRIPT_ESLINT
},
{
code: 'const [color, setColor] = useState<string>(\'#ffffff\')',
code: `import { useState } from 'react';
const [color, setColor] = useState<string>('#ffffff')`,
parser: parsers.TYPESCRIPT_ESLINT
}
].concat(parsers.TS([
{
code: 'const [color, setColor] = useState<string>()',
code: `import { useState } from 'react';
const [color, setColor] = useState<string>()`,
parser: parsers['@TYPESCRIPT_ESLINT']
},
{
code: 'const [color, setColor] = useState<string>(\'#ffffff\')',
code: `import { useState } from 'react';
const [color, setColor] = useState<string>('#ffffff')`,
parser: parsers['@TYPESCRIPT_ESLINT']
}
])
),
invalid: [
{
code: 'useState()',
code: `import { useState } from 'react';
useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: `import { useState as useStateAlternativeName } from 'react';
useStateAlternativeName()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const result = useState()',
code: `import { useState } from 'react';
const result = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const result = React.useState()',
code: `import { useState } from 'react';
const result = React.useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [, , extra1] = useState()',
code: `import { useState } from 'react';
const [, , extra1] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [, setColor] = useState()',
code: `import { useState } from 'react';
const [, setColor] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const { color } = useState()',
code: `import { useState } from 'react';
const { color } = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [] = useState()',
code: `import { useState } from 'react';
const [] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [, , , ,] = useState()',
code: `import { useState } from 'react';
const [, , , ,] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [color] = useState()',
code: `import { useState } from 'react';
const [color] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState()'
output: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [color, , extra1] = useState()',
code: `import { useState } from 'react';
const [color, , extra1] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState()'
output: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [color, setColor, extra1, extra2, extra3] = useState()',
code: `import { useState } from 'react';
const [color, setColor, extra1, extra2, extra3] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState()'
output: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [, makeColor] = useState()',
code: `import { useState } from 'react';
const [, makeColor] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}]
},
{
code: 'const [color, setFlavor, extraneous] = useState()',
code: `import { useState } from 'react';
const [color, setFlavor, extraneous] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState()'
output: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [color, setFlavor] = useState()',
code: `import { useState } from 'react';
const [color, setFlavor] = useState()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState()'
output: `import { useState } from 'react';
const [color, setColor] = useState()`
},
{
code: 'const [color, setFlavor] = useState<string>()',
code: `import { useState } from 'react';
const [color, setFlavor] = useState<string>()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState<string>()',
output: `import { useState } from 'react';
const [color, setColor] = useState<string>()`,
parser: parsers.TYPESCRIPT_ESLINT
}
].concat(
parsers.TS([
{
code: 'const [color, setFlavor] = useState<string>()',
code: `import { useState } from 'react';
const [color, setFlavor] = useState<string>()`,
errors: [{
message: 'setState call is not destructured into value + setter pair'
}],
output: 'const [color, setColor] = useState<string>()',
output: `import { useState } from 'react';
const [color, setColor] = useState<string>()`,
parser: parsers['@TYPESCRIPT_ESLINT']
}
])
Expand Down

0 comments on commit 2bfe443

Please sign in to comment.