Umama-at-Bluchip/Quick-UI
0
1/**2 * @fileoverview Rule that warns when identifier names are shorter or longer3 * than the values provided in configuration.4 * @author Burak Yigit Kaya aka BYK5 */6 7"use strict";8 9//------------------------------------------------------------------------------10// Requirements11//------------------------------------------------------------------------------12 13const { getGraphemeCount } = require("../shared/string-utils");14 15//------------------------------------------------------------------------------16// Rule Definition17//------------------------------------------------------------------------------18 19/** @type {import('../shared/types').Rule} */20module.exports = {21 meta: {22 type: "suggestion",23 24 docs: {25 description: "Enforce minimum and maximum identifier lengths",26 recommended: false,27 url: "https://eslint.org/docs/latest/rules/id-length"28 },29 30 schema: [31 {32 type: "object",33 properties: {34 min: {35 type: "integer",36 default: 237 },38 max: {39 type: "integer"40 },41 exceptions: {42 type: "array",43 uniqueItems: true,44 items: {45 type: "string"46 }47 },48 exceptionPatterns: {49 type: "array",50 uniqueItems: true,51 items: {52 type: "string"53 }54 },55 properties: {56 enum: ["always", "never"]57 }58 },59 additionalProperties: false60 }61 ],62 messages: {63 tooShort: "Identifier name '{{name}}' is too short (< {{min}}).",64 tooShortPrivate: "Identifier name '#{{name}}' is too short (< {{min}}).",65 tooLong: "Identifier name '{{name}}' is too long (> {{max}}).",66 tooLongPrivate: "Identifier name #'{{name}}' is too long (> {{max}})."67 }68 },69 70 create(context) {71 const options = context.options[0] || {};72 const minLength = typeof options.min !== "undefined" ? options.min : 2;73 const maxLength = typeof options.max !== "undefined" ? options.max : Infinity;74 const properties = options.properties !== "never";75 const exceptions = new Set(options.exceptions);76 const exceptionPatterns = (options.exceptionPatterns || []).map(pattern => new RegExp(pattern, "u"));77 const reportedNodes = new Set();78 79 /**80 * Checks if a string matches the provided exception patterns81 * @param {string} name The string to check.82 * @returns {boolean} if the string is a match83 * @private84 */85 function matchesExceptionPattern(name) {86 return exceptionPatterns.some(pattern => pattern.test(name));87 }88 89 const SUPPORTED_EXPRESSIONS = {90 MemberExpression: properties && function(parent) {91 return !parent.computed && (92 93 // regular property assignment94 (parent.parent.left === parent && parent.parent.type === "AssignmentExpression" ||95 96 // or the last identifier in an ObjectPattern destructuring97 parent.parent.type === "Property" && parent.parent.value === parent &&98 parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent)99 );100 },101 AssignmentPattern(parent, node) {102 return parent.left === node;103 },104 VariableDeclarator(parent, node) {105 return parent.id === node;106 },107 Property(parent, node) {108 109 if (parent.parent.type === "ObjectPattern") {110 const isKeyAndValueSame = parent.value.name === parent.key.name;111 112 return (113 !isKeyAndValueSame && parent.value === node ||114 isKeyAndValueSame && parent.key === node && properties115 );116 }117 return properties && !parent.computed && parent.key.name === node.name;118 },119 ImportDefaultSpecifier: true,120 RestElement: true,121 FunctionExpression: true,122 ArrowFunctionExpression: true,123 ClassDeclaration: true,124 FunctionDeclaration: true,125 MethodDefinition: true,126 PropertyDefinition: true,127 CatchClause: true,128 ArrayPattern: true129 };130 131 return {132 [[133 "Identifier",134 "PrivateIdentifier"135 ]](node) {136 const name = node.name;137 const parent = node.parent;138 139 const nameLength = getGraphemeCount(name);140 141 const isShort = nameLength < minLength;142 const isLong = nameLength > maxLength;143 144 if (!(isShort || isLong) || exceptions.has(name) || matchesExceptionPattern(name)) {145 return; // Nothing to report146 }147 148 const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];149 150 /*151 * We used the range instead of the node because it's possible152 * for the same identifier to be represented by two different153 * nodes, with the most clear example being shorthand properties:154 * { foo }155 * In this case, "foo" is represented by one node for the name156 * and one for the value. The only way to know they are the same157 * is to look at the range.158 */159 if (isValidExpression && !reportedNodes.has(node.range.toString()) && (isValidExpression === true || isValidExpression(parent, node))) {160 reportedNodes.add(node.range.toString());161 162 let messageId = isShort ? "tooShort" : "tooLong";163 164 if (node.type === "PrivateIdentifier") {165 messageId += "Private";166 }167 168 context.report({169 node,170 messageId,171 data: { name, min: minLength, max: maxLength }172 });173 }174 }175 };176 }177};178 