You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
4.6 KiB

4 years ago
  1. /**
  2. * @fileoverview Rule that warns when identifier names are shorter or longer
  3. * than the values provided in configuration.
  4. * @author Burak Yigit Kaya aka BYK
  5. */
  6. "use strict";
  7. //------------------------------------------------------------------------------
  8. // Rule Definition
  9. //------------------------------------------------------------------------------
  10. module.exports = {
  11. meta: {
  12. type: "suggestion",
  13. docs: {
  14. description: "enforce minimum and maximum identifier lengths",
  15. category: "Stylistic Issues",
  16. recommended: false,
  17. url: "https://eslint.org/docs/rules/id-length"
  18. },
  19. schema: [
  20. {
  21. type: "object",
  22. properties: {
  23. min: {
  24. type: "integer",
  25. default: 2
  26. },
  27. max: {
  28. type: "integer"
  29. },
  30. exceptions: {
  31. type: "array",
  32. uniqueItems: true,
  33. items: {
  34. type: "string"
  35. }
  36. },
  37. properties: {
  38. enum: ["always", "never"]
  39. }
  40. },
  41. additionalProperties: false
  42. }
  43. ],
  44. messages: {
  45. tooShort: "Identifier name '{{name}}' is too short (< {{min}}).",
  46. tooLong: "Identifier name '{{name}}' is too long (> {{max}})."
  47. }
  48. },
  49. create(context) {
  50. const options = context.options[0] || {};
  51. const minLength = typeof options.min !== "undefined" ? options.min : 2;
  52. const maxLength = typeof options.max !== "undefined" ? options.max : Infinity;
  53. const properties = options.properties !== "never";
  54. const exceptions = (options.exceptions ? options.exceptions : [])
  55. .reduce((obj, item) => {
  56. obj[item] = true;
  57. return obj;
  58. }, {});
  59. const reportedNode = new Set();
  60. const SUPPORTED_EXPRESSIONS = {
  61. MemberExpression: properties && function(parent) {
  62. return !parent.computed && (
  63. // regular property assignment
  64. (parent.parent.left === parent && parent.parent.type === "AssignmentExpression" ||
  65. // or the last identifier in an ObjectPattern destructuring
  66. parent.parent.type === "Property" && parent.parent.value === parent &&
  67. parent.parent.parent.type === "ObjectPattern" && parent.parent.parent.parent.left === parent.parent.parent)
  68. );
  69. },
  70. AssignmentPattern(parent, node) {
  71. return parent.left === node;
  72. },
  73. VariableDeclarator(parent, node) {
  74. return parent.id === node;
  75. },
  76. Property(parent, node) {
  77. if (parent.parent.type === "ObjectPattern") {
  78. return (
  79. parent.value !== parent.key && parent.value === node ||
  80. parent.value === parent.key && parent.key === node && properties
  81. );
  82. }
  83. return properties && !parent.computed && parent.key === node;
  84. },
  85. ImportDefaultSpecifier: true,
  86. RestElement: true,
  87. FunctionExpression: true,
  88. ArrowFunctionExpression: true,
  89. ClassDeclaration: true,
  90. FunctionDeclaration: true,
  91. MethodDefinition: true,
  92. CatchClause: true,
  93. ArrayPattern: true
  94. };
  95. return {
  96. Identifier(node) {
  97. const name = node.name;
  98. const parent = node.parent;
  99. const isShort = name.length < minLength;
  100. const isLong = name.length > maxLength;
  101. if (!(isShort || isLong) || exceptions[name]) {
  102. return; // Nothing to report
  103. }
  104. const isValidExpression = SUPPORTED_EXPRESSIONS[parent.type];
  105. if (isValidExpression && !reportedNode.has(node) && (isValidExpression === true || isValidExpression(parent, node))) {
  106. reportedNode.add(node);
  107. context.report({
  108. node,
  109. messageId: isShort ? "tooShort" : "tooLong",
  110. data: { name, min: minLength, max: maxLength }
  111. });
  112. }
  113. }
  114. };
  115. }
  116. };