UNPKG

4.71 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 url: "https://eslint.org/docs/rules/id-match"
19 },
20
21 schema: [
22 {
23 type: "string"
24 },
25 {
26 type: "object",
27 properties: {
28 properties: {
29 type: "boolean"
30 }
31 }
32 }
33 ]
34 },
35
36 create(context) {
37
38 //--------------------------------------------------------------------------
39 // Helpers
40 //--------------------------------------------------------------------------
41
42 const pattern = context.options[0] || "^.+$",
43 regexp = new RegExp(pattern);
44
45 const options = context.options[1] || {},
46 properties = !!options.properties,
47 onlyDeclarations = !!options.onlyDeclarations;
48
49 /**
50 * Checks if a string matches the provided pattern
51 * @param {string} name The string to check.
52 * @returns {boolean} if the string is a match
53 * @private
54 */
55 function isInvalid(name) {
56 return !regexp.test(name);
57 }
58
59 /**
60 * Verifies if we should report an error or not based on the effective
61 * parent node and the identifier name.
62 * @param {ASTNode} effectiveParent The effective parent node of the node to be reported
63 * @param {string} name The identifier name of the identifier node
64 * @returns {boolean} whether an error should be reported or not
65 */
66 function shouldReport(effectiveParent, name) {
67 return effectiveParent.type !== "CallExpression" &&
68 effectiveParent.type !== "NewExpression" &&
69 isInvalid(name);
70 }
71
72 /**
73 * Reports an AST node as a rule violation.
74 * @param {ASTNode} node The node to report.
75 * @returns {void}
76 * @private
77 */
78 function report(node) {
79 context.report({
80 node,
81 message: "Identifier '{{name}}' does not match the pattern '{{pattern}}'.",
82 data: {
83 name: node.name,
84 pattern
85 }
86 });
87 }
88
89 return {
90
91 Identifier(node) {
92 const name = node.name,
93 parent = node.parent,
94 effectiveParent = (parent.type === "MemberExpression") ? parent.parent : parent;
95
96 if (parent.type === "MemberExpression") {
97
98 if (!properties) {
99 return;
100 }
101
102 // Always check object names
103 if (parent.object.type === "Identifier" &&
104 parent.object.name === name) {
105 if (isInvalid(name)) {
106 report(node);
107 }
108
109 // Report AssignmentExpressions only if they are the left side of the assignment
110 } else if (effectiveParent.type === "AssignmentExpression" &&
111 (effectiveParent.right.type !== "MemberExpression" ||
112 effectiveParent.left.type === "MemberExpression" &&
113 effectiveParent.left.property.name === name)) {
114 if (isInvalid(name)) {
115 report(node);
116 }
117 }
118
119 } else if (parent.type === "Property") {
120
121 if (!properties || parent.key.name !== name) {
122 return;
123 }
124
125 if (shouldReport(effectiveParent, name)) {
126 report(node);
127 }
128
129 } else {
130 const isDeclaration = effectiveParent.type === "FunctionDeclaration" || effectiveParent.type === "VariableDeclarator";
131
132 if (onlyDeclarations && !isDeclaration) {
133 return;
134 }
135
136 if (shouldReport(effectiveParent, name)) {
137 report(node);
138 }
139 }
140 }
141
142 };
143
144 }
145};