eslint-plugin-rxjs-x 0.7.4 → 0.7.5

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 CHANGED
@@ -120,6 +120,6 @@ The package includes the following rules.
120
120
  | [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
121
121
  | [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | ✅ 🔒 | 🔧 | 💡 | | |
122
122
  | [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | 💭 | |
123
- | [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError`. | ✅ 🔒 | | | 💭 | |
123
+ | [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError` or `Subject.error`. | ✅ 🔒 | | | 💭 | |
124
124
 
125
125
  <!-- end auto-generated rules list -->
package/dist/index.d.mts CHANGED
@@ -150,7 +150,9 @@ declare const rxjsX: {
150
150
  'no-subscribe-in-pipe': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
151
151
  'no-tap': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
152
152
  'no-topromise': TSESLint.RuleModule<"forbidden" | "suggestLastValueFromWithDefault" | "suggestLastValueFrom" | "suggestFirstValueFrom", [], RxjsXRuleDocs, TSESLint.RuleListener>;
153
- 'no-unbound-methods': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
153
+ 'no-unbound-methods': TSESLint.RuleModule<"forbidden", readonly {
154
+ allowTypes?: string[];
155
+ }[], RxjsXRuleDocs, TSESLint.RuleListener>;
154
156
  'no-unsafe-catch': TSESLint.RuleModule<"forbidden", readonly {
155
157
  observable?: string;
156
158
  }[], RxjsXRuleDocs, TSESLint.RuleListener>;
package/dist/index.d.ts CHANGED
@@ -150,7 +150,9 @@ declare const rxjsX: {
150
150
  'no-subscribe-in-pipe': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
151
151
  'no-tap': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
152
152
  'no-topromise': TSESLint.RuleModule<"forbidden" | "suggestLastValueFromWithDefault" | "suggestLastValueFrom" | "suggestFirstValueFrom", [], RxjsXRuleDocs, TSESLint.RuleListener>;
153
- 'no-unbound-methods': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
153
+ 'no-unbound-methods': TSESLint.RuleModule<"forbidden", readonly {
154
+ allowTypes?: string[];
155
+ }[], RxjsXRuleDocs, TSESLint.RuleListener>;
154
156
  'no-unsafe-catch': TSESLint.RuleModule<"forbidden", readonly {
155
157
  observable?: string;
156
158
  }[], RxjsXRuleDocs, TSESLint.RuleListener>;
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// package.json
2
2
  var name = "eslint-plugin-rxjs-x";
3
- var version = "0.7.4";
3
+ var version = "0.7.5";
4
4
 
5
5
  // src/configs/recommended.ts
6
6
  var createRecommendedConfig = (plugin2) => ({
@@ -398,6 +398,9 @@ var SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
398
398
  "combineLatest",
399
399
  "forkJoin"
400
400
  ];
401
+ var DEFAULT_UNBOUND_ALLOWED_TYPES = [
402
+ "Signal"
403
+ ];
401
404
  var DEFAULT_VALID_POST_COMPLETION_OPERATORS = [
402
405
  "count",
403
406
  "defaultIfEmpty",
@@ -932,7 +935,7 @@ var noAsyncSubscribeRule = ruleCreator({
932
935
  requiresTypeChecking: true
933
936
  },
934
937
  messages: {
935
- forbidden: "Passing async functions to subscribe is forbidden."
938
+ forbidden: "Passing async functions to subscribe is forbidden. Use operators like `concatMap` or `switchMap` to avoid race conditions."
936
939
  },
937
940
  schema: [],
938
941
  type: "problem"
@@ -940,27 +943,39 @@ var noAsyncSubscribeRule = ruleCreator({
940
943
  name: "no-async-subscribe",
941
944
  create: (context) => {
942
945
  const { couldBeObservable } = getTypeServices(context);
943
- function checkNode(node) {
944
- const parentNode = node.parent;
946
+ function report(node) {
947
+ const { loc } = node;
948
+ const asyncLoc = {
949
+ ...loc,
950
+ end: {
951
+ ...loc.start,
952
+ column: loc.start.column + 5
953
+ }
954
+ };
955
+ context.report({
956
+ messageId: "forbidden",
957
+ loc: asyncLoc
958
+ });
959
+ }
960
+ function checkSingleNext(funcNode) {
961
+ const parentNode = funcNode.parent;
945
962
  const callee = parentNode.callee;
946
963
  if (couldBeObservable(callee.object)) {
947
- const { loc } = node;
948
- const asyncLoc = {
949
- ...loc,
950
- end: {
951
- ...loc.start,
952
- column: loc.start.column + 5
953
- }
954
- };
955
- context.report({
956
- messageId: "forbidden",
957
- loc: asyncLoc
958
- });
964
+ report(funcNode);
965
+ }
966
+ }
967
+ function checkObserverObjectProp(propNode) {
968
+ const parentNode = propNode.parent.parent;
969
+ const callee = parentNode.callee;
970
+ if (couldBeObservable(callee.object) && (isArrowFunctionExpression(propNode.value) || isFunctionExpression(propNode.value))) {
971
+ report(propNode.value);
959
972
  }
960
973
  }
961
974
  return {
962
- "CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]": checkNode,
963
- "CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]": checkNode
975
+ "CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]": checkSingleNext,
976
+ "CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]": checkSingleNext,
977
+ "CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"ArrowFunctionExpression\"][value.async=true]": checkObserverObjectProp,
978
+ "CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"FunctionExpression\"][value.async=true]": checkObserverObjectProp
964
979
  };
965
980
  }
966
981
  });
@@ -3116,8 +3131,9 @@ import { ${functionName} } from ${quote}rxjs${quote};`
3116
3131
 
3117
3132
  // src/rules/no-unbound-methods.ts
3118
3133
 
3134
+ var defaultOptions11 = [];
3119
3135
  var noUnboundMethodsRule = ruleCreator({
3120
- defaultOptions: [],
3136
+ defaultOptions: defaultOptions11,
3121
3137
  meta: {
3122
3138
  docs: {
3123
3139
  description: "Disallow passing unbound methods.",
@@ -3127,7 +3143,14 @@ var noUnboundMethodsRule = ruleCreator({
3127
3143
  messages: {
3128
3144
  forbidden: "Unbound methods are forbidden."
3129
3145
  },
3130
- schema: [],
3146
+ schema: [
3147
+ {
3148
+ properties: {
3149
+ allowTypes: { type: "array", items: { type: "string" }, description: "An array of function types that are allowed to be passed unbound.", default: DEFAULT_UNBOUND_ALLOWED_TYPES }
3150
+ },
3151
+ type: "object"
3152
+ }
3153
+ ],
3131
3154
  type: "problem"
3132
3155
  },
3133
3156
  name: "no-unbound-methods",
@@ -3135,9 +3158,14 @@ var noUnboundMethodsRule = ruleCreator({
3135
3158
  const { getTypeAtLocation } = _utils.ESLintUtils.getParserServices(context);
3136
3159
  const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
3137
3160
  const nodeMap = /* @__PURE__ */ new WeakMap();
3161
+ const [config = {}] = context.options;
3162
+ const { allowTypes = [] } = config;
3138
3163
  function mapArguments(node) {
3139
3164
  node.arguments.filter(isMemberExpression).forEach((arg) => {
3140
3165
  const argType = getTypeAtLocation(arg);
3166
+ if (allowTypes.some((t) => couldBeType(argType, t))) {
3167
+ return;
3168
+ }
3141
3169
  if (argType.getCallSignatures().length > 0) {
3142
3170
  nodeMap.set(arg);
3143
3171
  }
@@ -3180,9 +3208,9 @@ var noUnboundMethodsRule = ruleCreator({
3180
3208
 
3181
3209
  // src/rules/no-unsafe-catch.ts
3182
3210
 
3183
- var defaultOptions11 = [];
3211
+ var defaultOptions12 = [];
3184
3212
  var noUnsafeCatchRule = ruleCreator({
3185
- defaultOptions: defaultOptions11,
3213
+ defaultOptions: defaultOptions12,
3186
3214
  meta: {
3187
3215
  docs: {
3188
3216
  description: "Disallow unsafe `catchError` usage in effects and epics.",
@@ -3241,9 +3269,9 @@ var noUnsafeCatchRule = ruleCreator({
3241
3269
 
3242
3270
  // src/rules/no-unsafe-first.ts
3243
3271
 
3244
- var defaultOptions12 = [];
3272
+ var defaultOptions13 = [];
3245
3273
  var noUnsafeFirstRule = ruleCreator({
3246
- defaultOptions: defaultOptions12,
3274
+ defaultOptions: defaultOptions13,
3247
3275
  meta: {
3248
3276
  docs: {
3249
3277
  description: "Disallow unsafe `first`/`take` usage in effects and epics.",
@@ -3365,9 +3393,9 @@ var noUnsafeSubjectNext = ruleCreator({
3365
3393
  // src/rules/no-unsafe-switchmap.ts
3366
3394
 
3367
3395
  var _decamelize = require('decamelize'); var _decamelize2 = _interopRequireDefault(_decamelize);
3368
- var defaultOptions13 = [];
3396
+ var defaultOptions14 = [];
3369
3397
  var noUnsafeSwitchmapRule = ruleCreator({
3370
- defaultOptions: defaultOptions13,
3398
+ defaultOptions: defaultOptions14,
3371
3399
  meta: {
3372
3400
  docs: {
3373
3401
  description: "Disallow unsafe `switchMap` usage in effects and epics.",
@@ -3490,9 +3518,9 @@ var noUnsafeSwitchmapRule = ruleCreator({
3490
3518
 
3491
3519
  // src/rules/no-unsafe-takeuntil.ts
3492
3520
 
3493
- var defaultOptions14 = [];
3521
+ var defaultOptions15 = [];
3494
3522
  var noUnsafeTakeuntilRule = ruleCreator({
3495
- defaultOptions: defaultOptions14,
3523
+ defaultOptions: defaultOptions15,
3496
3524
  meta: {
3497
3525
  docs: {
3498
3526
  description: "Disallow applying operators after `takeUntil`.",
@@ -3553,9 +3581,9 @@ var noUnsafeTakeuntilRule = ruleCreator({
3553
3581
  });
3554
3582
 
3555
3583
  // src/rules/prefer-observer.ts
3556
- var defaultOptions15 = [];
3584
+ var defaultOptions16 = [];
3557
3585
  var preferObserverRule = ruleCreator({
3558
- defaultOptions: defaultOptions15,
3586
+ defaultOptions: defaultOptions16,
3559
3587
  meta: {
3560
3588
  docs: {
3561
3589
  description: "Disallow passing separate handlers to `subscribe` and `tap`.",
@@ -3791,9 +3819,9 @@ var preferRootOperatorsRule = ruleCreator({
3791
3819
 
3792
3820
  // src/rules/suffix-subjects.ts
3793
3821
 
3794
- var defaultOptions16 = [];
3822
+ var defaultOptions17 = [];
3795
3823
  var suffixSubjectsRule = ruleCreator({
3796
- defaultOptions: defaultOptions16,
3824
+ defaultOptions: defaultOptions17,
3797
3825
  meta: {
3798
3826
  docs: {
3799
3827
  description: "Enforce the use of a suffix in subject identifiers.",
@@ -3990,12 +4018,12 @@ var suffixSubjectsRule = ruleCreator({
3990
4018
  // src/rules/throw-error.ts
3991
4019
 
3992
4020
 
3993
- var defaultOptions17 = [];
4021
+ var defaultOptions18 = [];
3994
4022
  var throwErrorRule = ruleCreator({
3995
- defaultOptions: defaultOptions17,
4023
+ defaultOptions: defaultOptions18,
3996
4024
  meta: {
3997
4025
  docs: {
3998
- description: "Enforce passing only `Error` values to `throwError`.",
4026
+ description: "Enforce passing only `Error` values to `throwError` or `Subject.error`.",
3999
4027
  recommended: {
4000
4028
  recommended: true,
4001
4029
  strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }]
@@ -4019,14 +4047,14 @@ var throwErrorRule = ruleCreator({
4019
4047
  name: "throw-error",
4020
4048
  create: (context) => {
4021
4049
  const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = _utils.ESLintUtils.getParserServices(context);
4022
- const { couldBeObservable } = getTypeServices(context);
4050
+ const { couldBeObservable, couldBeSubject } = getTypeServices(context);
4023
4051
  const [config = {}] = context.options;
4024
4052
  const { allowThrowingAny = true, allowThrowingUnknown = true } = config;
4025
- function checkThrowArgument(node) {
4053
+ function checkThrowArgument(node, noFunction = false) {
4026
4054
  var _a;
4027
4055
  let type = getTypeAtLocation(node);
4028
4056
  let reportNode = node;
4029
- if (couldBeFunction(type)) {
4057
+ if (!noFunction && couldBeFunction(type)) {
4030
4058
  reportNode = (_a = node.body) != null ? _a : node;
4031
4059
  const tsNode = esTreeNodeToTSNodeMap.get(node);
4032
4060
  const annotation = tsNode.type;
@@ -4047,7 +4075,7 @@ var throwErrorRule = ruleCreator({
4047
4075
  node: reportNode
4048
4076
  });
4049
4077
  }
4050
- function checkNode(node) {
4078
+ function checkThrowError(node) {
4051
4079
  if (couldBeObservable(node)) {
4052
4080
  const [arg] = node.arguments;
4053
4081
  if (arg) {
@@ -4055,13 +4083,18 @@ var throwErrorRule = ruleCreator({
4055
4083
  }
4056
4084
  }
4057
4085
  }
4058
- return {
4059
- "CallExpression[callee.name='throwError']": (node) => {
4060
- checkNode(node);
4061
- },
4062
- "CallExpression[callee.property.name='throwError']": (node) => {
4063
- checkNode(node);
4086
+ function checkSubjectError(node) {
4087
+ if (isMemberExpression(node.callee) && couldBeSubject(node.callee.object)) {
4088
+ const [arg] = node.arguments;
4089
+ if (arg) {
4090
+ checkThrowArgument(arg, true);
4091
+ }
4064
4092
  }
4093
+ }
4094
+ return {
4095
+ "CallExpression[callee.name='throwError']": checkThrowError,
4096
+ "CallExpression[callee.property.name='throwError']": checkThrowError,
4097
+ "CallExpression[callee.property.name='error']": checkSubjectError
4065
4098
  };
4066
4099
  }
4067
4100
  });
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  // package.json
2
2
  var name = "eslint-plugin-rxjs-x";
3
- var version = "0.7.4";
3
+ var version = "0.7.5";
4
4
 
5
5
  // src/configs/recommended.ts
6
6
  var createRecommendedConfig = (plugin2) => ({
@@ -398,6 +398,9 @@ var SOURCES_OBJECT_ACCEPTING_STATIC_OBSERVABLE_CREATORS = [
398
398
  "combineLatest",
399
399
  "forkJoin"
400
400
  ];
401
+ var DEFAULT_UNBOUND_ALLOWED_TYPES = [
402
+ "Signal"
403
+ ];
401
404
  var DEFAULT_VALID_POST_COMPLETION_OPERATORS = [
402
405
  "count",
403
406
  "defaultIfEmpty",
@@ -932,7 +935,7 @@ var noAsyncSubscribeRule = ruleCreator({
932
935
  requiresTypeChecking: true
933
936
  },
934
937
  messages: {
935
- forbidden: "Passing async functions to subscribe is forbidden."
938
+ forbidden: "Passing async functions to subscribe is forbidden. Use operators like `concatMap` or `switchMap` to avoid race conditions."
936
939
  },
937
940
  schema: [],
938
941
  type: "problem"
@@ -940,27 +943,39 @@ var noAsyncSubscribeRule = ruleCreator({
940
943
  name: "no-async-subscribe",
941
944
  create: (context) => {
942
945
  const { couldBeObservable } = getTypeServices(context);
943
- function checkNode(node) {
944
- const parentNode = node.parent;
946
+ function report(node) {
947
+ const { loc } = node;
948
+ const asyncLoc = {
949
+ ...loc,
950
+ end: {
951
+ ...loc.start,
952
+ column: loc.start.column + 5
953
+ }
954
+ };
955
+ context.report({
956
+ messageId: "forbidden",
957
+ loc: asyncLoc
958
+ });
959
+ }
960
+ function checkSingleNext(funcNode) {
961
+ const parentNode = funcNode.parent;
945
962
  const callee = parentNode.callee;
946
963
  if (couldBeObservable(callee.object)) {
947
- const { loc } = node;
948
- const asyncLoc = {
949
- ...loc,
950
- end: {
951
- ...loc.start,
952
- column: loc.start.column + 5
953
- }
954
- };
955
- context.report({
956
- messageId: "forbidden",
957
- loc: asyncLoc
958
- });
964
+ report(funcNode);
965
+ }
966
+ }
967
+ function checkObserverObjectProp(propNode) {
968
+ const parentNode = propNode.parent.parent;
969
+ const callee = parentNode.callee;
970
+ if (couldBeObservable(callee.object) && (isArrowFunctionExpression(propNode.value) || isFunctionExpression(propNode.value))) {
971
+ report(propNode.value);
959
972
  }
960
973
  }
961
974
  return {
962
- "CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]": checkNode,
963
- "CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]": checkNode
975
+ "CallExpression[callee.property.name='subscribe'] > FunctionExpression[async=true]": checkSingleNext,
976
+ "CallExpression[callee.property.name='subscribe'] > ArrowFunctionExpression[async=true]": checkSingleNext,
977
+ "CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"ArrowFunctionExpression\"][value.async=true]": checkObserverObjectProp,
978
+ "CallExpression[callee.property.name='subscribe'] > ObjectExpression > Property[key.name='next'][value.type=\"FunctionExpression\"][value.async=true]": checkObserverObjectProp
964
979
  };
965
980
  }
966
981
  });
@@ -3116,8 +3131,9 @@ import { ${functionName} } from ${quote}rxjs${quote};`
3116
3131
 
3117
3132
  // src/rules/no-unbound-methods.ts
3118
3133
  import { ESLintUtils as ESLintUtils9 } from "@typescript-eslint/utils";
3134
+ var defaultOptions11 = [];
3119
3135
  var noUnboundMethodsRule = ruleCreator({
3120
- defaultOptions: [],
3136
+ defaultOptions: defaultOptions11,
3121
3137
  meta: {
3122
3138
  docs: {
3123
3139
  description: "Disallow passing unbound methods.",
@@ -3127,7 +3143,14 @@ var noUnboundMethodsRule = ruleCreator({
3127
3143
  messages: {
3128
3144
  forbidden: "Unbound methods are forbidden."
3129
3145
  },
3130
- schema: [],
3146
+ schema: [
3147
+ {
3148
+ properties: {
3149
+ allowTypes: { type: "array", items: { type: "string" }, description: "An array of function types that are allowed to be passed unbound.", default: DEFAULT_UNBOUND_ALLOWED_TYPES }
3150
+ },
3151
+ type: "object"
3152
+ }
3153
+ ],
3131
3154
  type: "problem"
3132
3155
  },
3133
3156
  name: "no-unbound-methods",
@@ -3135,9 +3158,14 @@ var noUnboundMethodsRule = ruleCreator({
3135
3158
  const { getTypeAtLocation } = ESLintUtils9.getParserServices(context);
3136
3159
  const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
3137
3160
  const nodeMap = /* @__PURE__ */ new WeakMap();
3161
+ const [config = {}] = context.options;
3162
+ const { allowTypes = [] } = config;
3138
3163
  function mapArguments(node) {
3139
3164
  node.arguments.filter(isMemberExpression).forEach((arg) => {
3140
3165
  const argType = getTypeAtLocation(arg);
3166
+ if (allowTypes.some((t) => couldBeType(argType, t))) {
3167
+ return;
3168
+ }
3141
3169
  if (argType.getCallSignatures().length > 0) {
3142
3170
  nodeMap.set(arg);
3143
3171
  }
@@ -3180,9 +3208,9 @@ var noUnboundMethodsRule = ruleCreator({
3180
3208
 
3181
3209
  // src/rules/no-unsafe-catch.ts
3182
3210
  import { stripIndent as stripIndent5 } from "common-tags";
3183
- var defaultOptions11 = [];
3211
+ var defaultOptions12 = [];
3184
3212
  var noUnsafeCatchRule = ruleCreator({
3185
- defaultOptions: defaultOptions11,
3213
+ defaultOptions: defaultOptions12,
3186
3214
  meta: {
3187
3215
  docs: {
3188
3216
  description: "Disallow unsafe `catchError` usage in effects and epics.",
@@ -3241,9 +3269,9 @@ var noUnsafeCatchRule = ruleCreator({
3241
3269
 
3242
3270
  // src/rules/no-unsafe-first.ts
3243
3271
  import { stripIndent as stripIndent6 } from "common-tags";
3244
- var defaultOptions12 = [];
3272
+ var defaultOptions13 = [];
3245
3273
  var noUnsafeFirstRule = ruleCreator({
3246
- defaultOptions: defaultOptions12,
3274
+ defaultOptions: defaultOptions13,
3247
3275
  meta: {
3248
3276
  docs: {
3249
3277
  description: "Disallow unsafe `first`/`take` usage in effects and epics.",
@@ -3365,9 +3393,9 @@ var noUnsafeSubjectNext = ruleCreator({
3365
3393
  // src/rules/no-unsafe-switchmap.ts
3366
3394
  import { stripIndent as stripIndent7 } from "common-tags";
3367
3395
  import decamelize from "decamelize";
3368
- var defaultOptions13 = [];
3396
+ var defaultOptions14 = [];
3369
3397
  var noUnsafeSwitchmapRule = ruleCreator({
3370
- defaultOptions: defaultOptions13,
3398
+ defaultOptions: defaultOptions14,
3371
3399
  meta: {
3372
3400
  docs: {
3373
3401
  description: "Disallow unsafe `switchMap` usage in effects and epics.",
@@ -3490,9 +3518,9 @@ var noUnsafeSwitchmapRule = ruleCreator({
3490
3518
 
3491
3519
  // src/rules/no-unsafe-takeuntil.ts
3492
3520
  import { stripIndent as stripIndent8 } from "common-tags";
3493
- var defaultOptions14 = [];
3521
+ var defaultOptions15 = [];
3494
3522
  var noUnsafeTakeuntilRule = ruleCreator({
3495
- defaultOptions: defaultOptions14,
3523
+ defaultOptions: defaultOptions15,
3496
3524
  meta: {
3497
3525
  docs: {
3498
3526
  description: "Disallow applying operators after `takeUntil`.",
@@ -3553,9 +3581,9 @@ var noUnsafeTakeuntilRule = ruleCreator({
3553
3581
  });
3554
3582
 
3555
3583
  // src/rules/prefer-observer.ts
3556
- var defaultOptions15 = [];
3584
+ var defaultOptions16 = [];
3557
3585
  var preferObserverRule = ruleCreator({
3558
- defaultOptions: defaultOptions15,
3586
+ defaultOptions: defaultOptions16,
3559
3587
  meta: {
3560
3588
  docs: {
3561
3589
  description: "Disallow passing separate handlers to `subscribe` and `tap`.",
@@ -3791,9 +3819,9 @@ var preferRootOperatorsRule = ruleCreator({
3791
3819
 
3792
3820
  // src/rules/suffix-subjects.ts
3793
3821
  import { AST_NODE_TYPES as AST_NODE_TYPES9, ESLintUtils as ESLintUtils11 } from "@typescript-eslint/utils";
3794
- var defaultOptions16 = [];
3822
+ var defaultOptions17 = [];
3795
3823
  var suffixSubjectsRule = ruleCreator({
3796
- defaultOptions: defaultOptions16,
3824
+ defaultOptions: defaultOptions17,
3797
3825
  meta: {
3798
3826
  docs: {
3799
3827
  description: "Enforce the use of a suffix in subject identifiers.",
@@ -3990,12 +4018,12 @@ var suffixSubjectsRule = ruleCreator({
3990
4018
  // src/rules/throw-error.ts
3991
4019
  import { ESLintUtils as ESLintUtils12 } from "@typescript-eslint/utils";
3992
4020
  import * as tsutils4 from "ts-api-utils";
3993
- var defaultOptions17 = [];
4021
+ var defaultOptions18 = [];
3994
4022
  var throwErrorRule = ruleCreator({
3995
- defaultOptions: defaultOptions17,
4023
+ defaultOptions: defaultOptions18,
3996
4024
  meta: {
3997
4025
  docs: {
3998
- description: "Enforce passing only `Error` values to `throwError`.",
4026
+ description: "Enforce passing only `Error` values to `throwError` or `Subject.error`.",
3999
4027
  recommended: {
4000
4028
  recommended: true,
4001
4029
  strict: [{ allowThrowingAny: false, allowThrowingUnknown: false }]
@@ -4019,14 +4047,14 @@ var throwErrorRule = ruleCreator({
4019
4047
  name: "throw-error",
4020
4048
  create: (context) => {
4021
4049
  const { esTreeNodeToTSNodeMap, program, getTypeAtLocation } = ESLintUtils12.getParserServices(context);
4022
- const { couldBeObservable } = getTypeServices(context);
4050
+ const { couldBeObservable, couldBeSubject } = getTypeServices(context);
4023
4051
  const [config = {}] = context.options;
4024
4052
  const { allowThrowingAny = true, allowThrowingUnknown = true } = config;
4025
- function checkThrowArgument(node) {
4053
+ function checkThrowArgument(node, noFunction = false) {
4026
4054
  var _a;
4027
4055
  let type = getTypeAtLocation(node);
4028
4056
  let reportNode = node;
4029
- if (couldBeFunction(type)) {
4057
+ if (!noFunction && couldBeFunction(type)) {
4030
4058
  reportNode = (_a = node.body) != null ? _a : node;
4031
4059
  const tsNode = esTreeNodeToTSNodeMap.get(node);
4032
4060
  const annotation = tsNode.type;
@@ -4047,7 +4075,7 @@ var throwErrorRule = ruleCreator({
4047
4075
  node: reportNode
4048
4076
  });
4049
4077
  }
4050
- function checkNode(node) {
4078
+ function checkThrowError(node) {
4051
4079
  if (couldBeObservable(node)) {
4052
4080
  const [arg] = node.arguments;
4053
4081
  if (arg) {
@@ -4055,13 +4083,18 @@ var throwErrorRule = ruleCreator({
4055
4083
  }
4056
4084
  }
4057
4085
  }
4058
- return {
4059
- "CallExpression[callee.name='throwError']": (node) => {
4060
- checkNode(node);
4061
- },
4062
- "CallExpression[callee.property.name='throwError']": (node) => {
4063
- checkNode(node);
4086
+ function checkSubjectError(node) {
4087
+ if (isMemberExpression(node.callee) && couldBeSubject(node.callee.object)) {
4088
+ const [arg] = node.arguments;
4089
+ if (arg) {
4090
+ checkThrowArgument(arg, true);
4091
+ }
4064
4092
  }
4093
+ }
4094
+ return {
4095
+ "CallExpression[callee.name='throwError']": checkThrowError,
4096
+ "CallExpression[callee.property.name='throwError']": checkThrowError,
4097
+ "CallExpression[callee.property.name='error']": checkSubjectError
4065
4098
  };
4066
4099
  }
4067
4100
  });
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-rxjs-x",
3
3
  "type": "commonjs",
4
- "version": "0.7.4",
4
+ "version": "0.7.5",
5
5
  "packageManager": "yarn@4.9.1+sha512.f95ce356460e05be48d66401c1ae64ef84d163dd689964962c6888a9810865e39097a5e9de748876c2e0bf89b232d583c33982773e9903ae7a76257270986538",
6
6
  "description": "ESLint v9+ plugin for RxJS",
7
7
  "author": "Jason Weinzierl <weinzierljason@gmail.com>",
@@ -72,28 +72,29 @@
72
72
  }
73
73
  },
74
74
  "devDependencies": {
75
- "@eslint/js": "^9.27.0",
75
+ "@eslint/js": "^9.28.0",
76
76
  "@stylistic/eslint-plugin": "^4.4.0",
77
77
  "@types/common-tags": "^1.8.4",
78
78
  "@types/node": "~18.18.0",
79
- "@typescript-eslint/rule-tester": "^8.32.1",
79
+ "@typescript-eslint/rule-tester": "^8.33.1",
80
80
  "@typescript/vfs": "^1.6.1",
81
- "@vitest/coverage-v8": "^3.1.4",
81
+ "@vitest/coverage-v8": "^3.2.0",
82
82
  "@vitest/eslint-plugin": "^1.2.1",
83
83
  "bumpp": "^10.1.1",
84
- "eslint": "^9.27.0",
84
+ "eslint": "^9.28.0",
85
85
  "eslint-config-flat-gitignore": "^2.1.0",
86
86
  "eslint-doc-generator": "^2.1.2",
87
- "eslint-import-resolver-typescript": "^4.4.0",
87
+ "eslint-import-resolver-typescript": "^4.4.2",
88
88
  "eslint-plugin-eslint-plugin": "^6.4.0",
89
- "eslint-plugin-import-x": "^4.13.1",
90
- "eslint-plugin-n": "^17.18.0",
89
+ "eslint-plugin-import-x": "^4.15.0",
90
+ "eslint-plugin-n": "^17.19.0",
91
91
  "markdownlint-cli2": "^0.18.1",
92
92
  "rxjs": "^7.8.2",
93
93
  "tsup": "^8.5.0",
94
94
  "typescript": "~5.8.3",
95
- "typescript-eslint": "^8.32.1",
96
- "vitest": "^3.1.4"
95
+ "typescript-eslint": "^8.33.1",
96
+ "vite": "^6.3.5",
97
+ "vitest": "^3.2.0"
97
98
  },
98
99
  "engines": {
99
100
  "node": "^18.18.0 || ^20.9.0 || >= 21.1.0"