@dartess/eslint-plugin 0.0.1
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 +7 -0
- package/README.md +134 -0
- package/dist/configs/mobx.d.ts +3 -0
- package/dist/configs/mobx.js +13 -0
- package/dist/configs/next.d.ts +3 -0
- package/dist/configs/next.js +17 -0
- package/dist/configs/react.d.ts +3 -0
- package/dist/configs/react.js +78 -0
- package/dist/configs/recommended.d.ts +3 -0
- package/dist/configs/recommended.js +211 -0
- package/dist/configs/storybook.d.ts +3 -0
- package/dist/configs/storybook.js +20 -0
- package/dist/configs/vendor-rules/best-practices.d.ts +120 -0
- package/dist/configs/vendor-rules/best-practices.js +248 -0
- package/dist/configs/vendor-rules/errors.d.ts +40 -0
- package/dist/configs/vendor-rules/errors.js +92 -0
- package/dist/configs/vendor-rules/es6.d.ts +47 -0
- package/dist/configs/vendor-rules/es6.js +108 -0
- package/dist/configs/vendor-rules/imports.d.ts +41 -0
- package/dist/configs/vendor-rules/imports.js +119 -0
- package/dist/configs/vendor-rules/next-config.d.ts +16 -0
- package/dist/configs/vendor-rules/next-config.js +22 -0
- package/dist/configs/vendor-rules/react-hooks.d.ts +10 -0
- package/dist/configs/vendor-rules/react-hooks.js +17 -0
- package/dist/configs/vendor-rules/react.d.ts +228 -0
- package/dist/configs/vendor-rules/react.js +513 -0
- package/dist/configs/vendor-rules/strict.d.ts +4 -0
- package/dist/configs/vendor-rules/strict.js +9 -0
- package/dist/configs/vendor-rules/style.d.ts +34 -0
- package/dist/configs/vendor-rules/style.js +78 -0
- package/dist/configs/vendor-rules/typescript-disablings.d.ts +5 -0
- package/dist/configs/vendor-rules/typescript-disablings.js +13 -0
- package/dist/configs/vendor-rules/typescript.d.ts +40 -0
- package/dist/configs/vendor-rules/typescript.js +69 -0
- package/dist/configs/vendor-rules/variables.d.ts +28 -0
- package/dist/configs/vendor-rules/variables.js +39 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +25 -0
- package/dist/rules/jsx-text-as-child.d.ts +13 -0
- package/dist/rules/jsx-text-as-child.js +90 -0
- package/dist/rules/max-parent-import-depth.d.ts +3 -0
- package/dist/rules/max-parent-import-depth.js +50 -0
- package/dist/rules/prevent-mixing-external-and-internal-classes.d.ts +13 -0
- package/dist/rules/prevent-mixing-external-and-internal-classes.js +72 -0
- package/dist/rules/require-observer.d.ts +3 -0
- package/dist/rules/require-observer.js +138 -0
- package/dist/rules/stories-export-meta.d.ts +3 -0
- package/dist/rules/stories-export-meta.js +37 -0
- package/dist/rules/stories-export-typed.d.ts +3 -0
- package/dist/rules/stories-export-typed.js +51 -0
- package/dist/rules/strict-observable-components-declaration.d.ts +14 -0
- package/dist/rules/strict-observable-components-declaration.js +118 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.js +1 -0
- package/dist/utils/parse-git-ignore.d.ts +2 -0
- package/dist/utils/parse-git-ignore.js +7 -0
- package/docs/rules/jsx-text-as-child.md +101 -0
- package/docs/rules/max-parent-import-depth.md +31 -0
- package/docs/rules/prevent-mixing-external-and-internal-classes.md +42 -0
- package/docs/rules/require-observer.md +43 -0
- package/docs/rules/stories-export-meta.md +37 -0
- package/docs/rules/stories-export-typed.md +42 -0
- package/docs/rules/strict-observable-components-declaration.md +57 -0
- package/package.json +91 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
|
+
name: 'stories-export-meta',
|
|
4
|
+
defaultOptions: [],
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'The default export should include type checking using `satisfy Meta`',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
exportDefaultTypeCheck: '`export default` should be `satisfies Meta<typeof T>`',
|
|
12
|
+
},
|
|
13
|
+
schema: [],
|
|
14
|
+
},
|
|
15
|
+
create(context) {
|
|
16
|
+
return {
|
|
17
|
+
ExportDefaultDeclaration(node) {
|
|
18
|
+
const { declaration } = node;
|
|
19
|
+
const hasSatisfies = declaration.type === AST_NODE_TYPES.TSSatisfiesExpression;
|
|
20
|
+
const isMeta = hasSatisfies &&
|
|
21
|
+
declaration.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&
|
|
22
|
+
declaration.typeAnnotation.typeName.type === AST_NODE_TYPES.Identifier &&
|
|
23
|
+
declaration.typeAnnotation.typeName.name === 'Meta';
|
|
24
|
+
const isMetaWithParameter = isMeta &&
|
|
25
|
+
declaration.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&
|
|
26
|
+
declaration.typeAnnotation.typeArguments &&
|
|
27
|
+
declaration.typeAnnotation.typeArguments.params.length > 0;
|
|
28
|
+
if (!hasSatisfies || !isMeta || !isMetaWithParameter) {
|
|
29
|
+
context.report({
|
|
30
|
+
node: declaration,
|
|
31
|
+
messageId: 'exportDefaultTypeCheck',
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Stories exports should include type checking using `Story` or `StoryObj`
|
|
4
|
+
* @author Sergey Kozlov
|
|
5
|
+
*/
|
|
6
|
+
const validStoryNames = ['Story', 'StoryObj'];
|
|
7
|
+
const validStoryNamesString = validStoryNames.map(name => `\`${name}\``).join(' or ');
|
|
8
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
9
|
+
name: 'stories-export-typed',
|
|
10
|
+
defaultOptions: [],
|
|
11
|
+
meta: {
|
|
12
|
+
type: 'suggestion',
|
|
13
|
+
docs: {
|
|
14
|
+
description: `Stories exports should include type checking using ${validStoryNamesString}`,
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
exportStoryType: `stories \`export\` should be typed as ${validStoryNamesString}`,
|
|
18
|
+
},
|
|
19
|
+
schema: [],
|
|
20
|
+
},
|
|
21
|
+
create(context) {
|
|
22
|
+
return {
|
|
23
|
+
ExportNamedDeclaration: node => {
|
|
24
|
+
if (!node.declaration || !('declarations' in node.declaration)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const nodeStoryId = node.declaration.declarations[0].id;
|
|
28
|
+
const { typeAnnotation } = nodeStoryId;
|
|
29
|
+
if (nodeStoryId) {
|
|
30
|
+
if (typeAnnotation?.typeAnnotation.type === AST_NODE_TYPES.TSTypeReference &&
|
|
31
|
+
typeAnnotation?.typeAnnotation?.typeName.type === AST_NODE_TYPES.Identifier &&
|
|
32
|
+
validStoryNames.includes(typeAnnotation?.typeAnnotation?.typeName?.name)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (typeAnnotation) {
|
|
36
|
+
context.report({
|
|
37
|
+
node: typeAnnotation,
|
|
38
|
+
messageId: 'exportStoryType',
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
context.report({
|
|
43
|
+
node: nodeStoryId,
|
|
44
|
+
messageId: 'exportStoryType',
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
},
|
|
51
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview The observable component must be an inline function.
|
|
4
|
+
* @author Sergey Kozlov
|
|
5
|
+
*/
|
|
6
|
+
type Options = [
|
|
7
|
+
{
|
|
8
|
+
ignoreObserverArg?: Array<string>;
|
|
9
|
+
allowedHocs?: Array<string>;
|
|
10
|
+
}
|
|
11
|
+
];
|
|
12
|
+
type MessageIds = 'observedIsInlined' | 'observedIsFE' | 'extraCallsAsParam' | 'observedIsNamed' | 'componentIsNamed' | 'componentIsNamedAsObserved';
|
|
13
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|
|
14
|
+
export default _default;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
|
|
2
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
|
+
name: 'strict-observable-components-declaration',
|
|
4
|
+
defaultOptions: [{}],
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Disallow missed and wrong named `observer` components.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
observedIsInlined: 'The component must be an inline function.',
|
|
12
|
+
observedIsFE: 'The component must be a function expression.',
|
|
13
|
+
extraCallsAsParam: `Passing the result of a function call '{{ callName }}' is not allowed by 'ignoreObserverArg' option.`,
|
|
14
|
+
observedIsNamed: 'The component must be a named function expression.',
|
|
15
|
+
componentIsNamed: 'The return value from the observer must be assigned to a variable.',
|
|
16
|
+
componentIsNamedAsObserved: 'The name of the observable component and the name of the variable must match.',
|
|
17
|
+
},
|
|
18
|
+
schema: [
|
|
19
|
+
{
|
|
20
|
+
type: 'object',
|
|
21
|
+
properties: {
|
|
22
|
+
ignoreObserverArg: {
|
|
23
|
+
type: 'array',
|
|
24
|
+
items: {
|
|
25
|
+
type: 'string',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
allowedHocs: {
|
|
29
|
+
type: 'array',
|
|
30
|
+
items: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
create(context) {
|
|
39
|
+
const getParent = (node, allowedHocs) => {
|
|
40
|
+
let { parent } = node;
|
|
41
|
+
if (!allowedHocs) {
|
|
42
|
+
return parent;
|
|
43
|
+
}
|
|
44
|
+
while (parent.type === AST_NODE_TYPES.CallExpression &&
|
|
45
|
+
'name' in parent.callee &&
|
|
46
|
+
allowedHocs.includes(parent.callee.name)) {
|
|
47
|
+
parent = parent.parent;
|
|
48
|
+
}
|
|
49
|
+
return parent;
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
CallExpression(node) {
|
|
53
|
+
if (!('name' in node.callee) || node.callee.name !== 'observer') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const [arg] = node.arguments;
|
|
57
|
+
const [options] = context.options;
|
|
58
|
+
const wrongArgType = () => {
|
|
59
|
+
context.report({
|
|
60
|
+
node: arg,
|
|
61
|
+
messageId: 'observedIsFE',
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
switch (arg.type) {
|
|
65
|
+
case AST_NODE_TYPES.Identifier: {
|
|
66
|
+
context.report({
|
|
67
|
+
node: arg,
|
|
68
|
+
messageId: 'observedIsInlined',
|
|
69
|
+
});
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case AST_NODE_TYPES.CallExpression: {
|
|
73
|
+
if (options?.ignoreObserverArg) {
|
|
74
|
+
if ('name' in arg.callee && !options.ignoreObserverArg.includes(arg.callee.name)) {
|
|
75
|
+
context.report({
|
|
76
|
+
node: arg,
|
|
77
|
+
messageId: 'extraCallsAsParam',
|
|
78
|
+
data: { callName: arg.callee.name },
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
wrongArgType();
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
case AST_NODE_TYPES.FunctionExpression: {
|
|
88
|
+
if (arg.id === null) {
|
|
89
|
+
context.report({
|
|
90
|
+
node: arg,
|
|
91
|
+
messageId: 'observedIsNamed',
|
|
92
|
+
});
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const parent = getParent(node, options?.allowedHocs);
|
|
96
|
+
if (parent && parent.type !== AST_NODE_TYPES.VariableDeclarator) {
|
|
97
|
+
context.report({
|
|
98
|
+
node,
|
|
99
|
+
messageId: 'componentIsNamed',
|
|
100
|
+
});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (parent && 'name' in parent.id && arg.id?.name !== parent.id.name) {
|
|
104
|
+
context.report({
|
|
105
|
+
node: parent,
|
|
106
|
+
messageId: 'componentIsNamedAsObserved',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
default: {
|
|
112
|
+
wrongArgType();
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
},
|
|
118
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseGitIgnore } from './parse-git-ignore.ts';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { parseGitIgnore } from "./parse-git-ignore.js";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { includeIgnoreFile } from '@eslint/compat';
|
|
3
|
+
export function parseGitIgnore() {
|
|
4
|
+
const config = includeIgnoreFile(path.resolve('.gitignore'));
|
|
5
|
+
config.ignores = config.ignores?.filter(ignore => !ignore.startsWith('!'));
|
|
6
|
+
return config;
|
|
7
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# JSX elements should not have text without translation (jsx-no-text-as-child)
|
|
2
|
+
|
|
3
|
+
This rule disallows text as child in JSX elements, except specified characters like emojis,
|
|
4
|
+
digits, special symbols and extra strings. This helps to ensure that JSX elements are only
|
|
5
|
+
used for their intended purpose of representing translated texts.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
<MyComponent>This is some text</MyComponent>
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Examples of **correct** code for this rule:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
<MyComponent>{t(translation.someText)}</MyComponent>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
`allowExtraStrings`: an array of strings that are allowed as text children in JSX elements.
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"@dartess/jsx-no-text-as-child": [
|
|
28
|
+
"error",
|
|
29
|
+
{
|
|
30
|
+
"allowExtraStrings": [
|
|
31
|
+
"USDT"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
`allowEmoji`: a boolean flag that allows emojis as text children in JSX elements.
|
|
39
|
+
|
|
40
|
+
```json
|
|
41
|
+
{
|
|
42
|
+
"@dartess/jsx-no-text-as-child": [
|
|
43
|
+
"error",
|
|
44
|
+
{
|
|
45
|
+
"allowEmoji": true
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`allowDigits`: a boolean flag that allows digits as text children in JSX elements.
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"@dartess/jsx-no-text-as-child": [
|
|
56
|
+
"error",
|
|
57
|
+
{
|
|
58
|
+
"allowDigits": true
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`allowSpecialSymbols`: a boolean flag that allows special symbols as text children in JSX elements.
|
|
65
|
+
|
|
66
|
+
List of allowed symbols:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
`-=[];\',./~!@#$%^&*()_+{}|:"<>?№–≈—
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"@dartess/jsx-no-text-as-child": [
|
|
75
|
+
"error",
|
|
76
|
+
{
|
|
77
|
+
"allowSpecialSymbols": true
|
|
78
|
+
}
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
`disallowedSymbols`: allows you to prohibit some previously allowed characters
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
```json
|
|
87
|
+
{
|
|
88
|
+
"@dartess/jsx-no-text-as-child": [
|
|
89
|
+
"error",
|
|
90
|
+
{
|
|
91
|
+
"allowSpecialSymbols": true,
|
|
92
|
+
"disallowedSymbols": ["~"]
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## When Not To Use It
|
|
99
|
+
|
|
100
|
+
This rule is followed except for those files where translations are optional
|
|
101
|
+
(service components, documentation components, etc.)
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Disallow relative imports going up more than a specified number of parent directories (max-parent-import-depth)
|
|
2
|
+
|
|
3
|
+
This rule limits the number of parent directory (../) levels allowed in import and export statements to enforce a flatter and more maintainable project structure.
|
|
4
|
+
|
|
5
|
+
Unlike `import-x/no-relative-parent-imports`, the syntax is checked, not the actual position of the import, so imports from higher directories are allowed if you use aliases.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
import a from '../../../way-too-high';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Examples of **correct** code for this rule:
|
|
16
|
+
|
|
17
|
+
```js
|
|
18
|
+
import a from '../../two-up';
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
This rule does not accept inline options, but requires a global ESLint setting:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"settings": {
|
|
28
|
+
"maxParentImportLevels": 3 // default 2
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Prevent mixing of outer and inner classes to avoid dependency on style order (prevent-mixing-external-and-internal-classes)
|
|
2
|
+
|
|
3
|
+
Avoid mixing outer and inner classes on the same element. The import order of the style is not guaranteed,
|
|
4
|
+
so the order in which the style is applied is also not guaranteed.
|
|
5
|
+
|
|
6
|
+
## Rule Details
|
|
7
|
+
|
|
8
|
+
Examples of **incorrect** code for this rule:
|
|
9
|
+
|
|
10
|
+
```js
|
|
11
|
+
cn(styles.root, className)
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
cn(styles.root, someItemClassName)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
cn(styles.root, props.className)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
cn(styles.root, props.obj.className)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
```js
|
|
27
|
+
cn(styles.root, props.someItemClassName)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Examples of **correct** code for this rule:
|
|
31
|
+
|
|
32
|
+
```js
|
|
33
|
+
cn(className)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
cn(styles.root, styles.classItem)
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Options
|
|
41
|
+
|
|
42
|
+
`libName` _(required)_: your classname-like package name, like `classnames` or `clsx`
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Require wrap components in observer if needed (require-observer)
|
|
2
|
+
|
|
3
|
+
This rule requires that React components using specified store hooks are wrapped in `observer()` from `mobx-react-lite`.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
Examples of **incorrect** code for this rule:
|
|
8
|
+
|
|
9
|
+
```js
|
|
10
|
+
function MyComponent() {
|
|
11
|
+
const store = useStore();
|
|
12
|
+
return <div>{store.value}</div>;
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Examples of **correct** code for this rule:
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
const MyComponent = observer(function MyComponent() {
|
|
20
|
+
const store = useStore();
|
|
21
|
+
return <div>{store.value}</div>;
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Options
|
|
26
|
+
|
|
27
|
+
This rule does not accept inline options, but requires a global ESLint setting:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{
|
|
31
|
+
"settings": {
|
|
32
|
+
"mobx": {
|
|
33
|
+
"storeHooks": ["useStore"]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- `storeHooks`: an array of hook names that require components to be wrapped in `observer()`.
|
|
40
|
+
|
|
41
|
+
## When Not To Use It
|
|
42
|
+
|
|
43
|
+
This rule should be disabled in projects that do not use MobX or do not require `observer()` wrapping for components.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Makes meta-information typing mandatory
|
|
2
|
+
|
|
3
|
+
Storybook stories should contain meta information. Thanks to this rule, meta-information will always be typed.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
Examples of **incorrect** code for this rule:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export default {
|
|
11
|
+
component: Tabs,
|
|
12
|
+
title: 'Redesign/Tabs',
|
|
13
|
+
}
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
export default {
|
|
18
|
+
component: Tabs,
|
|
19
|
+
title: 'Redesign/Tabs',
|
|
20
|
+
} as Meta;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
export default {
|
|
25
|
+
component: Tabs,
|
|
26
|
+
title: 'Redesign/Tabs',
|
|
27
|
+
} satisfies Meta;
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Examples of **correct** code for this rule:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
export default {
|
|
34
|
+
component: Tabs,
|
|
35
|
+
title: 'Redesign/Tabs',
|
|
36
|
+
} satisfies Meta<typeof Tabs>;
|
|
37
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Makes stories typing mandatory
|
|
2
|
+
|
|
3
|
+
Forces typing of exported stories.
|
|
4
|
+
|
|
5
|
+
## Rule Details
|
|
6
|
+
|
|
7
|
+
Examples of **incorrect** code for this rule:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
export const SimpleTabs = {
|
|
11
|
+
args: {
|
|
12
|
+
tabs: simpleTabs,
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Examples of **correct** code for this rule:
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
export const SimpleTabs: StoryObj<typeof Tabs> = {
|
|
21
|
+
args: {
|
|
22
|
+
tabs: simpleTabs,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
type Story = StoryObj<typeof Tabs>;
|
|
29
|
+
|
|
30
|
+
export const SimpleTabs: Story = {
|
|
31
|
+
args: {
|
|
32
|
+
tabs: simpleTabs,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const TabsWithDropdown: Story = {
|
|
37
|
+
args: {
|
|
38
|
+
tabs: orderTabs,
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Wrapping components in `observer` must comply with the regulations (strict-observable-components-declaration)
|
|
2
|
+
|
|
3
|
+
For more convenient work and debugging, several factors must be agreed upon:
|
|
4
|
+
the component that is passed to the observer must have the same name as
|
|
5
|
+
the variable to which it is assigned. This provides two main benefits:
|
|
6
|
+
|
|
7
|
+
1. Quick jump to a component in the IDE.
|
|
8
|
+
2. Displaying the correct component name in devtools.
|
|
9
|
+
|
|
10
|
+
## Rule Details
|
|
11
|
+
|
|
12
|
+
Examples of **incorrect** code for this rule:
|
|
13
|
+
|
|
14
|
+
```js
|
|
15
|
+
const Component = observer(function() {})
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
const Component = observer(() => null)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
```js
|
|
23
|
+
const fn = () => {};
|
|
24
|
+
const Component = observer(fn)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
console.log(observer(function Component() {}));
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
```js
|
|
32
|
+
const ComponentFoo = observer(function ComponentBar() {})
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Examples of **correct** code for this rule:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const Component = observer(function Component() {})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Options
|
|
42
|
+
|
|
43
|
+
`ignoreObserverArg`: an array of function names whose call result is valid as an argument for the observer.
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"@dartess/strict-observable-components-declaration": ["error", {"ignoreObserverArg": ["forwardRef"]}]
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
`allowedHocs`: an array of function names that are valid for use as HOC.
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"@dartess/strict-observable-components-declaration": ["error", {"allowedHocs": ["someHocName"]}]
|
|
56
|
+
}
|
|
57
|
+
```
|