@dartess/eslint-plugin 0.8.0 → 0.9.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,15 @@
2
2
 
3
3
  [//]: # (https://keepachangelog.com/en/1.1.0/)
4
4
 
5
+ ## [0.9.0] - 2026-02-03
6
+
7
+ - add `eslint-plugin-complete` to `recommended` config
8
+
9
+ ## [0.8.1] - 2026-01-24
10
+
11
+ - fix `mobx-require-observer`: now it doesn't lose generics
12
+ - fix `mobx-require-observer`: now it respects directives like `'use client'`
13
+
5
14
  ## [0.8.0] - 2026-01-22
6
15
 
7
16
  - All recommended warnings are converted to errors because warnings are useless.
package/README.md CHANGED
@@ -8,6 +8,7 @@ Also extends
8
8
  * `eslint-plugin-import-x` — `recommended` & `typescript`
9
9
  * `@eslint-community/eslint-plugin-eslint-comments` — `recommended`
10
10
  * `eslint-plugin-de-morgan` — `recommended`
11
+ * `eslint-plugin-complete` — `recommended`
11
12
 
12
13
  Also can extends (if it is applicable)
13
14
  * `@eslint-react/eslint-plugin` — `strict-type-checked`
@@ -23,7 +24,7 @@ All of it pinched with extra configs, setups and extra rules. Just take it and u
23
24
 
24
25
  ### Notes
25
26
 
26
- 1. The package is intended for use with TypeScript (it'll be useful for plain JS, but it hasn't been weel-tested).
27
+ 1. The package is intended for use with TypeScript (it'll be useful for plain JS, but it hasn't been well-tested).
27
28
 
28
29
  2. The package is intended for use only with the `flat` eslint config.
29
30
 
@@ -38,6 +39,7 @@ npm i -D eslint \
38
39
  eslint-plugin-import-x \
39
40
  eslint-import-resolver-typescript \
40
41
  eslint-plugin-unicorn \
42
+ eslint-plugin-complete \
41
43
  eslint-plugin-decorator-position \
42
44
  eslint-plugin-de-morgan \
43
45
  typescript-eslint \
@@ -10,6 +10,7 @@ import eslintCommentsPlugin from '@eslint-community/eslint-plugin-eslint-comment
10
10
  // @ts-ignore: https://github.com/NullVoxPopuli/eslint-plugin-decorator-position/issues/778
11
11
  import eslintPluginDecoratorPosition from 'eslint-plugin-decorator-position';
12
12
  import eslintPluginDeMorgan from 'eslint-plugin-de-morgan';
13
+ import esLintPluginComplete from 'eslint-plugin-complete';
13
14
  import dartessPlugin from "../index.js";
14
15
  import vendorRulesBestPractices from "./vendor-rules/best-practices.js";
15
16
  import vendorRulesErrors from "./vendor-rules/errors.js";
@@ -47,6 +48,7 @@ const config = [
47
48
  convertWarnsToErrorsIfNeeded(eslintPluginImportX.flatConfigs.typescript),
48
49
  convertWarnsToErrorsIfNeeded(eslintCommentsPlugin.recommended),
49
50
  convertWarnsToErrorsIfNeeded(eslintPluginDeMorgan.configs.recommended),
51
+ ...convertWarnsToErrorsIfNeeded(esLintPluginComplete.configs.recommended),
50
52
  {
51
53
  name: '@dartess/recommended',
52
54
  plugins: {
@@ -224,6 +226,12 @@ const config = [
224
226
  ],
225
227
  // require names for tuple elements
226
228
  '@dartess/ts-named-tuple-elements': 'error',
229
+ // disable some recommended rules
230
+ 'complete/prefer-readonly-parameter-types': 'off', // can be flase-positive for Built-in methods
231
+ 'complete/no-mutable-return': 'off', // can be hamful
232
+ 'complete/strict-undefined-functions': 'off', // prefer unicorn/no-useless-undefined
233
+ 'complete/require-break': 'off', // can be false-positive with TS7027
234
+ 'complete/no-void-return-type': 'off', // conflict with @typescript-eslint/explicit-module-boundary-types
227
235
  },
228
236
  },
229
237
  {
@@ -8,9 +8,6 @@ declare const rules: {
8
8
  }];
9
9
  'default-case-last': "error";
10
10
  'default-param-last': "error";
11
- eqeqeq: ["error", string, {
12
- null: string;
13
- }];
14
11
  'grouped-accessor-pairs': "error";
15
12
  'guard-for-in': "error";
16
13
  'max-classes-per-file': ["error", number];
@@ -88,7 +85,6 @@ declare const rules: {
88
85
  'no-self-compare': "error";
89
86
  'no-sequences': "error";
90
87
  'no-useless-concat': "error";
91
- 'no-useless-return': "error";
92
88
  'no-void': "error";
93
89
  'prefer-promise-reject-errors': ["error", {
94
90
  allowEmptyReject: boolean;
@@ -17,9 +17,6 @@ const rules = {
17
17
  'default-case-last': 'error',
18
18
  // https://eslint.org/docs/rules/default-param-last
19
19
  'default-param-last': 'error',
20
- // require the use of === and !==
21
- // https://eslint.org/docs/rules/eqeqeq
22
- eqeqeq: ['error', 'always', { null: 'ignore' }],
23
20
  // Require grouped accessor pairs in object literals and classes
24
21
  // https://eslint.org/docs/rules/grouped-accessor-pairs
25
22
  'grouped-accessor-pairs': 'error',
@@ -174,9 +171,6 @@ const rules = {
174
171
  // disallow useless string concatenation
175
172
  // https://eslint.org/docs/rules/no-useless-concat
176
173
  'no-useless-concat': 'error',
177
- // disallow redundant return; keywords
178
- // https://eslint.org/docs/rules/no-useless-return
179
- 'no-useless-return': 'error',
180
174
  // disallow use of void operator
181
175
  // https://eslint.org/docs/rules/no-void
182
176
  'no-void': 'error',
@@ -3,7 +3,6 @@ declare const rules: {
3
3
  'no-cond-assign': ["error", string];
4
4
  'no-inner-declarations': "error";
5
5
  'no-promise-executor-return': "error";
6
- 'no-template-curly-in-string': "error";
7
6
  'no-unreachable-loop': ["error", {
8
7
  ignore: never[];
9
8
  }];
@@ -13,9 +13,6 @@ const rules = {
13
13
  // Disallow returning values from Promise executor functions
14
14
  // https://eslint.org/docs/rules/no-promise-executor-return
15
15
  'no-promise-executor-return': 'error',
16
- // Disallow template literal placeholder syntax in regular strings
17
- // https://eslint.org/docs/rules/no-template-curly-in-string
18
- 'no-template-curly-in-string': 'error',
19
16
  // Disallow loops with a body that allows only one iteration
20
17
  // https://eslint.org/docs/rules/no-unreachable-loop
21
18
  'no-unreachable-loop': [
@@ -12,10 +12,6 @@ declare const rules: {
12
12
  ignoreConstructors: boolean;
13
13
  avoidQuotes: boolean;
14
14
  }];
15
- 'prefer-const': ["error", {
16
- destructuring: string;
17
- ignoreReadBeforeAssign: boolean;
18
- }];
19
15
  'prefer-destructuring': ["error", {
20
16
  VariableDeclarator: {
21
17
  array: boolean;
@@ -37,14 +37,6 @@ const rules = {
37
37
  avoidQuotes: true,
38
38
  },
39
39
  ],
40
- // suggest using of const declaration for variables that are never modified after declared
41
- 'prefer-const': [
42
- 'error',
43
- {
44
- destructuring: 'any',
45
- ignoreReadBeforeAssign: true,
46
- },
47
- ],
48
40
  // Prefer destructuring from arrays and objects
49
41
  // https://eslint.org/docs/rules/prefer-destructuring
50
42
  'prefer-destructuring': [
@@ -14,7 +14,6 @@ declare const rules: {
14
14
  'no-lonely-if': "error";
15
15
  'no-multi-assign': ["error"];
16
16
  'no-nested-ternary': "error";
17
- 'no-plusplus': "error";
18
17
  'no-underscore-dangle': ["error", {
19
18
  allow: never[];
20
19
  allowAfterThis: boolean;
@@ -39,9 +39,6 @@ const rules = {
39
39
  'no-multi-assign': ['error'],
40
40
  // disallow nested ternary expressions
41
41
  'no-nested-ternary': 'error',
42
- // disallow use of unary operators, ++ and --
43
- // https://eslint.org/docs/rules/no-plusplus
44
- 'no-plusplus': 'error',
45
42
  // disallow dangling underscores in identifiers
46
43
  // https://eslint.org/docs/rules/no-underscore-dangle
47
44
  'no-underscore-dangle': [
@@ -1,4 +1,4 @@
1
- import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
1
+ import { ESLintUtils, AST_NODE_TYPES, } from '@typescript-eslint/utils';
2
2
  function isCustomHook(fn) {
3
3
  if (fn.type === AST_NODE_TYPES.FunctionDeclaration && fn.id?.name.startsWith('use')) {
4
4
  return true;
@@ -13,6 +13,29 @@ function isCustomHook(fn) {
13
13
  }
14
14
  return false;
15
15
  }
16
+ function getTypeParamsText(fn, sourceCode) {
17
+ return fn.typeParameters ? sourceCode.getText(fn.typeParameters) : '';
18
+ }
19
+ function getObserverImportAnchor(program) {
20
+ const firstImport = program.body.find(n => n.type === AST_NODE_TYPES.ImportDeclaration);
21
+ if (firstImport) {
22
+ return { anchor: firstImport, method: 'insertTextBefore' };
23
+ }
24
+ let lastPrologue = null;
25
+ for (const node of program.body) {
26
+ if (node.type === AST_NODE_TYPES.ExpressionStatement &&
27
+ node.expression.type === AST_NODE_TYPES.Literal &&
28
+ typeof node.expression.value === 'string') {
29
+ lastPrologue = node;
30
+ continue;
31
+ }
32
+ break;
33
+ }
34
+ if (lastPrologue) {
35
+ return { anchor: lastPrologue, method: 'insertTextAfter' };
36
+ }
37
+ return { anchor: program.body[0], method: 'insertTextBefore' };
38
+ }
16
39
  export default ESLintUtils.RuleCreator(() => '')({
17
40
  name: 'mobx-require-observer',
18
41
  meta: {
@@ -97,7 +120,10 @@ export default ESLintUtils.RuleCreator(() => '')({
97
120
  fix(fixer) {
98
121
  const fixes = [];
99
122
  if (!hasObserverImport) {
100
- fixes.push(fixer.insertTextBefore(program.body[0], "import { observer } from 'mobx-react-lite';\n"));
123
+ const { anchor, method } = getObserverImportAnchor(program);
124
+ const nBefore = method === 'insertTextAfter' ? '\n' : '';
125
+ const nAfter = method === 'insertTextBefore' ? '\n' : '';
126
+ fixes.push(fixer[method](anchor, `${nBefore}import { observer } from 'mobx-react-lite';${nAfter}`));
101
127
  }
102
128
  const paramsText = fn.params.map(p => sourceCode.getText(p)).join(', ');
103
129
  const bodyText = sourceCode.getText(fn.body);
@@ -112,12 +138,13 @@ export default ESLintUtils.RuleCreator(() => '')({
112
138
  const replacement = `const ${name} = observer(${original});`;
113
139
  fixes.push(fixer.replaceText(fn, replacement));
114
140
  }
115
- else if (varDecl && varDecl.type === AST_NODE_TYPES.VariableDeclaration) {
141
+ else if (varDecl?.type === AST_NODE_TYPES.VariableDeclaration) {
116
142
  // const Name = () => {} or function expression
117
143
  const id = fn.parent.id;
118
144
  const { name } = id;
119
145
  const isExport = exportDecl?.type === AST_NODE_TYPES.ExportNamedDeclaration;
120
- const funcExpression = `function ${name}(${paramsText}) ${bodyText}`;
146
+ const typeParamsText = getTypeParamsText(fn, sourceCode);
147
+ const funcExpression = `function ${name}${typeParamsText}(${paramsText}) ${bodyText}`;
121
148
  const replacementNodeText = `${isExport ? 'export ' : ''}const ${name} = observer(${funcExpression});`;
122
149
  fixes.push(fixer.replaceText(exportDecl || varDecl, replacementNodeText));
123
150
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dartess/eslint-plugin",
3
3
  "type": "module",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "description": "A set of rules and configs for various TypeScript projects",
6
6
  "keywords": [
7
7
  "eslint",
@@ -53,6 +53,7 @@
53
53
  "@stylistic/eslint-plugin": "^5.7.0",
54
54
  "eslint": "^9.0.0",
55
55
  "eslint-import-resolver-typescript": "^4.0.0",
56
+ "eslint-plugin-complete": "^1.2.0",
56
57
  "eslint-plugin-de-morgan": "^2.0.0",
57
58
  "eslint-plugin-decorator-position": "^6.0.0",
58
59
  "eslint-plugin-import-x": "^4.1.0",