eslint-plugin-effector 0.3.0 → 0.4.2

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 CHANGED
@@ -41,10 +41,24 @@ To configure individual rules:
41
41
 
42
42
  ## Supported Rules
43
43
 
44
- - [effector/enforce-store-naming-convention](/rules/enforce-store-naming-convention/enforce-store-naming-convention.md)
45
- - [effector/enforce-effect-naming-convention](/rules/enforce-effect-naming-convention/enforce-effect-naming-convention.md)
46
- - [effector/no-getState](/rules/no-getState/no-getState.md)
47
- - [effector/no-unnecessary-duplication](/rules/no-unnecessary-duplication/no-unnecessary-duplication.md)
48
- - [effector/no-useless-methods](/rules/no-useless-methods/no-useless-methods.md)
49
- - [effector/no-ambiguity-target](/rules/no-ambiguity-target/no-ambiguity-target.md)
50
- - [effector/prefer-sample-over-forward-with-mapping](/rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.md)
44
+ - [effector/enforce-store-naming-convention](rules/enforce-store-naming-convention/enforce-store-naming-convention.md)
45
+ - [effector/enforce-effect-naming-convention](rules/enforce-effect-naming-convention/enforce-effect-naming-convention.md)
46
+ - [effector/no-getState](rules/no-getState/no-getState.md)
47
+ - [effector/no-unnecessary-duplication](rules/no-unnecessary-duplication/no-unnecessary-duplication.md)
48
+ - [effector/no-useless-methods](rules/no-useless-methods/no-useless-methods.md)
49
+ - [effector/no-ambiguity-target](rules/no-ambiguity-target/no-ambiguity-target.md)
50
+ - [effector/prefer-sample-over-forward-with-mapping](rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.md)
51
+ - [effector/no-watch](rules/no-watch/no-watch.md)
52
+ - [effector/no-unnecessary-combination](rules/no-unnecessary-combination/no-unnecessary-combination.md)
53
+
54
+ ## Maintenance
55
+
56
+ ### Release flow
57
+
58
+ 1. Bump `version` in [package.json](package.json)
59
+ 2. Fill [CHANGELOG.md](CHANGELOG.md)
60
+ 3. Commit changes by `git commin -m "Release X.X.X"`
61
+ 4. Create git tag for release by `git tag -a vX.X.X -m "vX.X.X"`
62
+ 5. Push changes to remote by `git push --follow-tags`
63
+ 6. Release package to registry by `yarn clean-publish`
64
+ 7. Fill release page with changelog on GitHub
@@ -7,5 +7,7 @@ module.exports = {
7
7
  "effector/no-unnecessary-duplication": "warn",
8
8
  "effector/prefer-sample-over-forward-with-mapping": "warn",
9
9
  "effector/no-ambiguity-target": "warn",
10
+ "effector/no-watch": "warn",
11
+ "effector/no-unnecessary-combination": "warn",
10
12
  },
11
13
  };
package/index.js CHANGED
@@ -7,8 +7,10 @@ module.exports = {
7
7
  "prefer-sample-over-forward-with-mapping": require("./rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping"),
8
8
  "no-useless-methods": require("./rules/no-useless-methods/no-useless-methods"),
9
9
  "no-ambiguity-target": require("./rules/no-ambiguity-target/no-ambiguity-target"),
10
+ "no-watch": require("./rules/no-watch/no-watch"),
11
+ "no-unnecessary-combination": require("./rules/no-unnecessary-combination/no-unnecessary-combination"),
10
12
  },
11
13
  configs: {
12
14
  recommended: require("./config/recommended"),
13
- }
15
+ },
14
16
  };
package/package.json CHANGED
@@ -1,33 +1,28 @@
1
1
  {
2
2
  "name": "eslint-plugin-effector",
3
- "version": "0.3.0",
3
+ "version": "0.4.2",
4
4
  "description": "Enforcing best practices for Effector",
5
+ "keywords": [
6
+ "eslint",
7
+ "eslint-plugin",
8
+ "eslintplugin",
9
+ "effector"
10
+ ],
11
+ "repository": "effector/eslint-plugin",
5
12
  "main": "index.js",
6
13
  "author": "Igor Kamyshev <igor@kamyshev.me>",
7
14
  "license": "MIT",
8
- "scripts": {
9
- "test": "jest"
10
- },
11
15
  "publishConfig": {
12
16
  "access": "public"
13
17
  },
14
18
  "engines": {
15
19
  "node": "^14 || ^16"
16
20
  },
17
- "devDependencies": {
18
- "@typescript-eslint/experimental-utils": "^4.29.3",
19
- "@typescript-eslint/parser": "^4.29.3",
20
- "effector": "^22.0.0",
21
- "eslint": "^7.32.0",
22
- "glob": "^7.1.7",
23
- "jest": "^27.1.0",
24
- "typescript": "^4.4.2"
25
- },
26
21
  "peerDependencies": {
27
22
  "effector": "*",
28
- "eslint": "*"
23
+ "eslint": "7 || 8"
29
24
  },
30
25
  "dependencies": {
31
26
  "prettier": "^2.3.2"
32
27
  }
33
- }
28
+ }
@@ -1,6 +1,7 @@
1
1
  const {
2
2
  extractImportedFromEffector,
3
3
  } = require("../../utils/extract-imported-from-effector");
4
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
4
5
 
5
6
  module.exports = {
6
7
  meta: {
@@ -10,6 +11,7 @@ module.exports = {
10
11
  "Enforce Fx as a suffix for any effect created by Effector methods",
11
12
  category: "Naming",
12
13
  recommended: true,
14
+ url: createLinkToRule("enforce-effect-naming-convention"),
13
15
  },
14
16
  messages: {
15
17
  invalidName:
@@ -17,6 +19,7 @@ module.exports = {
17
19
  renameEffect: 'Rename "{{ effectName }}" to "{{ effectName }}Fx"',
18
20
  },
19
21
  schema: [],
22
+ hasSuggestions: true,
20
23
  },
21
24
  create(context) {
22
25
  const parserServices = context.parserServices;
@@ -2,25 +2,34 @@ const {
2
2
  extractImportedFromEffector,
3
3
  } = require("../../utils/extract-imported-from-effector");
4
4
  const { isStoreNameValid } = require("../../utils/is-store-name-valid");
5
- const { validateStoreNameConvention } = require("../../utils/validate-store-name-convention");
6
- const { getStoreNameConvention } = require("../../utils/get-store-name-convention");
7
- const { getCorrectedStoreName } = require("../../utils/get-corrected-store-name");
5
+ const {
6
+ validateStoreNameConvention,
7
+ } = require("../../utils/validate-store-name-convention");
8
+ const {
9
+ getStoreNameConvention,
10
+ } = require("../../utils/get-store-name-convention");
11
+ const {
12
+ getCorrectedStoreName,
13
+ } = require("../../utils/get-corrected-store-name");
14
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
8
15
 
9
16
  module.exports = {
10
17
  meta: {
11
18
  type: "problem",
12
19
  docs: {
13
20
  description:
14
- "Enforce $ as a prefix or postfix for any store created by Effector methods",
21
+ "Enforce $ as a prefix or postfix for any store created by Effector methods",
15
22
  category: "Naming",
16
23
  recommended: true,
24
+ url: createLinkToRule("enforce-store-naming-convention"),
17
25
  },
18
26
  messages: {
19
27
  invalidName:
20
- 'Store "{{ storeName }}" should be named with {{ storeNameConvention }}, rename it to "{{ correctedStoreName }}"',
28
+ 'Store "{{ storeName }}" should be named with {{ storeNameConvention }}, rename it to "{{ correctedStoreName }}"',
21
29
  renameStore: 'Rename "{{ storeName }}" to "{{ correctedStoreName }}"',
22
30
  },
23
31
  schema: [],
32
+ hasSuggestions: true,
24
33
  },
25
34
  create(context) {
26
35
  const { parserServices } = context;
@@ -36,8 +45,8 @@ module.exports = {
36
45
  const type = checker.getTypeAtLocation(originalNode.initializer);
37
46
 
38
47
  const isEffectorStore =
39
- type?.symbol?.escapedName === "Store" &&
40
- type?.symbol?.parent?.escapedName?.includes("effector");
48
+ type?.symbol?.escapedName === "Store" &&
49
+ type?.symbol?.parent?.escapedName?.includes("effector");
41
50
 
42
51
  if (!isEffectorStore) {
43
52
  return;
@@ -52,7 +61,7 @@ module.exports = {
52
61
  reportStoreNameConventionViolation({
53
62
  context,
54
63
  node,
55
- storeName
64
+ storeName,
56
65
  });
57
66
  },
58
67
  };
@@ -79,7 +88,7 @@ module.exports = {
79
88
  }
80
89
 
81
90
  const resultSavedInVariable =
82
- node.parent.type === "VariableDeclarator";
91
+ node.parent.type === "VariableDeclarator";
83
92
  if (!resultSavedInVariable) {
84
93
  continue;
85
94
  }
@@ -93,7 +102,7 @@ module.exports = {
93
102
  reportStoreNameConventionViolation({
94
103
  context,
95
104
  node: node.parent,
96
- storeName
105
+ storeName,
97
106
  });
98
107
  return;
99
108
  }
@@ -107,7 +116,7 @@ module.exports = {
107
116
  }
108
117
 
109
118
  const resultSavedInVariable =
110
- node.parent.type === "VariableDeclarator";
119
+ node.parent.type === "VariableDeclarator";
111
120
  if (!resultSavedInVariable) {
112
121
  return;
113
122
  }
@@ -118,11 +127,10 @@ module.exports = {
118
127
  return;
119
128
  }
120
129
 
121
-
122
130
  reportStoreNameConventionViolation({
123
131
  context,
124
132
  node: node.parent,
125
- storeName
133
+ storeName,
126
134
  });
127
135
  return;
128
136
  }
@@ -130,10 +138,10 @@ module.exports = {
130
138
  // Store creation in domain
131
139
  const STORE_IN_DOMAIN_CREATION_METHODS = ["createStore", "store"];
132
140
  if (
133
- STORE_IN_DOMAIN_CREATION_METHODS.includes(node.callee?.property?.name)
141
+ STORE_IN_DOMAIN_CREATION_METHODS.includes(node.callee?.property?.name)
134
142
  ) {
135
143
  const resultSavedInVariable =
136
- node.parent.type === "VariableDeclarator";
144
+ node.parent.type === "VariableDeclarator";
137
145
  if (!resultSavedInVariable) {
138
146
  return;
139
147
  }
@@ -147,7 +155,7 @@ module.exports = {
147
155
  reportStoreNameConventionViolation({
148
156
  context,
149
157
  node: node.parent,
150
- storeName
158
+ storeName,
151
159
  });
152
160
  return;
153
161
  }
@@ -157,7 +165,6 @@ module.exports = {
157
165
  };
158
166
 
159
167
  function reportStoreNameConventionViolation({ context, node, storeName }) {
160
-
161
168
  const storeNameConvention = getStoreNameConvention(context);
162
169
  const correctedStoreName = getCorrectedStoreName(storeName, context);
163
170
 
@@ -167,7 +174,7 @@ function reportStoreNameConventionViolation({ context, node, storeName }) {
167
174
  data: {
168
175
  storeName,
169
176
  correctedStoreName,
170
- storeNameConvention
177
+ storeNameConvention,
171
178
  },
172
179
  suggest: [
173
180
  {
@@ -180,4 +187,3 @@ function reportStoreNameConventionViolation({ context, node, storeName }) {
180
187
  ],
181
188
  });
182
189
  }
183
-
@@ -17,7 +17,7 @@ Prefix convention will be enforced:
17
17
  const $name = createStore(null);
18
18
 
19
19
  // 👎 bad name
20
- const name = createStrore(null);
20
+ const name = createStore(null);
21
21
  ```
22
22
  ## Postfix convention
23
23
 
@@ -2,6 +2,7 @@ const {
2
2
  extractImportedFromEffector,
3
3
  } = require("../../utils/extract-imported-from-effector");
4
4
  const { traverseParentByType } = require("../../utils/traverse-parent-by-type");
5
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
6
 
6
7
  module.exports = {
7
8
  meta: {
@@ -10,6 +11,7 @@ module.exports = {
10
11
  description: "Forbids ambiguity targets in `sample` and `guard`",
11
12
  category: "Quality",
12
13
  recommended: true,
14
+ url: createLinkToRule("no-ambiguity-target"),
13
15
  },
14
16
  messages: {
15
17
  ambiguityTarget:
@@ -46,7 +48,8 @@ module.exports = {
46
48
 
47
49
  const resultAssignedInVariable = traverseParentByType(
48
50
  node,
49
- "VariableDeclarator"
51
+ "VariableDeclarator",
52
+ { stopOnTypes: ["BlockStatement"] }
50
53
  );
51
54
  const resultPartOfChain = traverseParentByType(
52
55
  node,
@@ -2,6 +2,7 @@ const {
2
2
  traverseNestedObjectNode,
3
3
  } = require("../../utils/traverse-nested-object-node");
4
4
  const { isStoreNameValid } = require("../../utils/is-store-name-valid");
5
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
6
 
6
7
  module.exports = {
7
8
  meta: {
@@ -10,6 +11,7 @@ module.exports = {
10
11
  description: "Forbids `.getState` calls on any Effector store",
11
12
  category: "Quality",
12
13
  recommended: true,
14
+ url: createLinkToRule("no-getState"),
13
15
  },
14
16
  messages: {
15
17
  abusiveCall:
@@ -0,0 +1,94 @@
1
+ const {
2
+ extractImportedFromEffector,
3
+ } = require("../../utils/extract-imported-from-effector");
4
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
+
6
+ module.exports = {
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description:
11
+ "Forbids unnecessary combinations in `clock`, `source` and `forward`",
12
+ category: "Quality",
13
+ recommended: true,
14
+ url: createLinkToRule("no-unnecessary-combination"),
15
+ },
16
+ messages: {
17
+ unnecessaryCombination:
18
+ "Method {{ methodName }} is used under the hood, you can omit it.",
19
+ },
20
+ schema: [],
21
+ },
22
+ create(context) {
23
+ const importedFromEffector = new Map();
24
+
25
+ return {
26
+ ImportDeclaration(node) {
27
+ extractImportedFromEffector(importedFromEffector, node);
28
+ },
29
+ CallExpression(node) {
30
+ const METHODS_WITH_POSSIBLE_UNNECESSARY_COMBINATION = [
31
+ "sample",
32
+ "guard",
33
+ "forward",
34
+ ];
35
+
36
+ const CONFIG_ARG_PROPERTIES = ["source", "clock", "from"];
37
+
38
+ function toLocalMethod(method) {
39
+ return importedFromEffector.get(method);
40
+ }
41
+
42
+ const UNNECESSARY_METHODS = {
43
+ source: ["combine", "merge"].map(toLocalMethod).filter(Boolean),
44
+ clock: ["merge"].map(toLocalMethod).filter(Boolean),
45
+ from: ["merge"].map(toLocalMethod).filter(Boolean),
46
+ };
47
+
48
+ for (const method of METHODS_WITH_POSSIBLE_UNNECESSARY_COMBINATION) {
49
+ const localMethod = importedFromEffector.get(method);
50
+ if (!localMethod) {
51
+ continue;
52
+ }
53
+
54
+ const isEffectorMethod = node?.callee?.name === localMethod;
55
+ if (!isEffectorMethod) {
56
+ continue;
57
+ }
58
+
59
+ const candidates =
60
+ node?.arguments?.[0]?.properties?.filter((n) =>
61
+ CONFIG_ARG_PROPERTIES.includes(n.key.name)
62
+ ) ?? [];
63
+
64
+ if (candidates.length === 0) {
65
+ continue;
66
+ }
67
+
68
+ for (const candidate of candidates) {
69
+ const candidateName = candidate?.value?.callee?.name;
70
+ const argProp = candidate?.key?.name;
71
+ if (!candidateName || !argProp) {
72
+ continue;
73
+ }
74
+
75
+ const localUnnecessaryMethods = UNNECESSARY_METHODS[argProp];
76
+
77
+ const UnnecessaryMethodIsEffectorMethod =
78
+ localUnnecessaryMethods.some((m) => m === candidateName);
79
+
80
+ if (!UnnecessaryMethodIsEffectorMethod) {
81
+ continue;
82
+ }
83
+
84
+ context.report({
85
+ node: candidate?.value,
86
+ messageId: "unnecessaryCombination",
87
+ data: { methodName: candidateName },
88
+ });
89
+ }
90
+ }
91
+ },
92
+ };
93
+ },
94
+ };
@@ -0,0 +1,14 @@
1
+ # effector/no-unnecessary-combination
2
+
3
+ Call of `combine`/`merge` in `clock`/`source` is unnecessary. It can be omitted from source code.
4
+
5
+ ```ts
6
+ // 👎 can be simplified
7
+ const badEventOne = guard({ clock: combine($store1, $store2), filter: $filter });
8
+ const badEventOne = guard({ clock: combine($store1, $store2, (store1, store2) => ({x: store1, y: store2})), filter: $filter });
9
+
10
+ // 👍 better
11
+ const goodEventOne = guard({ clock: [$store1, $store2], filter: $filter });
12
+ const goodEventTwo = guard({ clock: ({x: $store1, x: $store2}), filter: $filter });
13
+ ```
14
+
@@ -2,6 +2,7 @@ const {
2
2
  extractImportedFromEffector,
3
3
  } = require("../../utils/extract-imported-from-effector");
4
4
  const { areNodesSameInText } = require("../../utils/are-nodes-same-in-text");
5
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
6
 
6
7
  module.exports = {
7
8
  meta: {
@@ -10,6 +11,7 @@ module.exports = {
10
11
  description: "Forbids unnecessary duplication in `clock` and `source`",
11
12
  category: "Quality",
12
13
  recommended: true,
14
+ url: createLinkToRule("no-unnecessary-duplication"),
13
15
  },
14
16
  messages: {
15
17
  unnecessaryDuplication:
@@ -18,6 +20,7 @@ module.exports = {
18
20
  removeSource: "Remove `source`",
19
21
  },
20
22
  schema: [],
23
+ hasSuggestions: true,
21
24
  },
22
25
  create(context) {
23
26
  const importedFromEffector = new Map();
@@ -2,6 +2,7 @@ const {
2
2
  extractImportedFromEffector,
3
3
  } = require("../../utils/extract-imported-from-effector");
4
4
  const { traverseParentByType } = require("../../utils/traverse-parent-by-type");
5
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
6
 
6
7
  module.exports = {
7
8
  meta: {
@@ -10,6 +11,7 @@ module.exports = {
10
11
  description: "Forbids useless calls of `sample` and `guard`",
11
12
  category: "Quality",
12
13
  recommended: true,
14
+ url: createLinkToRule("no-useless-methods"),
13
15
  },
14
16
  messages: {
15
17
  uselessMethod:
@@ -68,6 +70,16 @@ module.exports = {
68
70
  continue;
69
71
  }
70
72
 
73
+ const resultIsWatched = node?.parent?.property?.name === "watch";
74
+ if (resultIsWatched) {
75
+ continue;
76
+ }
77
+
78
+ const resultIsArgument = node?.parent?.type === "CallExpression";
79
+ if (resultIsArgument) {
80
+ continue;
81
+ }
82
+
71
83
  context.report({
72
84
  node,
73
85
  messageId: "uselessMethod",
@@ -0,0 +1,59 @@
1
+ const {
2
+ traverseNestedObjectNode,
3
+ } = require("../../utils/traverse-nested-object-node");
4
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
+
6
+ module.exports = {
7
+ meta: {
8
+ type: "suggestion",
9
+ docs: {
10
+ description: "Avoid `.watch` calls on any Effector unit or operator",
11
+ category: "Quality",
12
+ recommended: true,
13
+ url: createLinkToRule("no-watch"),
14
+ },
15
+ messages: {
16
+ abusiveCall:
17
+ "Method `.watch` leads to imperative code. Try to replace it with operators (`sample`, `guard`, etc) or use the `target` parameter of the operators.",
18
+ },
19
+ schema: [],
20
+ },
21
+ create(context) {
22
+ const { parserServices } = context;
23
+ if (!parserServices.hasFullTypeInformation) {
24
+ // JavaScript-way https://github.com/effector/eslint-plugin/issues/48#issuecomment-931107829
25
+ return {};
26
+ }
27
+ const checker = parserServices.program.getTypeChecker();
28
+
29
+ return {
30
+ CallExpression(node) {
31
+ const methodName = node.callee?.property?.name;
32
+ if (methodName !== "watch") {
33
+ return;
34
+ }
35
+
36
+ const object = traverseNestedObjectNode(node.callee?.object);
37
+ const originalNode = parserServices.esTreeNodeToTSNodeMap.get(object);
38
+ const type = checker.getTypeAtLocation(originalNode);
39
+
40
+ const isEffectorUnit =
41
+ ["Effect", "Event", "Store"].includes(type?.symbol?.escapedName) &&
42
+ type?.symbol?.parent?.escapedName?.includes("effector");
43
+
44
+ if (!isEffectorUnit) {
45
+ return;
46
+ }
47
+
48
+ reportWatchCall({ context, node });
49
+ },
50
+ };
51
+ },
52
+ };
53
+
54
+ function reportWatchCall({ context, node }) {
55
+ context.report({
56
+ node,
57
+ messageId: "abusiveCall",
58
+ });
59
+ }
@@ -0,0 +1,42 @@
1
+ # effector/no-watch
2
+
3
+ Method `.watch` leads to imperative code. Try replacing it with operators (`forward`, `sample`, etc) or use the `target` parameter of the operators.
4
+
5
+ > Caution! This rule only works on projects using TypeScript.
6
+
7
+ ```ts
8
+ const myFx = createEffect();
9
+ const myEvent = createEvent();
10
+ const $awesome = createStore();
11
+
12
+ // 👍 good solutions
13
+ forward({
14
+ from: myFx.finally,
15
+ to: myEvent,
16
+ });
17
+
18
+ guard({
19
+ clock: myEvent,
20
+ filter: Boolean,
21
+ target: myFx,
22
+ });
23
+
24
+ sample({
25
+ from: $awesome.updates,
26
+ fn: identity,
27
+ to: myEvent,
28
+ });
29
+
30
+ // 👎 bad solutions
31
+ myFx.finally.watch(myEvent);
32
+
33
+ myEvent.watch((payload) => {
34
+ if (Boolean(payload)) {
35
+ myFx(payload);
36
+ }
37
+ });
38
+
39
+ $awesome.updates.watch((data) => {
40
+ myEvent(identity(data));
41
+ });
42
+ ```
@@ -4,6 +4,7 @@ const {
4
4
  const {
5
5
  traverseNestedObjectNode,
6
6
  } = require("../../utils/traverse-nested-object-node");
7
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
7
8
 
8
9
  module.exports = {
9
10
  meta: {
@@ -12,6 +13,7 @@ module.exports = {
12
13
  description: "Prefer `sample` over `forward` with `.map`/`.prepend`",
13
14
  category: "Quality",
14
15
  recommended: true,
16
+ url: createLinkToRule("prefer-sample-over-forward-with-mapping"),
15
17
  },
16
18
  messages: {
17
19
  overMap:
@@ -5,5 +5,5 @@
5
5
  "lib": ["es2017", "es2019"],
6
6
  "baseUrl": "./"
7
7
  },
8
- "include": ["./**/examples/*.ts"]
8
+ "include": ["./**/examples/**/*.ts"]
9
9
  }
@@ -0,0 +1,5 @@
1
+ function createLinkToRule(name) {
2
+ return `https://github.com/effector/eslint-plugin/blob/master/rules/${name}/${name}.md`;
3
+ }
4
+
5
+ module.exports = { createLinkToRule };
@@ -1,5 +1,7 @@
1
- function traverseParentByType(node, type) {
2
- if (!node) {
1
+ function traverseParentByType(node, type, config) {
2
+ const stopOnTypes = config?.stopOnTypes ?? [];
3
+
4
+ if (!node || stopOnTypes.includes(node.type)) {
3
5
  return null;
4
6
  }
5
7
 
@@ -7,7 +9,7 @@ function traverseParentByType(node, type) {
7
9
  return node;
8
10
  }
9
11
 
10
- return traverseParentByType(node.parent, type);
12
+ return traverseParentByType(node.parent, type, config);
11
13
  }
12
14
 
13
15
  module.exports = { traverseParentByType };
@@ -1,43 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [master]
6
- pull_request:
7
- branches: [master]
8
-
9
- jobs:
10
- checks:
11
- runs-on: ubuntu-latest
12
-
13
- strategy:
14
- matrix:
15
- node-version: [14.x, 16.x]
16
-
17
- steps:
18
- - uses: actions/checkout@v2
19
- - name: Use Node.js ${{ matrix.node-version }}
20
- uses: actions/setup-node@v2
21
- with:
22
- node-version: ${{ matrix.node-version }}
23
- cache: "yarn"
24
- - run: yarn install
25
- - run: yarn test --coverage
26
-
27
- reports:
28
- runs-on: ubuntu-latest
29
-
30
- if: ${{ github.event_name == 'pull_request' }}
31
-
32
- steps:
33
- - uses: actions/checkout@v2
34
- - name: Use Node.js
35
- uses: actions/setup-node@v2
36
- with:
37
- cache: "yarn"
38
- - run: yarn install
39
- - run: yarn test --coverage
40
- - name: Code Coverage Report
41
- uses: romeovs/lcov-reporter-action@v0.2.11
42
- with:
43
- github-token: ${{ secrets.GITHUB_TOKEN }}
package/CHANGELOG.md DELETED
@@ -1,24 +0,0 @@
1
- # Changelog
2
-
3
- ## v0.3.0
4
-
5
- - Add new rule: `no-useless-methods` ([PR #41](https://github.com/effector/eslint-plugin/pull/41))
6
- - Add new rule: `no-ambiguity-target` ([PR #42](https://github.com/effector/eslint-plugin/pull/42))
7
- - Add possibility to configure store's naming convention — suffix of prefix ([PR #37](https://github.com/effector/eslint-plugin/pull/37) by @ilyaryabchinski)
8
-
9
- ## v0.2.0
10
-
11
- - Add tests against Effector 22
12
- - Specify supported Node.JS versions
13
- - Add new rule: `prefer-sample-over-forward-with-mapping` ([PR #34](https://github.com/igorkamyshev/eslint-plugin-effector/pull/34))
14
-
15
- ## v0.1.4
16
-
17
- - Exclude test-coverage report from npm-package
18
- - Fixed SyntaxError in `no-unnecessary-duplication` suggestions ([PR #28](https://github.com/igorkamyshev/eslint-plugin-effector/pull/28))
19
-
20
- ## v0.1.3
21
-
22
- - Fixed false-positive in `no-unnecessary-duplication` with composite `clock`/`source` ([PR #22](https://github.com/igorkamyshev/eslint-plugin-effector/pull/22))
23
- - Fixed TypeError in `enforce-store-naming-convention` ([PR #25](https://github.com/igorkamyshev/eslint-plugin-effector/pull/25))
24
- - Fixed false-positive in `enforce-effect-naming-convention` with `combine` ([PR #26](https://github.com/igorkamyshev/eslint-plugin-effector/pull/26))
package/jest.config.js DELETED
@@ -1,7 +0,0 @@
1
- module.exports = {
2
- testRegex: "./.+\\.test\\.js$",
3
- collectCoverage: false,
4
- collectCoverageFrom: ["rules/**/{!(examples),}/*.js"],
5
- moduleFileExtensions: ["js"],
6
- coverageReporters: ["text-summary", "lcov"],
7
- };