Skip to content

Commit

Permalink
Fix FP S6479 (no-array-index-key) - Allow keys combining index and …
Browse files Browse the repository at this point in the history
…other values (#4556)

Co-authored-by: Yassin Kammoun <52890329+yassin-kammoun-sonarsource@users.noreply.github.com>
  • Loading branch information
1 parent 8cf4d4f commit 371e71e
Show file tree
Hide file tree
Showing 10 changed files with 180 additions and 33 deletions.
3 changes: 0 additions & 3 deletions its/ruling/src/test/expected/jsts/Joust/typescript-S6479.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"Joust:ts/components/EventLog.tsx": [
108
],
"Joust:ts/components/Timeline.tsx": [
144
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"ant-design:components/badge/ScrollNumber.tsx": [
59
],
"ant-design:components/card/Card.tsx": [
48
],
Expand All @@ -14,9 +11,6 @@
"ant-design:components/descriptions/index.tsx": [
182
],
"ant-design:components/list/Item.tsx": [
99
],
"ant-design:components/skeleton/Paragraph.tsx": [
29
],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"desktop:app/src/ui/changes/no-changes.tsx": [
216
],
"desktop:app/src/ui/check-runs/ci-check-run-actions-job-step-list.tsx": [
43
],
Expand Down
6 changes: 0 additions & 6 deletions its/ruling/src/test/expected/jsts/eigen/typescript-S6479.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,6 @@
"eigen:src/palette/elements/Tabs/ContentTabs.tsx": [
17
],
"eigen:src/palette/elements/Tabs/NavigationalTabs.tsx": [
30
],
"eigen:src/palette/elements/Tabs/StepTabs.tsx": [
27
],
"eigen:src/palette/elements/Tabs/Tabs.tests.tsx": [
51
]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
{
"react-cloud-music:src/application/Player/normal-player/index.jsx": [
236
],
"react-cloud-music:src/application/Rank/index.jsx": [
37,
49
],
"react-cloud-music:src/application/Search/index.jsx": [
98,
122
],
"react-cloud-music:src/application/Singers/index.jsx": [
64
37
],
"react-cloud-music:src/application/User/Login/PhoneForm/step-two/index.jsx": [
76
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
"vuetify:packages/vuetify/src/components/VCombobox/VCombobox.tsx": [
408
],
"vuetify:packages/vuetify/src/components/VMessages/VMessages.tsx": [
66
],
"vuetify:packages/vuetify/src/components/VSelect/VSelect.tsx": [
286
],
Expand Down
20 changes: 20 additions & 0 deletions packages/jsts/src/rules/S6479/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
export { rule } from './rule';
48 changes: 48 additions & 0 deletions packages/jsts/src/rules/S6479/rule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
// https://sonarsource.github.io/rspec/#/rspec/S6479/javascript

// inspired from `no-array-index` from `eslint-plugin-react`:
// https://github.com/jsx-eslint/eslint-plugin-react/blob/0a2f6b7e9df32215fcd4e3061ec69ea3f2eef793/lib/rules/no-array-index-key.js#L16

import { rules } from 'eslint-plugin-react';
import { interceptReportForReact } from '../helpers';
import { Rule } from 'eslint';

export const rule = interceptReportForReact(
rules['no-array-index-key'],
(context, reportDescriptor) => {
const { node } = reportDescriptor as Rule.ReportDescriptor & {
node: Rule.Node;
};

if (node.type === 'BinaryExpression') {
return;
}

// we got a report from ESLint, hence one of the expressions included in the literal _is_ the array index
// we can then safely bail if there is another expression in the literal
if (node.type === 'TemplateLiteral' && node.expressions.length > 1) {
return;
}

context.report(reportDescriptor);
},
);
109 changes: 109 additions & 0 deletions packages/jsts/src/rules/S6479/unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* SonarQube JavaScript Plugin
* Copyright (C) 2011-2024 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { JavaScriptRuleTester } from '../tools';
import { rule } from './rule';

const ruleTester = new JavaScriptRuleTester();

ruleTester.run('Rule S6479 - no-array-index-key', rule, {
valid: [
{
code: `
export const MyComponent = ({items}) => {
return <>{items.map((item, index) => {
return <div key={item.id + '' + index}/>;
})}</>;
}
`,
},
{
code: `
export const MyComponent = ({items}) => {
return <>{items.map((item, index) => {
return <div key={\`\${item.id}-\${index}\`}/>;
})}</>;
}
`,
},
{
code: `
export const MyComponent = ({items}) => {
const renderItems = () => {
let i = 0;
return items.map(() => {
return <div key={i++}/>;
});
}
return <>{renderItems()}</>;
}
`,
},
{
code: `
export const MyComponent = ({items}) => {
const computeKey = (item, index) => {
return item.id + '' + index;
}
return <>{items.map((item, index) => {
return <div key={computeKey(item, index)}/>;
})}</>;
}
`,
},
{
code: `
export const MyComponent = ({items}) => {
const computeKey = (index) => {
return index;
}
return <>{items.map((_item, index) => {
return <div key={computeKey(index)}/>;
})}</>;
} // this test should trigger the rule but it seems ESLint is missing it
`,
},
],
invalid: [
{
code: `
export const MyComponent = ({items}) => {
return <>{items.map((item, index) => {
return <div key={index}>{item.id}</div>;
})}</>;
}
`,
errors: 1,
},
{
code: `
export const MyComponent = ({items}) => {
return <>{items.map((item, index) => {
return <div key={\`\${index}\`}>{item.id}</div>;
})}</>;
}
`,
errors: 1,
},
],
});
2 changes: 2 additions & 0 deletions packages/jsts/src/rules/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ import { rule as S2817 } from './S2817'; // web-sql-database
import { rule as S5689 } from './S5689'; // x-powered-by
import { rule as S2755 } from './S2755'; // xml-parser-xxe
import { rule as S4817 } from './S4817'; // xpath
import { rule as S6479 } from './S6479'; // no-array-index-key

/**
* Maps ESLint rule keys declared in the JavaScript checks to rule implementations
Expand Down Expand Up @@ -587,5 +588,6 @@ rules['web-sql-database'] = S2817;
rules['x-powered-by'] = S5689;
rules['xml-parser-xxe'] = S2755;
rules['xpath'] = S4817;
rules['no-array-index-key'] = S6479;

export { rules };

0 comments on commit 371e71e

Please sign in to comment.