eslint-plugin-effector 0.16.0 → 0.18.0
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/README.md +24 -37
- package/dist/index.cjs +1488 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.mts +165 -0
- package/dist/index.mjs +1465 -0
- package/package.json +73 -17
- package/.nvmrc +0 -1
- package/config/future.js +0 -7
- package/config/patronum.js +0 -5
- package/config/react.js +0 -7
- package/config/recommended.js +0 -15
- package/config/scope.js +0 -6
- package/index.js +0 -31
- package/rules/enforce-effect-naming-convention/enforce-effect-naming-convention.js +0 -143
- package/rules/enforce-gate-naming-convention/enforce-gate-naming-convention.js +0 -122
- package/rules/enforce-store-naming-convention/enforce-store-naming-convention.js +0 -205
- package/rules/keep-options-order/config.js +0 -3
- package/rules/keep-options-order/keep-options-order.js +0 -107
- package/rules/mandatory-scope-binding/mandatory-scope-binding.js +0 -81
- package/rules/no-ambiguity-target/no-ambiguity-target.js +0 -74
- package/rules/no-duplicate-clock-or-source-array-values/no-duplicate-clock-or-source-array-values.js +0 -124
- package/rules/no-duplicate-on/no-duplicate-on.js +0 -137
- package/rules/no-forward/no-forward.js +0 -73
- package/rules/no-getState/no-getState.js +0 -50
- package/rules/no-guard/no-guard.js +0 -78
- package/rules/no-patronum-debug/no-patronum-debug.js +0 -133
- package/rules/no-unnecessary-combination/no-unnecessary-combination.js +0 -88
- package/rules/no-unnecessary-duplication/no-unnecessary-duplication.js +0 -115
- package/rules/no-useless-methods/no-useless-methods.js +0 -93
- package/rules/no-watch/no-watch.js +0 -61
- package/rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.js +0 -111
- package/rules/prefer-useUnit/prefer-useUnit.js +0 -56
- package/rules/require-pickup-in-persist/require-pickup-in-persist.js +0 -47
- package/rules/strict-effect-handlers/strict-effect-handlers.js +0 -76
- package/utils/are-nodes-same-in-text.js +0 -22
- package/utils/builders.js +0 -19
- package/utils/create-link-to-rule.js +0 -5
- package/utils/extract-config.js +0 -26
- package/utils/extract-imported-from.js +0 -18
- package/utils/get-corrected-store-name.js +0 -45
- package/utils/get-nested-object-name.js +0 -18
- package/utils/get-store-name-convention.js +0 -6
- package/utils/is.js +0 -39
- package/utils/method.js +0 -23
- package/utils/naming.js +0 -47
- package/utils/node-is-type.js +0 -5
- package/utils/node-type-is.js +0 -106
- package/utils/react.js +0 -214
- package/utils/read-example.js +0 -63
- package/utils/replace-by-sample.js +0 -98
- package/utils/traverse-nested-object-node.js +0 -9
- package/utils/traverse-parent-by-type.js +0 -15
- package/utils/validate-store-name-convention.js +0 -13
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
2
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
3
|
-
const { method } = require("../../utils/method");
|
|
4
|
-
const { replaceGuardBySample } = require("../../utils/replace-by-sample");
|
|
5
|
-
const { extractConfig } = require("../../utils/extract-config");
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
meta: {
|
|
9
|
-
type: "problem",
|
|
10
|
-
docs: {
|
|
11
|
-
description: "Prefer `sample` over `guard`",
|
|
12
|
-
category: "Quality",
|
|
13
|
-
recommended: true,
|
|
14
|
-
url: createLinkToRule("no-guard"),
|
|
15
|
-
},
|
|
16
|
-
messages: {
|
|
17
|
-
noGuard:
|
|
18
|
-
"Instead of `guard` you can use `sample`, it is more extendable.",
|
|
19
|
-
replaceWithSample: "Replace `guard` with `sample`.",
|
|
20
|
-
},
|
|
21
|
-
schema: [],
|
|
22
|
-
hasSuggestions: true,
|
|
23
|
-
},
|
|
24
|
-
create(context) {
|
|
25
|
-
const importNodes = new Map();
|
|
26
|
-
const importedFromEffector = new Map();
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
ImportDeclaration(node) {
|
|
30
|
-
extractImportedFrom({
|
|
31
|
-
importMap: importedFromEffector,
|
|
32
|
-
nodeMap: importNodes,
|
|
33
|
-
node,
|
|
34
|
-
packageName: "effector",
|
|
35
|
-
});
|
|
36
|
-
},
|
|
37
|
-
CallExpression(node) {
|
|
38
|
-
if (
|
|
39
|
-
method.isNot("guard", {
|
|
40
|
-
node,
|
|
41
|
-
importMap: importedFromEffector,
|
|
42
|
-
})
|
|
43
|
-
) {
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
const guardConfig = extractConfig(
|
|
48
|
-
["source", "clock", "target", "filter"],
|
|
49
|
-
{
|
|
50
|
-
node,
|
|
51
|
-
}
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
if (!guardConfig.clock || !guardConfig.filter) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
context.report({
|
|
59
|
-
messageId: "noGuard",
|
|
60
|
-
node,
|
|
61
|
-
suggest: [
|
|
62
|
-
{
|
|
63
|
-
messageId: "replaceWithSample",
|
|
64
|
-
*fix(fixer) {
|
|
65
|
-
yield* replaceGuardBySample(guardConfig, {
|
|
66
|
-
fixer,
|
|
67
|
-
node,
|
|
68
|
-
context,
|
|
69
|
-
importNodes,
|
|
70
|
-
});
|
|
71
|
-
},
|
|
72
|
-
},
|
|
73
|
-
],
|
|
74
|
-
});
|
|
75
|
-
},
|
|
76
|
-
};
|
|
77
|
-
},
|
|
78
|
-
};
|
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
2
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
3
|
-
|
|
4
|
-
module.exports = {
|
|
5
|
-
meta: {
|
|
6
|
-
type: "suggestion",
|
|
7
|
-
docs: {
|
|
8
|
-
description: "Disallow the use of patronum `debug`",
|
|
9
|
-
category: "Quality",
|
|
10
|
-
recommended: false,
|
|
11
|
-
url: createLinkToRule("no-patronum-debug"),
|
|
12
|
-
},
|
|
13
|
-
messages: {
|
|
14
|
-
noPatronumDebug: "Unexpected patronum `debug` statement",
|
|
15
|
-
removePatronumDebug: "Remove this `debug` from patronum",
|
|
16
|
-
},
|
|
17
|
-
schema: [],
|
|
18
|
-
hasSuggestions: true,
|
|
19
|
-
},
|
|
20
|
-
create(context) {
|
|
21
|
-
const importedFromPatronum = new Map();
|
|
22
|
-
const importNodes = new Map();
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
ImportDeclaration(node) {
|
|
26
|
-
extractImportedFrom({
|
|
27
|
-
packageName: ["patronum", "patronum/debug"],
|
|
28
|
-
importMap: importedFromPatronum,
|
|
29
|
-
nodeMap: importNodes,
|
|
30
|
-
node,
|
|
31
|
-
});
|
|
32
|
-
},
|
|
33
|
-
CallExpression(node) {
|
|
34
|
-
const currentMethod = node?.callee?.name ?? node?.callee?.object?.name;
|
|
35
|
-
const importedDebugFromPatronum = importedFromPatronum.get("debug");
|
|
36
|
-
|
|
37
|
-
if (
|
|
38
|
-
!importedDebugFromPatronum ||
|
|
39
|
-
currentMethod !== importedDebugFromPatronum
|
|
40
|
-
) {
|
|
41
|
-
return;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
context.report({
|
|
45
|
-
messageId: "noPatronumDebug",
|
|
46
|
-
node,
|
|
47
|
-
suggest: [
|
|
48
|
-
{
|
|
49
|
-
messageId: "removePatronumDebug",
|
|
50
|
-
*fix(fixer) {
|
|
51
|
-
yield* removeDebugFromPatronum({
|
|
52
|
-
fixer,
|
|
53
|
-
node,
|
|
54
|
-
context,
|
|
55
|
-
importNodes,
|
|
56
|
-
});
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
],
|
|
60
|
-
});
|
|
61
|
-
},
|
|
62
|
-
};
|
|
63
|
-
},
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
function* removeDebugFromPatronum({
|
|
67
|
-
fixer,
|
|
68
|
-
node,
|
|
69
|
-
context,
|
|
70
|
-
importNodes,
|
|
71
|
-
targetMethod = "debug",
|
|
72
|
-
}) {
|
|
73
|
-
const sourceCode = context.getSourceCode();
|
|
74
|
-
const startToken = sourceCode.getTokenBefore(node);
|
|
75
|
-
|
|
76
|
-
// remove line with debug
|
|
77
|
-
yield fixer.removeRange([startToken.range[1], node.range[1]]);
|
|
78
|
-
const semi = sourceCode.getTokenBefore(node, {
|
|
79
|
-
filter: (token) => token.value === ";",
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (semi) yield fixer.remove(semi);
|
|
83
|
-
|
|
84
|
-
const importDebugNode = importNodes.get(targetMethod);
|
|
85
|
-
|
|
86
|
-
if (!importDebugNode) {
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
// remove import with debug
|
|
91
|
-
const importParentNode = importDebugNode.parent;
|
|
92
|
-
const amountImportFromPatronum = importParentNode.specifiers.length;
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* import { debug } from 'patronum'
|
|
96
|
-
* import { debug } from 'patronum/debug'
|
|
97
|
-
*/
|
|
98
|
-
if (amountImportFromPatronum === 1) {
|
|
99
|
-
yield fixer.removeRange([
|
|
100
|
-
importParentNode.range[0],
|
|
101
|
-
importParentNode.range[1] + 1,
|
|
102
|
-
]);
|
|
103
|
-
|
|
104
|
-
return null;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const importLast = importParentNode.specifiers[amountImportFromPatronum - 1];
|
|
108
|
-
const filterTokenComma = { filter: (token) => token.value === "," };
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* import { debug, timeout } from 'patronum'
|
|
112
|
-
* import { condition, debug, throttle } from 'patronum'
|
|
113
|
-
*/
|
|
114
|
-
if (importDebugNode !== importLast) {
|
|
115
|
-
const prevNode = sourceCode.getTokenBefore(importDebugNode);
|
|
116
|
-
const comma = sourceCode.getTokenAfter(importDebugNode, filterTokenComma);
|
|
117
|
-
|
|
118
|
-
yield fixer.removeRange([prevNode.range[1], importDebugNode.range[0]]);
|
|
119
|
-
yield fixer.remove(importDebugNode);
|
|
120
|
-
yield fixer.remove(comma);
|
|
121
|
-
|
|
122
|
-
return null;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
/**
|
|
126
|
-
* import { condition, debug } from 'patronum'
|
|
127
|
-
*/
|
|
128
|
-
const comma = sourceCode.getTokenBefore(importDebugNode, filterTokenComma);
|
|
129
|
-
|
|
130
|
-
yield fixer.removeRange([comma.range[1], importDebugNode.range[0]]);
|
|
131
|
-
yield fixer.remove(importDebugNode);
|
|
132
|
-
yield fixer.remove(comma);
|
|
133
|
-
}
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
2
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
3
|
-
const { method } = require("../../utils/method");
|
|
4
|
-
|
|
5
|
-
module.exports = {
|
|
6
|
-
meta: {
|
|
7
|
-
type: "problem",
|
|
8
|
-
docs: {
|
|
9
|
-
description:
|
|
10
|
-
"Forbids unnecessary combinations in `clock`, `source` and `forward`",
|
|
11
|
-
category: "Quality",
|
|
12
|
-
recommended: true,
|
|
13
|
-
url: createLinkToRule("no-unnecessary-combination"),
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
unnecessaryCombination:
|
|
17
|
-
"Method {{ methodName }} is used under the hood, you can omit it.",
|
|
18
|
-
},
|
|
19
|
-
schema: [],
|
|
20
|
-
},
|
|
21
|
-
create(context) {
|
|
22
|
-
const importedFromEffector = new Map();
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
ImportDeclaration(node) {
|
|
26
|
-
extractImportedFrom({
|
|
27
|
-
importMap: importedFromEffector,
|
|
28
|
-
node,
|
|
29
|
-
packageName: "effector",
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
CallExpression(node) {
|
|
33
|
-
const CONFIG_ARG_PROPERTIES = ["source", "clock", "from"];
|
|
34
|
-
|
|
35
|
-
function toLocalMethod(methodName) {
|
|
36
|
-
return importedFromEffector.get(methodName);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const UNNECESSARY_METHODS = {
|
|
40
|
-
source: ["combine", "merge"].map(toLocalMethod).filter(Boolean),
|
|
41
|
-
clock: ["merge"].map(toLocalMethod).filter(Boolean),
|
|
42
|
-
from: ["merge"].map(toLocalMethod).filter(Boolean),
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
if (
|
|
46
|
-
method.isNot(["sample", "guard", "forward"], {
|
|
47
|
-
node,
|
|
48
|
-
importMap: importedFromEffector,
|
|
49
|
-
})
|
|
50
|
-
) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const candidates =
|
|
55
|
-
node?.arguments?.[0]?.properties?.filter((n) =>
|
|
56
|
-
CONFIG_ARG_PROPERTIES.includes(n.key.name)
|
|
57
|
-
) ?? [];
|
|
58
|
-
|
|
59
|
-
if (candidates.length === 0) {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
for (const candidate of candidates) {
|
|
64
|
-
const candidateName = candidate?.value?.callee?.name;
|
|
65
|
-
const argProp = candidate?.key?.name;
|
|
66
|
-
if (!candidateName || !argProp) {
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const localUnnecessaryMethods = UNNECESSARY_METHODS[argProp];
|
|
71
|
-
|
|
72
|
-
const UnnecessaryMethodIsEffectorMethod =
|
|
73
|
-
localUnnecessaryMethods.some((m) => m === candidateName);
|
|
74
|
-
|
|
75
|
-
if (!UnnecessaryMethodIsEffectorMethod) {
|
|
76
|
-
continue;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
context.report({
|
|
80
|
-
node: candidate?.value,
|
|
81
|
-
messageId: "unnecessaryCombination",
|
|
82
|
-
data: { methodName: candidateName },
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
},
|
|
88
|
-
};
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
2
|
-
const { areNodesSameInText } = require("../../utils/are-nodes-same-in-text");
|
|
3
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
4
|
-
const { buildObjectInText } = require("../../utils/builders");
|
|
5
|
-
const { method } = require("../../utils/method");
|
|
6
|
-
|
|
7
|
-
module.exports = {
|
|
8
|
-
meta: {
|
|
9
|
-
type: "problem",
|
|
10
|
-
docs: {
|
|
11
|
-
description: "Forbids unnecessary duplication in `clock` and `source`",
|
|
12
|
-
category: "Quality",
|
|
13
|
-
recommended: true,
|
|
14
|
-
url: createLinkToRule("no-unnecessary-duplication"),
|
|
15
|
-
},
|
|
16
|
-
messages: {
|
|
17
|
-
unnecessaryDuplication:
|
|
18
|
-
"Same `source` and `clock` can be replaced with only one of them.",
|
|
19
|
-
removeClock: "Remove `clock`",
|
|
20
|
-
removeSource: "Remove `source`",
|
|
21
|
-
},
|
|
22
|
-
schema: [],
|
|
23
|
-
hasSuggestions: true,
|
|
24
|
-
},
|
|
25
|
-
create(context) {
|
|
26
|
-
const importedFromEffector = new Map();
|
|
27
|
-
|
|
28
|
-
return {
|
|
29
|
-
ImportDeclaration(node) {
|
|
30
|
-
extractImportedFrom({
|
|
31
|
-
importMap: importedFromEffector,
|
|
32
|
-
node,
|
|
33
|
-
packageName: "effector",
|
|
34
|
-
});
|
|
35
|
-
},
|
|
36
|
-
CallExpression(node) {
|
|
37
|
-
if (
|
|
38
|
-
method.isNot(["sample", "guard"], {
|
|
39
|
-
node,
|
|
40
|
-
importMap: importedFromEffector,
|
|
41
|
-
})
|
|
42
|
-
) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const params = {
|
|
47
|
-
source: node?.arguments?.[0]?.properties?.find(
|
|
48
|
-
(n) => n.key.name === "source"
|
|
49
|
-
),
|
|
50
|
-
clock: node?.arguments?.[0]?.properties?.find(
|
|
51
|
-
(n) => n.key.name === "clock"
|
|
52
|
-
),
|
|
53
|
-
};
|
|
54
|
-
if (!params.source || !params.clock) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const sameSourceAndClock = areNodesSameInText({
|
|
59
|
-
context,
|
|
60
|
-
nodes: [params.source?.value, params.clock?.value],
|
|
61
|
-
});
|
|
62
|
-
if (!sameSourceAndClock) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
reportUnnecessaryDuplication({
|
|
67
|
-
context,
|
|
68
|
-
node,
|
|
69
|
-
params,
|
|
70
|
-
firstArgument: node?.arguments?.[0],
|
|
71
|
-
});
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
function reportUnnecessaryDuplication({
|
|
78
|
-
context,
|
|
79
|
-
node,
|
|
80
|
-
params,
|
|
81
|
-
firstArgument,
|
|
82
|
-
}) {
|
|
83
|
-
function excludeParamFromObjectInText(objectNode, paramToExcludeNode) {
|
|
84
|
-
const properties = objectNode?.properties?.filter?.(
|
|
85
|
-
(p) => p !== paramToExcludeNode
|
|
86
|
-
);
|
|
87
|
-
|
|
88
|
-
return buildObjectInText.fromArrayOfNodes({ properties, context });
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
context.report({
|
|
92
|
-
node,
|
|
93
|
-
messageId: "unnecessaryDuplication",
|
|
94
|
-
suggest: [
|
|
95
|
-
{
|
|
96
|
-
messageId: "removeClock",
|
|
97
|
-
fix(fixer) {
|
|
98
|
-
return fixer.replaceText(
|
|
99
|
-
firstArgument,
|
|
100
|
-
excludeParamFromObjectInText(firstArgument, params.clock)
|
|
101
|
-
);
|
|
102
|
-
},
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
messageId: "removeSource",
|
|
106
|
-
fix(fixer) {
|
|
107
|
-
return fixer.replaceText(
|
|
108
|
-
firstArgument,
|
|
109
|
-
excludeParamFromObjectInText(firstArgument, params.source)
|
|
110
|
-
);
|
|
111
|
-
},
|
|
112
|
-
},
|
|
113
|
-
],
|
|
114
|
-
});
|
|
115
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
2
|
-
const { traverseParentByType } = require("../../utils/traverse-parent-by-type");
|
|
3
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
4
|
-
const { method } = require("../../utils/method");
|
|
5
|
-
|
|
6
|
-
module.exports = {
|
|
7
|
-
meta: {
|
|
8
|
-
type: "problem",
|
|
9
|
-
docs: {
|
|
10
|
-
description: "Forbids useless calls of `sample` and `guard`",
|
|
11
|
-
category: "Quality",
|
|
12
|
-
recommended: true,
|
|
13
|
-
url: createLinkToRule("no-useless-methods"),
|
|
14
|
-
},
|
|
15
|
-
messages: {
|
|
16
|
-
uselessMethod:
|
|
17
|
-
"Method `{{ methodName }}` does nothing in this case. You should assign the result to variable or pass `target` to it.",
|
|
18
|
-
},
|
|
19
|
-
schema: [],
|
|
20
|
-
},
|
|
21
|
-
create(context) {
|
|
22
|
-
const importedFromEffector = new Map();
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
ImportDeclaration(node) {
|
|
26
|
-
extractImportedFrom({
|
|
27
|
-
importMap: importedFromEffector,
|
|
28
|
-
node,
|
|
29
|
-
packageName: "effector",
|
|
30
|
-
});
|
|
31
|
-
},
|
|
32
|
-
CallExpression(node) {
|
|
33
|
-
if (
|
|
34
|
-
method.isNot(["sample", "guard"], {
|
|
35
|
-
node,
|
|
36
|
-
importMap: importedFromEffector,
|
|
37
|
-
})
|
|
38
|
-
) {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const resultAssignedInVariable = traverseParentByType(
|
|
43
|
-
node,
|
|
44
|
-
"VariableDeclarator"
|
|
45
|
-
);
|
|
46
|
-
if (resultAssignedInVariable) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const resultReturnedFromFactory = traverseParentByType(
|
|
51
|
-
node,
|
|
52
|
-
"ReturnStatement"
|
|
53
|
-
);
|
|
54
|
-
if (resultReturnedFromFactory) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const resultPartOfChain = traverseParentByType(
|
|
59
|
-
node,
|
|
60
|
-
"ObjectExpression"
|
|
61
|
-
);
|
|
62
|
-
if (resultPartOfChain) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
const configHasTarget = node?.arguments?.[0]?.properties?.some(
|
|
67
|
-
(prop) => prop?.key.name === "target"
|
|
68
|
-
);
|
|
69
|
-
if (configHasTarget) {
|
|
70
|
-
return;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
const resultIsWatched = node?.parent?.property?.name === "watch";
|
|
74
|
-
if (resultIsWatched) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
const resultIsArgument = node?.parent?.type === "CallExpression";
|
|
79
|
-
if (resultIsArgument) {
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
context.report({
|
|
84
|
-
node,
|
|
85
|
-
messageId: "uselessMethod",
|
|
86
|
-
data: {
|
|
87
|
-
methodName: node?.callee?.name,
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
},
|
|
91
|
-
};
|
|
92
|
-
},
|
|
93
|
-
};
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
const { ESLintUtils } = require("@typescript-eslint/utils");
|
|
2
|
-
|
|
3
|
-
const {
|
|
4
|
-
traverseNestedObjectNode,
|
|
5
|
-
} = require("../../utils/traverse-nested-object-node");
|
|
6
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
7
|
-
const { nodeTypeIs } = require("../../utils/node-type-is");
|
|
8
|
-
|
|
9
|
-
module.exports = {
|
|
10
|
-
meta: {
|
|
11
|
-
type: "suggestion",
|
|
12
|
-
docs: {
|
|
13
|
-
description: "Avoid `.watch` calls on any Effector unit or operator",
|
|
14
|
-
category: "Quality",
|
|
15
|
-
recommended: true,
|
|
16
|
-
url: createLinkToRule("no-watch"),
|
|
17
|
-
},
|
|
18
|
-
messages: {
|
|
19
|
-
abusiveCall:
|
|
20
|
-
"Method `.watch` leads to imperative code. Try to replace it with operator (`sample`) or use the `target` parameter of the operator.",
|
|
21
|
-
},
|
|
22
|
-
schema: [],
|
|
23
|
-
},
|
|
24
|
-
create(context) {
|
|
25
|
-
let parserServices;
|
|
26
|
-
try {
|
|
27
|
-
parserServices = ESLintUtils.getParserServices(context);
|
|
28
|
-
} catch (err) {
|
|
29
|
-
// no types information
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (!parserServices?.program) {
|
|
33
|
-
// JavaScript-way https://github.com/effector/eslint-plugin/issues/48#issuecomment-931107829
|
|
34
|
-
return {};
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return {
|
|
38
|
-
'CallExpression[callee.property.name="watch"]'(node) {
|
|
39
|
-
const object = traverseNestedObjectNode(node.callee?.object);
|
|
40
|
-
|
|
41
|
-
const isEffectorUnit = nodeTypeIs.unit({
|
|
42
|
-
node: object,
|
|
43
|
-
context,
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
if (!isEffectorUnit) {
|
|
47
|
-
return;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
reportWatchCall({ context, node });
|
|
51
|
-
},
|
|
52
|
-
};
|
|
53
|
-
},
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
function reportWatchCall({ context, node }) {
|
|
57
|
-
context.report({
|
|
58
|
-
node,
|
|
59
|
-
messageId: "abusiveCall",
|
|
60
|
-
});
|
|
61
|
-
}
|
package/rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.js
DELETED
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
const { extractImportedFrom } = require("../../utils/extract-imported-from");
|
|
2
|
-
const {
|
|
3
|
-
traverseNestedObjectNode,
|
|
4
|
-
} = require("../../utils/traverse-nested-object-node");
|
|
5
|
-
const { createLinkToRule } = require("../../utils/create-link-to-rule");
|
|
6
|
-
const { method } = require("../../utils/method");
|
|
7
|
-
const { replaceForwardBySample } = require("../../utils/replace-by-sample");
|
|
8
|
-
const { extractConfig } = require("../../utils/extract-config");
|
|
9
|
-
|
|
10
|
-
module.exports = {
|
|
11
|
-
meta: {
|
|
12
|
-
type: "problem",
|
|
13
|
-
docs: {
|
|
14
|
-
description: "Prefer `sample` over `forward` with `.map`/`.prepend`",
|
|
15
|
-
category: "Quality",
|
|
16
|
-
recommended: true,
|
|
17
|
-
url: createLinkToRule("prefer-sample-over-forward-with-mapping"),
|
|
18
|
-
},
|
|
19
|
-
messages: {
|
|
20
|
-
overMap:
|
|
21
|
-
"Instead of `forward` with `{{ eventName }}.map` you can use `sample`",
|
|
22
|
-
overPrepend:
|
|
23
|
-
"Instead of `forward` with `{{ eventName }}.prepend` you can use `sample`",
|
|
24
|
-
replaceWithSample: "Replace `forward` with `sample`.",
|
|
25
|
-
},
|
|
26
|
-
schema: [],
|
|
27
|
-
hasSuggestions: true,
|
|
28
|
-
},
|
|
29
|
-
create(context) {
|
|
30
|
-
const importNodes = new Map();
|
|
31
|
-
const importedFromEffector = new Map();
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
ImportDeclaration(node) {
|
|
35
|
-
extractImportedFrom({
|
|
36
|
-
importMap: importedFromEffector,
|
|
37
|
-
nodeMap: importNodes,
|
|
38
|
-
node,
|
|
39
|
-
packageName: "effector",
|
|
40
|
-
});
|
|
41
|
-
},
|
|
42
|
-
CallExpression(node) {
|
|
43
|
-
if (
|
|
44
|
-
method.isNot("forward", {
|
|
45
|
-
node,
|
|
46
|
-
importMap: importedFromEffector,
|
|
47
|
-
})
|
|
48
|
-
) {
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const forwardConfig = extractConfig(["from", "to"], { node });
|
|
53
|
-
|
|
54
|
-
if (!forwardConfig.from || !forwardConfig.to) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function checkForMapping({ paramNode, methodName, messageId }) {
|
|
59
|
-
if (paramNode.value?.type !== "CallExpression") {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
if (paramNode.value?.callee?.property?.name !== methodName) {
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const eventNode = traverseNestedObjectNode(
|
|
68
|
-
paramNode.value?.callee?.object
|
|
69
|
-
);
|
|
70
|
-
const eventName = eventNode?.name;
|
|
71
|
-
|
|
72
|
-
if (!eventName) {
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
context.report({
|
|
77
|
-
node,
|
|
78
|
-
messageId,
|
|
79
|
-
data: {
|
|
80
|
-
eventName,
|
|
81
|
-
},
|
|
82
|
-
suggest: [
|
|
83
|
-
{
|
|
84
|
-
messageId: "replaceWithSample",
|
|
85
|
-
*fix(fixer) {
|
|
86
|
-
yield* replaceForwardBySample(forwardConfig, {
|
|
87
|
-
fixer,
|
|
88
|
-
node,
|
|
89
|
-
context,
|
|
90
|
-
importNodes,
|
|
91
|
-
});
|
|
92
|
-
},
|
|
93
|
-
},
|
|
94
|
-
],
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
checkForMapping({
|
|
99
|
-
paramNode: forwardConfig.from,
|
|
100
|
-
methodName: "map",
|
|
101
|
-
messageId: "overMap",
|
|
102
|
-
});
|
|
103
|
-
checkForMapping({
|
|
104
|
-
paramNode: forwardConfig.to,
|
|
105
|
-
methodName: "prepend",
|
|
106
|
-
messageId: "overPrepend",
|
|
107
|
-
});
|
|
108
|
-
},
|
|
109
|
-
};
|
|
110
|
-
},
|
|
111
|
-
};
|