@dartess/eslint-plugin 0.9.0 → 0.11.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/CHANGELOG.md +16 -0
- package/README.md +7 -1
- package/dist/configs/mobx.js +1 -0
- package/dist/configs/react.js +1 -0
- package/dist/configs/recommended.js +17 -3
- package/dist/configs/vendor-rules/best-practices.d.ts +0 -1
- package/dist/configs/vendor-rules/best-practices.js +0 -3
- package/dist/index.js +4 -0
- package/dist/rules/imports-max-parent-depth.d.ts +3 -1
- package/dist/rules/jsx-no-cross-context-classes.d.ts +4 -2
- package/dist/rules/jsx-no-cross-context-classes.js +2 -5
- package/dist/rules/jsx-no-text-as-child.d.ts +7 -1
- package/dist/rules/jsx-no-text-as-child.js +1 -1
- package/dist/rules/mobx-no-action-bound.d.ts +5 -0
- package/dist/rules/mobx-no-action-bound.js +25 -0
- package/dist/rules/mobx-require-observer.d.ts +3 -1
- package/dist/rules/mobx-require-observer.js +1 -1
- package/dist/rules/mobx-strict-observable-components-declaration.d.ts +3 -1
- package/dist/rules/mobx-sync-action.d.ts +3 -1
- package/dist/rules/mobx-sync-autorun.d.ts +3 -1
- package/dist/rules/no-props-with-children-type.d.ts +9 -0
- package/dist/rules/no-props-with-children-type.js +45 -0
- package/dist/rules/stories-export-meta.d.ts +3 -1
- package/dist/rules/stories-export-typed.d.ts +3 -1
- package/dist/rules/ts-named-tuple-elements.d.ts +3 -1
- package/dist/rules/ts-named-tuple-elements.js +2 -1
- package/dist/rules/utils/exhaustiveCheck.d.ts +1 -0
- package/dist/rules/utils/exhaustiveCheck.js +11 -0
- package/docs/rules/imports-max-parent-depth.md +1 -1
- package/docs/rules/mobx-no-action-bound.md +40 -0
- package/docs/rules/no-props-with-children-type.md +29 -0
- package/package.json +21 -12
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
[//]: # (https://keepachangelog.com/en/1.1.0/)
|
|
4
4
|
|
|
5
|
+
## [0.11.0] - 2026-03-27
|
|
6
|
+
|
|
7
|
+
- remove throwing errors from rules
|
|
8
|
+
- add `unicorn/numeric-separators-style` to `recommended` config
|
|
9
|
+
- replace `import-x/order` with `perfectionist/sort-imports`: now sort side-effects as first group and styles as last group; please, install `eslint-plugin-perfectionist`
|
|
10
|
+
- add rule `@dartess/no-props-with-children-type`: Disallow the use of PropsWithChildren utility type. Prefer explicit children prop typing instead.
|
|
11
|
+
- add `@dartess/no-props-with-children-type` to `react` config
|
|
12
|
+
- update deps
|
|
13
|
+
|
|
14
|
+
## [0.10.0] - 2026-02-23
|
|
15
|
+
|
|
16
|
+
- add rule `@dartess/mobx-no-action-bound`
|
|
17
|
+
- add `@dartess/mobx-no-action-bound` to `mobx` config
|
|
18
|
+
- change `no-sequences` option `allowInParentheses` from `true` to `false`
|
|
19
|
+
- allow `mobx-require-observer` without settings because `mobx` can be used without hooks
|
|
20
|
+
|
|
5
21
|
## [0.9.0] - 2026-02-03
|
|
6
22
|
|
|
7
23
|
- add `eslint-plugin-complete` to `recommended` config
|
package/README.md
CHANGED
|
@@ -42,6 +42,7 @@ npm i -D eslint \
|
|
|
42
42
|
eslint-plugin-complete \
|
|
43
43
|
eslint-plugin-decorator-position \
|
|
44
44
|
eslint-plugin-de-morgan \
|
|
45
|
+
eslint-plugin-perfectionist \
|
|
45
46
|
typescript-eslint \
|
|
46
47
|
@eslint-community/eslint-plugin-eslint-comments \
|
|
47
48
|
@dartess/eslint-plugin
|
|
@@ -70,6 +71,7 @@ npm i -D eslint-plugin-storybook
|
|
|
70
71
|
Edit or create `eslint.config.ts` (or `eslint.config.mts`). You probably have to install `jiti` for it.
|
|
71
72
|
|
|
72
73
|
```ts
|
|
74
|
+
import type { TSESLint } from '@typescript-eslint/utils';
|
|
73
75
|
import dartessEslintPluginRecommended from '@dartess/eslint-plugin/recommended';
|
|
74
76
|
import dartessEslintPluginRecommendedPostFormat from '@dartess/eslint-plugin/recommended-post-format';
|
|
75
77
|
|
|
@@ -110,7 +112,7 @@ export default [
|
|
|
110
112
|
// @see `Fine Tuning` -> `Formatters` section below
|
|
111
113
|
|
|
112
114
|
...dartessEslintPluginRecommendedPostFormat,
|
|
113
|
-
]
|
|
115
|
+
] satisfies TSESLint.FlatConfig.ConfigArray;
|
|
114
116
|
|
|
115
117
|
```
|
|
116
118
|
|
|
@@ -154,6 +156,8 @@ This plugin requires manual setup for you build tools.
|
|
|
154
156
|
|
|
155
157
|
If you're using Mobx with legacy decorators, you have to enable rule `mobx/missing-make-observable` manually.
|
|
156
158
|
|
|
159
|
+
if you're using Mobx stores with your custom hooks, set `settings.mobx.storeHooks` [by docs](docs/rules/mobx-require-observer.md).
|
|
160
|
+
|
|
157
161
|
## Supported Rules
|
|
158
162
|
|
|
159
163
|
Each rule has emojis denoting:
|
|
@@ -171,6 +175,7 @@ Each rule has emojis denoting:
|
|
|
171
175
|
| **React** | _config: react_ | | | |
|
|
172
176
|
| [jsx-no-text-as-child](docs/rules/jsx-no-text-as-child.md) | JSX elements should not have text without translation | | | |
|
|
173
177
|
| [jsx-no-cross-context-classes](docs/rules/jsx-no-cross-context-classes.md) | Prevent mixing of outer and inner classes to avoid dependency on style order. | | | |
|
|
178
|
+
| [no-props-with-children-type](docs/rules/no-props-with-children-type.md) | Disallow the use of `PropsWithChildren` utility type in favor explicit types. | ✅ | | |
|
|
174
179
|
| **Storybook** | _config: storybook_ | | | |
|
|
175
180
|
| [stories-export-meta](docs/rules/stories-export-meta.md) | Storybook's Meta should be typed | ✅ | | |
|
|
176
181
|
| [stories-export-typed](docs/rules/stories-export-typed.md) | Storybook's Stories should be typed | ✅ | | |
|
|
@@ -179,6 +184,7 @@ Each rule has emojis denoting:
|
|
|
179
184
|
| [mobx-require-observer](docs/rules/mobx-require-observer.md) | Components using the stores must be wrapped in an `observer` | ✅ | 🔧 | |
|
|
180
185
|
| [mobx-sync-autorun](docs/rules/mobx-sync-autorun.md) | Enforce synchronous autorun callback | ✅ | | |
|
|
181
186
|
| [mobx-sync-action](docs/rules/mobx-sync-action.md) | Enforce synchronous actions | ✅ | | |
|
|
187
|
+
| [mobx-no-action-bound](docs/rules/mobx-no-action-bound.md) | Enforce using arrow functions for binging `this` to actions | ✅ | | |
|
|
182
188
|
|
|
183
189
|
## Code Reuse Policy
|
|
184
190
|
|
package/dist/configs/mobx.js
CHANGED
|
@@ -9,6 +9,7 @@ const config = [
|
|
|
9
9
|
'mobx/missing-make-observable': 'off', // useless with modern decorators syntax. TODO check original plugin?
|
|
10
10
|
'@dartess/mobx-strict-observable-components-declaration': 'error',
|
|
11
11
|
'@dartess/mobx-require-observer': 'error',
|
|
12
|
+
'@dartess/mobx-no-action-bound': 'error',
|
|
12
13
|
'@dartess/mobx-sync-autorun': 'error', // TODO implement it by types?
|
|
13
14
|
'@dartess/mobx-sync-action': 'error', // TODO implement it by types?
|
|
14
15
|
},
|
package/dist/configs/react.js
CHANGED
|
@@ -58,6 +58,7 @@ const config = [
|
|
|
58
58
|
'@eslint-react/naming-convention/component-name': 'error',
|
|
59
59
|
'@stylistic/jsx-curly-brace-presence': ['error', { props: 'never', children: 'never' }],
|
|
60
60
|
'@stylistic/jsx-self-closing-comp': 'error',
|
|
61
|
+
'@dartess/no-props-with-children-type': 'error',
|
|
61
62
|
},
|
|
62
63
|
},
|
|
63
64
|
];
|
|
@@ -11,6 +11,7 @@ import eslintCommentsPlugin from '@eslint-community/eslint-plugin-eslint-comment
|
|
|
11
11
|
import eslintPluginDecoratorPosition from 'eslint-plugin-decorator-position';
|
|
12
12
|
import eslintPluginDeMorgan from 'eslint-plugin-de-morgan';
|
|
13
13
|
import esLintPluginComplete from 'eslint-plugin-complete';
|
|
14
|
+
import esLintPluginPerfectionist from 'eslint-plugin-perfectionist';
|
|
14
15
|
import dartessPlugin from "../index.js";
|
|
15
16
|
import vendorRulesBestPractices from "./vendor-rules/best-practices.js";
|
|
16
17
|
import vendorRulesErrors from "./vendor-rules/errors.js";
|
|
@@ -54,7 +55,9 @@ const config = [
|
|
|
54
55
|
plugins: {
|
|
55
56
|
unicorn: eslintPluginUnicorn,
|
|
56
57
|
'@dartess': dartessPlugin,
|
|
58
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- https://github.com/NullVoxPopuli/eslint-plugin-decorator-position/issues/778
|
|
57
59
|
'decorator-position': eslintPluginDecoratorPosition,
|
|
60
|
+
perfectionist: esLintPluginPerfectionist,
|
|
58
61
|
},
|
|
59
62
|
languageOptions: {
|
|
60
63
|
parser: tsEslint.parser,
|
|
@@ -87,12 +90,20 @@ const config = [
|
|
|
87
90
|
],
|
|
88
91
|
'unicorn/no-useless-undefined': 'error',
|
|
89
92
|
'unicorn/prefer-node-protocol': 'error',
|
|
93
|
+
'unicorn/numeric-separators-style': 'error',
|
|
90
94
|
'@dartess/imports-max-parent-depth': 'error',
|
|
91
|
-
'
|
|
95
|
+
'perfectionist/sort-imports': [
|
|
92
96
|
'error',
|
|
93
97
|
{
|
|
94
|
-
|
|
95
|
-
|
|
98
|
+
type: 'unsorted',
|
|
99
|
+
groups: [
|
|
100
|
+
'side-effect',
|
|
101
|
+
...['builtin', 'external', 'internal', 'parent', 'sibling', 'index'].map(group => [
|
|
102
|
+
`type-${group}`,
|
|
103
|
+
`value-${group}`,
|
|
104
|
+
]),
|
|
105
|
+
'style',
|
|
106
|
+
],
|
|
96
107
|
},
|
|
97
108
|
],
|
|
98
109
|
'prefer-arrow-callback': [
|
|
@@ -110,6 +121,8 @@ const config = [
|
|
|
110
121
|
methods: 'above',
|
|
111
122
|
},
|
|
112
123
|
],
|
|
124
|
+
// totally disable comma operator
|
|
125
|
+
'no-sequences': ['error', { allowInParentheses: false }],
|
|
113
126
|
},
|
|
114
127
|
},
|
|
115
128
|
{
|
|
@@ -232,6 +245,7 @@ const config = [
|
|
|
232
245
|
'complete/strict-undefined-functions': 'off', // prefer unicorn/no-useless-undefined
|
|
233
246
|
'complete/require-break': 'off', // can be false-positive with TS7027
|
|
234
247
|
'complete/no-void-return-type': 'off', // conflict with @typescript-eslint/explicit-module-boundary-types
|
|
248
|
+
'complete/require-ascii': 'off', // absoule useless
|
|
235
249
|
},
|
|
236
250
|
},
|
|
237
251
|
{
|
|
@@ -165,9 +165,6 @@ const rules = {
|
|
|
165
165
|
// disallow comparisons where both sides are exactly the same
|
|
166
166
|
// https://eslint.org/docs/rules/no-self-compare
|
|
167
167
|
'no-self-compare': 'error',
|
|
168
|
-
// disallow use of comma operator
|
|
169
|
-
// https://eslint.org/docs/rules/no-sequences
|
|
170
|
-
'no-sequences': 'error',
|
|
171
168
|
// disallow useless string concatenation
|
|
172
169
|
// https://eslint.org/docs/rules/no-useless-concat
|
|
173
170
|
'no-useless-concat': 'error',
|
package/dist/index.js
CHANGED
|
@@ -5,10 +5,12 @@ import ruleStoriesExportMeta from "./rules/stories-export-meta.js";
|
|
|
5
5
|
import ruleStoriesExportTyped from "./rules/stories-export-typed.js";
|
|
6
6
|
import ruleMobxStrictObservableComponentsDeclaration from "./rules/mobx-strict-observable-components-declaration.js";
|
|
7
7
|
import ruleMobxRequireObserver from "./rules/mobx-require-observer.js";
|
|
8
|
+
import ruleMobxNoActionBound from "./rules/mobx-no-action-bound.js";
|
|
8
9
|
import ruleImportsMaxParentDepth from "./rules/imports-max-parent-depth.js";
|
|
9
10
|
import ruleTsNamedTupleElements from "./rules/ts-named-tuple-elements.js";
|
|
10
11
|
import ruleMobxSyncAutorun from "./rules/mobx-sync-autorun.js";
|
|
11
12
|
import ruleMobxSyncAction from "./rules/mobx-sync-action.js";
|
|
13
|
+
import ruleNoPropsWithChildrenType from "./rules/no-props-with-children-type.js";
|
|
12
14
|
const plugin = {
|
|
13
15
|
meta: {
|
|
14
16
|
name: packageJson.name,
|
|
@@ -23,9 +25,11 @@ const plugin = {
|
|
|
23
25
|
'mobx-sync-action': ruleMobxSyncAction,
|
|
24
26
|
'mobx-sync-autorun': ruleMobxSyncAutorun,
|
|
25
27
|
'mobx-require-observer': ruleMobxRequireObserver,
|
|
28
|
+
'mobx-no-action-bound': ruleMobxNoActionBound,
|
|
26
29
|
'stories-export-typed': ruleStoriesExportTyped,
|
|
27
30
|
'stories-export-meta': ruleStoriesExportMeta,
|
|
28
31
|
'ts-named-tuple-elements': ruleTsNamedTupleElements,
|
|
32
|
+
'no-props-with-children-type': ruleNoPropsWithChildrenType,
|
|
29
33
|
},
|
|
30
34
|
};
|
|
31
35
|
export default plugin;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"tooDeep", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"tooDeep", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -5,9 +5,11 @@ import { ESLintUtils } from '@typescript-eslint/utils';
|
|
|
5
5
|
*/
|
|
6
6
|
type Options = [
|
|
7
7
|
mainOptions: {
|
|
8
|
-
libName
|
|
8
|
+
libName: string;
|
|
9
9
|
}
|
|
10
10
|
];
|
|
11
11
|
type MessageIds = 'avoidMix' | 'avoidRenaming';
|
|
12
|
-
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener
|
|
12
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
13
|
+
name: string;
|
|
14
|
+
};
|
|
13
15
|
export default _default;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
2
|
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
3
|
name: 'jsx-no-cross-context-classes',
|
|
4
|
-
defaultOptions: [{}],
|
|
4
|
+
defaultOptions: [{ libName: 'clsx' }],
|
|
5
5
|
meta: {
|
|
6
6
|
type: 'suggestion',
|
|
7
7
|
docs: {
|
|
@@ -26,10 +26,7 @@ export default ESLintUtils.RuleCreator(() => '')({
|
|
|
26
26
|
},
|
|
27
27
|
create(context) {
|
|
28
28
|
const [options] = context.options;
|
|
29
|
-
const libName = options
|
|
30
|
-
if (!libName || typeof libName !== 'string') {
|
|
31
|
-
throw new Error('libName option is required and must be a string');
|
|
32
|
-
}
|
|
29
|
+
const { libName } = options;
|
|
33
30
|
const isClassLike = (string) => /class/i.exec(string);
|
|
34
31
|
return {
|
|
35
32
|
CallExpression(node) {
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Disallows text as child in JSX elements, except specified characters like emojis, digits, special symbols and extra strings
|
|
3
|
+
* @author Sergey Kozlov
|
|
4
|
+
*/
|
|
1
5
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
6
|
type Options = [
|
|
3
7
|
mainOptions: {
|
|
@@ -9,5 +13,7 @@ type Options = [
|
|
|
9
13
|
}
|
|
10
14
|
];
|
|
11
15
|
type MessageIds = 'textAsChild' | 'disallowedSymbols';
|
|
12
|
-
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener
|
|
16
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
17
|
+
name: string;
|
|
18
|
+
};
|
|
13
19
|
export default _default;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
1
|
/**
|
|
3
2
|
* @fileoverview Disallows text as child in JSX elements, except specified characters like emojis, digits, special symbols and extra strings
|
|
4
3
|
* @author Sergey Kozlov
|
|
5
4
|
*/
|
|
5
|
+
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
6
6
|
import emojiRegex from 'emoji-regex';
|
|
7
7
|
export default ESLintUtils.RuleCreator(() => '')({
|
|
8
8
|
name: 'jsx-no-text-as-child',
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
|
+
name: 'mobx-no-action-bound',
|
|
4
|
+
defaultOptions: [],
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'problem',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Enforce using arrow functions for binging `this` to actions',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
noActionBound: 'rewrite action with arrow function for binding `this`',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
return {
|
|
17
|
+
"Decorator[expression.object.name='action'][expression.property.name='bound']": function (node) {
|
|
18
|
+
context.report({
|
|
19
|
+
node,
|
|
20
|
+
messageId: 'noActionBound',
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
},
|
|
25
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"requireObserver", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"requireObserver", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -54,7 +54,7 @@ export default ESLintUtils.RuleCreator(() => '')({
|
|
|
54
54
|
const mobxSettings = context.settings.mobx;
|
|
55
55
|
const hooks = Array.isArray(mobxSettings?.storeHooks) ? mobxSettings.storeHooks : [];
|
|
56
56
|
if (hooks.length === 0) {
|
|
57
|
-
|
|
57
|
+
return {};
|
|
58
58
|
}
|
|
59
59
|
const { sourceCode } = context;
|
|
60
60
|
const program = sourceCode.ast;
|
|
@@ -10,5 +10,7 @@ type Options = [
|
|
|
10
10
|
}
|
|
11
11
|
];
|
|
12
12
|
type MessageIds = 'observedIsInlined' | 'observedIsFE' | 'extraCallsAsParam' | 'observedIsNamed' | 'componentIsNamed' | 'componentIsNamedAsObserved';
|
|
13
|
-
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener
|
|
13
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
14
|
+
name: string;
|
|
15
|
+
};
|
|
14
16
|
export default _default;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"requireSyncAction", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"requireSyncAction", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"requireSyncAutorun", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"requireSyncAutorun", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Disallow the use of `PropsWithChildren` utility type in favor explicit types
|
|
3
|
+
* @author Sergey Kozlov
|
|
4
|
+
*/
|
|
5
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
6
|
+
declare const _default: ESLintUtils.RuleModule<"unexpectedPropsWithChildren", [], unknown, ESLintUtils.RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Disallow the use of `PropsWithChildren` utility type in favor explicit types
|
|
3
|
+
* @author Sergey Kozlov
|
|
4
|
+
*/
|
|
5
|
+
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
6
|
+
import { exhaustiveCheck } from "./utils/exhaustiveCheck.js";
|
|
7
|
+
function getTypeName(tsEntityName) {
|
|
8
|
+
switch (tsEntityName.type) {
|
|
9
|
+
case AST_NODE_TYPES.Identifier:
|
|
10
|
+
return tsEntityName.name;
|
|
11
|
+
case AST_NODE_TYPES.TSQualifiedName:
|
|
12
|
+
return tsEntityName.right.name;
|
|
13
|
+
case AST_NODE_TYPES.ThisExpression:
|
|
14
|
+
return null;
|
|
15
|
+
default:
|
|
16
|
+
exhaustiveCheck(tsEntityName);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
20
|
+
name: 'no-props-with-children-type',
|
|
21
|
+
defaultOptions: [],
|
|
22
|
+
meta: {
|
|
23
|
+
type: 'problem',
|
|
24
|
+
docs: {
|
|
25
|
+
description: 'Disallow the use of PropsWithChildren utility type. Prefer explicit children prop typing instead.',
|
|
26
|
+
},
|
|
27
|
+
messages: {
|
|
28
|
+
unexpectedPropsWithChildren: 'Do not use PropsWithChildren. Type the children prop explicitly instead.',
|
|
29
|
+
},
|
|
30
|
+
schema: [],
|
|
31
|
+
},
|
|
32
|
+
create(context) {
|
|
33
|
+
return {
|
|
34
|
+
TSTypeReference(node) {
|
|
35
|
+
const name = getTypeName(node.typeName);
|
|
36
|
+
if (name === 'PropsWithChildren') {
|
|
37
|
+
context.report({
|
|
38
|
+
node,
|
|
39
|
+
messageId: 'unexpectedPropsWithChildren',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"exportDefaultTypeCheck", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"exportDefaultTypeCheck", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
declare const _default: ESLintUtils.RuleModule<"exportStoryType", [], unknown, ESLintUtils.RuleListener
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"exportStoryType", [], unknown, ESLintUtils.RuleListener> & {
|
|
3
|
+
name: string;
|
|
4
|
+
};
|
|
3
5
|
export default _default;
|
|
@@ -9,5 +9,7 @@ type Options = [
|
|
|
9
9
|
}
|
|
10
10
|
];
|
|
11
11
|
type MessageIds = 'requireNames' | 'forbidNames';
|
|
12
|
-
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener
|
|
12
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener> & {
|
|
13
|
+
name: string;
|
|
14
|
+
};
|
|
13
15
|
export default _default;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
import { exhaustiveCheck } from "./utils/exhaustiveCheck.js";
|
|
2
3
|
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
4
|
name: 'ts-named-tuple-elements',
|
|
4
5
|
defaultOptions: [{ mode: 'always' }],
|
|
@@ -41,7 +42,7 @@ export default ESLintUtils.RuleCreator(() => '')({
|
|
|
41
42
|
},
|
|
42
43
|
};
|
|
43
44
|
default:
|
|
44
|
-
|
|
45
|
+
exhaustiveCheck(mode);
|
|
45
46
|
}
|
|
46
47
|
},
|
|
47
48
|
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function exhaustiveCheck(param: never): never;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Enforce using arrow functions for binging `this` to actions (mobx-no-action-bound)
|
|
2
|
+
|
|
3
|
+
Decorator `@action.bound` automatically bind methods to class instances to avoid context loss (`this`).
|
|
4
|
+
However, this can also be achieved by declaring methods as an properies with arrow functions.
|
|
5
|
+
|
|
6
|
+
This is the first problem with bound methods—their functionality is duplicated by native abilities.
|
|
7
|
+
|
|
8
|
+
In general, for optimization purposes, it's not recommended to bind _everything_; by default,
|
|
9
|
+
class methods should be on the prototype.
|
|
10
|
+
|
|
11
|
+
To resolve the dilemma of "how to avoid binding unnecessary things and avoid losing context"
|
|
12
|
+
the [`@typescript-eslint/unbound-method`](https://typescript-eslint.io/rules/unbound-method/) rule exists.
|
|
13
|
+
|
|
14
|
+
However, it can't detect whether a method is bound via an `@action.bound`. Therefore, it's best to avoid
|
|
15
|
+
using `@action.bound` at all and leave only one binding method—arrow functions with `@typescript-eslint/unbound-method`.
|
|
16
|
+
In this case you don't need think about it.
|
|
17
|
+
|
|
18
|
+
## Rule Details
|
|
19
|
+
|
|
20
|
+
Examples of **incorrect** code for this rule:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
class Store {
|
|
24
|
+
@action.bound
|
|
25
|
+
reset() {
|
|
26
|
+
this.value = null;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Examples of **correct** code for this rule:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
class Store {
|
|
35
|
+
@action
|
|
36
|
+
reset = () => {
|
|
37
|
+
this.value = null;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Disallow `PropsWithChildren` utility type (no-props-with-children-type)
|
|
2
|
+
|
|
3
|
+
Disallow the use of `PropsWithChildren` utility type from `@types/react`.
|
|
4
|
+
Prefer explicit `children` prop typing instead, as `PropsWithChildren` makes `children` optional by default,
|
|
5
|
+
which may hide bugs. Additionally, `children` is often narrower than `ReactNode` and should be typed explicitly.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
type ModalProps = PropsWithChildren<{ title: string }>;
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Examples of **correct** code for this rule:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
type ModalProps = {
|
|
19
|
+
title: string;
|
|
20
|
+
children: React.ReactNode;
|
|
21
|
+
};
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
type ModalProps = {
|
|
26
|
+
title: string;
|
|
27
|
+
children: string | number;
|
|
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.
|
|
4
|
+
"version": "0.11.2",
|
|
5
5
|
"description": "A set of rules and configs for various TypeScript projects",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"eslint",
|
|
@@ -59,6 +59,7 @@
|
|
|
59
59
|
"eslint-plugin-import-x": "^4.1.0",
|
|
60
60
|
"eslint-plugin-jsx-a11y": "^6.10.0",
|
|
61
61
|
"eslint-plugin-mobx": "~0.0.13",
|
|
62
|
+
"eslint-plugin-perfectionist": "^5.6.0",
|
|
62
63
|
"eslint-plugin-react-hooks": "^7.0.0",
|
|
63
64
|
"eslint-plugin-storybook": "^10.0.0",
|
|
64
65
|
"eslint-plugin-unicorn": ">=58.0.0",
|
|
@@ -88,32 +89,40 @@
|
|
|
88
89
|
}
|
|
89
90
|
},
|
|
90
91
|
"devDependencies": {
|
|
91
|
-
"@eslint-community/eslint-plugin-eslint-comments": "^4.
|
|
92
|
+
"@eslint-community/eslint-plugin-eslint-comments": "^4.7.1",
|
|
93
|
+
"@eslint-react/eslint-plugin": "^2.13.0",
|
|
92
94
|
"@eslint/js": "^9.39.2",
|
|
95
|
+
"@next/eslint-plugin-next": "^16.1.6",
|
|
96
|
+
"@stylistic/eslint-plugin": "^5.10.0",
|
|
93
97
|
"@types/confusing-browser-globals": "^1.0.3",
|
|
94
98
|
"@types/eslint-plugin-jsx-a11y": "^6.10.1",
|
|
95
99
|
"@types/eslint-plugin-mobx": "~0.0.0",
|
|
96
100
|
"@types/node": "^25.0.2",
|
|
97
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
98
|
-
"eslint": "^9.39.
|
|
101
|
+
"@typescript-eslint/rule-tester": "^8.56.1",
|
|
102
|
+
"eslint": "^9.39.4",
|
|
99
103
|
"eslint-config-prettier": "^10.1.8",
|
|
100
104
|
"eslint-import-resolver-typescript": "^4.4.4",
|
|
101
|
-
"eslint-plugin-
|
|
105
|
+
"eslint-plugin-complete": "^1.3.0",
|
|
106
|
+
"eslint-plugin-de-morgan": "^2.1.1",
|
|
107
|
+
"eslint-plugin-decorator-position": "^6.0.0",
|
|
108
|
+
"eslint-plugin-eslint-plugin": "^7.3.2",
|
|
102
109
|
"eslint-plugin-import-x": "^4.16.1",
|
|
103
|
-
"eslint-plugin-
|
|
110
|
+
"eslint-plugin-perfectionist": "^5.6.0",
|
|
111
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
104
112
|
"eslint-plugin-react-hooks": "^7.0.1",
|
|
105
|
-
"eslint-plugin-
|
|
113
|
+
"eslint-plugin-storybook": "^10.2.16",
|
|
114
|
+
"eslint-plugin-unicorn": "^63.0.0",
|
|
106
115
|
"husky": "^9.1.7",
|
|
107
116
|
"jiti": "^2.6.1",
|
|
108
|
-
"rimraf": "^6.1.
|
|
117
|
+
"rimraf": "^6.1.3",
|
|
109
118
|
"typescript": "~5.9.3",
|
|
110
|
-
"typescript-eslint": "^8.
|
|
119
|
+
"typescript-eslint": "^8.56.1"
|
|
111
120
|
},
|
|
112
121
|
"dependencies": {
|
|
113
|
-
"@eslint/compat": "^2.0.
|
|
114
|
-
"@typescript-eslint/utils": "^8.
|
|
122
|
+
"@eslint/compat": "^2.0.3",
|
|
123
|
+
"@typescript-eslint/utils": "^8.56.1",
|
|
115
124
|
"confusing-browser-globals": "^1.0.11",
|
|
116
125
|
"emoji-regex": "^10.6.0",
|
|
117
|
-
"globals": "^
|
|
126
|
+
"globals": "^17.4.0"
|
|
118
127
|
}
|
|
119
128
|
}
|