UNPKG

4.66 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({
79 node,
80 message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
81 data: {
82 name: node.name,
83 pattern
84 }
85 });
86 }
87
88 return {
89
90 Identifier(node) {
91 const name = node.name,
92 parent = node.parent,
93 effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
94
95 if (parent.type === "MemberExpression") {
96
97 if (!properties) {
98 return;
99 }
100
101 // Always check object names
102 if (parent.object.type === "Identifier" &&
103 parent.object.name === name) {
104 if (isInvalid(name)) {
105 report(node);
106 }
107
108 // Report AssignmentExpressions only if they are the left side of the assignment
109 } else if (effectiveParent.type === "AssignmentExpression" &&
110 (effectiveParent.right.type !== "MemberExpression" ||
111 effectiveParent.left.type === "MemberExpression" &&
112 effectiveParent.left.property.name === name)) {
113 if (isInvalid(name)) {
114 report(node);
115 }
116 }
117
118 } else if (parent.type === "Property") {
119
120 if (!properties || parent.key.name !== name) {
121 return;
122 }
123
124 if (shouldReport(effectiveParent, name)) {
125 report(node);
126 }
127
128 } else {
129 const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
130
131 if (onlyDeclarations && !isDeclaration) {
132 return;
133 }
134
135 if (shouldReport(effectiveParent, name)) {
136 report(node);
137 }
138 }
139 }
140
141 };
142
143 }
144};