eslint-plugin-effector 0.3.1 → 0.5.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.
Files changed (39) hide show
  1. package/README.md +40 -9
  2. package/config/react.js +5 -0
  3. package/config/recommended.js +3 -0
  4. package/config/scope.js +5 -0
  5. package/index.js +8 -1
  6. package/package.json +13 -15
  7. package/rules/enforce-effect-naming-convention/enforce-effect-naming-convention.js +19 -17
  8. package/rules/enforce-gate-naming-convention/enforce-gate-naming-convention.js +114 -0
  9. package/rules/enforce-gate-naming-convention/enforce-gate-naming-convention.md +11 -0
  10. package/rules/enforce-store-naming-convention/enforce-store-naming-convention.js +46 -40
  11. package/rules/enforce-store-naming-convention/enforce-store-naming-convention.md +12 -4
  12. package/rules/no-ambiguity-target/no-ambiguity-target.js +8 -4
  13. package/rules/no-duplicate-on/no-duplicate-on.js +128 -0
  14. package/rules/no-duplicate-on/no-duplicate-on.md +16 -0
  15. package/rules/no-getState/no-getState.js +11 -36
  16. package/rules/no-unnecessary-combination/no-unnecessary-combination.js +96 -0
  17. package/rules/no-unnecessary-combination/no-unnecessary-combination.md +25 -0
  18. package/rules/no-unnecessary-duplication/no-unnecessary-duplication.js +9 -5
  19. package/rules/no-useless-methods/no-useless-methods.js +18 -4
  20. package/rules/no-watch/no-watch.js +53 -0
  21. package/rules/no-watch/no-watch.md +42 -0
  22. package/rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.js +8 -4
  23. package/rules/strict-effect-handlers/strict-effect-handlers.js +74 -0
  24. package/rules/strict-effect-handlers/strict-effect-handlers.md +38 -0
  25. package/rules/tsconfig.json +2 -1
  26. package/utils/create-link-to-rule.js +5 -0
  27. package/utils/extract-imported-from.js +9 -0
  28. package/utils/get-corrected-store-name.js +12 -14
  29. package/utils/get-nested-object-name.js +18 -0
  30. package/utils/get-store-name-convention.js +3 -3
  31. package/utils/is.js +30 -0
  32. package/utils/naming.js +47 -0
  33. package/utils/node-type-is.js +55 -0
  34. package/utils/validate-store-name-convention.js +7 -7
  35. package/.github/workflows/ci.yml +0 -43
  36. package/CHANGELOG.md +0 -28
  37. package/jest.config.js +0 -7
  38. package/utils/extract-imported-from-effector.js +0 -8
  39. package/utils/is-store-name-valid.js +0 -22
package/README.md CHANGED
@@ -25,7 +25,7 @@ Add `effector` to the plugins section of your `.eslintrc` configuration file. Yo
25
25
  ```json
26
26
  {
27
27
  "plugins": ["effector"],
28
- "extends": ["plugin:effector/recommended"]
28
+ "extends": ["plugin:effector/recommended", "plugin:effector/scope"]
29
29
  }
30
30
  ```
31
31
 
@@ -39,12 +39,43 @@ To configure individual rules:
39
39
  }
40
40
  ```
41
41
 
42
- ## Supported Rules
42
+ ### Available presets
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
+ #### plugin:effector/recommended
45
+
46
+ This preset is recommended for most projects.
47
+
48
+ #### plugin:effector/scope
49
+
50
+ This preset is recommended for projects that use [Fork API](https://effector.dev/docs/api/effector/scope). You can read more about Fork API in [an article](https://dev.to/effector/the-best-part-of-effector-4c27).
51
+
52
+ #### plugin:effector/react
53
+
54
+ This preset is recommended for projects that use [React](https://reactjs.org) with Effector.
55
+
56
+ ### Supported rules
57
+
58
+ - [effector/enforce-store-naming-convention](rules/enforce-store-naming-convention/enforce-store-naming-convention.md)
59
+ - [effector/enforce-effect-naming-convention](rules/enforce-effect-naming-convention/enforce-effect-naming-convention.md)
60
+ - [effector/no-getState](rules/no-getState/no-getState.md)
61
+ - [effector/no-unnecessary-duplication](rules/no-unnecessary-duplication/no-unnecessary-duplication.md)
62
+ - [effector/no-useless-methods](rules/no-useless-methods/no-useless-methods.md)
63
+ - [effector/no-ambiguity-target](rules/no-ambiguity-target/no-ambiguity-target.md)
64
+ - [effector/prefer-sample-over-forward-with-mapping](rules/prefer-sample-over-forward-with-mapping/prefer-sample-over-forward-with-mapping.md)
65
+ - [effector/no-watch](rules/no-watch/no-watch.md)
66
+ - [effector/no-unnecessary-combination](rules/no-unnecessary-combination/no-unnecessary-combination.md)
67
+ - [effector/no-duplicate-on](rules/no-duplicate-on/no-duplicate-on.md)
68
+ - [effector/strict-effect-handlers](rules/strict-effect-handlers/strict-effect-handlers.md)
69
+ - [effector/enforce-gate-naming-convention](rules/enforce-gate-naming-convention/enforce-gate-naming-convention.md)
70
+
71
+ ## Maintenance
72
+
73
+ ### Release flow
74
+
75
+ 1. Bump `version` in [package.json](package.json)
76
+ 2. Fill [CHANGELOG.md](CHANGELOG.md)
77
+ 3. Commit changes by `git commit -m "Release X.X.X"`
78
+ 4. Create git tag for release by `git tag -a vX.X.X -m "vX.X.X"`
79
+ 5. Push changes to remote by `git push --follow-tags`
80
+ 6. Release package to registry by `yarn clean-publish`
81
+ 7. Fill release page with changelog on GitHub
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ rules: {
3
+ "effector/enforce-gate-naming-convention": "error",
4
+ },
5
+ };
@@ -7,5 +7,8 @@ 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",
12
+ "effector/no-duplicate-on": "error",
10
13
  },
11
14
  };
@@ -0,0 +1,5 @@
1
+ module.exports = {
2
+ rules: {
3
+ "effector/strict-effect-handlers": "error",
4
+ },
5
+ };
package/index.js CHANGED
@@ -7,8 +7,15 @@ 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"),
12
+ "no-duplicate-on": require("./rules/no-duplicate-on/no-duplicate-on"),
13
+ "strict-effect-handlers": require("./rules/strict-effect-handlers/strict-effect-handlers"),
14
+ "enforce-gate-naming-convention": require("./rules/enforce-gate-naming-convention/enforce-gate-naming-convention"),
10
15
  },
11
16
  configs: {
12
17
  recommended: require("./config/recommended"),
13
- }
18
+ scope: require("./config/scope"),
19
+ react: require("./config/react"),
20
+ },
14
21
  };
package/package.json CHANGED
@@ -1,33 +1,31 @@
1
1
  {
2
2
  "name": "eslint-plugin-effector",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
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"
27
+ },
28
+ "nano-staged": {
29
+ "*.{js,ts,md}": "prettier --write"
32
30
  }
33
- }
31
+ }
@@ -1,6 +1,7 @@
1
- const {
2
- extractImportedFromEffector,
3
- } = require("../../utils/extract-imported-from-effector");
1
+ const { extractImportedFrom } = require("../../utils/extract-imported-from");
2
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
3
+ const { nodeTypeIs } = require("../../utils/node-type-is");
4
+ const { namingOf } = require("../../utils/naming");
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;
@@ -24,13 +27,10 @@ module.exports = {
24
27
  if (parserServices.hasFullTypeInformation) {
25
28
  return {
26
29
  VariableDeclarator(node) {
27
- const checker = parserServices.program.getTypeChecker();
28
- const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
29
- const type = checker.getTypeAtLocation(originalNode.initializer);
30
-
31
- const isEffectorEffect =
32
- type?.symbol?.escapedName === "Effect" &&
33
- type?.symbol?.parent?.escapedName?.includes("effector");
30
+ const isEffectorEffect = nodeTypeIs.effect({
31
+ node,
32
+ context,
33
+ });
34
34
 
35
35
  if (!isEffectorEffect) {
36
36
  return;
@@ -38,11 +38,9 @@ module.exports = {
38
38
 
39
39
  const effectName = node.id.name;
40
40
 
41
- if (effectName?.endsWith("Fx")) {
42
- return;
41
+ if (namingOf.effect.isInvalid({ name: effectName })) {
42
+ reportEffectNameConventionViolation({ context, node, effectName });
43
43
  }
44
-
45
- reportEffectNameConventionViolation({ context, node, effectName });
46
44
  },
47
45
  };
48
46
  }
@@ -51,7 +49,11 @@ module.exports = {
51
49
  const importedFromEffector = new Map();
52
50
  return {
53
51
  ImportDeclaration(node) {
54
- extractImportedFromEffector(importedFromEffector, node);
52
+ extractImportedFrom({
53
+ importMap: importedFromEffector,
54
+ node,
55
+ packageName: "effector",
56
+ });
55
57
  },
56
58
  CallExpression(node) {
57
59
  // Effect creation with method
@@ -74,7 +76,7 @@ module.exports = {
74
76
  }
75
77
 
76
78
  const effectName = node.parent.id.name;
77
- if (effectName.endsWith("Fx")) {
79
+ if (namingOf.effect.isValid({ name: effectName })) {
78
80
  continue;
79
81
  }
80
82
 
@@ -98,7 +100,7 @@ module.exports = {
98
100
  }
99
101
 
100
102
  const effectName = node.parent.id.name;
101
- if (effectName.endsWith("Fx")) {
103
+ if (namingOf.effect.isValid({ name: effectName })) {
102
104
  return;
103
105
  }
104
106
 
@@ -0,0 +1,114 @@
1
+ const { extractImportedFrom } = require("../../utils/extract-imported-from");
2
+ const { nodeTypeIs } = require("../../utils/node-type-is");
3
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
4
+ const { namingOf } = require("../../utils/naming");
5
+
6
+ module.exports = {
7
+ meta: {
8
+ type: "problem",
9
+ docs: {
10
+ description: "Enforce first capital letter for gate naming",
11
+ category: "Naming",
12
+ recommended: true,
13
+ url: createLinkToRule("enforce-gate-naming-convention"),
14
+ },
15
+ messages: {
16
+ invalidName:
17
+ 'Gate "{{ gateName }}" should be named with first capital letter, rename it to "{{ correctedGateName }}"',
18
+ renameGate: 'Rename "{{ gateName }}" to "{{ correctedGateName }}"',
19
+ },
20
+ schema: [],
21
+ hasSuggestions: true,
22
+ },
23
+ create(context) {
24
+ const parserServices = context.parserServices;
25
+ // TypeScript-way
26
+ if (parserServices.hasFullTypeInformation) {
27
+ return {
28
+ VariableDeclarator(node) {
29
+ const isEffectorGate = nodeTypeIs.gate({
30
+ node,
31
+ context,
32
+ });
33
+
34
+ if (!isEffectorGate) {
35
+ return;
36
+ }
37
+
38
+ const gateName = node.id.name;
39
+
40
+ if (namingOf.gate.isInvalid({ name: gateName })) {
41
+ reportGateNameConventionViolation({ context, node, gateName });
42
+ }
43
+ },
44
+ };
45
+ }
46
+
47
+ // JavaScript-way
48
+ const importedFromEffectorReact = new Map();
49
+ return {
50
+ ImportDeclaration(node) {
51
+ extractImportedFrom({
52
+ importMap: importedFromEffectorReact,
53
+ node,
54
+ packageName: "effector-react",
55
+ });
56
+ },
57
+ CallExpression(node) {
58
+ // Effect creation with method
59
+ const GATE_CREATION_METHODS = ["createGate"];
60
+ for (const method of GATE_CREATION_METHODS) {
61
+ const localMethod = importedFromEffectorReact.get(method);
62
+ if (!localMethod) {
63
+ continue;
64
+ }
65
+
66
+ const isEffectorGateCreation = node.callee.name === localMethod;
67
+ if (!isEffectorGateCreation) {
68
+ continue;
69
+ }
70
+
71
+ const resultSavedInVariable =
72
+ node.parent.type === "VariableDeclarator";
73
+ if (!resultSavedInVariable) {
74
+ continue;
75
+ }
76
+
77
+ const gateName = node.parent.id.name;
78
+ if (namingOf.gate.isValid({ name: gateName })) {
79
+ continue;
80
+ }
81
+
82
+ reportGateNameConventionViolation({
83
+ context,
84
+ node: node.parent,
85
+ gateName,
86
+ });
87
+ }
88
+ },
89
+ };
90
+ },
91
+ };
92
+
93
+ function reportGateNameConventionViolation({ context, node, gateName }) {
94
+ const [firstChar, ...restChars] = gateName.split("");
95
+ const correctedGateName = [firstChar.toUpperCase(), ...restChars].join("");
96
+
97
+ context.report({
98
+ node,
99
+ messageId: "invalidName",
100
+ data: {
101
+ gateName,
102
+ correctedGateName,
103
+ },
104
+ suggest: [
105
+ {
106
+ messageId: "renameGate",
107
+ data: { gateName, correctedGateName },
108
+ fix(fixer) {
109
+ return fixer.replaceTextRange(node.id.range, correctedGateName);
110
+ },
111
+ },
112
+ ],
113
+ });
114
+ }
@@ -0,0 +1,11 @@
1
+ # effector/enforce-gate-naming-convention
2
+
3
+ Enforcing naming conventions helps keep the codebase consistent, and reduces overhead when thinking about how to name a variable with gate. Every gate is a react-component, so it should be named as regular react-compoent.
4
+
5
+ ```ts
6
+ // 👍 nice name
7
+ const MyFavoritePageGate = createGate();
8
+
9
+ // 👎 bad name
10
+ const otherFavoritePageGate = createGate();
11
+ ```
@@ -1,26 +1,34 @@
1
+ const { extractImportedFrom } = require("../../utils/extract-imported-from");
2
+ const { namingOf } = require("../../utils/naming");
1
3
  const {
2
- extractImportedFromEffector,
3
- } = require("../../utils/extract-imported-from-effector");
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");
4
+ validateStoreNameConvention,
5
+ } = require("../../utils/validate-store-name-convention");
6
+ const {
7
+ getStoreNameConvention,
8
+ } = require("../../utils/get-store-name-convention");
9
+ const {
10
+ getCorrectedStoreName,
11
+ } = require("../../utils/get-corrected-store-name");
12
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
13
+ const { nodeTypeIs } = require("../../utils/node-type-is");
8
14
 
9
15
  module.exports = {
10
16
  meta: {
11
17
  type: "problem",
12
18
  docs: {
13
19
  description:
14
- "Enforce $ as a prefix or postfix for any store created by Effector methods",
20
+ "Enforce $ as a prefix or postfix for any store created by Effector methods",
15
21
  category: "Naming",
16
22
  recommended: true,
23
+ url: createLinkToRule("enforce-store-naming-convention"),
17
24
  },
18
25
  messages: {
19
26
  invalidName:
20
- 'Store "{{ storeName }}" should be named with {{ storeNameConvention }}, rename it to "{{ correctedStoreName }}"',
27
+ 'Store "{{ storeName }}" should be named with {{ storeNameConvention }}, rename it to "{{ correctedStoreName }}"',
21
28
  renameStore: 'Rename "{{ storeName }}" to "{{ correctedStoreName }}"',
22
29
  },
23
30
  schema: [],
31
+ hasSuggestions: true,
24
32
  },
25
33
  create(context) {
26
34
  const { parserServices } = context;
@@ -31,13 +39,10 @@ module.exports = {
31
39
  if (parserServices.hasFullTypeInformation) {
32
40
  return {
33
41
  VariableDeclarator(node) {
34
- const checker = parserServices.program.getTypeChecker();
35
- const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
36
- const type = checker.getTypeAtLocation(originalNode.initializer);
37
-
38
- const isEffectorStore =
39
- type?.symbol?.escapedName === "Store" &&
40
- type?.symbol?.parent?.escapedName?.includes("effector");
42
+ const isEffectorStore = nodeTypeIs.store({
43
+ node,
44
+ context,
45
+ });
41
46
 
42
47
  if (!isEffectorStore) {
43
48
  return;
@@ -45,15 +50,13 @@ module.exports = {
45
50
 
46
51
  const storeName = node.id.name;
47
52
 
48
- if (isStoreNameValid(storeName, context)) {
49
- return;
53
+ if (namingOf.store.isInvalid({ name: storeName, context })) {
54
+ reportStoreNameConventionViolation({
55
+ context,
56
+ node,
57
+ storeName,
58
+ });
50
59
  }
51
-
52
- reportStoreNameConventionViolation({
53
- context,
54
- node,
55
- storeName
56
- });
57
60
  },
58
61
  };
59
62
  }
@@ -62,7 +65,11 @@ module.exports = {
62
65
  const importedFromEffector = new Map();
63
66
  return {
64
67
  ImportDeclaration(node) {
65
- extractImportedFromEffector(importedFromEffector, node);
68
+ extractImportedFrom({
69
+ importMap: importedFromEffector,
70
+ node,
71
+ packageName: "effector",
72
+ });
66
73
  },
67
74
  CallExpression(node) {
68
75
  // Store creation with method
@@ -79,21 +86,21 @@ module.exports = {
79
86
  }
80
87
 
81
88
  const resultSavedInVariable =
82
- node.parent.type === "VariableDeclarator";
89
+ node.parent.type === "VariableDeclarator";
83
90
  if (!resultSavedInVariable) {
84
91
  continue;
85
92
  }
86
93
 
87
94
  const storeName = node.parent.id.name;
88
95
 
89
- if (isStoreNameValid(storeName, context)) {
96
+ if (namingOf.store.isValid({ name: storeName, context })) {
90
97
  continue;
91
98
  }
92
99
 
93
100
  reportStoreNameConventionViolation({
94
101
  context,
95
102
  node: node.parent,
96
- storeName
103
+ storeName,
97
104
  });
98
105
  return;
99
106
  }
@@ -102,27 +109,28 @@ module.exports = {
102
109
  if (node.callee?.property?.name === "map") {
103
110
  const storeNameCreatedFromMap = node.callee?.object?.name;
104
111
 
105
- if (!isStoreNameValid(storeNameCreatedFromMap, context)) {
112
+ if (
113
+ namingOf.store.isInvalid({ name: storeNameCreatedFromMap, context })
114
+ ) {
106
115
  return;
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
  }
114
123
 
115
124
  const storeName = node.parent.id.name;
116
125
 
117
- if (isStoreNameValid(storeName, context)) {
126
+ if (namingOf.store.isValid({ name: storeName, context })) {
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,24 +138,24 @@ 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
  }
140
148
 
141
149
  const storeName = node.parent.id.name;
142
150
 
143
- if (isStoreNameValid(storeName, context)) {
151
+ if (namingOf.store.isValid({ name: storeName, context })) {
144
152
  return;
145
153
  }
146
154
 
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,12 +174,12 @@ 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
  {
174
181
  messageId: "renameStore",
175
- data: { storeName },
182
+ data: { storeName, correctedStoreName },
176
183
  fix(fixer) {
177
184
  return fixer.replaceTextRange(node.id.range, correctedStoreName);
178
185
  },
@@ -180,4 +187,3 @@ function reportStoreNameConventionViolation({ context, node, storeName }) {
180
187
  ],
181
188
  });
182
189
  }
183
-
@@ -3,7 +3,9 @@
3
3
  Enforcing naming conventions helps keep the codebase consistent, and reduces overhead when thinking about how to name a variable with store. Depending on the configuration your stores should be distinguished by a prefix or a postfix $. Enforces prefix convention by default.
4
4
 
5
5
  ## Prefix convention
6
+
6
7
  When configured as:
8
+
7
9
  ```js
8
10
  module.exports = {
9
11
  rules: {
@@ -11,17 +13,21 @@ module.exports = {
11
13
  },
12
14
  };
13
15
  ```
16
+
14
17
  Prefix convention will be enforced:
18
+
15
19
  ```ts
16
20
  // 👍 nice name
17
21
  const $name = createStore(null);
18
22
 
19
23
  // 👎 bad name
20
- const name = createStrore(null);
24
+ const name = createStore(null);
21
25
  ```
26
+
22
27
  ## Postfix convention
23
28
 
24
29
  When configured as:
30
+
25
31
  ```js
26
32
  module.exports = {
27
33
  rules: {
@@ -29,12 +35,14 @@ module.exports = {
29
35
  },
30
36
  settings: {
31
37
  effector: {
32
- storeNameConvention: "postfix"
33
- }
34
- }
38
+ storeNameConvention: "postfix",
39
+ },
40
+ },
35
41
  };
36
42
  ```
43
+
37
44
  Postfix convention will be enforced:
45
+
38
46
  ```ts
39
47
  // 👍 nice name
40
48
  const name$ = createStore(null);
@@ -1,7 +1,6 @@
1
- const {
2
- extractImportedFromEffector,
3
- } = require("../../utils/extract-imported-from-effector");
1
+ const { extractImportedFrom } = require("../../utils/extract-imported-from");
4
2
  const { traverseParentByType } = require("../../utils/traverse-parent-by-type");
3
+ const { createLinkToRule } = require("../../utils/create-link-to-rule");
5
4
 
6
5
  module.exports = {
7
6
  meta: {
@@ -10,6 +9,7 @@ module.exports = {
10
9
  description: "Forbids ambiguity targets in `sample` and `guard`",
11
10
  category: "Quality",
12
11
  recommended: true,
12
+ url: createLinkToRule("no-ambiguity-target"),
13
13
  },
14
14
  messages: {
15
15
  ambiguityTarget:
@@ -22,7 +22,11 @@ module.exports = {
22
22
 
23
23
  return {
24
24
  ImportDeclaration(node) {
25
- extractImportedFromEffector(importedFromEffector, node);
25
+ extractImportedFrom({
26
+ importMap: importedFromEffector,
27
+ node,
28
+ packageName: "effector",
29
+ });
26
30
  },
27
31
  CallExpression(node) {
28
32
  const POSSIBLE_USELESS_METHODS = ["sample", "guard"];