Skip to content

Commit

Permalink
feat: use singular array element variable name in autofix for `no-for…
Browse files Browse the repository at this point in the history
…-loop` rule

If the loop is iterating an array with a plural name (such as `plugins`), the generated element variable in the autofix could use the singular version of the array name (`plugin`), instead of just the generic name `element`.
  • Loading branch information
bmish committed May 27, 2020
1 parent 48bd5c8 commit 9fa0424
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 1 deletion.
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -40,6 +40,7 @@
"eslint-utils": "^2.0.0",
"import-modules": "^2.0.0",
"lodash": "^4.17.15",
"pluralize": "^8.0.0",
"read-pkg-up": "^7.0.1",
"regexp-tree": "^0.1.21",
"reserved-words": "^0.1.2",
Expand Down
16 changes: 15 additions & 1 deletion rules/no-for-loop.js
Expand Up @@ -3,6 +3,7 @@ const getDocumentationUrl = require('./utils/get-documentation-url');
const isLiteralValue = require('./utils/is-literal-value');
const {flatten} = require('lodash');
const avoidCapture = require('./utils/avoid-capture');
const {singular} = require('pluralize');

const defaultElementName = 'element';
const isLiteralZero = node => isLiteralValue(node, 0);
Expand Down Expand Up @@ -267,6 +268,19 @@ const getChildScopesRecursive = scope => [
...flatten(scope.childScopes.map(scope => getChildScopesRecursive(scope)))
];

const getSingularName = originalName => {
const singularName = singular(originalName);
if (
!singularName ||
singularName === originalName
) {
// Bail if we can't produce a singular name that differs from the original name.
return;
}

return singularName;
};

const create = context => {
const sourceCode = context.getSourceCode();
const {scopeManager} = sourceCode;
Expand Down Expand Up @@ -342,7 +356,7 @@ const create = context => {

const index = indexIdentifierName;
const element = elementIdentifierName ||
avoidCapture(defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion);
avoidCapture(getSingularName(arrayIdentifierName) || defaultElementName, getChildScopesRecursive(bodyScope), context.parserOptions.ecmaVersion);
const array = arrayIdentifierName;

let declarationElement = element;
Expand Down
51 changes: 51 additions & 0 deletions test/no-for-loop.js
Expand Up @@ -649,6 +649,57 @@ ruleTester.run('no-for-loop', rule, {
console.log(element);
console.log(element_);
}
`),

// Singularization (simple case):
testCase(outdent`
for (let i = 0; i < plugins.length; i++) {
console.log(plugins[i]);
}
`, outdent`
for (const plugin of plugins) {
console.log(plugin);
}
`),
// Singularization (irregular case):
testCase(outdent`
for (let i = 0; i < people.length; i++) {
console.log(people[i]);
}
`, outdent`
for (const person of people) {
console.log(person);
}
`),
// Singularization (avoid using reserved JavaScript keywords):
testCase(outdent`
for (let i = 0; i < cases.length; i++) {
console.log(cases[i]);
}
`, outdent`
for (const case_ of cases) {
console.log(case_);
}
`),
// Singularization (camelCase):
testCase(outdent`
for (let i = 0; i < largeCities.length; i++) {
console.log(largeCities[i]);
}
`, outdent`
for (const largeCity of largeCities) {
console.log(largeCity);
}
`),
// Singularization (capital letters, multiple words):
testCase(outdent`
for (let i = 0; i < LARGE_CITIES.length; i++) {
console.log(LARGE_CITIES[i]);
}
`, outdent`
for (const LARGE_CITY of LARGE_CITIES) {
console.log(LARGE_CITY);
}
`)
]
});
Expand Down

0 comments on commit 9fa0424

Please sign in to comment.