eslint-plugin-smarthr 6.17.0 → 6.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +1 -0
- package/libs/ast-utils.js +86 -0
- package/package.json +1 -1
- package/rules/best-practice-for-lazy-variable/README.md +42 -2
- package/rules/best-practice-for-lazy-variable/index.js +16 -3
- package/rules/best-practice-for-no-unnecessary-variable/README.md +432 -0
- package/rules/best-practice-for-no-unnecessary-variable/index.js +464 -0
- package/test/best-practice-for-lazy-variable.js +94 -0
- package/test/best-practice-for-no-unnecessary-variable-ts.test.js +251 -0
- package/test/best-practice-for-no-unnecessary-variable.js +1110 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [6.18.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.17.0...eslint-plugin-smarthr-v6.18.0) (2026-06-09)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* best-practice-for-lazy-variable に fix オプション追加 ([#1355](https://github.com/kufu/tamatebako/issues/1355)) ([d2d1cd6](https://github.com/kufu/tamatebako/commit/d2d1cd6df5d800a0ff9907ec528e597eca930261))
|
|
11
|
+
* best-practice-for-no-unnecessary-variableルールを追加 ([#1339](https://github.com/kufu/tamatebako/issues/1339)) ([57f82c2](https://github.com/kufu/tamatebako/commit/57f82c24ba97a3c4ea191c1c197b75a87d576d3a))
|
|
12
|
+
|
|
5
13
|
## [6.17.0](https://github.com/kufu/tamatebako/compare/eslint-plugin-smarthr-v6.16.0...eslint-plugin-smarthr-v6.17.0) (2026-06-08)
|
|
6
14
|
|
|
7
15
|
|
package/README.md
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
- [best-practice-for-default-props](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-default-props)
|
|
28
28
|
- [best-practice-for-interactive-element](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-interactive-element)
|
|
29
29
|
- [best-practice-for-lazy-variable](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-lazy-variable)
|
|
30
|
+
- [best-practice-for-no-unnecessary-variable](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-no-unnecessary-variable)
|
|
30
31
|
- [best-practice-for-layouts](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-layouts)
|
|
31
32
|
- [best-practice-for-nested-attributes-array-index](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-nested-attributes-array-index)
|
|
32
33
|
- [best-practice-for-optional-chaining](https://github.com/kufu/tamatebako/tree/master/packages/eslint-plugin-smarthr/rules/best-practice-for-optional-chaining)
|
package/libs/ast-utils.js
CHANGED
|
@@ -16,6 +16,15 @@ const LOOP_STATEMENT_TYPES = new Set([
|
|
|
16
16
|
'DoWhileStatement',
|
|
17
17
|
])
|
|
18
18
|
|
|
19
|
+
const NEEDING_PARENS_TYPES = new Set([
|
|
20
|
+
'NewExpression',
|
|
21
|
+
'ObjectExpression',
|
|
22
|
+
'TSAsExpression',
|
|
23
|
+
'TSNonNullExpression',
|
|
24
|
+
'TSTypeAssertion',
|
|
25
|
+
'ConditionalExpression',
|
|
26
|
+
])
|
|
27
|
+
|
|
19
28
|
/**
|
|
20
29
|
* ノードが関数スコープかどうか判定
|
|
21
30
|
*/
|
|
@@ -94,6 +103,81 @@ function containsAwait(node) {
|
|
|
94
103
|
return containsNodeType(node, 'AwaitExpression')
|
|
95
104
|
}
|
|
96
105
|
|
|
106
|
+
/**
|
|
107
|
+
* 式の複雑さを計算
|
|
108
|
+
* 関数呼び出し、プロパティアクセス、演算子などの数をカウント
|
|
109
|
+
* @param {object} node - ASTノード
|
|
110
|
+
* @param {number} [maxComplexity] - 最大複雑さ(この値に達したら計算を中断)
|
|
111
|
+
*/
|
|
112
|
+
function calculateComplexity(node, maxComplexity) {
|
|
113
|
+
let complexity = 0
|
|
114
|
+
|
|
115
|
+
function traverse(n) {
|
|
116
|
+
if (
|
|
117
|
+
!n || typeof n !== 'object' ||
|
|
118
|
+
// maxComplexityを超えたら計算を中断
|
|
119
|
+
maxComplexity !== undefined && complexity > maxComplexity
|
|
120
|
+
) {
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
switch (n.type) {
|
|
125
|
+
case 'CallExpression':
|
|
126
|
+
// 引数なしの関数呼び出しは複雑さにカウントしない
|
|
127
|
+
if (n.arguments.length > 0) {
|
|
128
|
+
complexity++
|
|
129
|
+
}
|
|
130
|
+
break
|
|
131
|
+
case 'MemberExpression':
|
|
132
|
+
case 'BinaryExpression':
|
|
133
|
+
case 'LogicalExpression':
|
|
134
|
+
case 'NewExpression':
|
|
135
|
+
case 'SpreadElement':
|
|
136
|
+
case 'TSAsExpression':
|
|
137
|
+
case 'TSTypeAssertion':
|
|
138
|
+
complexity++
|
|
139
|
+
break
|
|
140
|
+
case 'ConditionalExpression':
|
|
141
|
+
case 'ObjectExpression':
|
|
142
|
+
case 'ArrayExpression':
|
|
143
|
+
case 'ArrowFunctionExpression':
|
|
144
|
+
case 'FunctionExpression':
|
|
145
|
+
case 'JSXOpeningElement':
|
|
146
|
+
complexity += 2
|
|
147
|
+
break
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// 再帰的に子ノードを探索
|
|
151
|
+
for (const key in n) {
|
|
152
|
+
if (key !== 'parent') {
|
|
153
|
+
const child = n[key]
|
|
154
|
+
|
|
155
|
+
if (child) {
|
|
156
|
+
if (Array.isArray(child)) {
|
|
157
|
+
for (const c of child) {
|
|
158
|
+
traverse(c)
|
|
159
|
+
if (maxComplexity !== undefined && complexity > maxComplexity) return
|
|
160
|
+
}
|
|
161
|
+
} else if (typeof child === 'object' && child.type) {
|
|
162
|
+
traverse(child)
|
|
163
|
+
if (maxComplexity !== undefined && complexity > maxComplexity) return
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
traverse(node)
|
|
171
|
+
return complexity
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* インライン化時に括弧が必要な式タイプかどうかを判定
|
|
176
|
+
*/
|
|
177
|
+
function needsParentheses(node) {
|
|
178
|
+
return NEEDING_PARENS_TYPES.has(node.type)
|
|
179
|
+
}
|
|
180
|
+
|
|
97
181
|
module.exports = {
|
|
98
182
|
isFunctionScope,
|
|
99
183
|
isLoopStatement,
|
|
@@ -101,4 +185,6 @@ module.exports = {
|
|
|
101
185
|
containsNode,
|
|
102
186
|
containsNodeType,
|
|
103
187
|
containsAwait,
|
|
188
|
+
calculateComplexity,
|
|
189
|
+
needsParentheses,
|
|
104
190
|
}
|
package/package.json
CHANGED
|
@@ -35,7 +35,7 @@ if (condition) {
|
|
|
35
35
|
```js
|
|
36
36
|
{
|
|
37
37
|
rules: {
|
|
38
|
-
'smarthr/best-practice-for-lazy-variable': 'error',
|
|
38
|
+
'smarthr/best-practice-for-lazy-variable': ['error', { fix: false }], // デフォルト: 自動修正無効
|
|
39
39
|
},
|
|
40
40
|
}
|
|
41
41
|
```
|
|
@@ -222,9 +222,49 @@ for (const item of items) {
|
|
|
222
222
|
}
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
+
## options
|
|
226
|
+
|
|
227
|
+
### fix
|
|
228
|
+
|
|
229
|
+
自動修正を有効にするかどうかを指定します。
|
|
230
|
+
|
|
231
|
+
**デフォルト値**: `false`
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
{
|
|
235
|
+
rules: {
|
|
236
|
+
'smarthr/best-practice-for-lazy-variable': ['error', { fix: true }],
|
|
237
|
+
},
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
#### ⚠️ 自動修正の注意点
|
|
242
|
+
|
|
243
|
+
自動修正を有効にすると、変数宣言が使用箇所の直前に移動されます。
|
|
244
|
+
|
|
245
|
+
**副作用を持つ関数の場合、実行順序が変わる可能性があります**:
|
|
246
|
+
|
|
247
|
+
```js
|
|
248
|
+
// Before(副作用を持つ関数の場合)
|
|
249
|
+
const value = sideEffect1() // ← 先に実行される
|
|
250
|
+
sideEffect2()
|
|
251
|
+
if (condition) {
|
|
252
|
+
console.log(value)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// After(自動修正後)
|
|
256
|
+
sideEffect2() // ← 先に実行される
|
|
257
|
+
if (condition) {
|
|
258
|
+
const value = sideEffect1()
|
|
259
|
+
console.log(value)
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
このため、デフォルトでは自動修正を無効にしています。自動修正を使う前に、手動で確認することを推奨します。
|
|
264
|
+
|
|
225
265
|
## autofix
|
|
226
266
|
|
|
227
|
-
|
|
267
|
+
このルールは自動修正に対応しています。自動修正を有効にするには `fix: true` オプションを指定してください。
|
|
228
268
|
|
|
229
269
|
### 移動パターン
|
|
230
270
|
|
|
@@ -7,7 +7,18 @@ const {
|
|
|
7
7
|
containsAwait,
|
|
8
8
|
} = require('../../libs/ast-utils')
|
|
9
9
|
|
|
10
|
-
const SCHEMA = [
|
|
10
|
+
const SCHEMA = [
|
|
11
|
+
{
|
|
12
|
+
type: 'object',
|
|
13
|
+
properties: {
|
|
14
|
+
fix: {
|
|
15
|
+
type: 'boolean',
|
|
16
|
+
default: false,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
additionalProperties: false,
|
|
20
|
+
},
|
|
21
|
+
]
|
|
11
22
|
|
|
12
23
|
const EARLY_EXIT_STATEMENT_TYPES = new Set([
|
|
13
24
|
'ReturnStatement',
|
|
@@ -768,6 +779,8 @@ module.exports = {
|
|
|
768
779
|
},
|
|
769
780
|
create(context) {
|
|
770
781
|
const sourceCode = context.sourceCode || context.getSourceCode()
|
|
782
|
+
const options = context.options[0] || {}
|
|
783
|
+
const fix = options.fix
|
|
771
784
|
|
|
772
785
|
return {
|
|
773
786
|
'VariableDeclarator': (node) => {
|
|
@@ -778,13 +791,13 @@ module.exports = {
|
|
|
778
791
|
node: analysis.node,
|
|
779
792
|
messageId: 'moveToLazy',
|
|
780
793
|
data: { name: analysis.varName },
|
|
781
|
-
fix: createMoveFixer(
|
|
794
|
+
fix: fix ? createMoveFixer(
|
|
782
795
|
sourceCode,
|
|
783
796
|
analysis.variableDeclaration,
|
|
784
797
|
analysis.targetBody,
|
|
785
798
|
analysis.insertBeforeStatement,
|
|
786
799
|
analysis.firstUsageStatement
|
|
787
|
-
),
|
|
800
|
+
) : null,
|
|
788
801
|
})
|
|
789
802
|
},
|
|
790
803
|
}
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# smarthr/best-practice-for-no-unnecessary-variable
|
|
2
|
+
|
|
3
|
+
一度しか使用されない変数を直接使用することを促すルールです。
|
|
4
|
+
|
|
5
|
+
不要な変数を作らず、値を直接使用することでコードの可読性とパフォーマンスを向上させます。
|
|
6
|
+
|
|
7
|
+
## なぜ不要な変数を避けるべきか
|
|
8
|
+
|
|
9
|
+
### 1. 可読性の向上
|
|
10
|
+
|
|
11
|
+
一度しか使わない変数は、コードを読む際の認知負荷を増やします。
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
// 悪い例: 不要な変数が読みやすさを阻害
|
|
15
|
+
const value = obj.property
|
|
16
|
+
return value
|
|
17
|
+
|
|
18
|
+
// 良い例: 直接使用で意図が明確
|
|
19
|
+
return obj.property
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### 2. パフォーマンスの向上
|
|
23
|
+
|
|
24
|
+
不要な変数宣言とメモリ割り当てを削減します。
|
|
25
|
+
|
|
26
|
+
## 前提条件
|
|
27
|
+
|
|
28
|
+
このルールは `best-practice-for-lazy-variable` ルールが適用済みであることを前提としています。
|
|
29
|
+
両ルールを組み合わせることで、最適な変数配置とインライン化を実現します。
|
|
30
|
+
|
|
31
|
+
## rules
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
{
|
|
35
|
+
rules: {
|
|
36
|
+
'smarthr/best-practice-for-lazy-variable': 'error',
|
|
37
|
+
'smarthr/best-practice-for-no-unnecessary-variable': ['error', { fix: false }], // デフォルト: 自動修正無効
|
|
38
|
+
},
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## options
|
|
43
|
+
|
|
44
|
+
### maxComplexity
|
|
45
|
+
|
|
46
|
+
式の複雑さの合計が `maxComplexity` を超える場合、インライン化を行いません。
|
|
47
|
+
|
|
48
|
+
**デフォルト値**: `5`
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
{
|
|
52
|
+
rules: {
|
|
53
|
+
'smarthr/best-practice-for-no-unnecessary-variable': ['error', { maxComplexity: 5 }],
|
|
54
|
+
},
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### 複雑さの計算方法
|
|
59
|
+
|
|
60
|
+
**複雑さ +1:**
|
|
61
|
+
- 関数呼び出し (`CallExpression`) ※引数がある場合のみ
|
|
62
|
+
- プロパティアクセス (`MemberExpression`)
|
|
63
|
+
- 二項演算子 (`BinaryExpression`)
|
|
64
|
+
- 論理演算子 (`LogicalExpression`)
|
|
65
|
+
- new式 (`NewExpression`)
|
|
66
|
+
- スプレッド構文 (`SpreadElement`)
|
|
67
|
+
- 型アサーション (`TSAsExpression`, `TSTypeAssertion`)
|
|
68
|
+
- 型注釈 (TypeScript: `const x: Type = ...`)
|
|
69
|
+
|
|
70
|
+
**複雑さ +0:**
|
|
71
|
+
- 引数なし関数呼び出し (`getValue()`, `Date.now()` など)
|
|
72
|
+
|
|
73
|
+
**複雑さ +2:**
|
|
74
|
+
- 三項演算子 (`ConditionalExpression`)
|
|
75
|
+
- オブジェクトリテラル (`ObjectExpression`)
|
|
76
|
+
- 配列リテラル (`ArrayExpression`)
|
|
77
|
+
- アロー関数 (`ArrowFunctionExpression`)
|
|
78
|
+
- 関数式 (`FunctionExpression`)
|
|
79
|
+
- JSX要素 (`JSXOpeningElement`)
|
|
80
|
+
|
|
81
|
+
### fix
|
|
82
|
+
|
|
83
|
+
自動修正を有効にするかどうかを指定します。
|
|
84
|
+
|
|
85
|
+
**デフォルト値**: `false`
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
{
|
|
89
|
+
rules: {
|
|
90
|
+
'smarthr/best-practice-for-no-unnecessary-variable': ['error', { fix: true }],
|
|
91
|
+
},
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### ⚠️ 自動修正の注意点
|
|
96
|
+
|
|
97
|
+
自動修正を有効にすると、変数宣言が削除され、式が直接インライン化されます。
|
|
98
|
+
|
|
99
|
+
**副作用を持つ関数の場合、実行順序が変わる可能性があります**:
|
|
100
|
+
|
|
101
|
+
```js
|
|
102
|
+
// Before(副作用を持つ関数の場合)
|
|
103
|
+
const result = sideEffect1() // ← 先に実行される
|
|
104
|
+
sideEffect2()
|
|
105
|
+
console.log(result)
|
|
106
|
+
|
|
107
|
+
// After(自動修正後)
|
|
108
|
+
sideEffect2() // ← 先に実行される
|
|
109
|
+
console.log(sideEffect1())
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
このため、デフォルトでは自動修正を無効にしています。自動修正を使う前に、手動で確認することを推奨します。
|
|
113
|
+
|
|
114
|
+
#### 複雑さのチェック方法
|
|
115
|
+
|
|
116
|
+
**総合複雑さ = 変数の式の複雑さ + 使用箇所の複雑さ**
|
|
117
|
+
|
|
118
|
+
```js
|
|
119
|
+
// 変数の式: obj.method() = 1 (MemberExpression) ※引数なしCallExpressionは0
|
|
120
|
+
// 使用箇所: console.log(x) = 2 (MemberExpression + CallExpression)
|
|
121
|
+
// 総合複雑さ: 3
|
|
122
|
+
const result = obj.method()
|
|
123
|
+
console.log(result)
|
|
124
|
+
// → maxComplexity: 5 なのでインライン化される
|
|
125
|
+
|
|
126
|
+
// 引数ありの場合
|
|
127
|
+
// 変数の式: obj.method(arg) = 2 (MemberExpression + CallExpression)
|
|
128
|
+
// 使用箇所: console.log(x) = 2
|
|
129
|
+
// 総合複雑さ: 4
|
|
130
|
+
const result = obj.method(arg)
|
|
131
|
+
console.log(result)
|
|
132
|
+
// → maxComplexity: 5 なのでインライン化される
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**return文の特別扱い:**
|
|
136
|
+
- `return x` の形式(単一変数を返す場合)のみ、変数の式の複雑さチェックをスキップ
|
|
137
|
+
- 使用箇所の複雑さのみでチェック
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
// return文で単一変数を返す場合
|
|
141
|
+
function foo() {
|
|
142
|
+
const result = obj.method().another().property // 複雑さ 3 (MemberExpression x3、引数なしCallExpression x2は0)
|
|
143
|
+
return result // 使用箇所の複雑さ 0
|
|
144
|
+
}
|
|
145
|
+
// → 総合複雑さ 0 なのでインライン化される
|
|
146
|
+
|
|
147
|
+
// return文で式を含む場合(特別扱いされない)
|
|
148
|
+
function bar() {
|
|
149
|
+
const result = obj.method() // 複雑さ 1 (MemberExpression、引数なしCallExpressionは0)
|
|
150
|
+
return result.property // 使用箇所の複雑さ 1
|
|
151
|
+
}
|
|
152
|
+
// → 総合複雑さ 2 なのでインライン化される(maxComplexity: 5)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## ❌ Incorrect
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
// 一度しか使わない変数
|
|
159
|
+
const x = getValue()
|
|
160
|
+
console.log(x)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
```js
|
|
164
|
+
// return文で単一変数を返す
|
|
165
|
+
function foo() {
|
|
166
|
+
const result = calculateValue()
|
|
167
|
+
return result
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
// 関数の引数で一度だけ使用
|
|
173
|
+
const data = getData()
|
|
174
|
+
process(data)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```js
|
|
178
|
+
// 複雑さが低い式(総合複雑さ 4 ≤ maxComplexity: 5)
|
|
179
|
+
const obj = { a: 1, b: 2 } // ObjectExpression: 2
|
|
180
|
+
console.log(obj) // console.log: 2
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
```js
|
|
184
|
+
// JSX要素(総合複雑さ 4 ≤ maxComplexity: 5)
|
|
185
|
+
const element = <div>Hello</div> // JSXOpeningElement: 2
|
|
186
|
+
render(element) // render: 1 + CallExpression: 1
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## ✅ Correct
|
|
190
|
+
|
|
191
|
+
### インライン化されたパターン
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
// 直接使用
|
|
195
|
+
console.log(getValue())
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
```js
|
|
199
|
+
// return文で直接使用
|
|
200
|
+
function foo() {
|
|
201
|
+
return calculateValue()
|
|
202
|
+
}
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### 除外されるパターン
|
|
206
|
+
|
|
207
|
+
```js
|
|
208
|
+
// 2回以上使用される変数
|
|
209
|
+
const x = getValue()
|
|
210
|
+
console.log(x)
|
|
211
|
+
return x
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```js
|
|
215
|
+
// ループ内で使用される変数
|
|
216
|
+
const x = getValue()
|
|
217
|
+
for (let i = 0; i < 10; i++) {
|
|
218
|
+
console.log(x)
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
// 関数スコープ内で使用される変数
|
|
224
|
+
const x = getValue()
|
|
225
|
+
array.forEach(() => {
|
|
226
|
+
console.log(x)
|
|
227
|
+
})
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
```js
|
|
231
|
+
// React Hooks(useXxxで始まる関数)で初期化される変数
|
|
232
|
+
function Component() {
|
|
233
|
+
const handleClick = useCallback(() => {
|
|
234
|
+
console.log('clicked')
|
|
235
|
+
}, [])
|
|
236
|
+
return handleClick
|
|
237
|
+
}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
```js
|
|
241
|
+
// await式を含む変数
|
|
242
|
+
async function fetchData() {
|
|
243
|
+
const result = await fetchAPI()
|
|
244
|
+
console.log(result)
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
```js
|
|
249
|
+
// アロー関数・関数式は除外(可読性低下を防ぐため)
|
|
250
|
+
const getTitle = () => {
|
|
251
|
+
return condition ? 'A' : 'B'
|
|
252
|
+
}
|
|
253
|
+
console.log(getTitle())
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
```js
|
|
257
|
+
// TaggedTemplateExpression(styled componentなど)
|
|
258
|
+
const StyledDiv = styled.div`
|
|
259
|
+
color: red;
|
|
260
|
+
`
|
|
261
|
+
console.log(StyledDiv)
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
```js
|
|
265
|
+
// export宣言された変数は除外(他のファイルから参照される可能性があるため)
|
|
266
|
+
export const API_URL = 'https://example.com/api'
|
|
267
|
+
export type Config = typeof API_URL
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
```js
|
|
271
|
+
// UPPER_SNAKE_CASE形式の定数は除外(慣習的な定数命名)
|
|
272
|
+
const NULL = { label: '', value: '' }
|
|
273
|
+
console.log(NULL)
|
|
274
|
+
|
|
275
|
+
const API_BASE_URL = 'https://example.com'
|
|
276
|
+
fetch(API_BASE_URL)
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
// 複雑な式は除外(デフォルト maxComplexity: 5)
|
|
281
|
+
// 複雑さ 6 (MemberExpression x2 + CallExpression x1 + ArrowFunction x2 + 引数なしCallExpression x1は0) + console.log (複雑さ 2) = 8
|
|
282
|
+
const result = array.map(() => obj.method())
|
|
283
|
+
console.log(result)
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
```js
|
|
287
|
+
// var宣言は除外(スコープの扱いが複雑なため)
|
|
288
|
+
var x = getValue()
|
|
289
|
+
console.log(x)
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
```js
|
|
293
|
+
// 分割代入は除外(将来的に対応予定: object, array両方)
|
|
294
|
+
const { name } = user
|
|
295
|
+
console.log(name)
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
```js
|
|
299
|
+
// ループの宣言部分で定義される変数(for-in, for-of, for文のinit)
|
|
300
|
+
for (const item of items) {
|
|
301
|
+
console.log(item)
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < 10; i++) {
|
|
305
|
+
console.log(i)
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
```js
|
|
310
|
+
// 初期化なしの変数
|
|
311
|
+
let x
|
|
312
|
+
if (condition) {
|
|
313
|
+
x = getValue1()
|
|
314
|
+
} else {
|
|
315
|
+
x = getValue2()
|
|
316
|
+
}
|
|
317
|
+
console.log(x)
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## autofix
|
|
321
|
+
|
|
322
|
+
このルールは自動修正に対応しています。自動修正を有効にするには `fix: true` オプションを指定してください。
|
|
323
|
+
|
|
324
|
+
```js
|
|
325
|
+
// Before
|
|
326
|
+
const x = getValue()
|
|
327
|
+
console.log(x)
|
|
328
|
+
|
|
329
|
+
// After
|
|
330
|
+
console.log(getValue())
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
### 括弧の追加
|
|
334
|
+
|
|
335
|
+
一部の式タイプでは、インライン化時に括弧が自動的に追加されます。
|
|
336
|
+
|
|
337
|
+
```js
|
|
338
|
+
// Before
|
|
339
|
+
const result = condition ? value1 : value2
|
|
340
|
+
doSomething(result)
|
|
341
|
+
|
|
342
|
+
// After
|
|
343
|
+
doSomething((condition ? value1 : value2))
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
// Before
|
|
348
|
+
const input = element as HTMLInputElement
|
|
349
|
+
return input
|
|
350
|
+
|
|
351
|
+
// After
|
|
352
|
+
return (element as HTMLInputElement)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
```js
|
|
356
|
+
// Before
|
|
357
|
+
const obj = { a: 1, b: 2 }
|
|
358
|
+
console.log(obj.property)
|
|
359
|
+
|
|
360
|
+
// After
|
|
361
|
+
console.log(({ a: 1, b: 2 }).property)
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
```js
|
|
365
|
+
// 単項演算子で使用される場合も括弧が必要
|
|
366
|
+
// Before
|
|
367
|
+
const isNothing = value === 'nothing'
|
|
368
|
+
if (!isNothing) allN = false
|
|
369
|
+
|
|
370
|
+
// After
|
|
371
|
+
if (!(value === 'nothing')) allN = false
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
```js
|
|
375
|
+
// ExpressionStatementの先頭で使用される場合、セミコロンを前置
|
|
376
|
+
// Before
|
|
377
|
+
inputs[0].focus()
|
|
378
|
+
const input = inputs[0]
|
|
379
|
+
input.setSelectionRange(0, 0)
|
|
380
|
+
|
|
381
|
+
// After
|
|
382
|
+
inputs[0].focus()
|
|
383
|
+
;inputs[0].setSelectionRange(0, 0)
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
**注意:** セミコロンの前置は、前の文とのメソッドチェーンを防ぐために行われます。
|
|
387
|
+
|
|
388
|
+
### 型注釈の保持(TypeScript)
|
|
389
|
+
|
|
390
|
+
TypeScriptで型注釈が付いている変数は、インライン化時に`as`型アサーションとして型情報が保持されます。
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
// Before
|
|
394
|
+
const value: string = getValue()
|
|
395
|
+
console.log(value)
|
|
396
|
+
|
|
397
|
+
// After
|
|
398
|
+
console.log((getValue() as string))
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
// Before
|
|
403
|
+
function getUser() {
|
|
404
|
+
const user: User | null = fetchUser()
|
|
405
|
+
return user
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// After
|
|
409
|
+
function getUser() {
|
|
410
|
+
return (fetchUser() as User | null)
|
|
411
|
+
}
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
**注意:** 型注釈は複雑度+1として計算されます。
|
|
415
|
+
|
|
416
|
+
### 複数変数宣言への対応
|
|
417
|
+
|
|
418
|
+
複数の変数を同時に宣言している場合、対象の変数のみが削除されます。
|
|
419
|
+
|
|
420
|
+
```js
|
|
421
|
+
// Before
|
|
422
|
+
const x = 1, y = getValue(), z = 3
|
|
423
|
+
console.log(y)
|
|
424
|
+
|
|
425
|
+
// After
|
|
426
|
+
const x = 1, z = 3
|
|
427
|
+
console.log(getValue())
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
### フォーマット
|
|
431
|
+
|
|
432
|
+
自動修正後はprettierやoxfmtなどのフォーマッターによってインデントや改行が整形されます。
|