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