@dartess/eslint-plugin 0.3.0 → 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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  [//]: # (https://keepachangelog.com/en/1.1.0/)
4
4
 
5
+ ## [0.5.0] - 2026-01-16
6
+ - add rule `@dartess/mobx-sync-action`
7
+ - add `@dartess/mobx-sync-action` to `mobx` config
8
+
9
+ ## [0.4.0] - 2026-01-15
10
+ - add rule `@dartess/mobx-sync-autorun`
11
+ - add `@dartess/mobx-sync-autorun` to `mobx` config
12
+
5
13
  ## [0.3.0] - 2026-01-12
6
14
 
7
15
  - add `eslint-plugin-react-hooks:recommended` config to `react` config
package/README.md CHANGED
@@ -60,8 +60,6 @@ npm i -D eslint-plugin-storybook
60
60
 
61
61
  ## Usage configs
62
62
 
63
- Shared config based on `eslint-config-airbnb`, `eslint-config-airbnb-typescript`, `eslint-plugin-react/recommended`, `eslint-plugin-react/jsx-runtime`.
64
-
65
63
  Edit or create `eslint.config.ts` (or `eslint.config.mts`). You probably have to install `jiti` for it.
66
64
 
67
65
  ```ts
@@ -159,14 +157,21 @@ Each rule has emojis denoting:
159
157
 
160
158
  | Name | Description | ✅ | 🔧 | 💡 |
161
159
  |:-----------------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------|:--|:---|:---|
162
- | [strict-observable-components-declaration](docs/rules/strict-observable-components-declaration.md) | Wrapping components in `observer` must comply with the regulations. || | |
163
- | [require-observer](docs/rules/require-observer.md) | Components using the stores must be wrapped in an `observer` | ✅ | 🔧 | |
164
- | [prevent-mixing-external-and-internal-classes](docs/rules/prevent-mixing-external-and-internal-classes.md) | Prevent mixing of outer and inner classes to avoid dependency on style order. | | | |
160
+ | **imports** | _config: recommended_ | | | |
161
+ | [max-parent-import-depth](docs/rules/max-parent-import-depth.md) | Limit relative imports to a maximum parent depth. | ✅ | | |
162
+ | **TypeScript** | _config: recommended_ | | | |
163
+ | [ts-named-tuple-elements](docs/rules/ts-named-tuple-elements.md) | Enforce (or forbid) named tuple elements | ✅ | | |
164
+ | **React** | _config: react_ | | | |
165
165
  | [jsx-no-text-as-child](docs/rules/jsx-text-as-child.md) | JSX elements should not have text without translation | | | |
166
+ | [prevent-mixing-external-and-internal-classes](docs/rules/prevent-mixing-external-and-internal-classes.md) | Prevent mixing of outer and inner classes to avoid dependency on style order. | | | |
167
+ | **Storybook** | _config: storybook_ | | | |
166
168
  | [stories-export-meta](docs/rules/stories-export-meta.md) | Storybook's Meta should be typed | ✅ | | |
167
169
  | [stories-export-typed](docs/rules/stories-export-typed.md) | Storybook's Stories should be typed | ✅ | | |
168
- | [max-parent-import-depth](docs/rules/max-parent-import-depth.md) | Limit relative imports to a maximum parent depth. || | |
169
- | [ts-named-tuple-elements](docs/rules/ts-named-tuple-elements.md) | Enforce (or forbid) named tuple elements | ✅ | | |
170
+ | **MobX** | _config: mobx_ | | | |
171
+ | [strict-observable-components-declaration](docs/rules/strict-observable-components-declaration.md) | Wrapping components in `observer` must comply with the regulations. | ✅ | | |
172
+ | [require-observer](docs/rules/require-observer.md) | Components using the stores must be wrapped in an `observer` | ✅ | 🔧 | |
173
+ | [mobx-sync-autorun](docs/rules/mobx-sync-autorun.md) | Enforce synchronous autorun callback | ✅ | | |
174
+ | [mobx-sync-action](docs/rules/mobx-sync-action.md) | Enforce synchronous actions | | | |
170
175
 
171
176
  ## Code Reuse Policy
172
177
 
@@ -5,9 +5,11 @@ const config = [
5
5
  name: '@dartess/mobx',
6
6
  rules: {
7
7
  'mobx/missing-observer': 'off', // replaced by the neater "@dartess/require-observer"
8
- 'mobx/missing-make-observable': 'off', // useless with modern decorators syntax
8
+ 'mobx/missing-make-observable': 'off', // useless with modern decorators syntax. TODO check original plugin?
9
9
  '@dartess/strict-observable-components-declaration': 'error',
10
10
  '@dartess/require-observer': 'error',
11
+ '@dartess/mobx-sync-autorun': 'error', // TODO implement it by types?
12
+ '@dartess/mobx-sync-action': 'error', // TODO implement it by types?
11
13
  },
12
14
  },
13
15
  ];
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ import ruleStrictObservableComponentsDeclaration from "./rules/strict-observable
7
7
  import ruleRequireObserver from "./rules/require-observer.js";
8
8
  import ruleMaxParentImportDepth from "./rules/max-parent-import-depth.js";
9
9
  import ruleTsNamedTupleElements from "./rules/ts-named-tuple-elements.js";
10
+ import ruleMobxSyncAutorun from "./rules/mobx-sync-autorun.js";
11
+ import ruleMobxSyncAction from "./rules/mobx-sync-action.js";
10
12
  const plugin = {
11
13
  meta: {
12
14
  name: packageJson.name,
@@ -22,6 +24,8 @@ const plugin = {
22
24
  'require-observer': ruleRequireObserver,
23
25
  'max-parent-import-depth': ruleMaxParentImportDepth,
24
26
  'ts-named-tuple-elements': ruleTsNamedTupleElements,
27
+ 'mobx-sync-autorun': ruleMobxSyncAutorun,
28
+ 'mobx-sync-action': ruleMobxSyncAction,
25
29
  },
26
30
  };
27
31
  export default plugin;
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ declare const _default: ESLintUtils.RuleModule<"requireSyncAction", [], unknown, ESLintUtils.RuleListener>;
3
+ export default _default;
@@ -0,0 +1,28 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export default ESLintUtils.RuleCreator(() => '')({
3
+ name: 'mobx-sync-action',
4
+ defaultOptions: [],
5
+ meta: {
6
+ type: 'problem',
7
+ docs: {
8
+ description: 'Mobx methods marked as `@action` must must be synchronous.',
9
+ },
10
+ messages: {
11
+ requireSyncAction: '`action` must be synchronous function',
12
+ },
13
+ schema: [],
14
+ },
15
+ create(context) {
16
+ const selector = [
17
+ 'MethodDefinition[value.async="true"] Decorator[expression.object.name="action"]',
18
+ 'MethodDefinition[value.async="true"] Decorator[expression.name="action"]',
19
+ 'PropertyDefinition[value.type="ArrowFunctionExpression"][value.async="true"] Decorator[expression.object.name="action"]',
20
+ 'PropertyDefinition[value.type="ArrowFunctionExpression"][value.async="true"] Decorator[expression.name="action"]',
21
+ ].join(', ');
22
+ return {
23
+ [selector]: node => {
24
+ context.report({ node, messageId: 'requireSyncAction' });
25
+ },
26
+ };
27
+ },
28
+ });
@@ -0,0 +1,3 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ declare const _default: ESLintUtils.RuleModule<"requireSyncAutorun", [], unknown, ESLintUtils.RuleListener>;
3
+ export default _default;
@@ -0,0 +1,26 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export default ESLintUtils.RuleCreator(() => '')({
3
+ name: 'mobx-sync-autorun',
4
+ defaultOptions: [],
5
+ meta: {
6
+ type: 'problem',
7
+ docs: {
8
+ description: "Autorun tracks only the observables that are read during the synchronous execution of the provided function, but it won't track anything that happens asynchronously.",
9
+ },
10
+ messages: {
11
+ requireSyncAutorun: '`effect` must be synchronous function',
12
+ },
13
+ schema: [],
14
+ },
15
+ create(context) {
16
+ const selector = [
17
+ 'CallExpression[callee.name="autorun"] > ArrowFunctionExpression[async="true"]',
18
+ 'CallExpression[callee.name="autorun"] > FunctionExpression[async="true"]',
19
+ ].join(', ');
20
+ return {
21
+ [selector]: node => {
22
+ context.report({ node, messageId: 'requireSyncAutorun' });
23
+ },
24
+ };
25
+ },
26
+ });
@@ -0,0 +1,27 @@
1
+ # Enforce synchronous actions
2
+
3
+ Mobx methods marked as `@action` must be synchronous: https://mobx.js.org/actions.html#asynchronous-actions
4
+
5
+ ## Rule Details
6
+
7
+ Examples of **incorrect** code for this rule:
8
+
9
+ ```ts
10
+ class Store {
11
+ @action async method1() {};
12
+ @action.bound async method2() {};
13
+ @action method3 = async () => {};
14
+ @action.bound method4 = async () => {};
15
+ }
16
+ ```
17
+
18
+ Examples of **correct** code for this rule:
19
+
20
+ ```ts
21
+ class Store {
22
+ @action method1() {};
23
+ @action.bound method2() {};
24
+ @action method3 = () => {};
25
+ @action.bound method4 = () => {};
26
+ }
27
+ ```
@@ -0,0 +1,29 @@
1
+ # Enforce synchronous autorun callback
2
+
3
+ Mobx `autorun` function must accept only synchronous `effect` callback.
4
+ This follows from the rules from official documentation, https://mobx.js.org/reactions.html#rules #2:
5
+
6
+ ```
7
+ Autorun tracks only the observables that are read during the synchronous execution of the provided function, but it won't track anything that happens asynchronously.
8
+ ```
9
+
10
+ It would be nice to track this at the type level, but that doesn't happen at the moment.
11
+
12
+ ## Rule Details
13
+
14
+ Examples of **incorrect** code for this rule:
15
+
16
+ ```ts
17
+ autorun(async () => {
18
+ await sleep(1);
19
+ console.log(store.value)
20
+ })
21
+ ```
22
+
23
+ Examples of **correct** code for this rule:
24
+
25
+ ```ts
26
+ autorun(() => {
27
+ console.log(store.value)
28
+ })
29
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dartess/eslint-plugin",
3
3
  "type": "module",
4
- "version": "0.3.0",
4
+ "version": "0.5.0",
5
5
  "description": "A set of rules and configs for various TypeScript projects",
6
6
  "keywords": [
7
7
  "eslint",
@@ -83,7 +83,7 @@
83
83
  }
84
84
  },
85
85
  "devDependencies": {
86
- "@eslint-community/eslint-plugin-eslint-comments": "^4.5.0",
86
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.6.0",
87
87
  "@eslint/js": "^9.39.2",
88
88
  "@types/confusing-browser-globals": "^1.0.3",
89
89
  "@types/eslint-plugin-jsx-a11y": "^6.10.1",