eslint-plugin-crisp 1.0.48 → 1.0.50

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.0.48",
3
+ "version": "1.0.50",
4
4
  "description": "Custom EsLint Rules for Crisp",
5
5
  "main": "index.js",
6
6
  "author": "Crisp IM SAS",
@@ -11,30 +11,54 @@ module.exports = {
11
11
 
12
12
  create(context) {
13
13
  const sourceCode = context.getSourceCode();
14
- // Search for `foo && foo.` or `foo && foo[`
15
- // Notice: do not match `foo && foo.bar !==` or `foo && foo[bar] !==`, \
16
- // as the optional version would be unsafe
17
- const pattern = /\b(\w\S+)\s&&\s+\1\b[\[\.](?!\w\S+\s\!\=\=)/g;
14
+
15
+ const patterns = [
16
+ // Search for `foo && foo.` or `foo && foo[`
17
+ // Notice: do not match `foo && foo.bar !==` or `foo && foo[bar] !==`, \
18
+ // as the version with optional chaining would be unsafe
19
+ /\b(\w\S+)\s&&\s+\1\b[\[\.](?!\w\S+\s\!\=\=)/g,
20
+
21
+ // Search for patterns like `foo || {}).bar`, `foo || {})[`, \
22
+ // `foo || []).bar` or `foo || [])[`
23
+ // Notice: do not match if the value after the dot is "filter", "find", \
24
+ // "findIndex", "map", "reduce", "length <", "length === 0", or \
25
+ // "length == 0", as the version with optional chaining would be unsafe
26
+ /(.+?)\s\|\|\s(\{\}|\[\])\)(\[|\.(?!some\b|filter\b|find\b|findIndex\b|reduce\b|map\b|length\s*<|length\s*===\s*0|length\s*==\s*0))\w*/g
27
+ ];
18
28
 
19
29
  return {
20
30
  Program() {
21
31
  const text = sourceCode.getText();
22
32
 
23
- let match;
24
-
25
- while ((match = pattern.exec(text)) !== null) {
26
- const start = match.index;
27
- const end = start + match[0].length;
28
- const range = [start, end];
29
-
30
- context.report({
31
- message: "Prefer using optional chaining rather than: '{{codeFragment}}'.",
32
- data: {
33
- codeFragment: match[0]
34
- },
35
- loc: sourceCode.getLocFromIndex(range[0])
36
- });
37
- }
33
+ patterns.forEach((pattern, index) => {
34
+ let match;
35
+
36
+ // Reset lastIndex in case the RegExp object is reused
37
+ pattern.lastIndex = 0;
38
+
39
+ while ((match = pattern.exec(text)) !== null) {
40
+ const start = match.index;
41
+ const end = start + match[0].length;
42
+
43
+ const range = [start, end];
44
+
45
+ if (
46
+ index === 1 &&
47
+ /Object\.(keys|values|entries)\(/.test(match[1])
48
+ ) {
49
+ // Ignore `Object.keys(foo || {})` (and others) as it cannot be \
50
+ // safely transformed to optional chaining
51
+ } else {
52
+ context.report({
53
+ message: "Prefer using optional chaining rather than: '{{codeFragment}}'.",
54
+ data: {
55
+ codeFragment: match[0]
56
+ },
57
+ loc: sourceCode.getLocFromIndex(range[0])
58
+ });
59
+ }
60
+ }
61
+ });
38
62
  }
39
63
  };
40
64
  }