@ttsc/lint 0.7.2 → 0.7.3

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.
@@ -4,9 +4,9 @@
4
4
  package main
5
5
 
6
6
  import (
7
- "strings"
7
+ "strings"
8
8
 
9
- shimast "github.com/microsoft/typescript-go/shim/ast"
9
+ shimast "github.com/microsoft/typescript-go/shim/ast"
10
10
  )
11
11
 
12
12
  // no-alert: `alert()` / `confirm()` / `prompt()`. Rarely the right
@@ -16,14 +16,14 @@ type noAlert struct{}
16
16
  func (noAlert) Name() string { return "no-alert" }
17
17
  func (noAlert) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindCallExpression} }
18
18
  func (noAlert) Check(ctx *Context, node *shimast.Node) {
19
- call := node.AsCallExpression()
20
- if call == nil {
21
- return
22
- }
23
- switch callCalleeName(call) {
24
- case "alert", "confirm", "prompt":
25
- ctx.Report(node, "Unexpected "+callCalleeName(call)+".")
26
- }
19
+ call := node.AsCallExpression()
20
+ if call == nil {
21
+ return
22
+ }
23
+ switch callCalleeName(call) {
24
+ case "alert", "confirm", "prompt":
25
+ ctx.Report(node, "Unexpected "+callCalleeName(call)+".")
26
+ }
27
27
  }
28
28
 
29
29
  // no-bitwise: `&`, `|`, `^`, `~`, `<<`, `>>`, `>>>` — almost always a
@@ -32,38 +32,38 @@ type noBitwise struct{}
32
32
 
33
33
  func (noBitwise) Name() string { return "no-bitwise" }
34
34
  func (noBitwise) Visits() []shimast.Kind {
35
- return []shimast.Kind{shimast.KindBinaryExpression, shimast.KindPrefixUnaryExpression}
35
+ return []shimast.Kind{shimast.KindBinaryExpression, shimast.KindPrefixUnaryExpression}
36
36
  }
37
37
  func (noBitwise) Check(ctx *Context, node *shimast.Node) {
38
- if node.Kind == shimast.KindBinaryExpression {
39
- expr := node.AsBinaryExpression()
40
- if expr == nil || expr.OperatorToken == nil {
41
- return
42
- }
43
- switch expr.OperatorToken.Kind {
44
- case shimast.KindAmpersandToken,
45
- shimast.KindBarToken,
46
- shimast.KindCaretToken,
47
- shimast.KindLessThanLessThanToken,
48
- shimast.KindGreaterThanGreaterThanToken,
49
- shimast.KindGreaterThanGreaterThanGreaterThanToken,
50
- shimast.KindAmpersandEqualsToken,
51
- shimast.KindBarEqualsToken,
52
- shimast.KindCaretEqualsToken,
53
- shimast.KindLessThanLessThanEqualsToken,
54
- shimast.KindGreaterThanGreaterThanEqualsToken,
55
- shimast.KindGreaterThanGreaterThanGreaterThanEqualsToken:
56
- ctx.Report(node, "Unexpected use of bitwise operator.")
57
- }
58
- return
59
- }
60
- prefix := node.AsPrefixUnaryExpression()
61
- if prefix == nil {
62
- return
63
- }
64
- if prefix.Operator == shimast.KindTildeToken {
65
- ctx.Report(node, "Unexpected use of bitwise operator.")
66
- }
38
+ if node.Kind == shimast.KindBinaryExpression {
39
+ expr := node.AsBinaryExpression()
40
+ if expr == nil || expr.OperatorToken == nil {
41
+ return
42
+ }
43
+ switch expr.OperatorToken.Kind {
44
+ case shimast.KindAmpersandToken,
45
+ shimast.KindBarToken,
46
+ shimast.KindCaretToken,
47
+ shimast.KindLessThanLessThanToken,
48
+ shimast.KindGreaterThanGreaterThanToken,
49
+ shimast.KindGreaterThanGreaterThanGreaterThanToken,
50
+ shimast.KindAmpersandEqualsToken,
51
+ shimast.KindBarEqualsToken,
52
+ shimast.KindCaretEqualsToken,
53
+ shimast.KindLessThanLessThanEqualsToken,
54
+ shimast.KindGreaterThanGreaterThanEqualsToken,
55
+ shimast.KindGreaterThanGreaterThanGreaterThanEqualsToken:
56
+ ctx.Report(node, "Unexpected use of bitwise operator.")
57
+ }
58
+ return
59
+ }
60
+ prefix := node.AsPrefixUnaryExpression()
61
+ if prefix == nil {
62
+ return
63
+ }
64
+ if prefix.Operator == shimast.KindTildeToken {
65
+ ctx.Report(node, "Unexpected use of bitwise operator.")
66
+ }
67
67
  }
68
68
 
69
69
  // no-caller: `arguments.caller` / `arguments.callee` — strict-mode
@@ -73,17 +73,17 @@ type noCaller struct{}
73
73
  func (noCaller) Name() string { return "no-caller" }
74
74
  func (noCaller) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindPropertyAccessExpression} }
75
75
  func (noCaller) Check(ctx *Context, node *shimast.Node) {
76
- access := node.AsPropertyAccessExpression()
77
- if access == nil {
78
- return
79
- }
80
- if identifierText(access.Expression) != "arguments" {
81
- return
82
- }
83
- switch identifierText(access.Name()) {
84
- case "caller", "callee":
85
- ctx.Report(node, "Avoid arguments."+identifierText(access.Name())+".")
86
- }
76
+ access := node.AsPropertyAccessExpression()
77
+ if access == nil {
78
+ return
79
+ }
80
+ if identifierText(access.Expression) != "arguments" {
81
+ return
82
+ }
83
+ switch identifierText(access.Name()) {
84
+ case "caller", "callee":
85
+ ctx.Report(node, "Avoid arguments."+identifierText(access.Name())+".")
86
+ }
87
87
  }
88
88
 
89
89
  // no-case-declarations: `switch (x) { case 1: let y = 2; break; }` —
@@ -92,29 +92,29 @@ type noCaseDeclarations struct{}
92
92
 
93
93
  func (noCaseDeclarations) Name() string { return "no-case-declarations" }
94
94
  func (noCaseDeclarations) Visits() []shimast.Kind {
95
- return []shimast.Kind{shimast.KindCaseClause, shimast.KindDefaultClause}
95
+ return []shimast.Kind{shimast.KindCaseClause, shimast.KindDefaultClause}
96
96
  }
97
97
  func (noCaseDeclarations) Check(ctx *Context, node *shimast.Node) {
98
- clause := node.AsCaseOrDefaultClause()
99
- if clause == nil || clause.Statements == nil {
100
- return
101
- }
102
- for _, stmt := range clause.Statements.Nodes {
103
- if stmt == nil {
104
- continue
105
- }
106
- if stmt.Kind == shimast.KindVariableStatement {
107
- vstmt := stmt.AsVariableStatement()
108
- if vstmt != nil && vstmt.DeclarationList != nil && !shimast.IsVar(vstmt.DeclarationList) {
109
- ctx.Report(stmt, "Unexpected lexical declaration in case block.")
110
- continue
111
- }
112
- }
113
- switch stmt.Kind {
114
- case shimast.KindFunctionDeclaration, shimast.KindClassDeclaration:
115
- ctx.Report(stmt, "Unexpected lexical declaration in case block.")
116
- }
117
- }
98
+ clause := node.AsCaseOrDefaultClause()
99
+ if clause == nil || clause.Statements == nil {
100
+ return
101
+ }
102
+ for _, stmt := range clause.Statements.Nodes {
103
+ if stmt == nil {
104
+ continue
105
+ }
106
+ if stmt.Kind == shimast.KindVariableStatement {
107
+ vstmt := stmt.AsVariableStatement()
108
+ if vstmt != nil && vstmt.DeclarationList != nil && !shimast.IsVar(vstmt.DeclarationList) {
109
+ ctx.Report(stmt, "Unexpected lexical declaration in case block.")
110
+ continue
111
+ }
112
+ }
113
+ switch stmt.Kind {
114
+ case shimast.KindFunctionDeclaration, shimast.KindClassDeclaration:
115
+ ctx.Report(stmt, "Unexpected lexical declaration in case block.")
116
+ }
117
+ }
118
118
  }
119
119
 
120
120
  // no-continue: `continue` keyword. ESLint flags it as a code-smell
@@ -124,7 +124,7 @@ type noContinue struct{}
124
124
  func (noContinue) Name() string { return "no-continue" }
125
125
  func (noContinue) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindContinueStatement} }
126
126
  func (noContinue) Check(ctx *Context, node *shimast.Node) {
127
- ctx.Report(node, "Unexpected use of continue statement.")
127
+ ctx.Report(node, "Unexpected use of continue statement.")
128
128
  }
129
129
 
130
130
  // no-delete-var: `delete x` where `x` is a variable. Strict-mode error.
@@ -133,13 +133,13 @@ type noDeleteVar struct{}
133
133
  func (noDeleteVar) Name() string { return "no-delete-var" }
134
134
  func (noDeleteVar) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindDeleteExpression} }
135
135
  func (noDeleteVar) Check(ctx *Context, node *shimast.Node) {
136
- del := node.AsDeleteExpression()
137
- if del == nil {
138
- return
139
- }
140
- if del.Expression != nil && del.Expression.Kind == shimast.KindIdentifier {
141
- ctx.Report(node, "Variables should not be deleted.")
142
- }
136
+ del := node.AsDeleteExpression()
137
+ if del == nil {
138
+ return
139
+ }
140
+ if del.Expression != nil && del.Expression.Kind == shimast.KindIdentifier {
141
+ ctx.Report(node, "Variables should not be deleted.")
142
+ }
143
143
  }
144
144
 
145
145
  // no-eq-null: `x == null` — ambiguous with eqeqeq's `null` exception
@@ -149,20 +149,20 @@ type noEqNull struct{}
149
149
  func (noEqNull) Name() string { return "no-eq-null" }
150
150
  func (noEqNull) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
151
151
  func (noEqNull) Check(ctx *Context, node *shimast.Node) {
152
- expr := node.AsBinaryExpression()
153
- if expr == nil || expr.OperatorToken == nil {
154
- return
155
- }
156
- if expr.OperatorToken.Kind != shimast.KindEqualsEqualsToken && expr.OperatorToken.Kind != shimast.KindExclamationEqualsToken {
157
- return
158
- }
159
- if isNullLiteral(expr.Left) || isNullLiteral(expr.Right) {
160
- ctx.Report(node, "Use '===' to compare with null.")
161
- }
152
+ expr := node.AsBinaryExpression()
153
+ if expr == nil || expr.OperatorToken == nil {
154
+ return
155
+ }
156
+ if expr.OperatorToken.Kind != shimast.KindEqualsEqualsToken && expr.OperatorToken.Kind != shimast.KindExclamationEqualsToken {
157
+ return
158
+ }
159
+ if isNullLiteral(expr.Left) || isNullLiteral(expr.Right) {
160
+ ctx.Report(node, "Use '===' to compare with null.")
161
+ }
162
162
  }
163
163
 
164
164
  func isNullLiteral(node *shimast.Node) bool {
165
- return node != nil && node.Kind == shimast.KindNullKeyword
165
+ return node != nil && node.Kind == shimast.KindNullKeyword
166
166
  }
167
167
 
168
168
  // no-extra-bind: `(function () {}).bind(this)` where `this` isn't used
@@ -173,60 +173,60 @@ type noExtraBind struct{}
173
173
  func (noExtraBind) Name() string { return "no-extra-bind" }
174
174
  func (noExtraBind) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindCallExpression} }
175
175
  func (noExtraBind) Check(ctx *Context, node *shimast.Node) {
176
- call := node.AsCallExpression()
177
- if call == nil || call.Expression == nil {
178
- return
179
- }
180
- if call.Expression.Kind != shimast.KindPropertyAccessExpression {
181
- return
182
- }
183
- access := call.Expression.AsPropertyAccessExpression()
184
- if access == nil || identifierText(access.Name()) != "bind" {
185
- return
186
- }
187
- target := stripParens(access.Expression)
188
- if target == nil {
189
- return
190
- }
191
- if target.Kind != shimast.KindArrowFunction && target.Kind != shimast.KindFunctionExpression {
192
- return
193
- }
194
- // Arrow functions don't have their own `this`; `.bind` is always
195
- // useless on them.
196
- if target.Kind == shimast.KindArrowFunction {
197
- ctx.Report(node, "The function binding is unnecessary.")
198
- return
199
- }
200
- body := target.Body()
201
- if body != nil && !bodyReferencesThis(body) {
202
- ctx.Report(node, "The function binding is unnecessary.")
203
- }
176
+ call := node.AsCallExpression()
177
+ if call == nil || call.Expression == nil {
178
+ return
179
+ }
180
+ if call.Expression.Kind != shimast.KindPropertyAccessExpression {
181
+ return
182
+ }
183
+ access := call.Expression.AsPropertyAccessExpression()
184
+ if access == nil || identifierText(access.Name()) != "bind" {
185
+ return
186
+ }
187
+ target := stripParens(access.Expression)
188
+ if target == nil {
189
+ return
190
+ }
191
+ if target.Kind != shimast.KindArrowFunction && target.Kind != shimast.KindFunctionExpression {
192
+ return
193
+ }
194
+ // Arrow functions don't have their own `this`; `.bind` is always
195
+ // useless on them.
196
+ if target.Kind == shimast.KindArrowFunction {
197
+ ctx.Report(node, "The function binding is unnecessary.")
198
+ return
199
+ }
200
+ body := target.Body()
201
+ if body != nil && !bodyReferencesThis(body) {
202
+ ctx.Report(node, "The function binding is unnecessary.")
203
+ }
204
204
  }
205
205
 
206
206
  func bodyReferencesThis(node *shimast.Node) bool {
207
- if node == nil {
208
- return false
209
- }
210
- if node.Kind == shimast.KindThisKeyword {
211
- return true
212
- }
213
- // Don't descend into nested function-likes — their `this` is
214
- // independent.
215
- if isFunctionLikeKind(node) && node.Parent != nil {
216
- return false
217
- }
218
- found := false
219
- node.ForEachChild(func(child *shimast.Node) bool {
220
- if found {
221
- return true
222
- }
223
- if bodyReferencesThis(child) {
224
- found = true
225
- return true
226
- }
227
- return false
228
- })
229
- return found
207
+ if node == nil {
208
+ return false
209
+ }
210
+ if node.Kind == shimast.KindThisKeyword {
211
+ return true
212
+ }
213
+ // Don't descend into nested function-likes — their `this` is
214
+ // independent.
215
+ if isFunctionLikeKind(node) && node.Parent != nil {
216
+ return false
217
+ }
218
+ found := false
219
+ node.ForEachChild(func(child *shimast.Node) bool {
220
+ if found {
221
+ return true
222
+ }
223
+ if bodyReferencesThis(child) {
224
+ found = true
225
+ return true
226
+ }
227
+ return false
228
+ })
229
+ return found
230
230
  }
231
231
 
232
232
  // no-labels: labels (`outer: for (...) { break outer; }`) are
@@ -236,7 +236,7 @@ type noLabels struct{}
236
236
  func (noLabels) Name() string { return "no-labels" }
237
237
  func (noLabels) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindLabeledStatement} }
238
238
  func (noLabels) Check(ctx *Context, node *shimast.Node) {
239
- ctx.Report(node, "Unexpected labeled statement.")
239
+ ctx.Report(node, "Unexpected labeled statement.")
240
240
  }
241
241
 
242
242
  // no-lone-blocks: `{ doStuff(); }` outside a control flow context —
@@ -246,45 +246,45 @@ type noLoneBlocks struct{}
246
246
  func (noLoneBlocks) Name() string { return "no-lone-blocks" }
247
247
  func (noLoneBlocks) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBlock} }
248
248
  func (noLoneBlocks) Check(ctx *Context, node *shimast.Node) {
249
- parent := node.Parent
250
- if parent == nil {
251
- return
252
- }
253
- switch parent.Kind {
254
- case shimast.KindBlock, shimast.KindSourceFile, shimast.KindModuleBlock:
255
- default:
256
- return
257
- }
258
- // Skip blocks that are themselves a function/method body — those
259
- // are tracked by isFunctionLikeKind on the parent.
260
- if isFunctionLikeKind(parent) {
261
- return
262
- }
263
- block := node.AsBlock()
264
- if block == nil || block.Statements == nil {
265
- return
266
- }
267
- // Empty block is `no-empty`'s domain.
268
- if len(block.Statements.Nodes) == 0 {
269
- return
270
- }
271
- // Allow blocks whose only contents are block-scoped declarations
272
- // (`{ const x = 1; }` is occasionally used to limit scope).
273
- for _, stmt := range block.Statements.Nodes {
274
- if stmt == nil {
275
- continue
276
- }
277
- if stmt.Kind == shimast.KindVariableStatement {
278
- vstmt := stmt.AsVariableStatement()
279
- if vstmt != nil && vstmt.DeclarationList != nil && !shimast.IsVar(vstmt.DeclarationList) {
280
- return
281
- }
282
- }
283
- if stmt.Kind == shimast.KindClassDeclaration || stmt.Kind == shimast.KindFunctionDeclaration {
284
- return
285
- }
286
- }
287
- ctx.Report(node, "Block is redundant.")
249
+ parent := node.Parent
250
+ if parent == nil {
251
+ return
252
+ }
253
+ switch parent.Kind {
254
+ case shimast.KindBlock, shimast.KindSourceFile, shimast.KindModuleBlock:
255
+ default:
256
+ return
257
+ }
258
+ // Skip blocks that are themselves a function/method body — those
259
+ // are tracked by isFunctionLikeKind on the parent.
260
+ if isFunctionLikeKind(parent) {
261
+ return
262
+ }
263
+ block := node.AsBlock()
264
+ if block == nil || block.Statements == nil {
265
+ return
266
+ }
267
+ // Empty block is `no-empty`'s domain.
268
+ if len(block.Statements.Nodes) == 0 {
269
+ return
270
+ }
271
+ // Allow blocks whose only contents are block-scoped declarations
272
+ // (`{ const x = 1; }` is occasionally used to limit scope).
273
+ for _, stmt := range block.Statements.Nodes {
274
+ if stmt == nil {
275
+ continue
276
+ }
277
+ if stmt.Kind == shimast.KindVariableStatement {
278
+ vstmt := stmt.AsVariableStatement()
279
+ if vstmt != nil && vstmt.DeclarationList != nil && !shimast.IsVar(vstmt.DeclarationList) {
280
+ return
281
+ }
282
+ }
283
+ if stmt.Kind == shimast.KindClassDeclaration || stmt.Kind == shimast.KindFunctionDeclaration {
284
+ return
285
+ }
286
+ }
287
+ ctx.Report(node, "Block is redundant.")
288
288
  }
289
289
 
290
290
  // no-lonely-if: `else { if (...) {...} }` should be `else if (...)`.
@@ -293,26 +293,26 @@ type noLonelyIf struct{}
293
293
  func (noLonelyIf) Name() string { return "no-lonely-if" }
294
294
  func (noLonelyIf) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindIfStatement} }
295
295
  func (noLonelyIf) Check(ctx *Context, node *shimast.Node) {
296
- parent := node.Parent
297
- if parent == nil || parent.Kind != shimast.KindBlock {
298
- return
299
- }
300
- block := parent.AsBlock()
301
- if block == nil || block.Statements == nil {
302
- return
303
- }
304
- if len(block.Statements.Nodes) != 1 {
305
- return
306
- }
307
- grand := parent.Parent
308
- if grand == nil || grand.Kind != shimast.KindIfStatement {
309
- return
310
- }
311
- gif := grand.AsIfStatement()
312
- if gif == nil || gif.ElseStatement != parent {
313
- return
314
- }
315
- ctx.Report(node, "Unexpected if as the only statement in an else block.")
296
+ parent := node.Parent
297
+ if parent == nil || parent.Kind != shimast.KindBlock {
298
+ return
299
+ }
300
+ block := parent.AsBlock()
301
+ if block == nil || block.Statements == nil {
302
+ return
303
+ }
304
+ if len(block.Statements.Nodes) != 1 {
305
+ return
306
+ }
307
+ grand := parent.Parent
308
+ if grand == nil || grand.Kind != shimast.KindIfStatement {
309
+ return
310
+ }
311
+ gif := grand.AsIfStatement()
312
+ if gif == nil || gif.ElseStatement != parent {
313
+ return
314
+ }
315
+ ctx.Report(node, "Unexpected if as the only statement in an else block.")
316
316
  }
317
317
 
318
318
  // no-multi-assign: `a = b = 1`. Confusing right-to-left chains.
@@ -321,19 +321,19 @@ type noMultiAssign struct{}
321
321
  func (noMultiAssign) Name() string { return "no-multi-assign" }
322
322
  func (noMultiAssign) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
323
323
  func (noMultiAssign) Check(ctx *Context, node *shimast.Node) {
324
- expr := node.AsBinaryExpression()
325
- if expr == nil || expr.OperatorToken == nil {
326
- return
327
- }
328
- if expr.OperatorToken.Kind != shimast.KindEqualsToken {
329
- return
330
- }
331
- if expr.Right != nil && expr.Right.Kind == shimast.KindBinaryExpression {
332
- inner := expr.Right.AsBinaryExpression()
333
- if inner != nil && inner.OperatorToken != nil && inner.OperatorToken.Kind == shimast.KindEqualsToken {
334
- ctx.Report(node, "Unexpected chained assignment.")
335
- }
336
- }
324
+ expr := node.AsBinaryExpression()
325
+ if expr == nil || expr.OperatorToken == nil {
326
+ return
327
+ }
328
+ if expr.OperatorToken.Kind != shimast.KindEqualsToken {
329
+ return
330
+ }
331
+ if expr.Right != nil && expr.Right.Kind == shimast.KindBinaryExpression {
332
+ inner := expr.Right.AsBinaryExpression()
333
+ if inner != nil && inner.OperatorToken != nil && inner.OperatorToken.Kind == shimast.KindEqualsToken {
334
+ ctx.Report(node, "Unexpected chained assignment.")
335
+ }
336
+ }
337
337
  }
338
338
 
339
339
  // no-negated-condition: `if (!x) {} else {}`. Easier to read with the
@@ -342,53 +342,53 @@ type noNegatedCondition struct{}
342
342
 
343
343
  func (noNegatedCondition) Name() string { return "no-negated-condition" }
344
344
  func (noNegatedCondition) Visits() []shimast.Kind {
345
- return []shimast.Kind{shimast.KindIfStatement, shimast.KindConditionalExpression}
345
+ return []shimast.Kind{shimast.KindIfStatement, shimast.KindConditionalExpression}
346
346
  }
347
347
  func (noNegatedCondition) Check(ctx *Context, node *shimast.Node) {
348
- if node.Kind == shimast.KindIfStatement {
349
- stmt := node.AsIfStatement()
350
- if stmt == nil || stmt.ElseStatement == nil {
351
- return
352
- }
353
- // Allow `else if` chains — the branches aren't symmetric.
354
- if stmt.ElseStatement.Kind == shimast.KindIfStatement {
355
- return
356
- }
357
- if isNegatedExpression(stmt.Expression) {
358
- ctx.Report(node, "Unexpected negated condition.")
359
- }
360
- return
361
- }
362
- cond := node.AsConditionalExpression()
363
- if cond == nil {
364
- return
365
- }
366
- if isNegatedExpression(cond.Condition) {
367
- ctx.Report(node, "Unexpected negated condition.")
368
- }
348
+ if node.Kind == shimast.KindIfStatement {
349
+ stmt := node.AsIfStatement()
350
+ if stmt == nil || stmt.ElseStatement == nil {
351
+ return
352
+ }
353
+ // Allow `else if` chains — the branches aren't symmetric.
354
+ if stmt.ElseStatement.Kind == shimast.KindIfStatement {
355
+ return
356
+ }
357
+ if isNegatedExpression(stmt.Expression) {
358
+ ctx.Report(node, "Unexpected negated condition.")
359
+ }
360
+ return
361
+ }
362
+ cond := node.AsConditionalExpression()
363
+ if cond == nil {
364
+ return
365
+ }
366
+ if isNegatedExpression(cond.Condition) {
367
+ ctx.Report(node, "Unexpected negated condition.")
368
+ }
369
369
  }
370
370
 
371
371
  func isNegatedExpression(node *shimast.Node) bool {
372
- expr := stripParens(node)
373
- if expr == nil {
374
- return false
375
- }
376
- if expr.Kind == shimast.KindPrefixUnaryExpression {
377
- prefix := expr.AsPrefixUnaryExpression()
378
- if prefix != nil && prefix.Operator == shimast.KindExclamationToken {
379
- return true
380
- }
381
- }
382
- if expr.Kind == shimast.KindBinaryExpression {
383
- bin := expr.AsBinaryExpression()
384
- if bin != nil && bin.OperatorToken != nil {
385
- switch bin.OperatorToken.Kind {
386
- case shimast.KindExclamationEqualsToken, shimast.KindExclamationEqualsEqualsToken:
387
- return true
388
- }
389
- }
390
- }
391
- return false
372
+ expr := stripParens(node)
373
+ if expr == nil {
374
+ return false
375
+ }
376
+ if expr.Kind == shimast.KindPrefixUnaryExpression {
377
+ prefix := expr.AsPrefixUnaryExpression()
378
+ if prefix != nil && prefix.Operator == shimast.KindExclamationToken {
379
+ return true
380
+ }
381
+ }
382
+ if expr.Kind == shimast.KindBinaryExpression {
383
+ bin := expr.AsBinaryExpression()
384
+ if bin != nil && bin.OperatorToken != nil {
385
+ switch bin.OperatorToken.Kind {
386
+ case shimast.KindExclamationEqualsToken, shimast.KindExclamationEqualsEqualsToken:
387
+ return true
388
+ }
389
+ }
390
+ }
391
+ return false
392
392
  }
393
393
 
394
394
  // no-nested-ternary: `a ? b : c ? d : e`.
@@ -396,21 +396,21 @@ type noNestedTernary struct{}
396
396
 
397
397
  func (noNestedTernary) Name() string { return "no-nested-ternary" }
398
398
  func (noNestedTernary) Visits() []shimast.Kind {
399
- return []shimast.Kind{shimast.KindConditionalExpression}
399
+ return []shimast.Kind{shimast.KindConditionalExpression}
400
400
  }
401
401
  func (noNestedTernary) Check(ctx *Context, node *shimast.Node) {
402
- cond := node.AsConditionalExpression()
403
- if cond == nil {
404
- return
405
- }
406
- if hasConditional(cond.WhenTrue) || hasConditional(cond.WhenFalse) {
407
- ctx.Report(node, "Do not nest ternary expressions.")
408
- }
402
+ cond := node.AsConditionalExpression()
403
+ if cond == nil {
404
+ return
405
+ }
406
+ if hasConditional(cond.WhenTrue) || hasConditional(cond.WhenFalse) {
407
+ ctx.Report(node, "Do not nest ternary expressions.")
408
+ }
409
409
  }
410
410
 
411
411
  func hasConditional(node *shimast.Node) bool {
412
- expr := stripParens(node)
413
- return expr != nil && expr.Kind == shimast.KindConditionalExpression
412
+ expr := stripParens(node)
413
+ return expr != nil && expr.Kind == shimast.KindConditionalExpression
414
414
  }
415
415
 
416
416
  // no-new: `new Foo()` whose result is discarded. Either store it or
@@ -420,13 +420,13 @@ type noNew struct{}
420
420
  func (noNew) Name() string { return "no-new" }
421
421
  func (noNew) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindExpressionStatement} }
422
422
  func (noNew) Check(ctx *Context, node *shimast.Node) {
423
- stmt := node.AsExpressionStatement()
424
- if stmt == nil || stmt.Expression == nil {
425
- return
426
- }
427
- if stmt.Expression.Kind == shimast.KindNewExpression {
428
- ctx.Report(node, "Do not use 'new' for side effects.")
429
- }
423
+ stmt := node.AsExpressionStatement()
424
+ if stmt == nil || stmt.Expression == nil {
425
+ return
426
+ }
427
+ if stmt.Expression.Kind == shimast.KindNewExpression {
428
+ ctx.Report(node, "Do not use 'new' for side effects.")
429
+ }
430
430
  }
431
431
 
432
432
  // no-new-func: `new Function("...")` — a third form of dynamic eval.
@@ -434,18 +434,18 @@ type noNewFunc struct{}
434
434
 
435
435
  func (noNewFunc) Name() string { return "no-new-func" }
436
436
  func (noNewFunc) Visits() []shimast.Kind {
437
- return []shimast.Kind{shimast.KindNewExpression, shimast.KindCallExpression}
437
+ return []shimast.Kind{shimast.KindNewExpression, shimast.KindCallExpression}
438
438
  }
439
439
  func (noNewFunc) Check(ctx *Context, node *shimast.Node) {
440
- var callee *shimast.Node
441
- if node.Kind == shimast.KindNewExpression {
442
- callee = node.AsNewExpression().Expression
443
- } else {
444
- callee = node.AsCallExpression().Expression
445
- }
446
- if identifierText(callee) == "Function" {
447
- ctx.Report(node, "The Function constructor is eval.")
448
- }
440
+ var callee *shimast.Node
441
+ if node.Kind == shimast.KindNewExpression {
442
+ callee = node.AsNewExpression().Expression
443
+ } else {
444
+ callee = node.AsCallExpression().Expression
445
+ }
446
+ if identifierText(callee) == "Function" {
447
+ ctx.Report(node, "The Function constructor is eval.")
448
+ }
449
449
  }
450
450
 
451
451
  // no-object-constructor: `new Object()` / `Object()` — same shape as
@@ -454,30 +454,30 @@ type noObjectConstructor struct{}
454
454
 
455
455
  func (noObjectConstructor) Name() string { return "no-object-constructor" }
456
456
  func (noObjectConstructor) Visits() []shimast.Kind {
457
- return []shimast.Kind{shimast.KindNewExpression, shimast.KindCallExpression}
457
+ return []shimast.Kind{shimast.KindNewExpression, shimast.KindCallExpression}
458
458
  }
459
459
  func (noObjectConstructor) Check(ctx *Context, node *shimast.Node) {
460
- var callee *shimast.Node
461
- var argCount int
462
- if node.Kind == shimast.KindNewExpression {
463
- ne := node.AsNewExpression()
464
- callee = ne.Expression
465
- if ne.Arguments != nil {
466
- argCount = len(ne.Arguments.Nodes)
467
- }
468
- } else {
469
- call := node.AsCallExpression()
470
- callee = call.Expression
471
- if call.Arguments != nil {
472
- argCount = len(call.Arguments.Nodes)
473
- }
474
- }
475
- if argCount != 0 {
476
- return // 1+ args is a "make a wrapper", not "make an empty object".
477
- }
478
- if identifierText(callee) == "Object" {
479
- ctx.Report(node, "The object literal notation {} is preferable.")
480
- }
460
+ var callee *shimast.Node
461
+ var argCount int
462
+ if node.Kind == shimast.KindNewExpression {
463
+ ne := node.AsNewExpression()
464
+ callee = ne.Expression
465
+ if ne.Arguments != nil {
466
+ argCount = len(ne.Arguments.Nodes)
467
+ }
468
+ } else {
469
+ call := node.AsCallExpression()
470
+ callee = call.Expression
471
+ if call.Arguments != nil {
472
+ argCount = len(call.Arguments.Nodes)
473
+ }
474
+ }
475
+ if argCount != 0 {
476
+ return // 1+ args is a "make a wrapper", not "make an empty object".
477
+ }
478
+ if identifierText(callee) == "Object" {
479
+ ctx.Report(node, "The object literal notation {} is preferable.")
480
+ }
481
481
  }
482
482
 
483
483
  // no-octal-escape: `"\251"` — octal escapes in string literals are
@@ -486,36 +486,36 @@ type noOctalEscape struct{}
486
486
 
487
487
  func (noOctalEscape) Name() string { return "no-octal-escape" }
488
488
  func (noOctalEscape) Visits() []shimast.Kind {
489
- return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
489
+ return []shimast.Kind{shimast.KindStringLiteral, shimast.KindNoSubstitutionTemplateLiteral}
490
490
  }
491
491
  func (noOctalEscape) Check(ctx *Context, node *shimast.Node) {
492
- src := nodeText(ctx.File, node)
493
- if hasOctalEscape(src) {
494
- ctx.Report(node, "Don't use octal escape sequences.")
495
- }
492
+ src := nodeText(ctx.File, node)
493
+ if hasOctalEscape(src) {
494
+ ctx.Report(node, "Don't use octal escape sequences.")
495
+ }
496
496
  }
497
497
 
498
498
  func hasOctalEscape(src string) bool {
499
- for i := 0; i < len(src)-1; i++ {
500
- if src[i] != '\\' {
501
- continue
502
- }
503
- next := src[i+1]
504
- // A literal `\0` followed by a non-digit is not an octal
505
- // escape, just NUL — those are allowed.
506
- if next < '0' || next > '7' {
507
- i++
508
- continue
509
- }
510
- if next == '0' {
511
- if i+2 >= len(src) || src[i+2] < '0' || src[i+2] > '9' {
512
- i++
513
- continue
514
- }
515
- }
516
- return true
517
- }
518
- return false
499
+ for i := 0; i < len(src)-1; i++ {
500
+ if src[i] != '\\' {
501
+ continue
502
+ }
503
+ next := src[i+1]
504
+ // A literal `\0` followed by a non-digit is not an octal
505
+ // escape, just NUL — those are allowed.
506
+ if next < '0' || next > '7' {
507
+ i++
508
+ continue
509
+ }
510
+ if next == '0' {
511
+ if i+2 >= len(src) || src[i+2] < '0' || src[i+2] > '9' {
512
+ i++
513
+ continue
514
+ }
515
+ }
516
+ return true
517
+ }
518
+ return false
519
519
  }
520
520
 
521
521
  // no-plusplus: `++x` / `x++`. Equivalent to `x += 1`, considered less
@@ -524,19 +524,19 @@ type noPlusPlus struct{}
524
524
 
525
525
  func (noPlusPlus) Name() string { return "no-plusplus" }
526
526
  func (noPlusPlus) Visits() []shimast.Kind {
527
- return []shimast.Kind{shimast.KindPrefixUnaryExpression, shimast.KindPostfixUnaryExpression}
527
+ return []shimast.Kind{shimast.KindPrefixUnaryExpression, shimast.KindPostfixUnaryExpression}
528
528
  }
529
529
  func (noPlusPlus) Check(ctx *Context, node *shimast.Node) {
530
- var op shimast.Kind
531
- if node.Kind == shimast.KindPrefixUnaryExpression {
532
- op = node.AsPrefixUnaryExpression().Operator
533
- } else {
534
- op = node.AsPostfixUnaryExpression().Operator
535
- }
536
- switch op {
537
- case shimast.KindPlusPlusToken, shimast.KindMinusMinusToken:
538
- ctx.Report(node, "Unary operator '++'/'--' used.")
539
- }
530
+ var op shimast.Kind
531
+ if node.Kind == shimast.KindPrefixUnaryExpression {
532
+ op = node.AsPrefixUnaryExpression().Operator
533
+ } else {
534
+ op = node.AsPostfixUnaryExpression().Operator
535
+ }
536
+ switch op {
537
+ case shimast.KindPlusPlusToken, shimast.KindMinusMinusToken:
538
+ ctx.Report(node, "Unary operator '++'/'--' used.")
539
+ }
540
540
  }
541
541
 
542
542
  // no-regex-spaces: multiple spaces in a regex literal — confusing
@@ -545,50 +545,50 @@ type noRegexSpaces struct{}
545
545
 
546
546
  func (noRegexSpaces) Name() string { return "no-regex-spaces" }
547
547
  func (noRegexSpaces) Visits() []shimast.Kind {
548
- return []shimast.Kind{shimast.KindRegularExpressionLiteral}
548
+ return []shimast.Kind{shimast.KindRegularExpressionLiteral}
549
549
  }
550
550
  func (noRegexSpaces) Check(ctx *Context, node *shimast.Node) {
551
- src := nodeText(ctx.File, node)
552
- if regexHasMultipleSpaces(src) {
553
- ctx.Report(node, "Spaces are hard to count. Use {N}.")
554
- }
551
+ src := nodeText(ctx.File, node)
552
+ if regexHasMultipleSpaces(src) {
553
+ ctx.Report(node, "Spaces are hard to count. Use {N}.")
554
+ }
555
555
  }
556
556
 
557
557
  func regexHasMultipleSpaces(src string) bool {
558
- // Strip trailing flags.
559
- end := strings.LastIndex(src, "/")
560
- if end <= 0 {
561
- return false
562
- }
563
- body := src[:end]
564
- inClass := false
565
- run := 0
566
- for i := 0; i < len(body); i++ {
567
- c := body[i]
568
- switch c {
569
- case '\\':
570
- i++
571
- run = 0
572
- case '[':
573
- inClass = true
574
- run = 0
575
- case ']':
576
- inClass = false
577
- run = 0
578
- case ' ':
579
- if inClass {
580
- run = 0
581
- continue
582
- }
583
- run++
584
- if run >= 2 {
585
- return true
586
- }
587
- default:
588
- run = 0
589
- }
590
- }
591
- return false
558
+ // Strip trailing flags.
559
+ end := strings.LastIndex(src, "/")
560
+ if end <= 0 {
561
+ return false
562
+ }
563
+ body := src[:end]
564
+ inClass := false
565
+ run := 0
566
+ for i := 0; i < len(body); i++ {
567
+ c := body[i]
568
+ switch c {
569
+ case '\\':
570
+ i++
571
+ run = 0
572
+ case '[':
573
+ inClass = true
574
+ run = 0
575
+ case ']':
576
+ inClass = false
577
+ run = 0
578
+ case ' ':
579
+ if inClass {
580
+ run = 0
581
+ continue
582
+ }
583
+ run++
584
+ if run >= 2 {
585
+ return true
586
+ }
587
+ default:
588
+ run = 0
589
+ }
590
+ }
591
+ return false
592
592
  }
593
593
 
594
594
  // no-return-assign: `return a = b` mixes assignment with return.
@@ -596,27 +596,27 @@ type noReturnAssign struct{}
596
596
 
597
597
  func (noReturnAssign) Name() string { return "no-return-assign" }
598
598
  func (noReturnAssign) Visits() []shimast.Kind {
599
- return []shimast.Kind{shimast.KindReturnStatement, shimast.KindArrowFunction}
599
+ return []shimast.Kind{shimast.KindReturnStatement, shimast.KindArrowFunction}
600
600
  }
601
601
  func (noReturnAssign) Check(ctx *Context, node *shimast.Node) {
602
- switch node.Kind {
603
- case shimast.KindReturnStatement:
604
- ret := node.AsReturnStatement()
605
- if ret == nil || ret.Expression == nil {
606
- return
607
- }
608
- if isAssignmentExpression(stripParens(ret.Expression)) {
609
- ctx.Report(node, "Return statement should not contain assignment.")
610
- }
611
- case shimast.KindArrowFunction:
612
- arrow := node.AsArrowFunction()
613
- if arrow == nil || arrow.Body == nil || arrow.Body.Kind == shimast.KindBlock {
614
- return
615
- }
616
- if isAssignmentExpression(stripParens(arrow.Body)) {
617
- ctx.Report(node, "Arrow function should not return an assignment.")
618
- }
619
- }
602
+ switch node.Kind {
603
+ case shimast.KindReturnStatement:
604
+ ret := node.AsReturnStatement()
605
+ if ret == nil || ret.Expression == nil {
606
+ return
607
+ }
608
+ if isAssignmentExpression(stripParens(ret.Expression)) {
609
+ ctx.Report(node, "Return statement should not contain assignment.")
610
+ }
611
+ case shimast.KindArrowFunction:
612
+ arrow := node.AsArrowFunction()
613
+ if arrow == nil || arrow.Body == nil || arrow.Body.Kind == shimast.KindBlock {
614
+ return
615
+ }
616
+ if isAssignmentExpression(stripParens(arrow.Body)) {
617
+ ctx.Report(node, "Arrow function should not return an assignment.")
618
+ }
619
+ }
620
620
  }
621
621
 
622
622
  // no-sequences: `(a, b)` — comma operator. Almost always a confusing
@@ -626,25 +626,25 @@ type noSequences struct{}
626
626
  func (noSequences) Name() string { return "no-sequences" }
627
627
  func (noSequences) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
628
628
  func (noSequences) Check(ctx *Context, node *shimast.Node) {
629
- expr := node.AsBinaryExpression()
630
- if expr == nil || expr.OperatorToken == nil {
631
- return
632
- }
633
- if expr.OperatorToken.Kind != shimast.KindCommaToken {
634
- return
635
- }
636
- // `for (a; b; c)` headers naturally use the comma operator;
637
- // suppress when the parent is a ForStatement initializer/incrementor.
638
- parent := node.Parent
639
- if parent != nil && parent.Kind == shimast.KindForStatement {
640
- return
641
- }
642
- // Allow when wrapped in parens (the canonical "I really mean it"
643
- // idiom).
644
- if parent != nil && parent.Kind == shimast.KindParenthesizedExpression {
645
- return
646
- }
647
- ctx.Report(node, "Unexpected use of comma operator.")
629
+ expr := node.AsBinaryExpression()
630
+ if expr == nil || expr.OperatorToken == nil {
631
+ return
632
+ }
633
+ if expr.OperatorToken.Kind != shimast.KindCommaToken {
634
+ return
635
+ }
636
+ // `for (a; b; c)` headers naturally use the comma operator;
637
+ // suppress when the parent is a ForStatement initializer/incrementor.
638
+ parent := node.Parent
639
+ if parent != nil && parent.Kind == shimast.KindForStatement {
640
+ return
641
+ }
642
+ // Allow when wrapped in parens (the canonical "I really mean it"
643
+ // idiom).
644
+ if parent != nil && parent.Kind == shimast.KindParenthesizedExpression {
645
+ return
646
+ }
647
+ ctx.Report(node, "Unexpected use of comma operator.")
648
648
  }
649
649
 
650
650
  // no-shadow-restricted-names: redeclaring `undefined`, `NaN`, `Infinity`,
@@ -653,26 +653,26 @@ type noShadowRestrictedNames struct{}
653
653
 
654
654
  func (noShadowRestrictedNames) Name() string { return "no-shadow-restricted-names" }
655
655
  func (noShadowRestrictedNames) Visits() []shimast.Kind {
656
- return []shimast.Kind{shimast.KindVariableDeclaration, shimast.KindParameter, shimast.KindFunctionDeclaration}
656
+ return []shimast.Kind{shimast.KindVariableDeclaration, shimast.KindParameter, shimast.KindFunctionDeclaration}
657
657
  }
658
658
  func (noShadowRestrictedNames) Check(ctx *Context, node *shimast.Node) {
659
- var nameNode *shimast.Node
660
- switch node.Kind {
661
- case shimast.KindVariableDeclaration:
662
- nameNode = node.AsVariableDeclaration().Name()
663
- case shimast.KindParameter:
664
- nameNode = node.AsParameterDeclaration().Name()
665
- case shimast.KindFunctionDeclaration:
666
- nameNode = node.AsFunctionDeclaration().Name()
667
- }
668
- name := identifierText(nameNode)
669
- if name == "" {
670
- return
671
- }
672
- switch name {
673
- case "undefined", "NaN", "Infinity", "arguments", "eval":
674
- ctx.Report(node, "Shadowing of global property '"+name+"'.")
675
- }
659
+ var nameNode *shimast.Node
660
+ switch node.Kind {
661
+ case shimast.KindVariableDeclaration:
662
+ nameNode = node.AsVariableDeclaration().Name()
663
+ case shimast.KindParameter:
664
+ nameNode = node.AsParameterDeclaration().Name()
665
+ case shimast.KindFunctionDeclaration:
666
+ nameNode = node.AsFunctionDeclaration().Name()
667
+ }
668
+ name := identifierText(nameNode)
669
+ if name == "" {
670
+ return
671
+ }
672
+ switch name {
673
+ case "undefined", "NaN", "Infinity", "arguments", "eval":
674
+ ctx.Report(node, "Shadowing of global property '"+name+"'.")
675
+ }
676
676
  }
677
677
 
678
678
  // no-undefined: literal `undefined` (vs `void 0`). Easier to misuse
@@ -682,39 +682,39 @@ type noUndefined struct{}
682
682
  func (noUndefined) Name() string { return "no-undefined" }
683
683
  func (noUndefined) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindIdentifier} }
684
684
  func (noUndefined) Check(ctx *Context, node *shimast.Node) {
685
- if identifierText(node) != "undefined" {
686
- return
687
- }
688
- parent := node.Parent
689
- if parent == nil {
690
- return
691
- }
692
- // Don't flag a declaration *named* `undefined` (no-shadow-restricted-names
693
- // covers that), or a member-access / object-key position
694
- // (`x.undefined`, `{ undefined: 1 }`).
695
- switch parent.Kind {
696
- case shimast.KindParameter:
697
- decl := parent.AsParameterDeclaration()
698
- if decl != nil && decl.Name() != nil && nodesShareLoc(decl.Name(), node) {
699
- return
700
- }
701
- case shimast.KindVariableDeclaration:
702
- decl := parent.AsVariableDeclaration()
703
- if decl != nil && decl.Name() != nil && nodesShareLoc(decl.Name(), node) {
704
- return
705
- }
706
- case shimast.KindPropertyAccessExpression:
707
- access := parent.AsPropertyAccessExpression()
708
- if access != nil && access.Name() != nil && nodesShareLoc(access.Name(), node) {
709
- return
710
- }
711
- case shimast.KindPropertyAssignment:
712
- assign := parent.AsPropertyAssignment()
713
- if assign != nil && assign.Name() != nil && nodesShareLoc(assign.Name(), node) {
714
- return
715
- }
716
- }
717
- ctx.Report(node, "Unexpected use of undefined.")
685
+ if identifierText(node) != "undefined" {
686
+ return
687
+ }
688
+ parent := node.Parent
689
+ if parent == nil {
690
+ return
691
+ }
692
+ // Don't flag a declaration *named* `undefined` (no-shadow-restricted-names
693
+ // covers that), or a member-access / object-key position
694
+ // (`x.undefined`, `{ undefined: 1 }`).
695
+ switch parent.Kind {
696
+ case shimast.KindParameter:
697
+ decl := parent.AsParameterDeclaration()
698
+ if decl != nil && decl.Name() != nil && nodesShareLoc(decl.Name(), node) {
699
+ return
700
+ }
701
+ case shimast.KindVariableDeclaration:
702
+ decl := parent.AsVariableDeclaration()
703
+ if decl != nil && decl.Name() != nil && nodesShareLoc(decl.Name(), node) {
704
+ return
705
+ }
706
+ case shimast.KindPropertyAccessExpression:
707
+ access := parent.AsPropertyAccessExpression()
708
+ if access != nil && access.Name() != nil && nodesShareLoc(access.Name(), node) {
709
+ return
710
+ }
711
+ case shimast.KindPropertyAssignment:
712
+ assign := parent.AsPropertyAssignment()
713
+ if assign != nil && assign.Name() != nil && nodesShareLoc(assign.Name(), node) {
714
+ return
715
+ }
716
+ }
717
+ ctx.Report(node, "Unexpected use of undefined.")
718
718
  }
719
719
 
720
720
  // nodesShareLoc reports whether two `*ast.Node` references describe the
@@ -722,10 +722,10 @@ func (noUndefined) Check(ctx *Context, node *shimast.Node) {
722
722
  // parser exposes its fields through accessor methods that may return
723
723
  // fresh wrappers; comparing positions works regardless.
724
724
  func nodesShareLoc(a, b *shimast.Node) bool {
725
- if a == nil || b == nil {
726
- return false
727
- }
728
- return a == b || (a.Pos() == b.Pos() && a.End() == b.End())
725
+ if a == nil || b == nil {
726
+ return false
727
+ }
728
+ return a == b || (a.Pos() == b.Pos() && a.End() == b.End())
729
729
  }
730
730
 
731
731
  // no-unneeded-ternary: `x ? true : false` → `Boolean(x)` / `!!x`.
@@ -733,20 +733,20 @@ type noUnneededTernary struct{}
733
733
 
734
734
  func (noUnneededTernary) Name() string { return "no-unneeded-ternary" }
735
735
  func (noUnneededTernary) Visits() []shimast.Kind {
736
- return []shimast.Kind{shimast.KindConditionalExpression}
736
+ return []shimast.Kind{shimast.KindConditionalExpression}
737
737
  }
738
738
  func (noUnneededTernary) Check(ctx *Context, node *shimast.Node) {
739
- cond := node.AsConditionalExpression()
740
- if cond == nil {
741
- return
742
- }
743
- t := stripParens(cond.WhenTrue)
744
- f := stripParens(cond.WhenFalse)
745
- tBool, tOk := isLiteralBoolean(t)
746
- fBool, fOk := isLiteralBoolean(f)
747
- if tOk && fOk && tBool != fBool {
748
- ctx.Report(node, "Unnecessary use of conditional expression for boolean.")
749
- }
739
+ cond := node.AsConditionalExpression()
740
+ if cond == nil {
741
+ return
742
+ }
743
+ t := stripParens(cond.WhenTrue)
744
+ f := stripParens(cond.WhenFalse)
745
+ tBool, tOk := isLiteralBoolean(t)
746
+ fBool, fOk := isLiteralBoolean(f)
747
+ if tOk && fOk && tBool != fBool {
748
+ ctx.Report(node, "Unnecessary use of conditional expression for boolean.")
749
+ }
750
750
  }
751
751
 
752
752
  // no-unused-expressions: an expression statement whose value isn't used.
@@ -755,61 +755,61 @@ type noUnusedExpressions struct{}
755
755
 
756
756
  func (noUnusedExpressions) Name() string { return "no-unused-expressions" }
757
757
  func (noUnusedExpressions) Visits() []shimast.Kind {
758
- return []shimast.Kind{shimast.KindExpressionStatement}
758
+ return []shimast.Kind{shimast.KindExpressionStatement}
759
759
  }
760
760
  func (noUnusedExpressions) Check(ctx *Context, node *shimast.Node) {
761
- stmt := node.AsExpressionStatement()
762
- if stmt == nil || stmt.Expression == nil {
763
- return
764
- }
765
- if isProductiveExpression(stmt.Expression) {
766
- return
767
- }
768
- ctx.Report(node, "Expected an assignment or function call and instead saw an expression.")
761
+ stmt := node.AsExpressionStatement()
762
+ if stmt == nil || stmt.Expression == nil {
763
+ return
764
+ }
765
+ if isProductiveExpression(stmt.Expression) {
766
+ return
767
+ }
768
+ ctx.Report(node, "Expected an assignment or function call and instead saw an expression.")
769
769
  }
770
770
 
771
771
  func isProductiveExpression(node *shimast.Node) bool {
772
- expr := stripParens(node)
773
- if expr == nil {
774
- return false
775
- }
776
- switch expr.Kind {
777
- case shimast.KindCallExpression,
778
- shimast.KindNewExpression,
779
- shimast.KindAwaitExpression,
780
- shimast.KindYieldExpression,
781
- shimast.KindDeleteExpression,
782
- shimast.KindBinaryExpression,
783
- shimast.KindPrefixUnaryExpression,
784
- shimast.KindPostfixUnaryExpression,
785
- shimast.KindTaggedTemplateExpression:
786
- // These can have side effects. The narrower checks
787
- // (no-cond-assign, no-bitwise) handle the suspicious shapes.
788
- switch expr.Kind {
789
- case shimast.KindBinaryExpression:
790
- bin := expr.AsBinaryExpression()
791
- if bin != nil && bin.OperatorToken != nil && isAssignmentOperator(bin.OperatorToken.Kind) {
792
- return true
793
- }
794
- return false
795
- case shimast.KindPrefixUnaryExpression:
796
- prefix := expr.AsPrefixUnaryExpression()
797
- if prefix != nil && (prefix.Operator == shimast.KindPlusPlusToken || prefix.Operator == shimast.KindMinusMinusToken) {
798
- return true
799
- }
800
- return false
801
- case shimast.KindPostfixUnaryExpression:
802
- return true
803
- }
804
- return true
805
- case shimast.KindStringLiteral:
806
- // "use strict" prologue.
807
- text := expr.AsStringLiteral()
808
- if text != nil && (text.Text == "use strict" || text.Text == "use asm") {
809
- return true
810
- }
811
- }
812
- return false
772
+ expr := stripParens(node)
773
+ if expr == nil {
774
+ return false
775
+ }
776
+ switch expr.Kind {
777
+ case shimast.KindCallExpression,
778
+ shimast.KindNewExpression,
779
+ shimast.KindAwaitExpression,
780
+ shimast.KindYieldExpression,
781
+ shimast.KindDeleteExpression,
782
+ shimast.KindBinaryExpression,
783
+ shimast.KindPrefixUnaryExpression,
784
+ shimast.KindPostfixUnaryExpression,
785
+ shimast.KindTaggedTemplateExpression:
786
+ // These can have side effects. The narrower checks
787
+ // (no-cond-assign, no-bitwise) handle the suspicious shapes.
788
+ switch expr.Kind {
789
+ case shimast.KindBinaryExpression:
790
+ bin := expr.AsBinaryExpression()
791
+ if bin != nil && bin.OperatorToken != nil && isAssignmentOperator(bin.OperatorToken.Kind) {
792
+ return true
793
+ }
794
+ return false
795
+ case shimast.KindPrefixUnaryExpression:
796
+ prefix := expr.AsPrefixUnaryExpression()
797
+ if prefix != nil && (prefix.Operator == shimast.KindPlusPlusToken || prefix.Operator == shimast.KindMinusMinusToken) {
798
+ return true
799
+ }
800
+ return false
801
+ case shimast.KindPostfixUnaryExpression:
802
+ return true
803
+ }
804
+ return true
805
+ case shimast.KindStringLiteral:
806
+ // "use strict" prologue.
807
+ text := expr.AsStringLiteral()
808
+ if text != nil && (text.Text == "use strict" || text.Text == "use asm") {
809
+ return true
810
+ }
811
+ }
812
+ return false
813
813
  }
814
814
 
815
815
  // no-useless-call: `func.call(undefined, ...args)` / `func.apply(undefined, args)`
@@ -819,26 +819,26 @@ type noUselessCall struct{}
819
819
  func (noUselessCall) Name() string { return "no-useless-call" }
820
820
  func (noUselessCall) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindCallExpression} }
821
821
  func (noUselessCall) Check(ctx *Context, node *shimast.Node) {
822
- call := node.AsCallExpression()
823
- if call == nil || call.Expression == nil || call.Expression.Kind != shimast.KindPropertyAccessExpression {
824
- return
825
- }
826
- access := call.Expression.AsPropertyAccessExpression()
827
- method := identifierText(access.Name())
828
- if method != "call" && method != "apply" {
829
- return
830
- }
831
- if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
832
- return
833
- }
834
- first := call.Arguments.Nodes[0]
835
- first = stripParens(first)
836
- if first == nil {
837
- return
838
- }
839
- if first.Kind == shimast.KindNullKeyword || identifierText(first) == "undefined" {
840
- ctx.Report(node, "Unnecessary "+method+"().")
841
- }
822
+ call := node.AsCallExpression()
823
+ if call == nil || call.Expression == nil || call.Expression.Kind != shimast.KindPropertyAccessExpression {
824
+ return
825
+ }
826
+ access := call.Expression.AsPropertyAccessExpression()
827
+ method := identifierText(access.Name())
828
+ if method != "call" && method != "apply" {
829
+ return
830
+ }
831
+ if call.Arguments == nil || len(call.Arguments.Nodes) == 0 {
832
+ return
833
+ }
834
+ first := call.Arguments.Nodes[0]
835
+ first = stripParens(first)
836
+ if first == nil {
837
+ return
838
+ }
839
+ if first.Kind == shimast.KindNullKeyword || identifierText(first) == "undefined" {
840
+ ctx.Report(node, "Unnecessary "+method+"().")
841
+ }
842
842
  }
843
843
 
844
844
  // no-useless-computed-key: `{ ["foo"]: 1 }` could be `{ foo: 1 }`.
@@ -846,34 +846,34 @@ type noUselessComputedKey struct{}
846
846
 
847
847
  func (noUselessComputedKey) Name() string { return "no-useless-computed-key" }
848
848
  func (noUselessComputedKey) Visits() []shimast.Kind {
849
- return []shimast.Kind{shimast.KindPropertyAssignment, shimast.KindMethodDeclaration}
849
+ return []shimast.Kind{shimast.KindPropertyAssignment, shimast.KindMethodDeclaration}
850
850
  }
851
851
  func (noUselessComputedKey) Check(ctx *Context, node *shimast.Node) {
852
- var name *shimast.Node
853
- switch node.Kind {
854
- case shimast.KindPropertyAssignment:
855
- name = node.AsPropertyAssignment().Name()
856
- case shimast.KindMethodDeclaration:
857
- name = node.AsMethodDeclaration().Name()
858
- }
859
- if name == nil || name.Kind != shimast.KindComputedPropertyName {
860
- return
861
- }
862
- computed := name.AsComputedPropertyName()
863
- if computed == nil || computed.Expression == nil {
864
- return
865
- }
866
- // Only fire when the computed key is a string / numeric / template
867
- // literal — a bare identifier inside `[ ]` reads its *value* and is
868
- // not equivalent to the same identifier as a static key.
869
- expr := stripParens(computed.Expression)
870
- switch expr.Kind {
871
- case shimast.KindStringLiteral,
872
- shimast.KindNoSubstitutionTemplateLiteral,
873
- shimast.KindNumericLiteral,
874
- shimast.KindBigIntLiteral:
875
- ctx.Report(name, "Unnecessarily computed property key.")
876
- }
852
+ var name *shimast.Node
853
+ switch node.Kind {
854
+ case shimast.KindPropertyAssignment:
855
+ name = node.AsPropertyAssignment().Name()
856
+ case shimast.KindMethodDeclaration:
857
+ name = node.AsMethodDeclaration().Name()
858
+ }
859
+ if name == nil || name.Kind != shimast.KindComputedPropertyName {
860
+ return
861
+ }
862
+ computed := name.AsComputedPropertyName()
863
+ if computed == nil || computed.Expression == nil {
864
+ return
865
+ }
866
+ // Only fire when the computed key is a string / numeric / template
867
+ // literal — a bare identifier inside `[ ]` reads its *value* and is
868
+ // not equivalent to the same identifier as a static key.
869
+ expr := stripParens(computed.Expression)
870
+ switch expr.Kind {
871
+ case shimast.KindStringLiteral,
872
+ shimast.KindNoSubstitutionTemplateLiteral,
873
+ shimast.KindNumericLiteral,
874
+ shimast.KindBigIntLiteral:
875
+ ctx.Report(name, "Unnecessarily computed property key.")
876
+ }
877
877
  }
878
878
 
879
879
  // no-useless-rename: `import { x as x } from ...` / `const { x: x } = obj`
@@ -882,35 +882,35 @@ type noUselessRename struct{}
882
882
 
883
883
  func (noUselessRename) Name() string { return "no-useless-rename" }
884
884
  func (noUselessRename) Visits() []shimast.Kind {
885
- return []shimast.Kind{shimast.KindImportSpecifier, shimast.KindExportSpecifier, shimast.KindBindingElement}
885
+ return []shimast.Kind{shimast.KindImportSpecifier, shimast.KindExportSpecifier, shimast.KindBindingElement}
886
886
  }
887
887
  func (noUselessRename) Check(ctx *Context, node *shimast.Node) {
888
- switch node.Kind {
889
- case shimast.KindImportSpecifier:
890
- spec := node.AsImportSpecifier()
891
- if spec == nil || spec.PropertyName == nil {
892
- return
893
- }
894
- if identifierText(spec.PropertyName) == identifierText(spec.Name()) {
895
- ctx.Report(node, "Import { x as x } is redundant.")
896
- }
897
- case shimast.KindExportSpecifier:
898
- spec := node.AsExportSpecifier()
899
- if spec == nil || spec.PropertyName == nil {
900
- return
901
- }
902
- if identifierText(spec.PropertyName) == identifierText(spec.Name()) {
903
- ctx.Report(node, "Export { x as x } is redundant.")
904
- }
905
- case shimast.KindBindingElement:
906
- el := node.AsBindingElement()
907
- if el == nil || el.PropertyName == nil {
908
- return
909
- }
910
- if identifierText(el.PropertyName) == identifierText(el.Name()) {
911
- ctx.Report(node, "Destructuring rename to the same name is redundant.")
912
- }
913
- }
888
+ switch node.Kind {
889
+ case shimast.KindImportSpecifier:
890
+ spec := node.AsImportSpecifier()
891
+ if spec == nil || spec.PropertyName == nil {
892
+ return
893
+ }
894
+ if identifierText(spec.PropertyName) == identifierText(spec.Name()) {
895
+ ctx.Report(node, "Import { x as x } is redundant.")
896
+ }
897
+ case shimast.KindExportSpecifier:
898
+ spec := node.AsExportSpecifier()
899
+ if spec == nil || spec.PropertyName == nil {
900
+ return
901
+ }
902
+ if identifierText(spec.PropertyName) == identifierText(spec.Name()) {
903
+ ctx.Report(node, "Export { x as x } is redundant.")
904
+ }
905
+ case shimast.KindBindingElement:
906
+ el := node.AsBindingElement()
907
+ if el == nil || el.PropertyName == nil {
908
+ return
909
+ }
910
+ if identifierText(el.PropertyName) == identifierText(el.Name()) {
911
+ ctx.Report(node, "Destructuring rename to the same name is redundant.")
912
+ }
913
+ }
914
914
  }
915
915
 
916
916
  // object-shorthand: `{ x: x }` → `{ x }`.
@@ -919,18 +919,18 @@ type objectShorthand struct{}
919
919
  func (objectShorthand) Name() string { return "object-shorthand" }
920
920
  func (objectShorthand) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindPropertyAssignment} }
921
921
  func (objectShorthand) Check(ctx *Context, node *shimast.Node) {
922
- prop := node.AsPropertyAssignment()
923
- if prop == nil || prop.Name() == nil || prop.Initializer == nil {
924
- return
925
- }
926
- keyName := identifierText(prop.Name())
927
- valueName := identifierText(prop.Initializer)
928
- if keyName == "" || valueName == "" {
929
- return
930
- }
931
- if keyName == valueName {
932
- ctx.Report(node, "Expected property shorthand.")
933
- }
922
+ prop := node.AsPropertyAssignment()
923
+ if prop == nil || prop.Name() == nil || prop.Initializer == nil {
924
+ return
925
+ }
926
+ keyName := identifierText(prop.Name())
927
+ valueName := identifierText(prop.Initializer)
928
+ if keyName == "" || valueName == "" {
929
+ return
930
+ }
931
+ if keyName == valueName {
932
+ ctx.Report(node, "Expected property shorthand.")
933
+ }
934
934
  }
935
935
 
936
936
  // operator-assignment: `x = x + 1` → `x += 1`.
@@ -938,39 +938,39 @@ type operatorAssignment struct{}
938
938
 
939
939
  func (operatorAssignment) Name() string { return "operator-assignment" }
940
940
  func (operatorAssignment) Visits() []shimast.Kind {
941
- return []shimast.Kind{shimast.KindBinaryExpression}
941
+ return []shimast.Kind{shimast.KindBinaryExpression}
942
942
  }
943
943
  func (operatorAssignment) Check(ctx *Context, node *shimast.Node) {
944
- expr := node.AsBinaryExpression()
945
- if expr == nil || expr.OperatorToken == nil {
946
- return
947
- }
948
- if expr.OperatorToken.Kind != shimast.KindEqualsToken {
949
- return
950
- }
951
- if expr.Right == nil || expr.Right.Kind != shimast.KindBinaryExpression {
952
- return
953
- }
954
- right := expr.Right.AsBinaryExpression()
955
- if right == nil || right.OperatorToken == nil {
956
- return
957
- }
958
- if !isCompoundEligibleOperator(right.OperatorToken.Kind) {
959
- return
960
- }
961
- if nodeText(ctx.File, expr.Left) == nodeText(ctx.File, right.Left) {
962
- ctx.Report(node, "Assignment can be replaced with compound operator.")
963
- }
944
+ expr := node.AsBinaryExpression()
945
+ if expr == nil || expr.OperatorToken == nil {
946
+ return
947
+ }
948
+ if expr.OperatorToken.Kind != shimast.KindEqualsToken {
949
+ return
950
+ }
951
+ if expr.Right == nil || expr.Right.Kind != shimast.KindBinaryExpression {
952
+ return
953
+ }
954
+ right := expr.Right.AsBinaryExpression()
955
+ if right == nil || right.OperatorToken == nil {
956
+ return
957
+ }
958
+ if !isCompoundEligibleOperator(right.OperatorToken.Kind) {
959
+ return
960
+ }
961
+ if nodeText(ctx.File, expr.Left) == nodeText(ctx.File, right.Left) {
962
+ ctx.Report(node, "Assignment can be replaced with compound operator.")
963
+ }
964
964
  }
965
965
 
966
966
  func isCompoundEligibleOperator(kind shimast.Kind) bool {
967
- switch kind {
968
- case shimast.KindPlusToken, shimast.KindAsteriskToken, shimast.KindSlashToken,
969
- shimast.KindAsteriskAsteriskToken, shimast.KindAmpersandToken, shimast.KindBarToken,
970
- shimast.KindCaretToken:
971
- return true
972
- }
973
- return false
967
+ switch kind {
968
+ case shimast.KindPlusToken, shimast.KindAsteriskToken, shimast.KindSlashToken,
969
+ shimast.KindAsteriskAsteriskToken, shimast.KindAmpersandToken, shimast.KindBarToken,
970
+ shimast.KindCaretToken:
971
+ return true
972
+ }
973
+ return false
974
974
  }
975
975
 
976
976
  // prefer-exponentiation-operator: `Math.pow(a, b)` → `a ** b`.
@@ -978,17 +978,17 @@ type preferExponentiationOperator struct{}
978
978
 
979
979
  func (preferExponentiationOperator) Name() string { return "prefer-exponentiation-operator" }
980
980
  func (preferExponentiationOperator) Visits() []shimast.Kind {
981
- return []shimast.Kind{shimast.KindCallExpression}
981
+ return []shimast.Kind{shimast.KindCallExpression}
982
982
  }
983
983
  func (preferExponentiationOperator) Check(ctx *Context, node *shimast.Node) {
984
- call := node.AsCallExpression()
985
- if call == nil {
986
- return
987
- }
988
- if !isMatchingPropertyAccess(call.Expression, "Math", "pow") {
989
- return
990
- }
991
- ctx.Report(node, "Use the '**' operator instead of 'Math.pow'.")
984
+ call := node.AsCallExpression()
985
+ if call == nil {
986
+ return
987
+ }
988
+ if !isMatchingPropertyAccess(call.Expression, "Math", "pow") {
989
+ return
990
+ }
991
+ ctx.Report(node, "Use the '**' operator instead of 'Math.pow'.")
992
992
  }
993
993
 
994
994
  // prefer-spread: `fn.apply(null, args)` → `fn(...args)`.
@@ -997,29 +997,29 @@ type preferSpread struct{}
997
997
  func (preferSpread) Name() string { return "prefer-spread" }
998
998
  func (preferSpread) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindCallExpression} }
999
999
  func (preferSpread) Check(ctx *Context, node *shimast.Node) {
1000
- call := node.AsCallExpression()
1001
- if call == nil || call.Expression == nil {
1002
- return
1003
- }
1004
- if call.Expression.Kind != shimast.KindPropertyAccessExpression {
1005
- return
1006
- }
1007
- access := call.Expression.AsPropertyAccessExpression()
1008
- if access == nil || identifierText(access.Name()) != "apply" {
1009
- return
1010
- }
1011
- if call.Arguments == nil || len(call.Arguments.Nodes) != 2 {
1012
- return
1013
- }
1014
- first := stripParens(call.Arguments.Nodes[0])
1015
- if first == nil {
1016
- return
1017
- }
1018
- // ESLint default: only fire when the `this` arg is null/undefined,
1019
- // which is the canonical "I just want to spread" pattern.
1020
- if first.Kind == shimast.KindNullKeyword || identifierText(first) == "undefined" {
1021
- ctx.Report(node, "Use the spread operator instead of '.apply()'.")
1022
- }
1000
+ call := node.AsCallExpression()
1001
+ if call == nil || call.Expression == nil {
1002
+ return
1003
+ }
1004
+ if call.Expression.Kind != shimast.KindPropertyAccessExpression {
1005
+ return
1006
+ }
1007
+ access := call.Expression.AsPropertyAccessExpression()
1008
+ if access == nil || identifierText(access.Name()) != "apply" {
1009
+ return
1010
+ }
1011
+ if call.Arguments == nil || len(call.Arguments.Nodes) != 2 {
1012
+ return
1013
+ }
1014
+ first := stripParens(call.Arguments.Nodes[0])
1015
+ if first == nil {
1016
+ return
1017
+ }
1018
+ // ESLint default: only fire when the `this` arg is null/undefined,
1019
+ // which is the canonical "I just want to spread" pattern.
1020
+ if first.Kind == shimast.KindNullKeyword || identifierText(first) == "undefined" {
1021
+ ctx.Report(node, "Use the spread operator instead of '.apply()'.")
1022
+ }
1023
1023
  }
1024
1024
 
1025
1025
  // prefer-template: string concatenation that would read better as a
@@ -1030,44 +1030,44 @@ type preferTemplate struct{}
1030
1030
  func (preferTemplate) Name() string { return "prefer-template" }
1031
1031
  func (preferTemplate) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
1032
1032
  func (preferTemplate) Check(ctx *Context, node *shimast.Node) {
1033
- expr := node.AsBinaryExpression()
1034
- if expr == nil || expr.OperatorToken == nil {
1035
- return
1036
- }
1037
- if expr.OperatorToken.Kind != shimast.KindPlusToken {
1038
- return
1039
- }
1040
- // Skip when the parent is also a string-concat — only the topmost
1041
- // `+` chain emits one finding.
1042
- parent := node.Parent
1043
- if parent != nil && parent.Kind == shimast.KindBinaryExpression {
1044
- parentBin := parent.AsBinaryExpression()
1045
- if parentBin != nil && parentBin.OperatorToken != nil && parentBin.OperatorToken.Kind == shimast.KindPlusToken {
1046
- return
1047
- }
1048
- }
1049
- hasString, hasOther := concatChainShape(node)
1050
- if hasString && hasOther {
1051
- ctx.Report(node, "Unexpected string concatenation.")
1052
- }
1033
+ expr := node.AsBinaryExpression()
1034
+ if expr == nil || expr.OperatorToken == nil {
1035
+ return
1036
+ }
1037
+ if expr.OperatorToken.Kind != shimast.KindPlusToken {
1038
+ return
1039
+ }
1040
+ // Skip when the parent is also a string-concat — only the topmost
1041
+ // `+` chain emits one finding.
1042
+ parent := node.Parent
1043
+ if parent != nil && parent.Kind == shimast.KindBinaryExpression {
1044
+ parentBin := parent.AsBinaryExpression()
1045
+ if parentBin != nil && parentBin.OperatorToken != nil && parentBin.OperatorToken.Kind == shimast.KindPlusToken {
1046
+ return
1047
+ }
1048
+ }
1049
+ hasString, hasOther := concatChainShape(node)
1050
+ if hasString && hasOther {
1051
+ ctx.Report(node, "Unexpected string concatenation.")
1052
+ }
1053
1053
  }
1054
1054
 
1055
1055
  func concatChainShape(node *shimast.Node) (hasString bool, hasOther bool) {
1056
- if node == nil {
1057
- return false, false
1058
- }
1059
- if node.Kind == shimast.KindBinaryExpression {
1060
- bin := node.AsBinaryExpression()
1061
- if bin != nil && bin.OperatorToken != nil && bin.OperatorToken.Kind == shimast.KindPlusToken {
1062
- ls, lo := concatChainShape(bin.Left)
1063
- rs, ro := concatChainShape(bin.Right)
1064
- return ls || rs, lo || ro
1065
- }
1066
- }
1067
- if isStringLikeLiteral(stripParens(node)) {
1068
- return true, false
1069
- }
1070
- return false, true
1056
+ if node == nil {
1057
+ return false, false
1058
+ }
1059
+ if node.Kind == shimast.KindBinaryExpression {
1060
+ bin := node.AsBinaryExpression()
1061
+ if bin != nil && bin.OperatorToken != nil && bin.OperatorToken.Kind == shimast.KindPlusToken {
1062
+ ls, lo := concatChainShape(bin.Left)
1063
+ rs, ro := concatChainShape(bin.Right)
1064
+ return ls || rs, lo || ro
1065
+ }
1066
+ }
1067
+ if isStringLikeLiteral(stripParens(node)) {
1068
+ return true, false
1069
+ }
1070
+ return false, true
1071
1071
  }
1072
1072
 
1073
1073
  // require-yield: `function* gen() { return 1; }` — generators that
@@ -1076,58 +1076,58 @@ type requireYield struct{}
1076
1076
 
1077
1077
  func (requireYield) Name() string { return "require-yield" }
1078
1078
  func (requireYield) Visits() []shimast.Kind {
1079
- return []shimast.Kind{shimast.KindFunctionDeclaration, shimast.KindFunctionExpression, shimast.KindMethodDeclaration}
1079
+ return []shimast.Kind{shimast.KindFunctionDeclaration, shimast.KindFunctionExpression, shimast.KindMethodDeclaration}
1080
1080
  }
1081
1081
  func (requireYield) Check(ctx *Context, node *shimast.Node) {
1082
- if !hasAsteriskModifier(node) {
1083
- return
1084
- }
1085
- body := node.Body()
1086
- if body == nil {
1087
- return
1088
- }
1089
- if !subtreeContainsYield(body) {
1090
- ctx.Report(node, "This generator function does not have 'yield'.")
1091
- }
1082
+ if !hasAsteriskModifier(node) {
1083
+ return
1084
+ }
1085
+ body := node.Body()
1086
+ if body == nil {
1087
+ return
1088
+ }
1089
+ if !subtreeContainsYield(body) {
1090
+ ctx.Report(node, "This generator function does not have 'yield'.")
1091
+ }
1092
1092
  }
1093
1093
 
1094
1094
  func hasAsteriskModifier(node *shimast.Node) bool {
1095
- if node == nil {
1096
- return false
1097
- }
1098
- switch node.Kind {
1099
- case shimast.KindFunctionDeclaration:
1100
- decl := node.AsFunctionDeclaration()
1101
- return decl != nil && decl.AsteriskToken != nil
1102
- case shimast.KindFunctionExpression:
1103
- decl := node.AsFunctionExpression()
1104
- return decl != nil && decl.AsteriskToken != nil
1105
- case shimast.KindMethodDeclaration:
1106
- decl := node.AsMethodDeclaration()
1107
- return decl != nil && decl.AsteriskToken != nil
1108
- }
1109
- return false
1095
+ if node == nil {
1096
+ return false
1097
+ }
1098
+ switch node.Kind {
1099
+ case shimast.KindFunctionDeclaration:
1100
+ decl := node.AsFunctionDeclaration()
1101
+ return decl != nil && decl.AsteriskToken != nil
1102
+ case shimast.KindFunctionExpression:
1103
+ decl := node.AsFunctionExpression()
1104
+ return decl != nil && decl.AsteriskToken != nil
1105
+ case shimast.KindMethodDeclaration:
1106
+ decl := node.AsMethodDeclaration()
1107
+ return decl != nil && decl.AsteriskToken != nil
1108
+ }
1109
+ return false
1110
1110
  }
1111
1111
 
1112
1112
  func subtreeContainsYield(node *shimast.Node) bool {
1113
- if node == nil {
1114
- return false
1115
- }
1116
- if node.Kind == shimast.KindYieldExpression {
1117
- return true
1118
- }
1119
- if isFunctionLikeKind(node) && node.Parent != nil {
1120
- return false
1121
- }
1122
- found := false
1123
- node.ForEachChild(func(child *shimast.Node) bool {
1124
- if subtreeContainsYield(child) {
1125
- found = true
1126
- return true
1127
- }
1128
- return false
1129
- })
1130
- return found
1113
+ if node == nil {
1114
+ return false
1115
+ }
1116
+ if node.Kind == shimast.KindYieldExpression {
1117
+ return true
1118
+ }
1119
+ if isFunctionLikeKind(node) && node.Parent != nil {
1120
+ return false
1121
+ }
1122
+ found := false
1123
+ node.ForEachChild(func(child *shimast.Node) bool {
1124
+ if subtreeContainsYield(child) {
1125
+ found = true
1126
+ return true
1127
+ }
1128
+ return false
1129
+ })
1130
+ return found
1131
1131
  }
1132
1132
 
1133
1133
  // vars-on-top: `var` declarations should appear at the top of their
@@ -1137,65 +1137,65 @@ type varsOnTop struct{}
1137
1137
  func (varsOnTop) Name() string { return "vars-on-top" }
1138
1138
  func (varsOnTop) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindVariableStatement} }
1139
1139
  func (varsOnTop) Check(ctx *Context, node *shimast.Node) {
1140
- stmt := node.AsVariableStatement()
1141
- if stmt == nil || stmt.DeclarationList == nil {
1142
- return
1143
- }
1144
- if !shimast.IsVar(stmt.DeclarationList) {
1145
- return
1146
- }
1147
- parent := node.Parent
1148
- if parent == nil {
1149
- return
1150
- }
1151
- switch parent.Kind {
1152
- case shimast.KindSourceFile, shimast.KindModuleBlock:
1153
- case shimast.KindBlock:
1154
- grand := parent.Parent
1155
- if grand == nil || !isFunctionLikeKind(grand) {
1156
- ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1157
- return
1158
- }
1159
- default:
1160
- ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1161
- return
1162
- }
1163
- // Same-block: must be the first non-trivial statement.
1164
- siblings := parentStatements(parent)
1165
- for _, sib := range siblings {
1166
- if sib == node {
1167
- return
1168
- }
1169
- if sib.Kind == shimast.KindVariableStatement {
1170
- continue
1171
- }
1172
- ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1173
- return
1174
- }
1140
+ stmt := node.AsVariableStatement()
1141
+ if stmt == nil || stmt.DeclarationList == nil {
1142
+ return
1143
+ }
1144
+ if !shimast.IsVar(stmt.DeclarationList) {
1145
+ return
1146
+ }
1147
+ parent := node.Parent
1148
+ if parent == nil {
1149
+ return
1150
+ }
1151
+ switch parent.Kind {
1152
+ case shimast.KindSourceFile, shimast.KindModuleBlock:
1153
+ case shimast.KindBlock:
1154
+ grand := parent.Parent
1155
+ if grand == nil || !isFunctionLikeKind(grand) {
1156
+ ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1157
+ return
1158
+ }
1159
+ default:
1160
+ ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1161
+ return
1162
+ }
1163
+ // Same-block: must be the first non-trivial statement.
1164
+ siblings := parentStatements(parent)
1165
+ for _, sib := range siblings {
1166
+ if sib == node {
1167
+ return
1168
+ }
1169
+ if sib.Kind == shimast.KindVariableStatement {
1170
+ continue
1171
+ }
1172
+ ctx.Report(node, "All 'var' declarations must be at the top of the function scope.")
1173
+ return
1174
+ }
1175
1175
  }
1176
1176
 
1177
1177
  func parentStatements(parent *shimast.Node) []*shimast.Node {
1178
- if parent == nil {
1179
- return nil
1180
- }
1181
- switch parent.Kind {
1182
- case shimast.KindBlock:
1183
- block := parent.AsBlock()
1184
- if block != nil && block.Statements != nil {
1185
- return block.Statements.Nodes
1186
- }
1187
- case shimast.KindSourceFile:
1188
- file := parent.AsSourceFile()
1189
- if file != nil && file.Statements != nil {
1190
- return file.Statements.Nodes
1191
- }
1192
- case shimast.KindModuleBlock:
1193
- mb := parent.AsModuleBlock()
1194
- if mb != nil && mb.Statements != nil {
1195
- return mb.Statements.Nodes
1196
- }
1197
- }
1198
- return nil
1178
+ if parent == nil {
1179
+ return nil
1180
+ }
1181
+ switch parent.Kind {
1182
+ case shimast.KindBlock:
1183
+ block := parent.AsBlock()
1184
+ if block != nil && block.Statements != nil {
1185
+ return block.Statements.Nodes
1186
+ }
1187
+ case shimast.KindSourceFile:
1188
+ file := parent.AsSourceFile()
1189
+ if file != nil && file.Statements != nil {
1190
+ return file.Statements.Nodes
1191
+ }
1192
+ case shimast.KindModuleBlock:
1193
+ mb := parent.AsModuleBlock()
1194
+ if mb != nil && mb.Statements != nil {
1195
+ return mb.Statements.Nodes
1196
+ }
1197
+ }
1198
+ return nil
1199
1199
  }
1200
1200
 
1201
1201
  // yoda: `if (1 === x)` — ESLint flags literals on the left of a
@@ -1205,54 +1205,54 @@ type yoda struct{}
1205
1205
  func (yoda) Name() string { return "yoda" }
1206
1206
  func (yoda) Visits() []shimast.Kind { return []shimast.Kind{shimast.KindBinaryExpression} }
1207
1207
  func (yoda) Check(ctx *Context, node *shimast.Node) {
1208
- expr := node.AsBinaryExpression()
1209
- if expr == nil || expr.OperatorToken == nil {
1210
- return
1211
- }
1212
- if !isComparisonOperator(expr.OperatorToken.Kind) {
1213
- return
1214
- }
1215
- if isLiteralExpression(stripParens(expr.Left)) && !isLiteralExpression(stripParens(expr.Right)) {
1216
- ctx.Report(node, "Expected literal to be on the right side of comparison.")
1217
- }
1208
+ expr := node.AsBinaryExpression()
1209
+ if expr == nil || expr.OperatorToken == nil {
1210
+ return
1211
+ }
1212
+ if !isComparisonOperator(expr.OperatorToken.Kind) {
1213
+ return
1214
+ }
1215
+ if isLiteralExpression(stripParens(expr.Left)) && !isLiteralExpression(stripParens(expr.Right)) {
1216
+ ctx.Report(node, "Expected literal to be on the right side of comparison.")
1217
+ }
1218
1218
  }
1219
1219
 
1220
1220
  func init() {
1221
- Register(noAlert{})
1222
- Register(noBitwise{})
1223
- Register(noCaller{})
1224
- Register(noCaseDeclarations{})
1225
- Register(noContinue{})
1226
- Register(noDeleteVar{})
1227
- Register(noEqNull{})
1228
- Register(noExtraBind{})
1229
- Register(noLabels{})
1230
- Register(noLoneBlocks{})
1231
- Register(noLonelyIf{})
1232
- Register(noMultiAssign{})
1233
- Register(noNegatedCondition{})
1234
- Register(noNestedTernary{})
1235
- Register(noNew{})
1236
- Register(noNewFunc{})
1237
- Register(noObjectConstructor{})
1238
- Register(noOctalEscape{})
1239
- Register(noPlusPlus{})
1240
- Register(noRegexSpaces{})
1241
- Register(noReturnAssign{})
1242
- Register(noSequences{})
1243
- Register(noShadowRestrictedNames{})
1244
- Register(noUndefined{})
1245
- Register(noUnneededTernary{})
1246
- Register(noUnusedExpressions{})
1247
- Register(noUselessCall{})
1248
- Register(noUselessComputedKey{})
1249
- Register(noUselessRename{})
1250
- Register(objectShorthand{})
1251
- Register(operatorAssignment{})
1252
- Register(preferExponentiationOperator{})
1253
- Register(preferSpread{})
1254
- Register(preferTemplate{})
1255
- Register(requireYield{})
1256
- Register(varsOnTop{})
1257
- Register(yoda{})
1221
+ Register(noAlert{})
1222
+ Register(noBitwise{})
1223
+ Register(noCaller{})
1224
+ Register(noCaseDeclarations{})
1225
+ Register(noContinue{})
1226
+ Register(noDeleteVar{})
1227
+ Register(noEqNull{})
1228
+ Register(noExtraBind{})
1229
+ Register(noLabels{})
1230
+ Register(noLoneBlocks{})
1231
+ Register(noLonelyIf{})
1232
+ Register(noMultiAssign{})
1233
+ Register(noNegatedCondition{})
1234
+ Register(noNestedTernary{})
1235
+ Register(noNew{})
1236
+ Register(noNewFunc{})
1237
+ Register(noObjectConstructor{})
1238
+ Register(noOctalEscape{})
1239
+ Register(noPlusPlus{})
1240
+ Register(noRegexSpaces{})
1241
+ Register(noReturnAssign{})
1242
+ Register(noSequences{})
1243
+ Register(noShadowRestrictedNames{})
1244
+ Register(noUndefined{})
1245
+ Register(noUnneededTernary{})
1246
+ Register(noUnusedExpressions{})
1247
+ Register(noUselessCall{})
1248
+ Register(noUselessComputedKey{})
1249
+ Register(noUselessRename{})
1250
+ Register(objectShorthand{})
1251
+ Register(operatorAssignment{})
1252
+ Register(preferExponentiationOperator{})
1253
+ Register(preferSpread{})
1254
+ Register(preferTemplate{})
1255
+ Register(requireYield{})
1256
+ Register(varsOnTop{})
1257
+ Register(yoda{})
1258
1258
  }