2 * @fileoverview Rule to flag non-camelcased identifiers
3 * @author Nicholas C. Zakas
4 * @copyright 2015 Dieter Oberkofler. All rights reserved.
9 //------------------------------------------------------------------------------
11 //------------------------------------------------------------------------------
13 module.exports = function(context) {
15 //--------------------------------------------------------------------------
17 //--------------------------------------------------------------------------
20 * Checks if a string contains an underscore and isn't all upper-case
21 * @param {String} name The string to check.
22 * @returns {boolean} if the string is underscored
25 function isUnderscored(name) {
27 // if there's an underscore, it might be A_CONSTANT, which is okay
28 return name.indexOf("_") > -1 && name !== name.toUpperCase();
32 * Reports an AST node as a rule violation.
33 * @param {ASTNode} node The node to report.
37 function report(node) {
38 context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name });
41 var options = context.options[0] || {},
42 properties = options.properties || "";
44 if (properties !== "always" && properties !== "never") {
45 properties = "always";
50 "Identifier": function(node) {
52 // Leading and trailing underscores are commonly used to flag private/protected identifiers, strip them
53 var name = node.name.replace(/^_+|_+$/g, ""),
54 effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent;
56 // MemberExpressions get special rules
57 if (node.parent.type === "MemberExpression") {
59 // Always report underscored object names
60 if (node.parent.object.type === "Identifier" &&
61 node.parent.object.name === node.name &&
62 isUnderscored(name)) {
65 // Report AssignmentExpressions only if they are the left side of the assignment
66 } else if (effectiveParent.type === "AssignmentExpression" &&
67 isUnderscored(name) &&
68 (effectiveParent.right.type !== "MemberExpression" ||
69 effectiveParent.left.type === "MemberExpression" &&
70 effectiveParent.left.property.name === node.name)) {
74 // Properties have their own rules
75 } else if (node.parent.type === "Property") {
77 // "never" check properties
78 if (properties === "never") {
82 if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {
86 // Report anything that is underscored that isn't a CallExpression
87 } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") {