eslint-plugin-rxjs-x 0.0.2 → 0.1.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/dist/index.cjs CHANGED
@@ -2,10 +2,9 @@
2
2
 
3
3
  const utils = require('@typescript-eslint/utils');
4
4
  const commonTags = require('common-tags');
5
- const tsutils = require('tsutils-etc');
5
+ const tsutils = require('ts-api-utils');
6
6
  const ts = require('typescript');
7
7
  const scopeManager = require('@typescript-eslint/scope-manager');
8
- const tsutils$1 = require('tsutils');
9
8
  const decamelize = require('decamelize');
10
9
 
11
10
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
@@ -24,11 +23,10 @@ function _interopNamespaceCompat(e) {
24
23
 
25
24
  const tsutils__namespace = /*#__PURE__*/_interopNamespaceCompat(tsutils);
26
25
  const ts__namespace = /*#__PURE__*/_interopNamespaceCompat(ts);
27
- const tsutils__namespace$1 = /*#__PURE__*/_interopNamespaceCompat(tsutils$1);
28
26
  const decamelize__default = /*#__PURE__*/_interopDefaultCompat(decamelize);
29
27
 
30
28
  const name = "eslint-plugin-rxjs-x";
31
- const version = "0.0.2";
29
+ const version = "0.1.0";
32
30
 
33
31
  const createRecommendedConfig = (plugin) => ({
34
32
  plugins: {
@@ -200,6 +198,75 @@ const banOperatorsRule = ruleCreator({
200
198
  }
201
199
  });
202
200
 
201
+ function couldBeType(type, name, qualified) {
202
+ if (tsutils__namespace.isTypeReference(type)) {
203
+ type = type.target;
204
+ }
205
+ if (isType(type, name, qualified)) {
206
+ return true;
207
+ }
208
+ if (tsutils__namespace.isUnionOrIntersectionType(type)) {
209
+ return type.types.some((t) => couldBeType(t, name, qualified));
210
+ }
211
+ const baseTypes = type.getBaseTypes();
212
+ if (baseTypes?.some((t) => couldBeType(t, name, qualified))) {
213
+ return true;
214
+ }
215
+ if (couldImplement(type, name, qualified)) {
216
+ return true;
217
+ }
218
+ return false;
219
+ }
220
+ function isType(type, name, qualified) {
221
+ if (!type.symbol) {
222
+ return false;
223
+ }
224
+ if (qualified && !qualified.name.test(
225
+ qualified.typeChecker.getFullyQualifiedName(type.symbol)
226
+ )) {
227
+ return false;
228
+ }
229
+ return typeof name === "string" ? type.symbol.name === name : Boolean(type.symbol.name.match(name));
230
+ }
231
+ function couldImplement(type, name, qualified) {
232
+ const { symbol } = type;
233
+ if (symbol) {
234
+ const { valueDeclaration } = symbol;
235
+ if (valueDeclaration && ts__namespace.isClassDeclaration(valueDeclaration)) {
236
+ const { heritageClauses } = valueDeclaration;
237
+ if (heritageClauses) {
238
+ const implemented = heritageClauses.some(
239
+ ({ token, types }) => token === ts__namespace.SyntaxKind.ImplementsKeyword && types.some((node) => isMatchingNode(node, name, qualified))
240
+ );
241
+ if (implemented) {
242
+ return true;
243
+ }
244
+ }
245
+ }
246
+ }
247
+ return false;
248
+ }
249
+ function isMatchingNode(node, name, qualified) {
250
+ const { expression } = node;
251
+ if (qualified) {
252
+ const type = qualified.typeChecker.getTypeAtLocation(expression);
253
+ if (type) {
254
+ const qualifiedName = qualified.typeChecker.getFullyQualifiedName(
255
+ type.symbol
256
+ );
257
+ if (!qualified.name.test(qualifiedName)) {
258
+ return false;
259
+ }
260
+ }
261
+ }
262
+ const text = expression.getText();
263
+ return typeof name === "string" ? text === name : Boolean(text.match(name));
264
+ }
265
+
266
+ function couldBeFunction(type) {
267
+ return type.getCallSignatures().length > 0 || couldBeType(type, "Function") || couldBeType(type, "ArrowFunction") || couldBeType(type, ts__namespace.InternalSymbolName.Function);
268
+ }
269
+
203
270
  function findParent(node, ...args) {
204
271
  const [arg] = args;
205
272
  const predicate = typeof arg === "function" ? arg : (type) => !args.includes(type) ? "continue" : "return";
@@ -282,9 +349,9 @@ function getTypeServices(context) {
282
349
  const services = utils.ESLintUtils.getParserServices(context);
283
350
  const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = services;
284
351
  const typeChecker = program.getTypeChecker();
285
- const couldBeType = (node, name, qualified) => {
352
+ const couldBeType$1 = (node, name, qualified) => {
286
353
  const type = getType(node);
287
- return tsutils__namespace.couldBeType(
354
+ return couldBeType(
288
355
  type,
289
356
  name,
290
357
  qualified ? { ...qualified, typeChecker } : void 0
@@ -299,7 +366,7 @@ function getTypeServices(context) {
299
366
  tsTypeNode = tsNode.type;
300
367
  }
301
368
  return Boolean(
302
- tsTypeNode && tsutils__namespace.couldBeType(
369
+ tsTypeNode && couldBeType(
303
370
  typeChecker.getTypeAtLocation(tsTypeNode),
304
371
  name,
305
372
  qualified ? { ...qualified, typeChecker } : void 0
@@ -310,25 +377,25 @@ function getTypeServices(context) {
310
377
  return getTypeAtLocation(node);
311
378
  };
312
379
  return {
313
- couldBeBehaviorSubject: (node) => couldBeType(node, "BehaviorSubject"),
314
- couldBeError: (node) => couldBeType(node, "Error"),
380
+ couldBeBehaviorSubject: (node) => couldBeType$1(node, "BehaviorSubject"),
381
+ couldBeError: (node) => couldBeType$1(node, "Error"),
315
382
  couldBeFunction: (node) => {
316
383
  if (isArrowFunctionExpression(node) || isFunctionDeclaration(node)) {
317
384
  return true;
318
385
  }
319
- return tsutils__namespace.couldBeFunction(getType(node));
386
+ return couldBeFunction(getType(node));
320
387
  },
321
- couldBeMonoTypeOperatorFunction: (node) => couldBeType(node, "MonoTypeOperatorFunction"),
322
- couldBeObservable: (node) => couldBeType(node, "Observable"),
323
- couldBeSubject: (node) => couldBeType(node, "Subject"),
324
- couldBeSubscription: (node) => couldBeType(node, "Subscription"),
325
- couldBeType,
388
+ couldBeMonoTypeOperatorFunction: (node) => couldBeType$1(node, "MonoTypeOperatorFunction"),
389
+ couldBeObservable: (node) => couldBeType$1(node, "Observable"),
390
+ couldBeSubject: (node) => couldBeType$1(node, "Subject"),
391
+ couldBeSubscription: (node) => couldBeType$1(node, "Subscription"),
392
+ couldBeType: couldBeType$1,
326
393
  couldReturnObservable: (node) => couldReturnType(node, "Observable"),
327
394
  couldReturnType,
328
395
  getType,
329
- isAny: (node) => tsutils__namespace.isAny(getType(node)),
330
- isReferenceType: (node) => tsutils__namespace.isReferenceType(getType(node)),
331
- isUnknown: (node) => tsutils__namespace.isUnknown(getType(node)),
396
+ isAny: (node) => tsutils__namespace.isIntrinsicAnyType(getType(node)),
397
+ isReferenceType: (node) => tsutils__namespace.isTypeReference(getType(node)),
398
+ isUnknown: (node) => tsutils__namespace.isIntrinsicUnknownType(getType(node)),
332
399
  typeChecker
333
400
  };
334
401
  }
@@ -2288,19 +2355,19 @@ const noUnsafeSubjectNext = ruleCreator({
2288
2355
  [`CallExpression[callee.property.name='next']`]: (node) => {
2289
2356
  if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
2290
2357
  const type = getType(node.callee.object);
2291
- if (tsutils.isReferenceType(type) && tsutils.couldBeType(type, "Subject")) {
2358
+ if (tsutils__namespace.isTypeReference(type) && couldBeType(type, "Subject")) {
2292
2359
  const [typeArg] = typeChecker.getTypeArguments(type);
2293
- if (tsutils__namespace$1.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Any)) {
2360
+ if (tsutils__namespace.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Any)) {
2294
2361
  return;
2295
2362
  }
2296
- if (tsutils__namespace$1.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Unknown)) {
2363
+ if (tsutils__namespace.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Unknown)) {
2297
2364
  return;
2298
2365
  }
2299
- if (tsutils__namespace$1.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Void)) {
2366
+ if (tsutils__namespace.isTypeFlagSet(typeArg, ts__namespace.TypeFlags.Void)) {
2300
2367
  return;
2301
2368
  }
2302
- if (tsutils.isUnionType(typeArg) && typeArg.types.some(
2303
- (t) => tsutils__namespace$1.isTypeFlagSet(t, ts__namespace.TypeFlags.Void)
2369
+ if (tsutils__namespace.isUnionType(typeArg) && typeArg.types.some(
2370
+ (t) => tsutils__namespace.isTypeFlagSet(t, ts__namespace.TypeFlags.Void)
2304
2371
  )) {
2305
2372
  return;
2306
2373
  }
@@ -2852,13 +2919,13 @@ const throwErrorRule = ruleCreator({
2852
2919
  const { couldBeObservable, getType } = getTypeServices(context);
2853
2920
  function checkNode(node) {
2854
2921
  let type = getType(node);
2855
- if (tsutils.couldBeFunction(type)) {
2922
+ if (couldBeFunction(type)) {
2856
2923
  const tsNode = esTreeNodeToTSNodeMap.get(node);
2857
2924
  const annotation = tsNode.type;
2858
2925
  const body = tsNode.body;
2859
2926
  type = program.getTypeChecker().getTypeAtLocation(annotation ?? body);
2860
2927
  }
2861
- if (!tsutils.isAny(type) && !tsutils.isUnknown(type) && !tsutils.couldBeType(type, /^(Error|DOMException)$/)) {
2928
+ if (!tsutils__namespace.isIntrinsicAnyType(type) && !tsutils__namespace.isIntrinsicUnknownType(type) && !couldBeType(type, /^(Error|DOMException)$/)) {
2862
2929
  context.report({
2863
2930
  messageId: "forbidden",
2864
2931
  node
package/dist/index.mjs CHANGED
@@ -1,14 +1,12 @@
1
1
  import { ESLintUtils, AST_NODE_TYPES } from '@typescript-eslint/utils';
2
2
  import { stripIndent } from 'common-tags';
3
- import * as tsutils from 'tsutils-etc';
4
- import { isReferenceType, couldBeType, isUnionType, couldBeFunction, isAny, isUnknown } from 'tsutils-etc';
3
+ import * as tsutils from 'ts-api-utils';
5
4
  import * as ts from 'typescript';
6
5
  import { DefinitionType } from '@typescript-eslint/scope-manager';
7
- import * as tsutils$1 from 'tsutils';
8
6
  import decamelize from 'decamelize';
9
7
 
10
8
  const name = "eslint-plugin-rxjs-x";
11
- const version = "0.0.2";
9
+ const version = "0.1.0";
12
10
 
13
11
  const createRecommendedConfig = (plugin) => ({
14
12
  plugins: {
@@ -180,6 +178,75 @@ const banOperatorsRule = ruleCreator({
180
178
  }
181
179
  });
182
180
 
181
+ function couldBeType(type, name, qualified) {
182
+ if (tsutils.isTypeReference(type)) {
183
+ type = type.target;
184
+ }
185
+ if (isType(type, name, qualified)) {
186
+ return true;
187
+ }
188
+ if (tsutils.isUnionOrIntersectionType(type)) {
189
+ return type.types.some((t) => couldBeType(t, name, qualified));
190
+ }
191
+ const baseTypes = type.getBaseTypes();
192
+ if (baseTypes?.some((t) => couldBeType(t, name, qualified))) {
193
+ return true;
194
+ }
195
+ if (couldImplement(type, name, qualified)) {
196
+ return true;
197
+ }
198
+ return false;
199
+ }
200
+ function isType(type, name, qualified) {
201
+ if (!type.symbol) {
202
+ return false;
203
+ }
204
+ if (qualified && !qualified.name.test(
205
+ qualified.typeChecker.getFullyQualifiedName(type.symbol)
206
+ )) {
207
+ return false;
208
+ }
209
+ return typeof name === "string" ? type.symbol.name === name : Boolean(type.symbol.name.match(name));
210
+ }
211
+ function couldImplement(type, name, qualified) {
212
+ const { symbol } = type;
213
+ if (symbol) {
214
+ const { valueDeclaration } = symbol;
215
+ if (valueDeclaration && ts.isClassDeclaration(valueDeclaration)) {
216
+ const { heritageClauses } = valueDeclaration;
217
+ if (heritageClauses) {
218
+ const implemented = heritageClauses.some(
219
+ ({ token, types }) => token === ts.SyntaxKind.ImplementsKeyword && types.some((node) => isMatchingNode(node, name, qualified))
220
+ );
221
+ if (implemented) {
222
+ return true;
223
+ }
224
+ }
225
+ }
226
+ }
227
+ return false;
228
+ }
229
+ function isMatchingNode(node, name, qualified) {
230
+ const { expression } = node;
231
+ if (qualified) {
232
+ const type = qualified.typeChecker.getTypeAtLocation(expression);
233
+ if (type) {
234
+ const qualifiedName = qualified.typeChecker.getFullyQualifiedName(
235
+ type.symbol
236
+ );
237
+ if (!qualified.name.test(qualifiedName)) {
238
+ return false;
239
+ }
240
+ }
241
+ }
242
+ const text = expression.getText();
243
+ return typeof name === "string" ? text === name : Boolean(text.match(name));
244
+ }
245
+
246
+ function couldBeFunction(type) {
247
+ return type.getCallSignatures().length > 0 || couldBeType(type, "Function") || couldBeType(type, "ArrowFunction") || couldBeType(type, ts.InternalSymbolName.Function);
248
+ }
249
+
183
250
  function findParent(node, ...args) {
184
251
  const [arg] = args;
185
252
  const predicate = typeof arg === "function" ? arg : (type) => !args.includes(type) ? "continue" : "return";
@@ -262,9 +329,9 @@ function getTypeServices(context) {
262
329
  const services = ESLintUtils.getParserServices(context);
263
330
  const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = services;
264
331
  const typeChecker = program.getTypeChecker();
265
- const couldBeType = (node, name, qualified) => {
332
+ const couldBeType$1 = (node, name, qualified) => {
266
333
  const type = getType(node);
267
- return tsutils.couldBeType(
334
+ return couldBeType(
268
335
  type,
269
336
  name,
270
337
  qualified ? { ...qualified, typeChecker } : void 0
@@ -279,7 +346,7 @@ function getTypeServices(context) {
279
346
  tsTypeNode = tsNode.type;
280
347
  }
281
348
  return Boolean(
282
- tsTypeNode && tsutils.couldBeType(
349
+ tsTypeNode && couldBeType(
283
350
  typeChecker.getTypeAtLocation(tsTypeNode),
284
351
  name,
285
352
  qualified ? { ...qualified, typeChecker } : void 0
@@ -290,25 +357,25 @@ function getTypeServices(context) {
290
357
  return getTypeAtLocation(node);
291
358
  };
292
359
  return {
293
- couldBeBehaviorSubject: (node) => couldBeType(node, "BehaviorSubject"),
294
- couldBeError: (node) => couldBeType(node, "Error"),
360
+ couldBeBehaviorSubject: (node) => couldBeType$1(node, "BehaviorSubject"),
361
+ couldBeError: (node) => couldBeType$1(node, "Error"),
295
362
  couldBeFunction: (node) => {
296
363
  if (isArrowFunctionExpression(node) || isFunctionDeclaration(node)) {
297
364
  return true;
298
365
  }
299
- return tsutils.couldBeFunction(getType(node));
366
+ return couldBeFunction(getType(node));
300
367
  },
301
- couldBeMonoTypeOperatorFunction: (node) => couldBeType(node, "MonoTypeOperatorFunction"),
302
- couldBeObservable: (node) => couldBeType(node, "Observable"),
303
- couldBeSubject: (node) => couldBeType(node, "Subject"),
304
- couldBeSubscription: (node) => couldBeType(node, "Subscription"),
305
- couldBeType,
368
+ couldBeMonoTypeOperatorFunction: (node) => couldBeType$1(node, "MonoTypeOperatorFunction"),
369
+ couldBeObservable: (node) => couldBeType$1(node, "Observable"),
370
+ couldBeSubject: (node) => couldBeType$1(node, "Subject"),
371
+ couldBeSubscription: (node) => couldBeType$1(node, "Subscription"),
372
+ couldBeType: couldBeType$1,
306
373
  couldReturnObservable: (node) => couldReturnType(node, "Observable"),
307
374
  couldReturnType,
308
375
  getType,
309
- isAny: (node) => tsutils.isAny(getType(node)),
310
- isReferenceType: (node) => tsutils.isReferenceType(getType(node)),
311
- isUnknown: (node) => tsutils.isUnknown(getType(node)),
376
+ isAny: (node) => tsutils.isIntrinsicAnyType(getType(node)),
377
+ isReferenceType: (node) => tsutils.isTypeReference(getType(node)),
378
+ isUnknown: (node) => tsutils.isIntrinsicUnknownType(getType(node)),
312
379
  typeChecker
313
380
  };
314
381
  }
@@ -2268,19 +2335,19 @@ const noUnsafeSubjectNext = ruleCreator({
2268
2335
  [`CallExpression[callee.property.name='next']`]: (node) => {
2269
2336
  if (node.arguments.length === 0 && isMemberExpression(node.callee)) {
2270
2337
  const type = getType(node.callee.object);
2271
- if (isReferenceType(type) && couldBeType(type, "Subject")) {
2338
+ if (tsutils.isTypeReference(type) && couldBeType(type, "Subject")) {
2272
2339
  const [typeArg] = typeChecker.getTypeArguments(type);
2273
- if (tsutils$1.isTypeFlagSet(typeArg, ts.TypeFlags.Any)) {
2340
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Any)) {
2274
2341
  return;
2275
2342
  }
2276
- if (tsutils$1.isTypeFlagSet(typeArg, ts.TypeFlags.Unknown)) {
2343
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Unknown)) {
2277
2344
  return;
2278
2345
  }
2279
- if (tsutils$1.isTypeFlagSet(typeArg, ts.TypeFlags.Void)) {
2346
+ if (tsutils.isTypeFlagSet(typeArg, ts.TypeFlags.Void)) {
2280
2347
  return;
2281
2348
  }
2282
- if (isUnionType(typeArg) && typeArg.types.some(
2283
- (t) => tsutils$1.isTypeFlagSet(t, ts.TypeFlags.Void)
2349
+ if (tsutils.isUnionType(typeArg) && typeArg.types.some(
2350
+ (t) => tsutils.isTypeFlagSet(t, ts.TypeFlags.Void)
2284
2351
  )) {
2285
2352
  return;
2286
2353
  }
@@ -2838,7 +2905,7 @@ const throwErrorRule = ruleCreator({
2838
2905
  const body = tsNode.body;
2839
2906
  type = program.getTypeChecker().getTypeAtLocation(annotation ?? body);
2840
2907
  }
2841
- if (!isAny(type) && !isUnknown(type) && !couldBeType(type, /^(Error|DOMException)$/)) {
2908
+ if (!tsutils.isIntrinsicAnyType(type) && !tsutils.isIntrinsicUnknownType(type) && !couldBeType(type, /^(Error|DOMException)$/)) {
2842
2909
  context.report({
2843
2910
  messageId: "forbidden",
2844
2911
  node
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-rxjs-x",
3
3
  "type": "module",
4
- "version": "0.0.2",
4
+ "version": "0.1.0",
5
5
  "packageManager": "yarn@4.5.1+sha512.341db9396b6e289fecc30cd7ab3af65060e05ebff4b3b47547b278b9e67b08f485ecd8c79006b405446262142c7a38154445ef7f17c1d5d1de7d90bf9ce7054d",
6
6
  "description": "ESLint v9+ plugin for RxJS",
7
7
  "author": "Jason Weinzierl <weinzierljason@gmail.com>",
@@ -53,14 +53,13 @@
53
53
  "@typescript-eslint/utils": "^8.12.2",
54
54
  "common-tags": "^1.8.0",
55
55
  "decamelize": "^5.0.0 || ^6.0.0",
56
- "tslib": "^2.0.0",
57
- "tsutils": "^3.0.0",
58
- "tsutils-etc": "^1.4.2"
56
+ "ts-api-utils": "^1.3.0",
57
+ "tslib": "^2.1.0"
59
58
  },
60
59
  "peerDependencies": {
61
60
  "eslint": "^8.57.0 || ^9.0.0",
62
61
  "rxjs": ">=7.0.0",
63
- "typescript": ">=4.0.0"
62
+ "typescript": ">=4.2.0"
64
63
  },
65
64
  "devDependencies": {
66
65
  "@eslint/js": "^9.13.0",
@@ -68,7 +67,9 @@
68
67
  "@types/common-tags": "^1.8.4",
69
68
  "@types/node": "^18.18.0",
70
69
  "@typescript-eslint/rule-tester": "^8.12.2",
70
+ "@typescript/vfs": "^1.6.0",
71
71
  "@vitest/coverage-v8": "^2.1.4",
72
+ "@vitest/eslint-plugin": "^1.1.7",
72
73
  "bumpp": "^9.8.0",
73
74
  "eslint": "^9.13.0",
74
75
  "eslint-config-flat-gitignore": "^0.3.0",