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 +1 -1
- package/rules/enforce-optional.js +43 -19
package/package.json
CHANGED
|
@@ -11,30 +11,54 @@ module.exports = {
|
|
|
11
11
|
|
|
12
12
|
create(context) {
|
|
13
13
|
const sourceCode = context.getSourceCode();
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
}
|