Ohm-Management - Projektarbeit B-ME
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.

camelcase.js 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. /**
  2. * @fileoverview Rule to flag non-camelcased identifiers
  3. * @author Nicholas C. Zakas
  4. */
  5. "use strict";
  6. //------------------------------------------------------------------------------
  7. // Rule Definition
  8. //------------------------------------------------------------------------------
  9. module.exports = {
  10. meta: {
  11. type: "suggestion",
  12. docs: {
  13. description: "enforce camelcase naming convention",
  14. category: "Stylistic Issues",
  15. recommended: false,
  16. url: "https://eslint.org/docs/rules/camelcase"
  17. },
  18. schema: [
  19. {
  20. type: "object",
  21. properties: {
  22. ignoreDestructuring: {
  23. type: "boolean"
  24. },
  25. properties: {
  26. enum: ["always", "never"]
  27. },
  28. allow: {
  29. type: "array",
  30. items: [
  31. {
  32. type: "string"
  33. }
  34. ],
  35. minItems: 0,
  36. uniqueItems: true
  37. }
  38. },
  39. additionalProperties: false
  40. }
  41. ],
  42. messages: {
  43. notCamelCase: "Identifier '{{name}}' is not in camel case."
  44. }
  45. },
  46. create(context) {
  47. const options = context.options[0] || {};
  48. let properties = options.properties || "";
  49. const ignoreDestructuring = options.ignoreDestructuring || false;
  50. const allow = options.allow || [];
  51. if (properties !== "always" && properties !== "never") {
  52. properties = "always";
  53. }
  54. //--------------------------------------------------------------------------
  55. // Helpers
  56. //--------------------------------------------------------------------------
  57. // contains reported nodes to avoid reporting twice on destructuring with shorthand notation
  58. const reported = [];
  59. const ALLOWED_PARENT_TYPES = new Set(["CallExpression", "NewExpression"]);
  60. /**
  61. * Checks if a string contains an underscore and isn't all upper-case
  62. * @param {string} name The string to check.
  63. * @returns {boolean} if the string is underscored
  64. * @private
  65. */
  66. function isUnderscored(name) {
  67. // if there's an underscore, it might be A_CONSTANT, which is okay
  68. return name.indexOf("_") > -1 && name !== name.toUpperCase();
  69. }
  70. /**
  71. * Checks if a string match the ignore list
  72. * @param {string} name The string to check.
  73. * @returns {boolean} if the string is ignored
  74. * @private
  75. */
  76. function isAllowed(name) {
  77. return allow.findIndex(
  78. entry => name === entry || name.match(new RegExp(entry))
  79. ) !== -1;
  80. }
  81. /**
  82. * Checks if a parent of a node is an ObjectPattern.
  83. * @param {ASTNode} node The node to check.
  84. * @returns {boolean} if the node is inside an ObjectPattern
  85. * @private
  86. */
  87. function isInsideObjectPattern(node) {
  88. let { parent } = node;
  89. while (parent) {
  90. if (parent.type === "ObjectPattern") {
  91. return true;
  92. }
  93. parent = parent.parent;
  94. }
  95. return false;
  96. }
  97. /**
  98. * Reports an AST node as a rule violation.
  99. * @param {ASTNode} node The node to report.
  100. * @returns {void}
  101. * @private
  102. */
  103. function report(node) {
  104. if (reported.indexOf(node) < 0) {
  105. reported.push(node);
  106. context.report({ node, messageId: "notCamelCase", data: { name: node.name } });
  107. }
  108. }
  109. return {
  110. Identifier(node) {
  111. /*
  112. * Leading and trailing underscores are commonly used to flag
  113. * private/protected identifiers, strip them
  114. */
  115. const name = node.name.replace(/^_+|_+$/g, ""),
  116. effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
  117. // First, we ignore the node if it match the ignore list
  118. if (isAllowed(name)) {
  119. return;
  120. }
  121. // MemberExpressions get special rules
  122. if (node.parent.type === "MemberExpression") {
  123. // "never" check properties
  124. if (properties === "never") {
  125. return;
  126. }
  127. // Always report underscored object names
  128. if (node.parent.object.type === "Identifier" && node.parent.object.name === node.name && isUnderscored(name)) {
  129. report(node);
  130. // Report AssignmentExpressions only if they are the left side of the assignment
  131. } else if (effectiveParent.type === "AssignmentExpression" && isUnderscored(name) && (effectiveParent.right.type !== "MemberExpression" || effectiveParent.left.type === "MemberExpression" && effectiveParent.left.property.name === node.name)) {
  132. report(node);
  133. }
  134. /*
  135. * Properties have their own rules, and
  136. * AssignmentPattern nodes can be treated like Properties:
  137. * e.g.: const { no_camelcased = false } = bar;
  138. */
  139. } else if (node.parent.type === "Property" || node.parent.type === "AssignmentPattern") {
  140. if (node.parent.parent && node.parent.parent.type === "ObjectPattern") {
  141. if (node.parent.shorthand && node.parent.value.left && isUnderscored(name)) {
  142. report(node);
  143. }
  144. const assignmentKeyEqualsValue = node.parent.key.name === node.parent.value.name;
  145. // prevent checking righthand side of destructured object
  146. if (node.parent.key === node && node.parent.value !== node) {
  147. return;
  148. }
  149. const valueIsUnderscored = node.parent.value.name && isUnderscored(name);
  150. // ignore destructuring if the option is set, unless a new identifier is created
  151. if (valueIsUnderscored && !(assignmentKeyEqualsValue && ignoreDestructuring)) {
  152. report(node);
  153. }
  154. }
  155. // "never" check properties or always ignore destructuring
  156. if (properties === "never" || (ignoreDestructuring && isInsideObjectPattern(node))) {
  157. return;
  158. }
  159. // don't check right hand side of AssignmentExpression to prevent duplicate warnings
  160. if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type) && !(node.parent.right === node)) {
  161. report(node);
  162. }
  163. // Check if it's an import specifier
  164. } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) {
  165. // Report only if the local imported identifier is underscored
  166. if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) {
  167. report(node);
  168. }
  169. // Report anything that is underscored that isn't a CallExpression
  170. } else if (isUnderscored(name) && !ALLOWED_PARENT_TYPES.has(effectiveParent.type)) {
  171. report(node);
  172. }
  173. }
  174. };
  175. }
  176. };