1ee838d1c4002134ff5af32da272140586c4d31deJohn Reck// Copyright 2016 The Chromium Authors. All rights reserved. 2ee838d1c4002134ff5af32da272140586c4d31deJohn Reck// Use of this source code is governed by a BSD-style license that can be 3ee838d1c4002134ff5af32da272140586c4d31deJohn Reck// found in the LICENSE file. 4ee838d1c4002134ff5af32da272140586c4d31deJohn Reck/* eslint-disable */ 5ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 6ee838d1c4002134ff5af32da272140586c4d31deJohn Reck/** 7ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @fileoverview Rule to flag non-camelcased identifiers 8ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @author Nicholas C. Zakas 9ee838d1c4002134ff5af32da272140586c4d31deJohn Reck */ 10ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 11ee838d1c4002134ff5af32da272140586c4d31deJohn Reck'use strict'; 12ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 13ee838d1c4002134ff5af32da272140586c4d31deJohn Reck//------------------------------------------------------------------------------ 14ee838d1c4002134ff5af32da272140586c4d31deJohn Reck// Rule Definition 15ee838d1c4002134ff5af32da272140586c4d31deJohn Reck//------------------------------------------------------------------------------ 16ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 17ee838d1c4002134ff5af32da272140586c4d31deJohn Reckmodule.exports = { 18ee838d1c4002134ff5af32da272140586c4d31deJohn Reck meta: { 19ee838d1c4002134ff5af32da272140586c4d31deJohn Reck docs: { 20ee838d1c4002134ff5af32da272140586c4d31deJohn Reck description: "enforce Catapult camelcase naming convention", 21ee838d1c4002134ff5af32da272140586c4d31deJohn Reck category: "Stylistic Issues", 22ee838d1c4002134ff5af32da272140586c4d31deJohn Reck recommended: false 23ee838d1c4002134ff5af32da272140586c4d31deJohn Reck }, 24ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 25ee838d1c4002134ff5af32da272140586c4d31deJohn Reck schema: [ 26ee838d1c4002134ff5af32da272140586c4d31deJohn Reck { 27ee838d1c4002134ff5af32da272140586c4d31deJohn Reck type: "object", 28ee838d1c4002134ff5af32da272140586c4d31deJohn Reck properties: { 29ee838d1c4002134ff5af32da272140586c4d31deJohn Reck properties: { 30ee838d1c4002134ff5af32da272140586c4d31deJohn Reck enum: ["always", "never"] 31ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 32ee838d1c4002134ff5af32da272140586c4d31deJohn Reck }, 33ee838d1c4002134ff5af32da272140586c4d31deJohn Reck additionalProperties: false 34ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 35ee838d1c4002134ff5af32da272140586c4d31deJohn Reck ] 36ee838d1c4002134ff5af32da272140586c4d31deJohn Reck }, 37ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 38ee838d1c4002134ff5af32da272140586c4d31deJohn Reck create(context) { 39ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 40ee838d1c4002134ff5af32da272140586c4d31deJohn Reck //-------------------------------------------------------------------------- 41ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Helpers 42ee838d1c4002134ff5af32da272140586c4d31deJohn Reck //-------------------------------------------------------------------------- 43ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 44ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // contains reported nodes to avoid reporting twice on destructuring with shorthand notation 45ee838d1c4002134ff5af32da272140586c4d31deJohn Reck var reported = []; 46ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 47ee838d1c4002134ff5af32da272140586c4d31deJohn Reck /** 48ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * Checks if a string contains an underscore and isn't all upper-case 49ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @param {string} name The string to check. 50ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @returns {boolean} if the string is underscored 51ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @private 52ee838d1c4002134ff5af32da272140586c4d31deJohn Reck */ 53ee838d1c4002134ff5af32da272140586c4d31deJohn Reck function isUnderscored(name) { 54ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 55ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // if there's an underscore, it might be A_VARANT, which is okay 56ee838d1c4002134ff5af32da272140586c4d31deJohn Reck return name.indexOf("_") > -1 && name !== name.toUpperCase(); 57ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 58ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 59ee838d1c4002134ff5af32da272140586c4d31deJohn Reck /** 60ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * Reports an AST node as a rule violation. 61ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @param {ASTNode} node The node to report. 62ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @returns {void} 63ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * @private 64ee838d1c4002134ff5af32da272140586c4d31deJohn Reck */ 65ee838d1c4002134ff5af32da272140586c4d31deJohn Reck function report(node) { 66ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (reported.indexOf(node) < 0) { 67ee838d1c4002134ff5af32da272140586c4d31deJohn Reck reported.push(node); 68ee838d1c4002134ff5af32da272140586c4d31deJohn Reck context.report(node, "Identifier '{{name}}' is not in camel case.", { name: node.name }); 69ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 70ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 71ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 72ee838d1c4002134ff5af32da272140586c4d31deJohn Reck var options = context.options[0] || {}; 73ee838d1c4002134ff5af32da272140586c4d31deJohn Reck let properties = options.properties || ""; 74ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 75ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (properties !== "always" && properties !== "never") { 76ee838d1c4002134ff5af32da272140586c4d31deJohn Reck properties = "always"; 77ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 78ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 79ee838d1c4002134ff5af32da272140586c4d31deJohn Reck return { 80ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 81ee838d1c4002134ff5af32da272140586c4d31deJohn Reck Identifier(node) { 82ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 83ee838d1c4002134ff5af32da272140586c4d31deJohn Reck /* 84ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * Leading and trailing underscores are commonly used to flag 85ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * private/protected identifiers, strip them. 86ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * 87ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * NOTE: This has four Catapult-specific style exceptions: 88ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * 89ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * - The prefix opt_ 90ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * - The prefix g_ 91ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * - The suffix _smallerIsBetter 92ee838d1c4002134ff5af32da272140586c4d31deJohn Reck * - The suffix _biggerIsBetter 93ee838d1c4002134ff5af32da272140586c4d31deJohn Reck */ 94ee838d1c4002134ff5af32da272140586c4d31deJohn Reck var name = node.name.replace(/(?:^opt_)|^(?:^g_)|^_+|_+$|(?:_smallerIsBetter)$|(?:_biggerIsBetter)$/g, ""), 95ee838d1c4002134ff5af32da272140586c4d31deJohn Reck effectiveParent = (node.parent.type === "MemberExpression") ? node.parent.parent : node.parent; 96ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 97ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // MemberExpressions get special rules 98ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (node.parent.type === "MemberExpression") { 99ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 100ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // "never" check properties 101ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (properties === "never") { 102ee838d1c4002134ff5af32da272140586c4d31deJohn Reck return; 103ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 104ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 105ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Always report underscored object names 106ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (node.parent.object.type === "Identifier" && 107ee838d1c4002134ff5af32da272140586c4d31deJohn Reck node.parent.object.name === node.name && 108ee838d1c4002134ff5af32da272140586c4d31deJohn Reck isUnderscored(name)) { 109ee838d1c4002134ff5af32da272140586c4d31deJohn Reck report(node); 110ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 111ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Report AssignmentExpressions only if they are the left side of the assignment 112ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } else if (effectiveParent.type === "AssignmentExpression" && 113ee838d1c4002134ff5af32da272140586c4d31deJohn Reck isUnderscored(name) && 114ee838d1c4002134ff5af32da272140586c4d31deJohn Reck (effectiveParent.right.type !== "MemberExpression" || 115ee838d1c4002134ff5af32da272140586c4d31deJohn Reck effectiveParent.left.type === "MemberExpression" && 116ee838d1c4002134ff5af32da272140586c4d31deJohn Reck effectiveParent.left.property.name === node.name)) { 117ee838d1c4002134ff5af32da272140586c4d31deJohn Reck report(node); 118ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 119ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 120ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Properties have their own rules 121ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } else if (node.parent.type === "Property") { 122ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 123ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // "never" check properties 124ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (properties === "never") { 125ee838d1c4002134ff5af32da272140586c4d31deJohn Reck return; 126ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 127ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 128ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (node.parent.parent && node.parent.parent.type === "ObjectPattern" && 129ee838d1c4002134ff5af32da272140586c4d31deJohn Reck node.parent.key === node && node.parent.value !== node) { 130ee838d1c4002134ff5af32da272140586c4d31deJohn Reck return; 131ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 132ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 133ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { 134ee838d1c4002134ff5af32da272140586c4d31deJohn Reck report(node); 135ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 136ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 137ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Check if it's an import specifier 138ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } else if (["ImportSpecifier", "ImportNamespaceSpecifier", "ImportDefaultSpecifier"].indexOf(node.parent.type) >= 0) { 139ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 140ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Report only if the local imported identifier is underscored 141ee838d1c4002134ff5af32da272140586c4d31deJohn Reck if (node.parent.local && node.parent.local.name === node.name && isUnderscored(name)) { 142ee838d1c4002134ff5af32da272140586c4d31deJohn Reck report(node); 143ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 144ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 145ee838d1c4002134ff5af32da272140586c4d31deJohn Reck // Report anything that is underscored that isn't a CallExpression 146ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } else if (isUnderscored(name) && effectiveParent.type !== "CallExpression") { 147ee838d1c4002134ff5af32da272140586c4d31deJohn Reck report(node); 148ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 149ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 150ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 151ee838d1c4002134ff5af32da272140586c4d31deJohn Reck }; 152ee838d1c4002134ff5af32da272140586c4d31deJohn Reck 153ee838d1c4002134ff5af32da272140586c4d31deJohn Reck } 154ee838d1c4002134ff5af32da272140586c4d31deJohn Reck}; 155