UNPKG

4.76 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag trailing underscores in variable declarations.
3 * @author Matt DuVall <http://www.mattduvall.com>
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = function(context) {
13
14 var options = context.options[0] || {};
15 var ALLOWED_VARIABLES = options.allow ? options.allow : [];
16 var allowAfterThis = typeof options.allowAfterThis !== "undefined" ? options.allowAfterThis : false;
17
18 //-------------------------------------------------------------------------
19 // Helpers
20 //-------------------------------------------------------------------------
21
22 /**
23 * Check if identifier is present inside the allowed option
24 * @param {string} identifier name of the node
25 * @returns {boolean} true if its is present
26 * @private
27 */
28 function isAllowed(identifier) {
29 return ALLOWED_VARIABLES.some(function(ident) {
30 return ident === identifier;
31 });
32 }
33
34 /**
35 * Check if identifier has a underscore at the end
36 * @param {ASTNode} identifier node to evaluate
37 * @returns {boolean} true if its is present
38 * @private
39 */
40 function hasTrailingUnderscore(identifier) {
41 var len = identifier.length;
42
43 return identifier !== "_" && (identifier[0] === "_" || identifier[len - 1] === "_");
44 }
45
46 /**
47 * Check if identifier is a special case member expression
48 * @param {ASTNode} identifier node to evaluate
49 * @returns {boolean} true if its is a special case
50 * @private
51 */
52 function isSpecialCaseIdentifierForMemberExpression(identifier) {
53 return identifier === "__proto__";
54 }
55
56 /**
57 * Check if identifier is a special case variable expression
58 * @param {ASTNode} identifier node to evaluate
59 * @returns {boolean} true if its is a special case
60 * @private
61 */
62 function isSpecialCaseIdentifierInVariableExpression(identifier) {
63 // Checks for the underscore library usage here
64 return identifier === "_";
65 }
66
67 /**
68 * Check if function has a underscore at the end
69 * @param {ASTNode} node node to evaluate
70 * @returns {void}
71 * @private
72 */
73 function checkForTrailingUnderscoreInFunctionDeclaration(node) {
74 if (node.id) {
75 var identifier = node.id.name;
76
77 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) && !isAllowed(identifier)) {
78 context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
79 }
80 }
81 }
82
83 /**
84 * Check if variable expression has a underscore at the end
85 * @param {ASTNode} node node to evaluate
86 * @returns {void}
87 * @private
88 */
89 function checkForTrailingUnderscoreInVariableExpression(node) {
90 var identifier = node.id.name;
91
92 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
93 !isSpecialCaseIdentifierInVariableExpression(identifier) && !isAllowed(identifier)) {
94 context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
95 }
96 }
97
98 /**
99 * Check if member expression has a underscore at the end
100 * @param {ASTNode} node node to evaluate
101 * @returns {void}
102 * @private
103 */
104 function checkForTrailingUnderscoreInMemberExpression(node) {
105 var identifier = node.property.name,
106 isMemberOfThis = node.object.type === "ThisExpression";
107
108 if (typeof identifier !== "undefined" && hasTrailingUnderscore(identifier) &&
109 !(isMemberOfThis && allowAfterThis) &&
110 !isSpecialCaseIdentifierForMemberExpression(identifier) && !isAllowed(identifier)) {
111 context.report(node, "Unexpected dangling '_' in '" + identifier + "'.");
112 }
113 }
114
115 //--------------------------------------------------------------------------
116 // Public API
117 //--------------------------------------------------------------------------
118
119 return {
120 "FunctionDeclaration": checkForTrailingUnderscoreInFunctionDeclaration,
121 "VariableDeclarator": checkForTrailingUnderscoreInVariableExpression,
122 "MemberExpression": checkForTrailingUnderscoreInMemberExpression
123 };
124
125};
126
127module.exports.schema = [
128 {
129 "type": "object",
130 "properties": {
131 "allow": {
132 "type": "array",
133 "items": {
134 "type": "string"
135 }
136 },
137 "allowAfterThis": {
138 "type": "boolean"
139 }
140 },
141 "additionalProperties": false
142 }
143];