eslint-plugin-crisp 1.7.9 → 1.7.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-plugin-crisp",
3
- "version": "1.7.9",
3
+ "version": "1.7.10",
4
4
  "description": "Custom ESLint Rules for Crisp",
5
5
  "author": "Crisp IM SAS",
6
6
  "main": "index.js",
@@ -94,6 +94,14 @@ function isReference(node) {
94
94
  );
95
95
  }
96
96
 
97
+ // Checks an empty object or array literal (eg. `{}` or `[]`)
98
+ function isEmptyLiteral(node) {
99
+ return (
100
+ (node.type === "ObjectExpression" && node.properties.length === 0) ||
101
+ (node.type === "ArrayExpression" && node.elements.length === 0)
102
+ );
103
+ }
104
+
97
105
  // Checks a fallback expression like `value || "none"` or `value ?? other`
98
106
  function isFallback(node) {
99
107
  node = unwrapTransparentExpression(node);
@@ -111,6 +119,7 @@ function isFallback(node) {
111
119
 
112
120
  return (
113
121
  operand.type === "Literal" ||
122
+ isEmptyLiteral(operand) ||
114
123
  isReference(operand) ||
115
124
  isFallback(operand)
116
125
  );
@@ -151,6 +160,61 @@ function isReferenceObject(node) {
151
160
  });
152
161
  }
153
162
 
163
+ // Checks a node is a `logger.levels.<level>` member expression
164
+ function isLevelsReference(node) {
165
+ node = unwrapTransparentExpression(node);
166
+
167
+ return (
168
+ Boolean(node) &&
169
+ node.type === "MemberExpression" &&
170
+ node.object.type === "MemberExpression" &&
171
+ getPropertyName(node.object) === "levels" &&
172
+ node.object.object.type === "MemberExpression" &&
173
+ getPropertyName(node.object.object) === "logger"
174
+ );
175
+ }
176
+
177
+ // Checks a condition tests a logger level (eg. `logger.levels.error === true && x`)
178
+ function isLevelCheck(node) {
179
+ node = unwrapTransparentExpression(node);
180
+
181
+ if (!node) {
182
+ return false;
183
+ }
184
+
185
+ if (node.type === "LogicalExpression" && node.operator === "&&") {
186
+ return isLevelCheck(node.left) || isLevelCheck(node.right);
187
+ }
188
+
189
+ if (
190
+ node.type === "BinaryExpression" &&
191
+ (node.operator === "===" || node.operator === "==")
192
+ ) {
193
+ return isLevelsReference(node.left) || isLevelsReference(node.right);
194
+ }
195
+
196
+ return isLevelsReference(node);
197
+ }
198
+
199
+ // Checks a node is inside the consequent of a logger level guard
200
+ function isGuarded(ancestors, node) {
201
+ const chain = [...ancestors, node];
202
+
203
+ for (let index = chain.length - 2; index >= 0; index--) {
204
+ const ancestor = chain[index];
205
+
206
+ if (
207
+ ancestor.type === "IfStatement" &&
208
+ chain[index + 1] === ancestor.consequent &&
209
+ isLevelCheck(ancestor.test)
210
+ ) {
211
+ return true;
212
+ }
213
+ }
214
+
215
+ return false;
216
+ }
217
+
154
218
  export default {
155
219
  meta: {
156
220
  type: "suggestion",
@@ -177,6 +241,11 @@ export default {
177
241
  return;
178
242
  }
179
243
 
244
+ // Guarded by a log level check: computed values are allowed
245
+ if (isGuarded(sourceCode.getAncestors(node), node)) {
246
+ return;
247
+ }
248
+
180
249
  const [message, ...values] = node.arguments;
181
250
 
182
251
  if (
@@ -19,6 +19,12 @@ ruleTester.run("logger-arguments", rule, {
19
19
  "App.logger.debug(\"Loaded value: %s\", this.value ?? \"none\");",
20
20
  "App.logger.debug(\"Loaded value: %s\", first || second || \"none\");",
21
21
  "App.logger.debug(\"Loaded value: %s\", { user: userId || \"none\" });",
22
+ "if (App.logger.levels.error === true) { App.logger.error(\"Purge failed: %s\", buckets.join(\", \"), error); }",
23
+ "if (App.logger.levels.warn === true) { App.logger.warn(fn_log_format()); }",
24
+ "if (App.logger.levels.error === true && other) { if (x) { App.logger.error(\"Slow: %s\", a + b); } }",
25
+ "if (this._app.logger.levels.debug) { this._app.logger.debug(\"Count: %s\", list.length + 1); }",
26
+ "App.logger.error(\"Failed\", { params: (request.params || {}) });",
27
+ "App.logger.error(\"Failed: %s\", list || []);",
22
28
  "App.logger.warn(\"Shutting down\", { bufferedCount });",
23
29
  "App.logger.warn(\"Shutting down\", { count: this.count, ...meta });",
24
30
  "App.logger.warn(\"Shutting down\", { nested: { bufferedCount } }, logMeta);",
@@ -123,6 +129,22 @@ ruleTester.run("logger-arguments", rule, {
123
129
  }
124
130
  ]
125
131
  },
132
+ {
133
+ code: "if (App.logger.levels.error === true) {} else { App.logger.error(\"Purge: %s\", buckets.join(\", \")); }",
134
+ errors: [
135
+ {
136
+ messageId: "reference"
137
+ }
138
+ ]
139
+ },
140
+ {
141
+ code: "if (enabled) { App.logger.error(\"Purge: %s\", buckets.join(\", \")); }",
142
+ errors: [
143
+ {
144
+ messageId: "reference"
145
+ }
146
+ ]
147
+ },
126
148
  {
127
149
  code: "App.logger.debug(\"Retry count: %s\", 3);",
128
150
  errors: [