| |
| |
| |
| |
| |
| |
| "use strict"; |
|
|
| |
| |
| |
|
|
| const { getGraphemeCount } = require("../shared/string-utils"); |
| const { |
| getModuleExportName, |
| isImportAttributeKey, |
| } = require("./utils/ast-utils"); |
|
|
| |
| |
| |
|
|
| |
| module.exports = { |
| meta: { |
| type: "suggestion", |
|
|
| defaultOptions: [ |
| { |
| exceptionPatterns: [], |
| exceptions: [], |
| min: 2, |
| properties: "always", |
| }, |
| ], |
|
|
| docs: { |
| description: "Enforce minimum and maximum identifier lengths", |
| recommended: false, |
| frozen: true, |
| url: "https://eslint.org/docs/latest/rules/id-length", |
| }, |
|
|
| schema: [ |
| { |
| type: "object", |
| properties: { |
| min: { |
| type: "integer", |
| }, |
| max: { |
| type: "integer", |
| }, |
| exceptions: { |
| type: "array", |
| uniqueItems: true, |
| items: { |
| type: "string", |
| }, |
| }, |
| exceptionPatterns: { |
| type: "array", |
| uniqueItems: true, |
| items: { |
| type: "string", |
| }, |
| }, |
| properties: { |
| enum: ["always", "never"], |
| }, |
| }, |
| additionalProperties: false, |
| }, |
| ], |
| messages: { |
| tooShort: "Identifier name '{{name}}' is too short (< {{min}}).", |
| tooShortPrivate: |
| "Identifier name '#{{name}}' is too short (< {{min}}).", |
| tooLong: "Identifier name '{{name}}' is too long (> {{max}}).", |
| tooLongPrivate: |
| "Identifier name #'{{name}}' is too long (> {{max}}).", |
| }, |
| }, |
|
|
| create(context) { |
| const [options] = context.options; |
| const { max: maxLength = Infinity, min: minLength } = options; |
| const properties = options.properties !== "never"; |
| const exceptions = new Set(options.exceptions); |
| const exceptionPatterns = options.exceptionPatterns.map( |
| pattern => new RegExp(pattern, "u"), |
| ); |
| const reportedNodes = new Set(); |
|
|
| |
| |
| |
| |
| |
| |
| function matchesExceptionPattern(name) { |
| return exceptionPatterns.some(pattern => pattern.test(name)); |
| } |
|
|
| const SUPPORTED_EXPRESSIONS = { |
| MemberExpression: |
| properties && |
| function (parent) { |
| return ( |
| !parent.computed && |
| |
| ((parent.parent.left === parent && |
| parent.parent.type === "AssignmentExpression") || |
| |
| (parent.parent.type === "Property" && |
| parent.parent.value === parent && |
| parent.parent.parent.type === "ObjectPattern" && |
| parent.parent.parent.parent.left === |
| parent.parent.parent)) |
| ); |
| }, |
| AssignmentPattern(parent, node) { |
| return parent.left === node; |
| }, |
| VariableDeclarator(parent, node) { |
| return parent.id === node; |
| }, |
| Property(parent, node) { |
| if (parent.parent.type === "ObjectPattern") { |
| const isKeyAndValueSame = |
| parent.value.name === parent.key.name; |
|
|
| return ( |
| (!isKeyAndValueSame && parent.value === node) || |
| (isKeyAndValueSame && parent.key === node && properties) |
| ); |
| } |
| return ( |
| properties && |
| !isImportAttributeKey(node) && |
| !parent.computed && |
| parent.key.name === node.name |
| ); |
| }, |
| ImportSpecifier(parent, node) { |
| return ( |
| parent.local === node && |
| getModuleExportName(parent.imported) !== |
| getModuleExportName(parent.local) |
| ); |
| }, |
| ImportDefaultSpecifier: true, |
| ImportNamespaceSpecifier: true, |
| RestElement: true, |
| FunctionExpression: true, |
| ArrowFunctionExpression: true, |
| ClassDeclaration: true, |
| FunctionDeclaration: true, |
| MethodDefinition: true, |
| PropertyDefinition: true, |
| CatchClause: true, |
| ArrayPattern: true, |
| }; |
|
|
| return { |
| [["Identifier", "PrivateIdentifier"]](node) { |
| const name = node.name; |
| const parent = node.parent; |
|
|
| const nameLength = getGraphemeCount(name); |
|
|
| const isShort = nameLength < minLength; |
| const isLong = nameLength > maxLength; |
|
|
| if ( |
| !(isShort || isLong) || |
| exceptions.has(name) || |
| matchesExceptionPattern(name) |
| ) { |
| return; |
| } |
|
|
| const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| if ( |
| isValidExpression && |
| !reportedNodes.has(node.range.toString()) && |
| (isValidExpression === true || |
| isValidExpression(parent, node)) |
| ) { |
| reportedNodes.add(node.range.toString()); |
|
|
| let messageId = isShort ? "tooShort" : "tooLong"; |
|
|
| if (node.type === "PrivateIdentifier") { |
| messageId += "Private"; |
| } |
|
|
| context.report({ |
| node, |
| messageId, |
| data: { name, min: minLength, max: maxLength }, |
| }); |
| } |
| }, |
| }; |
| }, |
| }; |
|
|