Skip to content

Commit fdeba42

Browse files
fix(eslint-plugin): [no-for-in-array] refine report location (#8874)
* [no-for-in-array] refine report location * move code to util * lint check * update snapshot
1 parent eef257b commit fdeba42

File tree

4 files changed

+121
-14
lines changed

4 files changed

+121
-14
lines changed

packages/eslint-plugin/src/rules/no-for-in-array.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
getParserServices,
77
isTypeArrayTypeOrUnionOfArrayTypes,
88
} from '../util';
9+
import { getForStatementHeadLoc } from '../util/getForStatementHeadLoc';
910

1011
export default createRule({
1112
name: 'no-for-in-array',
@@ -36,7 +37,7 @@ export default createRule({
3637
(type.flags & ts.TypeFlags.StringLike) !== 0
3738
) {
3839
context.report({
39-
node,
40+
loc: getForStatementHeadLoc(context.sourceCode, node),
4041
messageId: 'forInViolation',
4142
});
4243
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import type { TSESLint, TSESTree } from '@typescript-eslint/utils';
2+
import { nullThrows } from '@typescript-eslint/utils/eslint-utils';
3+
4+
/**
5+
* Gets the location of the head of the given for statement variant for reporting.
6+
*
7+
* - `for (const foo in bar) expressionOrBlock`
8+
* ^^^^^^^^^^^^^^^^^^^^^^
9+
*
10+
* - `for (const foo of bar) expressionOrBlock`
11+
* ^^^^^^^^^^^^^^^^^^^^^^
12+
*
13+
* - `for await (const foo of bar) expressionOrBlock`
14+
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
15+
*
16+
* - `for (let i = 0; i < 10; i++) expressionOrBlock`
17+
* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
18+
*/
19+
export function getForStatementHeadLoc(
20+
sourceCode: TSESLint.SourceCode,
21+
node:
22+
| TSESTree.ForInStatement
23+
| TSESTree.ForOfStatement
24+
| TSESTree.ForStatement,
25+
): TSESTree.SourceLocation {
26+
const closingParens = nullThrows(
27+
sourceCode.getTokenBefore(node.body, token => token.value === ')'),
28+
'for statement must have a closing parenthesis.',
29+
);
30+
return {
31+
start: structuredClone(node.loc.start),
32+
end: structuredClone(closingParens.loc.end),
33+
};
34+
}

packages/eslint-plugin/tests/docs-eslint-output-snapshots/no-for-in-array.shot

+2-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/eslint-plugin/tests/rules/no-for-in-array.test.ts

+83-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import { RuleTester } from '@typescript-eslint/rule-tester';
2-
import { AST_NODE_TYPES } from '@typescript-eslint/utils';
1+
import { noFormat, RuleTester } from '@typescript-eslint/rule-tester';
32

43
import rule from '../../src/rules/no-for-in-array';
54
import { getFixturesRootDir } from '../RuleTester';
@@ -38,7 +37,10 @@ for (const x in [3, 4, 5]) {
3837
errors: [
3938
{
4039
messageId: 'forInViolation',
41-
type: AST_NODE_TYPES.ForInStatement,
40+
line: 2,
41+
column: 1,
42+
endLine: 2,
43+
endColumn: 27,
4244
},
4345
],
4446
},
@@ -52,7 +54,10 @@ for (const x in z) {
5254
errors: [
5355
{
5456
messageId: 'forInViolation',
55-
type: AST_NODE_TYPES.ForInStatement,
57+
line: 3,
58+
column: 1,
59+
endLine: 3,
60+
endColumn: 19,
5661
},
5762
],
5863
},
@@ -67,7 +72,10 @@ const fn = (arr: number[]) => {
6772
errors: [
6873
{
6974
messageId: 'forInViolation',
70-
type: AST_NODE_TYPES.ForInStatement,
75+
line: 3,
76+
column: 3,
77+
endLine: 3,
78+
endColumn: 23,
7179
},
7280
],
7381
},
@@ -82,7 +90,10 @@ const fn = (arr: number[] | string[]) => {
8290
errors: [
8391
{
8492
messageId: 'forInViolation',
85-
type: AST_NODE_TYPES.ForInStatement,
93+
line: 3,
94+
column: 3,
95+
endLine: 3,
96+
endColumn: 23,
8697
},
8798
],
8899
},
@@ -97,7 +108,72 @@ const fn = <T extends any[]>(arr: T) => {
97108
errors: [
98109
{
99110
messageId: 'forInViolation',
100-
type: AST_NODE_TYPES.ForInStatement,
111+
line: 3,
112+
column: 3,
113+
endLine: 3,
114+
endColumn: 23,
115+
},
116+
],
117+
},
118+
{
119+
code: noFormat`
120+
for (const x
121+
in
122+
(
123+
(
124+
(
125+
[3, 4, 5]
126+
)
127+
)
128+
)
129+
)
130+
// weird
131+
/* spot for a */
132+
// comment
133+
/* ) */
134+
/* ( */
135+
{
136+
console.log(x);
137+
}
138+
`,
139+
errors: [
140+
{
141+
messageId: 'forInViolation',
142+
line: 2,
143+
column: 1,
144+
endLine: 11,
145+
endColumn: 4,
146+
},
147+
],
148+
},
149+
{
150+
code: noFormat`
151+
for (const x
152+
in
153+
(
154+
(
155+
(
156+
[3, 4, 5]
157+
)
158+
)
159+
)
160+
)
161+
// weird
162+
/* spot for a */
163+
// comment
164+
/* ) */
165+
/* ( */
166+
167+
((((console.log('body without braces ')))));
168+
169+
`,
170+
errors: [
171+
{
172+
messageId: 'forInViolation',
173+
line: 2,
174+
column: 1,
175+
endLine: 11,
176+
endColumn: 4,
101177
},
102178
],
103179
},

0 commit comments

Comments
 (0)