eslint-plugin-array-plural
Version:
ESLint plugin to force usage of plural noun to name array variables
143 lines (125 loc) • 3.52 kB
JavaScript
/**
* @fileoverview Force usage of plural nouns to name array variables
* @author Koki Takahashi
*/
const inflected = require('inflected');
const {noCase} = require('no-case');
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: 'Force usage of plural nouns to name array variables',
category: 'Fill me in',
recommended: false,
},
fixable: null, // or "code" or "whitespace"
schema: [
{
type: 'object',
properties: {
bracket: {
type: 'boolean',
},
allows: {
type: 'array',
items: {
type: 'string',
},
uniqueItems: true,
},
},
additionalProperties: false,
},
],
},
create(context) {
const arrayLikeMethods = ['map', 'split', 'keys', 'values', 'entries'];
const [{bracket = true, allows = ['array', 'list']} = {}] = context.options;
const isPlural = (name) => {
const identifierWords = noCase(name).split(/\s+/);
const lastWord = identifierWords[identifierWords.length - 1];
const pluralized = inflected.pluralize(lastWord).toLowerCase();
const singularized = inflected.singularize(lastWord).toLowerCase();
return allows.indexOf(lastWord) !== -1 || singularized === pluralized || singularized !== lastWord.toLowerCase();
};
const isArrayLike = (node) => {
// [...]
if (node.type === 'ArrayExpression') {
return true;
}
// array.map(...)
if (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.computed === false &&
node.callee.property.type === 'Identifier' &&
arrayLikeMethods.indexOf(node.callee.property.name) !== -1
) {
return true;
}
// new Array(...)
if (
node.type === 'NewExpression' &&
node.callee.type === 'Identifier' &&
node.callee.name === 'Array'
) {
return true;
}
// Array.from(...)
if (
node.type === 'CallExpression' &&
node.callee.type === 'MemberExpression' &&
node.callee.computed === false &&
node.callee.object.type === 'Identifier' &&
node.callee.object.name === 'Array' &&
node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'from'
) {
return true;
}
return false;
};
return {
VariableDeclarator: (node) => {
if (
node.id.type !== 'Identifier' ||
node.init === null ||
!isArrayLike(node.init)
) {
return;
}
if (!isPlural(node.id.name)) {
context.report(node.id, 'Use plural nouns to name array variable');
}
},
AssignmentExpression: (node) => {
if (
node.operator !== '=' ||
node.left.type !== 'Identifier' ||
!isArrayLike(node.right)
) {
return;
}
if (!isPlural(node.left.name)) {
context.report(node.left, 'Use plural nouns to name array variable');
}
},
MemberExpression: (node) => {
if (
!bracket ||
node.computed === false ||
node.object.type !== 'Identifier' ||
node.property.type !== 'Literal' ||
typeof node.property.value !== 'number'
) {
return;
}
if (!isPlural(node.object.name)) {
context.report(node.object, 'Use plural nouns to name array variable');
}
},
};
},
};