eslint-plugin-rxjs-x 0.8.0 → 0.8.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/README.md +49 -47
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +160 -1
- package/dist/index.mjs +160 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -108,52 +108,54 @@ The package includes the following rules.
|
|
|
108
108
|
💭 Requires [type information](https://typescript-eslint.io/linting/typed-linting).\
|
|
109
109
|
❌ Deprecated.
|
|
110
110
|
|
|
111
|
-
| Name
|
|
112
|
-
|
|
|
113
|
-
| [ban-observables](docs/rules/ban-observables.md)
|
|
114
|
-
| [ban-operators](docs/rules/ban-operators.md)
|
|
115
|
-
| [finnish](docs/rules/finnish.md)
|
|
116
|
-
| [just](docs/rules/just.md)
|
|
117
|
-
| [macro](docs/rules/macro.md)
|
|
118
|
-
| [no-async-subscribe](docs/rules/no-async-subscribe.md)
|
|
119
|
-
| [no-compat](docs/rules/no-compat.md)
|
|
120
|
-
| [no-connectable](docs/rules/no-connectable.md)
|
|
121
|
-
| [no-create](docs/rules/no-create.md)
|
|
122
|
-
| [no-cyclic-action](docs/rules/no-cyclic-action.md)
|
|
123
|
-
| [no-explicit-generics](docs/rules/no-explicit-generics.md)
|
|
124
|
-
| [no-exposed-subjects](docs/rules/no-exposed-subjects.md)
|
|
125
|
-
| [no-finnish](docs/rules/no-finnish.md)
|
|
126
|
-
| [no-floating-observables](docs/rules/no-floating-observables.md)
|
|
127
|
-
| [no-ignored-default-value](docs/rules/no-ignored-default-value.md)
|
|
128
|
-
| [no-ignored-error](docs/rules/no-ignored-error.md)
|
|
129
|
-
| [no-ignored-notifier](docs/rules/no-ignored-notifier.md)
|
|
130
|
-
| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md)
|
|
131
|
-
| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md)
|
|
132
|
-
| [no-ignored-subscription](docs/rules/no-ignored-subscription.md)
|
|
133
|
-
| [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md)
|
|
134
|
-
| [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md)
|
|
135
|
-
| [no-index](docs/rules/no-index.md)
|
|
136
|
-
| [no-internal](docs/rules/no-internal.md)
|
|
137
|
-
| [no-misused-observables](docs/rules/no-misused-observables.md)
|
|
138
|
-
| [no-nested-subscribe](docs/rules/no-nested-subscribe.md)
|
|
139
|
-
| [no-redundant-notify](docs/rules/no-redundant-notify.md)
|
|
140
|
-
| [no-sharereplay](docs/rules/no-sharereplay.md)
|
|
141
|
-
| [no-
|
|
142
|
-
| [no-
|
|
143
|
-
| [no-subject-
|
|
144
|
-
| [no-
|
|
145
|
-
| [no-subscribe-
|
|
146
|
-
| [no-
|
|
147
|
-
| [no-
|
|
148
|
-
| [no-
|
|
149
|
-
| [no-
|
|
150
|
-
| [no-
|
|
151
|
-
| [no-unsafe-
|
|
152
|
-
| [no-unsafe-
|
|
153
|
-
| [no-unsafe-
|
|
154
|
-
| [
|
|
155
|
-
| [
|
|
156
|
-
| [
|
|
157
|
-
| [
|
|
111
|
+
| Name | Description | 💼 | 🔧 | 💡 | 💭 | ❌ |
|
|
112
|
+
| :------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------- | :--- | :- | :- | :- | :- |
|
|
113
|
+
| [ban-observables](docs/rules/ban-observables.md) | Disallow banned observable creators. | | | | | |
|
|
114
|
+
| [ban-operators](docs/rules/ban-operators.md) | Disallow banned operators. | | | | 💭 | |
|
|
115
|
+
| [finnish](docs/rules/finnish.md) | Enforce Finnish notation. | | | | 💭 | |
|
|
116
|
+
| [just](docs/rules/just.md) | Require the use of `just` instead of `of`. | | 🔧 | | | |
|
|
117
|
+
| [macro](docs/rules/macro.md) | Require the use of the RxJS Tools Babel macro. | | 🔧 | | | ❌ |
|
|
118
|
+
| [no-async-subscribe](docs/rules/no-async-subscribe.md) | Disallow passing `async` functions to `subscribe`. | ✅ 🔒 | | | 💭 | |
|
|
119
|
+
| [no-compat](docs/rules/no-compat.md) | Disallow the `rxjs-compat` package. | | | | | ❌ |
|
|
120
|
+
| [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | 💭 | |
|
|
121
|
+
| [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | ✅ 🔒 | | | 💭 | |
|
|
122
|
+
| [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | 💭 | |
|
|
123
|
+
| [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | | | | | |
|
|
124
|
+
| [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | 🔒 | | | 💭 | |
|
|
125
|
+
| [no-finnish](docs/rules/no-finnish.md) | Disallow Finnish notation. | | | | 💭 | |
|
|
126
|
+
| [no-floating-observables](docs/rules/no-floating-observables.md) | Require Observables to be handled appropriately. | 🔒 | | | 💭 | |
|
|
127
|
+
| [no-ignored-default-value](docs/rules/no-ignored-default-value.md) | Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value. | 🔒 | | | 💭 | |
|
|
128
|
+
| [no-ignored-error](docs/rules/no-ignored-error.md) | Disallow calling `subscribe` without specifying an error handler. | 🔒 | | | 💭 | |
|
|
129
|
+
| [no-ignored-notifier](docs/rules/no-ignored-notifier.md) | Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier. | ✅ 🔒 | | | 💭 | |
|
|
130
|
+
| [no-ignored-replay-buffer](docs/rules/no-ignored-replay-buffer.md) | Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size. | ✅ 🔒 | | | | |
|
|
131
|
+
| [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | 💭 | |
|
|
132
|
+
| [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | 💭 | |
|
|
133
|
+
| [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md) | Disallow ignoring the value within `takeWhile`. | ✅ 🔒 | | | | |
|
|
134
|
+
| [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError` operators. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
|
|
135
|
+
| [no-index](docs/rules/no-index.md) | Disallow importing index modules. | ✅ 🔒 | | | | |
|
|
136
|
+
| [no-internal](docs/rules/no-internal.md) | Disallow importing internal modules. | ✅ 🔒 | 🔧 | 💡 | | |
|
|
137
|
+
| [no-misused-observables](docs/rules/no-misused-observables.md) | Disallow Observables in places not designed to handle them. | 🔒 | | | 💭 | |
|
|
138
|
+
| [no-nested-subscribe](docs/rules/no-nested-subscribe.md) | Disallow calling `subscribe` within a `subscribe` callback. | ✅ 🔒 | | | 💭 | |
|
|
139
|
+
| [no-redundant-notify](docs/rules/no-redundant-notify.md) | Disallow sending redundant notifications from completed or errored observables. | ✅ 🔒 | | | 💭 | |
|
|
140
|
+
| [no-sharereplay](docs/rules/no-sharereplay.md) | Disallow unsafe `shareReplay` usage. | ✅ 🔒 | | | | |
|
|
141
|
+
| [no-sharereplay-before-takeuntil](docs/rules/no-sharereplay-before-takeuntil.md) | Disallow using `shareReplay({ refCount: false })` before `takeUntil`. | 🔒 | | | | |
|
|
142
|
+
| [no-subclass](docs/rules/no-subclass.md) | Disallow subclassing RxJS classes. | 🔒 | | | 💭 | |
|
|
143
|
+
| [no-subject-unsubscribe](docs/rules/no-subject-unsubscribe.md) | Disallow calling the `unsubscribe` method of subjects. | ✅ 🔒 | | | 💭 | |
|
|
144
|
+
| [no-subject-value](docs/rules/no-subject-value.md) | Disallow accessing the `value` property of a `BehaviorSubject` instance. | | | | 💭 | |
|
|
145
|
+
| [no-subscribe-handlers](docs/rules/no-subscribe-handlers.md) | Disallow passing handlers to `subscribe`. | | | | 💭 | |
|
|
146
|
+
| [no-subscribe-in-pipe](docs/rules/no-subscribe-in-pipe.md) | Disallow calling of `subscribe` within any RxJS operator inside a `pipe`. | ✅ 🔒 | | | 💭 | |
|
|
147
|
+
| [no-tap](docs/rules/no-tap.md) | Disallow the `tap` operator. | | | | | ❌ |
|
|
148
|
+
| [no-topromise](docs/rules/no-topromise.md) | Disallow use of the `toPromise` method. | ✅ 🔒 | | 💡 | 💭 | |
|
|
149
|
+
| [no-unbound-methods](docs/rules/no-unbound-methods.md) | Disallow passing unbound methods. | ✅ 🔒 | | | 💭 | |
|
|
150
|
+
| [no-unnecessary-collection](docs/rules/no-unnecessary-collection.md) | Disallow unnecessary usage of collection arguments with single values. | 🔒 | | | | |
|
|
151
|
+
| [no-unsafe-catch](docs/rules/no-unsafe-catch.md) | Disallow unsafe `catchError` usage in effects and epics. | | | | 💭 | |
|
|
152
|
+
| [no-unsafe-first](docs/rules/no-unsafe-first.md) | Disallow unsafe `first`/`take` usage in effects and epics. | | | | 💭 | |
|
|
153
|
+
| [no-unsafe-subject-next](docs/rules/no-unsafe-subject-next.md) | Disallow unsafe optional `next` calls. | ✅ 🔒 | | | 💭 | |
|
|
154
|
+
| [no-unsafe-switchmap](docs/rules/no-unsafe-switchmap.md) | Disallow unsafe `switchMap` usage in effects and epics. | | | | 💭 | |
|
|
155
|
+
| [no-unsafe-takeuntil](docs/rules/no-unsafe-takeuntil.md) | Disallow applying operators after `takeUntil`. | ✅ 🔒 | | | 💭 | |
|
|
156
|
+
| [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
|
|
157
|
+
| [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | ✅ 🔒 | 🔧 | 💡 | | |
|
|
158
|
+
| [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | 💭 | |
|
|
159
|
+
| [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError` or `Subject.error`. | ✅ 🔒 | | | 💭 | |
|
|
158
160
|
|
|
159
161
|
<!-- end auto-generated rules list -->
|
package/dist/index.d.mts
CHANGED
|
@@ -159,6 +159,10 @@ declare const allRules: {
|
|
|
159
159
|
description: "Disallow unsafe `shareReplay` usage.";
|
|
160
160
|
recommended: "recommended";
|
|
161
161
|
}, TSESLint.RuleListener>;
|
|
162
|
+
'no-sharereplay-before-takeuntil': TSESLint.RuleModule<"forbidden", [], {
|
|
163
|
+
description: "Disallow using `shareReplay({ refCount: false })` before `takeUntil`.";
|
|
164
|
+
recommended: "strict";
|
|
165
|
+
}, TSESLint.RuleListener>;
|
|
162
166
|
'no-subclass': TSESLint.RuleModule<"forbidden", [], {
|
|
163
167
|
description: "Disallow subclassing RxJS classes.";
|
|
164
168
|
recommended: "strict";
|
|
@@ -197,6 +201,11 @@ declare const allRules: {
|
|
|
197
201
|
recommended: "recommended";
|
|
198
202
|
requiresTypeChecking: true;
|
|
199
203
|
}, TSESLint.RuleListener>;
|
|
204
|
+
'no-unnecessary-collection': TSESLint.RuleModule<"forbidden", [], {
|
|
205
|
+
description: "Disallow unnecessary usage of collection arguments with single values.";
|
|
206
|
+
recommended: "strict";
|
|
207
|
+
requiresTypeChecking: false;
|
|
208
|
+
}, TSESLint.RuleListener>;
|
|
200
209
|
'no-unsafe-catch': TSESLint.RuleModule<"forbidden", readonly {
|
|
201
210
|
observable?: string;
|
|
202
211
|
}[], {
|
|
@@ -319,12 +328,14 @@ declare const rxjsX: {
|
|
|
319
328
|
'rxjs-x/no-misused-observables': "error";
|
|
320
329
|
'rxjs-x/no-nested-subscribe': "error";
|
|
321
330
|
'rxjs-x/no-redundant-notify': "error";
|
|
331
|
+
'rxjs-x/no-sharereplay-before-takeuntil': "error";
|
|
322
332
|
'rxjs-x/no-sharereplay': "error";
|
|
323
333
|
'rxjs-x/no-subclass': "error";
|
|
324
334
|
'rxjs-x/no-subject-unsubscribe': "error";
|
|
325
335
|
'rxjs-x/no-subscribe-in-pipe': "error";
|
|
326
336
|
'rxjs-x/no-topromise': "error";
|
|
327
337
|
'rxjs-x/no-unbound-methods': "error";
|
|
338
|
+
'rxjs-x/no-unnecessary-collection': "error";
|
|
328
339
|
'rxjs-x/no-unsafe-subject-next': "error";
|
|
329
340
|
'rxjs-x/no-unsafe-takeuntil': "error";
|
|
330
341
|
'rxjs-x/prefer-observer': "error";
|
package/dist/index.d.ts
CHANGED
|
@@ -159,6 +159,10 @@ declare const allRules: {
|
|
|
159
159
|
description: "Disallow unsafe `shareReplay` usage.";
|
|
160
160
|
recommended: "recommended";
|
|
161
161
|
}, TSESLint.RuleListener>;
|
|
162
|
+
'no-sharereplay-before-takeuntil': TSESLint.RuleModule<"forbidden", [], {
|
|
163
|
+
description: "Disallow using `shareReplay({ refCount: false })` before `takeUntil`.";
|
|
164
|
+
recommended: "strict";
|
|
165
|
+
}, TSESLint.RuleListener>;
|
|
162
166
|
'no-subclass': TSESLint.RuleModule<"forbidden", [], {
|
|
163
167
|
description: "Disallow subclassing RxJS classes.";
|
|
164
168
|
recommended: "strict";
|
|
@@ -197,6 +201,11 @@ declare const allRules: {
|
|
|
197
201
|
recommended: "recommended";
|
|
198
202
|
requiresTypeChecking: true;
|
|
199
203
|
}, TSESLint.RuleListener>;
|
|
204
|
+
'no-unnecessary-collection': TSESLint.RuleModule<"forbidden", [], {
|
|
205
|
+
description: "Disallow unnecessary usage of collection arguments with single values.";
|
|
206
|
+
recommended: "strict";
|
|
207
|
+
requiresTypeChecking: false;
|
|
208
|
+
}, TSESLint.RuleListener>;
|
|
200
209
|
'no-unsafe-catch': TSESLint.RuleModule<"forbidden", readonly {
|
|
201
210
|
observable?: string;
|
|
202
211
|
}[], {
|
|
@@ -319,12 +328,14 @@ declare const rxjsX: {
|
|
|
319
328
|
'rxjs-x/no-misused-observables': "error";
|
|
320
329
|
'rxjs-x/no-nested-subscribe': "error";
|
|
321
330
|
'rxjs-x/no-redundant-notify': "error";
|
|
331
|
+
'rxjs-x/no-sharereplay-before-takeuntil': "error";
|
|
322
332
|
'rxjs-x/no-sharereplay': "error";
|
|
323
333
|
'rxjs-x/no-subclass': "error";
|
|
324
334
|
'rxjs-x/no-subject-unsubscribe': "error";
|
|
325
335
|
'rxjs-x/no-subscribe-in-pipe': "error";
|
|
326
336
|
'rxjs-x/no-topromise': "error";
|
|
327
337
|
'rxjs-x/no-unbound-methods': "error";
|
|
338
|
+
'rxjs-x/no-unnecessary-collection': "error";
|
|
328
339
|
'rxjs-x/no-unsafe-subject-next': "error";
|
|
329
340
|
'rxjs-x/no-unsafe-takeuntil': "error";
|
|
330
341
|
'rxjs-x/prefer-observer': "error";
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
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.8.
|
|
3
|
+
var version = "0.8.1";
|
|
4
4
|
|
|
5
5
|
// src/configs/recommended.ts
|
|
6
6
|
var createRecommendedConfig = (plugin2) => ({
|
|
@@ -58,12 +58,14 @@ var createStrictConfig = (plugin2) => ({
|
|
|
58
58
|
"rxjs-x/no-misused-observables": "error",
|
|
59
59
|
"rxjs-x/no-nested-subscribe": "error",
|
|
60
60
|
"rxjs-x/no-redundant-notify": "error",
|
|
61
|
+
"rxjs-x/no-sharereplay-before-takeuntil": "error",
|
|
61
62
|
"rxjs-x/no-sharereplay": "error",
|
|
62
63
|
"rxjs-x/no-subclass": "error",
|
|
63
64
|
"rxjs-x/no-subject-unsubscribe": "error",
|
|
64
65
|
"rxjs-x/no-subscribe-in-pipe": "error",
|
|
65
66
|
"rxjs-x/no-topromise": "error",
|
|
66
67
|
"rxjs-x/no-unbound-methods": "error",
|
|
68
|
+
"rxjs-x/no-unnecessary-collection": "error",
|
|
67
69
|
"rxjs-x/no-unsafe-subject-next": "error",
|
|
68
70
|
"rxjs-x/no-unsafe-takeuntil": "error",
|
|
69
71
|
"rxjs-x/prefer-observer": "error",
|
|
@@ -403,6 +405,14 @@ var SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
|
403
405
|
"combineLatest",
|
|
404
406
|
"forkJoin"
|
|
405
407
|
];
|
|
408
|
+
var MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
409
|
+
"combineLatest",
|
|
410
|
+
"forkJoin",
|
|
411
|
+
"merge",
|
|
412
|
+
"zip",
|
|
413
|
+
"concat",
|
|
414
|
+
"race"
|
|
415
|
+
];
|
|
406
416
|
var DEFAULT_UNBOUND_ALLOWED_TYPES = [
|
|
407
417
|
"Signal"
|
|
408
418
|
];
|
|
@@ -2825,6 +2835,65 @@ var noSharereplayRule = ruleCreator({
|
|
|
2825
2835
|
}
|
|
2826
2836
|
});
|
|
2827
2837
|
|
|
2838
|
+
// src/rules/no-sharereplay-before-takeuntil.ts
|
|
2839
|
+
var noSharereplayBeforeTakeuntilRule = ruleCreator({
|
|
2840
|
+
defaultOptions: [],
|
|
2841
|
+
meta: {
|
|
2842
|
+
docs: {
|
|
2843
|
+
description: "Disallow using `shareReplay({ refCount: false })` before `takeUntil`.",
|
|
2844
|
+
recommended: "strict"
|
|
2845
|
+
},
|
|
2846
|
+
messages: {
|
|
2847
|
+
forbidden: "shareReplay before takeUntil is forbidden unless 'refCount: true' is specified."
|
|
2848
|
+
},
|
|
2849
|
+
schema: [],
|
|
2850
|
+
type: "problem"
|
|
2851
|
+
},
|
|
2852
|
+
name: "no-sharereplay-before-takeuntil",
|
|
2853
|
+
create: (context) => {
|
|
2854
|
+
function checkCallExpression(node) {
|
|
2855
|
+
const pipeCallExpression = node.parent;
|
|
2856
|
+
if (!pipeCallExpression.arguments || !isMemberExpression(pipeCallExpression.callee) || !isIdentifier(pipeCallExpression.callee.property) || pipeCallExpression.callee.property.name !== "pipe") {
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
const { isOrderValid, operatorNode: takeUntilNode } = findIsLastOperatorOrderValid(
|
|
2860
|
+
pipeCallExpression,
|
|
2861
|
+
/^takeUntil$/,
|
|
2862
|
+
DEFAULT_VALID_POST_COMPLETION_OPERATORS
|
|
2863
|
+
);
|
|
2864
|
+
if (!isOrderValid || !takeUntilNode) {
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
if (takeUntilNode.range[0] < node.range[0]) {
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
const shareReplayConfig = node.arguments[0];
|
|
2871
|
+
if (!shareReplayConfig || !isObjectExpression(shareReplayConfig)) {
|
|
2872
|
+
context.report({
|
|
2873
|
+
messageId: "forbidden",
|
|
2874
|
+
node: node.callee
|
|
2875
|
+
});
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
const refCountElement = shareReplayConfig.properties.filter(isProperty).find((prop) => isIdentifier(prop.key) && prop.key.name === "refCount");
|
|
2879
|
+
if (!refCountElement || isLiteral(refCountElement.value) && refCountElement.value.value === false) {
|
|
2880
|
+
context.report({
|
|
2881
|
+
messageId: "forbidden",
|
|
2882
|
+
node: node.callee
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return {
|
|
2887
|
+
'CallExpression[callee.name="shareReplay"]': (node) => {
|
|
2888
|
+
checkCallExpression(node);
|
|
2889
|
+
},
|
|
2890
|
+
'CallExpression[callee.property.name="shareReplay"]': (node) => {
|
|
2891
|
+
checkCallExpression(node);
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
|
|
2828
2897
|
// src/rules/no-subclass.ts
|
|
2829
2898
|
var noSubclassRule = ruleCreator({
|
|
2830
2899
|
defaultOptions: [],
|
|
@@ -3235,6 +3304,94 @@ var noUnboundMethodsRule = ruleCreator({
|
|
|
3235
3304
|
}
|
|
3236
3305
|
});
|
|
3237
3306
|
|
|
3307
|
+
// src/rules/no-unnecessary-collection.ts
|
|
3308
|
+
var noUnnecessaryCollectionRule = ruleCreator({
|
|
3309
|
+
defaultOptions: [],
|
|
3310
|
+
meta: {
|
|
3311
|
+
docs: {
|
|
3312
|
+
description: "Disallow unnecessary usage of collection arguments with single values.",
|
|
3313
|
+
recommended: "strict",
|
|
3314
|
+
requiresTypeChecking: false
|
|
3315
|
+
},
|
|
3316
|
+
messages: {
|
|
3317
|
+
forbidden: "Unnecessary {{operator}} with {{inputType}}. Use the observable directly instead."
|
|
3318
|
+
},
|
|
3319
|
+
schema: [],
|
|
3320
|
+
type: "suggestion"
|
|
3321
|
+
},
|
|
3322
|
+
name: "no-unnecessary-collection",
|
|
3323
|
+
create: (context) => {
|
|
3324
|
+
const { couldBeType: couldBeType2, couldBeObservable } = getTypeServices(context);
|
|
3325
|
+
function couldBeFromRxjs(node, operatorName) {
|
|
3326
|
+
return couldBeType2(node, operatorName, { name: /[/\\]rxjs[/\\]/ });
|
|
3327
|
+
}
|
|
3328
|
+
function checkCallExpression(node, operatorName) {
|
|
3329
|
+
const args = node.arguments;
|
|
3330
|
+
if (args.length === 0) {
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
const firstArg = args[0];
|
|
3334
|
+
if (isArrayExpression(firstArg)) {
|
|
3335
|
+
const nonNullElements = firstArg.elements.filter((element) => element !== null);
|
|
3336
|
+
if (nonNullElements.length === 1 && couldBeObservable(nonNullElements[0])) {
|
|
3337
|
+
context.report({
|
|
3338
|
+
messageId: "forbidden",
|
|
3339
|
+
node: node.callee,
|
|
3340
|
+
data: {
|
|
3341
|
+
operator: operatorName,
|
|
3342
|
+
inputType: "single-valued array"
|
|
3343
|
+
}
|
|
3344
|
+
});
|
|
3345
|
+
}
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
if (isObjectExpression(firstArg) && SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS.includes(operatorName)) {
|
|
3349
|
+
if (firstArg.properties.length === 1 && isProperty(firstArg.properties[0])) {
|
|
3350
|
+
const property = firstArg.properties[0];
|
|
3351
|
+
if (property.value && couldBeObservable(property.value)) {
|
|
3352
|
+
context.report({
|
|
3353
|
+
messageId: "forbidden",
|
|
3354
|
+
node: node.callee,
|
|
3355
|
+
data: {
|
|
3356
|
+
operator: operatorName,
|
|
3357
|
+
inputType: "single-property object"
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
if (args.length === 1 && couldBeObservable(firstArg)) {
|
|
3365
|
+
context.report({
|
|
3366
|
+
messageId: "forbidden",
|
|
3367
|
+
node: node.callee,
|
|
3368
|
+
data: {
|
|
3369
|
+
operator: operatorName,
|
|
3370
|
+
inputType: "single argument"
|
|
3371
|
+
}
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
const callExpressionVisitors = {};
|
|
3376
|
+
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3377
|
+
callExpressionVisitors[`CallExpression[callee.name="${operator}"]`] = (node) => {
|
|
3378
|
+
if (couldBeFromRxjs(node.callee, operator)) {
|
|
3379
|
+
checkCallExpression(node, operator);
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3384
|
+
callExpressionVisitors[`CallExpression[callee.type="MemberExpression"][callee.property.name="${operator}"]`] = (node) => {
|
|
3385
|
+
const memberExpr = node.callee;
|
|
3386
|
+
if (couldBeFromRxjs(memberExpr.property, operator)) {
|
|
3387
|
+
checkCallExpression(node, operator);
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
return callExpressionVisitors;
|
|
3392
|
+
}
|
|
3393
|
+
});
|
|
3394
|
+
|
|
3238
3395
|
// src/rules/no-unsafe-catch.ts
|
|
3239
3396
|
|
|
3240
3397
|
var defaultOptions12 = [];
|
|
@@ -4158,6 +4315,7 @@ var allRules = {
|
|
|
4158
4315
|
"no-nested-subscribe": noNestedSubscribeRule,
|
|
4159
4316
|
"no-redundant-notify": noRedundantNotifyRule,
|
|
4160
4317
|
"no-sharereplay": noSharereplayRule,
|
|
4318
|
+
"no-sharereplay-before-takeuntil": noSharereplayBeforeTakeuntilRule,
|
|
4161
4319
|
"no-subclass": noSubclassRule,
|
|
4162
4320
|
"no-subject-unsubscribe": noSubjectUnsubscribeRule,
|
|
4163
4321
|
"no-subject-value": noSubjectValueRule,
|
|
@@ -4166,6 +4324,7 @@ var allRules = {
|
|
|
4166
4324
|
"no-tap": noTapRule,
|
|
4167
4325
|
"no-topromise": noTopromiseRule,
|
|
4168
4326
|
"no-unbound-methods": noUnboundMethodsRule,
|
|
4327
|
+
"no-unnecessary-collection": noUnnecessaryCollectionRule,
|
|
4169
4328
|
"no-unsafe-catch": noUnsafeCatchRule,
|
|
4170
4329
|
"no-unsafe-first": noUnsafeFirstRule,
|
|
4171
4330
|
"no-unsafe-subject-next": noUnsafeSubjectNext,
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var name = "eslint-plugin-rxjs-x";
|
|
3
|
-
var version = "0.8.
|
|
3
|
+
var version = "0.8.1";
|
|
4
4
|
|
|
5
5
|
// src/configs/recommended.ts
|
|
6
6
|
var createRecommendedConfig = (plugin2) => ({
|
|
@@ -58,12 +58,14 @@ var createStrictConfig = (plugin2) => ({
|
|
|
58
58
|
"rxjs-x/no-misused-observables": "error",
|
|
59
59
|
"rxjs-x/no-nested-subscribe": "error",
|
|
60
60
|
"rxjs-x/no-redundant-notify": "error",
|
|
61
|
+
"rxjs-x/no-sharereplay-before-takeuntil": "error",
|
|
61
62
|
"rxjs-x/no-sharereplay": "error",
|
|
62
63
|
"rxjs-x/no-subclass": "error",
|
|
63
64
|
"rxjs-x/no-subject-unsubscribe": "error",
|
|
64
65
|
"rxjs-x/no-subscribe-in-pipe": "error",
|
|
65
66
|
"rxjs-x/no-topromise": "error",
|
|
66
67
|
"rxjs-x/no-unbound-methods": "error",
|
|
68
|
+
"rxjs-x/no-unnecessary-collection": "error",
|
|
67
69
|
"rxjs-x/no-unsafe-subject-next": "error",
|
|
68
70
|
"rxjs-x/no-unsafe-takeuntil": "error",
|
|
69
71
|
"rxjs-x/prefer-observer": "error",
|
|
@@ -403,6 +405,14 @@ var SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
|
403
405
|
"combineLatest",
|
|
404
406
|
"forkJoin"
|
|
405
407
|
];
|
|
408
|
+
var MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
409
|
+
"combineLatest",
|
|
410
|
+
"forkJoin",
|
|
411
|
+
"merge",
|
|
412
|
+
"zip",
|
|
413
|
+
"concat",
|
|
414
|
+
"race"
|
|
415
|
+
];
|
|
406
416
|
var DEFAULT_UNBOUND_ALLOWED_TYPES = [
|
|
407
417
|
"Signal"
|
|
408
418
|
];
|
|
@@ -2825,6 +2835,65 @@ var noSharereplayRule = ruleCreator({
|
|
|
2825
2835
|
}
|
|
2826
2836
|
});
|
|
2827
2837
|
|
|
2838
|
+
// src/rules/no-sharereplay-before-takeuntil.ts
|
|
2839
|
+
var noSharereplayBeforeTakeuntilRule = ruleCreator({
|
|
2840
|
+
defaultOptions: [],
|
|
2841
|
+
meta: {
|
|
2842
|
+
docs: {
|
|
2843
|
+
description: "Disallow using `shareReplay({ refCount: false })` before `takeUntil`.",
|
|
2844
|
+
recommended: "strict"
|
|
2845
|
+
},
|
|
2846
|
+
messages: {
|
|
2847
|
+
forbidden: "shareReplay before takeUntil is forbidden unless 'refCount: true' is specified."
|
|
2848
|
+
},
|
|
2849
|
+
schema: [],
|
|
2850
|
+
type: "problem"
|
|
2851
|
+
},
|
|
2852
|
+
name: "no-sharereplay-before-takeuntil",
|
|
2853
|
+
create: (context) => {
|
|
2854
|
+
function checkCallExpression(node) {
|
|
2855
|
+
const pipeCallExpression = node.parent;
|
|
2856
|
+
if (!pipeCallExpression.arguments || !isMemberExpression(pipeCallExpression.callee) || !isIdentifier(pipeCallExpression.callee.property) || pipeCallExpression.callee.property.name !== "pipe") {
|
|
2857
|
+
return;
|
|
2858
|
+
}
|
|
2859
|
+
const { isOrderValid, operatorNode: takeUntilNode } = findIsLastOperatorOrderValid(
|
|
2860
|
+
pipeCallExpression,
|
|
2861
|
+
/^takeUntil$/,
|
|
2862
|
+
DEFAULT_VALID_POST_COMPLETION_OPERATORS
|
|
2863
|
+
);
|
|
2864
|
+
if (!isOrderValid || !takeUntilNode) {
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
if (takeUntilNode.range[0] < node.range[0]) {
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
const shareReplayConfig = node.arguments[0];
|
|
2871
|
+
if (!shareReplayConfig || !isObjectExpression(shareReplayConfig)) {
|
|
2872
|
+
context.report({
|
|
2873
|
+
messageId: "forbidden",
|
|
2874
|
+
node: node.callee
|
|
2875
|
+
});
|
|
2876
|
+
return;
|
|
2877
|
+
}
|
|
2878
|
+
const refCountElement = shareReplayConfig.properties.filter(isProperty).find((prop) => isIdentifier(prop.key) && prop.key.name === "refCount");
|
|
2879
|
+
if (!refCountElement || isLiteral(refCountElement.value) && refCountElement.value.value === false) {
|
|
2880
|
+
context.report({
|
|
2881
|
+
messageId: "forbidden",
|
|
2882
|
+
node: node.callee
|
|
2883
|
+
});
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
return {
|
|
2887
|
+
'CallExpression[callee.name="shareReplay"]': (node) => {
|
|
2888
|
+
checkCallExpression(node);
|
|
2889
|
+
},
|
|
2890
|
+
'CallExpression[callee.property.name="shareReplay"]': (node) => {
|
|
2891
|
+
checkCallExpression(node);
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2894
|
+
}
|
|
2895
|
+
});
|
|
2896
|
+
|
|
2828
2897
|
// src/rules/no-subclass.ts
|
|
2829
2898
|
var noSubclassRule = ruleCreator({
|
|
2830
2899
|
defaultOptions: [],
|
|
@@ -3235,6 +3304,94 @@ var noUnboundMethodsRule = ruleCreator({
|
|
|
3235
3304
|
}
|
|
3236
3305
|
});
|
|
3237
3306
|
|
|
3307
|
+
// src/rules/no-unnecessary-collection.ts
|
|
3308
|
+
var noUnnecessaryCollectionRule = ruleCreator({
|
|
3309
|
+
defaultOptions: [],
|
|
3310
|
+
meta: {
|
|
3311
|
+
docs: {
|
|
3312
|
+
description: "Disallow unnecessary usage of collection arguments with single values.",
|
|
3313
|
+
recommended: "strict",
|
|
3314
|
+
requiresTypeChecking: false
|
|
3315
|
+
},
|
|
3316
|
+
messages: {
|
|
3317
|
+
forbidden: "Unnecessary {{operator}} with {{inputType}}. Use the observable directly instead."
|
|
3318
|
+
},
|
|
3319
|
+
schema: [],
|
|
3320
|
+
type: "suggestion"
|
|
3321
|
+
},
|
|
3322
|
+
name: "no-unnecessary-collection",
|
|
3323
|
+
create: (context) => {
|
|
3324
|
+
const { couldBeType: couldBeType2, couldBeObservable } = getTypeServices(context);
|
|
3325
|
+
function couldBeFromRxjs(node, operatorName) {
|
|
3326
|
+
return couldBeType2(node, operatorName, { name: /[/\\]rxjs[/\\]/ });
|
|
3327
|
+
}
|
|
3328
|
+
function checkCallExpression(node, operatorName) {
|
|
3329
|
+
const args = node.arguments;
|
|
3330
|
+
if (args.length === 0) {
|
|
3331
|
+
return;
|
|
3332
|
+
}
|
|
3333
|
+
const firstArg = args[0];
|
|
3334
|
+
if (isArrayExpression(firstArg)) {
|
|
3335
|
+
const nonNullElements = firstArg.elements.filter((element) => element !== null);
|
|
3336
|
+
if (nonNullElements.length === 1 && couldBeObservable(nonNullElements[0])) {
|
|
3337
|
+
context.report({
|
|
3338
|
+
messageId: "forbidden",
|
|
3339
|
+
node: node.callee,
|
|
3340
|
+
data: {
|
|
3341
|
+
operator: operatorName,
|
|
3342
|
+
inputType: "single-valued array"
|
|
3343
|
+
}
|
|
3344
|
+
});
|
|
3345
|
+
}
|
|
3346
|
+
return;
|
|
3347
|
+
}
|
|
3348
|
+
if (isObjectExpression(firstArg) && SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS.includes(operatorName)) {
|
|
3349
|
+
if (firstArg.properties.length === 1 && isProperty(firstArg.properties[0])) {
|
|
3350
|
+
const property = firstArg.properties[0];
|
|
3351
|
+
if (property.value && couldBeObservable(property.value)) {
|
|
3352
|
+
context.report({
|
|
3353
|
+
messageId: "forbidden",
|
|
3354
|
+
node: node.callee,
|
|
3355
|
+
data: {
|
|
3356
|
+
operator: operatorName,
|
|
3357
|
+
inputType: "single-property object"
|
|
3358
|
+
}
|
|
3359
|
+
});
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return;
|
|
3363
|
+
}
|
|
3364
|
+
if (args.length === 1 && couldBeObservable(firstArg)) {
|
|
3365
|
+
context.report({
|
|
3366
|
+
messageId: "forbidden",
|
|
3367
|
+
node: node.callee,
|
|
3368
|
+
data: {
|
|
3369
|
+
operator: operatorName,
|
|
3370
|
+
inputType: "single argument"
|
|
3371
|
+
}
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
const callExpressionVisitors = {};
|
|
3376
|
+
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3377
|
+
callExpressionVisitors[`CallExpression[callee.name="${operator}"]`] = (node) => {
|
|
3378
|
+
if (couldBeFromRxjs(node.callee, operator)) {
|
|
3379
|
+
checkCallExpression(node, operator);
|
|
3380
|
+
}
|
|
3381
|
+
};
|
|
3382
|
+
}
|
|
3383
|
+
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3384
|
+
callExpressionVisitors[`CallExpression[callee.type="MemberExpression"][callee.property.name="${operator}"]`] = (node) => {
|
|
3385
|
+
const memberExpr = node.callee;
|
|
3386
|
+
if (couldBeFromRxjs(memberExpr.property, operator)) {
|
|
3387
|
+
checkCallExpression(node, operator);
|
|
3388
|
+
}
|
|
3389
|
+
};
|
|
3390
|
+
}
|
|
3391
|
+
return callExpressionVisitors;
|
|
3392
|
+
}
|
|
3393
|
+
});
|
|
3394
|
+
|
|
3238
3395
|
// src/rules/no-unsafe-catch.ts
|
|
3239
3396
|
import { stripIndent as stripIndent5 } from "common-tags";
|
|
3240
3397
|
var defaultOptions12 = [];
|
|
@@ -4158,6 +4315,7 @@ var allRules = {
|
|
|
4158
4315
|
"no-nested-subscribe": noNestedSubscribeRule,
|
|
4159
4316
|
"no-redundant-notify": noRedundantNotifyRule,
|
|
4160
4317
|
"no-sharereplay": noSharereplayRule,
|
|
4318
|
+
"no-sharereplay-before-takeuntil": noSharereplayBeforeTakeuntilRule,
|
|
4161
4319
|
"no-subclass": noSubclassRule,
|
|
4162
4320
|
"no-subject-unsubscribe": noSubjectUnsubscribeRule,
|
|
4163
4321
|
"no-subject-value": noSubjectValueRule,
|
|
@@ -4166,6 +4324,7 @@ var allRules = {
|
|
|
4166
4324
|
"no-tap": noTapRule,
|
|
4167
4325
|
"no-topromise": noTopromiseRule,
|
|
4168
4326
|
"no-unbound-methods": noUnboundMethodsRule,
|
|
4327
|
+
"no-unnecessary-collection": noUnnecessaryCollectionRule,
|
|
4169
4328
|
"no-unsafe-catch": noUnsafeCatchRule,
|
|
4170
4329
|
"no-unsafe-first": noUnsafeFirstRule,
|
|
4171
4330
|
"no-unsafe-subject-next": noUnsafeSubjectNext,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eslint-plugin-rxjs-x",
|
|
3
3
|
"type": "commonjs",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.1",
|
|
5
5
|
"packageManager": "yarn@4.10.3+sha512.c38cafb5c7bb273f3926d04e55e1d8c9dfa7d9c3ea1f36a4868fa028b9e5f72298f0b7f401ad5eb921749eb012eb1c3bb74bf7503df3ee43fd600d14a018266f",
|
|
6
6
|
"description": "ESLint v9+ plugin for RxJS",
|
|
7
7
|
"author": "Jason Weinzierl <weinzierljason@gmail.com>",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"@types/common-tags": "^1.8.4",
|
|
79
79
|
"@types/node": "~18.18.0",
|
|
80
80
|
"@typescript-eslint/rule-tester": "^8.46.2",
|
|
81
|
-
"@typescript/vfs": "^1.6.
|
|
81
|
+
"@typescript/vfs": "^1.6.2",
|
|
82
82
|
"@vitest/coverage-v8": "^3.2.4",
|
|
83
83
|
"@vitest/eslint-plugin": "^1.4.0",
|
|
84
84
|
"bumpp": "^10.3.1",
|