Permalink
177 lines (154 sloc)
6.51 KB
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
codeql-action/node_modules/eslint/lib/rules/id-length.js
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @fileoverview Rule that warns when identifier names are shorter or longer | |
* than the values provided in configuration. | |
* @author Burak Yigit Kaya aka BYK | |
*/ | |
"use strict"; | |
//------------------------------------------------------------------------------ | |
// Requirements | |
//------------------------------------------------------------------------------ | |
const { getGraphemeCount } = require("../shared/string-utils"); | |
//------------------------------------------------------------------------------ | |
// Rule Definition | |
//------------------------------------------------------------------------------ | |
/** @type {import('../shared/types').Rule} */ | |
module.exports = { | |
meta: { | |
type: "suggestion", | |
docs: { | |
description: "Enforce minimum and maximum identifier lengths", | |
recommended: false, | |
url: "https://eslint.org/docs/latest/rules/id-length" | |
}, | |
schema: [ | |
{ | |
type: "object", | |
properties: { | |
min: { | |
type: "integer", | |
default: 2 | |
}, | |
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[0] || {}; | |
const minLength = typeof options.min !== "undefined" ? options.min : 2; | |
const maxLength = typeof options.max !== "undefined" ? options.max : Infinity; | |
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(); | |
/** | |
* Checks if a string matches the provided exception patterns | |
* @param {string} name The string to check. | |
* @returns {boolean} if the string is a match | |
* @private | |
*/ | |
function matchesExceptionPattern(name) { | |
return exceptionPatterns.some(pattern => pattern.test(name)); | |
} | |
const SUPPORTED_EXPRESSIONS = { | |
MemberExpression: properties && function(parent) { | |
return !parent.computed && ( | |
// regular property assignment | |
(parent.parent.left === parent && parent.parent.type === "AssignmentExpression" || | |
// or the last identifier in an ObjectPattern destructuring | |
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 && !parent.computed && parent.key.name === node.name; | |
}, | |
ImportDefaultSpecifier: 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; // Nothing to report | |
} | |
const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type]; | |
/* | |
* We used the range instead of the node because it's possible | |
* for the same identifier to be represented by two different | |
* nodes, with the most clear example being shorthand properties: | |
* { foo } | |
* In this case, "foo" is represented by one node for the name | |
* and one for the value. The only way to know they are the same | |
* is to look at the range. | |
*/ | |
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 } | |
}); | |
} | |
} | |
}; | |
} | |
}; |