Skip to content

Commit dd3aefc

Browse files
committed
improve location of warnings
1 parent 33a3f57 commit dd3aefc

File tree

3 files changed

+40
-13
lines changed

3 files changed

+40
-13
lines changed

src/rules/deprecatedProps.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ParserServices, TSESLint, TSESTree } from '@typescript-eslint/experimen
22
import ts from 'typescript';
33

44
interface JSDocProperty {
5+
node: TSESTree.JSXIdentifier;
56
name: string;
67
tag: string;
78
description?: string;
@@ -87,16 +88,20 @@ export default {
8788

8889
const ancestors = context.getAncestors();
8990
const openingJsxElement = getOpeningElement(ancestors);
90-
const attributeNames =
91-
openingJsxElement?.attributes
92-
.filter((attribute) => attribute.type === 'JSXAttribute')
93-
.map((attribute) => attribute.name.name) ?? [];
91+
const attributeElements =
92+
openingJsxElement?.attributes.filter((attribute) => attribute.type === 'JSXAttribute') ??
93+
[];
9494

9595
// If the JSX element has no props
96-
if (attributeNames.length === 0) {
96+
if (attributeElements.length === 0) {
9797
return false;
9898
}
9999

100+
const attributeMap = attributeElements.reduce(
101+
(memo, element) => ({ ...memo, [element.name.name]: element }),
102+
{},
103+
) as Record<string, TSESTree.JSXAttribute>;
104+
100105
// Get JSDoc from parent def (source file)
101106
const sourceFileDeclaration =
102107
symbol != null ? getSourceFileParent(symbol.valueDeclaration) : null; // Need parent
@@ -127,11 +132,12 @@ export default {
127132
.filter(
128133
(property) =>
129134
property.doc.some((tag) => tag.name === 'deprecated') &&
130-
attributeNames.includes(property.name),
135+
attributeMap[property.name] != null,
131136
)
132137
.map((property) => {
133138
const deprecated = property.doc.find((tag) => tag.name === 'deprecated');
134139
return {
140+
node: attributeMap[property.name].name,
135141
name: property.name,
136142
tag: deprecated!.name,
137143
description: deprecated?.text,
@@ -143,7 +149,7 @@ export default {
143149

144150
for (const report of deprecatedPropReports) {
145151
context.report({
146-
node,
152+
node: report.node,
147153
messageId: 'avoidDeprecated',
148154
data: {
149155
name: report.name,

tests/integration/__tests__/avoid-deprecated.test.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,28 @@ describe('avoidDeprecated', () => {
2727
expect(errorCount).toEqual(0);
2828
});
2929

30-
it('generates the right warning', () => {
30+
it('matches the message pattern', () => {
3131
const { messages } = res.results[0]!;
32-
3332
const text = messages[0].message;
33+
3434
expect(text).toMatch(stringPattern);
3535
});
3636

3737
it('generates exactly the right warning', () => {
3838
const { messages } = res.results[0]!;
39-
4039
const text = messages[0].message;
40+
4141
expect(text).toMatch(`Avoid using 'category' since it's deprecated. use color instead`);
4242
});
43+
44+
it('the warning is at the right position', () => {
45+
const { messages } = res.results[0]!;
46+
const { column, line, endColumn } = messages[0];
47+
48+
expect(line).toEqual(7);
49+
expect(column).toEqual(31);
50+
expect(endColumn).toEqual(39);
51+
});
4352
});
4453

4554
describe('when the component interface is in the same file', () => {
@@ -57,7 +66,7 @@ describe('avoidDeprecated', () => {
5766
expect(errorCount).toEqual(0);
5867
});
5968

60-
it('generates the right warnings', () => {
69+
it('matches the message pattern', () => {
6170
const { messages } = res.results[0]!;
6271

6372
const text1 = messages[0].message;
@@ -76,6 +85,18 @@ describe('avoidDeprecated', () => {
7685
const text2 = messages[1].message;
7786
expect(text2).toMatch(`Avoid using 'someProp2' since it's deprecated. reason2`);
7887
});
88+
89+
it('the warnings are at the right position', () => {
90+
const { messages } = res.results[0]!;
91+
92+
expect(messages[0].line).toEqual(27);
93+
expect(messages[0].column).toEqual(18);
94+
expect(messages[0].endColumn).toEqual(26);
95+
96+
expect(messages[1].line).toEqual(27);
97+
expect(messages[1].column).toEqual(30);
98+
expect(messages[1].endColumn).toEqual(39);
99+
});
79100
});
80101

81102
describe('when the component interface extends from another interface', () => {
@@ -93,7 +114,7 @@ describe('avoidDeprecated', () => {
93114
expect(errorCount).toEqual(0);
94115
});
95116

96-
it('generates the right warning', () => {
117+
it('matches the message pattern', () => {
97118
const { messages } = res.results[0]!;
98119

99120
const text = messages[0].message;

tests/integration/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"private": true,
33
"name": "eslint-plugin-deprecated-props-tester",
44
"scripts": {
5-
"lint": "eslint --config ./.eslintrc.js --ext .tsx ./local-definition-extends-external.tsx",
5+
"lint": "eslint --config ./.eslintrc.js --ext .tsx ./external-definition.tsx",
66
"test": "jest --config ../../jest.config.js"
77
},
88
"devDependencies": {

0 commit comments

Comments
 (0)