eslint-plugin-rxjs-x 0.9.4 → 1.0.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 +60 -104
- package/dist/index.d.ts +346 -385
- package/dist/index.js +3329 -4370
- package/package.json +34 -39
- package/dist/index.d.mts +0 -393
- package/dist/index.mjs +0 -4576
package/dist/index.mjs
DELETED
|
@@ -1,4576 +0,0 @@
|
|
|
1
|
-
// package.json
|
|
2
|
-
var name = "eslint-plugin-rxjs-x";
|
|
3
|
-
var version = "0.9.4";
|
|
4
|
-
|
|
5
|
-
// src/configs/recommended.ts
|
|
6
|
-
var createRecommendedConfig = (plugin2) => ({
|
|
7
|
-
...baseConfig,
|
|
8
|
-
name: "rxjs-x/recommended",
|
|
9
|
-
plugins: {
|
|
10
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- "A type annotation is necessary."
|
|
11
|
-
"rxjs-x": plugin2
|
|
12
|
-
}
|
|
13
|
-
});
|
|
14
|
-
var createLegacyRecommendedConfig = () => ({
|
|
15
|
-
...baseConfig,
|
|
16
|
-
plugins: ["rxjs-x"]
|
|
17
|
-
});
|
|
18
|
-
var baseConfig = {
|
|
19
|
-
rules: {
|
|
20
|
-
"rxjs-x/no-async-subscribe": "error",
|
|
21
|
-
"rxjs-x/no-create": "error",
|
|
22
|
-
"rxjs-x/no-ignored-notifier": "error",
|
|
23
|
-
"rxjs-x/no-ignored-replay-buffer": "error",
|
|
24
|
-
"rxjs-x/no-ignored-takewhile-value": "error",
|
|
25
|
-
"rxjs-x/no-implicit-any-catch": "error",
|
|
26
|
-
"rxjs-x/no-index": "error",
|
|
27
|
-
"rxjs-x/no-internal": "error",
|
|
28
|
-
"rxjs-x/no-nested-subscribe": "error",
|
|
29
|
-
"rxjs-x/no-redundant-notify": "error",
|
|
30
|
-
"rxjs-x/no-sharereplay": "error",
|
|
31
|
-
"rxjs-x/no-subject-unsubscribe": "error",
|
|
32
|
-
"rxjs-x/no-subscribe-in-pipe": "error",
|
|
33
|
-
"rxjs-x/no-topromise": "error",
|
|
34
|
-
"rxjs-x/no-unbound-methods": "error",
|
|
35
|
-
"rxjs-x/no-unsafe-subject-next": "error",
|
|
36
|
-
"rxjs-x/no-unsafe-takeuntil": "error",
|
|
37
|
-
"rxjs-x/prefer-observer": "error",
|
|
38
|
-
"rxjs-x/prefer-root-operators": "error",
|
|
39
|
-
"rxjs-x/throw-error": "error"
|
|
40
|
-
}
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
// src/configs/strict.ts
|
|
44
|
-
var createStrictConfig = (plugin2) => ({
|
|
45
|
-
name: "rxjs-x/strict",
|
|
46
|
-
plugins: {
|
|
47
|
-
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion -- "A type annotation is necessary."
|
|
48
|
-
"rxjs-x": plugin2
|
|
49
|
-
},
|
|
50
|
-
rules: {
|
|
51
|
-
"rxjs-x/no-async-subscribe": "error",
|
|
52
|
-
"rxjs-x/no-create": "error",
|
|
53
|
-
"rxjs-x/no-exposed-subjects": "error",
|
|
54
|
-
"rxjs-x/no-floating-observables": "error",
|
|
55
|
-
"rxjs-x/no-ignored-default-value": "error",
|
|
56
|
-
"rxjs-x/no-ignored-error": "error",
|
|
57
|
-
"rxjs-x/no-ignored-notifier": "error",
|
|
58
|
-
"rxjs-x/no-ignored-replay-buffer": "error",
|
|
59
|
-
"rxjs-x/no-ignored-takewhile-value": "error",
|
|
60
|
-
"rxjs-x/no-implicit-any-catch": ["error", {
|
|
61
|
-
allowExplicitAny: false
|
|
62
|
-
}],
|
|
63
|
-
"rxjs-x/no-index": "error",
|
|
64
|
-
"rxjs-x/no-internal": "error",
|
|
65
|
-
"rxjs-x/no-misused-observables": "error",
|
|
66
|
-
"rxjs-x/no-nested-subscribe": "error",
|
|
67
|
-
"rxjs-x/no-redundant-notify": "error",
|
|
68
|
-
"rxjs-x/no-sharereplay-before-takeuntil": "error",
|
|
69
|
-
"rxjs-x/no-sharereplay": "error",
|
|
70
|
-
"rxjs-x/no-subclass": "error",
|
|
71
|
-
"rxjs-x/no-subject-unsubscribe": "error",
|
|
72
|
-
"rxjs-x/no-subscribe-in-pipe": "error",
|
|
73
|
-
"rxjs-x/no-topromise": "error",
|
|
74
|
-
"rxjs-x/no-unbound-methods": "error",
|
|
75
|
-
"rxjs-x/no-unnecessary-collection": "error",
|
|
76
|
-
"rxjs-x/no-unsafe-subject-next": "error",
|
|
77
|
-
"rxjs-x/no-unsafe-takeuntil": "error",
|
|
78
|
-
"rxjs-x/prefer-observer": "error",
|
|
79
|
-
"rxjs-x/prefer-root-operators": "error",
|
|
80
|
-
"rxjs-x/throw-error": ["error", {
|
|
81
|
-
allowThrowingAny: false,
|
|
82
|
-
allowThrowingUnknown: false
|
|
83
|
-
}]
|
|
84
|
-
}
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// src/rules/ban-observables.ts
|
|
88
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES3 } from "@typescript-eslint/utils";
|
|
89
|
-
import { stripIndent } from "common-tags";
|
|
90
|
-
|
|
91
|
-
// src/utils/create-regexp-for-words.ts
|
|
92
|
-
function createRegExpForWords(config) {
|
|
93
|
-
if (!(config == null ? void 0 : config.length)) {
|
|
94
|
-
return void 0;
|
|
95
|
-
}
|
|
96
|
-
const flags = "i";
|
|
97
|
-
if (typeof config === "string") {
|
|
98
|
-
return new RegExp(config, flags);
|
|
99
|
-
}
|
|
100
|
-
const words = config;
|
|
101
|
-
const joined = words.map((word) => String.raw`(\b|_)${word}(\b|_)`).join("|");
|
|
102
|
-
return new RegExp(`(${joined})`, flags);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// src/utils/escape-regexp.ts
|
|
106
|
-
function escapeRegExp(text) {
|
|
107
|
-
return text.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// src/etc/could-be-function.ts
|
|
111
|
-
import ts2 from "typescript";
|
|
112
|
-
|
|
113
|
-
// src/etc/could-be-type.ts
|
|
114
|
-
import * as tsutils from "ts-api-utils";
|
|
115
|
-
import ts from "typescript";
|
|
116
|
-
function couldBeType(type, name2, qualified) {
|
|
117
|
-
if (tsutils.isTypeReference(type)) {
|
|
118
|
-
type = type.target;
|
|
119
|
-
}
|
|
120
|
-
if (isType(type.symbol, name2, qualified)) {
|
|
121
|
-
return true;
|
|
122
|
-
}
|
|
123
|
-
if (type.aliasSymbol && isType(type.aliasSymbol, name2, qualified)) {
|
|
124
|
-
return true;
|
|
125
|
-
}
|
|
126
|
-
if (tsutils.isUnionOrIntersectionType(type)) {
|
|
127
|
-
return type.types.some((t) => couldBeType(t, name2, qualified));
|
|
128
|
-
}
|
|
129
|
-
const baseTypes = type.getBaseTypes();
|
|
130
|
-
if (baseTypes == null ? void 0 : baseTypes.some((t) => couldBeType(t, name2, qualified))) {
|
|
131
|
-
return true;
|
|
132
|
-
}
|
|
133
|
-
if (couldImplement(type, name2, qualified)) {
|
|
134
|
-
return true;
|
|
135
|
-
}
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
function isType(symbol, name2, qualified) {
|
|
139
|
-
if (!symbol) {
|
|
140
|
-
return false;
|
|
141
|
-
}
|
|
142
|
-
if (qualified && !qualified.name.test(
|
|
143
|
-
qualified.typeChecker.getFullyQualifiedName(symbol)
|
|
144
|
-
)) {
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
return typeof name2 === "string" ? symbol.name === name2 : Boolean(symbol.name.match(name2));
|
|
148
|
-
}
|
|
149
|
-
function couldImplement(type, name2, qualified) {
|
|
150
|
-
const { symbol } = type;
|
|
151
|
-
if (symbol) {
|
|
152
|
-
const { valueDeclaration } = symbol;
|
|
153
|
-
if (valueDeclaration && ts.isClassDeclaration(valueDeclaration)) {
|
|
154
|
-
const { heritageClauses } = valueDeclaration;
|
|
155
|
-
if (heritageClauses) {
|
|
156
|
-
const implemented = heritageClauses.some(
|
|
157
|
-
({ token, types }) => token === ts.SyntaxKind.ImplementsKeyword && types.some((node) => isMatchingNode(node, name2, qualified))
|
|
158
|
-
);
|
|
159
|
-
if (implemented) {
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
return false;
|
|
166
|
-
}
|
|
167
|
-
function isMatchingNode(node, name2, qualified) {
|
|
168
|
-
const { expression } = node;
|
|
169
|
-
if (qualified) {
|
|
170
|
-
const type = qualified.typeChecker.getTypeAtLocation(expression);
|
|
171
|
-
if (type) {
|
|
172
|
-
const qualifiedName = qualified.typeChecker.getFullyQualifiedName(
|
|
173
|
-
type.symbol
|
|
174
|
-
);
|
|
175
|
-
if (!qualified.name.test(qualifiedName)) {
|
|
176
|
-
return false;
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
const text = expression.getText();
|
|
181
|
-
return typeof name2 === "string" ? text === name2 : Boolean(text.match(name2));
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// src/etc/could-be-function.ts
|
|
185
|
-
function couldBeFunction(type) {
|
|
186
|
-
return type.getCallSignatures().length > 0 || couldBeType(type, "Function") || couldBeType(type, "ArrowFunction") || couldBeType(type, ts2.InternalSymbolName.Function);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// src/etc/find-parent.ts
|
|
190
|
-
function findParent(node, ...args) {
|
|
191
|
-
const [arg] = args;
|
|
192
|
-
const predicate = typeof arg === "function" ? arg : (type) => !args.includes(type) ? "continue" : "return";
|
|
193
|
-
let parent = node.parent;
|
|
194
|
-
while (parent) {
|
|
195
|
-
switch (predicate(parent.type)) {
|
|
196
|
-
case "break":
|
|
197
|
-
return void 0;
|
|
198
|
-
case "return":
|
|
199
|
-
return parent;
|
|
200
|
-
default:
|
|
201
|
-
break;
|
|
202
|
-
}
|
|
203
|
-
parent = parent.parent;
|
|
204
|
-
}
|
|
205
|
-
return void 0;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// src/etc/get-loc.ts
|
|
209
|
-
import ts3 from "typescript";
|
|
210
|
-
function getLoc(node) {
|
|
211
|
-
const sourceFile = node.getSourceFile();
|
|
212
|
-
const start = ts3.getLineAndCharacterOfPosition(sourceFile, node.getStart());
|
|
213
|
-
const end = ts3.getLineAndCharacterOfPosition(sourceFile, node.getEnd());
|
|
214
|
-
return {
|
|
215
|
-
start: {
|
|
216
|
-
line: start.line + 1,
|
|
217
|
-
column: start.character
|
|
218
|
-
},
|
|
219
|
-
end: {
|
|
220
|
-
line: end.line + 1,
|
|
221
|
-
column: end.character
|
|
222
|
-
}
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// src/etc/get-type-services.ts
|
|
227
|
-
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
228
|
-
import * as tsutils2 from "ts-api-utils";
|
|
229
|
-
|
|
230
|
-
// src/etc/is.ts
|
|
231
|
-
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
232
|
-
function hasTypeAnnotation(node) {
|
|
233
|
-
return "typeAnnotation" in node && !!node.typeAnnotation;
|
|
234
|
-
}
|
|
235
|
-
function isAccessorProperty(node) {
|
|
236
|
-
return node.type === AST_NODE_TYPES.AccessorProperty;
|
|
237
|
-
}
|
|
238
|
-
function isArrayExpression(node) {
|
|
239
|
-
return node.type === AST_NODE_TYPES.ArrayExpression;
|
|
240
|
-
}
|
|
241
|
-
function isArrayPattern(node) {
|
|
242
|
-
return node.type === AST_NODE_TYPES.ArrayPattern;
|
|
243
|
-
}
|
|
244
|
-
function isArrowFunctionExpression(node) {
|
|
245
|
-
return node.type === AST_NODE_TYPES.ArrowFunctionExpression;
|
|
246
|
-
}
|
|
247
|
-
function isBlockStatement(node) {
|
|
248
|
-
return node.type === AST_NODE_TYPES.BlockStatement;
|
|
249
|
-
}
|
|
250
|
-
function isCallExpression(node) {
|
|
251
|
-
return node.type === AST_NODE_TYPES.CallExpression;
|
|
252
|
-
}
|
|
253
|
-
function isChainExpression(node) {
|
|
254
|
-
return node.type === AST_NODE_TYPES.ChainExpression;
|
|
255
|
-
}
|
|
256
|
-
function isFunctionDeclaration(node) {
|
|
257
|
-
return node.type === AST_NODE_TYPES.FunctionDeclaration;
|
|
258
|
-
}
|
|
259
|
-
function isFunctionExpression(node) {
|
|
260
|
-
return node.type === AST_NODE_TYPES.FunctionExpression;
|
|
261
|
-
}
|
|
262
|
-
function isIdentifier(node) {
|
|
263
|
-
return node.type === AST_NODE_TYPES.Identifier;
|
|
264
|
-
}
|
|
265
|
-
function isImportDeclaration(node) {
|
|
266
|
-
return node.type === AST_NODE_TYPES.ImportDeclaration;
|
|
267
|
-
}
|
|
268
|
-
function isImportNamespaceSpecifier(node) {
|
|
269
|
-
return node.type === AST_NODE_TYPES.ImportNamespaceSpecifier;
|
|
270
|
-
}
|
|
271
|
-
function isImportSpecifier(node) {
|
|
272
|
-
return node.type === AST_NODE_TYPES.ImportSpecifier;
|
|
273
|
-
}
|
|
274
|
-
function isJSXExpressionContainer(node) {
|
|
275
|
-
return node.type === AST_NODE_TYPES.JSXExpressionContainer;
|
|
276
|
-
}
|
|
277
|
-
function isLiteral(node) {
|
|
278
|
-
return node.type === AST_NODE_TYPES.Literal;
|
|
279
|
-
}
|
|
280
|
-
function isTemplateLiteral(node) {
|
|
281
|
-
return node.type === AST_NODE_TYPES.TemplateLiteral;
|
|
282
|
-
}
|
|
283
|
-
function isMemberExpression(node) {
|
|
284
|
-
return node.type === AST_NODE_TYPES.MemberExpression;
|
|
285
|
-
}
|
|
286
|
-
function isMethodDefinition(node) {
|
|
287
|
-
return node.type === AST_NODE_TYPES.MethodDefinition;
|
|
288
|
-
}
|
|
289
|
-
function isObjectExpression(node) {
|
|
290
|
-
return node.type === AST_NODE_TYPES.ObjectExpression;
|
|
291
|
-
}
|
|
292
|
-
function isObjectPattern(node) {
|
|
293
|
-
return node.type === AST_NODE_TYPES.ObjectPattern;
|
|
294
|
-
}
|
|
295
|
-
function isProgram(node) {
|
|
296
|
-
return node.type === AST_NODE_TYPES.Program;
|
|
297
|
-
}
|
|
298
|
-
function isProperty(node) {
|
|
299
|
-
return node.type === AST_NODE_TYPES.Property;
|
|
300
|
-
}
|
|
301
|
-
function isPropertyDefinition(node) {
|
|
302
|
-
return node.type === AST_NODE_TYPES.PropertyDefinition;
|
|
303
|
-
}
|
|
304
|
-
function isSpreadElement(node) {
|
|
305
|
-
return node.type === AST_NODE_TYPES.SpreadElement;
|
|
306
|
-
}
|
|
307
|
-
function isTSAsExpression(node) {
|
|
308
|
-
return node.type === AST_NODE_TYPES.TSAsExpression;
|
|
309
|
-
}
|
|
310
|
-
function isTSSatisfiesExpression(node) {
|
|
311
|
-
return node.type === AST_NODE_TYPES.TSSatisfiesExpression;
|
|
312
|
-
}
|
|
313
|
-
function isUnaryExpression(node) {
|
|
314
|
-
return node.type === AST_NODE_TYPES.UnaryExpression;
|
|
315
|
-
}
|
|
316
|
-
function isUnionType(node) {
|
|
317
|
-
return node.type === AST_NODE_TYPES.TSUnionType;
|
|
318
|
-
}
|
|
319
|
-
function isVariableDeclarator(node) {
|
|
320
|
-
return node.type === AST_NODE_TYPES.VariableDeclarator;
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// src/etc/get-type-services.ts
|
|
324
|
-
function getTypeServices(context) {
|
|
325
|
-
const services = ESLintUtils.getParserServices(context);
|
|
326
|
-
const { program, getTypeAtLocation } = services;
|
|
327
|
-
const typeChecker = program.getTypeChecker();
|
|
328
|
-
const couldBeType2 = (node, name2, qualified) => {
|
|
329
|
-
const type = getTypeAtLocation(node);
|
|
330
|
-
return couldBeType(
|
|
331
|
-
type,
|
|
332
|
-
name2,
|
|
333
|
-
qualified ? { ...qualified, typeChecker } : void 0
|
|
334
|
-
);
|
|
335
|
-
};
|
|
336
|
-
const couldReturnType = (node, name2, qualified) => {
|
|
337
|
-
const type = getTypeAtLocation(node);
|
|
338
|
-
for (const signature of tsutils2.getCallSignaturesOfType(type)) {
|
|
339
|
-
const returnType = signature.getReturnType();
|
|
340
|
-
if (couldBeType(
|
|
341
|
-
returnType,
|
|
342
|
-
name2,
|
|
343
|
-
qualified ? { ...qualified, typeChecker } : void 0
|
|
344
|
-
)) {
|
|
345
|
-
return true;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
return false;
|
|
349
|
-
};
|
|
350
|
-
return {
|
|
351
|
-
couldBeBehaviorSubject: (node) => couldBeType2(node, "BehaviorSubject"),
|
|
352
|
-
couldBeFunction: (node) => {
|
|
353
|
-
if (isArrowFunctionExpression(node) || isFunctionDeclaration(node)) {
|
|
354
|
-
return true;
|
|
355
|
-
}
|
|
356
|
-
return couldBeFunction(getTypeAtLocation(node));
|
|
357
|
-
},
|
|
358
|
-
couldBeMonoTypeOperatorFunction: (node) => couldBeType2(node, "MonoTypeOperatorFunction"),
|
|
359
|
-
couldBeObservable: (node) => couldBeType2(node, "Observable"),
|
|
360
|
-
couldBeSubject: (node) => couldBeType2(node, "Subject"),
|
|
361
|
-
couldBeSubscription: (node) => couldBeType2(node, "Subscription"),
|
|
362
|
-
couldBeType: couldBeType2,
|
|
363
|
-
couldReturnObservable: (node) => couldReturnType(node, "Observable"),
|
|
364
|
-
couldReturnType
|
|
365
|
-
};
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
// src/etc/is-import.ts
|
|
369
|
-
import { DefinitionType } from "@typescript-eslint/scope-manager";
|
|
370
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES2 } from "@typescript-eslint/utils";
|
|
371
|
-
function isImport(scope, name2, source) {
|
|
372
|
-
const variable = scope.variables.find((variable2) => variable2.name === name2);
|
|
373
|
-
if (variable) {
|
|
374
|
-
return variable.defs.some(
|
|
375
|
-
(def) => def.type === DefinitionType.ImportBinding && def.parent.type === AST_NODE_TYPES2.ImportDeclaration && (typeof source === "string" ? def.parent.source.value === source : source.test(def.parent.source.value))
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
return scope.upper ? isImport(scope.upper, name2, source) : false;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
// src/utils/find-is-last-operator-order-valid.ts
|
|
382
|
-
function findIsLastOperatorOrderValid(pipeCallExpression, operatorsRegExp, allow) {
|
|
383
|
-
let isOrderValid = true;
|
|
384
|
-
let operatorNode;
|
|
385
|
-
for (let i = pipeCallExpression.arguments.length - 1; i >= 0; i--) {
|
|
386
|
-
const arg = pipeCallExpression.arguments[i];
|
|
387
|
-
if (operatorNode) {
|
|
388
|
-
break;
|
|
389
|
-
}
|
|
390
|
-
if (!isCallExpression(arg)) {
|
|
391
|
-
isOrderValid = false;
|
|
392
|
-
continue;
|
|
393
|
-
}
|
|
394
|
-
let operatorName;
|
|
395
|
-
if (isIdentifier(arg.callee)) {
|
|
396
|
-
operatorName = arg.callee.name;
|
|
397
|
-
} else if (isMemberExpression(arg.callee) && isIdentifier(arg.callee.property)) {
|
|
398
|
-
operatorName = arg.callee.property.name;
|
|
399
|
-
} else {
|
|
400
|
-
isOrderValid = false;
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
if (operatorsRegExp.test(operatorName)) {
|
|
404
|
-
operatorNode = arg.callee;
|
|
405
|
-
break;
|
|
406
|
-
}
|
|
407
|
-
if (!allow.includes(operatorName)) {
|
|
408
|
-
isOrderValid = false;
|
|
409
|
-
continue;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
return { isOrderValid, operatorNode };
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
// src/utils/rule-creator.ts
|
|
416
|
-
import { ESLintUtils as ESLintUtils2 } from "@typescript-eslint/utils";
|
|
417
|
-
var REPO_URL = "https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x";
|
|
418
|
-
var ruleCreator = ESLintUtils2.RuleCreator(
|
|
419
|
-
(name2) => `${REPO_URL}/blob/v${version}/docs/rules/${name2}.md`
|
|
420
|
-
// Ensure the resulting types are narrowed to exactly what each rule declares.
|
|
421
|
-
);
|
|
422
|
-
|
|
423
|
-
// src/rules/ban-observables.ts
|
|
424
|
-
var defaultOptions = [];
|
|
425
|
-
var banObservablesRule = ruleCreator({
|
|
426
|
-
defaultOptions,
|
|
427
|
-
meta: {
|
|
428
|
-
docs: {
|
|
429
|
-
description: "Disallow banned observable creators."
|
|
430
|
-
},
|
|
431
|
-
messages: {
|
|
432
|
-
forbidden: "RxJS observable is banned: {{name}}{{explanation}}."
|
|
433
|
-
},
|
|
434
|
-
schema: [
|
|
435
|
-
{
|
|
436
|
-
type: "object",
|
|
437
|
-
description: stripIndent`
|
|
438
|
-
An object containing keys that are names of observable factory functions
|
|
439
|
-
and values that are either booleans or strings containing the explanation for the ban.`
|
|
440
|
-
}
|
|
441
|
-
],
|
|
442
|
-
type: "problem"
|
|
443
|
-
},
|
|
444
|
-
name: "ban-observables",
|
|
445
|
-
create: (context) => {
|
|
446
|
-
const bans = [];
|
|
447
|
-
const [config] = context.options;
|
|
448
|
-
if (!config) {
|
|
449
|
-
return {};
|
|
450
|
-
}
|
|
451
|
-
Object.entries(config).forEach(([key, value]) => {
|
|
452
|
-
if (value !== false) {
|
|
453
|
-
bans.push({
|
|
454
|
-
explanation: typeof value === "string" ? value : "",
|
|
455
|
-
regExp: new RegExp(`^${key}$`)
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
function getFailure(name2) {
|
|
460
|
-
for (let b = 0, length = bans.length; b < length; ++b) {
|
|
461
|
-
const ban = bans[b];
|
|
462
|
-
if (ban.regExp.test(name2)) {
|
|
463
|
-
const explanation = ban.explanation ? `: ${ban.explanation}` : "";
|
|
464
|
-
return {
|
|
465
|
-
messageId: "forbidden",
|
|
466
|
-
data: { name: name2, explanation }
|
|
467
|
-
};
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
return void 0;
|
|
471
|
-
}
|
|
472
|
-
return {
|
|
473
|
-
"ImportDeclaration[source.value='rxjs'] > ImportSpecifier": (node) => {
|
|
474
|
-
const identifier = node.imported;
|
|
475
|
-
const name2 = identifier.type === AST_NODE_TYPES3.Identifier ? identifier.name : identifier.value;
|
|
476
|
-
const failure = getFailure(name2);
|
|
477
|
-
if (failure) {
|
|
478
|
-
context.report({
|
|
479
|
-
...failure,
|
|
480
|
-
node: identifier
|
|
481
|
-
});
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// src/rules/ban-operators.ts
|
|
489
|
-
import { stripIndent as stripIndent2 } from "common-tags";
|
|
490
|
-
var defaultOptions2 = [];
|
|
491
|
-
var banOperatorsRule = ruleCreator({
|
|
492
|
-
defaultOptions: defaultOptions2,
|
|
493
|
-
meta: {
|
|
494
|
-
docs: {
|
|
495
|
-
description: "Disallow banned operators.",
|
|
496
|
-
requiresTypeChecking: true
|
|
497
|
-
},
|
|
498
|
-
messages: {
|
|
499
|
-
forbidden: "RxJS operator is banned: {{name}}{{explanation}}."
|
|
500
|
-
},
|
|
501
|
-
schema: [
|
|
502
|
-
{
|
|
503
|
-
type: "object",
|
|
504
|
-
description: stripIndent2`
|
|
505
|
-
An object containing keys that are names of operators
|
|
506
|
-
and values that are either booleans or strings containing the explanation for the ban.`
|
|
507
|
-
}
|
|
508
|
-
],
|
|
509
|
-
type: "problem"
|
|
510
|
-
},
|
|
511
|
-
name: "ban-operators",
|
|
512
|
-
create: (context) => {
|
|
513
|
-
const { couldBeType: couldBeType2 } = getTypeServices(context);
|
|
514
|
-
const bans = [];
|
|
515
|
-
const [config] = context.options;
|
|
516
|
-
if (!config) {
|
|
517
|
-
return {};
|
|
518
|
-
}
|
|
519
|
-
Object.entries(config).forEach(([key, value]) => {
|
|
520
|
-
if (value !== false) {
|
|
521
|
-
bans.push({
|
|
522
|
-
name: key,
|
|
523
|
-
explanation: typeof value === "string" ? value : ""
|
|
524
|
-
});
|
|
525
|
-
}
|
|
526
|
-
});
|
|
527
|
-
function checkNode(node) {
|
|
528
|
-
for (const ban of bans) {
|
|
529
|
-
if (couldBeType2(node, ban.name, { name: /[/\\]rxjs[/\\]/ })) {
|
|
530
|
-
const explanation = ban.explanation ? `: ${ban.explanation}` : "";
|
|
531
|
-
context.report({
|
|
532
|
-
messageId: "forbidden",
|
|
533
|
-
data: { name: ban.name, explanation },
|
|
534
|
-
node
|
|
535
|
-
});
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
return {
|
|
541
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[callee.name]": (node) => {
|
|
542
|
-
checkNode(node.callee);
|
|
543
|
-
},
|
|
544
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[callee.type=\"MemberExpression\"]": (node) => {
|
|
545
|
-
const callee = node.callee;
|
|
546
|
-
checkNode(callee.property);
|
|
547
|
-
}
|
|
548
|
-
};
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
|
|
552
|
-
// src/rules/finnish.ts
|
|
553
|
-
import { ESLintUtils as ESLintUtils3 } from "@typescript-eslint/utils";
|
|
554
|
-
var defaultOptions3 = [];
|
|
555
|
-
var baseShouldBeFinnish = "Finnish notation should be used here.";
|
|
556
|
-
var finnishRule = ruleCreator({
|
|
557
|
-
defaultOptions: defaultOptions3,
|
|
558
|
-
meta: {
|
|
559
|
-
docs: {
|
|
560
|
-
description: "Enforce Finnish notation.",
|
|
561
|
-
requiresTypeChecking: true
|
|
562
|
-
},
|
|
563
|
-
messages: {
|
|
564
|
-
shouldBeFinnish: baseShouldBeFinnish,
|
|
565
|
-
shouldBeFinnishProperty: `${baseShouldBeFinnish} Add a type annotation, assertion, or 'satisfies' to silence this rule.`,
|
|
566
|
-
shouldNotBeFinnish: "Finnish notation should not be used here."
|
|
567
|
-
},
|
|
568
|
-
schema: [
|
|
569
|
-
{
|
|
570
|
-
properties: {
|
|
571
|
-
functions: { type: "boolean", description: "Require for functions." },
|
|
572
|
-
methods: { type: "boolean", description: "Require for methods." },
|
|
573
|
-
names: { type: "object", description: "Enforce for specific names. Keys are a RegExp, values are a boolean." },
|
|
574
|
-
parameters: { type: "boolean", description: "Require for parameters." },
|
|
575
|
-
properties: { type: "boolean", description: 'Require for properties, except object literal keys (see "objects" option).' },
|
|
576
|
-
objects: { type: "boolean", description: "Require for object literal keys." },
|
|
577
|
-
strict: { type: "boolean", description: "Disallow Finnish notation for non-Observables." },
|
|
578
|
-
types: { type: "object", description: "Enforce for specific types. Keys are a RegExp, values are a boolean." },
|
|
579
|
-
variables: { type: "boolean", description: "Require for variables." }
|
|
580
|
-
},
|
|
581
|
-
type: "object"
|
|
582
|
-
}
|
|
583
|
-
],
|
|
584
|
-
type: "problem"
|
|
585
|
-
},
|
|
586
|
-
name: "finnish",
|
|
587
|
-
create: (context) => {
|
|
588
|
-
const { esTreeNodeToTSNodeMap } = ESLintUtils3.getParserServices(context);
|
|
589
|
-
const {
|
|
590
|
-
couldBeObservable,
|
|
591
|
-
couldBeType: couldBeType2,
|
|
592
|
-
couldReturnObservable,
|
|
593
|
-
couldReturnType
|
|
594
|
-
} = getTypeServices(context);
|
|
595
|
-
const [config = {}] = context.options;
|
|
596
|
-
const { strict = false } = config;
|
|
597
|
-
const validate = {
|
|
598
|
-
functions: true,
|
|
599
|
-
methods: true,
|
|
600
|
-
parameters: true,
|
|
601
|
-
properties: true,
|
|
602
|
-
objects: true,
|
|
603
|
-
variables: true,
|
|
604
|
-
...config
|
|
605
|
-
};
|
|
606
|
-
const names = [];
|
|
607
|
-
if (config.names) {
|
|
608
|
-
Object.entries(config.names).forEach(
|
|
609
|
-
([key, validate2]) => {
|
|
610
|
-
names.push({ regExp: new RegExp(key), validate: validate2 });
|
|
611
|
-
}
|
|
612
|
-
);
|
|
613
|
-
} else {
|
|
614
|
-
names.push({
|
|
615
|
-
regExp: /^(canActivate|canActivateChild|canDeactivate|canLoad|intercept|resolve|validate)$/,
|
|
616
|
-
validate: false
|
|
617
|
-
});
|
|
618
|
-
}
|
|
619
|
-
const types = [];
|
|
620
|
-
if (config.types) {
|
|
621
|
-
Object.entries(config.types).forEach(
|
|
622
|
-
([key, validate2]) => {
|
|
623
|
-
types.push({ regExp: new RegExp(key), validate: validate2 });
|
|
624
|
-
}
|
|
625
|
-
);
|
|
626
|
-
} else {
|
|
627
|
-
types.push({
|
|
628
|
-
regExp: /^EventEmitter$/,
|
|
629
|
-
validate: false
|
|
630
|
-
});
|
|
631
|
-
}
|
|
632
|
-
function checkNode(nameNode, typeNode, shouldMessage = "shouldBeFinnish") {
|
|
633
|
-
const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
|
|
634
|
-
const text = tsNode.getText();
|
|
635
|
-
const hasFinnish = text.endsWith("$");
|
|
636
|
-
if (hasFinnish && !strict) {
|
|
637
|
-
return;
|
|
638
|
-
}
|
|
639
|
-
const shouldBeFinnish = hasFinnish ? () => {
|
|
640
|
-
} : () => {
|
|
641
|
-
context.report({
|
|
642
|
-
loc: getLoc(tsNode),
|
|
643
|
-
messageId: shouldMessage
|
|
644
|
-
});
|
|
645
|
-
};
|
|
646
|
-
const shouldNotBeFinnish = hasFinnish ? () => {
|
|
647
|
-
context.report({
|
|
648
|
-
loc: getLoc(tsNode),
|
|
649
|
-
messageId: "shouldNotBeFinnish"
|
|
650
|
-
});
|
|
651
|
-
} : () => {
|
|
652
|
-
};
|
|
653
|
-
const nameWithoutDollar = text.endsWith("$") ? text.slice(0, -1) : text;
|
|
654
|
-
for (const name2 of names) {
|
|
655
|
-
const { regExp, validate: validate2 } = name2;
|
|
656
|
-
if (regExp.test(text) || regExp.test(nameWithoutDollar)) {
|
|
657
|
-
if (validate2) {
|
|
658
|
-
shouldBeFinnish();
|
|
659
|
-
} else {
|
|
660
|
-
shouldNotBeFinnish();
|
|
661
|
-
}
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
for (const type of types) {
|
|
666
|
-
const { regExp, validate: validate2 } = type;
|
|
667
|
-
if (couldBeType2(typeNode != null ? typeNode : nameNode, regExp) || couldReturnType(typeNode != null ? typeNode : nameNode, regExp)) {
|
|
668
|
-
if (validate2) {
|
|
669
|
-
shouldBeFinnish();
|
|
670
|
-
} else {
|
|
671
|
-
shouldNotBeFinnish();
|
|
672
|
-
}
|
|
673
|
-
return;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
if (couldBeObservable(typeNode != null ? typeNode : nameNode) || couldReturnObservable(typeNode != null ? typeNode : nameNode)) {
|
|
677
|
-
shouldBeFinnish();
|
|
678
|
-
} else {
|
|
679
|
-
shouldNotBeFinnish();
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
return {
|
|
683
|
-
"ArrayPattern > Identifier": (node) => {
|
|
684
|
-
const found = findParent(
|
|
685
|
-
node,
|
|
686
|
-
"ArrowFunctionExpression",
|
|
687
|
-
"FunctionDeclaration",
|
|
688
|
-
"FunctionExpression",
|
|
689
|
-
"VariableDeclarator"
|
|
690
|
-
);
|
|
691
|
-
if (!found) {
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
if (!validate.variables && isVariableDeclarator(found)) {
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if (!validate.parameters) {
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
700
|
-
checkNode(node);
|
|
701
|
-
},
|
|
702
|
-
"ArrowFunctionExpression > Identifier": (node) => {
|
|
703
|
-
if (validate.parameters) {
|
|
704
|
-
const parent = node.parent;
|
|
705
|
-
if (node !== parent.body) {
|
|
706
|
-
checkNode(node);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
},
|
|
710
|
-
"PropertyDefinition[computed=false]": (node) => {
|
|
711
|
-
if (validate.properties) {
|
|
712
|
-
if (node.override) {
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
checkNode(node.key);
|
|
716
|
-
}
|
|
717
|
-
},
|
|
718
|
-
"FunctionDeclaration > Identifier": (node) => {
|
|
719
|
-
const parent = node.parent;
|
|
720
|
-
if (node === parent.id) {
|
|
721
|
-
if (validate.functions) {
|
|
722
|
-
checkNode(node, parent);
|
|
723
|
-
}
|
|
724
|
-
} else {
|
|
725
|
-
if (validate.parameters) {
|
|
726
|
-
checkNode(node);
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
},
|
|
730
|
-
"FunctionExpression > Identifier": (node) => {
|
|
731
|
-
const parent = node.parent;
|
|
732
|
-
if (node === parent.id) {
|
|
733
|
-
if (validate.functions) {
|
|
734
|
-
checkNode(node, parent);
|
|
735
|
-
}
|
|
736
|
-
} else {
|
|
737
|
-
if (validate.parameters) {
|
|
738
|
-
checkNode(node);
|
|
739
|
-
}
|
|
740
|
-
}
|
|
741
|
-
},
|
|
742
|
-
"MethodDefinition[kind='get'][computed=false]": (node) => {
|
|
743
|
-
if (validate.properties) {
|
|
744
|
-
if (node.override) {
|
|
745
|
-
return;
|
|
746
|
-
}
|
|
747
|
-
checkNode(node.key, node);
|
|
748
|
-
}
|
|
749
|
-
},
|
|
750
|
-
"MethodDefinition[kind='method'][computed=false]": (node) => {
|
|
751
|
-
if (validate.methods) {
|
|
752
|
-
if (node.override) {
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
checkNode(node.key, node);
|
|
756
|
-
}
|
|
757
|
-
},
|
|
758
|
-
"MethodDefinition[kind='set'][computed=false]": (node) => {
|
|
759
|
-
if (validate.properties) {
|
|
760
|
-
if (node.override) {
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
checkNode(node.key, node);
|
|
764
|
-
}
|
|
765
|
-
},
|
|
766
|
-
"TSAbstractMethodDefinition[computed=false]": (node) => {
|
|
767
|
-
if (node.override) {
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
|
-
if (validate.methods && node.kind === "method") {
|
|
771
|
-
checkNode(node.key, node);
|
|
772
|
-
}
|
|
773
|
-
if (validate.properties && (node.kind === "get" || node.kind === "set")) {
|
|
774
|
-
checkNode(node.key, node);
|
|
775
|
-
}
|
|
776
|
-
if (validate.parameters) {
|
|
777
|
-
node.value.params.forEach((param) => {
|
|
778
|
-
checkNode(param);
|
|
779
|
-
});
|
|
780
|
-
}
|
|
781
|
-
},
|
|
782
|
-
"ObjectExpression > Property[computed=false] > Identifier": (node) => {
|
|
783
|
-
if (!validate.objects) {
|
|
784
|
-
return;
|
|
785
|
-
}
|
|
786
|
-
const found = findParent(
|
|
787
|
-
node,
|
|
788
|
-
"CallExpression",
|
|
789
|
-
"VariableDeclarator",
|
|
790
|
-
"TSSatisfiesExpression",
|
|
791
|
-
"TSAsExpression"
|
|
792
|
-
);
|
|
793
|
-
if (found) {
|
|
794
|
-
if (isCallExpression(found)) {
|
|
795
|
-
return;
|
|
796
|
-
} else if (isVariableDeclarator(found) && !!found.id.typeAnnotation) {
|
|
797
|
-
return;
|
|
798
|
-
} else if (isTSAsExpression(found) || isTSSatisfiesExpression(found)) {
|
|
799
|
-
return;
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
const parent = node.parent;
|
|
803
|
-
if (node === parent.key) {
|
|
804
|
-
checkNode(node, void 0, "shouldBeFinnishProperty");
|
|
805
|
-
}
|
|
806
|
-
},
|
|
807
|
-
"ObjectPattern > Property > Identifier": (node) => {
|
|
808
|
-
const found = findParent(
|
|
809
|
-
node,
|
|
810
|
-
"ArrowFunctionExpression",
|
|
811
|
-
"FunctionDeclaration",
|
|
812
|
-
"FunctionExpression",
|
|
813
|
-
"VariableDeclarator"
|
|
814
|
-
);
|
|
815
|
-
if (!found) {
|
|
816
|
-
return;
|
|
817
|
-
}
|
|
818
|
-
if (!validate.variables && isVariableDeclarator(found)) {
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
if (!validate.parameters) {
|
|
822
|
-
return;
|
|
823
|
-
}
|
|
824
|
-
const parent = node.parent;
|
|
825
|
-
if (node === parent.value) {
|
|
826
|
-
checkNode(node);
|
|
827
|
-
}
|
|
828
|
-
},
|
|
829
|
-
"TSCallSignatureDeclaration > Identifier": (node) => {
|
|
830
|
-
if (validate.parameters) {
|
|
831
|
-
checkNode(node);
|
|
832
|
-
}
|
|
833
|
-
},
|
|
834
|
-
"TSConstructSignatureDeclaration > Identifier": (node) => {
|
|
835
|
-
if (validate.parameters) {
|
|
836
|
-
checkNode(node);
|
|
837
|
-
}
|
|
838
|
-
},
|
|
839
|
-
"TSMethodSignature[computed=false]": (node) => {
|
|
840
|
-
if (validate.methods) {
|
|
841
|
-
checkNode(node.key, node);
|
|
842
|
-
}
|
|
843
|
-
if (validate.parameters) {
|
|
844
|
-
node.params.forEach((param) => {
|
|
845
|
-
checkNode(param);
|
|
846
|
-
});
|
|
847
|
-
}
|
|
848
|
-
},
|
|
849
|
-
"TSParameterProperty > Identifier": (node) => {
|
|
850
|
-
if (validate.parameters || validate.properties) {
|
|
851
|
-
checkNode(node);
|
|
852
|
-
}
|
|
853
|
-
},
|
|
854
|
-
"TSPropertySignature[computed=false]": (node) => {
|
|
855
|
-
if (validate.properties) {
|
|
856
|
-
checkNode(node.key);
|
|
857
|
-
}
|
|
858
|
-
},
|
|
859
|
-
"VariableDeclarator > Identifier": (node) => {
|
|
860
|
-
const parent = node.parent;
|
|
861
|
-
if (validate.variables && node === parent.id) {
|
|
862
|
-
checkNode(node);
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
});
|
|
868
|
-
|
|
869
|
-
// src/rules/just.ts
|
|
870
|
-
var justRule = ruleCreator({
|
|
871
|
-
defaultOptions: [],
|
|
872
|
-
meta: {
|
|
873
|
-
docs: {
|
|
874
|
-
description: "Require the use of `just` instead of `of`."
|
|
875
|
-
},
|
|
876
|
-
fixable: "code",
|
|
877
|
-
messages: {
|
|
878
|
-
forbidden: "Use just alias."
|
|
879
|
-
},
|
|
880
|
-
schema: [],
|
|
881
|
-
type: "problem"
|
|
882
|
-
},
|
|
883
|
-
name: "just",
|
|
884
|
-
create: (context) => {
|
|
885
|
-
return {
|
|
886
|
-
"ImportDeclaration[source.value='rxjs'] > ImportSpecifier[imported.name='of']": (node) => {
|
|
887
|
-
if (node.local.range[0] !== node.imported.range[0] && node.local.range[1] !== node.imported.range[1]) {
|
|
888
|
-
return;
|
|
889
|
-
}
|
|
890
|
-
context.report({
|
|
891
|
-
messageId: "forbidden",
|
|
892
|
-
node,
|
|
893
|
-
fix: (fixer) => fixer.replaceTextRange(node.range, "of as just")
|
|
894
|
-
});
|
|
895
|
-
const [ofImport] = context.sourceCode.getDeclaredVariables(node);
|
|
896
|
-
ofImport.references.forEach((ref) => {
|
|
897
|
-
context.report({
|
|
898
|
-
messageId: "forbidden",
|
|
899
|
-
node: ref.identifier,
|
|
900
|
-
fix: (fixer) => fixer.replaceTextRange(ref.identifier.range, "just")
|
|
901
|
-
});
|
|
902
|
-
});
|
|
903
|
-
}
|
|
904
|
-
};
|
|
905
|
-
}
|
|
906
|
-
});
|
|
907
|
-
|
|
908
|
-
// src/rules/macro.ts
|
|
909
|
-
var macroRule = ruleCreator({
|
|
910
|
-
defaultOptions: [],
|
|
911
|
-
meta: {
|
|
912
|
-
deprecated: true,
|
|
913
|
-
docs: {
|
|
914
|
-
description: "Require the use of the RxJS Tools Babel macro."
|
|
915
|
-
},
|
|
916
|
-
fixable: "code",
|
|
917
|
-
messages: {
|
|
918
|
-
macro: "Use the RxJS Tools Babel macro."
|
|
919
|
-
},
|
|
920
|
-
schema: [],
|
|
921
|
-
type: "problem"
|
|
922
|
-
},
|
|
923
|
-
name: "macro",
|
|
924
|
-
create: (context) => {
|
|
925
|
-
let hasFailure = false;
|
|
926
|
-
let hasMacroImport = false;
|
|
927
|
-
let program = void 0;
|
|
928
|
-
function fix(fixer) {
|
|
929
|
-
return fixer.insertTextBefore(
|
|
930
|
-
/* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
|
|
931
|
-
program,
|
|
932
|
-
`import "babel-plugin-rxjs-tools/macro";
|
|
933
|
-
`
|
|
934
|
-
);
|
|
935
|
-
}
|
|
936
|
-
return {
|
|
937
|
-
"CallExpression[callee.property.name=/^(pipe|subscribe)$/]": (node) => {
|
|
938
|
-
if (hasFailure || hasMacroImport) {
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
hasFailure = true;
|
|
942
|
-
context.report({
|
|
943
|
-
fix,
|
|
944
|
-
messageId: "macro",
|
|
945
|
-
node: node.callee
|
|
946
|
-
});
|
|
947
|
-
},
|
|
948
|
-
"ImportDeclaration[source.value='babel-plugin-rxjs-tools/macro']": (_node) => {
|
|
949
|
-
hasMacroImport = true;
|
|
950
|
-
},
|
|
951
|
-
[String.raw`ImportDeclaration[source.value=/^rxjs(\u002f|$)/]`]: (node) => {
|
|
952
|
-
if (hasFailure || hasMacroImport) {
|
|
953
|
-
return;
|
|
954
|
-
}
|
|
955
|
-
hasFailure = true;
|
|
956
|
-
context.report({
|
|
957
|
-
fix,
|
|
958
|
-
messageId: "macro",
|
|
959
|
-
node
|
|
960
|
-
});
|
|
961
|
-
},
|
|
962
|
-
"Program": (node) => {
|
|
963
|
-
program = node;
|
|
964
|
-
}
|
|
965
|
-
};
|
|
966
|
-
}
|
|
967
|
-
});
|
|
968
|
-
|
|
969
|
-
// src/rules/no-async-subscribe.ts
|
|
970
|
-
var noAsyncSubscribeRule = ruleCreator({
|
|
971
|
-
defaultOptions: [],
|
|
972
|
-
meta: {
|
|
973
|
-
docs: {
|
|
974
|
-
description: "Disallow passing `async` functions to `subscribe`.",
|
|
975
|
-
recommended: "recommended",
|
|
976
|
-
requiresTypeChecking: true
|
|
977
|
-
},
|
|
978
|
-
messages: {
|
|
979
|
-
forbidden: "Passing async functions to subscribe is forbidden. Use operators like `concatMap` or `switchMap` to avoid race conditions."
|
|
980
|
-
},
|
|
981
|
-
schema: [],
|
|
982
|
-
type: "problem"
|
|
983
|
-
},
|
|
984
|
-
name: "no-async-subscribe",
|
|
985
|
-
create: (context) => {
|
|
986
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
987
|
-
function report(node) {
|
|
988
|
-
const { loc } = node;
|
|
989
|
-
const asyncLoc = {
|
|
990
|
-
...loc,
|
|
991
|
-
end: {
|
|
992
|
-
...loc.start,
|
|
993
|
-
column: loc.start.column + 5
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
context.report({
|
|
997
|
-
messageId: "forbidden",
|
|
998
|
-
loc: asyncLoc
|
|
999
|
-
});
|
|
1000
|
-
}
|
|
1001
|
-
function checkSingleNext(funcNode) {
|
|
1002
|
-
const parentNode = funcNode.parent;
|
|
1003
|
-
const callee = parentNode.callee;
|
|
1004
|
-
if (couldBeObservable(callee.object)) {
|
|
1005
|
-
report(funcNode);
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1008
|
-
function checkObserverObjectProp(propNode) {
|
|
1009
|
-
const parentNode = propNode.parent.parent;
|
|
1010
|
-
const callee = parentNode.callee;
|
|
1011
|
-
if (couldBeObservable(callee.object) && (isArrowFunctionExpression(propNode.value) || isFunctionExpression(propNode.value))) {
|
|
1012
|
-
report(propNode.value);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
return {
|
|
1016
|
-
"CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]": checkSingleNext,
|
|
1017
|
-
"CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]": checkSingleNext,
|
|
1018
|
-
"CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"ArrowFunctionExpression\"][value.async=true]": checkObserverObjectProp,
|
|
1019
|
-
"CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"FunctionExpression\"][value.async=true]": checkObserverObjectProp
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
1022
|
-
});
|
|
1023
|
-
|
|
1024
|
-
// src/rules/no-compat.ts
|
|
1025
|
-
var noCompatRule = ruleCreator({
|
|
1026
|
-
defaultOptions: [],
|
|
1027
|
-
meta: {
|
|
1028
|
-
deprecated: true,
|
|
1029
|
-
docs: {
|
|
1030
|
-
description: "Disallow the `rxjs-compat` package."
|
|
1031
|
-
},
|
|
1032
|
-
messages: {
|
|
1033
|
-
forbidden: "'rxjs-compat'-dependent import locations are forbidden."
|
|
1034
|
-
},
|
|
1035
|
-
schema: [],
|
|
1036
|
-
type: "problem"
|
|
1037
|
-
},
|
|
1038
|
-
name: "no-compat",
|
|
1039
|
-
create: (context) => {
|
|
1040
|
-
return {
|
|
1041
|
-
[String.raw`ImportDeclaration Literal[value=/^rxjs\u002f/]:not(Literal[value=/^rxjs\u002f(ajax|fetch|operators|testing|webSocket)/])`]: (node) => {
|
|
1042
|
-
context.report({
|
|
1043
|
-
messageId: "forbidden",
|
|
1044
|
-
node
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
};
|
|
1048
|
-
}
|
|
1049
|
-
});
|
|
1050
|
-
|
|
1051
|
-
// src/rules/no-connectable.ts
|
|
1052
|
-
var noConnectableRule = ruleCreator({
|
|
1053
|
-
defaultOptions: [],
|
|
1054
|
-
meta: {
|
|
1055
|
-
docs: {
|
|
1056
|
-
description: "Disallow operators that return connectable observables.",
|
|
1057
|
-
requiresTypeChecking: true
|
|
1058
|
-
},
|
|
1059
|
-
messages: {
|
|
1060
|
-
forbidden: "Connectable observables are forbidden."
|
|
1061
|
-
},
|
|
1062
|
-
schema: [],
|
|
1063
|
-
type: "problem"
|
|
1064
|
-
},
|
|
1065
|
-
name: "no-connectable",
|
|
1066
|
-
create: (context) => {
|
|
1067
|
-
const { couldBeFunction: couldBeFunction2 } = getTypeServices(context);
|
|
1068
|
-
return {
|
|
1069
|
-
"CallExpression[callee.name='multicast']": (node) => {
|
|
1070
|
-
if (node.arguments.length === 1) {
|
|
1071
|
-
context.report({
|
|
1072
|
-
messageId: "forbidden",
|
|
1073
|
-
node: node.callee
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
},
|
|
1077
|
-
"CallExpression[callee.name=/^(publish|publishBehavior|publishLast|publishReplay)$/]": (node) => {
|
|
1078
|
-
if (!node.arguments.some((arg) => couldBeFunction2(arg))) {
|
|
1079
|
-
context.report({
|
|
1080
|
-
messageId: "forbidden",
|
|
1081
|
-
node: node.callee
|
|
1082
|
-
});
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
};
|
|
1086
|
-
}
|
|
1087
|
-
});
|
|
1088
|
-
|
|
1089
|
-
// src/rules/no-create.ts
|
|
1090
|
-
var noCreateRule = ruleCreator({
|
|
1091
|
-
defaultOptions: [],
|
|
1092
|
-
meta: {
|
|
1093
|
-
docs: {
|
|
1094
|
-
description: "Disallow the static `Observable.create` and `Subject.create` functions.",
|
|
1095
|
-
recommended: "recommended",
|
|
1096
|
-
requiresTypeChecking: true
|
|
1097
|
-
},
|
|
1098
|
-
messages: {
|
|
1099
|
-
forbidden: "Observable.create is forbidden; use new Observable.",
|
|
1100
|
-
forbiddenSubject: "Subject.create is forbidden."
|
|
1101
|
-
},
|
|
1102
|
-
schema: [],
|
|
1103
|
-
type: "problem"
|
|
1104
|
-
},
|
|
1105
|
-
name: "no-create",
|
|
1106
|
-
create: (context) => {
|
|
1107
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
1108
|
-
return {
|
|
1109
|
-
"CallExpression > MemberExpression[object.name='Observable'] > Identifier[name='create']": (node) => {
|
|
1110
|
-
const memberExpression = node.parent;
|
|
1111
|
-
if (couldBeObservable(memberExpression.object)) {
|
|
1112
|
-
context.report({
|
|
1113
|
-
messageId: "forbidden",
|
|
1114
|
-
node
|
|
1115
|
-
});
|
|
1116
|
-
}
|
|
1117
|
-
},
|
|
1118
|
-
"CallExpression > MemberExpression[object.name=/^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/] > Identifier[name='create']": (node) => {
|
|
1119
|
-
const memberExpression = node.parent;
|
|
1120
|
-
if (couldBeType2(memberExpression.object, /^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/)) {
|
|
1121
|
-
context.report({
|
|
1122
|
-
messageId: "forbiddenSubject",
|
|
1123
|
-
node
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
};
|
|
1128
|
-
}
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
// src/rules/no-cyclic-action.ts
|
|
1132
|
-
import { ESLintUtils as ESLintUtils4 } from "@typescript-eslint/utils";
|
|
1133
|
-
import { stripIndent as stripIndent3 } from "common-tags";
|
|
1134
|
-
import ts4 from "typescript";
|
|
1135
|
-
|
|
1136
|
-
// src/constants.ts
|
|
1137
|
-
var defaultObservable = String.raw`[Aa]ction(s|s\$|\$)$`;
|
|
1138
|
-
var SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
1139
|
-
"combineLatest",
|
|
1140
|
-
"forkJoin"
|
|
1141
|
-
];
|
|
1142
|
-
var MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
|
|
1143
|
-
"combineLatest",
|
|
1144
|
-
"forkJoin",
|
|
1145
|
-
"merge",
|
|
1146
|
-
"zip",
|
|
1147
|
-
"concat",
|
|
1148
|
-
"race"
|
|
1149
|
-
];
|
|
1150
|
-
var DEFAULT_UNBOUND_ALLOWED_TYPES = [
|
|
1151
|
-
"Signal"
|
|
1152
|
-
];
|
|
1153
|
-
var DEFAULT_VALID_POST_COMPLETION_OPERATORS = [
|
|
1154
|
-
"count",
|
|
1155
|
-
"defaultIfEmpty",
|
|
1156
|
-
"endWith",
|
|
1157
|
-
"every",
|
|
1158
|
-
"finalize",
|
|
1159
|
-
"finally",
|
|
1160
|
-
"isEmpty",
|
|
1161
|
-
"last",
|
|
1162
|
-
"max",
|
|
1163
|
-
"min",
|
|
1164
|
-
"publish",
|
|
1165
|
-
"publishBehavior",
|
|
1166
|
-
"publishLast",
|
|
1167
|
-
"publishReplay",
|
|
1168
|
-
"reduce",
|
|
1169
|
-
"share",
|
|
1170
|
-
"shareReplay",
|
|
1171
|
-
"skipLast",
|
|
1172
|
-
"takeLast",
|
|
1173
|
-
"throwIfEmpty",
|
|
1174
|
-
"toArray"
|
|
1175
|
-
];
|
|
1176
|
-
|
|
1177
|
-
// src/rules/no-cyclic-action.ts
|
|
1178
|
-
function isTypeReference2(type) {
|
|
1179
|
-
return Boolean(type.target);
|
|
1180
|
-
}
|
|
1181
|
-
var defaultOptions4 = [];
|
|
1182
|
-
var noCyclicActionRule = ruleCreator({
|
|
1183
|
-
defaultOptions: defaultOptions4,
|
|
1184
|
-
meta: {
|
|
1185
|
-
docs: {
|
|
1186
|
-
description: "Disallow cyclic actions in effects and epics.",
|
|
1187
|
-
requiresTypeChecking: true
|
|
1188
|
-
},
|
|
1189
|
-
messages: {
|
|
1190
|
-
forbidden: "Effects and epics that re-emit filtered actions are forbidden."
|
|
1191
|
-
},
|
|
1192
|
-
schema: [
|
|
1193
|
-
{
|
|
1194
|
-
properties: {
|
|
1195
|
-
observable: { type: "string", description: "A RegExp that matches an effect or epic's actions observable.", default: defaultObservable }
|
|
1196
|
-
},
|
|
1197
|
-
type: "object",
|
|
1198
|
-
description: stripIndent3`
|
|
1199
|
-
An optional object with an optional \`observable\` property.
|
|
1200
|
-
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`
|
|
1201
|
-
}
|
|
1202
|
-
],
|
|
1203
|
-
type: "problem"
|
|
1204
|
-
},
|
|
1205
|
-
name: "no-cyclic-action",
|
|
1206
|
-
create: (context) => {
|
|
1207
|
-
const [config = {}] = context.options;
|
|
1208
|
-
const { observable = defaultObservable } = config;
|
|
1209
|
-
const observableRegExp = new RegExp(observable);
|
|
1210
|
-
const { getTypeAtLocation, program } = ESLintUtils4.getParserServices(context);
|
|
1211
|
-
const typeChecker = program.getTypeChecker();
|
|
1212
|
-
function checkNode(pipeCallExpression) {
|
|
1213
|
-
const operatorCallExpression = pipeCallExpression.arguments.find(
|
|
1214
|
-
(arg) => isCallExpression(arg) && isIdentifier(arg.callee) && arg.callee.name === "ofType"
|
|
1215
|
-
);
|
|
1216
|
-
if (!operatorCallExpression) {
|
|
1217
|
-
return;
|
|
1218
|
-
}
|
|
1219
|
-
const operatorType = getTypeAtLocation(operatorCallExpression);
|
|
1220
|
-
const [signature] = typeChecker.getSignaturesOfType(
|
|
1221
|
-
operatorType,
|
|
1222
|
-
ts4.SignatureKind.Call
|
|
1223
|
-
);
|
|
1224
|
-
if (!signature) {
|
|
1225
|
-
return;
|
|
1226
|
-
}
|
|
1227
|
-
const operatorReturnType = typeChecker.getReturnTypeOfSignature(signature);
|
|
1228
|
-
if (!isTypeReference2(operatorReturnType)) {
|
|
1229
|
-
return;
|
|
1230
|
-
}
|
|
1231
|
-
const [operatorElementType] = typeChecker.getTypeArguments(operatorReturnType);
|
|
1232
|
-
if (!operatorElementType) {
|
|
1233
|
-
return;
|
|
1234
|
-
}
|
|
1235
|
-
const pipeType = getTypeAtLocation(pipeCallExpression);
|
|
1236
|
-
if (!isTypeReference2(pipeType)) {
|
|
1237
|
-
return;
|
|
1238
|
-
}
|
|
1239
|
-
const [pipeElementType] = typeChecker.getTypeArguments(pipeType);
|
|
1240
|
-
if (!pipeElementType) {
|
|
1241
|
-
return;
|
|
1242
|
-
}
|
|
1243
|
-
const operatorActionTypes = getActionTypes(operatorElementType);
|
|
1244
|
-
const pipeActionTypes = getActionTypes(pipeElementType);
|
|
1245
|
-
for (const actionType of operatorActionTypes) {
|
|
1246
|
-
if (pipeActionTypes.includes(actionType)) {
|
|
1247
|
-
context.report({
|
|
1248
|
-
messageId: "forbidden",
|
|
1249
|
-
node: pipeCallExpression.callee
|
|
1250
|
-
});
|
|
1251
|
-
return;
|
|
1252
|
-
}
|
|
1253
|
-
}
|
|
1254
|
-
}
|
|
1255
|
-
function getActionTypes(type) {
|
|
1256
|
-
if (type.isUnion()) {
|
|
1257
|
-
const memberActionTypes = [];
|
|
1258
|
-
for (const memberType of type.types) {
|
|
1259
|
-
memberActionTypes.push(...getActionTypes(memberType));
|
|
1260
|
-
}
|
|
1261
|
-
return memberActionTypes;
|
|
1262
|
-
}
|
|
1263
|
-
const symbol = typeChecker.getPropertyOfType(type, "type");
|
|
1264
|
-
if (!(symbol == null ? void 0 : symbol.valueDeclaration)) {
|
|
1265
|
-
return [];
|
|
1266
|
-
}
|
|
1267
|
-
const actionType = typeChecker.getTypeOfSymbolAtLocation(
|
|
1268
|
-
symbol,
|
|
1269
|
-
symbol.valueDeclaration
|
|
1270
|
-
);
|
|
1271
|
-
return [typeChecker.typeToString(actionType)];
|
|
1272
|
-
}
|
|
1273
|
-
return {
|
|
1274
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.name=${observableRegExp}]`]: checkNode,
|
|
1275
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.property.name=${observableRegExp}]`]: checkNode
|
|
1276
|
-
};
|
|
1277
|
-
}
|
|
1278
|
-
});
|
|
1279
|
-
|
|
1280
|
-
// src/rules/no-explicit-generics.ts
|
|
1281
|
-
import { ESLintUtils as ESLintUtils5 } from "@typescript-eslint/utils";
|
|
1282
|
-
import * as tsutils3 from "ts-api-utils";
|
|
1283
|
-
var noExplicitGenericsRule = ruleCreator({
|
|
1284
|
-
defaultOptions: [],
|
|
1285
|
-
meta: {
|
|
1286
|
-
docs: {
|
|
1287
|
-
description: "Disallow unnecessary explicit generic type arguments.",
|
|
1288
|
-
requiresTypeChecking: true
|
|
1289
|
-
},
|
|
1290
|
-
messages: {
|
|
1291
|
-
forbidden: "Explicit generic type arguments are forbidden."
|
|
1292
|
-
},
|
|
1293
|
-
schema: [],
|
|
1294
|
-
type: "problem"
|
|
1295
|
-
},
|
|
1296
|
-
name: "no-explicit-generics",
|
|
1297
|
-
create: (context) => {
|
|
1298
|
-
function report(node) {
|
|
1299
|
-
context.report({
|
|
1300
|
-
messageId: "forbidden",
|
|
1301
|
-
node
|
|
1302
|
-
});
|
|
1303
|
-
}
|
|
1304
|
-
function isUnion(node) {
|
|
1305
|
-
if (!node) {
|
|
1306
|
-
return false;
|
|
1307
|
-
}
|
|
1308
|
-
if (isUnionType(node)) {
|
|
1309
|
-
return true;
|
|
1310
|
-
}
|
|
1311
|
-
const { getTypeAtLocation } = ESLintUtils5.getParserServices(context);
|
|
1312
|
-
const type = getTypeAtLocation(node);
|
|
1313
|
-
return tsutils3.isUnionOrIntersectionType(type);
|
|
1314
|
-
}
|
|
1315
|
-
function checkBehaviorSubjects(node) {
|
|
1316
|
-
var _a;
|
|
1317
|
-
const parent = node.parent;
|
|
1318
|
-
const {
|
|
1319
|
-
arguments: [value]
|
|
1320
|
-
} = parent;
|
|
1321
|
-
const typeArgs = (_a = parent.typeArguments) == null ? void 0 : _a.params[0];
|
|
1322
|
-
if (isArrayExpression(value) || isObjectExpression(value) || isUnion(typeArgs)) {
|
|
1323
|
-
return;
|
|
1324
|
-
}
|
|
1325
|
-
report(node);
|
|
1326
|
-
}
|
|
1327
|
-
function checkNotifications(node) {
|
|
1328
|
-
var _a;
|
|
1329
|
-
const parent = node.parent;
|
|
1330
|
-
const {
|
|
1331
|
-
arguments: [, value]
|
|
1332
|
-
} = parent;
|
|
1333
|
-
const typeArgs = (_a = parent.typeArguments) == null ? void 0 : _a.params[0];
|
|
1334
|
-
if (isArrayExpression(value) || isObjectExpression(value) || isUnion(typeArgs)) {
|
|
1335
|
-
return;
|
|
1336
|
-
}
|
|
1337
|
-
report(node);
|
|
1338
|
-
}
|
|
1339
|
-
return {
|
|
1340
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[typeArguments.params.length > 0] > Identifier": report,
|
|
1341
|
-
"NewExpression[typeArguments.params.length > 0] > Identifier[name='BehaviorSubject']": checkBehaviorSubjects,
|
|
1342
|
-
"CallExpression[typeArguments.params.length > 0] > Identifier[name=/^(from|of)$/]": report,
|
|
1343
|
-
"NewExpression[typeArguments.params.length > 0][arguments.0.value='N'] > Identifier[name='Notification']": checkNotifications
|
|
1344
|
-
};
|
|
1345
|
-
}
|
|
1346
|
-
});
|
|
1347
|
-
|
|
1348
|
-
// src/rules/no-exposed-subjects.ts
|
|
1349
|
-
var defaultAllowedTypesRegExp = /^EventEmitter$/;
|
|
1350
|
-
var defaultOptions5 = [];
|
|
1351
|
-
var noExposedSubjectsRule = ruleCreator({
|
|
1352
|
-
defaultOptions: defaultOptions5,
|
|
1353
|
-
meta: {
|
|
1354
|
-
docs: {
|
|
1355
|
-
description: "Disallow public and protected subjects.",
|
|
1356
|
-
recommended: "strict",
|
|
1357
|
-
requiresTypeChecking: true
|
|
1358
|
-
},
|
|
1359
|
-
messages: {
|
|
1360
|
-
forbidden: "Subject '{{subject}}' must be private.",
|
|
1361
|
-
forbiddenAllowProtected: "Subject '{{subject}}' must be private or protected."
|
|
1362
|
-
},
|
|
1363
|
-
schema: [
|
|
1364
|
-
{
|
|
1365
|
-
properties: {
|
|
1366
|
-
allowProtected: { type: "boolean", description: "Allow protected subjects.", default: false }
|
|
1367
|
-
},
|
|
1368
|
-
type: "object"
|
|
1369
|
-
}
|
|
1370
|
-
],
|
|
1371
|
-
type: "problem"
|
|
1372
|
-
},
|
|
1373
|
-
name: "no-exposed-subjects",
|
|
1374
|
-
create: (context) => {
|
|
1375
|
-
const [config = {}] = context.options;
|
|
1376
|
-
const { allowProtected = false } = config;
|
|
1377
|
-
const { couldBeSubject, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
1378
|
-
const messageId = allowProtected ? "forbiddenAllowProtected" : "forbidden";
|
|
1379
|
-
const accessibilityRexExp = allowProtected ? /^(private|protected)$/ : /^private$/;
|
|
1380
|
-
function isSubject(node) {
|
|
1381
|
-
return couldBeSubject(node) && !couldBeType2(node, defaultAllowedTypesRegExp);
|
|
1382
|
-
}
|
|
1383
|
-
return {
|
|
1384
|
-
[`PropertyDefinition[accessibility!=${accessibilityRexExp}]`]: (node) => {
|
|
1385
|
-
if (isSubject(node)) {
|
|
1386
|
-
const { key } = node;
|
|
1387
|
-
if (isIdentifier(key)) {
|
|
1388
|
-
context.report({
|
|
1389
|
-
messageId,
|
|
1390
|
-
node: key,
|
|
1391
|
-
data: {
|
|
1392
|
-
subject: key.name
|
|
1393
|
-
}
|
|
1394
|
-
});
|
|
1395
|
-
}
|
|
1396
|
-
}
|
|
1397
|
-
},
|
|
1398
|
-
[`MethodDefinition[kind='constructor'] > FunctionExpression > TSParameterProperty[accessibility!=${accessibilityRexExp}] > Identifier`]: (node) => {
|
|
1399
|
-
if (isSubject(node)) {
|
|
1400
|
-
const { loc } = node;
|
|
1401
|
-
context.report({
|
|
1402
|
-
messageId,
|
|
1403
|
-
loc: {
|
|
1404
|
-
...loc,
|
|
1405
|
-
end: {
|
|
1406
|
-
...loc.start,
|
|
1407
|
-
column: loc.start.column + node.name.length
|
|
1408
|
-
}
|
|
1409
|
-
},
|
|
1410
|
-
data: {
|
|
1411
|
-
subject: node.name
|
|
1412
|
-
}
|
|
1413
|
-
});
|
|
1414
|
-
}
|
|
1415
|
-
},
|
|
1416
|
-
[`MethodDefinition[accessibility!=${accessibilityRexExp}][kind=/^(get|set)$/]`]: (node) => {
|
|
1417
|
-
if (isSubject(node)) {
|
|
1418
|
-
const key = node.key;
|
|
1419
|
-
context.report({
|
|
1420
|
-
messageId,
|
|
1421
|
-
node: key,
|
|
1422
|
-
data: {
|
|
1423
|
-
subject: key.name
|
|
1424
|
-
}
|
|
1425
|
-
});
|
|
1426
|
-
}
|
|
1427
|
-
},
|
|
1428
|
-
[`MethodDefinition[accessibility!=${accessibilityRexExp}][kind='method']`]: (node) => {
|
|
1429
|
-
const functionExpression = node.value;
|
|
1430
|
-
const returnType = functionExpression.returnType;
|
|
1431
|
-
if (!returnType) {
|
|
1432
|
-
return;
|
|
1433
|
-
}
|
|
1434
|
-
const typeAnnotation = returnType.typeAnnotation;
|
|
1435
|
-
if (!typeAnnotation) {
|
|
1436
|
-
return;
|
|
1437
|
-
}
|
|
1438
|
-
if (isSubject(typeAnnotation)) {
|
|
1439
|
-
const key = node.key;
|
|
1440
|
-
context.report({
|
|
1441
|
-
messageId,
|
|
1442
|
-
node: key,
|
|
1443
|
-
data: {
|
|
1444
|
-
subject: key.name
|
|
1445
|
-
}
|
|
1446
|
-
});
|
|
1447
|
-
}
|
|
1448
|
-
}
|
|
1449
|
-
};
|
|
1450
|
-
}
|
|
1451
|
-
});
|
|
1452
|
-
|
|
1453
|
-
// src/rules/no-finnish.ts
|
|
1454
|
-
import { ESLintUtils as ESLintUtils6 } from "@typescript-eslint/utils";
|
|
1455
|
-
var noFinnishRule = ruleCreator({
|
|
1456
|
-
defaultOptions: [],
|
|
1457
|
-
meta: {
|
|
1458
|
-
docs: {
|
|
1459
|
-
description: "Disallow Finnish notation.",
|
|
1460
|
-
requiresTypeChecking: true
|
|
1461
|
-
},
|
|
1462
|
-
messages: {
|
|
1463
|
-
forbidden: "Finnish notation is forbidden."
|
|
1464
|
-
},
|
|
1465
|
-
schema: [],
|
|
1466
|
-
type: "problem"
|
|
1467
|
-
},
|
|
1468
|
-
name: "no-finnish",
|
|
1469
|
-
create: (context) => {
|
|
1470
|
-
const { esTreeNodeToTSNodeMap } = ESLintUtils6.getParserServices(context);
|
|
1471
|
-
const { couldBeObservable, couldReturnObservable } = getTypeServices(context);
|
|
1472
|
-
function checkNode(nameNode, typeNode) {
|
|
1473
|
-
if (couldBeObservable(typeNode != null ? typeNode : nameNode) || couldReturnObservable(typeNode != null ? typeNode : nameNode)) {
|
|
1474
|
-
const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
|
|
1475
|
-
if (/[$]+$/.test(tsNode.getText())) {
|
|
1476
|
-
context.report({
|
|
1477
|
-
loc: getLoc(tsNode),
|
|
1478
|
-
messageId: "forbidden"
|
|
1479
|
-
});
|
|
1480
|
-
}
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
return {
|
|
1484
|
-
"ArrayPattern > Identifier[name=/[$]+$/]": (node) => {
|
|
1485
|
-
checkNode(node);
|
|
1486
|
-
},
|
|
1487
|
-
"ArrowFunctionExpression > Identifier[name=/[$]+$/]": (node) => {
|
|
1488
|
-
const parent = node.parent;
|
|
1489
|
-
if (node !== parent.body) {
|
|
1490
|
-
checkNode(node);
|
|
1491
|
-
}
|
|
1492
|
-
},
|
|
1493
|
-
"PropertyDefinition[key.name=/[$]+$/] > Identifier": (node) => {
|
|
1494
|
-
checkNode(node, node.parent);
|
|
1495
|
-
},
|
|
1496
|
-
"FunctionDeclaration > Identifier[name=/[$]+$/]": (node) => {
|
|
1497
|
-
const parent = node.parent;
|
|
1498
|
-
if (node === parent.id) {
|
|
1499
|
-
checkNode(node, parent);
|
|
1500
|
-
} else {
|
|
1501
|
-
checkNode(node);
|
|
1502
|
-
}
|
|
1503
|
-
},
|
|
1504
|
-
"FunctionExpression > Identifier[name=/[$]+$/]": (node) => {
|
|
1505
|
-
const parent = node.parent;
|
|
1506
|
-
if (node === parent.id) {
|
|
1507
|
-
checkNode(node, parent);
|
|
1508
|
-
} else {
|
|
1509
|
-
checkNode(node);
|
|
1510
|
-
}
|
|
1511
|
-
},
|
|
1512
|
-
"MethodDefinition[key.name=/[$]+$/]": (node) => {
|
|
1513
|
-
checkNode(node.key, node);
|
|
1514
|
-
},
|
|
1515
|
-
"ObjectExpression > Property[computed=false][key.name=/[$]+$/]": (node) => {
|
|
1516
|
-
checkNode(node.key);
|
|
1517
|
-
},
|
|
1518
|
-
"ObjectPattern > Property[value.name=/[$]+$/]": (node) => {
|
|
1519
|
-
checkNode(node.value);
|
|
1520
|
-
},
|
|
1521
|
-
"TSCallSignatureDeclaration > Identifier[name=/[$]+$/]": (node) => {
|
|
1522
|
-
checkNode(node);
|
|
1523
|
-
},
|
|
1524
|
-
"TSConstructSignatureDeclaration > Identifier[name=/[$]+$/]": (node) => {
|
|
1525
|
-
checkNode(node);
|
|
1526
|
-
},
|
|
1527
|
-
"TSParameterProperty > Identifier[name=/[$]+$/]": (node) => {
|
|
1528
|
-
checkNode(node);
|
|
1529
|
-
},
|
|
1530
|
-
"TSPropertySignature > Identifier[name=/[$]+$/]": (node) => {
|
|
1531
|
-
checkNode(node, node.parent);
|
|
1532
|
-
},
|
|
1533
|
-
"TSMethodSignature > Identifier[name=/[$]+$/]": (node) => {
|
|
1534
|
-
const parent = node.parent;
|
|
1535
|
-
if (node === parent.key) {
|
|
1536
|
-
checkNode(node, parent);
|
|
1537
|
-
} else {
|
|
1538
|
-
checkNode(node);
|
|
1539
|
-
}
|
|
1540
|
-
},
|
|
1541
|
-
"VariableDeclarator[id.name=/[$]+$/]": (node) => {
|
|
1542
|
-
var _a;
|
|
1543
|
-
checkNode(node.id, (_a = node.init) != null ? _a : node);
|
|
1544
|
-
}
|
|
1545
|
-
};
|
|
1546
|
-
}
|
|
1547
|
-
});
|
|
1548
|
-
|
|
1549
|
-
// src/rules/no-floating-observables.ts
|
|
1550
|
-
var defaultOptions6 = [];
|
|
1551
|
-
var messageBase = "Observables must be subscribed to, returned, converted to a promise and awaited, or be explicitly marked as ignored with the `void` operator.";
|
|
1552
|
-
var messageBaseNoVoid = "Observables must be subscribed to, returned, or converted to a promise and awaited.";
|
|
1553
|
-
var noFloatingObservablesRule = ruleCreator({
|
|
1554
|
-
defaultOptions: defaultOptions6,
|
|
1555
|
-
meta: {
|
|
1556
|
-
docs: {
|
|
1557
|
-
description: "Require Observables to be handled appropriately.",
|
|
1558
|
-
recommended: "strict",
|
|
1559
|
-
requiresTypeChecking: true
|
|
1560
|
-
},
|
|
1561
|
-
messages: {
|
|
1562
|
-
forbidden: messageBase,
|
|
1563
|
-
forbiddenNoVoid: messageBaseNoVoid
|
|
1564
|
-
},
|
|
1565
|
-
schema: [
|
|
1566
|
-
{
|
|
1567
|
-
properties: {
|
|
1568
|
-
ignoreVoid: { type: "boolean", default: true, description: "Whether to ignore `void` expressions." }
|
|
1569
|
-
},
|
|
1570
|
-
type: "object"
|
|
1571
|
-
}
|
|
1572
|
-
],
|
|
1573
|
-
type: "problem"
|
|
1574
|
-
},
|
|
1575
|
-
name: "no-floating-observables",
|
|
1576
|
-
create: (context) => {
|
|
1577
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
1578
|
-
const [config = {}] = context.options;
|
|
1579
|
-
const { ignoreVoid = true } = config;
|
|
1580
|
-
function checkNode(node) {
|
|
1581
|
-
if (couldBeObservable(node)) {
|
|
1582
|
-
context.report({
|
|
1583
|
-
messageId: ignoreVoid ? "forbidden" : "forbiddenNoVoid",
|
|
1584
|
-
node
|
|
1585
|
-
});
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
function checkVoid(node) {
|
|
1589
|
-
if (ignoreVoid) return;
|
|
1590
|
-
if (node.operator !== "void") return;
|
|
1591
|
-
let expression = node.argument;
|
|
1592
|
-
if (isChainExpression(expression)) {
|
|
1593
|
-
expression = expression.expression;
|
|
1594
|
-
}
|
|
1595
|
-
if (!isCallExpression(expression)) return;
|
|
1596
|
-
checkNode(expression);
|
|
1597
|
-
}
|
|
1598
|
-
return {
|
|
1599
|
-
"ExpressionStatement > CallExpression": (node) => {
|
|
1600
|
-
checkNode(node);
|
|
1601
|
-
},
|
|
1602
|
-
"ExpressionStatement > UnaryExpression": (node) => {
|
|
1603
|
-
checkVoid(node);
|
|
1604
|
-
},
|
|
1605
|
-
"ExpressionStatement > ChainExpression": (node) => {
|
|
1606
|
-
if (!isCallExpression(node.expression)) return;
|
|
1607
|
-
checkNode(node.expression);
|
|
1608
|
-
},
|
|
1609
|
-
"ExpressionStatement > SequenceExpression": (node) => {
|
|
1610
|
-
node.expressions.forEach((expression) => {
|
|
1611
|
-
if (isCallExpression(expression)) {
|
|
1612
|
-
checkNode(expression);
|
|
1613
|
-
}
|
|
1614
|
-
});
|
|
1615
|
-
},
|
|
1616
|
-
"ExpressionStatement > ArrayExpression": (node) => {
|
|
1617
|
-
node.elements.forEach((expression) => {
|
|
1618
|
-
if (!expression) return;
|
|
1619
|
-
if (isCallExpression(expression)) {
|
|
1620
|
-
checkNode(expression);
|
|
1621
|
-
} else if (isUnaryExpression(expression)) {
|
|
1622
|
-
checkVoid(expression);
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1625
|
-
}
|
|
1626
|
-
};
|
|
1627
|
-
}
|
|
1628
|
-
});
|
|
1629
|
-
|
|
1630
|
-
// src/rules/no-ignored-default-value.ts
|
|
1631
|
-
import { ESLintUtils as ESLintUtils7 } from "@typescript-eslint/utils";
|
|
1632
|
-
var noIgnoredDefaultValueRule = ruleCreator({
|
|
1633
|
-
defaultOptions: [],
|
|
1634
|
-
meta: {
|
|
1635
|
-
docs: {
|
|
1636
|
-
description: "Disallow using `firstValueFrom`, `lastValueFrom`, `first`, and `last` without specifying a default value.",
|
|
1637
|
-
recommended: "strict",
|
|
1638
|
-
requiresTypeChecking: true
|
|
1639
|
-
},
|
|
1640
|
-
messages: {
|
|
1641
|
-
forbidden: "Not specifying a default value is forbidden."
|
|
1642
|
-
},
|
|
1643
|
-
schema: [],
|
|
1644
|
-
type: "problem"
|
|
1645
|
-
},
|
|
1646
|
-
name: "no-ignored-default-value",
|
|
1647
|
-
create: (context) => {
|
|
1648
|
-
const { getTypeAtLocation } = ESLintUtils7.getParserServices(context);
|
|
1649
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
1650
|
-
function checkConfigObj(configArg) {
|
|
1651
|
-
if (!configArg.properties.some((p) => isProperty(p) && isIdentifier(p.key) && p.key.name === "defaultValue")) {
|
|
1652
|
-
context.report({
|
|
1653
|
-
messageId: "forbidden",
|
|
1654
|
-
node: configArg
|
|
1655
|
-
});
|
|
1656
|
-
}
|
|
1657
|
-
}
|
|
1658
|
-
function checkConfigType(configArg) {
|
|
1659
|
-
const configArgType = getTypeAtLocation(configArg);
|
|
1660
|
-
if (!(configArgType == null ? void 0 : configArgType.getProperties().some((p) => p.name === "defaultValue"))) {
|
|
1661
|
-
context.report({
|
|
1662
|
-
messageId: "forbidden",
|
|
1663
|
-
node: configArg
|
|
1664
|
-
});
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
function checkArg(arg) {
|
|
1668
|
-
if (isIdentifier(arg)) {
|
|
1669
|
-
checkConfigType(arg);
|
|
1670
|
-
return;
|
|
1671
|
-
} else if (isMemberExpression(arg) && isIdentifier(arg.property)) {
|
|
1672
|
-
checkConfigType(arg.property);
|
|
1673
|
-
return;
|
|
1674
|
-
}
|
|
1675
|
-
if (!isObjectExpression(arg)) {
|
|
1676
|
-
return;
|
|
1677
|
-
}
|
|
1678
|
-
checkConfigObj(arg);
|
|
1679
|
-
}
|
|
1680
|
-
function checkFunctionArgs(node, args) {
|
|
1681
|
-
if (!couldBeType2(node, "firstValueFrom", { name: /[/\\]rxjs[/\\]/ }) && !couldBeType2(node, "lastValueFrom", { name: /[/\\]rxjs[/\\]/ })) {
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
if (!args || args.length <= 0) {
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
|
-
const [observableArg, configArg] = args;
|
|
1688
|
-
if (!couldBeObservable(observableArg)) {
|
|
1689
|
-
return;
|
|
1690
|
-
}
|
|
1691
|
-
if (!configArg) {
|
|
1692
|
-
context.report({
|
|
1693
|
-
messageId: "forbidden",
|
|
1694
|
-
node
|
|
1695
|
-
});
|
|
1696
|
-
return;
|
|
1697
|
-
}
|
|
1698
|
-
checkArg(configArg);
|
|
1699
|
-
}
|
|
1700
|
-
function checkOperatorArgs(node, args) {
|
|
1701
|
-
if (!couldBeType2(node, "first", { name: /[/\\]rxjs[/\\]/ }) && !couldBeType2(node, "last", { name: /[/\\]rxjs[/\\]/ })) {
|
|
1702
|
-
return;
|
|
1703
|
-
}
|
|
1704
|
-
if (!args || args.length <= 0) {
|
|
1705
|
-
context.report({
|
|
1706
|
-
messageId: "forbidden",
|
|
1707
|
-
node
|
|
1708
|
-
});
|
|
1709
|
-
return;
|
|
1710
|
-
}
|
|
1711
|
-
const [arg] = args;
|
|
1712
|
-
checkArg(arg);
|
|
1713
|
-
}
|
|
1714
|
-
return {
|
|
1715
|
-
"CallExpression[callee.name=/^(firstValueFrom|lastValueFrom)$/]": (node) => {
|
|
1716
|
-
checkFunctionArgs(node.callee, node.arguments);
|
|
1717
|
-
},
|
|
1718
|
-
"CallExpression[callee.property.name=/^(firstValueFrom|lastValueFrom)$/]": (node) => {
|
|
1719
|
-
const memberExpression = node.callee;
|
|
1720
|
-
checkFunctionArgs(memberExpression.property, node.arguments);
|
|
1721
|
-
},
|
|
1722
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[callee.name=/^(first|last)$/]": (node) => {
|
|
1723
|
-
checkOperatorArgs(node.callee, node.arguments);
|
|
1724
|
-
},
|
|
1725
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[callee.property.name=/^(first|last)$/]": (node) => {
|
|
1726
|
-
const memberExpression = node.callee;
|
|
1727
|
-
checkOperatorArgs(memberExpression.property, node.arguments);
|
|
1728
|
-
}
|
|
1729
|
-
};
|
|
1730
|
-
}
|
|
1731
|
-
});
|
|
1732
|
-
|
|
1733
|
-
// src/rules/no-ignored-error.ts
|
|
1734
|
-
import { ESLintUtils as ESLintUtils8 } from "@typescript-eslint/utils";
|
|
1735
|
-
var noIgnoredErrorRule = ruleCreator({
|
|
1736
|
-
defaultOptions: [],
|
|
1737
|
-
meta: {
|
|
1738
|
-
docs: {
|
|
1739
|
-
description: "Disallow calling `subscribe` without specifying an error handler.",
|
|
1740
|
-
recommended: "strict",
|
|
1741
|
-
requiresTypeChecking: true
|
|
1742
|
-
},
|
|
1743
|
-
messages: {
|
|
1744
|
-
forbidden: "Calling subscribe without an error handler is forbidden."
|
|
1745
|
-
},
|
|
1746
|
-
schema: [],
|
|
1747
|
-
type: "problem"
|
|
1748
|
-
},
|
|
1749
|
-
name: "no-ignored-error",
|
|
1750
|
-
create: (context) => {
|
|
1751
|
-
const { getTypeAtLocation } = ESLintUtils8.getParserServices(context);
|
|
1752
|
-
const { couldBeObservable, couldBeFunction: couldBeFunction2 } = getTypeServices(context);
|
|
1753
|
-
function isMissingErrorCallback(callExpression) {
|
|
1754
|
-
if (callExpression.arguments.length >= 2) {
|
|
1755
|
-
return false;
|
|
1756
|
-
}
|
|
1757
|
-
return couldBeFunction2(callExpression.arguments[0]);
|
|
1758
|
-
}
|
|
1759
|
-
function isObjMissingError(arg) {
|
|
1760
|
-
return !arg.properties.some(
|
|
1761
|
-
(property) => isProperty(property) && isIdentifier(property.key) && property.key.name === "error"
|
|
1762
|
-
);
|
|
1763
|
-
}
|
|
1764
|
-
function isTypeMissingError(arg) {
|
|
1765
|
-
const argType = getTypeAtLocation(arg);
|
|
1766
|
-
return !(argType == null ? void 0 : argType.getProperties().some((p) => p.name === "error"));
|
|
1767
|
-
}
|
|
1768
|
-
function isMissingErrorProperty(callExpression) {
|
|
1769
|
-
if (callExpression.arguments.length !== 1) {
|
|
1770
|
-
return false;
|
|
1771
|
-
}
|
|
1772
|
-
const [arg] = callExpression.arguments;
|
|
1773
|
-
if (isObjectExpression(arg)) {
|
|
1774
|
-
return isObjMissingError(arg);
|
|
1775
|
-
}
|
|
1776
|
-
if (isIdentifier(arg)) {
|
|
1777
|
-
return isTypeMissingError(arg);
|
|
1778
|
-
}
|
|
1779
|
-
if (isMemberExpression(arg) && isIdentifier(arg.property)) {
|
|
1780
|
-
return isTypeMissingError(arg.property);
|
|
1781
|
-
}
|
|
1782
|
-
return false;
|
|
1783
|
-
}
|
|
1784
|
-
return {
|
|
1785
|
-
"CallExpression[arguments.length > 0] > MemberExpression > Identifier[name='subscribe']": (node) => {
|
|
1786
|
-
const memberExpression = node.parent;
|
|
1787
|
-
const callExpression = memberExpression.parent;
|
|
1788
|
-
if ((isMissingErrorCallback(callExpression) || isMissingErrorProperty(callExpression)) && couldBeObservable(memberExpression.object)) {
|
|
1789
|
-
context.report({
|
|
1790
|
-
messageId: "forbidden",
|
|
1791
|
-
node
|
|
1792
|
-
});
|
|
1793
|
-
}
|
|
1794
|
-
}
|
|
1795
|
-
};
|
|
1796
|
-
}
|
|
1797
|
-
});
|
|
1798
|
-
|
|
1799
|
-
// src/rules/no-ignored-notifier.ts
|
|
1800
|
-
var noIgnoredNotifierRule = ruleCreator({
|
|
1801
|
-
defaultOptions: [],
|
|
1802
|
-
meta: {
|
|
1803
|
-
docs: {
|
|
1804
|
-
description: "Disallow observables not composed from the `repeatWhen` or `retryWhen` notifier.",
|
|
1805
|
-
recommended: "recommended",
|
|
1806
|
-
requiresTypeChecking: true
|
|
1807
|
-
},
|
|
1808
|
-
messages: {
|
|
1809
|
-
forbidden: "Ignoring the notifier is forbidden."
|
|
1810
|
-
},
|
|
1811
|
-
schema: [],
|
|
1812
|
-
type: "problem"
|
|
1813
|
-
},
|
|
1814
|
-
name: "no-ignored-notifier",
|
|
1815
|
-
create: (context) => {
|
|
1816
|
-
const { couldBeMonoTypeOperatorFunction } = getTypeServices(context);
|
|
1817
|
-
const entries = [];
|
|
1818
|
-
function getEntry() {
|
|
1819
|
-
const { length, [length - 1]: entry } = entries;
|
|
1820
|
-
return entry;
|
|
1821
|
-
}
|
|
1822
|
-
return {
|
|
1823
|
-
"CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]": (node) => {
|
|
1824
|
-
if (couldBeMonoTypeOperatorFunction(node)) {
|
|
1825
|
-
const [arg] = node.arguments;
|
|
1826
|
-
if (isArrowFunctionExpression(arg) || isFunctionExpression(arg)) {
|
|
1827
|
-
const [param] = arg.params;
|
|
1828
|
-
if (param) {
|
|
1829
|
-
entries.push({
|
|
1830
|
-
node,
|
|
1831
|
-
param,
|
|
1832
|
-
sightings: 0
|
|
1833
|
-
});
|
|
1834
|
-
} else {
|
|
1835
|
-
context.report({
|
|
1836
|
-
messageId: "forbidden",
|
|
1837
|
-
node: node.callee
|
|
1838
|
-
});
|
|
1839
|
-
}
|
|
1840
|
-
}
|
|
1841
|
-
}
|
|
1842
|
-
},
|
|
1843
|
-
"CallExpression[callee.name=/^(repeatWhen|retryWhen)$/]:exit": (node) => {
|
|
1844
|
-
const entry = getEntry();
|
|
1845
|
-
if (!entry) {
|
|
1846
|
-
return;
|
|
1847
|
-
}
|
|
1848
|
-
if (entry.node === node) {
|
|
1849
|
-
if (entry.sightings < 2) {
|
|
1850
|
-
context.report({
|
|
1851
|
-
messageId: "forbidden",
|
|
1852
|
-
node: node.callee
|
|
1853
|
-
});
|
|
1854
|
-
}
|
|
1855
|
-
entries.pop();
|
|
1856
|
-
}
|
|
1857
|
-
},
|
|
1858
|
-
"Identifier": (node) => {
|
|
1859
|
-
const entry = getEntry();
|
|
1860
|
-
if (!entry) {
|
|
1861
|
-
return;
|
|
1862
|
-
}
|
|
1863
|
-
if (node.name === entry.param.name) {
|
|
1864
|
-
++entry.sightings;
|
|
1865
|
-
}
|
|
1866
|
-
}
|
|
1867
|
-
};
|
|
1868
|
-
}
|
|
1869
|
-
});
|
|
1870
|
-
|
|
1871
|
-
// src/rules/no-ignored-observable.ts
|
|
1872
|
-
var noIgnoredObservableRule = ruleCreator({
|
|
1873
|
-
defaultOptions: [],
|
|
1874
|
-
meta: {
|
|
1875
|
-
deprecated: true,
|
|
1876
|
-
docs: {
|
|
1877
|
-
description: "Disallow ignoring of observables returned by functions."
|
|
1878
|
-
},
|
|
1879
|
-
messages: {
|
|
1880
|
-
forbidden: "Ignoring a returned Observable is forbidden."
|
|
1881
|
-
},
|
|
1882
|
-
replacedBy: ["no-floating-observables"],
|
|
1883
|
-
schema: [],
|
|
1884
|
-
type: "problem"
|
|
1885
|
-
},
|
|
1886
|
-
name: "no-ignored-observable",
|
|
1887
|
-
create: (context) => {
|
|
1888
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
1889
|
-
return {
|
|
1890
|
-
"ExpressionStatement > CallExpression": (node) => {
|
|
1891
|
-
if (couldBeObservable(node)) {
|
|
1892
|
-
context.report({
|
|
1893
|
-
messageId: "forbidden",
|
|
1894
|
-
node
|
|
1895
|
-
});
|
|
1896
|
-
}
|
|
1897
|
-
}
|
|
1898
|
-
};
|
|
1899
|
-
}
|
|
1900
|
-
});
|
|
1901
|
-
|
|
1902
|
-
// src/rules/no-ignored-replay-buffer.ts
|
|
1903
|
-
var noIgnoredReplayBufferRule = ruleCreator({
|
|
1904
|
-
defaultOptions: [],
|
|
1905
|
-
meta: {
|
|
1906
|
-
docs: {
|
|
1907
|
-
description: "Disallow using `ReplaySubject`, `publishReplay` or `shareReplay` without specifying the buffer size.",
|
|
1908
|
-
recommended: "recommended"
|
|
1909
|
-
},
|
|
1910
|
-
messages: {
|
|
1911
|
-
forbidden: "Ignoring the buffer size is forbidden."
|
|
1912
|
-
},
|
|
1913
|
-
schema: [],
|
|
1914
|
-
type: "problem"
|
|
1915
|
-
},
|
|
1916
|
-
name: "no-ignored-replay-buffer",
|
|
1917
|
-
create: (context) => {
|
|
1918
|
-
function checkShareReplayConfig(node, shareReplayConfigArg) {
|
|
1919
|
-
if (!shareReplayConfigArg.properties.some((p) => isProperty(p) && isIdentifier(p.key) && p.key.name === "bufferSize")) {
|
|
1920
|
-
context.report({
|
|
1921
|
-
messageId: "forbidden",
|
|
1922
|
-
node
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
function checkNode(node, { arguments: args }) {
|
|
1927
|
-
if (!args || args.length === 0) {
|
|
1928
|
-
context.report({
|
|
1929
|
-
messageId: "forbidden",
|
|
1930
|
-
node
|
|
1931
|
-
});
|
|
1932
|
-
}
|
|
1933
|
-
if (node.name === "shareReplay" && (args == null ? void 0 : args.length) === 1) {
|
|
1934
|
-
const [arg] = args;
|
|
1935
|
-
if (isObjectExpression(arg)) {
|
|
1936
|
-
checkShareReplayConfig(node, arg);
|
|
1937
|
-
}
|
|
1938
|
-
}
|
|
1939
|
-
}
|
|
1940
|
-
return {
|
|
1941
|
-
"NewExpression > Identifier[name='ReplaySubject']": (node) => {
|
|
1942
|
-
const newExpression = node.parent;
|
|
1943
|
-
checkNode(node, newExpression);
|
|
1944
|
-
},
|
|
1945
|
-
"NewExpression > MemberExpression > Identifier[name='ReplaySubject']": (node) => {
|
|
1946
|
-
const memberExpression = node.parent;
|
|
1947
|
-
const newExpression = memberExpression.parent;
|
|
1948
|
-
checkNode(node, newExpression);
|
|
1949
|
-
},
|
|
1950
|
-
"CallExpression > Identifier[name=/^(publishReplay|shareReplay)$/]": (node) => {
|
|
1951
|
-
const callExpression = node.parent;
|
|
1952
|
-
checkNode(node, callExpression);
|
|
1953
|
-
},
|
|
1954
|
-
"CallExpression > MemberExpression > Identifier[name=/^(publishReplay|shareReplay)$/]": (node) => {
|
|
1955
|
-
const memberExpression = node.parent;
|
|
1956
|
-
const callExpression = memberExpression.parent;
|
|
1957
|
-
checkNode(node, callExpression);
|
|
1958
|
-
}
|
|
1959
|
-
};
|
|
1960
|
-
}
|
|
1961
|
-
});
|
|
1962
|
-
|
|
1963
|
-
// src/rules/no-ignored-subscribe.ts
|
|
1964
|
-
var noIgnoredSubscribeRule = ruleCreator({
|
|
1965
|
-
defaultOptions: [],
|
|
1966
|
-
meta: {
|
|
1967
|
-
docs: {
|
|
1968
|
-
description: "Disallow calling `subscribe` without specifying arguments.",
|
|
1969
|
-
requiresTypeChecking: true
|
|
1970
|
-
},
|
|
1971
|
-
messages: {
|
|
1972
|
-
forbidden: "Calling subscribe without arguments is forbidden."
|
|
1973
|
-
},
|
|
1974
|
-
schema: [],
|
|
1975
|
-
type: "problem"
|
|
1976
|
-
},
|
|
1977
|
-
name: "no-ignored-subscribe",
|
|
1978
|
-
create: (context) => {
|
|
1979
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
1980
|
-
return {
|
|
1981
|
-
"CallExpression[arguments.length = 0][callee.property.name='subscribe']": (node) => {
|
|
1982
|
-
const callee = node.callee;
|
|
1983
|
-
if (couldBeObservable(callee.object) || couldBeType2(callee.object, "Subscribable")) {
|
|
1984
|
-
context.report({
|
|
1985
|
-
messageId: "forbidden",
|
|
1986
|
-
node: callee.property
|
|
1987
|
-
});
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
};
|
|
1991
|
-
}
|
|
1992
|
-
});
|
|
1993
|
-
|
|
1994
|
-
// src/rules/no-ignored-subscription.ts
|
|
1995
|
-
import { stripIndent as stripIndent4 } from "common-tags";
|
|
1996
|
-
var defaultOptions7 = [];
|
|
1997
|
-
var noIgnoredSubscriptionRule = ruleCreator({
|
|
1998
|
-
defaultOptions: defaultOptions7,
|
|
1999
|
-
meta: {
|
|
2000
|
-
docs: {
|
|
2001
|
-
description: "Disallow ignoring the subscription returned by `subscribe`.",
|
|
2002
|
-
requiresTypeChecking: true
|
|
2003
|
-
},
|
|
2004
|
-
messages: {
|
|
2005
|
-
forbidden: "Ignoring returned subscriptions is forbidden."
|
|
2006
|
-
},
|
|
2007
|
-
schema: [
|
|
2008
|
-
{
|
|
2009
|
-
properties: {
|
|
2010
|
-
completers: { type: "array", items: { type: "string" }, description: "An array of operator names that will complete the observable and silence this rule.", default: ["takeUntil", "takeWhile", "take", "first", "last", "takeUntilDestroyed"] },
|
|
2011
|
-
postCompleters: { type: "array", items: { type: "string" }, description: "An array of operator names that are allowed to follow the completion operators.", default: DEFAULT_VALID_POST_COMPLETION_OPERATORS }
|
|
2012
|
-
},
|
|
2013
|
-
type: "object",
|
|
2014
|
-
description: stripIndent4`
|
|
2015
|
-
An object with optional \`completers\` and \`postCompleters\` properties.
|
|
2016
|
-
The \`completers\` property is an array containing the names of operators that will complete the observable and silence this rule.
|
|
2017
|
-
The \`postCompleters\` property is an array containing the names of the operators that are allowed to follow the completion operators.
|
|
2018
|
-
`
|
|
2019
|
-
}
|
|
2020
|
-
],
|
|
2021
|
-
type: "problem"
|
|
2022
|
-
},
|
|
2023
|
-
name: "no-ignored-subscription",
|
|
2024
|
-
create: (context) => {
|
|
2025
|
-
const [config = {}] = context.options;
|
|
2026
|
-
const {
|
|
2027
|
-
completers = ["takeUntil", "takeWhile", "take", "first", "last", "takeUntilDestroyed"],
|
|
2028
|
-
postCompleters = DEFAULT_VALID_POST_COMPLETION_OPERATORS
|
|
2029
|
-
} = config;
|
|
2030
|
-
const checkedOperatorsRegExp = new RegExp(
|
|
2031
|
-
`^(${completers.join("|")})$`
|
|
2032
|
-
);
|
|
2033
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
2034
|
-
function hasAllowedOperator(node) {
|
|
2035
|
-
if (isCallExpression(node) && isMemberExpression(node.callee) && isIdentifier(node.callee.property) && node.callee.property.name === "pipe") {
|
|
2036
|
-
const { isOrderValid, operatorNode } = findIsLastOperatorOrderValid(
|
|
2037
|
-
node,
|
|
2038
|
-
checkedOperatorsRegExp,
|
|
2039
|
-
postCompleters
|
|
2040
|
-
);
|
|
2041
|
-
return isOrderValid && !!operatorNode;
|
|
2042
|
-
}
|
|
2043
|
-
return false;
|
|
2044
|
-
}
|
|
2045
|
-
return {
|
|
2046
|
-
"ExpressionStatement > CallExpression > MemberExpression[property.name='subscribe']": (node) => {
|
|
2047
|
-
if (couldBeObservable(node.object)) {
|
|
2048
|
-
const callExpression = node.parent;
|
|
2049
|
-
if (callExpression.arguments.length === 1 && couldBeType2(callExpression.arguments[0], "Subscriber")) {
|
|
2050
|
-
return;
|
|
2051
|
-
}
|
|
2052
|
-
if (hasAllowedOperator(node.object)) {
|
|
2053
|
-
return;
|
|
2054
|
-
}
|
|
2055
|
-
context.report({
|
|
2056
|
-
messageId: "forbidden",
|
|
2057
|
-
node: node.property
|
|
2058
|
-
});
|
|
2059
|
-
}
|
|
2060
|
-
}
|
|
2061
|
-
};
|
|
2062
|
-
}
|
|
2063
|
-
});
|
|
2064
|
-
|
|
2065
|
-
// src/rules/no-ignored-takewhile-value.ts
|
|
2066
|
-
var noIgnoredTakewhileValueRule = ruleCreator({
|
|
2067
|
-
defaultOptions: [],
|
|
2068
|
-
meta: {
|
|
2069
|
-
docs: {
|
|
2070
|
-
description: "Disallow ignoring the value within `takeWhile`.",
|
|
2071
|
-
recommended: "recommended"
|
|
2072
|
-
},
|
|
2073
|
-
messages: {
|
|
2074
|
-
forbidden: "Ignoring the value within takeWhile is forbidden."
|
|
2075
|
-
},
|
|
2076
|
-
schema: [],
|
|
2077
|
-
type: "problem"
|
|
2078
|
-
},
|
|
2079
|
-
name: "no-ignored-takewhile-value",
|
|
2080
|
-
create: (context) => {
|
|
2081
|
-
function checkNode(expression) {
|
|
2082
|
-
const scope = context.sourceCode.getScope(expression);
|
|
2083
|
-
if (!isImport(scope, "takeWhile", /^rxjs\/?/)) {
|
|
2084
|
-
return;
|
|
2085
|
-
}
|
|
2086
|
-
let ignored = true;
|
|
2087
|
-
const [param] = expression.params;
|
|
2088
|
-
if (param) {
|
|
2089
|
-
if (isIdentifier(param)) {
|
|
2090
|
-
const variable = scope.variables.find(
|
|
2091
|
-
({ name: name2 }) => name2 === param.name
|
|
2092
|
-
);
|
|
2093
|
-
if (variable && variable.references.length > 0) {
|
|
2094
|
-
ignored = false;
|
|
2095
|
-
}
|
|
2096
|
-
} else if (isArrayPattern(param)) {
|
|
2097
|
-
ignored = false;
|
|
2098
|
-
} else if (isObjectPattern(param)) {
|
|
2099
|
-
ignored = false;
|
|
2100
|
-
}
|
|
2101
|
-
}
|
|
2102
|
-
if (ignored) {
|
|
2103
|
-
context.report({
|
|
2104
|
-
messageId: "forbidden",
|
|
2105
|
-
node: expression
|
|
2106
|
-
});
|
|
2107
|
-
}
|
|
2108
|
-
}
|
|
2109
|
-
return {
|
|
2110
|
-
"CallExpression[callee.name='takeWhile'] > ArrowFunctionExpression": (node) => {
|
|
2111
|
-
checkNode(node);
|
|
2112
|
-
},
|
|
2113
|
-
"CallExpression[callee.name='takeWhile'] > FunctionExpression": (node) => {
|
|
2114
|
-
checkNode(node);
|
|
2115
|
-
}
|
|
2116
|
-
};
|
|
2117
|
-
}
|
|
2118
|
-
});
|
|
2119
|
-
|
|
2120
|
-
// src/rules/no-implicit-any-catch.ts
|
|
2121
|
-
import {
|
|
2122
|
-
AST_NODE_TYPES as AST_NODE_TYPES4
|
|
2123
|
-
} from "@typescript-eslint/utils";
|
|
2124
|
-
function isParenthesised(sourceCode, node) {
|
|
2125
|
-
const before = sourceCode.getTokenBefore(node);
|
|
2126
|
-
const after = sourceCode.getTokenAfter(node);
|
|
2127
|
-
return before && after && before.value === "(" && before.range[1] <= node.range[0] && after.value === ")" && after.range[0] >= node.range[1];
|
|
2128
|
-
}
|
|
2129
|
-
var defaultOptions8 = [];
|
|
2130
|
-
var noImplicitAnyCatchRule = ruleCreator({
|
|
2131
|
-
defaultOptions: defaultOptions8,
|
|
2132
|
-
meta: {
|
|
2133
|
-
docs: {
|
|
2134
|
-
description: "Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`.",
|
|
2135
|
-
recommended: {
|
|
2136
|
-
recommended: true,
|
|
2137
|
-
strict: [{
|
|
2138
|
-
allowExplicitAny: false
|
|
2139
|
-
}]
|
|
2140
|
-
},
|
|
2141
|
-
requiresTypeChecking: true
|
|
2142
|
-
},
|
|
2143
|
-
fixable: "code",
|
|
2144
|
-
hasSuggestions: true,
|
|
2145
|
-
messages: {
|
|
2146
|
-
explicitAny: "Explicit `any` in error callback.",
|
|
2147
|
-
implicitAny: "Implicit `any` in error callback.",
|
|
2148
|
-
narrowed: "Error type must be `unknown` or `any`.",
|
|
2149
|
-
narrowedAllowError: "Error type must be `unknown`, `any`, or `Error`.",
|
|
2150
|
-
suggestExplicitUnknown: "Use `unknown` instead to explicitly and safely assert the type is correct.",
|
|
2151
|
-
suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety.",
|
|
2152
|
-
suggestExplicitError: "Use `Error` instead."
|
|
2153
|
-
},
|
|
2154
|
-
schema: [
|
|
2155
|
-
{
|
|
2156
|
-
additionalProperties: false,
|
|
2157
|
-
properties: {
|
|
2158
|
-
allowExplicitAny: {
|
|
2159
|
-
type: "boolean",
|
|
2160
|
-
description: "Allow error variable to be explicitly typed as `any`.",
|
|
2161
|
-
default: true
|
|
2162
|
-
},
|
|
2163
|
-
allowExplicitError: {
|
|
2164
|
-
type: "boolean",
|
|
2165
|
-
description: "Allow narrowing error type to `Error`.",
|
|
2166
|
-
default: false
|
|
2167
|
-
}
|
|
2168
|
-
},
|
|
2169
|
-
type: "object"
|
|
2170
|
-
}
|
|
2171
|
-
],
|
|
2172
|
-
type: "suggestion"
|
|
2173
|
-
},
|
|
2174
|
-
name: "no-implicit-any-catch",
|
|
2175
|
-
create: (context) => {
|
|
2176
|
-
const [config = {}] = context.options;
|
|
2177
|
-
const { allowExplicitAny = true, allowExplicitError = false } = config;
|
|
2178
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
2179
|
-
const sourceCode = context.sourceCode;
|
|
2180
|
-
function createReplacerFix(typeAnnotation, replaceWith) {
|
|
2181
|
-
return function fix(fixer) {
|
|
2182
|
-
return fixer.replaceText(typeAnnotation, `: ${replaceWith}`);
|
|
2183
|
-
};
|
|
2184
|
-
}
|
|
2185
|
-
function createInserterFix(param, annotateWith, { hasRestParams = false } = {}) {
|
|
2186
|
-
return function fix(fixer) {
|
|
2187
|
-
if (hasRestParams || isParenthesised(sourceCode, param)) {
|
|
2188
|
-
return fixer.insertTextAfter(param, `: ${annotateWith}`);
|
|
2189
|
-
}
|
|
2190
|
-
return [
|
|
2191
|
-
fixer.insertTextBefore(param, "("),
|
|
2192
|
-
fixer.insertTextAfter(param, `: ${annotateWith})`)
|
|
2193
|
-
];
|
|
2194
|
-
};
|
|
2195
|
-
}
|
|
2196
|
-
function checkCallback(callback) {
|
|
2197
|
-
if (isArrowFunctionExpression(callback) || isFunctionExpression(callback)) {
|
|
2198
|
-
const [param, ...restParams] = callback.params;
|
|
2199
|
-
if (!param) {
|
|
2200
|
-
return;
|
|
2201
|
-
}
|
|
2202
|
-
if (hasTypeAnnotation(param)) {
|
|
2203
|
-
const { typeAnnotation } = param;
|
|
2204
|
-
const {
|
|
2205
|
-
typeAnnotation: { type }
|
|
2206
|
-
} = typeAnnotation;
|
|
2207
|
-
if (type === AST_NODE_TYPES4.TSAnyKeyword) {
|
|
2208
|
-
if (allowExplicitAny) {
|
|
2209
|
-
return;
|
|
2210
|
-
}
|
|
2211
|
-
context.report({
|
|
2212
|
-
messageId: "explicitAny",
|
|
2213
|
-
node: param,
|
|
2214
|
-
suggest: [
|
|
2215
|
-
{
|
|
2216
|
-
messageId: "suggestExplicitUnknown",
|
|
2217
|
-
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2218
|
-
}
|
|
2219
|
-
]
|
|
2220
|
-
});
|
|
2221
|
-
} else if (type !== AST_NODE_TYPES4.TSUnknownKeyword) {
|
|
2222
|
-
let isAllowedError = false;
|
|
2223
|
-
if (allowExplicitError && type === AST_NODE_TYPES4.TSTypeReference) {
|
|
2224
|
-
const typeRef = typeAnnotation.typeAnnotation;
|
|
2225
|
-
if (isIdentifier(typeRef.typeName)) {
|
|
2226
|
-
isAllowedError = typeRef.typeName.name === "Error";
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
if (!isAllowedError) {
|
|
2230
|
-
context.report({
|
|
2231
|
-
messageId: allowExplicitError ? "narrowedAllowError" : "narrowed",
|
|
2232
|
-
node: param,
|
|
2233
|
-
suggest: [
|
|
2234
|
-
{
|
|
2235
|
-
messageId: "suggestExplicitUnknown",
|
|
2236
|
-
fix: createReplacerFix(typeAnnotation, "unknown")
|
|
2237
|
-
},
|
|
2238
|
-
allowExplicitAny ? {
|
|
2239
|
-
messageId: "suggestExplicitAny",
|
|
2240
|
-
fix: createReplacerFix(typeAnnotation, "any")
|
|
2241
|
-
} : null,
|
|
2242
|
-
allowExplicitError && !isAllowedError ? {
|
|
2243
|
-
messageId: "suggestExplicitError",
|
|
2244
|
-
fix: createReplacerFix(typeAnnotation, "Error")
|
|
2245
|
-
} : null
|
|
2246
|
-
].filter((x) => !!x)
|
|
2247
|
-
});
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
} else {
|
|
2251
|
-
const hasRestParams = restParams.length > 0;
|
|
2252
|
-
context.report({
|
|
2253
|
-
fix: allowExplicitAny ? createInserterFix(param, "any", { hasRestParams }) : void 0,
|
|
2254
|
-
messageId: "implicitAny",
|
|
2255
|
-
node: param,
|
|
2256
|
-
suggest: [
|
|
2257
|
-
{
|
|
2258
|
-
messageId: "suggestExplicitUnknown",
|
|
2259
|
-
fix: createInserterFix(param, "unknown", { hasRestParams })
|
|
2260
|
-
},
|
|
2261
|
-
allowExplicitAny ? {
|
|
2262
|
-
messageId: "suggestExplicitAny",
|
|
2263
|
-
fix: createInserterFix(param, "any", { hasRestParams })
|
|
2264
|
-
} : null
|
|
2265
|
-
].filter((x) => !!x)
|
|
2266
|
-
});
|
|
2267
|
-
}
|
|
2268
|
-
}
|
|
2269
|
-
}
|
|
2270
|
-
return {
|
|
2271
|
-
"CallExpression[callee.name='catchError']": (node) => {
|
|
2272
|
-
const [callback] = node.arguments;
|
|
2273
|
-
if (!callback) {
|
|
2274
|
-
return;
|
|
2275
|
-
}
|
|
2276
|
-
checkCallback(callback);
|
|
2277
|
-
},
|
|
2278
|
-
"CallExpression[callee.property.name='subscribe'],CallExpression[callee.name='tap']": (node) => {
|
|
2279
|
-
const { callee } = node;
|
|
2280
|
-
if (isMemberExpression(callee) && !couldBeObservable(callee.object)) {
|
|
2281
|
-
return;
|
|
2282
|
-
}
|
|
2283
|
-
const [observer, callback] = node.arguments;
|
|
2284
|
-
if (callback) {
|
|
2285
|
-
checkCallback(callback);
|
|
2286
|
-
} else if (observer && isObjectExpression(observer)) {
|
|
2287
|
-
const errorProperty = observer.properties.find(
|
|
2288
|
-
(property) => isProperty(property) && isIdentifier(property.key) && property.key.name === "error"
|
|
2289
|
-
);
|
|
2290
|
-
if (errorProperty) {
|
|
2291
|
-
checkCallback(errorProperty.value);
|
|
2292
|
-
}
|
|
2293
|
-
}
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
}
|
|
2297
|
-
});
|
|
2298
|
-
|
|
2299
|
-
// src/rules/no-index.ts
|
|
2300
|
-
var noIndexRule = ruleCreator({
|
|
2301
|
-
defaultOptions: [],
|
|
2302
|
-
meta: {
|
|
2303
|
-
docs: {
|
|
2304
|
-
description: "Disallow importing index modules.",
|
|
2305
|
-
recommended: "recommended"
|
|
2306
|
-
},
|
|
2307
|
-
messages: {
|
|
2308
|
-
forbidden: "RxJS imports from index modules are forbidden."
|
|
2309
|
-
},
|
|
2310
|
-
schema: [],
|
|
2311
|
-
type: "problem"
|
|
2312
|
-
},
|
|
2313
|
-
name: "no-index",
|
|
2314
|
-
create: (context) => {
|
|
2315
|
-
return {
|
|
2316
|
-
[String.raw`ImportDeclaration Literal[value=/^rxjs(?:\u002f\w+)?\u002findex/]`]: (node) => {
|
|
2317
|
-
context.report({
|
|
2318
|
-
messageId: "forbidden",
|
|
2319
|
-
node
|
|
2320
|
-
});
|
|
2321
|
-
}
|
|
2322
|
-
};
|
|
2323
|
-
}
|
|
2324
|
-
});
|
|
2325
|
-
|
|
2326
|
-
// src/rules/no-internal.ts
|
|
2327
|
-
var noInternalRule = ruleCreator({
|
|
2328
|
-
defaultOptions: [],
|
|
2329
|
-
meta: {
|
|
2330
|
-
docs: {
|
|
2331
|
-
description: "Disallow importing internal modules.",
|
|
2332
|
-
recommended: "recommended"
|
|
2333
|
-
},
|
|
2334
|
-
fixable: "code",
|
|
2335
|
-
hasSuggestions: true,
|
|
2336
|
-
messages: {
|
|
2337
|
-
forbidden: "RxJS imports from internal are forbidden.",
|
|
2338
|
-
suggest: "Import from a non-internal location."
|
|
2339
|
-
},
|
|
2340
|
-
schema: [],
|
|
2341
|
-
type: "problem"
|
|
2342
|
-
},
|
|
2343
|
-
name: "no-internal",
|
|
2344
|
-
create: (context) => {
|
|
2345
|
-
function getReplacement(location) {
|
|
2346
|
-
const match = /^\s*('|")/.exec(location);
|
|
2347
|
-
if (!match) {
|
|
2348
|
-
return void 0;
|
|
2349
|
-
}
|
|
2350
|
-
const [, quote] = match;
|
|
2351
|
-
if (/^['"]rxjs\/internal\/ajax/.test(location)) {
|
|
2352
|
-
return `${quote}rxjs/ajax${quote}`;
|
|
2353
|
-
}
|
|
2354
|
-
if (/^['"]rxjs\/internal\/observable\/dom\/fetch/.test(location)) {
|
|
2355
|
-
return `${quote}rxjs/fetch${quote}`;
|
|
2356
|
-
}
|
|
2357
|
-
if (/^['"]rxjs\/internal\/observable\/dom\/webSocket/i.test(location)) {
|
|
2358
|
-
return `${quote}rxjs/webSocket${quote}`;
|
|
2359
|
-
}
|
|
2360
|
-
if (/^['"]rxjs\/internal\/observable/.test(location)) {
|
|
2361
|
-
return `${quote}rxjs${quote}`;
|
|
2362
|
-
}
|
|
2363
|
-
if (/^['"]rxjs\/internal\/operators/.test(location)) {
|
|
2364
|
-
return `${quote}rxjs/operators${quote}`;
|
|
2365
|
-
}
|
|
2366
|
-
if (/^['"]rxjs\/internal\/scheduled/.test(location)) {
|
|
2367
|
-
return `${quote}rxjs${quote}`;
|
|
2368
|
-
}
|
|
2369
|
-
if (/^['"]rxjs\/internal\/scheduler/.test(location)) {
|
|
2370
|
-
return `${quote}rxjs${quote}`;
|
|
2371
|
-
}
|
|
2372
|
-
if (/^['"]rxjs\/internal\/testing/.test(location)) {
|
|
2373
|
-
return `${quote}rxjs/testing${quote}`;
|
|
2374
|
-
}
|
|
2375
|
-
return void 0;
|
|
2376
|
-
}
|
|
2377
|
-
return {
|
|
2378
|
-
[String.raw`ImportDeclaration Literal[value=/^rxjs\u002finternal/]`]: (node) => {
|
|
2379
|
-
const replacement = getReplacement(node.raw);
|
|
2380
|
-
if (replacement) {
|
|
2381
|
-
let fix2 = function(fixer) {
|
|
2382
|
-
return fixer.replaceText(node, replacement);
|
|
2383
|
-
};
|
|
2384
|
-
var fix = fix2;
|
|
2385
|
-
context.report({
|
|
2386
|
-
fix: fix2,
|
|
2387
|
-
messageId: "forbidden",
|
|
2388
|
-
node,
|
|
2389
|
-
suggest: [{ fix: fix2, messageId: "suggest" }]
|
|
2390
|
-
});
|
|
2391
|
-
} else {
|
|
2392
|
-
context.report({
|
|
2393
|
-
messageId: "forbidden",
|
|
2394
|
-
node
|
|
2395
|
-
});
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
};
|
|
2399
|
-
}
|
|
2400
|
-
});
|
|
2401
|
-
|
|
2402
|
-
// src/rules/no-misused-observables.ts
|
|
2403
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES5, ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
|
|
2404
|
-
import { getFunctionHeadLocation, isFunction } from "@typescript-eslint/utils/ast-utils";
|
|
2405
|
-
import * as tsutils4 from "ts-api-utils";
|
|
2406
|
-
import ts5 from "typescript";
|
|
2407
|
-
function parseChecksVoidReturn(checksVoidReturn) {
|
|
2408
|
-
var _a, _b, _c, _d, _e, _f;
|
|
2409
|
-
switch (checksVoidReturn) {
|
|
2410
|
-
case false:
|
|
2411
|
-
return false;
|
|
2412
|
-
case true:
|
|
2413
|
-
case void 0:
|
|
2414
|
-
return {
|
|
2415
|
-
arguments: true,
|
|
2416
|
-
attributes: true,
|
|
2417
|
-
inheritedMethods: true,
|
|
2418
|
-
properties: true,
|
|
2419
|
-
returns: true,
|
|
2420
|
-
variables: true
|
|
2421
|
-
};
|
|
2422
|
-
default:
|
|
2423
|
-
return {
|
|
2424
|
-
arguments: (_a = checksVoidReturn.arguments) != null ? _a : true,
|
|
2425
|
-
attributes: (_b = checksVoidReturn.attributes) != null ? _b : true,
|
|
2426
|
-
inheritedMethods: (_c = checksVoidReturn.inheritedMethods) != null ? _c : true,
|
|
2427
|
-
properties: (_d = checksVoidReturn.properties) != null ? _d : true,
|
|
2428
|
-
returns: (_e = checksVoidReturn.returns) != null ? _e : true,
|
|
2429
|
-
variables: (_f = checksVoidReturn.variables) != null ? _f : true
|
|
2430
|
-
};
|
|
2431
|
-
}
|
|
2432
|
-
}
|
|
2433
|
-
var defaultOptions9 = [];
|
|
2434
|
-
var noMisusedObservablesRule = ruleCreator({
|
|
2435
|
-
defaultOptions: defaultOptions9,
|
|
2436
|
-
meta: {
|
|
2437
|
-
docs: {
|
|
2438
|
-
description: "Disallow Observables in places not designed to handle them.",
|
|
2439
|
-
recommended: "strict",
|
|
2440
|
-
requiresTypeChecking: true
|
|
2441
|
-
},
|
|
2442
|
-
messages: {
|
|
2443
|
-
forbiddenVoidReturnArgument: "Observable returned in function argument where a void return was expected.",
|
|
2444
|
-
forbiddenVoidReturnAttribute: "Observable-returning function provided to attribute where a void return was expected.",
|
|
2445
|
-
forbiddenVoidReturnInheritedMethod: "Observable-returning method provided where a void return was expected by extended/implemented type '{{heritageTypeName}}'.",
|
|
2446
|
-
forbiddenVoidReturnProperty: "Observable-returning function provided to property where a void return was expected.",
|
|
2447
|
-
forbiddenVoidReturnReturnValue: "Observable-returning function provided to return value where a void return was expected.",
|
|
2448
|
-
forbiddenVoidReturnVariable: "Observable-returning function provided to variable where a void return was expected.",
|
|
2449
|
-
forbiddenSpread: "Expected a non-Observable value to be spread into an object."
|
|
2450
|
-
},
|
|
2451
|
-
schema: [
|
|
2452
|
-
{
|
|
2453
|
-
properties: {
|
|
2454
|
-
checksVoidReturn: {
|
|
2455
|
-
default: true,
|
|
2456
|
-
description: "Disallow returning an Observable from a function typed as returning `void`.",
|
|
2457
|
-
oneOf: [
|
|
2458
|
-
{
|
|
2459
|
-
default: true,
|
|
2460
|
-
type: "boolean",
|
|
2461
|
-
description: "Disallow returning an Observable from all types of functions typed as returning `void`."
|
|
2462
|
-
},
|
|
2463
|
-
{
|
|
2464
|
-
type: "object",
|
|
2465
|
-
additionalProperties: false,
|
|
2466
|
-
description: "Which forms of functions may have checking disabled.",
|
|
2467
|
-
properties: {
|
|
2468
|
-
arguments: { type: "boolean", description: "Disallow passing an Observable-returning function as an argument where the parameter type expects a function that returns `void`." },
|
|
2469
|
-
attributes: { type: "boolean", description: "Disallow passing an Observable-returning function as a JSX attribute expected to be a function that returns `void`." },
|
|
2470
|
-
inheritedMethods: { type: "boolean", description: "Disallow providing an Observable-returning function where a function that returns `void` is expected by an extended or implemented type." },
|
|
2471
|
-
properties: { type: "boolean", description: "Disallow providing an Observable-returning function where a function that returns `void` is expected by a property." },
|
|
2472
|
-
returns: { type: "boolean", description: "Disallow returning an Observable-returning function where a function that returns `void` is expected." },
|
|
2473
|
-
variables: { type: "boolean", description: "Disallow assigning or declaring an Observable-returning function where a function that returns `void` is expected." }
|
|
2474
|
-
}
|
|
2475
|
-
}
|
|
2476
|
-
]
|
|
2477
|
-
},
|
|
2478
|
-
checksSpreads: { type: "boolean", default: true, description: "Disallow `...` spreading an Observable." }
|
|
2479
|
-
},
|
|
2480
|
-
type: "object"
|
|
2481
|
-
}
|
|
2482
|
-
],
|
|
2483
|
-
type: "problem"
|
|
2484
|
-
},
|
|
2485
|
-
name: "no-misused-observables",
|
|
2486
|
-
create: (context) => {
|
|
2487
|
-
const { program, esTreeNodeToTSNodeMap, getTypeAtLocation } = ESLintUtils9.getParserServices(context);
|
|
2488
|
-
const checker = program.getTypeChecker();
|
|
2489
|
-
const { couldBeObservable, couldReturnObservable } = getTypeServices(context);
|
|
2490
|
-
const [config = {}] = context.options;
|
|
2491
|
-
const { checksVoidReturn = true, checksSpreads = true } = config;
|
|
2492
|
-
const parsedChecksVoidReturn = parseChecksVoidReturn(checksVoidReturn);
|
|
2493
|
-
const voidReturnChecks = parsedChecksVoidReturn ? {
|
|
2494
|
-
...parsedChecksVoidReturn.arguments && {
|
|
2495
|
-
CallExpression: checkArguments,
|
|
2496
|
-
NewExpression: checkArguments
|
|
2497
|
-
},
|
|
2498
|
-
...parsedChecksVoidReturn.attributes && {
|
|
2499
|
-
JSXAttribute: checkJSXAttribute
|
|
2500
|
-
},
|
|
2501
|
-
...parsedChecksVoidReturn.inheritedMethods && {
|
|
2502
|
-
ClassDeclaration: checkClassLikeOrInterfaceNode,
|
|
2503
|
-
ClassExpression: checkClassLikeOrInterfaceNode,
|
|
2504
|
-
TSInterfaceDeclaration: checkClassLikeOrInterfaceNode
|
|
2505
|
-
},
|
|
2506
|
-
...parsedChecksVoidReturn.properties && {
|
|
2507
|
-
Property: checkProperty
|
|
2508
|
-
},
|
|
2509
|
-
...parsedChecksVoidReturn.returns && {
|
|
2510
|
-
ReturnStatement: checkReturnStatement
|
|
2511
|
-
},
|
|
2512
|
-
...parsedChecksVoidReturn.variables && {
|
|
2513
|
-
AssignmentExpression: checkAssignment,
|
|
2514
|
-
VariableDeclarator: checkVariableDeclaration
|
|
2515
|
-
}
|
|
2516
|
-
} : {};
|
|
2517
|
-
const spreadChecks = {
|
|
2518
|
-
SpreadElement: (node) => {
|
|
2519
|
-
if (couldBeObservable(node.argument)) {
|
|
2520
|
-
context.report({
|
|
2521
|
-
messageId: "forbiddenSpread",
|
|
2522
|
-
node: node.argument
|
|
2523
|
-
});
|
|
2524
|
-
}
|
|
2525
|
-
}
|
|
2526
|
-
};
|
|
2527
|
-
function checkArguments(node) {
|
|
2528
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
2529
|
-
const voidArgs = voidFunctionArguments(checker, tsNode);
|
|
2530
|
-
if (!voidArgs.size) {
|
|
2531
|
-
return;
|
|
2532
|
-
}
|
|
2533
|
-
for (const [index, argument] of node.arguments.entries()) {
|
|
2534
|
-
if (!voidArgs.has(index)) {
|
|
2535
|
-
continue;
|
|
2536
|
-
}
|
|
2537
|
-
if (couldReturnObservable(argument)) {
|
|
2538
|
-
context.report({
|
|
2539
|
-
messageId: "forbiddenVoidReturnArgument",
|
|
2540
|
-
node: argument
|
|
2541
|
-
});
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
}
|
|
2545
|
-
function checkJSXAttribute(node) {
|
|
2546
|
-
if (node.value == null || !isJSXExpressionContainer(node.value)) {
|
|
2547
|
-
return;
|
|
2548
|
-
}
|
|
2549
|
-
const expressionContainer = esTreeNodeToTSNodeMap.get(
|
|
2550
|
-
node.value
|
|
2551
|
-
);
|
|
2552
|
-
const contextualType = checker.getContextualType(expressionContainer);
|
|
2553
|
-
if (contextualType != null && isVoidReturningFunctionType(contextualType) && couldReturnObservable(node.value.expression)) {
|
|
2554
|
-
context.report({
|
|
2555
|
-
messageId: "forbiddenVoidReturnAttribute",
|
|
2556
|
-
node: node.value
|
|
2557
|
-
});
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
function checkClassLikeOrInterfaceNode(node) {
|
|
2561
|
-
var _a;
|
|
2562
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
2563
|
-
const heritageTypes = getHeritageTypes(checker, tsNode);
|
|
2564
|
-
if (!(heritageTypes == null ? void 0 : heritageTypes.length)) {
|
|
2565
|
-
return;
|
|
2566
|
-
}
|
|
2567
|
-
for (const element of node.body.body) {
|
|
2568
|
-
const tsElement = esTreeNodeToTSNodeMap.get(element);
|
|
2569
|
-
const memberName = (_a = tsElement == null ? void 0 : tsElement.name) == null ? void 0 : _a.getText();
|
|
2570
|
-
if (memberName == null) {
|
|
2571
|
-
continue;
|
|
2572
|
-
}
|
|
2573
|
-
if (!couldReturnObservable(element)) {
|
|
2574
|
-
continue;
|
|
2575
|
-
}
|
|
2576
|
-
if (isStaticMember(element)) {
|
|
2577
|
-
continue;
|
|
2578
|
-
}
|
|
2579
|
-
for (const heritageType of heritageTypes) {
|
|
2580
|
-
const heritageMember = getMemberIfExists(heritageType, memberName);
|
|
2581
|
-
if (heritageMember == null) {
|
|
2582
|
-
continue;
|
|
2583
|
-
}
|
|
2584
|
-
const memberType = checker.getTypeOfSymbolAtLocation(heritageMember, tsElement);
|
|
2585
|
-
if (!isVoidReturningFunctionType(memberType)) {
|
|
2586
|
-
continue;
|
|
2587
|
-
}
|
|
2588
|
-
context.report({
|
|
2589
|
-
messageId: "forbiddenVoidReturnInheritedMethod",
|
|
2590
|
-
node: element,
|
|
2591
|
-
data: { heritageTypeName: checker.typeToString(heritageType) }
|
|
2592
|
-
});
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
function checkProperty(node) {
|
|
2597
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
2598
|
-
const contextualType = getPropertyContextualType(checker, tsNode);
|
|
2599
|
-
if (contextualType == null) {
|
|
2600
|
-
return;
|
|
2601
|
-
}
|
|
2602
|
-
if (!isVoidReturningFunctionType(contextualType)) {
|
|
2603
|
-
return;
|
|
2604
|
-
}
|
|
2605
|
-
if (!couldReturnObservable(node.value)) {
|
|
2606
|
-
return;
|
|
2607
|
-
}
|
|
2608
|
-
if (isFunction(node.value)) {
|
|
2609
|
-
const functionNode = node.value;
|
|
2610
|
-
if (functionNode.returnType) {
|
|
2611
|
-
context.report({
|
|
2612
|
-
messageId: "forbiddenVoidReturnProperty",
|
|
2613
|
-
node: functionNode.returnType.typeAnnotation
|
|
2614
|
-
});
|
|
2615
|
-
} else {
|
|
2616
|
-
context.report({
|
|
2617
|
-
messageId: "forbiddenVoidReturnProperty",
|
|
2618
|
-
loc: getFunctionHeadLocation(functionNode, context.sourceCode)
|
|
2619
|
-
});
|
|
2620
|
-
}
|
|
2621
|
-
} else {
|
|
2622
|
-
context.report({
|
|
2623
|
-
messageId: "forbiddenVoidReturnProperty",
|
|
2624
|
-
node: node.value
|
|
2625
|
-
});
|
|
2626
|
-
}
|
|
2627
|
-
}
|
|
2628
|
-
function checkReturnStatement(node) {
|
|
2629
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
2630
|
-
if (tsNode.expression == null || !node.argument) {
|
|
2631
|
-
return;
|
|
2632
|
-
}
|
|
2633
|
-
function getFunctionNode() {
|
|
2634
|
-
let current = node.parent;
|
|
2635
|
-
while (current && !isArrowFunctionExpression(current) && !isFunctionExpression(current) && !isFunctionDeclaration(current)) {
|
|
2636
|
-
current = current.parent;
|
|
2637
|
-
}
|
|
2638
|
-
return current;
|
|
2639
|
-
}
|
|
2640
|
-
const functionNode = getFunctionNode();
|
|
2641
|
-
if ((functionNode == null ? void 0 : functionNode.returnType) && !isPossiblyFunctionType(functionNode.returnType)) {
|
|
2642
|
-
return;
|
|
2643
|
-
}
|
|
2644
|
-
const contextualType = checker.getContextualType(tsNode.expression);
|
|
2645
|
-
if (contextualType == null) {
|
|
2646
|
-
return;
|
|
2647
|
-
}
|
|
2648
|
-
if (!isVoidReturningFunctionType(contextualType)) {
|
|
2649
|
-
return;
|
|
2650
|
-
}
|
|
2651
|
-
if (!couldReturnObservable(node.argument)) {
|
|
2652
|
-
return;
|
|
2653
|
-
}
|
|
2654
|
-
context.report({
|
|
2655
|
-
node: node.argument,
|
|
2656
|
-
messageId: "forbiddenVoidReturnReturnValue"
|
|
2657
|
-
});
|
|
2658
|
-
}
|
|
2659
|
-
function checkAssignment(node) {
|
|
2660
|
-
const varType = getTypeAtLocation(node.left);
|
|
2661
|
-
if (!isVoidReturningFunctionType(varType)) {
|
|
2662
|
-
return;
|
|
2663
|
-
}
|
|
2664
|
-
if (couldReturnObservable(node.right)) {
|
|
2665
|
-
context.report({
|
|
2666
|
-
messageId: "forbiddenVoidReturnVariable",
|
|
2667
|
-
node: node.right
|
|
2668
|
-
});
|
|
2669
|
-
}
|
|
2670
|
-
}
|
|
2671
|
-
function checkVariableDeclaration(node) {
|
|
2672
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
2673
|
-
if (tsNode.initializer == null || node.init == null || node.id.typeAnnotation == null) {
|
|
2674
|
-
return;
|
|
2675
|
-
}
|
|
2676
|
-
if (!isPossiblyFunctionType(node.id.typeAnnotation)) {
|
|
2677
|
-
return;
|
|
2678
|
-
}
|
|
2679
|
-
const varType = getTypeAtLocation(node.id);
|
|
2680
|
-
if (!isVoidReturningFunctionType(varType)) {
|
|
2681
|
-
return;
|
|
2682
|
-
}
|
|
2683
|
-
if (couldReturnObservable(node.init)) {
|
|
2684
|
-
context.report({
|
|
2685
|
-
messageId: "forbiddenVoidReturnVariable",
|
|
2686
|
-
node: node.init
|
|
2687
|
-
});
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
return {
|
|
2691
|
-
...checksVoidReturn ? voidReturnChecks : {},
|
|
2692
|
-
...checksSpreads ? spreadChecks : {}
|
|
2693
|
-
};
|
|
2694
|
-
}
|
|
2695
|
-
});
|
|
2696
|
-
function voidFunctionArguments(checker, tsNode) {
|
|
2697
|
-
if (!tsNode.arguments) {
|
|
2698
|
-
return /* @__PURE__ */ new Set();
|
|
2699
|
-
}
|
|
2700
|
-
const voidReturnIndices = /* @__PURE__ */ new Set();
|
|
2701
|
-
const type = checker.getTypeAtLocation(tsNode.expression);
|
|
2702
|
-
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2703
|
-
const signatures = ts5.isCallExpression(tsNode) ? subType.getCallSignatures() : subType.getConstructSignatures();
|
|
2704
|
-
for (const signature of signatures) {
|
|
2705
|
-
for (const [index, parameter] of signature.parameters.entries()) {
|
|
2706
|
-
const type2 = checker.getTypeOfSymbolAtLocation(parameter, tsNode.expression);
|
|
2707
|
-
if (isVoidReturningFunctionType(type2)) {
|
|
2708
|
-
voidReturnIndices.add(index);
|
|
2709
|
-
}
|
|
2710
|
-
}
|
|
2711
|
-
}
|
|
2712
|
-
}
|
|
2713
|
-
return voidReturnIndices;
|
|
2714
|
-
}
|
|
2715
|
-
function isVoidReturningFunctionType(type) {
|
|
2716
|
-
let hasVoidReturn = false;
|
|
2717
|
-
for (const subType of tsutils4.unionConstituents(type)) {
|
|
2718
|
-
for (const signature of subType.getCallSignatures()) {
|
|
2719
|
-
const returnType = signature.getReturnType();
|
|
2720
|
-
if (couldBeType(returnType, "Observable")) {
|
|
2721
|
-
return false;
|
|
2722
|
-
}
|
|
2723
|
-
hasVoidReturn || (hasVoidReturn = tsutils4.isTypeFlagSet(returnType, ts5.TypeFlags.Void));
|
|
2724
|
-
}
|
|
2725
|
-
}
|
|
2726
|
-
return hasVoidReturn;
|
|
2727
|
-
}
|
|
2728
|
-
function getHeritageTypes(checker, tsNode) {
|
|
2729
|
-
var _a;
|
|
2730
|
-
return (_a = tsNode.heritageClauses) == null ? void 0 : _a.flatMap((clause) => clause.types).map((typeExpressions) => checker.getTypeAtLocation(typeExpressions));
|
|
2731
|
-
}
|
|
2732
|
-
function getMemberIfExists(type, memberName) {
|
|
2733
|
-
var _a, _b;
|
|
2734
|
-
const escapedMemberName = ts5.escapeLeadingUnderscores(memberName);
|
|
2735
|
-
const symbolMemberMatch = (_b = (_a = type.getSymbol()) == null ? void 0 : _a.members) == null ? void 0 : _b.get(escapedMemberName);
|
|
2736
|
-
return symbolMemberMatch != null ? symbolMemberMatch : tsutils4.getPropertyOfType(type, escapedMemberName);
|
|
2737
|
-
}
|
|
2738
|
-
function isStaticMember(node) {
|
|
2739
|
-
return (isMethodDefinition(node) || isPropertyDefinition(node) || isAccessorProperty(node)) && node.static;
|
|
2740
|
-
}
|
|
2741
|
-
function getPropertyContextualType(checker, tsNode) {
|
|
2742
|
-
if (ts5.isPropertyAssignment(tsNode)) {
|
|
2743
|
-
return checker.getContextualType(tsNode.initializer);
|
|
2744
|
-
} else if (ts5.isShorthandPropertyAssignment(tsNode)) {
|
|
2745
|
-
return checker.getContextualType(tsNode.name);
|
|
2746
|
-
} else if (ts5.isMethodDeclaration(tsNode)) {
|
|
2747
|
-
if (ts5.isComputedPropertyName(tsNode.name)) {
|
|
2748
|
-
return;
|
|
2749
|
-
}
|
|
2750
|
-
const obj = tsNode.parent;
|
|
2751
|
-
if (!ts5.isObjectLiteralExpression(obj)) {
|
|
2752
|
-
return;
|
|
2753
|
-
}
|
|
2754
|
-
const objType = checker.getContextualType(obj);
|
|
2755
|
-
if (objType == null) {
|
|
2756
|
-
return;
|
|
2757
|
-
}
|
|
2758
|
-
const propertySymbol = tsutils4.unionConstituents(objType).map((t) => checker.getPropertyOfType(t, tsNode.name.getText())).find((p) => p);
|
|
2759
|
-
if (propertySymbol == null) {
|
|
2760
|
-
return;
|
|
2761
|
-
}
|
|
2762
|
-
return checker.getTypeOfSymbolAtLocation(propertySymbol, tsNode.name);
|
|
2763
|
-
} else {
|
|
2764
|
-
return void 0;
|
|
2765
|
-
}
|
|
2766
|
-
}
|
|
2767
|
-
function isPossiblyFunctionType(node) {
|
|
2768
|
-
switch (node.typeAnnotation.type) {
|
|
2769
|
-
case AST_NODE_TYPES5.TSConditionalType:
|
|
2770
|
-
case AST_NODE_TYPES5.TSConstructorType:
|
|
2771
|
-
case AST_NODE_TYPES5.TSFunctionType:
|
|
2772
|
-
case AST_NODE_TYPES5.TSImportType:
|
|
2773
|
-
case AST_NODE_TYPES5.TSIndexedAccessType:
|
|
2774
|
-
case AST_NODE_TYPES5.TSInferType:
|
|
2775
|
-
case AST_NODE_TYPES5.TSIntersectionType:
|
|
2776
|
-
case AST_NODE_TYPES5.TSQualifiedName:
|
|
2777
|
-
case AST_NODE_TYPES5.TSThisType:
|
|
2778
|
-
case AST_NODE_TYPES5.TSTypeOperator:
|
|
2779
|
-
case AST_NODE_TYPES5.TSTypeQuery:
|
|
2780
|
-
case AST_NODE_TYPES5.TSTypeReference:
|
|
2781
|
-
case AST_NODE_TYPES5.TSUnionType:
|
|
2782
|
-
return true;
|
|
2783
|
-
case AST_NODE_TYPES5.TSTypeLiteral:
|
|
2784
|
-
return node.typeAnnotation.members.some(
|
|
2785
|
-
(member) => member.type === AST_NODE_TYPES5.TSCallSignatureDeclaration || member.type === AST_NODE_TYPES5.TSConstructSignatureDeclaration
|
|
2786
|
-
);
|
|
2787
|
-
case AST_NODE_TYPES5.TSAbstractKeyword:
|
|
2788
|
-
case AST_NODE_TYPES5.TSAnyKeyword:
|
|
2789
|
-
case AST_NODE_TYPES5.TSArrayType:
|
|
2790
|
-
case AST_NODE_TYPES5.TSAsyncKeyword:
|
|
2791
|
-
case AST_NODE_TYPES5.TSBigIntKeyword:
|
|
2792
|
-
case AST_NODE_TYPES5.TSBooleanKeyword:
|
|
2793
|
-
case AST_NODE_TYPES5.TSDeclareKeyword:
|
|
2794
|
-
case AST_NODE_TYPES5.TSExportKeyword:
|
|
2795
|
-
case AST_NODE_TYPES5.TSIntrinsicKeyword:
|
|
2796
|
-
case AST_NODE_TYPES5.TSLiteralType:
|
|
2797
|
-
case AST_NODE_TYPES5.TSMappedType:
|
|
2798
|
-
case AST_NODE_TYPES5.TSNamedTupleMember:
|
|
2799
|
-
case AST_NODE_TYPES5.TSNeverKeyword:
|
|
2800
|
-
case AST_NODE_TYPES5.TSNullKeyword:
|
|
2801
|
-
case AST_NODE_TYPES5.TSNumberKeyword:
|
|
2802
|
-
case AST_NODE_TYPES5.TSObjectKeyword:
|
|
2803
|
-
case AST_NODE_TYPES5.TSOptionalType:
|
|
2804
|
-
case AST_NODE_TYPES5.TSPrivateKeyword:
|
|
2805
|
-
case AST_NODE_TYPES5.TSProtectedKeyword:
|
|
2806
|
-
case AST_NODE_TYPES5.TSPublicKeyword:
|
|
2807
|
-
case AST_NODE_TYPES5.TSReadonlyKeyword:
|
|
2808
|
-
case AST_NODE_TYPES5.TSRestType:
|
|
2809
|
-
case AST_NODE_TYPES5.TSStaticKeyword:
|
|
2810
|
-
case AST_NODE_TYPES5.TSStringKeyword:
|
|
2811
|
-
case AST_NODE_TYPES5.TSSymbolKeyword:
|
|
2812
|
-
case AST_NODE_TYPES5.TSTemplateLiteralType:
|
|
2813
|
-
case AST_NODE_TYPES5.TSTupleType:
|
|
2814
|
-
case AST_NODE_TYPES5.TSTypePredicate:
|
|
2815
|
-
case AST_NODE_TYPES5.TSUndefinedKeyword:
|
|
2816
|
-
case AST_NODE_TYPES5.TSUnknownKeyword:
|
|
2817
|
-
case AST_NODE_TYPES5.TSVoidKeyword:
|
|
2818
|
-
return false;
|
|
2819
|
-
}
|
|
2820
|
-
}
|
|
2821
|
-
|
|
2822
|
-
// src/rules/no-nested-subscribe.ts
|
|
2823
|
-
var noNestedSubscribeRule = ruleCreator({
|
|
2824
|
-
defaultOptions: [],
|
|
2825
|
-
meta: {
|
|
2826
|
-
docs: {
|
|
2827
|
-
description: "Disallow calling `subscribe` within a `subscribe` callback.",
|
|
2828
|
-
recommended: "recommended",
|
|
2829
|
-
requiresTypeChecking: true
|
|
2830
|
-
},
|
|
2831
|
-
messages: {
|
|
2832
|
-
forbidden: "Nested subscribe calls are forbidden."
|
|
2833
|
-
},
|
|
2834
|
-
schema: [],
|
|
2835
|
-
type: "problem"
|
|
2836
|
-
},
|
|
2837
|
-
name: "no-nested-subscribe",
|
|
2838
|
-
create: (context) => {
|
|
2839
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
2840
|
-
const argumentsMap = /* @__PURE__ */ new WeakMap();
|
|
2841
|
-
return {
|
|
2842
|
-
[`CallExpression > MemberExpression[property.name='subscribe']`]: (node) => {
|
|
2843
|
-
if (!couldBeObservable(node.object) && !couldBeType2(node.object, "Subscribable")) {
|
|
2844
|
-
return;
|
|
2845
|
-
}
|
|
2846
|
-
const callExpression = node.parent;
|
|
2847
|
-
let parent = callExpression.parent;
|
|
2848
|
-
while (parent) {
|
|
2849
|
-
if (argumentsMap.has(parent)) {
|
|
2850
|
-
context.report({
|
|
2851
|
-
messageId: "forbidden",
|
|
2852
|
-
node: node.property
|
|
2853
|
-
});
|
|
2854
|
-
return;
|
|
2855
|
-
}
|
|
2856
|
-
parent = parent.parent;
|
|
2857
|
-
}
|
|
2858
|
-
for (const arg of callExpression.arguments) {
|
|
2859
|
-
argumentsMap.set(arg);
|
|
2860
|
-
}
|
|
2861
|
-
}
|
|
2862
|
-
};
|
|
2863
|
-
}
|
|
2864
|
-
});
|
|
2865
|
-
|
|
2866
|
-
// src/rules/no-redundant-notify.ts
|
|
2867
|
-
var noRedundantNotifyRule = ruleCreator({
|
|
2868
|
-
defaultOptions: [],
|
|
2869
|
-
meta: {
|
|
2870
|
-
docs: {
|
|
2871
|
-
description: "Disallow sending redundant notifications from completed or errored observables.",
|
|
2872
|
-
recommended: "recommended",
|
|
2873
|
-
requiresTypeChecking: true
|
|
2874
|
-
},
|
|
2875
|
-
messages: {
|
|
2876
|
-
forbidden: "Redundant notifications are forbidden."
|
|
2877
|
-
},
|
|
2878
|
-
schema: [],
|
|
2879
|
-
type: "problem"
|
|
2880
|
-
},
|
|
2881
|
-
name: "no-redundant-notify",
|
|
2882
|
-
create: (context) => {
|
|
2883
|
-
const sourceCode = context.sourceCode;
|
|
2884
|
-
const { couldBeType: couldBeType2 } = getTypeServices(context);
|
|
2885
|
-
return {
|
|
2886
|
-
"ExpressionStatement[expression.callee.property.name=/^(complete|error|unsubscribe)$/] + ExpressionStatement[expression.callee.property.name=/^(next|complete|error|unsubscribe)$/]": (node) => {
|
|
2887
|
-
const parent = node.parent;
|
|
2888
|
-
if (!parent) {
|
|
2889
|
-
return;
|
|
2890
|
-
}
|
|
2891
|
-
if (!isBlockStatement(parent) && !isProgram(parent)) {
|
|
2892
|
-
return;
|
|
2893
|
-
}
|
|
2894
|
-
const { body } = parent;
|
|
2895
|
-
const index = body.indexOf(node);
|
|
2896
|
-
const sibling = body[index - 1];
|
|
2897
|
-
if (getExpressionText(sibling, sourceCode) !== getExpressionText(node, sourceCode)) {
|
|
2898
|
-
return;
|
|
2899
|
-
}
|
|
2900
|
-
if (!isExpressionObserver(sibling, couldBeType2) || !isExpressionObserver(node, couldBeType2)) {
|
|
2901
|
-
return;
|
|
2902
|
-
}
|
|
2903
|
-
const { expression } = node;
|
|
2904
|
-
if (isCallExpression(expression)) {
|
|
2905
|
-
const { callee } = expression;
|
|
2906
|
-
if (isMemberExpression(callee)) {
|
|
2907
|
-
const { property } = callee;
|
|
2908
|
-
if (isIdentifier(property)) {
|
|
2909
|
-
context.report({
|
|
2910
|
-
messageId: "forbidden",
|
|
2911
|
-
node: property
|
|
2912
|
-
});
|
|
2913
|
-
}
|
|
2914
|
-
}
|
|
2915
|
-
}
|
|
2916
|
-
}
|
|
2917
|
-
};
|
|
2918
|
-
}
|
|
2919
|
-
});
|
|
2920
|
-
function getExpressionText(expressionStatement, sourceCode) {
|
|
2921
|
-
if (!isCallExpression(expressionStatement.expression)) {
|
|
2922
|
-
return void 0;
|
|
2923
|
-
}
|
|
2924
|
-
const callExpression = expressionStatement.expression;
|
|
2925
|
-
if (!isMemberExpression(callExpression.callee)) {
|
|
2926
|
-
return void 0;
|
|
2927
|
-
}
|
|
2928
|
-
const { object } = callExpression.callee;
|
|
2929
|
-
return sourceCode.getText(object);
|
|
2930
|
-
}
|
|
2931
|
-
function isExpressionObserver(expressionStatement, couldBeType2) {
|
|
2932
|
-
if (!isCallExpression(expressionStatement.expression)) {
|
|
2933
|
-
return false;
|
|
2934
|
-
}
|
|
2935
|
-
const callExpression = expressionStatement.expression;
|
|
2936
|
-
if (!isMemberExpression(callExpression.callee)) {
|
|
2937
|
-
return false;
|
|
2938
|
-
}
|
|
2939
|
-
const { object } = callExpression.callee;
|
|
2940
|
-
return couldBeType2(object, /^(Subject|Subscriber)$/);
|
|
2941
|
-
}
|
|
2942
|
-
|
|
2943
|
-
// src/rules/no-sharereplay.ts
|
|
2944
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES6 } from "@typescript-eslint/utils";
|
|
2945
|
-
var defaultOptions10 = [];
|
|
2946
|
-
var noSharereplayRule = ruleCreator({
|
|
2947
|
-
defaultOptions: defaultOptions10,
|
|
2948
|
-
meta: {
|
|
2949
|
-
docs: {
|
|
2950
|
-
description: "Disallow unsafe `shareReplay` usage.",
|
|
2951
|
-
recommended: "recommended"
|
|
2952
|
-
},
|
|
2953
|
-
messages: {
|
|
2954
|
-
forbidden: "shareReplay is forbidden.",
|
|
2955
|
-
forbiddenWithoutConfig: "shareReplay is forbidden unless a config argument is passed."
|
|
2956
|
-
},
|
|
2957
|
-
schema: [
|
|
2958
|
-
{
|
|
2959
|
-
properties: {
|
|
2960
|
-
allowConfig: { type: "boolean", description: "Allow shareReplay if a config argument is specified.", default: true }
|
|
2961
|
-
},
|
|
2962
|
-
type: "object"
|
|
2963
|
-
}
|
|
2964
|
-
],
|
|
2965
|
-
type: "problem"
|
|
2966
|
-
},
|
|
2967
|
-
name: "no-sharereplay",
|
|
2968
|
-
create: (context) => {
|
|
2969
|
-
const [config = {}] = context.options;
|
|
2970
|
-
const { allowConfig = true } = config;
|
|
2971
|
-
return {
|
|
2972
|
-
"CallExpression[callee.name='shareReplay']": (node) => {
|
|
2973
|
-
let report = true;
|
|
2974
|
-
if (allowConfig) {
|
|
2975
|
-
report = node.arguments.length !== 1 || node.arguments[0].type !== AST_NODE_TYPES6.ObjectExpression;
|
|
2976
|
-
}
|
|
2977
|
-
if (report) {
|
|
2978
|
-
context.report({
|
|
2979
|
-
messageId: allowConfig ? "forbiddenWithoutConfig" : "forbidden",
|
|
2980
|
-
node: node.callee
|
|
2981
|
-
});
|
|
2982
|
-
}
|
|
2983
|
-
}
|
|
2984
|
-
};
|
|
2985
|
-
}
|
|
2986
|
-
});
|
|
2987
|
-
|
|
2988
|
-
// src/rules/no-sharereplay-before-takeuntil.ts
|
|
2989
|
-
var defaultOptions11 = [];
|
|
2990
|
-
var noSharereplayBeforeTakeuntilRule = ruleCreator({
|
|
2991
|
-
defaultOptions: defaultOptions11,
|
|
2992
|
-
meta: {
|
|
2993
|
-
docs: {
|
|
2994
|
-
description: "Disallow using `shareReplay({ refCount: false })` before `takeUntil`.",
|
|
2995
|
-
recommended: "strict"
|
|
2996
|
-
},
|
|
2997
|
-
messages: {
|
|
2998
|
-
forbidden: "shareReplay before '{{takeUntilAlias}}' is forbidden unless 'refCount: true' is specified."
|
|
2999
|
-
},
|
|
3000
|
-
schema: [{
|
|
3001
|
-
properties: {
|
|
3002
|
-
takeUntilAlias: { type: "array", description: "List of operators to treat as takeUntil.", default: ["takeUntilDestroyed"] }
|
|
3003
|
-
},
|
|
3004
|
-
type: "object"
|
|
3005
|
-
}],
|
|
3006
|
-
type: "problem"
|
|
3007
|
-
},
|
|
3008
|
-
name: "no-sharereplay-before-takeuntil",
|
|
3009
|
-
create: (context) => {
|
|
3010
|
-
const [config = {}] = context.options;
|
|
3011
|
-
const { takeUntilAlias = ["takeUntilDestroyed"] } = config;
|
|
3012
|
-
function checkCallExpression(node) {
|
|
3013
|
-
const pipeCallExpression = node.parent;
|
|
3014
|
-
if (!pipeCallExpression.arguments || !isMemberExpression(pipeCallExpression.callee) || !isIdentifier(pipeCallExpression.callee.property) || pipeCallExpression.callee.property.name !== "pipe") {
|
|
3015
|
-
return;
|
|
3016
|
-
}
|
|
3017
|
-
const allTakeUntilAlias = ["takeUntil", ...takeUntilAlias];
|
|
3018
|
-
const takeUntilRegex = new RegExp(`^(${allTakeUntilAlias.join("|")})$`);
|
|
3019
|
-
const { isOrderValid, operatorNode: takeUntilNode } = findIsLastOperatorOrderValid(
|
|
3020
|
-
pipeCallExpression,
|
|
3021
|
-
takeUntilRegex,
|
|
3022
|
-
DEFAULT_VALID_POST_COMPLETION_OPERATORS
|
|
3023
|
-
);
|
|
3024
|
-
if (!isOrderValid || !takeUntilNode) {
|
|
3025
|
-
return;
|
|
3026
|
-
}
|
|
3027
|
-
if (takeUntilNode.range[0] < node.range[0]) {
|
|
3028
|
-
return;
|
|
3029
|
-
}
|
|
3030
|
-
const shareReplayConfig = node.arguments[0];
|
|
3031
|
-
if (!shareReplayConfig || !isObjectExpression(shareReplayConfig)) {
|
|
3032
|
-
context.report({
|
|
3033
|
-
messageId: "forbidden",
|
|
3034
|
-
data: { takeUntilAlias: isIdentifier(takeUntilNode) ? takeUntilNode.name : "takeUntil" },
|
|
3035
|
-
node: node.callee
|
|
3036
|
-
});
|
|
3037
|
-
return;
|
|
3038
|
-
}
|
|
3039
|
-
const refCountElement = shareReplayConfig.properties.filter(isProperty).find((prop) => isIdentifier(prop.key) && prop.key.name === "refCount");
|
|
3040
|
-
if (!refCountElement || isLiteral(refCountElement.value) && refCountElement.value.value === false) {
|
|
3041
|
-
context.report({
|
|
3042
|
-
messageId: "forbidden",
|
|
3043
|
-
data: { takeUntilAlias: isIdentifier(takeUntilNode) ? takeUntilNode.name : "takeUntil" },
|
|
3044
|
-
node: node.callee
|
|
3045
|
-
});
|
|
3046
|
-
}
|
|
3047
|
-
}
|
|
3048
|
-
return {
|
|
3049
|
-
'CallExpression[callee.name="shareReplay"]': (node) => {
|
|
3050
|
-
checkCallExpression(node);
|
|
3051
|
-
},
|
|
3052
|
-
'CallExpression[callee.property.name="shareReplay"]': (node) => {
|
|
3053
|
-
checkCallExpression(node);
|
|
3054
|
-
}
|
|
3055
|
-
};
|
|
3056
|
-
}
|
|
3057
|
-
});
|
|
3058
|
-
|
|
3059
|
-
// src/rules/no-subclass.ts
|
|
3060
|
-
var noSubclassRule = ruleCreator({
|
|
3061
|
-
defaultOptions: [],
|
|
3062
|
-
meta: {
|
|
3063
|
-
docs: {
|
|
3064
|
-
description: "Disallow subclassing RxJS classes.",
|
|
3065
|
-
recommended: "strict",
|
|
3066
|
-
requiresTypeChecking: true
|
|
3067
|
-
},
|
|
3068
|
-
messages: {
|
|
3069
|
-
forbidden: "Subclassing RxJS classes is forbidden."
|
|
3070
|
-
},
|
|
3071
|
-
schema: [],
|
|
3072
|
-
type: "problem"
|
|
3073
|
-
},
|
|
3074
|
-
name: "no-subclass",
|
|
3075
|
-
create: (context) => {
|
|
3076
|
-
const { couldBeType: couldBeType2 } = getTypeServices(context);
|
|
3077
|
-
const queryNames = [
|
|
3078
|
-
"AsyncSubject",
|
|
3079
|
-
"BehaviorSubject",
|
|
3080
|
-
"Observable",
|
|
3081
|
-
"ReplaySubject",
|
|
3082
|
-
"Scheduler",
|
|
3083
|
-
"Subject",
|
|
3084
|
-
"Subscriber"
|
|
3085
|
-
];
|
|
3086
|
-
return {
|
|
3087
|
-
[`ClassDeclaration[superClass.name=/^(${queryNames.join(
|
|
3088
|
-
"|"
|
|
3089
|
-
)})$/] > Identifier.superClass`]: (node) => {
|
|
3090
|
-
if (queryNames.some(
|
|
3091
|
-
(name2) => couldBeType2(node, name2, { name: /[/\\]rxjs[/\\]/ })
|
|
3092
|
-
)) {
|
|
3093
|
-
context.report({
|
|
3094
|
-
messageId: "forbidden",
|
|
3095
|
-
node
|
|
3096
|
-
});
|
|
3097
|
-
}
|
|
3098
|
-
}
|
|
3099
|
-
};
|
|
3100
|
-
}
|
|
3101
|
-
});
|
|
3102
|
-
|
|
3103
|
-
// src/rules/no-subject-unsubscribe.ts
|
|
3104
|
-
var noSubjectUnsubscribeRule = ruleCreator({
|
|
3105
|
-
defaultOptions: [],
|
|
3106
|
-
meta: {
|
|
3107
|
-
docs: {
|
|
3108
|
-
description: "Disallow calling the `unsubscribe` method of subjects.",
|
|
3109
|
-
recommended: "recommended",
|
|
3110
|
-
requiresTypeChecking: true
|
|
3111
|
-
},
|
|
3112
|
-
messages: {
|
|
3113
|
-
forbidden: "Calling unsubscribe on a subject is forbidden."
|
|
3114
|
-
},
|
|
3115
|
-
schema: [],
|
|
3116
|
-
type: "problem"
|
|
3117
|
-
},
|
|
3118
|
-
name: "no-subject-unsubscribe",
|
|
3119
|
-
create: (context) => {
|
|
3120
|
-
const { couldBeSubject, couldBeSubscription } = getTypeServices(context);
|
|
3121
|
-
return {
|
|
3122
|
-
"MemberExpression[property.name='unsubscribe']": (node) => {
|
|
3123
|
-
if (couldBeSubject(node.object)) {
|
|
3124
|
-
context.report({
|
|
3125
|
-
messageId: "forbidden",
|
|
3126
|
-
node: node.property
|
|
3127
|
-
});
|
|
3128
|
-
}
|
|
3129
|
-
},
|
|
3130
|
-
"CallExpression[callee.property.name='add'][arguments.length > 0]": (node) => {
|
|
3131
|
-
const memberExpression = node.callee;
|
|
3132
|
-
if (couldBeSubscription(memberExpression.object)) {
|
|
3133
|
-
const [arg] = node.arguments;
|
|
3134
|
-
if (couldBeSubject(arg)) {
|
|
3135
|
-
context.report({
|
|
3136
|
-
messageId: "forbidden",
|
|
3137
|
-
node: arg
|
|
3138
|
-
});
|
|
3139
|
-
}
|
|
3140
|
-
}
|
|
3141
|
-
}
|
|
3142
|
-
};
|
|
3143
|
-
}
|
|
3144
|
-
});
|
|
3145
|
-
|
|
3146
|
-
// src/rules/no-subject-value.ts
|
|
3147
|
-
var noSubjectValueRule = ruleCreator({
|
|
3148
|
-
defaultOptions: [],
|
|
3149
|
-
meta: {
|
|
3150
|
-
docs: {
|
|
3151
|
-
description: "Disallow accessing the `value` property of a `BehaviorSubject` instance.",
|
|
3152
|
-
requiresTypeChecking: true
|
|
3153
|
-
},
|
|
3154
|
-
messages: {
|
|
3155
|
-
forbidden: "Accessing the value property of a BehaviorSubject is forbidden."
|
|
3156
|
-
},
|
|
3157
|
-
schema: [],
|
|
3158
|
-
type: "problem"
|
|
3159
|
-
},
|
|
3160
|
-
name: "no-subject-value",
|
|
3161
|
-
create: (context) => {
|
|
3162
|
-
const { couldBeBehaviorSubject } = getTypeServices(context);
|
|
3163
|
-
return {
|
|
3164
|
-
"Identifier[name=/^(value|getValue)$/]": (node) => {
|
|
3165
|
-
const parent = node.parent;
|
|
3166
|
-
if (!parent || !("object" in parent)) {
|
|
3167
|
-
return;
|
|
3168
|
-
}
|
|
3169
|
-
if (couldBeBehaviorSubject(parent.object)) {
|
|
3170
|
-
context.report({
|
|
3171
|
-
messageId: "forbidden",
|
|
3172
|
-
node
|
|
3173
|
-
});
|
|
3174
|
-
}
|
|
3175
|
-
}
|
|
3176
|
-
};
|
|
3177
|
-
}
|
|
3178
|
-
});
|
|
3179
|
-
|
|
3180
|
-
// src/rules/no-subscribe-handlers.ts
|
|
3181
|
-
var noSubscribeHandlersRule = ruleCreator({
|
|
3182
|
-
defaultOptions: [],
|
|
3183
|
-
meta: {
|
|
3184
|
-
docs: {
|
|
3185
|
-
description: "Disallow passing handlers to `subscribe`.",
|
|
3186
|
-
requiresTypeChecking: true
|
|
3187
|
-
},
|
|
3188
|
-
messages: {
|
|
3189
|
-
forbidden: "Passing handlers to subscribe is forbidden."
|
|
3190
|
-
},
|
|
3191
|
-
schema: [],
|
|
3192
|
-
type: "problem"
|
|
3193
|
-
},
|
|
3194
|
-
name: "no-subscribe-handlers",
|
|
3195
|
-
create: (context) => {
|
|
3196
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
3197
|
-
return {
|
|
3198
|
-
"CallExpression[arguments.length > 0][callee.property.name='subscribe']": (node) => {
|
|
3199
|
-
const callee = node.callee;
|
|
3200
|
-
if (couldBeObservable(callee.object) || couldBeType2(callee.object, "Subscribable")) {
|
|
3201
|
-
context.report({
|
|
3202
|
-
messageId: "forbidden",
|
|
3203
|
-
node: callee.property
|
|
3204
|
-
});
|
|
3205
|
-
}
|
|
3206
|
-
}
|
|
3207
|
-
};
|
|
3208
|
-
}
|
|
3209
|
-
});
|
|
3210
|
-
|
|
3211
|
-
// src/rules/no-subscribe-in-pipe.ts
|
|
3212
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES7 } from "@typescript-eslint/utils";
|
|
3213
|
-
var noSubscribeInPipeRule = ruleCreator({
|
|
3214
|
-
defaultOptions: [],
|
|
3215
|
-
meta: {
|
|
3216
|
-
docs: {
|
|
3217
|
-
description: "Disallow calling of `subscribe` within any RxJS operator inside a `pipe`.",
|
|
3218
|
-
recommended: "recommended",
|
|
3219
|
-
requiresTypeChecking: true
|
|
3220
|
-
},
|
|
3221
|
-
messages: {
|
|
3222
|
-
forbidden: "Subscribe calls within pipe operators are forbidden."
|
|
3223
|
-
},
|
|
3224
|
-
schema: [],
|
|
3225
|
-
type: "problem"
|
|
3226
|
-
},
|
|
3227
|
-
name: "no-subscribe-in-pipe",
|
|
3228
|
-
create: (context) => {
|
|
3229
|
-
const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
|
|
3230
|
-
function isWithinPipe(node) {
|
|
3231
|
-
let parent = node.parent;
|
|
3232
|
-
while (parent) {
|
|
3233
|
-
if (parent.type === AST_NODE_TYPES7.CallExpression && parent.callee.type === AST_NODE_TYPES7.MemberExpression && parent.callee.property.type === AST_NODE_TYPES7.Identifier && parent.callee.property.name === "pipe") {
|
|
3234
|
-
return true;
|
|
3235
|
-
}
|
|
3236
|
-
parent = parent.parent;
|
|
3237
|
-
}
|
|
3238
|
-
return false;
|
|
3239
|
-
}
|
|
3240
|
-
return {
|
|
3241
|
-
"CallExpression > MemberExpression[property.name='subscribe']": (node) => {
|
|
3242
|
-
if (!couldBeObservable(node.object) && !couldBeType2(node.object, "Subscribable")) {
|
|
3243
|
-
return;
|
|
3244
|
-
}
|
|
3245
|
-
if (isWithinPipe(node)) {
|
|
3246
|
-
context.report({
|
|
3247
|
-
messageId: "forbidden",
|
|
3248
|
-
node: node.property
|
|
3249
|
-
});
|
|
3250
|
-
}
|
|
3251
|
-
}
|
|
3252
|
-
};
|
|
3253
|
-
}
|
|
3254
|
-
});
|
|
3255
|
-
|
|
3256
|
-
// src/rules/no-tap.ts
|
|
3257
|
-
var noTapRule = ruleCreator({
|
|
3258
|
-
defaultOptions: [],
|
|
3259
|
-
meta: {
|
|
3260
|
-
deprecated: true,
|
|
3261
|
-
docs: {
|
|
3262
|
-
description: "Disallow the `tap` operator."
|
|
3263
|
-
},
|
|
3264
|
-
messages: {
|
|
3265
|
-
forbidden: "The tap operator is forbidden."
|
|
3266
|
-
},
|
|
3267
|
-
replacedBy: ["ban-operators"],
|
|
3268
|
-
schema: [],
|
|
3269
|
-
type: "problem"
|
|
3270
|
-
},
|
|
3271
|
-
name: "no-tap",
|
|
3272
|
-
create: (context) => {
|
|
3273
|
-
return {
|
|
3274
|
-
[String.raw`ImportDeclaration[source.value=/^rxjs(\u002foperators)?$/] > ImportSpecifier[imported.name='tap']`]: (node) => {
|
|
3275
|
-
const { loc } = node;
|
|
3276
|
-
context.report({
|
|
3277
|
-
messageId: "forbidden",
|
|
3278
|
-
loc: {
|
|
3279
|
-
...loc,
|
|
3280
|
-
end: {
|
|
3281
|
-
...loc.start,
|
|
3282
|
-
column: loc.start.column + 3
|
|
3283
|
-
}
|
|
3284
|
-
}
|
|
3285
|
-
});
|
|
3286
|
-
}
|
|
3287
|
-
};
|
|
3288
|
-
}
|
|
3289
|
-
});
|
|
3290
|
-
|
|
3291
|
-
// src/rules/no-topromise.ts
|
|
3292
|
-
var noTopromiseRule = ruleCreator({
|
|
3293
|
-
defaultOptions: [],
|
|
3294
|
-
meta: {
|
|
3295
|
-
docs: {
|
|
3296
|
-
description: "Disallow use of the `toPromise` method.",
|
|
3297
|
-
recommended: "recommended",
|
|
3298
|
-
requiresTypeChecking: true
|
|
3299
|
-
},
|
|
3300
|
-
hasSuggestions: true,
|
|
3301
|
-
messages: {
|
|
3302
|
-
forbidden: "The toPromise method is forbidden.",
|
|
3303
|
-
suggestLastValueFromWithDefault: "Use lastValueFrom(..., { defaultValue: undefined }) instead.",
|
|
3304
|
-
suggestLastValueFrom: "Use lastValueFrom instead.",
|
|
3305
|
-
suggestFirstValueFrom: "Use firstValueFrom instead."
|
|
3306
|
-
},
|
|
3307
|
-
schema: [],
|
|
3308
|
-
type: "problem"
|
|
3309
|
-
},
|
|
3310
|
-
name: "no-topromise",
|
|
3311
|
-
create: (context) => {
|
|
3312
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
3313
|
-
function getQuote(raw) {
|
|
3314
|
-
const match = /^\s*('|")/.exec(raw);
|
|
3315
|
-
if (!match) {
|
|
3316
|
-
return void 0;
|
|
3317
|
-
}
|
|
3318
|
-
const [, quote] = match;
|
|
3319
|
-
return quote;
|
|
3320
|
-
}
|
|
3321
|
-
function createFix(conversion, callExpression, observableNode, importDeclarations, { withDefault } = {}) {
|
|
3322
|
-
return function* fix(fixer) {
|
|
3323
|
-
var _a, _b, _c;
|
|
3324
|
-
let namespace = "";
|
|
3325
|
-
let functionName = conversion;
|
|
3326
|
-
const rxjsImportDeclaration = importDeclarations.find((node) => node.source.value === "rxjs");
|
|
3327
|
-
if ((_a = rxjsImportDeclaration == null ? void 0 : rxjsImportDeclaration.specifiers) == null ? void 0 : _a.every(isImportNamespaceSpecifier)) {
|
|
3328
|
-
namespace = rxjsImportDeclaration.specifiers[0].local.name + ".";
|
|
3329
|
-
} else if ((_b = rxjsImportDeclaration == null ? void 0 : rxjsImportDeclaration.specifiers) == null ? void 0 : _b.every(isImportSpecifier)) {
|
|
3330
|
-
const { specifiers } = rxjsImportDeclaration;
|
|
3331
|
-
const existingSpecifier = specifiers.find((node) => (isIdentifier(node.imported) ? node.imported.name : node.imported.value) === functionName);
|
|
3332
|
-
if (existingSpecifier) {
|
|
3333
|
-
functionName = existingSpecifier.local.name;
|
|
3334
|
-
} else {
|
|
3335
|
-
const lastSpecifier = specifiers[specifiers.length - 1];
|
|
3336
|
-
yield fixer.insertTextAfter(lastSpecifier, `, ${functionName}`);
|
|
3337
|
-
}
|
|
3338
|
-
} else if (importDeclarations.length) {
|
|
3339
|
-
const lastImport = importDeclarations[importDeclarations.length - 1];
|
|
3340
|
-
const quote = (_c = getQuote(lastImport.source.raw)) != null ? _c : '"';
|
|
3341
|
-
yield fixer.insertTextAfter(
|
|
3342
|
-
importDeclarations[importDeclarations.length - 1],
|
|
3343
|
-
`
|
|
3344
|
-
import { ${functionName} } from ${quote}rxjs${quote};`
|
|
3345
|
-
);
|
|
3346
|
-
} else {
|
|
3347
|
-
console.warn("No import declarations found. Unable to suggest a fix.");
|
|
3348
|
-
return;
|
|
3349
|
-
}
|
|
3350
|
-
yield fixer.replaceText(
|
|
3351
|
-
callExpression,
|
|
3352
|
-
`${namespace}${functionName}(${context.sourceCode.getText(observableNode)}${withDefault ? ", { defaultValue: undefined }" : ""})`
|
|
3353
|
-
);
|
|
3354
|
-
};
|
|
3355
|
-
}
|
|
3356
|
-
return {
|
|
3357
|
-
[`CallExpression[callee.property.name="toPromise"]`]: (node) => {
|
|
3358
|
-
const memberExpression = node.callee;
|
|
3359
|
-
if (!couldBeObservable(memberExpression.object)) {
|
|
3360
|
-
return;
|
|
3361
|
-
}
|
|
3362
|
-
const { body } = context.sourceCode.ast;
|
|
3363
|
-
const importDeclarations = body.filter(isImportDeclaration);
|
|
3364
|
-
if (!importDeclarations.length) {
|
|
3365
|
-
return;
|
|
3366
|
-
}
|
|
3367
|
-
context.report({
|
|
3368
|
-
messageId: "forbidden",
|
|
3369
|
-
node: memberExpression.property,
|
|
3370
|
-
suggest: [
|
|
3371
|
-
{
|
|
3372
|
-
messageId: "suggestLastValueFromWithDefault",
|
|
3373
|
-
fix: createFix("lastValueFrom", node, memberExpression.object, importDeclarations, { withDefault: true })
|
|
3374
|
-
},
|
|
3375
|
-
{
|
|
3376
|
-
messageId: "suggestLastValueFrom",
|
|
3377
|
-
fix: createFix("lastValueFrom", node, memberExpression.object, importDeclarations)
|
|
3378
|
-
},
|
|
3379
|
-
{
|
|
3380
|
-
messageId: "suggestFirstValueFrom",
|
|
3381
|
-
fix: createFix("firstValueFrom", node, memberExpression.object, importDeclarations)
|
|
3382
|
-
}
|
|
3383
|
-
]
|
|
3384
|
-
});
|
|
3385
|
-
}
|
|
3386
|
-
};
|
|
3387
|
-
}
|
|
3388
|
-
});
|
|
3389
|
-
|
|
3390
|
-
// src/rules/no-unbound-methods.ts
|
|
3391
|
-
import { ESLintUtils as ESLintUtils10 } from "@typescript-eslint/utils";
|
|
3392
|
-
var defaultOptions12 = [];
|
|
3393
|
-
var noUnboundMethodsRule = ruleCreator({
|
|
3394
|
-
defaultOptions: defaultOptions12,
|
|
3395
|
-
meta: {
|
|
3396
|
-
docs: {
|
|
3397
|
-
description: "Disallow passing unbound methods.",
|
|
3398
|
-
recommended: "recommended",
|
|
3399
|
-
requiresTypeChecking: true
|
|
3400
|
-
},
|
|
3401
|
-
messages: {
|
|
3402
|
-
forbidden: "Unbound methods are forbidden."
|
|
3403
|
-
},
|
|
3404
|
-
schema: [
|
|
3405
|
-
{
|
|
3406
|
-
properties: {
|
|
3407
|
-
allowTypes: { type: "array", items: { type: "string" }, description: "An array of function types that are allowed to be passed unbound.", default: DEFAULT_UNBOUND_ALLOWED_TYPES }
|
|
3408
|
-
},
|
|
3409
|
-
type: "object"
|
|
3410
|
-
}
|
|
3411
|
-
],
|
|
3412
|
-
type: "problem"
|
|
3413
|
-
},
|
|
3414
|
-
name: "no-unbound-methods",
|
|
3415
|
-
create: (context) => {
|
|
3416
|
-
const { getTypeAtLocation } = ESLintUtils10.getParserServices(context);
|
|
3417
|
-
const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
|
|
3418
|
-
const nodeMap = /* @__PURE__ */ new WeakMap();
|
|
3419
|
-
const [config = {}] = context.options;
|
|
3420
|
-
const { allowTypes = DEFAULT_UNBOUND_ALLOWED_TYPES } = config;
|
|
3421
|
-
function mapArguments(node) {
|
|
3422
|
-
node.arguments.filter(isMemberExpression).forEach((arg) => {
|
|
3423
|
-
const argType = getTypeAtLocation(arg);
|
|
3424
|
-
if (allowTypes.some((t) => couldBeType(argType, t))) {
|
|
3425
|
-
return;
|
|
3426
|
-
}
|
|
3427
|
-
if (argType.getCallSignatures().length > 0) {
|
|
3428
|
-
nodeMap.set(arg);
|
|
3429
|
-
}
|
|
3430
|
-
});
|
|
3431
|
-
}
|
|
3432
|
-
function isObservableOrSubscription(node, action) {
|
|
3433
|
-
if (!isMemberExpression(node.callee)) {
|
|
3434
|
-
return;
|
|
3435
|
-
}
|
|
3436
|
-
if (couldBeObservable(node.callee.object) || couldBeSubscription(node.callee.object)) {
|
|
3437
|
-
action(node);
|
|
3438
|
-
}
|
|
3439
|
-
}
|
|
3440
|
-
return {
|
|
3441
|
-
"CallExpression[callee.property.name='pipe']": (node) => {
|
|
3442
|
-
isObservableOrSubscription(node, ({ arguments: args }) => {
|
|
3443
|
-
args.filter(isCallExpression).forEach(mapArguments);
|
|
3444
|
-
});
|
|
3445
|
-
},
|
|
3446
|
-
"CallExpression[callee.property.name=/^(add|subscribe)$/]": (node) => {
|
|
3447
|
-
isObservableOrSubscription(node, mapArguments);
|
|
3448
|
-
},
|
|
3449
|
-
"NewExpression[callee.name='Subscription']": mapArguments,
|
|
3450
|
-
"ThisExpression": (node) => {
|
|
3451
|
-
let parent = node.parent;
|
|
3452
|
-
while (parent) {
|
|
3453
|
-
if (nodeMap.has(parent)) {
|
|
3454
|
-
context.report({
|
|
3455
|
-
messageId: "forbidden",
|
|
3456
|
-
node: parent
|
|
3457
|
-
});
|
|
3458
|
-
return;
|
|
3459
|
-
}
|
|
3460
|
-
parent = parent.parent;
|
|
3461
|
-
}
|
|
3462
|
-
}
|
|
3463
|
-
};
|
|
3464
|
-
}
|
|
3465
|
-
});
|
|
3466
|
-
|
|
3467
|
-
// src/rules/no-unnecessary-collection.ts
|
|
3468
|
-
var noUnnecessaryCollectionRule = ruleCreator({
|
|
3469
|
-
defaultOptions: [],
|
|
3470
|
-
meta: {
|
|
3471
|
-
docs: {
|
|
3472
|
-
description: "Disallow unnecessary usage of collection arguments with single values.",
|
|
3473
|
-
recommended: "strict",
|
|
3474
|
-
requiresTypeChecking: false
|
|
3475
|
-
},
|
|
3476
|
-
messages: {
|
|
3477
|
-
forbidden: "Unnecessary {{operator}} with {{inputType}}. Use the observable directly instead."
|
|
3478
|
-
},
|
|
3479
|
-
schema: [],
|
|
3480
|
-
type: "suggestion"
|
|
3481
|
-
},
|
|
3482
|
-
name: "no-unnecessary-collection",
|
|
3483
|
-
create: (context) => {
|
|
3484
|
-
const { couldBeType: couldBeType2, couldBeObservable } = getTypeServices(context);
|
|
3485
|
-
function couldBeFromRxjs(node, operatorName) {
|
|
3486
|
-
return couldBeType2(node, operatorName, { name: /[/\\]rxjs[/\\]/ });
|
|
3487
|
-
}
|
|
3488
|
-
function checkCallExpression(node, operatorName) {
|
|
3489
|
-
const args = node.arguments;
|
|
3490
|
-
if (args.length === 0) {
|
|
3491
|
-
return;
|
|
3492
|
-
}
|
|
3493
|
-
const firstArg = args[0];
|
|
3494
|
-
if (isArrayExpression(firstArg)) {
|
|
3495
|
-
const nonNullElements = firstArg.elements.filter((element) => element !== null);
|
|
3496
|
-
if (nonNullElements.length === 1 && couldBeObservable(nonNullElements[0])) {
|
|
3497
|
-
context.report({
|
|
3498
|
-
messageId: "forbidden",
|
|
3499
|
-
node: node.callee,
|
|
3500
|
-
data: {
|
|
3501
|
-
operator: operatorName,
|
|
3502
|
-
inputType: "single-valued array"
|
|
3503
|
-
}
|
|
3504
|
-
});
|
|
3505
|
-
}
|
|
3506
|
-
return;
|
|
3507
|
-
}
|
|
3508
|
-
if (isObjectExpression(firstArg) && SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS.includes(operatorName)) {
|
|
3509
|
-
if (firstArg.properties.length === 1 && isProperty(firstArg.properties[0])) {
|
|
3510
|
-
const property = firstArg.properties[0];
|
|
3511
|
-
if (property.value && couldBeObservable(property.value)) {
|
|
3512
|
-
context.report({
|
|
3513
|
-
messageId: "forbidden",
|
|
3514
|
-
node: node.callee,
|
|
3515
|
-
data: {
|
|
3516
|
-
operator: operatorName,
|
|
3517
|
-
inputType: "single-property object"
|
|
3518
|
-
}
|
|
3519
|
-
});
|
|
3520
|
-
}
|
|
3521
|
-
}
|
|
3522
|
-
return;
|
|
3523
|
-
}
|
|
3524
|
-
if (args.length === 1 && !isSpreadElement(firstArg) && couldBeObservable(firstArg)) {
|
|
3525
|
-
context.report({
|
|
3526
|
-
messageId: "forbidden",
|
|
3527
|
-
node: node.callee,
|
|
3528
|
-
data: {
|
|
3529
|
-
operator: operatorName,
|
|
3530
|
-
inputType: "single argument"
|
|
3531
|
-
}
|
|
3532
|
-
});
|
|
3533
|
-
}
|
|
3534
|
-
}
|
|
3535
|
-
const callExpressionVisitors = {};
|
|
3536
|
-
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3537
|
-
callExpressionVisitors[`CallExpression[callee.name="${operator}"]`] = (node) => {
|
|
3538
|
-
if (couldBeFromRxjs(node.callee, operator)) {
|
|
3539
|
-
checkCallExpression(node, operator);
|
|
3540
|
-
}
|
|
3541
|
-
};
|
|
3542
|
-
}
|
|
3543
|
-
for (const operator of MULTIPLE_OBSERVABLE_ACCEPTING_STATIC_OBSERVABLE_CREATORS) {
|
|
3544
|
-
callExpressionVisitors[`CallExpression[callee.type="MemberExpression"][callee.property.name="${operator}"]`] = (node) => {
|
|
3545
|
-
const memberExpr = node.callee;
|
|
3546
|
-
if (couldBeFromRxjs(memberExpr.property, operator)) {
|
|
3547
|
-
checkCallExpression(node, operator);
|
|
3548
|
-
}
|
|
3549
|
-
};
|
|
3550
|
-
}
|
|
3551
|
-
return callExpressionVisitors;
|
|
3552
|
-
}
|
|
3553
|
-
});
|
|
3554
|
-
|
|
3555
|
-
// src/rules/no-unsafe-catch.ts
|
|
3556
|
-
import { stripIndent as stripIndent5 } from "common-tags";
|
|
3557
|
-
var defaultOptions13 = [];
|
|
3558
|
-
var noUnsafeCatchRule = ruleCreator({
|
|
3559
|
-
defaultOptions: defaultOptions13,
|
|
3560
|
-
meta: {
|
|
3561
|
-
docs: {
|
|
3562
|
-
description: "Disallow unsafe `catchError` usage in effects and epics.",
|
|
3563
|
-
requiresTypeChecking: true
|
|
3564
|
-
},
|
|
3565
|
-
messages: {
|
|
3566
|
-
forbidden: "Unsafe catchError usage in effects and epics are forbidden."
|
|
3567
|
-
},
|
|
3568
|
-
schema: [
|
|
3569
|
-
{
|
|
3570
|
-
properties: {
|
|
3571
|
-
observable: { type: "string", description: "A RegExp that matches an effect or epic's actions observable.", default: defaultObservable }
|
|
3572
|
-
},
|
|
3573
|
-
type: "object",
|
|
3574
|
-
description: stripIndent5`
|
|
3575
|
-
An optional object with an optional \`observable\` property.
|
|
3576
|
-
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`
|
|
3577
|
-
}
|
|
3578
|
-
],
|
|
3579
|
-
type: "problem"
|
|
3580
|
-
},
|
|
3581
|
-
name: "no-unsafe-catch",
|
|
3582
|
-
create: (context) => {
|
|
3583
|
-
const invalidOperatorsRegExp = /^(catchError)$/;
|
|
3584
|
-
const [config = {}] = context.options;
|
|
3585
|
-
const { observable = defaultObservable } = config;
|
|
3586
|
-
const observableRegExp = new RegExp(observable);
|
|
3587
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
3588
|
-
function isUnsafe([arg]) {
|
|
3589
|
-
if (arg && (isFunctionDeclaration(arg) || isArrowFunctionExpression(arg))) {
|
|
3590
|
-
return arg.params.length < 2;
|
|
3591
|
-
}
|
|
3592
|
-
return false;
|
|
3593
|
-
}
|
|
3594
|
-
function checkNode(node) {
|
|
3595
|
-
if (!node.arguments || !couldBeObservable(node)) {
|
|
3596
|
-
return;
|
|
3597
|
-
}
|
|
3598
|
-
node.arguments.forEach((arg) => {
|
|
3599
|
-
if (isCallExpression(arg) && isIdentifier(arg.callee)) {
|
|
3600
|
-
if (invalidOperatorsRegExp.test(arg.callee.name) && isUnsafe(arg.arguments)) {
|
|
3601
|
-
context.report({
|
|
3602
|
-
messageId: "forbidden",
|
|
3603
|
-
node: arg.callee
|
|
3604
|
-
});
|
|
3605
|
-
}
|
|
3606
|
-
}
|
|
3607
|
-
});
|
|
3608
|
-
}
|
|
3609
|
-
return {
|
|
3610
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.name=${observableRegExp}]`]: checkNode,
|
|
3611
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.property.name=${observableRegExp}]`]: checkNode
|
|
3612
|
-
};
|
|
3613
|
-
}
|
|
3614
|
-
});
|
|
3615
|
-
|
|
3616
|
-
// src/rules/no-unsafe-first.ts
|
|
3617
|
-
import { stripIndent as stripIndent6 } from "common-tags";
|
|
3618
|
-
var defaultOptions14 = [];
|
|
3619
|
-
var noUnsafeFirstRule = ruleCreator({
|
|
3620
|
-
defaultOptions: defaultOptions14,
|
|
3621
|
-
meta: {
|
|
3622
|
-
docs: {
|
|
3623
|
-
description: "Disallow unsafe `first`/`take` usage in effects and epics.",
|
|
3624
|
-
requiresTypeChecking: true
|
|
3625
|
-
},
|
|
3626
|
-
messages: {
|
|
3627
|
-
forbidden: "Unsafe first and take usage in effects and epics are forbidden."
|
|
3628
|
-
},
|
|
3629
|
-
schema: [
|
|
3630
|
-
{
|
|
3631
|
-
properties: {
|
|
3632
|
-
observable: { type: "string", description: "A RegExp that matches an effect or epic's actions observable.", default: defaultObservable }
|
|
3633
|
-
},
|
|
3634
|
-
type: "object",
|
|
3635
|
-
description: stripIndent6`
|
|
3636
|
-
An optional object with an optional \`observable\` property.
|
|
3637
|
-
The property can be specified as a regular expression string and is used to identify the action observables from which effects and epics are composed.`
|
|
3638
|
-
}
|
|
3639
|
-
],
|
|
3640
|
-
type: "problem"
|
|
3641
|
-
},
|
|
3642
|
-
name: "no-unsafe-first",
|
|
3643
|
-
create: (context) => {
|
|
3644
|
-
const invalidOperatorsRegExp = /^(take|first)$/;
|
|
3645
|
-
const [config = {}] = context.options;
|
|
3646
|
-
const { observable = defaultObservable } = config;
|
|
3647
|
-
const observableRegExp = new RegExp(observable);
|
|
3648
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
3649
|
-
const nodes = [];
|
|
3650
|
-
function checkNode(node) {
|
|
3651
|
-
if (!node.arguments || !couldBeObservable(node)) {
|
|
3652
|
-
return;
|
|
3653
|
-
}
|
|
3654
|
-
node.arguments.forEach((arg) => {
|
|
3655
|
-
if (isCallExpression(arg) && isIdentifier(arg.callee)) {
|
|
3656
|
-
if (invalidOperatorsRegExp.test(arg.callee.name)) {
|
|
3657
|
-
context.report({
|
|
3658
|
-
messageId: "forbidden",
|
|
3659
|
-
node: arg.callee
|
|
3660
|
-
});
|
|
3661
|
-
}
|
|
3662
|
-
}
|
|
3663
|
-
});
|
|
3664
|
-
}
|
|
3665
|
-
return {
|
|
3666
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.name=${observableRegExp}]`]: (node) => {
|
|
3667
|
-
if (nodes.push(node) === 1) {
|
|
3668
|
-
checkNode(node);
|
|
3669
|
-
}
|
|
3670
|
-
},
|
|
3671
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.name=${observableRegExp}]:exit`]: () => {
|
|
3672
|
-
nodes.pop();
|
|
3673
|
-
},
|
|
3674
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.property.name=${observableRegExp}]`]: (node) => {
|
|
3675
|
-
if (nodes.push(node) === 1) {
|
|
3676
|
-
checkNode(node);
|
|
3677
|
-
}
|
|
3678
|
-
},
|
|
3679
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.property.name=${observableRegExp}]:exit`]: () => {
|
|
3680
|
-
nodes.pop();
|
|
3681
|
-
}
|
|
3682
|
-
};
|
|
3683
|
-
}
|
|
3684
|
-
});
|
|
3685
|
-
|
|
3686
|
-
// src/rules/no-unsafe-subject-next.ts
|
|
3687
|
-
import { ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
|
|
3688
|
-
import * as tsutils5 from "ts-api-utils";
|
|
3689
|
-
import ts6 from "typescript";
|
|
3690
|
-
var noUnsafeSubjectNext = ruleCreator({
|
|
3691
|
-
defaultOptions: [],
|
|
3692
|
-
meta: {
|
|
3693
|
-
docs: {
|
|
3694
|
-
description: "Disallow unsafe optional `next` calls.",
|
|
3695
|
-
recommended: "recommended",
|
|
3696
|
-
requiresTypeChecking: true
|
|
3697
|
-
},
|
|
3698
|
-
messages: {
|
|
3699
|
-
forbidden: "Unsafe optional next calls are forbidden."
|
|
3700
|
-
},
|
|
3701
|
-
schema: [],
|
|
3702
|
-
type: "problem"
|
|
3703
|
-
},
|
|
3704
|
-
name: "no-unsafe-subject-next",
|
|
3705
|
-
create: (context) => {
|
|
3706
|
-
const { getTypeAtLocation, program } = ESLintUtils11.getParserServices(context);
|
|
3707
|
-
const typeChecker = program.getTypeChecker();
|
|
3708
|
-
return {
|
|
3709
|
-
[`CallExpression[callee.property.name='next']`]: (node) => {
|
|
3710
|
-
if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
|
|
3711
|
-
const type = getTypeAtLocation(node.callee.object);
|
|
3712
|
-
if (tsutils5.isTypeReference(type) && couldBeType(type, "Subject")) {
|
|
3713
|
-
const [typeArg] = typeChecker.getTypeArguments(type);
|
|
3714
|
-
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Any)) {
|
|
3715
|
-
return;
|
|
3716
|
-
}
|
|
3717
|
-
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Unknown)) {
|
|
3718
|
-
return;
|
|
3719
|
-
}
|
|
3720
|
-
if (tsutils5.isTypeFlagSet(typeArg, ts6.TypeFlags.Void)) {
|
|
3721
|
-
return;
|
|
3722
|
-
}
|
|
3723
|
-
if (tsutils5.isUnionType(typeArg) && typeArg.types.some(
|
|
3724
|
-
(t) => tsutils5.isTypeFlagSet(t, ts6.TypeFlags.Void)
|
|
3725
|
-
)) {
|
|
3726
|
-
return;
|
|
3727
|
-
}
|
|
3728
|
-
context.report({
|
|
3729
|
-
messageId: "forbidden",
|
|
3730
|
-
node: node.callee.property
|
|
3731
|
-
});
|
|
3732
|
-
}
|
|
3733
|
-
}
|
|
3734
|
-
}
|
|
3735
|
-
};
|
|
3736
|
-
}
|
|
3737
|
-
});
|
|
3738
|
-
|
|
3739
|
-
// src/rules/no-unsafe-switchmap.ts
|
|
3740
|
-
import { stripIndent as stripIndent7 } from "common-tags";
|
|
3741
|
-
import decamelize from "decamelize";
|
|
3742
|
-
var DEFAULT_DISALLOW = [
|
|
3743
|
-
"add",
|
|
3744
|
-
"create",
|
|
3745
|
-
"delete",
|
|
3746
|
-
"post",
|
|
3747
|
-
"put",
|
|
3748
|
-
"remove",
|
|
3749
|
-
"set",
|
|
3750
|
-
"update"
|
|
3751
|
-
];
|
|
3752
|
-
var defaultOptions15 = [];
|
|
3753
|
-
var noUnsafeSwitchmapRule = ruleCreator({
|
|
3754
|
-
defaultOptions: defaultOptions15,
|
|
3755
|
-
meta: {
|
|
3756
|
-
docs: {
|
|
3757
|
-
description: "Disallow unsafe `switchMap` usage in effects and epics.",
|
|
3758
|
-
requiresTypeChecking: true
|
|
3759
|
-
},
|
|
3760
|
-
messages: {
|
|
3761
|
-
forbidden: "Unsafe switchMap usage in effects and epics is forbidden."
|
|
3762
|
-
},
|
|
3763
|
-
schema: [
|
|
3764
|
-
{
|
|
3765
|
-
properties: {
|
|
3766
|
-
allow: {
|
|
3767
|
-
description: "Action types that are allowed to be used with switchMap. Mutually exclusive with `disallow`.",
|
|
3768
|
-
oneOf: [
|
|
3769
|
-
{ type: "string", description: "A regular expression string." },
|
|
3770
|
-
{ type: "array", items: { type: "string" }, description: "An array of words." }
|
|
3771
|
-
]
|
|
3772
|
-
},
|
|
3773
|
-
disallow: {
|
|
3774
|
-
description: "Action types that are disallowed to be used with switchMap. Mutually exclusive with `allow`.",
|
|
3775
|
-
oneOf: [
|
|
3776
|
-
{ type: "string", description: "A regular expression string." },
|
|
3777
|
-
{ type: "array", items: { type: "string" }, description: "An array of words." }
|
|
3778
|
-
],
|
|
3779
|
-
default: DEFAULT_DISALLOW
|
|
3780
|
-
},
|
|
3781
|
-
observable: {
|
|
3782
|
-
type: "string",
|
|
3783
|
-
description: "A RegExp that matches an effect or epic's actions observable.",
|
|
3784
|
-
default: defaultObservable
|
|
3785
|
-
}
|
|
3786
|
-
},
|
|
3787
|
-
type: "object",
|
|
3788
|
-
description: stripIndent7`
|
|
3789
|
-
An optional object with optional \`allow\`, \`disallow\` and \`observable\` properties.
|
|
3790
|
-
The properties can be specified as regular expression strings or as arrays of words.
|
|
3791
|
-
The \`allow\` or \`disallow\` properties are mutually exclusive. Whether or not
|
|
3792
|
-
\`switchMap\` is allowed will depend upon the matching of action types with \`allow\` or \`disallow\`.
|
|
3793
|
-
The \`observable\` property is used to identify the action observables from which effects and epics are composed.
|
|
3794
|
-
`
|
|
3795
|
-
}
|
|
3796
|
-
],
|
|
3797
|
-
type: "problem"
|
|
3798
|
-
},
|
|
3799
|
-
name: "no-unsafe-switchmap",
|
|
3800
|
-
create: (context) => {
|
|
3801
|
-
var _a, _b, _c;
|
|
3802
|
-
let allowRegExp = void 0;
|
|
3803
|
-
let disallowRegExp = void 0;
|
|
3804
|
-
const [config = {}] = context.options;
|
|
3805
|
-
if (config.allow) {
|
|
3806
|
-
allowRegExp = createRegExpForWords((_a = config.allow) != null ? _a : []);
|
|
3807
|
-
} else {
|
|
3808
|
-
disallowRegExp = createRegExpForWords((_b = config.disallow) != null ? _b : DEFAULT_DISALLOW);
|
|
3809
|
-
}
|
|
3810
|
-
const observableRegExp = new RegExp((_c = config.observable) != null ? _c : defaultObservable);
|
|
3811
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
3812
|
-
function shouldDisallow(args) {
|
|
3813
|
-
const names = args.map((arg) => {
|
|
3814
|
-
if (isLiteral(arg) && typeof arg.value === "string") {
|
|
3815
|
-
return arg.value;
|
|
3816
|
-
}
|
|
3817
|
-
if (isIdentifier(arg)) {
|
|
3818
|
-
return arg.name;
|
|
3819
|
-
}
|
|
3820
|
-
if (isMemberExpression(arg) && isIdentifier(arg.property)) {
|
|
3821
|
-
return arg.property.name;
|
|
3822
|
-
}
|
|
3823
|
-
return "";
|
|
3824
|
-
}).map((name2) => decamelize(name2));
|
|
3825
|
-
if (allowRegExp) {
|
|
3826
|
-
return !names.every((name2) => allowRegExp == null ? void 0 : allowRegExp.test(name2));
|
|
3827
|
-
}
|
|
3828
|
-
if (disallowRegExp) {
|
|
3829
|
-
return names.some((name2) => disallowRegExp == null ? void 0 : disallowRegExp.test(name2));
|
|
3830
|
-
}
|
|
3831
|
-
return false;
|
|
3832
|
-
}
|
|
3833
|
-
function checkNode(node) {
|
|
3834
|
-
if (!node.arguments || !couldBeObservable(node)) {
|
|
3835
|
-
return;
|
|
3836
|
-
}
|
|
3837
|
-
const hasUnsafeOfType = node.arguments.some((arg) => {
|
|
3838
|
-
if (isCallExpression(arg) && isIdentifier(arg.callee) && arg.callee.name === "ofType") {
|
|
3839
|
-
return shouldDisallow(arg.arguments);
|
|
3840
|
-
}
|
|
3841
|
-
return false;
|
|
3842
|
-
});
|
|
3843
|
-
if (!hasUnsafeOfType) {
|
|
3844
|
-
return;
|
|
3845
|
-
}
|
|
3846
|
-
node.arguments.forEach((arg) => {
|
|
3847
|
-
if (isCallExpression(arg) && isIdentifier(arg.callee) && arg.callee.name === "switchMap") {
|
|
3848
|
-
context.report({
|
|
3849
|
-
messageId: "forbidden",
|
|
3850
|
-
node: arg.callee
|
|
3851
|
-
});
|
|
3852
|
-
}
|
|
3853
|
-
});
|
|
3854
|
-
}
|
|
3855
|
-
return {
|
|
3856
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.name=${observableRegExp}]`]: checkNode,
|
|
3857
|
-
[`CallExpression[callee.property.name='pipe'][callee.object.property.name=${observableRegExp}]`]: checkNode
|
|
3858
|
-
};
|
|
3859
|
-
}
|
|
3860
|
-
});
|
|
3861
|
-
|
|
3862
|
-
// src/rules/no-unsafe-takeuntil.ts
|
|
3863
|
-
import { stripIndent as stripIndent8 } from "common-tags";
|
|
3864
|
-
var defaultOptions16 = [];
|
|
3865
|
-
var noUnsafeTakeuntilRule = ruleCreator({
|
|
3866
|
-
defaultOptions: defaultOptions16,
|
|
3867
|
-
meta: {
|
|
3868
|
-
docs: {
|
|
3869
|
-
description: "Disallow applying operators after `takeUntil`.",
|
|
3870
|
-
recommended: "recommended",
|
|
3871
|
-
requiresTypeChecking: true
|
|
3872
|
-
},
|
|
3873
|
-
messages: {
|
|
3874
|
-
forbidden: "Applying operators after takeUntil is forbidden."
|
|
3875
|
-
},
|
|
3876
|
-
schema: [
|
|
3877
|
-
{
|
|
3878
|
-
properties: {
|
|
3879
|
-
alias: { type: "array", items: { type: "string" }, description: "An array of operator names that should be treated similarly to `takeUntil`." },
|
|
3880
|
-
allow: { type: "array", items: { type: "string" }, description: "An array of operator names that are allowed to follow `takeUntil`.", default: DEFAULT_VALID_POST_COMPLETION_OPERATORS }
|
|
3881
|
-
},
|
|
3882
|
-
type: "object",
|
|
3883
|
-
description: stripIndent8`
|
|
3884
|
-
An optional object with optional \`alias\` and \`allow\` properties.
|
|
3885
|
-
The \`alias\` property is an array containing the names of operators that aliases for \`takeUntil\`.
|
|
3886
|
-
The \`allow\` property is an array containing the names of the operators that are allowed to follow \`takeUntil\`.`
|
|
3887
|
-
}
|
|
3888
|
-
],
|
|
3889
|
-
type: "problem"
|
|
3890
|
-
},
|
|
3891
|
-
name: "no-unsafe-takeuntil",
|
|
3892
|
-
create: (context) => {
|
|
3893
|
-
let checkedOperatorsRegExp = /^takeUntil$/;
|
|
3894
|
-
const [config = {}] = context.options;
|
|
3895
|
-
const { alias, allow = DEFAULT_VALID_POST_COMPLETION_OPERATORS } = config;
|
|
3896
|
-
if (alias) {
|
|
3897
|
-
checkedOperatorsRegExp = new RegExp(
|
|
3898
|
-
`^(${alias.concat("takeUntil").join("|")})$`
|
|
3899
|
-
);
|
|
3900
|
-
}
|
|
3901
|
-
const { couldBeObservable } = getTypeServices(context);
|
|
3902
|
-
function checkNode(node) {
|
|
3903
|
-
const pipeCallExpression = node.parent;
|
|
3904
|
-
if (!pipeCallExpression.arguments || !couldBeObservable(pipeCallExpression)) {
|
|
3905
|
-
return;
|
|
3906
|
-
}
|
|
3907
|
-
const { isOrderValid, operatorNode } = findIsLastOperatorOrderValid(
|
|
3908
|
-
pipeCallExpression,
|
|
3909
|
-
checkedOperatorsRegExp,
|
|
3910
|
-
allow
|
|
3911
|
-
);
|
|
3912
|
-
if (!isOrderValid && operatorNode) {
|
|
3913
|
-
context.report({
|
|
3914
|
-
messageId: "forbidden",
|
|
3915
|
-
node: operatorNode
|
|
3916
|
-
});
|
|
3917
|
-
}
|
|
3918
|
-
}
|
|
3919
|
-
return {
|
|
3920
|
-
[`CallExpression[callee.property.name='pipe'] > CallExpression[callee.name=${checkedOperatorsRegExp}]`]: checkNode,
|
|
3921
|
-
[`CallExpression[callee.property.name='pipe'] > CallExpression[callee.property.name=${checkedOperatorsRegExp}]`]: checkNode
|
|
3922
|
-
};
|
|
3923
|
-
}
|
|
3924
|
-
});
|
|
3925
|
-
|
|
3926
|
-
// src/rules/prefer-observer.ts
|
|
3927
|
-
var defaultOptions17 = [];
|
|
3928
|
-
var preferObserverRule = ruleCreator({
|
|
3929
|
-
defaultOptions: defaultOptions17,
|
|
3930
|
-
meta: {
|
|
3931
|
-
docs: {
|
|
3932
|
-
description: "Disallow passing separate handlers to `subscribe` and `tap`.",
|
|
3933
|
-
recommended: "recommended",
|
|
3934
|
-
requiresTypeChecking: true
|
|
3935
|
-
},
|
|
3936
|
-
fixable: "code",
|
|
3937
|
-
hasSuggestions: true,
|
|
3938
|
-
messages: {
|
|
3939
|
-
forbidden: "Passing separate handlers is forbidden; pass an observer instead.",
|
|
3940
|
-
suggest: "Replace with observer object."
|
|
3941
|
-
},
|
|
3942
|
-
schema: [
|
|
3943
|
-
{
|
|
3944
|
-
properties: {
|
|
3945
|
-
allowNext: { type: "boolean", description: "Allows a single `next` callback.", default: true }
|
|
3946
|
-
},
|
|
3947
|
-
type: "object"
|
|
3948
|
-
}
|
|
3949
|
-
],
|
|
3950
|
-
type: "problem"
|
|
3951
|
-
},
|
|
3952
|
-
name: "prefer-observer",
|
|
3953
|
-
create: (context) => {
|
|
3954
|
-
const { couldBeFunction: couldBeFunction2, couldBeObservable } = getTypeServices(context);
|
|
3955
|
-
const [config = {}] = context.options;
|
|
3956
|
-
const { allowNext = true } = config;
|
|
3957
|
-
function checkArgs(callExpression, reportNode) {
|
|
3958
|
-
const { arguments: args, callee } = callExpression;
|
|
3959
|
-
if (isMemberExpression(callee) && !couldBeObservable(callee.object)) {
|
|
3960
|
-
return;
|
|
3961
|
-
}
|
|
3962
|
-
function* fix(fixer) {
|
|
3963
|
-
const sourceCode = context.sourceCode;
|
|
3964
|
-
const [nextArg, errorArg, completeArg] = args;
|
|
3965
|
-
const nextArgText = nextArg ? sourceCode.getText(nextArg) : "";
|
|
3966
|
-
const errorArgText = errorArg ? sourceCode.getText(errorArg) : "";
|
|
3967
|
-
const completeArgText = completeArg ? sourceCode.getText(completeArg) : "";
|
|
3968
|
-
let observer = "{";
|
|
3969
|
-
if (nextArgText && nextArgText !== "undefined" && nextArgText !== "null") {
|
|
3970
|
-
observer += ` next: ${nextArgText}${isValidArgText(errorArgText) || isValidArgText(completeArgText) ? "," : ""}`;
|
|
3971
|
-
}
|
|
3972
|
-
if (errorArgText && errorArgText !== "undefined" && errorArgText !== "null") {
|
|
3973
|
-
observer += ` error: ${errorArgText}${isValidArgText(completeArgText) ? "," : ""}`;
|
|
3974
|
-
}
|
|
3975
|
-
if (completeArgText && completeArgText !== "undefined" && completeArgText !== "null") {
|
|
3976
|
-
observer += ` complete: ${completeArgText}`;
|
|
3977
|
-
}
|
|
3978
|
-
observer += " }";
|
|
3979
|
-
yield fixer.replaceText(callExpression.arguments[0], observer);
|
|
3980
|
-
const [, start] = callExpression.arguments[0].range;
|
|
3981
|
-
const [, end] = callExpression.arguments[callExpression.arguments.length - 1].range;
|
|
3982
|
-
yield fixer.removeRange([start, end]);
|
|
3983
|
-
}
|
|
3984
|
-
if (args.length > 1) {
|
|
3985
|
-
context.report({
|
|
3986
|
-
messageId: "forbidden",
|
|
3987
|
-
node: reportNode,
|
|
3988
|
-
fix,
|
|
3989
|
-
suggest: [
|
|
3990
|
-
{
|
|
3991
|
-
messageId: "suggest",
|
|
3992
|
-
fix
|
|
3993
|
-
}
|
|
3994
|
-
]
|
|
3995
|
-
});
|
|
3996
|
-
} else if (args.length === 1 && !allowNext) {
|
|
3997
|
-
const [arg] = args;
|
|
3998
|
-
if (isArrowFunctionExpression(arg) || isFunctionExpression(arg) || couldBeFunction2(arg)) {
|
|
3999
|
-
context.report({
|
|
4000
|
-
messageId: "forbidden",
|
|
4001
|
-
node: reportNode,
|
|
4002
|
-
fix,
|
|
4003
|
-
suggest: [
|
|
4004
|
-
{
|
|
4005
|
-
messageId: "suggest",
|
|
4006
|
-
fix
|
|
4007
|
-
}
|
|
4008
|
-
]
|
|
4009
|
-
});
|
|
4010
|
-
}
|
|
4011
|
-
}
|
|
4012
|
-
}
|
|
4013
|
-
return {
|
|
4014
|
-
"CallExpression[callee.property.name='pipe'] > CallExpression[callee.name='tap']": (node) => {
|
|
4015
|
-
checkArgs(node, node.callee);
|
|
4016
|
-
},
|
|
4017
|
-
"CallExpression[callee.property.name='subscribe']": (node) => {
|
|
4018
|
-
checkArgs(node, node.callee.property);
|
|
4019
|
-
}
|
|
4020
|
-
};
|
|
4021
|
-
}
|
|
4022
|
-
});
|
|
4023
|
-
function isValidArgText(argText) {
|
|
4024
|
-
return argText && argText !== "undefined" && argText !== "null";
|
|
4025
|
-
}
|
|
4026
|
-
|
|
4027
|
-
// src/rules/prefer-root-operators.ts
|
|
4028
|
-
var RENAMED_OPERATORS = {
|
|
4029
|
-
combineLatest: "combineLatestWith",
|
|
4030
|
-
concat: "concatWith",
|
|
4031
|
-
merge: "mergeWith",
|
|
4032
|
-
onErrorResumeNext: "onErrorResumeNextWith",
|
|
4033
|
-
race: "raceWith",
|
|
4034
|
-
zip: "zipWith"
|
|
4035
|
-
};
|
|
4036
|
-
var DEPRECATED_OPERATORS = [
|
|
4037
|
-
"partition"
|
|
4038
|
-
];
|
|
4039
|
-
var preferRootOperatorsRule = ruleCreator({
|
|
4040
|
-
defaultOptions: [],
|
|
4041
|
-
meta: {
|
|
4042
|
-
docs: {
|
|
4043
|
-
description: "Disallow importing operators from `rxjs/operators`.",
|
|
4044
|
-
recommended: "recommended"
|
|
4045
|
-
},
|
|
4046
|
-
fixable: "code",
|
|
4047
|
-
hasSuggestions: true,
|
|
4048
|
-
messages: {
|
|
4049
|
-
forbidden: "RxJS imports from `rxjs/operators` are forbidden; import from `rxjs` instead.",
|
|
4050
|
-
forbiddenWithoutFix: "RxJS imports from `rxjs/operators` are forbidden; import from `rxjs` instead. Note some operators may have been renamed or deprecated.",
|
|
4051
|
-
suggest: "Replace with import from `rxjs`."
|
|
4052
|
-
},
|
|
4053
|
-
schema: [],
|
|
4054
|
-
type: "suggestion"
|
|
4055
|
-
},
|
|
4056
|
-
name: "prefer-root-operators",
|
|
4057
|
-
create: (context) => {
|
|
4058
|
-
function getQuote(raw) {
|
|
4059
|
-
const match = /^\s*('|")/.exec(raw);
|
|
4060
|
-
if (!match) {
|
|
4061
|
-
return void 0;
|
|
4062
|
-
}
|
|
4063
|
-
const [, quote] = match;
|
|
4064
|
-
return quote;
|
|
4065
|
-
}
|
|
4066
|
-
function getSourceReplacement(rawLocation) {
|
|
4067
|
-
const quote = getQuote(rawLocation);
|
|
4068
|
-
if (!quote) {
|
|
4069
|
-
return void 0;
|
|
4070
|
-
}
|
|
4071
|
-
if (/^['"]rxjs\/operators/.test(rawLocation)) {
|
|
4072
|
-
return `${quote}rxjs${quote}`;
|
|
4073
|
-
}
|
|
4074
|
-
return void 0;
|
|
4075
|
-
}
|
|
4076
|
-
function hasDeprecatedOperators(specifiers) {
|
|
4077
|
-
return !!(specifiers == null ? void 0 : specifiers.some((s) => DEPRECATED_OPERATORS.includes(getName(getOperatorNode(s)))));
|
|
4078
|
-
}
|
|
4079
|
-
function getName(node) {
|
|
4080
|
-
return isIdentifier(node) ? node.name : node.value;
|
|
4081
|
-
}
|
|
4082
|
-
function getOperatorNode(node) {
|
|
4083
|
-
return isImportSpecifier(node) ? node.imported : node.local;
|
|
4084
|
-
}
|
|
4085
|
-
function getAliasNode(node) {
|
|
4086
|
-
return isImportSpecifier(node) ? node.local : node.exported;
|
|
4087
|
-
}
|
|
4088
|
-
function getOperatorReplacement(name2) {
|
|
4089
|
-
return RENAMED_OPERATORS[name2];
|
|
4090
|
-
}
|
|
4091
|
-
function isNodesEqual(a, b) {
|
|
4092
|
-
return a.range[0] === b.range[0] && a.range[1] === b.range[1];
|
|
4093
|
-
}
|
|
4094
|
-
function createFix(source, replacement, specifiers) {
|
|
4095
|
-
return function* fix(fixer) {
|
|
4096
|
-
yield fixer.replaceText(source, replacement);
|
|
4097
|
-
for (const specifier of specifiers) {
|
|
4098
|
-
const operatorNode = getOperatorNode(specifier);
|
|
4099
|
-
const operatorName = getName(operatorNode);
|
|
4100
|
-
const operatorReplacement = getOperatorReplacement(operatorName);
|
|
4101
|
-
if (!operatorReplacement) {
|
|
4102
|
-
continue;
|
|
4103
|
-
}
|
|
4104
|
-
const aliasNode = getAliasNode(specifier);
|
|
4105
|
-
if (isNodesEqual(aliasNode, operatorNode)) {
|
|
4106
|
-
yield fixer.insertTextBefore(operatorNode, operatorReplacement + " as ");
|
|
4107
|
-
} else if (isIdentifier(operatorNode)) {
|
|
4108
|
-
yield fixer.replaceText(operatorNode, operatorReplacement);
|
|
4109
|
-
} else {
|
|
4110
|
-
const quote = getQuote(operatorNode.raw);
|
|
4111
|
-
if (!quote) {
|
|
4112
|
-
continue;
|
|
4113
|
-
}
|
|
4114
|
-
yield fixer.replaceText(operatorNode, quote + operatorReplacement + quote);
|
|
4115
|
-
}
|
|
4116
|
-
}
|
|
4117
|
-
};
|
|
4118
|
-
}
|
|
4119
|
-
function reportNode(source, specifiers) {
|
|
4120
|
-
const replacement = getSourceReplacement(source.raw);
|
|
4121
|
-
if (!replacement || hasDeprecatedOperators(specifiers)) {
|
|
4122
|
-
context.report({
|
|
4123
|
-
messageId: "forbiddenWithoutFix",
|
|
4124
|
-
node: source
|
|
4125
|
-
});
|
|
4126
|
-
return;
|
|
4127
|
-
}
|
|
4128
|
-
if (!specifiers) {
|
|
4129
|
-
context.report({
|
|
4130
|
-
messageId: "forbiddenWithoutFix",
|
|
4131
|
-
node: source,
|
|
4132
|
-
suggest: [{ messageId: "suggest", fix: (fixer) => fixer.replaceText(source, replacement) }]
|
|
4133
|
-
});
|
|
4134
|
-
return;
|
|
4135
|
-
}
|
|
4136
|
-
const fix = createFix(source, replacement, specifiers);
|
|
4137
|
-
context.report({
|
|
4138
|
-
fix,
|
|
4139
|
-
messageId: "forbidden",
|
|
4140
|
-
node: source,
|
|
4141
|
-
suggest: [{ messageId: "suggest", fix }]
|
|
4142
|
-
});
|
|
4143
|
-
}
|
|
4144
|
-
return {
|
|
4145
|
-
'ImportDeclaration[source.value="rxjs/operators"]': (node) => {
|
|
4146
|
-
const specifiers = node.specifiers.length && node.specifiers.every((importClause) => isImportSpecifier(importClause)) ? node.specifiers : void 0;
|
|
4147
|
-
reportNode(node.source, specifiers);
|
|
4148
|
-
},
|
|
4149
|
-
'ImportExpression[source.value="rxjs/operators"]': (node) => {
|
|
4150
|
-
if (isLiteral(node.source)) {
|
|
4151
|
-
reportNode(node.source);
|
|
4152
|
-
}
|
|
4153
|
-
},
|
|
4154
|
-
'ExportNamedDeclaration[source.value="rxjs/operators"]': (node) => {
|
|
4155
|
-
reportNode(node.source, node.specifiers);
|
|
4156
|
-
},
|
|
4157
|
-
'ExportAllDeclaration[source.value="rxjs/operators"]': (node) => {
|
|
4158
|
-
reportNode(node.source);
|
|
4159
|
-
}
|
|
4160
|
-
};
|
|
4161
|
-
}
|
|
4162
|
-
});
|
|
4163
|
-
|
|
4164
|
-
// src/rules/suffix-subjects.ts
|
|
4165
|
-
import { ESLintUtils as ESLintUtils12 } from "@typescript-eslint/utils";
|
|
4166
|
-
var defaultOptions18 = [];
|
|
4167
|
-
var baseShouldHaveSuffix = 'Subject identifiers must end with "{{suffix}}".';
|
|
4168
|
-
var suffixSubjectsRule = ruleCreator({
|
|
4169
|
-
defaultOptions: defaultOptions18,
|
|
4170
|
-
meta: {
|
|
4171
|
-
docs: {
|
|
4172
|
-
description: "Enforce the use of a suffix in subject identifiers.",
|
|
4173
|
-
requiresTypeChecking: true
|
|
4174
|
-
},
|
|
4175
|
-
messages: {
|
|
4176
|
-
forbidden: baseShouldHaveSuffix,
|
|
4177
|
-
forbiddenProperty: `${baseShouldHaveSuffix} Add a type annotation, assertion, or 'satisfies' to silence this rule.`
|
|
4178
|
-
},
|
|
4179
|
-
schema: [
|
|
4180
|
-
{
|
|
4181
|
-
properties: {
|
|
4182
|
-
parameters: { type: "boolean", description: "Require for parameters." },
|
|
4183
|
-
properties: { type: "boolean", description: 'Require for properties, except object literal keys (see "objects" option).' },
|
|
4184
|
-
objects: { type: "boolean", description: "Require for object literal keys." },
|
|
4185
|
-
suffix: { type: "string", description: "The suffix to enforce." },
|
|
4186
|
-
types: { type: "object", description: "Enforce for specific types. Keys are a RegExp, values are a boolean." },
|
|
4187
|
-
variables: { type: "boolean", description: "Require for variables." }
|
|
4188
|
-
},
|
|
4189
|
-
type: "object"
|
|
4190
|
-
}
|
|
4191
|
-
],
|
|
4192
|
-
type: "problem"
|
|
4193
|
-
},
|
|
4194
|
-
name: "suffix-subjects",
|
|
4195
|
-
create: (context) => {
|
|
4196
|
-
const { esTreeNodeToTSNodeMap } = ESLintUtils12.getParserServices(context);
|
|
4197
|
-
const { couldBeType: couldBeType2 } = getTypeServices(context);
|
|
4198
|
-
const [config = {}] = context.options;
|
|
4199
|
-
const validate = {
|
|
4200
|
-
parameters: true,
|
|
4201
|
-
properties: true,
|
|
4202
|
-
objects: true,
|
|
4203
|
-
variables: true,
|
|
4204
|
-
...config
|
|
4205
|
-
};
|
|
4206
|
-
const types = [];
|
|
4207
|
-
if (config.types) {
|
|
4208
|
-
Object.entries(config.types).forEach(
|
|
4209
|
-
([key, validate2]) => {
|
|
4210
|
-
types.push({ regExp: new RegExp(key), validate: validate2 });
|
|
4211
|
-
}
|
|
4212
|
-
);
|
|
4213
|
-
} else {
|
|
4214
|
-
types.push({
|
|
4215
|
-
regExp: /^EventEmitter$/,
|
|
4216
|
-
validate: false
|
|
4217
|
-
});
|
|
4218
|
-
}
|
|
4219
|
-
const { suffix = "Subject" } = config;
|
|
4220
|
-
const suffixRegex = new RegExp(
|
|
4221
|
-
String.raw`${escapeRegExp(suffix)}\$?$`,
|
|
4222
|
-
"i"
|
|
4223
|
-
);
|
|
4224
|
-
function checkNode(nameNode, typeNode, shouldMessage = "forbidden") {
|
|
4225
|
-
const tsNode = esTreeNodeToTSNodeMap.get(nameNode);
|
|
4226
|
-
const text = tsNode.getText();
|
|
4227
|
-
if (!suffixRegex.test(text) && couldBeType2(typeNode != null ? typeNode : nameNode, "Subject")) {
|
|
4228
|
-
for (const type of types) {
|
|
4229
|
-
const { regExp, validate: validate2 } = type;
|
|
4230
|
-
if (couldBeType2(typeNode != null ? typeNode : nameNode, regExp) && !validate2) {
|
|
4231
|
-
return;
|
|
4232
|
-
}
|
|
4233
|
-
}
|
|
4234
|
-
context.report({
|
|
4235
|
-
data: { suffix },
|
|
4236
|
-
loc: getLoc(tsNode),
|
|
4237
|
-
messageId: shouldMessage
|
|
4238
|
-
});
|
|
4239
|
-
}
|
|
4240
|
-
}
|
|
4241
|
-
return {
|
|
4242
|
-
"ArrayPattern > Identifier": (node) => {
|
|
4243
|
-
const found = findParent(
|
|
4244
|
-
node,
|
|
4245
|
-
"ArrowFunctionExpression",
|
|
4246
|
-
"FunctionDeclaration",
|
|
4247
|
-
"FunctionExpression",
|
|
4248
|
-
"VariableDeclarator"
|
|
4249
|
-
);
|
|
4250
|
-
if (!found) {
|
|
4251
|
-
return;
|
|
4252
|
-
}
|
|
4253
|
-
if (!validate.variables && isVariableDeclarator(found)) {
|
|
4254
|
-
return;
|
|
4255
|
-
}
|
|
4256
|
-
if (!validate.parameters) {
|
|
4257
|
-
return;
|
|
4258
|
-
}
|
|
4259
|
-
checkNode(node);
|
|
4260
|
-
},
|
|
4261
|
-
"ArrowFunctionExpression > Identifier": (node) => {
|
|
4262
|
-
if (validate.parameters) {
|
|
4263
|
-
const parent = node.parent;
|
|
4264
|
-
if (node !== parent.body) {
|
|
4265
|
-
checkNode(node);
|
|
4266
|
-
}
|
|
4267
|
-
}
|
|
4268
|
-
},
|
|
4269
|
-
"PropertyDefinition[computed=false]": (node) => {
|
|
4270
|
-
const anyNode = node;
|
|
4271
|
-
if (validate.properties) {
|
|
4272
|
-
if (node.override) {
|
|
4273
|
-
return;
|
|
4274
|
-
}
|
|
4275
|
-
checkNode(anyNode.key);
|
|
4276
|
-
}
|
|
4277
|
-
},
|
|
4278
|
-
"FunctionDeclaration > Identifier": (node) => {
|
|
4279
|
-
if (validate.parameters) {
|
|
4280
|
-
const parent = node.parent;
|
|
4281
|
-
if (node !== parent.id) {
|
|
4282
|
-
checkNode(node);
|
|
4283
|
-
}
|
|
4284
|
-
}
|
|
4285
|
-
},
|
|
4286
|
-
"FunctionExpression > Identifier": (node) => {
|
|
4287
|
-
if (validate.parameters) {
|
|
4288
|
-
const parent = node.parent;
|
|
4289
|
-
if (node !== parent.id) {
|
|
4290
|
-
checkNode(node);
|
|
4291
|
-
}
|
|
4292
|
-
}
|
|
4293
|
-
},
|
|
4294
|
-
"MethodDefinition[kind='get'][computed=false]": (node) => {
|
|
4295
|
-
if (validate.properties) {
|
|
4296
|
-
if (node.override) {
|
|
4297
|
-
return;
|
|
4298
|
-
}
|
|
4299
|
-
checkNode(node.key, node);
|
|
4300
|
-
}
|
|
4301
|
-
},
|
|
4302
|
-
"MethodDefinition[kind='set'][computed=false]": (node) => {
|
|
4303
|
-
if (validate.properties) {
|
|
4304
|
-
if (node.override) {
|
|
4305
|
-
return;
|
|
4306
|
-
}
|
|
4307
|
-
checkNode(node.key, node);
|
|
4308
|
-
}
|
|
4309
|
-
},
|
|
4310
|
-
"TSAbstractMethodDefinition[computed=false]": (node) => {
|
|
4311
|
-
if (node.override) {
|
|
4312
|
-
return;
|
|
4313
|
-
}
|
|
4314
|
-
if (validate.properties && (node.kind === "get" || node.kind === "set")) {
|
|
4315
|
-
checkNode(node.key, node);
|
|
4316
|
-
}
|
|
4317
|
-
if (validate.parameters) {
|
|
4318
|
-
node.value.params.forEach((param) => {
|
|
4319
|
-
checkNode(param);
|
|
4320
|
-
});
|
|
4321
|
-
}
|
|
4322
|
-
},
|
|
4323
|
-
"ObjectExpression > Property[computed=false] > Identifier": (node) => {
|
|
4324
|
-
if (!validate.objects) {
|
|
4325
|
-
return;
|
|
4326
|
-
}
|
|
4327
|
-
const parent = node.parent;
|
|
4328
|
-
if (node !== parent.key) {
|
|
4329
|
-
return;
|
|
4330
|
-
}
|
|
4331
|
-
const found = findParent(
|
|
4332
|
-
node,
|
|
4333
|
-
"CallExpression",
|
|
4334
|
-
"VariableDeclarator",
|
|
4335
|
-
"TSSatisfiesExpression",
|
|
4336
|
-
"TSAsExpression"
|
|
4337
|
-
);
|
|
4338
|
-
if (found) {
|
|
4339
|
-
if (isCallExpression(found)) {
|
|
4340
|
-
return;
|
|
4341
|
-
} else if (isVariableDeclarator(found) && !!found.id.typeAnnotation) {
|
|
4342
|
-
return;
|
|
4343
|
-
} else if (isTSAsExpression(found) || isTSSatisfiesExpression(found)) {
|
|
4344
|
-
return;
|
|
4345
|
-
}
|
|
4346
|
-
}
|
|
4347
|
-
checkNode(node, void 0, "forbiddenProperty");
|
|
4348
|
-
},
|
|
4349
|
-
"ObjectPattern > Property > Identifier": (node) => {
|
|
4350
|
-
const found = findParent(
|
|
4351
|
-
node,
|
|
4352
|
-
"ArrowFunctionExpression",
|
|
4353
|
-
"FunctionDeclaration",
|
|
4354
|
-
"FunctionExpression",
|
|
4355
|
-
"VariableDeclarator"
|
|
4356
|
-
);
|
|
4357
|
-
if (!found) {
|
|
4358
|
-
return;
|
|
4359
|
-
}
|
|
4360
|
-
if (!validate.variables && isVariableDeclarator(found)) {
|
|
4361
|
-
return;
|
|
4362
|
-
}
|
|
4363
|
-
if (!validate.parameters) {
|
|
4364
|
-
return;
|
|
4365
|
-
}
|
|
4366
|
-
const parent = node.parent;
|
|
4367
|
-
if (node === parent.value) {
|
|
4368
|
-
checkNode(node);
|
|
4369
|
-
}
|
|
4370
|
-
},
|
|
4371
|
-
"TSCallSignatureDeclaration > Identifier": (node) => {
|
|
4372
|
-
if (validate.parameters) {
|
|
4373
|
-
checkNode(node);
|
|
4374
|
-
}
|
|
4375
|
-
},
|
|
4376
|
-
"TSConstructSignatureDeclaration > Identifier": (node) => {
|
|
4377
|
-
if (validate.parameters) {
|
|
4378
|
-
checkNode(node);
|
|
4379
|
-
}
|
|
4380
|
-
},
|
|
4381
|
-
"TSMethodSignature > Identifier": (node) => {
|
|
4382
|
-
if (validate.parameters) {
|
|
4383
|
-
checkNode(node);
|
|
4384
|
-
}
|
|
4385
|
-
},
|
|
4386
|
-
"TSParameterProperty > Identifier": (node) => {
|
|
4387
|
-
if (validate.parameters || validate.properties) {
|
|
4388
|
-
checkNode(node);
|
|
4389
|
-
}
|
|
4390
|
-
},
|
|
4391
|
-
"TSPropertySignature[computed=false]": (node) => {
|
|
4392
|
-
if (validate.properties) {
|
|
4393
|
-
checkNode(node.key);
|
|
4394
|
-
}
|
|
4395
|
-
},
|
|
4396
|
-
"VariableDeclarator > Identifier": (node) => {
|
|
4397
|
-
const parent = node.parent;
|
|
4398
|
-
if (validate.variables && node === parent.id) {
|
|
4399
|
-
checkNode(node);
|
|
4400
|
-
}
|
|
4401
|
-
}
|
|
4402
|
-
};
|
|
4403
|
-
}
|
|
4404
|
-
});
|
|
4405
|
-
|
|
4406
|
-
// src/rules/throw-error.ts
|
|
4407
|
-
import { ESLintUtils as ESLintUtils13 } from "@typescript-eslint/utils";
|
|
4408
|
-
import * as tsutils6 from "ts-api-utils";
|
|
4409
|
-
var defaultOptions19 = [];
|
|
4410
|
-
var throwErrorRule = ruleCreator({
|
|
4411
|
-
defaultOptions: defaultOptions19,
|
|
4412
|
-
meta: {
|
|
4413
|
-
docs: {
|
|
4414
|
-
description: "Enforce passing only `Error` values to `throwError` or `Subject.error`.",
|
|
4415
|
-
recommended: {
|
|
4416
|
-
recommended: true,
|
|
4417
|
-
strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }]
|
|
4418
|
-
},
|
|
4419
|
-
requiresTypeChecking: true
|
|
4420
|
-
},
|
|
4421
|
-
messages: {
|
|
4422
|
-
forbidden: "Passing non-Error values is forbidden.",
|
|
4423
|
-
suggestErrorConstructor: "Wrap string in Error constructor."
|
|
4424
|
-
},
|
|
4425
|
-
schema: [
|
|
4426
|
-
{
|
|
4427
|
-
properties: {
|
|
4428
|
-
allowThrowingAny: { type: "boolean", default: true, description: "Whether to always allow throwing values typed as `any`." },
|
|
4429
|
-
allowThrowingUnknown: { type: "boolean", default: true, description: "Whether to always allow throwing values typed as `unknown`." }
|
|
4430
|
-
},
|
|
4431
|
-
type: "object"
|
|
4432
|
-
}
|
|
4433
|
-
],
|
|
4434
|
-
type: "problem",
|
|
4435
|
-
hasSuggestions: true
|
|
4436
|
-
},
|
|
4437
|
-
name: "throw-error",
|
|
4438
|
-
create: (context) => {
|
|
4439
|
-
const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = ESLintUtils13.getParserServices(context);
|
|
4440
|
-
const { couldBeObservable, couldBeSubject } = getTypeServices(context);
|
|
4441
|
-
const [config = {}] = context.options;
|
|
4442
|
-
const { allowThrowingAny = true, allowThrowingUnknown = true } = config;
|
|
4443
|
-
function checkThrowArgument(node, noFunction = false) {
|
|
4444
|
-
var _a;
|
|
4445
|
-
let type = getTypeAtLocation(node);
|
|
4446
|
-
let reportNode = node;
|
|
4447
|
-
if (!noFunction && couldBeFunction(type)) {
|
|
4448
|
-
reportNode = (_a = node.body) != null ? _a : node;
|
|
4449
|
-
const tsNode = esTreeNodeToTSNodeMap.get(node);
|
|
4450
|
-
const annotation = tsNode.type;
|
|
4451
|
-
const body = tsNode.body;
|
|
4452
|
-
type = program.getTypeChecker().getTypeAtLocation(annotation != null ? annotation : body);
|
|
4453
|
-
}
|
|
4454
|
-
if (allowThrowingAny && tsutils6.isIntrinsicAnyType(type)) {
|
|
4455
|
-
return;
|
|
4456
|
-
}
|
|
4457
|
-
if (allowThrowingUnknown && tsutils6.isIntrinsicUnknownType(type)) {
|
|
4458
|
-
return;
|
|
4459
|
-
}
|
|
4460
|
-
if (couldBeType(type, /^Error$/)) {
|
|
4461
|
-
return;
|
|
4462
|
-
}
|
|
4463
|
-
const isString = isTemplateLiteral(reportNode) || isLiteral(reportNode) && typeof reportNode.value === "string";
|
|
4464
|
-
context.report({
|
|
4465
|
-
messageId: "forbidden",
|
|
4466
|
-
node: reportNode,
|
|
4467
|
-
...isString && {
|
|
4468
|
-
suggest: [
|
|
4469
|
-
{
|
|
4470
|
-
messageId: "suggestErrorConstructor",
|
|
4471
|
-
fix: (fixer) => {
|
|
4472
|
-
const sourceCode = context.sourceCode;
|
|
4473
|
-
const nodeText = sourceCode.getText(reportNode);
|
|
4474
|
-
return fixer.replaceText(reportNode, `new Error(${nodeText})`);
|
|
4475
|
-
}
|
|
4476
|
-
}
|
|
4477
|
-
]
|
|
4478
|
-
}
|
|
4479
|
-
});
|
|
4480
|
-
}
|
|
4481
|
-
function checkThrowError(node) {
|
|
4482
|
-
if (couldBeObservable(node)) {
|
|
4483
|
-
const [arg] = node.arguments;
|
|
4484
|
-
if (arg) {
|
|
4485
|
-
checkThrowArgument(arg);
|
|
4486
|
-
}
|
|
4487
|
-
}
|
|
4488
|
-
}
|
|
4489
|
-
function checkSubjectError(node) {
|
|
4490
|
-
if (isMemberExpression(node.callee) && couldBeSubject(node.callee.object)) {
|
|
4491
|
-
const [arg] = node.arguments;
|
|
4492
|
-
if (arg) {
|
|
4493
|
-
checkThrowArgument(arg, true);
|
|
4494
|
-
}
|
|
4495
|
-
}
|
|
4496
|
-
}
|
|
4497
|
-
return {
|
|
4498
|
-
"CallExpression[callee.name='throwError']": checkThrowError,
|
|
4499
|
-
"CallExpression[callee.property.name='throwError']": checkThrowError,
|
|
4500
|
-
"CallExpression[callee.property.name='error']": checkSubjectError
|
|
4501
|
-
};
|
|
4502
|
-
}
|
|
4503
|
-
});
|
|
4504
|
-
|
|
4505
|
-
// src/index.ts
|
|
4506
|
-
var allRules = {
|
|
4507
|
-
"ban-observables": banObservablesRule,
|
|
4508
|
-
"ban-operators": banOperatorsRule,
|
|
4509
|
-
"finnish": finnishRule,
|
|
4510
|
-
"just": justRule,
|
|
4511
|
-
"macro": macroRule,
|
|
4512
|
-
"no-async-subscribe": noAsyncSubscribeRule,
|
|
4513
|
-
"no-compat": noCompatRule,
|
|
4514
|
-
"no-connectable": noConnectableRule,
|
|
4515
|
-
"no-create": noCreateRule,
|
|
4516
|
-
"no-cyclic-action": noCyclicActionRule,
|
|
4517
|
-
"no-explicit-generics": noExplicitGenericsRule,
|
|
4518
|
-
"no-exposed-subjects": noExposedSubjectsRule,
|
|
4519
|
-
"no-finnish": noFinnishRule,
|
|
4520
|
-
"no-floating-observables": noFloatingObservablesRule,
|
|
4521
|
-
"no-ignored-default-value": noIgnoredDefaultValueRule,
|
|
4522
|
-
"no-ignored-error": noIgnoredErrorRule,
|
|
4523
|
-
"no-ignored-notifier": noIgnoredNotifierRule,
|
|
4524
|
-
"no-ignored-observable": noIgnoredObservableRule,
|
|
4525
|
-
"no-ignored-replay-buffer": noIgnoredReplayBufferRule,
|
|
4526
|
-
"no-ignored-subscribe": noIgnoredSubscribeRule,
|
|
4527
|
-
"no-ignored-subscription": noIgnoredSubscriptionRule,
|
|
4528
|
-
"no-ignored-takewhile-value": noIgnoredTakewhileValueRule,
|
|
4529
|
-
"no-implicit-any-catch": noImplicitAnyCatchRule,
|
|
4530
|
-
"no-index": noIndexRule,
|
|
4531
|
-
"no-internal": noInternalRule,
|
|
4532
|
-
"no-misused-observables": noMisusedObservablesRule,
|
|
4533
|
-
"no-nested-subscribe": noNestedSubscribeRule,
|
|
4534
|
-
"no-redundant-notify": noRedundantNotifyRule,
|
|
4535
|
-
"no-sharereplay": noSharereplayRule,
|
|
4536
|
-
"no-sharereplay-before-takeuntil": noSharereplayBeforeTakeuntilRule,
|
|
4537
|
-
"no-subclass": noSubclassRule,
|
|
4538
|
-
"no-subject-unsubscribe": noSubjectUnsubscribeRule,
|
|
4539
|
-
"no-subject-value": noSubjectValueRule,
|
|
4540
|
-
"no-subscribe-handlers": noSubscribeHandlersRule,
|
|
4541
|
-
"no-subscribe-in-pipe": noSubscribeInPipeRule,
|
|
4542
|
-
"no-tap": noTapRule,
|
|
4543
|
-
"no-topromise": noTopromiseRule,
|
|
4544
|
-
"no-unbound-methods": noUnboundMethodsRule,
|
|
4545
|
-
"no-unnecessary-collection": noUnnecessaryCollectionRule,
|
|
4546
|
-
"no-unsafe-catch": noUnsafeCatchRule,
|
|
4547
|
-
"no-unsafe-first": noUnsafeFirstRule,
|
|
4548
|
-
"no-unsafe-subject-next": noUnsafeSubjectNext,
|
|
4549
|
-
"no-unsafe-switchmap": noUnsafeSwitchmapRule,
|
|
4550
|
-
"no-unsafe-takeuntil": noUnsafeTakeuntilRule,
|
|
4551
|
-
"prefer-observer": preferObserverRule,
|
|
4552
|
-
"prefer-root-operators": preferRootOperatorsRule,
|
|
4553
|
-
"suffix-subjects": suffixSubjectsRule,
|
|
4554
|
-
"throw-error": throwErrorRule
|
|
4555
|
-
};
|
|
4556
|
-
var plugin = {
|
|
4557
|
-
meta: {
|
|
4558
|
-
name,
|
|
4559
|
-
version,
|
|
4560
|
-
namespace: "rxjs-x"
|
|
4561
|
-
},
|
|
4562
|
-
/** Compatibility with `defineConfig` until https://github.com/typescript-eslint/typescript-eslint/issues/11543 is addressed. */
|
|
4563
|
-
rules: allRules
|
|
4564
|
-
};
|
|
4565
|
-
var rxjsX = {
|
|
4566
|
-
...plugin,
|
|
4567
|
-
configs: {
|
|
4568
|
-
"recommended": createRecommendedConfig(plugin),
|
|
4569
|
-
"strict": createStrictConfig(plugin),
|
|
4570
|
-
"recommended-legacy": createLegacyRecommendedConfig()
|
|
4571
|
-
}
|
|
4572
|
-
};
|
|
4573
|
-
var index_default = rxjsX;
|
|
4574
|
-
export {
|
|
4575
|
-
index_default as default
|
|
4576
|
-
};
|