@dartess/eslint-plugin 0.1.0 → 0.2.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 +10 -0
- package/README.md +35 -15
- package/dist/configs/post-format.d.ts +3 -0
- package/dist/configs/post-format.js +9 -0
- package/dist/configs/recommended.js +2 -1
- package/dist/configs/vendor-rules/imports.js +4 -9
- package/dist/index.js +2 -0
- package/dist/rules/jsx-text-as-child.d.ts +1 -1
- package/dist/rules/prevent-mixing-external-and-internal-classes.d.ts +1 -1
- package/dist/rules/strict-observable-components-declaration.d.ts +1 -1
- package/dist/rules/ts-named-tuple-elements.d.ts +13 -0
- package/dist/rules/ts-named-tuple-elements.js +47 -0
- package/docs/rules/ts-named-tuple-elements.md +36 -0
- package/package.json +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
[//]: # (https://keepachangelog.com/en/1.1.0/)
|
|
4
4
|
|
|
5
|
+
## [0.2.1] - 2026-01-10
|
|
6
|
+
|
|
7
|
+
- add `recommended-post-format` config for using after formatting tools
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-01-05
|
|
10
|
+
|
|
11
|
+
- improve `import-x/no-extraneous-dependencies` options
|
|
12
|
+
- add rule `@dartess/ts-named-tuple-elements`
|
|
13
|
+
- add `@dartess/ts-named-tuple-elements` to `recommended` config
|
|
14
|
+
|
|
5
15
|
## [0.1.0] - 2026-01-02
|
|
6
16
|
|
|
7
17
|
- add `eslint-plugin-de-morgan` to `recommended` config
|
package/README.md
CHANGED
|
@@ -30,10 +30,18 @@ All of it pinched with extra configs, setups and extra rules. Just take it and u
|
|
|
30
30
|
|
|
31
31
|
## Installation
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
Install [ESLint](https://eslint.org/), required peer deps and the plugin itself:
|
|
34
34
|
|
|
35
35
|
```sh
|
|
36
|
-
npm i -D eslint
|
|
36
|
+
npm i -D eslint \
|
|
37
|
+
eslint-plugin-import-x \
|
|
38
|
+
eslint-import-resolver-typescript \
|
|
39
|
+
eslint-plugin-unicorn \
|
|
40
|
+
eslint-plugin-decorator-position \
|
|
41
|
+
eslint-plugin-de-morgan \
|
|
42
|
+
typescript-eslint \
|
|
43
|
+
@eslint-community/eslint-plugin-eslint-comments \
|
|
44
|
+
@dartess/eslint-plugin
|
|
37
45
|
```
|
|
38
46
|
|
|
39
47
|
Next, also install the packages that suit your needs.
|
|
@@ -51,12 +59,6 @@ npm i -D eslint-plugin-mobx
|
|
|
51
59
|
npm i -D eslint-plugin-storybook
|
|
52
60
|
```
|
|
53
61
|
|
|
54
|
-
Next, install `@dartess/eslint-plugin` itself.
|
|
55
|
-
|
|
56
|
-
```sh
|
|
57
|
-
npm i -D @dartess/eslint-plugin
|
|
58
|
-
```
|
|
59
|
-
|
|
60
62
|
## Usage configs
|
|
61
63
|
|
|
62
64
|
Shared config based on `eslint-config-airbnb`, `eslint-config-airbnb-typescript`, `eslint-plugin-react/recommended`, `eslint-plugin-react/jsx-runtime`.
|
|
@@ -65,6 +67,7 @@ Edit or create `eslint.config.ts` (or `eslint.config.mts`). You probably have to
|
|
|
65
67
|
|
|
66
68
|
```ts
|
|
67
69
|
import dartessEslintPluginRecommended from '@dartess/eslint-plugin/recommended';
|
|
70
|
+
import dartessEslintPluginRecommendedPostFormat from '@dartess/eslint-plugin/recommended-post-format';
|
|
68
71
|
|
|
69
72
|
// if `react` is used
|
|
70
73
|
import dartessEslintPluginReact from '@dartess/eslint-plugin/react';
|
|
@@ -89,6 +92,7 @@ export default [
|
|
|
89
92
|
},
|
|
90
93
|
|
|
91
94
|
...dartessEslintPluginRecommended,
|
|
95
|
+
|
|
92
96
|
// if `react` is used
|
|
93
97
|
...dartessEslintPluginReact,
|
|
94
98
|
// if `next.js` is used
|
|
@@ -97,21 +101,26 @@ export default [
|
|
|
97
101
|
...dartessEslintPluginMobx,
|
|
98
102
|
// if `storybook` is used
|
|
99
103
|
...dartessEslintPluginStorybook,
|
|
104
|
+
|
|
105
|
+
// <-- Put here your formatters congifs -->
|
|
106
|
+
// @see `Fine Tuning` -> `Formatters` section below
|
|
107
|
+
|
|
108
|
+
...dartessEslintPluginRecommendedPostFormat,
|
|
100
109
|
]
|
|
101
110
|
|
|
102
111
|
```
|
|
103
112
|
|
|
104
|
-
##
|
|
113
|
+
## Fine Tuning
|
|
105
114
|
|
|
106
|
-
|
|
107
|
-
[eslint-plugin-react-refresh](https://www.npmjs.com/package/eslint-plugin-react-refresh).
|
|
108
|
-
This plugin requires manual setup for you build tools.
|
|
115
|
+
### Formatting tools
|
|
109
116
|
|
|
110
|
-
If you're
|
|
117
|
+
If you're want to (and you should to) use formatting tools, you need to additionally install and setup something else.
|
|
111
118
|
|
|
112
|
-
|
|
119
|
+
Replace the `<-- Put here your formatters congifs -->` comment with the required code, beacuse we have a special config
|
|
120
|
+
that fine-tunes formatter behavior and should be applied afterward.
|
|
113
121
|
|
|
114
|
-
|
|
122
|
+
In case you for some reason don't want to use any formatting tools, you still have to put
|
|
123
|
+
`...dartessEslintPluginRecommendedPostFormat` in any place of your config.
|
|
115
124
|
|
|
116
125
|
#### dprint
|
|
117
126
|
|
|
@@ -131,6 +140,16 @@ Use `eslint-plugin-oxlint` for disabling unnecessary rules.
|
|
|
131
140
|
* Or use `eslint-plugin-prettier` for running `prettier` as eslint rule.
|
|
132
141
|
* Or use `eslint-plugin-format` with rule `format/prettier` for running `prettier` as eslint rule (you probably will want to add `eslint-config-prettier` for disabling unnecessary rules).
|
|
133
142
|
|
|
143
|
+
### (for React users)
|
|
144
|
+
|
|
145
|
+
If you're using React, you also probably will want to add
|
|
146
|
+
[eslint-plugin-react-refresh](https://www.npmjs.com/package/eslint-plugin-react-refresh).
|
|
147
|
+
This plugin requires manual setup for you build tools.
|
|
148
|
+
|
|
149
|
+
### (for Mobx users)
|
|
150
|
+
|
|
151
|
+
If you're using Mobx with legacy decorators, you have to enable rule `mobx/missing-make-observable` manually.
|
|
152
|
+
|
|
134
153
|
## Supported Rules
|
|
135
154
|
|
|
136
155
|
Each rule has emojis denoting:
|
|
@@ -148,6 +167,7 @@ Each rule has emojis denoting:
|
|
|
148
167
|
| [stories-export-meta](docs/rules/stories-export-meta.md) | Storybook's Meta should be typed | ✅ | | |
|
|
149
168
|
| [stories-export-typed](docs/rules/stories-export-typed.md) | Storybook's Stories should be typed | ✅ | | |
|
|
150
169
|
| [max-parent-import-depth](docs/rules/max-parent-import-depth.md) | Limit relative imports to a maximum parent depth. | ✅ | | |
|
|
170
|
+
| [ts-named-tuple-elements](docs/rules/ts-named-tuple-elements.md) | Enforce (or forbid) named tuple elements | ✅ | | |
|
|
151
171
|
|
|
152
172
|
## Code Reuse Policy
|
|
153
173
|
|
|
@@ -85,7 +85,6 @@ const config = [
|
|
|
85
85
|
'unicorn/no-useless-undefined': 'error',
|
|
86
86
|
'unicorn/prefer-node-protocol': 'error',
|
|
87
87
|
'@dartess/max-parent-import-depth': 'error',
|
|
88
|
-
curly: ['error', 'all'],
|
|
89
88
|
'import-x/order': [
|
|
90
89
|
'error',
|
|
91
90
|
{
|
|
@@ -222,6 +221,8 @@ const config = [
|
|
|
222
221
|
disallowTypeAnnotations: false,
|
|
223
222
|
},
|
|
224
223
|
],
|
|
224
|
+
// require names for tuple elements
|
|
225
|
+
'@dartess/ts-named-tuple-elements': 'error',
|
|
225
226
|
},
|
|
226
227
|
},
|
|
227
228
|
{
|
|
@@ -26,25 +26,20 @@ const rules = {
|
|
|
26
26
|
'test/**', // tape, common npm pattern
|
|
27
27
|
'tests/**', // also common npm pattern
|
|
28
28
|
'spec/**', // mocha, rspec-like pattern
|
|
29
|
+
'scripts/**', // custom infra scripts
|
|
29
30
|
'**/__tests__/**', // jest pattern
|
|
30
31
|
'**/__mocks__/**', // jest pattern
|
|
31
32
|
'test.{js,jsx}', // repos with a single test file
|
|
32
33
|
'test-*.{js,jsx}', // repos with multiple top-level test files
|
|
33
34
|
'**/*{.,_}{test,spec}.{js,jsx}', // tests where the extension or filename suffix denotes that it is a test
|
|
34
|
-
'**/jest.config.js', // jest config
|
|
35
35
|
'**/jest.setup.js', // jest setup
|
|
36
|
-
'**/vue.config.js', // vue-cli config
|
|
37
|
-
'**/webpack.config.js', // webpack config
|
|
38
|
-
'**/webpack.config.*.js', // webpack config
|
|
39
|
-
'**/rollup.config.js', // rollup config
|
|
40
|
-
'**/rollup.config.*.js', // rollup config
|
|
41
36
|
'**/gulpfile.js', // gulp config
|
|
42
37
|
'**/gulpfile.*.js', // gulp config
|
|
43
38
|
'**/Gruntfile{,.js}', // grunt config
|
|
44
|
-
'**/protractor.conf.js', // protractor config
|
|
45
|
-
'**/protractor.conf.*.js', // protractor config
|
|
46
|
-
'**/karma.conf.js', // karma config
|
|
47
39
|
'**/.eslintrc.js', // eslint config
|
|
40
|
+
'**/*.conf{,ig}.js', // any configs
|
|
41
|
+
'**/*.conf{,ig}.*.js', // any configs
|
|
42
|
+
'**/*.stories.jsx', // storybook stories
|
|
48
43
|
],
|
|
49
44
|
optionalDependencies: false,
|
|
50
45
|
},
|
package/dist/index.js
CHANGED
|
@@ -6,6 +6,7 @@ import ruleStoriesExportTyped from "./rules/stories-export-typed.js";
|
|
|
6
6
|
import ruleStrictObservableComponentsDeclaration from "./rules/strict-observable-components-declaration.js";
|
|
7
7
|
import ruleRequireObserver from "./rules/require-observer.js";
|
|
8
8
|
import ruleMaxParentImportDepth from "./rules/max-parent-import-depth.js";
|
|
9
|
+
import ruleTsNamedTupleElements from "./rules/ts-named-tuple-elements.js";
|
|
9
10
|
const plugin = {
|
|
10
11
|
meta: {
|
|
11
12
|
name: packageJson.name,
|
|
@@ -20,6 +21,7 @@ const plugin = {
|
|
|
20
21
|
'strict-observable-components-declaration': ruleStrictObservableComponentsDeclaration,
|
|
21
22
|
'require-observer': ruleRequireObserver,
|
|
22
23
|
'max-parent-import-depth': ruleMaxParentImportDepth,
|
|
24
|
+
'ts-named-tuple-elements': ruleTsNamedTupleElements,
|
|
23
25
|
},
|
|
24
26
|
};
|
|
25
27
|
export default plugin;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
/**
|
|
3
|
+
* @fileoverview Enforce (or forbid) named tuple elements
|
|
4
|
+
* @author Sergey Kozlov
|
|
5
|
+
*/
|
|
6
|
+
type Options = [
|
|
7
|
+
mainOptions: {
|
|
8
|
+
mode?: 'always' | 'never';
|
|
9
|
+
}
|
|
10
|
+
];
|
|
11
|
+
type MessageIds = 'requireNames' | 'forbidNames';
|
|
12
|
+
declare const _default: ESLintUtils.RuleModule<MessageIds, Options, unknown, ESLintUtils.RuleListener>;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
export default ESLintUtils.RuleCreator(() => '')({
|
|
3
|
+
name: 'ts-named-tuple-elements',
|
|
4
|
+
defaultOptions: [{ mode: 'always' }],
|
|
5
|
+
meta: {
|
|
6
|
+
type: 'suggestion',
|
|
7
|
+
docs: {
|
|
8
|
+
description: 'Enforces consistent usage of named elements in TypeScript tuple types.',
|
|
9
|
+
},
|
|
10
|
+
messages: {
|
|
11
|
+
requireNames: 'Tuple elements must have names.',
|
|
12
|
+
forbidNames: 'Tuple elements must not have names.',
|
|
13
|
+
},
|
|
14
|
+
schema: [
|
|
15
|
+
{
|
|
16
|
+
type: 'object',
|
|
17
|
+
properties: {
|
|
18
|
+
mode: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
enum: ['always', 'never'],
|
|
21
|
+
default: 'always',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
create(context) {
|
|
28
|
+
const [options] = context.options;
|
|
29
|
+
const { mode = 'always' } = options ?? {};
|
|
30
|
+
switch (mode) {
|
|
31
|
+
case 'always':
|
|
32
|
+
return {
|
|
33
|
+
'TSTupleType > :not(TSNamedTupleMember)': node => {
|
|
34
|
+
context.report({ node, messageId: 'requireNames' });
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
case 'never':
|
|
38
|
+
return {
|
|
39
|
+
'TSTupleType > TSNamedTupleMember': node => {
|
|
40
|
+
context.report({ node, messageId: 'forbidNames' });
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
default:
|
|
44
|
+
throw new Error(`Invalig mode value: ${String(mode)}`);
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
});
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Enforce (or forbid) named tuple elements (ts-named-tuple-elements)
|
|
2
|
+
|
|
3
|
+
Enforces consistent usage of named elements in TypeScript tuple types.
|
|
4
|
+
This rule helps improve readability, self-documentation, and maintainability of tuple types
|
|
5
|
+
by explicitly naming their elements instead of relying on positional meaning.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
Examples of **incorrect** code for this rule:
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
type Location = [number, number]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Examples of **correct** code for this rule:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
type Location = [lat: number, long: number]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
`mode`: `always` (by default) or `never`
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"@dartess/ts-named-tuple-elements": [
|
|
28
|
+
"error",
|
|
29
|
+
{
|
|
30
|
+
"mode": "never"
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
When mode is "never", tuple elements should not have names.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dartess/eslint-plugin",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "A set of rules and configs for various TypeScript projects",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"eslint",
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"exports": {
|
|
17
17
|
".": "./dist/index.js",
|
|
18
18
|
"./recommended": "./dist/configs/recommended.js",
|
|
19
|
+
"./recommended-post-format": "./dist/configs/post-format.js",
|
|
19
20
|
"./react": "./dist/configs/react.js",
|
|
20
21
|
"./next": "./dist/configs/next.js",
|
|
21
22
|
"./mobx": "./dist/configs/mobx.js",
|