Skip to content

Commit

Permalink
Merge branch 'release/0.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
hiukky committed Oct 11, 2021
2 parents cd7dc76 + 71ed259 commit f706de1
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 26 deletions.
53 changes: 29 additions & 24 deletions lib/rules/sort/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ module.exports = {

if (isExportableDeclaration()) {
declarations =
node['declaration']['declarations']?.[0]['init'] ||
node['declaration']?.['declarations']?.[0]['init'] ||
node['declaration']
} else {
declarations = node['declarations']?.[0]['init'] || node
}

return declarations['body']?.['body']
return declarations?.['body']?.['body']
})
.filter(Boolean)
.forEach((declarations: Node[]) => {
let nodes: Node[] = []

declarations.forEach(node => {
declarations?.forEach(node => {
if (node['type'] === 'ExpressionStatement') {
nodes.push(node['expression'])
}
Expand All @@ -85,46 +85,51 @@ module.exports = {
})

const hooks = nodes
.map(
?.map(
({ type, callee, init }) =>
(type === 'CallExpression'
? [type, callee]
: type === 'VariableDeclarator'
? [type, init]
: []) as [string, Node],
: []) as [Node['type'], Node],
)
.filter(node => node.length)
.map(([type, declaration]) => {
const getHookName = (): string =>
type === 'CallExpression'
? declaration.name
: declaration.callee.name

const getHookNode = (): Node =>
type === 'CallExpression' ? declaration : declaration.callee

return [getHookName(), getHookNode()] as [string, Node]
switch (type) {
case 'MemberExpression':
return declaration.property

case 'CallExpression':
return declaration.type === 'MemberExpression'
? declaration.property
: declaration.callee || declaration

case 'VariableDeclarator':
default:
return declaration.callee.property || declaration.callee
}
})
.filter(Boolean)
.filter(
([name]) =>
name?.slice(0, 3) === 'use' && groups.includes(name),
hook =>
hook.name.slice(0, 3) === 'use' && groups.includes(hook.name),
)

const correctOrdering: [string, Node][] = [...hooks].sort(
(a, b) => groups.indexOf(a[0]) - groups.indexOf(b[0]),
const correctOrdering: Node[] = [...hooks].sort(
(a, b) => groups.indexOf(a.name) - groups.indexOf(b.name),
)

hooks.forEach((hook, index) => {
hooks.forEach((hook, idx) => {
const noMatching = (): boolean =>
correctOrdering.length > 1 &&
correctOrdering[index][0] !== hook[0]
correctOrdering[idx].name !== hook.name

if (noMatching()) {
ctx.report(
hook[1],
`Non-matching declaration order. ${hook[0]} comes ${
!index ? 'after' : 'before'
} ${correctOrdering[index][0]}.`,
hook,
`Non-matching declaration order. ${hook.name} comes ${
!idx ? 'after' : 'before'
} ${correctOrdering[idx].name}.`,
)
}
})
Expand Down
62 changes: 61 additions & 1 deletion lib/rules/sort/sort.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,37 @@ const options = [

Tester.run('hooks/sort', rule as unknown as Rule.RuleModule, {
valid: [
{
code: `
import React from 'react'
export const App = () => {
return <></>
}
`,
parserOptions,
options,
},
{
code: `
import * as React from 'react'
import { useRef } from 'react'
export const ComponentA = () => {
const [count, setCount] = React.useState(0)
const countRef = useRef(0)
React.useEffect(() => {
console.log('Hello')
},[])
return <></>
}
`,
parserOptions,
options,
},
{
code: `
import { useState, useEffect, useReducer } from 'react'
Expand Down Expand Up @@ -190,7 +221,6 @@ Tester.run('hooks/sort', rule as unknown as Rule.RuleModule, {
export function ComponentA() {
const [count, setCount] = useState(0)
const locale = useContext(LocaleContext)
}
Expand Down Expand Up @@ -223,5 +253,35 @@ Tester.run('hooks/sort', rule as unknown as Rule.RuleModule, {
parserOptions,
options,
},
{
code: `
import * as React from 'react'
import { useRef } from 'react'
export const ComponentA = () => {
React.useEffect(() => {
console.log('Hello')
},[])
const countRef = useRef(0)
const [count, setCount] = React.useState(0)
return <></>
}
`,
errors: [
{
message:
'Non-matching declaration order. useEffect comes after useState.',
},
{
message:
'Non-matching declaration order. useState comes before useEffect.',
},
],
parserOptions,
options,
},
],
})
3 changes: 3 additions & 0 deletions lib/rules/sort/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export type Node = {
type:
| 'Identifier'
| 'FunctionDeclaration'
| 'VariableDeclaration'
| 'ExportNamedDeclaration'
Expand All @@ -8,13 +9,15 @@ export type Node = {
| 'VariableDeclaration'
| 'CallExpression'
| 'VariableDeclarator'
| 'MemberExpression'
name: string
body: {
body: any[]
}
init: Node[]
callee: Node
expression: Node
property: Node
declaration: {
declarations: {
init: Node
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eslint-plugin-hooks",
"version": "0.3.0",
"version": "0.4.0",
"description": "A simple organizer for ordering hooks.",
"main": "dist/index.js",
"repository": {
Expand Down

0 comments on commit f706de1

Please sign in to comment.