eslint-plugin-rxjs-x 0.8.5 → 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/README.md +61 -50
- package/dist/index.d.mts +29 -1
- package/dist/index.d.ts +29 -1
- package/dist/index.js +126 -84
- package/dist/index.mjs +141 -99
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -2,87 +2,97 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x/blob/master/LICENSE)
|
|
4
4
|
[](https://www.npmjs.com/package/eslint-plugin-rxjs-x)
|
|
5
|
+
[](https://scorecard.dev/viewer/?uri=github.com/JasonWeinzierl/eslint-plugin-rxjs-x)
|
|
5
6
|
|
|
6
7
|
This ESLint plugin is intended to prevent issues with [RxJS](https://github.com/ReactiveX/rxjs).
|
|
7
8
|
|
|
8
9
|
Most of these rules require TypeScript typed linting and are indicated as such below.
|
|
9
10
|
|
|
10
|
-
##
|
|
11
|
+
## Installation Guide (Flat Configuration)
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
but has since introduced new features which involve breaking changes.
|
|
13
|
+
See [typescript-eslint's Getting Started](https://typescript-eslint.io/getting-started) for a full ESLint setup guide.
|
|
14
14
|
|
|
15
|
-
1.
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
|
|
15
|
+
1. Install `eslint-plugin-rxjs-x` using your preferred package manager.
|
|
16
|
+
2. Enable typed linting.
|
|
17
|
+
- See [Linting with Type Information](https://typescript-eslint.io/getting-started/typed-linting/) for more information.
|
|
18
|
+
3. Import this plugin into your config.
|
|
19
|
+
Add the `rxjsX.configs.recommended` shared config to your configuration like so:
|
|
19
20
|
|
|
20
21
|
```diff
|
|
22
|
+
// @ts-check
|
|
23
|
+
import { defineConfig } from 'eslint/config';
|
|
24
|
+
import tseslint from 'typescript-eslint';
|
|
21
25
|
+ import rxjsX from 'eslint-plugin-rxjs-x';
|
|
26
|
+
|
|
27
|
+
export default defineConfig({
|
|
28
|
+
extends: [
|
|
29
|
+
tseslint.configs.recommended,
|
|
30
|
+
+ rxjsX.configs.recommended,
|
|
31
|
+
],
|
|
32
|
+
languageOptions: {
|
|
33
|
+
parserOptions: {
|
|
34
|
+
projectService: true,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
});
|
|
22
38
|
```
|
|
23
39
|
|
|
24
|
-
|
|
40
|
+
Additionally, consider if the `rxjsX.configs.strict` shared config is right for your project.
|
|
41
|
+
|
|
42
|
+
## Legacy Migration Guide from `eslint-plugin-rxjs`
|
|
43
|
+
|
|
44
|
+
> [!TIP]
|
|
45
|
+
> A complete description of all changes from `eslint-plugin-rxjs` are documented in the [CHANGELOG](CHANGELOG.md) file.
|
|
46
|
+
|
|
47
|
+
This project started as a fork of [`eslint-plugin-rxjs`](https://github.com/cartant/eslint-plugin-rxjs)
|
|
48
|
+
but is still compatible with the eslintrc configuration format.
|
|
49
|
+
|
|
50
|
+
> [!WARNING]
|
|
51
|
+
> eslintrc compatibility will be removed in v1.
|
|
52
|
+
> Users are highly encouraged to upgrade to ESLint's flat configuration format.
|
|
53
|
+
> See: [https://eslint.org/docs/latest/use/configure/migration-guide]
|
|
54
|
+
|
|
55
|
+
1. Install `eslint-plugin-rxjs-x` using your preferred package manager.
|
|
56
|
+
2. If you previously used the `plugin:rxjs/recommended` shared config,
|
|
57
|
+
replace it with `plugin:rxjs-x/recommended-legacy`:
|
|
25
58
|
|
|
26
59
|
```diff
|
|
27
|
-
extends: [
|
|
28
|
-
|
|
60
|
+
"extends": [
|
|
61
|
+
"plugin:@typescript-eslint/recommended",
|
|
62
|
+
- "plugin:rxjs/recommended",
|
|
63
|
+
+ "plugin:rxjs-x/recommended-legacy",
|
|
29
64
|
],
|
|
30
65
|
```
|
|
31
66
|
|
|
32
|
-
|
|
33
|
-
|
|
67
|
+
3. If you previously did _not_ use a shared config,
|
|
68
|
+
then replace the `rxjs` plugin to your `plugins` block:
|
|
34
69
|
|
|
35
70
|
```diff
|
|
36
|
-
plugins:
|
|
37
|
-
|
|
38
|
-
|
|
71
|
+
"plugins": [
|
|
72
|
+
"@typescript-eslint",
|
|
73
|
+
- "rxjs",
|
|
74
|
+
+ "rxjs-x",
|
|
75
|
+
],
|
|
39
76
|
```
|
|
40
77
|
|
|
41
|
-
- Note: this is unnecessary if you are using
|
|
42
|
-
|
|
78
|
+
- Note: this is unnecessary if you are using the `recommended-legacy` shared config.
|
|
79
|
+
4. In your `rules` blocks, replace the namespace `rxjs` with `rxjs-x` for all rules:
|
|
43
80
|
|
|
44
81
|
```diff
|
|
45
|
-
|
|
46
|
-
|
|
82
|
+
"rules": {
|
|
83
|
+
- "rxjs/no-subject-value": "error",
|
|
84
|
+
+ "rxjs-x/no-subject-value": "error",
|
|
85
|
+
},
|
|
47
86
|
```
|
|
48
87
|
|
|
49
|
-
|
|
88
|
+
- Note: if your project has inline comments (e.g. `eslint-disable-next-line`) referencing `rxjs` rules, you must update the namespace there too.
|
|
89
|
+
5. If you previously used `rxjs/no-ignored-observable`, consider replacing it with `rxjs-x/no-floating-observables`. `no-ignored-observable` will be removed in v1.
|
|
50
90
|
|
|
51
91
|
```diff
|
|
52
92
|
- 'rxjs/no-ignored-observable': 'error',
|
|
53
93
|
+ 'rxjs-x/no-floating-observables': 'error',
|
|
54
94
|
```
|
|
55
95
|
|
|
56
|
-
> [!TIP]
|
|
57
|
-
> A complete description of all changes are documented in the [CHANGELOG](CHANGELOG.md) file.
|
|
58
|
-
|
|
59
|
-
## Installation Guide
|
|
60
|
-
|
|
61
|
-
See [typescript-eslint's Getting Started](https://typescript-eslint.io/getting-started) for a full ESLint setup guide.
|
|
62
|
-
|
|
63
|
-
1. Enable typed linting.
|
|
64
|
-
- See [Linting with Type Information](https://typescript-eslint.io/getting-started/typed-linting/) for more information.
|
|
65
|
-
2. Start with the `recommended` shared config in your `eslint.config.mjs`.
|
|
66
|
-
|
|
67
|
-
```js
|
|
68
|
-
// @ts-check
|
|
69
|
-
import { defineConfig } from 'eslint/config';
|
|
70
|
-
import tseslint from 'typescript-eslint';
|
|
71
|
-
import rxjsX from 'eslint-plugin-rxjs-x';
|
|
72
|
-
|
|
73
|
-
export default defineConfig({
|
|
74
|
-
extends: [
|
|
75
|
-
...tseslint.configs.recommended,
|
|
76
|
-
rxjsX.configs.recommended,
|
|
77
|
-
],
|
|
78
|
-
languageOptions: {
|
|
79
|
-
parserOptions: {
|
|
80
|
-
projectService: true,
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
```
|
|
85
|
-
|
|
86
96
|
## Configs
|
|
87
97
|
|
|
88
98
|
<!-- begin auto-generated configs list -->
|
|
@@ -127,6 +137,7 @@ The package includes the following rules.
|
|
|
127
137
|
| [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | 🔒 | | | 💭 | |
|
|
128
138
|
| [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | 🔒 | | | 💭 | |
|
|
129
139
|
| [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | ✅ 🔒 | | | 💭 | |
|
|
140
|
+
| [no-ignored-observable](docs/rules/no-ignored-observable.md) | Disallow ignoring of observables returned by functions. | | | | | ❌ |
|
|
130
141
|
| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | ✅ 🔒 | | | | |
|
|
131
142
|
| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | 💭 | |
|
|
132
143
|
| [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | 💭 | |
|
package/dist/index.d.mts
CHANGED
|
@@ -97,6 +97,9 @@ declare const allRules: {
|
|
|
97
97
|
recommended: "recommended";
|
|
98
98
|
requiresTypeChecking: true;
|
|
99
99
|
}, TSESLint.RuleListener>;
|
|
100
|
+
'no-ignored-observable': TSESLint.RuleModule<"forbidden", [], {
|
|
101
|
+
description: "Disallow ignoring of observables returned by functions.";
|
|
102
|
+
}, TSESLint.RuleListener>;
|
|
100
103
|
'no-ignored-replay-buffer': TSESLint.RuleModule<"forbidden", [], {
|
|
101
104
|
description: "Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.";
|
|
102
105
|
recommended: "recommended";
|
|
@@ -116,7 +119,7 @@ declare const allRules: {
|
|
|
116
119
|
description: "Disallow ignoring the value within `takeWhile`.";
|
|
117
120
|
recommended: "recommended";
|
|
118
121
|
}, TSESLint.RuleListener>;
|
|
119
|
-
'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown", readonly {
|
|
122
|
+
'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown" | "suggestExplicitAny", readonly {
|
|
120
123
|
allowExplicitAny?: boolean;
|
|
121
124
|
}[], {
|
|
122
125
|
description: "Disallow implicit `any` error parameters in `catchError` operators.";
|
|
@@ -349,6 +352,31 @@ declare const rxjsX: {
|
|
|
349
352
|
}];
|
|
350
353
|
};
|
|
351
354
|
};
|
|
355
|
+
'recommended-legacy': {
|
|
356
|
+
plugins: ["rxjs-x"];
|
|
357
|
+
rules: {
|
|
358
|
+
'rxjs-x/no-async-subscribe': "error";
|
|
359
|
+
'rxjs-x/no-create': "error";
|
|
360
|
+
'rxjs-x/no-ignored-notifier': "error";
|
|
361
|
+
'rxjs-x/no-ignored-replay-buffer': "error";
|
|
362
|
+
'rxjs-x/no-ignored-takewhile-value': "error";
|
|
363
|
+
'rxjs-x/no-implicit-any-catch': "error";
|
|
364
|
+
'rxjs-x/no-index': "error";
|
|
365
|
+
'rxjs-x/no-internal': "error";
|
|
366
|
+
'rxjs-x/no-nested-subscribe': "error";
|
|
367
|
+
'rxjs-x/no-redundant-notify': "error";
|
|
368
|
+
'rxjs-x/no-sharereplay': "error";
|
|
369
|
+
'rxjs-x/no-subject-unsubscribe': "error";
|
|
370
|
+
'rxjs-x/no-subscribe-in-pipe': "error";
|
|
371
|
+
'rxjs-x/no-topromise': "error";
|
|
372
|
+
'rxjs-x/no-unbound-methods': "error";
|
|
373
|
+
'rxjs-x/no-unsafe-subject-next': "error";
|
|
374
|
+
'rxjs-x/no-unsafe-takeuntil': "error";
|
|
375
|
+
'rxjs-x/prefer-observer': "error";
|
|
376
|
+
'rxjs-x/prefer-root-operators': "error";
|
|
377
|
+
'rxjs-x/throw-error': "error";
|
|
378
|
+
};
|
|
379
|
+
};
|
|
352
380
|
};
|
|
353
381
|
meta: {
|
|
354
382
|
name: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -97,6 +97,9 @@ declare const allRules: {
|
|
|
97
97
|
recommended: "recommended";
|
|
98
98
|
requiresTypeChecking: true;
|
|
99
99
|
}, TSESLint.RuleListener>;
|
|
100
|
+
'no-ignored-observable': TSESLint.RuleModule<"forbidden", [], {
|
|
101
|
+
description: "Disallow ignoring of observables returned by functions.";
|
|
102
|
+
}, TSESLint.RuleListener>;
|
|
100
103
|
'no-ignored-replay-buffer': TSESLint.RuleModule<"forbidden", [], {
|
|
101
104
|
description: "Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.";
|
|
102
105
|
recommended: "recommended";
|
|
@@ -116,7 +119,7 @@ declare const allRules: {
|
|
|
116
119
|
description: "Disallow ignoring the value within `takeWhile`.";
|
|
117
120
|
recommended: "recommended";
|
|
118
121
|
}, TSESLint.RuleListener>;
|
|
119
|
-
'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown", readonly {
|
|
122
|
+
'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown" | "suggestExplicitAny", readonly {
|
|
120
123
|
allowExplicitAny?: boolean;
|
|
121
124
|
}[], {
|
|
122
125
|
description: "Disallow implicit `any` error parameters in `catchError` operators.";
|
|
@@ -349,6 +352,31 @@ declare const rxjsX: {
|
|
|
349
352
|
}];
|
|
350
353
|
};
|
|
351
354
|
};
|
|
355
|
+
'recommended-legacy': {
|
|
356
|
+
plugins: ["rxjs-x"];
|
|
357
|
+
rules: {
|
|
358
|
+
'rxjs-x/no-async-subscribe': "error";
|
|
359
|
+
'rxjs-x/no-create': "error";
|
|
360
|
+
'rxjs-x/no-ignored-notifier': "error";
|
|
361
|
+
'rxjs-x/no-ignored-replay-buffer': "error";
|
|
362
|
+
'rxjs-x/no-ignored-takewhile-value': "error";
|
|
363
|
+
'rxjs-x/no-implicit-any-catch': "error";
|
|
364
|
+
'rxjs-x/no-index': "error";
|
|
365
|
+
'rxjs-x/no-internal': "error";
|
|
366
|
+
'rxjs-x/no-nested-subscribe': "error";
|
|
367
|
+
'rxjs-x/no-redundant-notify': "error";
|
|
368
|
+
'rxjs-x/no-sharereplay': "error";
|
|
369
|
+
'rxjs-x/no-subject-unsubscribe': "error";
|
|
370
|
+
'rxjs-x/no-subscribe-in-pipe': "error";
|
|
371
|
+
'rxjs-x/no-topromise': "error";
|
|
372
|
+
'rxjs-x/no-unbound-methods': "error";
|
|
373
|
+
'rxjs-x/no-unsafe-subject-next': "error";
|
|
374
|
+
'rxjs-x/no-unsafe-takeuntil': "error";
|
|
375
|
+
'rxjs-x/prefer-observer': "error";
|
|
376
|
+
'rxjs-x/prefer-root-operators': "error";
|
|
377
|
+
'rxjs-x/throw-error': "error";
|
|
378
|
+
};
|
|
379
|
+
};
|
|
352
380
|
};
|
|
353
381
|
meta: {
|
|
354
382
|
name: string;
|
package/dist/index.js
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// package.json
|
|
2
2
|
var name = "eslint-plugin-rxjs-x";
|
|
3
|
-
var version = "0.
|
|
3
|
+
var version = "0.9.0";
|
|
4
4
|
|
|
5
5
|
// src/configs/recommended.ts
|
|
6
6
|
var createRecommendedConfig = (plugin2) => ({
|
|
7
|
+
...baseConfig,
|
|
7
8
|
name: "rxjs-x/recommended",
|
|
8
9
|
plugins: {
|
|
9
10
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- "A type annotation is necessary."
|
|
10
11
|
"rxjs-x": plugin2
|
|
11
|
-
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
var createLegacyRecommendedConfig = () => ({
|
|
15
|
+
...baseConfig,
|
|
16
|
+
plugins: ["rxjs-x"]
|
|
17
|
+
});
|
|
18
|
+
var baseConfig = {
|
|
12
19
|
rules: {
|
|
13
20
|
"rxjs-x/no-async-subscribe": "error",
|
|
14
21
|
"rxjs-x/no-create": "error",
|
|
@@ -31,7 +38,7 @@ var createRecommendedConfig = (plugin2) => ({
|
|
|
31
38
|
"rxjs-x/prefer-root-operators": "error",
|
|
32
39
|
"rxjs-x/throw-error": "error"
|
|
33
40
|
}
|
|
34
|
-
}
|
|
41
|
+
};
|
|
35
42
|
|
|
36
43
|
// src/configs/strict.ts
|
|
37
44
|
var createStrictConfig = (plugin2) => ({
|
|
@@ -104,7 +111,7 @@ function escapeRegExp(text) {
|
|
|
104
111
|
var _typescript = require('typescript'); var _typescript2 = _interopRequireDefault(_typescript);
|
|
105
112
|
|
|
106
113
|
// src/etc/could-be-type.ts
|
|
107
|
-
var _tsapiutils = require('ts-api-utils'); var tsutils = _interopRequireWildcard(_tsapiutils); var tsutils2 = _interopRequireWildcard(_tsapiutils); var tsutils3 = _interopRequireWildcard(_tsapiutils); var tsutils4 = _interopRequireWildcard(_tsapiutils); var tsutils5 = _interopRequireWildcard(_tsapiutils);
|
|
114
|
+
var _tsapiutils = require('ts-api-utils'); var tsutils = _interopRequireWildcard(_tsapiutils); var tsutils2 = _interopRequireWildcard(_tsapiutils); var tsutils3 = _interopRequireWildcard(_tsapiutils); var tsutils4 = _interopRequireWildcard(_tsapiutils); var tsutils5 = _interopRequireWildcard(_tsapiutils); var tsutils6 = _interopRequireWildcard(_tsapiutils);
|
|
108
115
|
|
|
109
116
|
function couldBeType(type, name2, qualified) {
|
|
110
117
|
if (tsutils.isTypeReference(type)) {
|
|
@@ -301,7 +308,7 @@ function isUnionType(node) {
|
|
|
301
308
|
// src/etc/get-type-services.ts
|
|
302
309
|
function getTypeServices(context) {
|
|
303
310
|
const services = _utils.ESLintUtils.getParserServices(context);
|
|
304
|
-
const {
|
|
311
|
+
const { program, getTypeAtLocation } = services;
|
|
305
312
|
const typeChecker = program.getTypeChecker();
|
|
306
313
|
const couldBeType2 = (node, name2, qualified) => {
|
|
307
314
|
const type = getTypeAtLocation(node);
|
|
@@ -312,30 +319,18 @@ function getTypeServices(context) {
|
|
|
312
319
|
);
|
|
313
320
|
};
|
|
314
321
|
const couldReturnType = (node, name2, qualified) => {
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
} else if (tsNode.body && _typescript2.default.isBlock(tsNode.body)) {
|
|
321
|
-
const returnStatement = tsNode.body.statements.find(_typescript2.default.isReturnStatement);
|
|
322
|
-
if (returnStatement == null ? void 0 : returnStatement.expression) {
|
|
323
|
-
tsTypeNode = returnStatement.expression;
|
|
324
|
-
}
|
|
325
|
-
} else {
|
|
326
|
-
tsTypeNode = tsNode.body;
|
|
327
|
-
}
|
|
328
|
-
} else if (_typescript2.default.isCallSignatureDeclaration(tsNode) || _typescript2.default.isMethodSignature(tsNode)) {
|
|
329
|
-
tsTypeNode = tsNode.type;
|
|
330
|
-
} else if (_typescript2.default.isPropertySignature(tsNode)) {
|
|
331
|
-
}
|
|
332
|
-
return Boolean(
|
|
333
|
-
tsTypeNode && couldBeType(
|
|
334
|
-
typeChecker.getTypeAtLocation(tsTypeNode),
|
|
322
|
+
const type = getTypeAtLocation(node);
|
|
323
|
+
for (const signature of tsutils2.getCallSignaturesOfType(type)) {
|
|
324
|
+
const returnType = signature.getReturnType();
|
|
325
|
+
if (couldBeType(
|
|
326
|
+
returnType,
|
|
335
327
|
name2,
|
|
336
328
|
qualified ? { ...qualified, typeChecker } : void 0
|
|
337
|
-
)
|
|
338
|
-
|
|
329
|
+
)) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
339
334
|
};
|
|
340
335
|
return {
|
|
341
336
|
couldBeBehaviorSubject: (node) => couldBeType2(node, "BehaviorSubject"),
|
|
@@ -682,21 +677,30 @@ var finnishRule = ruleCreator({
|
|
|
682
677
|
});
|
|
683
678
|
} : () => {
|
|
684
679
|
};
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
680
|
+
const nameWithoutDollar = text.endsWith("$") ? text.slice(0, -1) : text;
|
|
681
|
+
for (const name2 of names) {
|
|
682
|
+
const { regExp, validate: validate2 } = name2;
|
|
683
|
+
if (regExp.test(text) || regExp.test(nameWithoutDollar)) {
|
|
684
|
+
if (validate2) {
|
|
685
|
+
shouldBeFinnish();
|
|
686
|
+
} else {
|
|
689
687
|
shouldNotBeFinnish();
|
|
690
|
-
return;
|
|
691
688
|
}
|
|
689
|
+
return;
|
|
692
690
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
691
|
+
}
|
|
692
|
+
for (const type of types) {
|
|
693
|
+
const { regExp, validate: validate2 } = type;
|
|
694
|
+
if (couldBeType2(typeNode != null ? typeNode : nameNode, regExp) || couldReturnType(typeNode != null ? typeNode : nameNode, regExp)) {
|
|
695
|
+
if (validate2) {
|
|
696
|
+
shouldBeFinnish();
|
|
697
|
+
} else {
|
|
696
698
|
shouldNotBeFinnish();
|
|
697
|
-
return;
|
|
698
699
|
}
|
|
700
|
+
return;
|
|
699
701
|
}
|
|
702
|
+
}
|
|
703
|
+
if (couldBeObservable(typeNode != null ? typeNode : nameNode) || couldReturnObservable(typeNode != null ? typeNode : nameNode)) {
|
|
700
704
|
shouldBeFinnish();
|
|
701
705
|
} else {
|
|
702
706
|
shouldNotBeFinnish();
|
|
@@ -1235,7 +1239,7 @@ var noExplicitGenericsRule = ruleCreator({
|
|
|
1235
1239
|
}
|
|
1236
1240
|
const { getTypeAtLocation } = _utils.ESLintUtils.getParserServices(context);
|
|
1237
1241
|
const type = getTypeAtLocation(node);
|
|
1238
|
-
return
|
|
1242
|
+
return tsutils3.isUnionOrIntersectionType(type);
|
|
1239
1243
|
}
|
|
1240
1244
|
function checkBehaviorSubjects(node) {
|
|
1241
1245
|
var _a;
|
|
@@ -1793,6 +1797,37 @@ var noIgnoredNotifierRule = ruleCreator({
|
|
|
1793
1797
|
}
|
|
1794
1798
|
});
|
|
1795
1799
|
|
|
1800
|
+
// src/rules/no-ignored-observable.ts
|
|
1801
|
+
var noIgnoredObservableRule = ruleCreator({
|
|
1802
|
+
defaultOptions: [],
|
|
1803
|
+
meta: {
|
|
1804
|
+
deprecated: true,
|
|
1805
|
+
docs: {
|
|
1806
|
+
description: "Disallow ignoring of observables returned by functions."
|
|
1807
|
+
},
|
|
1808
|
+
messages: {
|
|
1809
|
+
forbidden: "Ignoring a returned Observable is forbidden."
|
|
1810
|
+
},
|
|
1811
|
+
replacedBy: ["no-floating-observables"],
|
|
1812
|
+
schema: [],
|
|
1813
|
+
type: "problem"
|
|
1814
|
+
},
|
|
1815
|
+
name: "no-ignored-observable",
|
|
1816
|
+
create: (context) => {
|
|
1817
|
+
const { couldBeObservable } = getTypeServices(context);
|
|
1818
|
+
return {
|
|
1819
|
+
"ExpressionStatement > CallExpression": (node) => {
|
|
1820
|
+
if (couldBeObservable(node)) {
|
|
1821
|
+
context.report({
|
|
1822
|
+
messageId: "forbidden",
|
|
1823
|
+
node
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1796
1831
|
// src/rules/no-ignored-replay-buffer.ts
|
|
1797
1832
|
var noIgnoredReplayBufferRule = ruleCreator({
|
|
1798
1833
|
defaultOptions: [],
|
|
@@ -2037,10 +2072,11 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2037
2072
|
fixable: "code",
|
|
2038
2073
|
hasSuggestions: true,
|
|
2039
2074
|
messages: {
|
|
2040
|
-
explicitAny: "Explicit `any` in
|
|
2041
|
-
implicitAny: "Implicit `any` in
|
|
2075
|
+
explicitAny: "Explicit `any` in error callback.",
|
|
2076
|
+
implicitAny: "Implicit `any` in error callback.",
|
|
2042
2077
|
narrowed: "Error type must be `unknown` or `any`.",
|
|
2043
|
-
suggestExplicitUnknown: "Use `unknown` instead
|
|
2078
|
+
suggestExplicitUnknown: "Use `unknown` instead to explicitly and safely assert the type is correct.",
|
|
2079
|
+
suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety."
|
|
2044
2080
|
},
|
|
2045
2081
|
schema: [
|
|
2046
2082
|
{
|
|
@@ -2063,6 +2099,22 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2063
2099
|
const { allowExplicitAny = true } = config;
|
|
2064
2100
|
const { couldBeObservable } = getTypeServices(context);
|
|
2065
2101
|
const sourceCode = context.sourceCode;
|
|
2102
|
+
function createReplacerFix(typeAnnotation, replaceWith) {
|
|
2103
|
+
return function fix(fixer) {
|
|
2104
|
+
return fixer.replaceText(typeAnnotation, `: ${replaceWith}`);
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
function createInserterFix(param, annotateWith, { hasRestParams = false } = {}) {
|
|
2108
|
+
return function fix(fixer) {
|
|
2109
|
+
if (hasRestParams || isParenthesised(sourceCode, param)) {
|
|
2110
|
+
return fixer.insertTextAfter(param, `: ${annotateWith}`);
|
|
2111
|
+
}
|
|
2112
|
+
return [
|
|
2113
|
+
fixer.insertTextBefore(param, "("),
|
|
2114
|
+
fixer.insertTextAfter(param, `: ${annotateWith})`)
|
|
2115
|
+
];
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2066
2118
|
function checkCallback(callback) {
|
|
2067
2119
|
if (isArrowFunctionExpression(callback) || isFunctionExpression(callback)) {
|
|
2068
2120
|
const [param, ...restParams] = callback.params;
|
|
@@ -2075,61 +2127,51 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2075
2127
|
typeAnnotation: { type }
|
|
2076
2128
|
} = typeAnnotation;
|
|
2077
2129
|
if (type === _utils.AST_NODE_TYPES.TSAnyKeyword) {
|
|
2078
|
-
let fix2 = function(fixer) {
|
|
2079
|
-
return fixer.replaceText(typeAnnotation, ": unknown");
|
|
2080
|
-
};
|
|
2081
|
-
var fix = fix2;
|
|
2082
2130
|
if (allowExplicitAny) {
|
|
2083
2131
|
return;
|
|
2084
2132
|
}
|
|
2085
2133
|
context.report({
|
|
2086
|
-
fix: fix2,
|
|
2087
2134
|
messageId: "explicitAny",
|
|
2088
2135
|
node: param,
|
|
2089
2136
|
suggest: [
|
|
2090
2137
|
{
|
|
2091
2138
|
messageId: "suggestExplicitUnknown",
|
|
2092
|
-
fix:
|
|
2139
|
+
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2093
2140
|
}
|
|
2094
2141
|
]
|
|
2095
2142
|
});
|
|
2096
2143
|
} else if (type !== _utils.AST_NODE_TYPES.TSUnknownKeyword) {
|
|
2097
|
-
let fix2 = function(fixer) {
|
|
2098
|
-
return fixer.replaceText(typeAnnotation, ": unknown");
|
|
2099
|
-
};
|
|
2100
|
-
var fix = fix2;
|
|
2101
2144
|
context.report({
|
|
2102
2145
|
messageId: "narrowed",
|
|
2103
2146
|
node: param,
|
|
2104
2147
|
suggest: [
|
|
2105
2148
|
{
|
|
2106
2149
|
messageId: "suggestExplicitUnknown",
|
|
2107
|
-
fix:
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2150
|
+
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2151
|
+
},
|
|
2152
|
+
allowExplicitAny ? {
|
|
2153
|
+
messageId: "suggestExplicitAny",
|
|
2154
|
+
fix: createReplacerFix(typeAnnotation, "any")
|
|
2155
|
+
} : null
|
|
2156
|
+
].filter((x) => !!x)
|
|
2110
2157
|
});
|
|
2111
2158
|
}
|
|
2112
2159
|
} else {
|
|
2113
|
-
|
|
2114
|
-
if (isParenthesised(sourceCode, param) || restParams.length > 0) {
|
|
2115
|
-
return fixer.insertTextAfter(param, ": unknown");
|
|
2116
|
-
}
|
|
2117
|
-
return [
|
|
2118
|
-
fixer.insertTextBefore(param, "("),
|
|
2119
|
-
fixer.insertTextAfter(param, ": unknown)")
|
|
2120
|
-
];
|
|
2121
|
-
};
|
|
2122
|
-
var fix = fix2;
|
|
2160
|
+
const hasRestParams = restParams.length > 0;
|
|
2123
2161
|
context.report({
|
|
2124
|
-
fix:
|
|
2162
|
+
fix: allowExplicitAny ? createInserterFix(param, "any", { hasRestParams }) : void 0,
|
|
2125
2163
|
messageId: "implicitAny",
|
|
2126
2164
|
node: param,
|
|
2127
2165
|
suggest: [
|
|
2128
2166
|
{
|
|
2129
2167
|
messageId: "suggestExplicitUnknown",
|
|
2130
|
-
fix:
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2168
|
+
fix: createInserterFix(param, "unknown", { hasRestParams })
|
|
2169
|
+
},
|
|
2170
|
+
allowExplicitAny ? {
|
|
2171
|
+
messageId: "suggestExplicitAny",
|
|
2172
|
+
fix: createInserterFix(param, "any", { hasRestParams })
|
|
2173
|
+
} : null
|
|
2174
|
+
].filter((x) => !!x)
|
|
2133
2175
|
});
|
|
2134
2176
|
}
|
|
2135
2177
|
}
|
|
@@ -2566,7 +2608,7 @@ function voidFunctionArguments(checker, tsNode) {
|
|
|
2566
2608
|
}
|
|
2567
2609
|
const voidReturnIndices = /* @__PURE__ */ new Set();
|
|
2568
2610
|
const type = checker.getTypeAtLocation(tsNode.expression);
|
|
2569
|
-
for (const subType of
|
|
2611
|
+
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2570
2612
|
const signatures = _typescript2.default.isCallExpression(tsNode) ? subType.getCallSignatures() : subType.getConstructSignatures();
|
|
2571
2613
|
for (const signature of signatures) {
|
|
2572
2614
|
for (const [index, parameter] of signature.parameters.entries()) {
|
|
@@ -2581,13 +2623,13 @@ function voidFunctionArguments(checker, tsNode) {
|
|
|
2581
2623
|
}
|
|
2582
2624
|
function isVoidReturningFunctionType(type) {
|
|
2583
2625
|
let hasVoidReturn = false;
|
|
2584
|
-
for (const subType of
|
|
2626
|
+
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2585
2627
|
for (const signature of subType.getCallSignatures()) {
|
|
2586
2628
|
const returnType = signature.getReturnType();
|
|
2587
2629
|
if (couldBeType(returnType, "Observable")) {
|
|
2588
2630
|
return false;
|
|
2589
2631
|
}
|
|
2590
|
-
hasVoidReturn || (hasVoidReturn =
|
|
2632
|
+
hasVoidReturn || (hasVoidReturn = tsutils4.isTypeFlagSet(returnType, _typescript2.default.TypeFlags.Void));
|
|
2591
2633
|
}
|
|
2592
2634
|
}
|
|
2593
2635
|
return hasVoidReturn;
|
|
@@ -2600,7 +2642,7 @@ function getMemberIfExists(type, memberName) {
|
|
|
2600
2642
|
var _a, _b;
|
|
2601
2643
|
const escapedMemberName = _typescript2.default.escapeLeadingUnderscores(memberName);
|
|
2602
2644
|
const symbolMemberMatch = (_b = (_a = type.getSymbol()) == null ? void 0 : _a.members) == null ? void 0 : _b.get(escapedMemberName);
|
|
2603
|
-
return symbolMemberMatch != null ? symbolMemberMatch :
|
|
2645
|
+
return symbolMemberMatch != null ? symbolMemberMatch : tsutils4.getPropertyOfType(type, escapedMemberName);
|
|
2604
2646
|
}
|
|
2605
2647
|
function isStaticMember(node) {
|
|
2606
2648
|
return (isMethodDefinition(node) || isPropertyDefinition(node) || isAccessorProperty(node)) && node.static;
|
|
@@ -2622,7 +2664,7 @@ function getPropertyContextualType(checker, tsNode) {
|
|
|
2622
2664
|
if (objType == null) {
|
|
2623
2665
|
return;
|
|
2624
2666
|
}
|
|
2625
|
-
const propertySymbol = checker.getPropertyOfType(
|
|
2667
|
+
const propertySymbol = tsutils4.unionConstituents(objType).map((t) => checker.getPropertyOfType(t, tsNode.name.getText())).find((p) => p);
|
|
2626
2668
|
if (propertySymbol == null) {
|
|
2627
2669
|
return;
|
|
2628
2670
|
}
|
|
@@ -3085,8 +3127,6 @@ var noSubscribeInPipeRule = ruleCreator({
|
|
|
3085
3127
|
recommended: "recommended",
|
|
3086
3128
|
requiresTypeChecking: true
|
|
3087
3129
|
},
|
|
3088
|
-
fixable: void 0,
|
|
3089
|
-
hasSuggestions: false,
|
|
3090
3130
|
messages: {
|
|
3091
3131
|
forbidden: "Subscribe calls within pipe operators are forbidden."
|
|
3092
3132
|
},
|
|
@@ -3578,19 +3618,19 @@ var noUnsafeSubjectNext = ruleCreator({
|
|
|
3578
3618
|
[`CallExpression[callee.property.name='next']`]: (node) => {
|
|
3579
3619
|
if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
|
|
3580
3620
|
const type = getTypeAtLocation(node.callee.object);
|
|
3581
|
-
if (
|
|
3621
|
+
if (tsutils5.isTypeReference(type) && couldBeType(type, "Subject")) {
|
|
3582
3622
|
const [typeArg] = typeChecker.getTypeArguments(type);
|
|
3583
|
-
if (
|
|
3623
|
+
if (tsutils5.isTypeFlagSet(typeArg, _typescript2.default.TypeFlags.Any)) {
|
|
3584
3624
|
return;
|
|
3585
3625
|
}
|
|
3586
|
-
if (
|
|
3626
|
+
if (tsutils5.isTypeFlagSet(typeArg, _typescript2.default.TypeFlags.Unknown)) {
|
|
3587
3627
|
return;
|
|
3588
3628
|
}
|
|
3589
|
-
if (
|
|
3629
|
+
if (tsutils5.isTypeFlagSet(typeArg, _typescript2.default.TypeFlags.Void)) {
|
|
3590
3630
|
return;
|
|
3591
3631
|
}
|
|
3592
|
-
if (
|
|
3593
|
-
(t) =>
|
|
3632
|
+
if (tsutils5.isUnionType(typeArg) && typeArg.types.some(
|
|
3633
|
+
(t) => tsutils5.isTypeFlagSet(t, _typescript2.default.TypeFlags.Void)
|
|
3594
3634
|
)) {
|
|
3595
3635
|
return;
|
|
3596
3636
|
}
|
|
@@ -4277,10 +4317,10 @@ var throwErrorRule = ruleCreator({
|
|
|
4277
4317
|
const body = tsNode.body;
|
|
4278
4318
|
type = program.getTypeChecker().getTypeAtLocation(annotation != null ? annotation : body);
|
|
4279
4319
|
}
|
|
4280
|
-
if (allowThrowingAny &&
|
|
4320
|
+
if (allowThrowingAny && tsutils6.isIntrinsicAnyType(type)) {
|
|
4281
4321
|
return;
|
|
4282
4322
|
}
|
|
4283
|
-
if (allowThrowingUnknown &&
|
|
4323
|
+
if (allowThrowingUnknown && tsutils6.isIntrinsicUnknownType(type)) {
|
|
4284
4324
|
return;
|
|
4285
4325
|
}
|
|
4286
4326
|
if (couldBeType(type, /^Error$/)) {
|
|
@@ -4334,6 +4374,7 @@ var allRules = {
|
|
|
4334
4374
|
"no-ignored-default-value": noIgnoredDefaultValueRule,
|
|
4335
4375
|
"no-ignored-error": noIgnoredErrorRule,
|
|
4336
4376
|
"no-ignored-notifier": noIgnoredNotifierRule,
|
|
4377
|
+
"no-ignored-observable": noIgnoredObservableRule,
|
|
4337
4378
|
"no-ignored-replay-buffer": noIgnoredReplayBufferRule,
|
|
4338
4379
|
"no-ignored-subscribe": noIgnoredSubscribeRule,
|
|
4339
4380
|
"no-ignored-subscription": noIgnoredSubscriptionRule,
|
|
@@ -4377,8 +4418,9 @@ var plugin = {
|
|
|
4377
4418
|
var rxjsX = {
|
|
4378
4419
|
...plugin,
|
|
4379
4420
|
configs: {
|
|
4380
|
-
recommended: createRecommendedConfig(plugin),
|
|
4381
|
-
strict: createStrictConfig(plugin)
|
|
4421
|
+
"recommended": createRecommendedConfig(plugin),
|
|
4422
|
+
"strict": createStrictConfig(plugin),
|
|
4423
|
+
"recommended-legacy": createLegacyRecommendedConfig()
|
|
4382
4424
|
}
|
|
4383
4425
|
};
|
|
4384
4426
|
var index_default = rxjsX;
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var name = "eslint-plugin-rxjs-x";
|
|
3
|
-
var version = "0.
|
|
3
|
+
var version = "0.9.0";
|
|
4
4
|
|
|
5
5
|
// src/configs/recommended.ts
|
|
6
6
|
var createRecommendedConfig = (plugin2) => ({
|
|
7
|
+
...baseConfig,
|
|
7
8
|
name: "rxjs-x/recommended",
|
|
8
9
|
plugins: {
|
|
9
10
|
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- "A type annotation is necessary."
|
|
10
11
|
"rxjs-x": plugin2
|
|
11
|
-
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
var createLegacyRecommendedConfig = () => ({
|
|
15
|
+
...baseConfig,
|
|
16
|
+
plugins: ["rxjs-x"]
|
|
17
|
+
});
|
|
18
|
+
var baseConfig = {
|
|
12
19
|
rules: {
|
|
13
20
|
"rxjs-x/no-async-subscribe": "error",
|
|
14
21
|
"rxjs-x/no-create": "error",
|
|
@@ -31,7 +38,7 @@ var createRecommendedConfig = (plugin2) => ({
|
|
|
31
38
|
"rxjs-x/prefer-root-operators": "error",
|
|
32
39
|
"rxjs-x/throw-error": "error"
|
|
33
40
|
}
|
|
34
|
-
}
|
|
41
|
+
};
|
|
35
42
|
|
|
36
43
|
// src/configs/strict.ts
|
|
37
44
|
var createStrictConfig = (plugin2) => ({
|
|
@@ -215,7 +222,7 @@ function getLoc(node) {
|
|
|
215
222
|
|
|
216
223
|
// src/etc/get-type-services.ts
|
|
217
224
|
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
218
|
-
import
|
|
225
|
+
import * as tsutils2 from "ts-api-utils";
|
|
219
226
|
|
|
220
227
|
// src/etc/is.ts
|
|
221
228
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
@@ -301,7 +308,7 @@ function isUnionType(node) {
|
|
|
301
308
|
// src/etc/get-type-services.ts
|
|
302
309
|
function getTypeServices(context) {
|
|
303
310
|
const services = ESLintUtils.getParserServices(context);
|
|
304
|
-
const {
|
|
311
|
+
const { program, getTypeAtLocation } = services;
|
|
305
312
|
const typeChecker = program.getTypeChecker();
|
|
306
313
|
const couldBeType2 = (node, name2, qualified) => {
|
|
307
314
|
const type = getTypeAtLocation(node);
|
|
@@ -312,30 +319,18 @@ function getTypeServices(context) {
|
|
|
312
319
|
);
|
|
313
320
|
};
|
|
314
321
|
const couldReturnType = (node, name2, qualified) => {
|
|
315
|
-
|
|
316
|
-
const
|
|
317
|
-
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
} else if (tsNode.body && ts4.isBlock(tsNode.body)) {
|
|
321
|
-
const returnStatement = tsNode.body.statements.find(ts4.isReturnStatement);
|
|
322
|
-
if (returnStatement == null ? void 0 : returnStatement.expression) {
|
|
323
|
-
tsTypeNode = returnStatement.expression;
|
|
324
|
-
}
|
|
325
|
-
} else {
|
|
326
|
-
tsTypeNode = tsNode.body;
|
|
327
|
-
}
|
|
328
|
-
} else if (ts4.isCallSignatureDeclaration(tsNode) || ts4.isMethodSignature(tsNode)) {
|
|
329
|
-
tsTypeNode = tsNode.type;
|
|
330
|
-
} else if (ts4.isPropertySignature(tsNode)) {
|
|
331
|
-
}
|
|
332
|
-
return Boolean(
|
|
333
|
-
tsTypeNode && couldBeType(
|
|
334
|
-
typeChecker.getTypeAtLocation(tsTypeNode),
|
|
322
|
+
const type = getTypeAtLocation(node);
|
|
323
|
+
for (const signature of tsutils2.getCallSignaturesOfType(type)) {
|
|
324
|
+
const returnType = signature.getReturnType();
|
|
325
|
+
if (couldBeType(
|
|
326
|
+
returnType,
|
|
335
327
|
name2,
|
|
336
328
|
qualified ? { ...qualified, typeChecker } : void 0
|
|
337
|
-
)
|
|
338
|
-
|
|
329
|
+
)) {
|
|
330
|
+
return true;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return false;
|
|
339
334
|
};
|
|
340
335
|
return {
|
|
341
336
|
couldBeBehaviorSubject: (node) => couldBeType2(node, "BehaviorSubject"),
|
|
@@ -682,21 +677,30 @@ var finnishRule = ruleCreator({
|
|
|
682
677
|
});
|
|
683
678
|
} : () => {
|
|
684
679
|
};
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
680
|
+
const nameWithoutDollar = text.endsWith("$") ? text.slice(0, -1) : text;
|
|
681
|
+
for (const name2 of names) {
|
|
682
|
+
const { regExp, validate: validate2 } = name2;
|
|
683
|
+
if (regExp.test(text) || regExp.test(nameWithoutDollar)) {
|
|
684
|
+
if (validate2) {
|
|
685
|
+
shouldBeFinnish();
|
|
686
|
+
} else {
|
|
689
687
|
shouldNotBeFinnish();
|
|
690
|
-
return;
|
|
691
688
|
}
|
|
689
|
+
return;
|
|
692
690
|
}
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
691
|
+
}
|
|
692
|
+
for (const type of types) {
|
|
693
|
+
const { regExp, validate: validate2 } = type;
|
|
694
|
+
if (couldBeType2(typeNode != null ? typeNode : nameNode, regExp) || couldReturnType(typeNode != null ? typeNode : nameNode, regExp)) {
|
|
695
|
+
if (validate2) {
|
|
696
|
+
shouldBeFinnish();
|
|
697
|
+
} else {
|
|
696
698
|
shouldNotBeFinnish();
|
|
697
|
-
return;
|
|
698
699
|
}
|
|
700
|
+
return;
|
|
699
701
|
}
|
|
702
|
+
}
|
|
703
|
+
if (couldBeObservable(typeNode != null ? typeNode : nameNode) || couldReturnObservable(typeNode != null ? typeNode : nameNode)) {
|
|
700
704
|
shouldBeFinnish();
|
|
701
705
|
} else {
|
|
702
706
|
shouldNotBeFinnish();
|
|
@@ -1099,7 +1103,7 @@ var noCreateRule = ruleCreator({
|
|
|
1099
1103
|
// src/rules/no-cyclic-action.ts
|
|
1100
1104
|
import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
|
|
1101
1105
|
import { stripIndent as stripIndent3 } from "common-tags";
|
|
1102
|
-
import
|
|
1106
|
+
import ts4 from "typescript";
|
|
1103
1107
|
function isTypeReference2(type) {
|
|
1104
1108
|
return Boolean(type.target);
|
|
1105
1109
|
}
|
|
@@ -1144,7 +1148,7 @@ var noCyclicActionRule = ruleCreator({
|
|
|
1144
1148
|
const operatorType = getTypeAtLocation(operatorCallExpression);
|
|
1145
1149
|
const [signature] = typeChecker.getSignaturesOfType(
|
|
1146
1150
|
operatorType,
|
|
1147
|
-
|
|
1151
|
+
ts4.SignatureKind.Call
|
|
1148
1152
|
);
|
|
1149
1153
|
if (!signature) {
|
|
1150
1154
|
return;
|
|
@@ -1204,7 +1208,7 @@ var noCyclicActionRule = ruleCreator({
|
|
|
1204
1208
|
|
|
1205
1209
|
// src/rules/no-explicit-generics.ts
|
|
1206
1210
|
import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
|
|
1207
|
-
import * as
|
|
1211
|
+
import * as tsutils3 from "ts-api-utils";
|
|
1208
1212
|
var noExplicitGenericsRule = ruleCreator({
|
|
1209
1213
|
defaultOptions: [],
|
|
1210
1214
|
meta: {
|
|
@@ -1235,7 +1239,7 @@ var noExplicitGenericsRule = ruleCreator({
|
|
|
1235
1239
|
}
|
|
1236
1240
|
const { getTypeAtLocation } = ESLintUtils5.getParserServices(context);
|
|
1237
1241
|
const type = getTypeAtLocation(node);
|
|
1238
|
-
return
|
|
1242
|
+
return tsutils3.isUnionOrIntersectionType(type);
|
|
1239
1243
|
}
|
|
1240
1244
|
function checkBehaviorSubjects(node) {
|
|
1241
1245
|
var _a;
|
|
@@ -1793,6 +1797,37 @@ var noIgnoredNotifierRule = ruleCreator({
|
|
|
1793
1797
|
}
|
|
1794
1798
|
});
|
|
1795
1799
|
|
|
1800
|
+
// src/rules/no-ignored-observable.ts
|
|
1801
|
+
var noIgnoredObservableRule = ruleCreator({
|
|
1802
|
+
defaultOptions: [],
|
|
1803
|
+
meta: {
|
|
1804
|
+
deprecated: true,
|
|
1805
|
+
docs: {
|
|
1806
|
+
description: "Disallow ignoring of observables returned by functions."
|
|
1807
|
+
},
|
|
1808
|
+
messages: {
|
|
1809
|
+
forbidden: "Ignoring a returned Observable is forbidden."
|
|
1810
|
+
},
|
|
1811
|
+
replacedBy: ["no-floating-observables"],
|
|
1812
|
+
schema: [],
|
|
1813
|
+
type: "problem"
|
|
1814
|
+
},
|
|
1815
|
+
name: "no-ignored-observable",
|
|
1816
|
+
create: (context) => {
|
|
1817
|
+
const { couldBeObservable } = getTypeServices(context);
|
|
1818
|
+
return {
|
|
1819
|
+
"ExpressionStatement > CallExpression": (node) => {
|
|
1820
|
+
if (couldBeObservable(node)) {
|
|
1821
|
+
context.report({
|
|
1822
|
+
messageId: "forbidden",
|
|
1823
|
+
node
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
};
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
|
|
1796
1831
|
// src/rules/no-ignored-replay-buffer.ts
|
|
1797
1832
|
var noIgnoredReplayBufferRule = ruleCreator({
|
|
1798
1833
|
defaultOptions: [],
|
|
@@ -2037,10 +2072,11 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2037
2072
|
fixable: "code",
|
|
2038
2073
|
hasSuggestions: true,
|
|
2039
2074
|
messages: {
|
|
2040
|
-
explicitAny: "Explicit `any` in
|
|
2041
|
-
implicitAny: "Implicit `any` in
|
|
2075
|
+
explicitAny: "Explicit `any` in error callback.",
|
|
2076
|
+
implicitAny: "Implicit `any` in error callback.",
|
|
2042
2077
|
narrowed: "Error type must be `unknown` or `any`.",
|
|
2043
|
-
suggestExplicitUnknown: "Use `unknown` instead
|
|
2078
|
+
suggestExplicitUnknown: "Use `unknown` instead to explicitly and safely assert the type is correct.",
|
|
2079
|
+
suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety."
|
|
2044
2080
|
},
|
|
2045
2081
|
schema: [
|
|
2046
2082
|
{
|
|
@@ -2063,6 +2099,22 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2063
2099
|
const { allowExplicitAny = true } = config;
|
|
2064
2100
|
const { couldBeObservable } = getTypeServices(context);
|
|
2065
2101
|
const sourceCode = context.sourceCode;
|
|
2102
|
+
function createReplacerFix(typeAnnotation, replaceWith) {
|
|
2103
|
+
return function fix(fixer) {
|
|
2104
|
+
return fixer.replaceText(typeAnnotation, `: ${replaceWith}`);
|
|
2105
|
+
};
|
|
2106
|
+
}
|
|
2107
|
+
function createInserterFix(param, annotateWith, { hasRestParams = false } = {}) {
|
|
2108
|
+
return function fix(fixer) {
|
|
2109
|
+
if (hasRestParams || isParenthesised(sourceCode, param)) {
|
|
2110
|
+
return fixer.insertTextAfter(param, `: ${annotateWith}`);
|
|
2111
|
+
}
|
|
2112
|
+
return [
|
|
2113
|
+
fixer.insertTextBefore(param, "("),
|
|
2114
|
+
fixer.insertTextAfter(param, `: ${annotateWith})`)
|
|
2115
|
+
];
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2066
2118
|
function checkCallback(callback) {
|
|
2067
2119
|
if (isArrowFunctionExpression(callback) || isFunctionExpression(callback)) {
|
|
2068
2120
|
const [param, ...restParams] = callback.params;
|
|
@@ -2075,61 +2127,51 @@ var noImplicitAnyCatchRule = ruleCreator({
|
|
|
2075
2127
|
typeAnnotation: { type }
|
|
2076
2128
|
} = typeAnnotation;
|
|
2077
2129
|
if (type === AST_NODE_TYPES5.TSAnyKeyword) {
|
|
2078
|
-
let fix2 = function(fixer) {
|
|
2079
|
-
return fixer.replaceText(typeAnnotation, ": unknown");
|
|
2080
|
-
};
|
|
2081
|
-
var fix = fix2;
|
|
2082
2130
|
if (allowExplicitAny) {
|
|
2083
2131
|
return;
|
|
2084
2132
|
}
|
|
2085
2133
|
context.report({
|
|
2086
|
-
fix: fix2,
|
|
2087
2134
|
messageId: "explicitAny",
|
|
2088
2135
|
node: param,
|
|
2089
2136
|
suggest: [
|
|
2090
2137
|
{
|
|
2091
2138
|
messageId: "suggestExplicitUnknown",
|
|
2092
|
-
fix:
|
|
2139
|
+
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2093
2140
|
}
|
|
2094
2141
|
]
|
|
2095
2142
|
});
|
|
2096
2143
|
} else if (type !== AST_NODE_TYPES5.TSUnknownKeyword) {
|
|
2097
|
-
let fix2 = function(fixer) {
|
|
2098
|
-
return fixer.replaceText(typeAnnotation, ": unknown");
|
|
2099
|
-
};
|
|
2100
|
-
var fix = fix2;
|
|
2101
2144
|
context.report({
|
|
2102
2145
|
messageId: "narrowed",
|
|
2103
2146
|
node: param,
|
|
2104
2147
|
suggest: [
|
|
2105
2148
|
{
|
|
2106
2149
|
messageId: "suggestExplicitUnknown",
|
|
2107
|
-
fix:
|
|
2108
|
-
}
|
|
2109
|
-
|
|
2150
|
+
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2151
|
+
},
|
|
2152
|
+
allowExplicitAny ? {
|
|
2153
|
+
messageId: "suggestExplicitAny",
|
|
2154
|
+
fix: createReplacerFix(typeAnnotation, "any")
|
|
2155
|
+
} : null
|
|
2156
|
+
].filter((x) => !!x)
|
|
2110
2157
|
});
|
|
2111
2158
|
}
|
|
2112
2159
|
} else {
|
|
2113
|
-
|
|
2114
|
-
if (isParenthesised(sourceCode, param) || restParams.length > 0) {
|
|
2115
|
-
return fixer.insertTextAfter(param, ": unknown");
|
|
2116
|
-
}
|
|
2117
|
-
return [
|
|
2118
|
-
fixer.insertTextBefore(param, "("),
|
|
2119
|
-
fixer.insertTextAfter(param, ": unknown)")
|
|
2120
|
-
];
|
|
2121
|
-
};
|
|
2122
|
-
var fix = fix2;
|
|
2160
|
+
const hasRestParams = restParams.length > 0;
|
|
2123
2161
|
context.report({
|
|
2124
|
-
fix:
|
|
2162
|
+
fix: allowExplicitAny ? createInserterFix(param, "any", { hasRestParams }) : void 0,
|
|
2125
2163
|
messageId: "implicitAny",
|
|
2126
2164
|
node: param,
|
|
2127
2165
|
suggest: [
|
|
2128
2166
|
{
|
|
2129
2167
|
messageId: "suggestExplicitUnknown",
|
|
2130
|
-
fix:
|
|
2131
|
-
}
|
|
2132
|
-
|
|
2168
|
+
fix: createInserterFix(param, "unknown", { hasRestParams })
|
|
2169
|
+
},
|
|
2170
|
+
allowExplicitAny ? {
|
|
2171
|
+
messageId: "suggestExplicitAny",
|
|
2172
|
+
fix: createInserterFix(param, "any", { hasRestParams })
|
|
2173
|
+
} : null
|
|
2174
|
+
].filter((x) => !!x)
|
|
2133
2175
|
});
|
|
2134
2176
|
}
|
|
2135
2177
|
}
|
|
@@ -2269,8 +2311,8 @@ var noInternalRule = ruleCreator({
|
|
|
2269
2311
|
// src/rules/no-misused-observables.ts
|
|
2270
2312
|
import { AST_NODE_TYPES as AST_NODE_TYPES6, ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
|
|
2271
2313
|
import { getFunctionHeadLocation, isFunction } from "@typescript-eslint/utils/ast-utils";
|
|
2272
|
-
import * as
|
|
2273
|
-
import
|
|
2314
|
+
import * as tsutils4 from "ts-api-utils";
|
|
2315
|
+
import ts5 from "typescript";
|
|
2274
2316
|
function parseChecksVoidReturn(checksVoidReturn) {
|
|
2275
2317
|
var _a, _b, _c, _d, _e, _f;
|
|
2276
2318
|
switch (checksVoidReturn) {
|
|
@@ -2566,8 +2608,8 @@ function voidFunctionArguments(checker, tsNode) {
|
|
|
2566
2608
|
}
|
|
2567
2609
|
const voidReturnIndices = /* @__PURE__ */ new Set();
|
|
2568
2610
|
const type = checker.getTypeAtLocation(tsNode.expression);
|
|
2569
|
-
for (const subType of
|
|
2570
|
-
const signatures =
|
|
2611
|
+
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2612
|
+
const signatures = ts5.isCallExpression(tsNode) ? subType.getCallSignatures() : subType.getConstructSignatures();
|
|
2571
2613
|
for (const signature of signatures) {
|
|
2572
2614
|
for (const [index, parameter] of signature.parameters.entries()) {
|
|
2573
2615
|
const type2 = checker.getTypeOfSymbolAtLocation(parameter, tsNode.expression);
|
|
@@ -2581,13 +2623,13 @@ function voidFunctionArguments(checker, tsNode) {
|
|
|
2581
2623
|
}
|
|
2582
2624
|
function isVoidReturningFunctionType(type) {
|
|
2583
2625
|
let hasVoidReturn = false;
|
|
2584
|
-
for (const subType of
|
|
2626
|
+
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2585
2627
|
for (const signature of subType.getCallSignatures()) {
|
|
2586
2628
|
const returnType = signature.getReturnType();
|
|
2587
2629
|
if (couldBeType(returnType, "Observable")) {
|
|
2588
2630
|
return false;
|
|
2589
2631
|
}
|
|
2590
|
-
hasVoidReturn || (hasVoidReturn =
|
|
2632
|
+
hasVoidReturn || (hasVoidReturn = tsutils4.isTypeFlagSet(returnType, ts5.TypeFlags.Void));
|
|
2591
2633
|
}
|
|
2592
2634
|
}
|
|
2593
2635
|
return hasVoidReturn;
|
|
@@ -2598,31 +2640,31 @@ function getHeritageTypes(checker, tsNode) {
|
|
|
2598
2640
|
}
|
|
2599
2641
|
function getMemberIfExists(type, memberName) {
|
|
2600
2642
|
var _a, _b;
|
|
2601
|
-
const escapedMemberName =
|
|
2643
|
+
const escapedMemberName = ts5.escapeLeadingUnderscores(memberName);
|
|
2602
2644
|
const symbolMemberMatch = (_b = (_a = type.getSymbol()) == null ? void 0 : _a.members) == null ? void 0 : _b.get(escapedMemberName);
|
|
2603
|
-
return symbolMemberMatch != null ? symbolMemberMatch :
|
|
2645
|
+
return symbolMemberMatch != null ? symbolMemberMatch : tsutils4.getPropertyOfType(type, escapedMemberName);
|
|
2604
2646
|
}
|
|
2605
2647
|
function isStaticMember(node) {
|
|
2606
2648
|
return (isMethodDefinition(node) || isPropertyDefinition(node) || isAccessorProperty(node)) && node.static;
|
|
2607
2649
|
}
|
|
2608
2650
|
function getPropertyContextualType(checker, tsNode) {
|
|
2609
|
-
if (
|
|
2651
|
+
if (ts5.isPropertyAssignment(tsNode)) {
|
|
2610
2652
|
return checker.getContextualType(tsNode.initializer);
|
|
2611
|
-
} else if (
|
|
2653
|
+
} else if (ts5.isShorthandPropertyAssignment(tsNode)) {
|
|
2612
2654
|
return checker.getContextualType(tsNode.name);
|
|
2613
|
-
} else if (
|
|
2614
|
-
if (
|
|
2655
|
+
} else if (ts5.isMethodDeclaration(tsNode)) {
|
|
2656
|
+
if (ts5.isComputedPropertyName(tsNode.name)) {
|
|
2615
2657
|
return;
|
|
2616
2658
|
}
|
|
2617
2659
|
const obj = tsNode.parent;
|
|
2618
|
-
if (!
|
|
2660
|
+
if (!ts5.isObjectLiteralExpression(obj)) {
|
|
2619
2661
|
return;
|
|
2620
2662
|
}
|
|
2621
2663
|
const objType = checker.getContextualType(obj);
|
|
2622
2664
|
if (objType == null) {
|
|
2623
2665
|
return;
|
|
2624
2666
|
}
|
|
2625
|
-
const propertySymbol = checker.getPropertyOfType(
|
|
2667
|
+
const propertySymbol = tsutils4.unionConstituents(objType).map((t) => checker.getPropertyOfType(t, tsNode.name.getText())).find((p) => p);
|
|
2626
2668
|
if (propertySymbol == null) {
|
|
2627
2669
|
return;
|
|
2628
2670
|
}
|
|
@@ -3085,8 +3127,6 @@ var noSubscribeInPipeRule = ruleCreator({
|
|
|
3085
3127
|
recommended: "recommended",
|
|
3086
3128
|
requiresTypeChecking: true
|
|
3087
3129
|
},
|
|
3088
|
-
fixable: void 0,
|
|
3089
|
-
hasSuggestions: false,
|
|
3090
3130
|
messages: {
|
|
3091
3131
|
forbidden: "Subscribe calls within pipe operators are forbidden."
|
|
3092
3132
|
},
|
|
@@ -3554,8 +3594,8 @@ var noUnsafeFirstRule = ruleCreator({
|
|
|
3554
3594
|
|
|
3555
3595
|
// src/rules/no-unsafe-subject-next.ts
|
|
3556
3596
|
import { ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
|
|
3557
|
-
import * as
|
|
3558
|
-
import
|
|
3597
|
+
import * as tsutils5 from "ts-api-utils";
|
|
3598
|
+
import ts6 from "typescript";
|
|
3559
3599
|
var noUnsafeSubjectNext = ruleCreator({
|
|
3560
3600
|
defaultOptions: [],
|
|
3561
3601
|
meta: {
|
|
@@ -3578,19 +3618,19 @@ var noUnsafeSubjectNext = ruleCreator({
|
|
|
3578
3618
|
[`CallExpression[callee.property.name='next']`]: (node) => {
|
|
3579
3619
|
if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
|
|
3580
3620
|
const type = getTypeAtLocation(node.callee.object);
|
|
3581
|
-
if (
|
|
3621
|
+
if (tsutils5.isTypeReference(type) && couldBeType(type, "Subject")) {
|
|
3582
3622
|
const [typeArg] = typeChecker.getTypeArguments(type);
|
|
3583
|
-
if (
|
|
3623
|
+
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Any)) {
|
|
3584
3624
|
return;
|
|
3585
3625
|
}
|
|
3586
|
-
if (
|
|
3626
|
+
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Unknown)) {
|
|
3587
3627
|
return;
|
|
3588
3628
|
}
|
|
3589
|
-
if (
|
|
3629
|
+
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Void)) {
|
|
3590
3630
|
return;
|
|
3591
3631
|
}
|
|
3592
|
-
if (
|
|
3593
|
-
(t) =>
|
|
3632
|
+
if (tsutils5.isUnionType(typeArg) && typeArg.types.some(
|
|
3633
|
+
(t) => tsutils5.isTypeFlagSet(t, ts6.TypeFlags.Void)
|
|
3594
3634
|
)) {
|
|
3595
3635
|
return;
|
|
3596
3636
|
}
|
|
@@ -4233,7 +4273,7 @@ var suffixSubjectsRule = ruleCreator({
|
|
|
4233
4273
|
|
|
4234
4274
|
// src/rules/throw-error.ts
|
|
4235
4275
|
import { ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
|
|
4236
|
-
import * as
|
|
4276
|
+
import * as tsutils6 from "ts-api-utils";
|
|
4237
4277
|
var defaultOptions19 = [];
|
|
4238
4278
|
var throwErrorRule = ruleCreator({
|
|
4239
4279
|
defaultOptions: defaultOptions19,
|
|
@@ -4277,10 +4317,10 @@ var throwErrorRule = ruleCreator({
|
|
|
4277
4317
|
const body = tsNode.body;
|
|
4278
4318
|
type = program.getTypeChecker().getTypeAtLocation(annotation != null ? annotation : body);
|
|
4279
4319
|
}
|
|
4280
|
-
if (allowThrowingAny &&
|
|
4320
|
+
if (allowThrowingAny && tsutils6.isIntrinsicAnyType(type)) {
|
|
4281
4321
|
return;
|
|
4282
4322
|
}
|
|
4283
|
-
if (allowThrowingUnknown &&
|
|
4323
|
+
if (allowThrowingUnknown && tsutils6.isIntrinsicUnknownType(type)) {
|
|
4284
4324
|
return;
|
|
4285
4325
|
}
|
|
4286
4326
|
if (couldBeType(type, /^Error$/)) {
|
|
@@ -4334,6 +4374,7 @@ var allRules = {
|
|
|
4334
4374
|
"no-ignored-default-value": noIgnoredDefaultValueRule,
|
|
4335
4375
|
"no-ignored-error": noIgnoredErrorRule,
|
|
4336
4376
|
"no-ignored-notifier": noIgnoredNotifierRule,
|
|
4377
|
+
"no-ignored-observable": noIgnoredObservableRule,
|
|
4337
4378
|
"no-ignored-replay-buffer": noIgnoredReplayBufferRule,
|
|
4338
4379
|
"no-ignored-subscribe": noIgnoredSubscribeRule,
|
|
4339
4380
|
"no-ignored-subscription": noIgnoredSubscriptionRule,
|
|
@@ -4377,8 +4418,9 @@ var plugin = {
|
|
|
4377
4418
|
var rxjsX = {
|
|
4378
4419
|
...plugin,
|
|
4379
4420
|
configs: {
|
|
4380
|
-
recommended: createRecommendedConfig(plugin),
|
|
4381
|
-
strict: createStrictConfig(plugin)
|
|
4421
|
+
"recommended": createRecommendedConfig(plugin),
|
|
4422
|
+
"strict": createStrictConfig(plugin),
|
|
4423
|
+
"recommended-legacy": createLegacyRecommendedConfig()
|
|
4382
4424
|
}
|
|
4383
4425
|
};
|
|
4384
4426
|
var index_default = rxjsX;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-rxjs-x",
|
|
3
3
|
"type": "commonjs",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.9.0",
|
|
5
5
|
"packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
|
|
6
6
|
"description": "Modern ESLint plugin for RxJS",
|
|
7
7
|
"author": "Jason Weinzierl <weinzierljason@gmail.com>",
|
|
@@ -58,11 +58,11 @@
|
|
|
58
58
|
"typecheck": "tsc --noEmit"
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@typescript-eslint/scope-manager": "^8.
|
|
62
|
-
"@typescript-eslint/utils": "^8.
|
|
61
|
+
"@typescript-eslint/scope-manager": "^8.32.0",
|
|
62
|
+
"@typescript-eslint/utils": "^8.32.0",
|
|
63
63
|
"common-tags": "^1.8.0",
|
|
64
64
|
"decamelize": "^5.0.1",
|
|
65
|
-
"ts-api-utils": "^2.
|
|
65
|
+
"ts-api-utils": "^2.1.0",
|
|
66
66
|
"tslib": "^2.1.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"@stylistic/eslint-plugin": "^5.7.1",
|
|
81
81
|
"@types/common-tags": "^1.8.4",
|
|
82
82
|
"@types/node": "~18.18.0",
|
|
83
|
-
"@typescript-eslint/rule-tester": "^8.
|
|
83
|
+
"@typescript-eslint/rule-tester": "^8.54.0",
|
|
84
84
|
"@typescript/vfs": "^1.6.2",
|
|
85
85
|
"@vitest/coverage-v8": "^3.2.4",
|
|
86
86
|
"@vitest/eslint-plugin": "^1.4.0",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
"rxjs": "^7.8.2",
|
|
97
97
|
"tsup": "8.5.0",
|
|
98
98
|
"typescript": "~5.9.3",
|
|
99
|
-
"typescript-eslint": "^8.
|
|
99
|
+
"typescript-eslint": "^8.54.0",
|
|
100
100
|
"vite": "^6.4.1",
|
|
101
101
|
"vitest": "^3.2.4"
|
|
102
102
|
},
|