UNPKG

4.56 kBJavaScriptView Raw
1/**
2 * @fileoverview Rule to flag non-matching identifiers
3 * @author Matthieu Larcher
4 */
5
6"use strict";
7
8//------------------------------------------------------------------------------
9// Rule Definition
10//------------------------------------------------------------------------------
11
12module.exports = {
13 meta: {
14 docs: {
15 description: "require identifiers to match a specified regular expression",
16 category: "Stylistic Issues",
17 recommended: false
18 },
19
20 schema: [
21 {
22 type: "string"
23 },
24 {
25 type: "object",
26 properties: {
27 properties: {
28 type: "boolean"
29 }
30 }
31 }
32 ]
33 },
34
35 create(context) {
36
37 //--------------------------------------------------------------------------
38 // Helpers
39 //--------------------------------------------------------------------------
40
41 const pattern = context.options[0] || "^.+$",
42 regexp = new RegExp(pattern);
43
44 const options = context.options[1] || {},
45 properties = !!options.properties,
46 onlyDeclarations = !!options.onlyDeclarations;
47
48 /**
49 * Checks if a string matches the provided pattern
50 * @param {string} name The string to check.
51 * @returns {boolean} if the string is a match
52 * @private
53 */
54 function isInvalid(name) {
55 return !regexp.test(name);
56 }
57
58 /**
59 * Verifies if we should report an error or not based on the effective
60 * parent node and the identifier name.
61 * @param {ASTNode} effectiveParent The effective parent node of the node to be reported
62 * @param {string} name The identifier name of the identifier node
63 * @returns {boolean} whether an error should be reported or not
64 */
65 function shouldReport(effectiveParent, name) {
66 return effectiveParent.type !== "CallExpression"
67 && effectiveParent.type !== "NewExpression" &&
68 isInvalid(name);
69 }
70
71 /**
72 * Reports an AST node as a rule violation.
73 * @param {ASTNode} node The node to report.
74 * @returns {void}
75 * @private
76 */
77 function report(node) {
78 context.report(node, "Identifier '{{name}}' does not match the pattern '{{pattern}}'.", {
79 name: node.name,
80 pattern
81 });
82 }
83
84 return {
85
86 Identifier(node) {
87 const name = node.name,
88 parent = node.parent,
89 effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
90
91 if (parent.type === "MemberExpression") {
92
93 if (!properties) {
94 return;
95 }
96
97 // Always check object names
98 if (parent.object.type === "Identifier" &&
99 parent.object.name === name) {
100 if (isInvalid(name)) {
101 report(node);
102 }
103
104 // Report AssignmentExpressions only if they are the left side of the assignment
105 } else if (effectiveParent.type === "AssignmentExpression" &&
106 (effectiveParent.right.type !== "MemberExpression" ||
107 effectiveParent.left.type === "MemberExpression" &&
108 effectiveParent.left.property.name === name)) {
109 if (isInvalid(name)) {
110 report(node);
111 }
112 }
113
114 } else if (parent.type === "Property") {
115
116 if (!properties || parent.key.name !== name) {
117 return;
118 }
119
120 if (shouldReport(effectiveParent, name)) {
121 report(node);
122 }
123
124 } else {
125 const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
126
127 if (onlyDeclarations && !isDeclaration) {
128 return;
129 }
130
131 if (shouldReport(effectiveParent, name)) {
132 report(node);
133 }
134 }
135 }
136
137 };
138
139 }
140};