Skip to content

Commit 2002093

Browse files
authored
Use singular array element variable name in autofix for no-for-loop rule (#745)
1 parent 48bd5c8 commit 2002093

File tree

3 files changed

+61
-1
lines changed

3 files changed

+61
-1
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
"eslint-utils": "^2.0.0",
4141
"import-modules": "^2.0.0",
4242
"lodash": "^4.17.15",
43+
"pluralize": "^8.0.0",
4344
"read-pkg-up": "^7.0.1",
4445
"regexp-tree": "^0.1.21",
4546
"reserved-words": "^0.1.2",

rules/no-for-loop.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ const getDocumentationUrl = require('./utils/get-documentation-url');
33
const isLiteralValue = require('./utils/is-literal-value');
44
const {flatten} = require('lodash');
55
const avoidCapture = require('./utils/avoid-capture');
6+
const {singular} = require('pluralize');
67

78
const defaultElementName = 'element';
89
const isLiteralZero = node => isLiteralValue(node, 0);
@@ -267,6 +268,13 @@ const getChildScopesRecursive = scope => [
267268
...flatten(scope.childScopes.map(scope => getChildScopesRecursive(scope)))
268269
];
269270

271+
const getSingularName = originalName => {
272+
const singularName = singular(originalName);
273+
if (singularName !== originalName) {
274+
return singularName;
275+
}
276+
};
277+
270278
const create = context => {
271279
const sourceCode = context.getSourceCode();
272280
const {scopeManager} = sourceCode;
@@ -342,7 +350,7 @@ const create = context => {
342350

343351
const index = indexIdentifierName;
344352
const element = elementIdentifierName ||
345-
avoidCapture(defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion);
353+
avoidCapture(getSingularName(arrayIdentifierName) || defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion);
346354
const array = arrayIdentifierName;
347355

348356
let declarationElement = element;

test/no-for-loop.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,57 @@ ruleTester.run('no-for-loop', rule, {
649649
console.log(element);
650650
console.log(element_);
651651
}
652+
`),
653+
654+
// Singularization:
655+
...[
656+
['plugin', 'plugins'], // Simple
657+
['person', 'people'], // Irregular
658+
['girlsAndBoy', 'girlsAndBoys'], // Multiple plurals
659+
['largeCity', 'largeCities'], // CamelCase
660+
['LARGE_CITY', 'LARGE_CITIES'], // Caps, snake_case
661+
['element', 'news'], // No singular version, ends in s
662+
['element', 'list'] // No singular version
663+
].map(([elementName, arrayName]) =>
664+
testCase(
665+
`for(const i = 0; i < ${arrayName}.length; i++) {console.log(${arrayName}[i])}`,
666+
`for(const ${elementName} of ${arrayName}) {console.log(${elementName})}`
667+
)
668+
),
669+
670+
// Singularization (avoid using reserved JavaScript keywords):
671+
testCase(outdent`
672+
for (let i = 0; i < cases.length; i++) {
673+
console.log(cases[i]);
674+
}
675+
`, outdent`
676+
for (const case_ of cases) {
677+
console.log(case_);
678+
}
679+
`),
680+
// Singularization (avoid variable name collision):
681+
testCase(outdent`
682+
for (let i = 0; i < cities.length; i++) {
683+
console.log(cities[i]);
684+
const city = foo();
685+
console.log(city);
686+
}
687+
`, outdent`
688+
for (const city_ of cities) {
689+
console.log(city_);
690+
const city = foo();
691+
console.log(city);
692+
}
693+
`),
694+
// Singularization (uses i):
695+
testCase(outdent`
696+
for (let i = 0; i < cities.length; i++) {
697+
console.log(i, cities[i]);
698+
}
699+
`, outdent`
700+
for (const [i, city] of cities.entries()) {
701+
console.log(i, city);
702+
}
652703
`)
653704
]
654705
});

0 commit comments

Comments
 (0)