eslint-plugin-rxjs-x 0.9.1 → 0.9.3

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
@@ -128,7 +128,7 @@ The package includes the following rules.
128
128
  | [no-async-subscribe](docs/rules/no-async-subscribe.md) | Disallow passing `async` functions to `subscribe`. | ✅ 🔒 | | | 💭 | |
129
129
  | [no-compat](docs/rules/no-compat.md) | Disallow the `rxjs-compat` package. | | | | | ❌ |
130
130
  | [no-connectable](docs/rules/no-connectable.md) | Disallow operators that return connectable observables. | | | | 💭 | |
131
- | [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` function. | ✅ 🔒 | | | 💭 | |
131
+ | [no-create](docs/rules/no-create.md) | Disallow the static `Observable.create` and `Subject.create` functions. | ✅ 🔒 | | | 💭 | |
132
132
  | [no-cyclic-action](docs/rules/no-cyclic-action.md) | Disallow cyclic actions in effects and epics. | | | | 💭 | |
133
133
  | [no-explicit-generics](docs/rules/no-explicit-generics.md) | Disallow unnecessary explicit generic type arguments. | | | | 💭 | |
134
134
  | [no-exposed-subjects](docs/rules/no-exposed-subjects.md) | Disallow public and protected subjects. | 🔒 | | | 💭 | |
@@ -142,7 +142,7 @@ The package includes the following rules.
142
142
  | [no-ignored-subscribe](docs/rules/no-ignored-subscribe.md) | Disallow calling `subscribe` without specifying arguments. | | | | 💭 | |
143
143
  | [no-ignored-subscription](docs/rules/no-ignored-subscription.md) | Disallow ignoring the subscription returned by `subscribe`. | | | | 💭 | |
144
144
  | [no-ignored-takewhile-value](docs/rules/no-ignored-takewhile-value.md) | Disallow ignoring the value within `takeWhile`. | ✅ 🔒 | | | | |
145
- | [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError` operators. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
145
+ | [no-implicit-any-catch](docs/rules/no-implicit-any-catch.md) | Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
146
146
  | [no-index](docs/rules/no-index.md) | Disallow importing index modules. | ✅ 🔒 | | | | |
147
147
  | [no-internal](docs/rules/no-internal.md) | Disallow importing internal modules. | ✅ 🔒 | 🔧 | 💡 | | |
148
148
  | [no-misused-observables](docs/rules/no-misused-observables.md) | Disallow Observables in places not designed to handle them. | 🔒 | | | 💭 | |
@@ -167,6 +167,6 @@ The package includes the following rules.
167
167
  | [prefer-observer](docs/rules/prefer-observer.md) | Disallow passing separate handlers to `subscribe` and `tap`. | ✅ 🔒 | 🔧 | 💡 | 💭 | |
168
168
  | [prefer-root-operators](docs/rules/prefer-root-operators.md) | Disallow importing operators from `rxjs/operators`. | ✅ 🔒 | 🔧 | 💡 | | |
169
169
  | [suffix-subjects](docs/rules/suffix-subjects.md) | Enforce the use of a suffix in subject identifiers. | | | | 💭 | |
170
- | [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError` or `Subject.error`. | ✅ 🔒 | | | 💭 | |
170
+ | [throw-error](docs/rules/throw-error.md) | Enforce passing only `Error` values to `throwError` or `Subject.error`. | ✅ 🔒 | | 💡 | 💭 | |
171
171
 
172
172
  <!-- end auto-generated rules list -->
package/dist/index.d.mts CHANGED
@@ -50,8 +50,8 @@ declare const allRules: {
50
50
  description: "Disallow operators that return connectable observables.";
51
51
  requiresTypeChecking: true;
52
52
  }, TSESLint.RuleListener>;
53
- 'no-create': TSESLint.RuleModule<"forbidden", [], {
54
- description: "Disallow the static `Observable.create` function.";
53
+ 'no-create': TSESLint.RuleModule<"forbidden" | "forbiddenSubject", [], {
54
+ description: "Disallow the static `Observable.create` and `Subject.create` functions.";
55
55
  recommended: "recommended";
56
56
  requiresTypeChecking: true;
57
57
  }, TSESLint.RuleListener>;
@@ -120,10 +120,11 @@ declare const allRules: {
120
120
  description: "Disallow ignoring the value within `takeWhile`.";
121
121
  recommended: "recommended";
122
122
  }, TSESLint.RuleListener>;
123
- 'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown" | "suggestExplicitAny", readonly {
123
+ 'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "narrowedAllowError" | "suggestExplicitUnknown" | "suggestExplicitAny" | "suggestExplicitError", readonly {
124
124
  allowExplicitAny?: boolean;
125
+ allowExplicitError?: boolean;
125
126
  }[], {
126
- description: "Disallow implicit `any` error parameters in `catchError` operators.";
127
+ description: "Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`.";
127
128
  recommended: {
128
129
  recommended: true;
129
130
  strict: [{
@@ -267,7 +268,7 @@ declare const allRules: {
267
268
  description: "Enforce the use of a suffix in subject identifiers.";
268
269
  requiresTypeChecking: true;
269
270
  }, TSESLint.RuleListener>;
270
- 'throw-error': TSESLint.RuleModule<"forbidden", readonly {
271
+ 'throw-error': TSESLint.RuleModule<"forbidden" | "suggestErrorConstructor", readonly {
271
272
  allowThrowingAny?: boolean;
272
273
  allowThrowingUnknown?: boolean;
273
274
  }[], {
package/dist/index.d.ts CHANGED
@@ -50,8 +50,8 @@ declare const allRules: {
50
50
  description: "Disallow operators that return connectable observables.";
51
51
  requiresTypeChecking: true;
52
52
  }, TSESLint.RuleListener>;
53
- 'no-create': TSESLint.RuleModule<"forbidden", [], {
54
- description: "Disallow the static `Observable.create` function.";
53
+ 'no-create': TSESLint.RuleModule<"forbidden" | "forbiddenSubject", [], {
54
+ description: "Disallow the static `Observable.create` and `Subject.create` functions.";
55
55
  recommended: "recommended";
56
56
  requiresTypeChecking: true;
57
57
  }, TSESLint.RuleListener>;
@@ -120,10 +120,11 @@ declare const allRules: {
120
120
  description: "Disallow ignoring the value within `takeWhile`.";
121
121
  recommended: "recommended";
122
122
  }, TSESLint.RuleListener>;
123
- 'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown" | "suggestExplicitAny", readonly {
123
+ 'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "narrowedAllowError" | "suggestExplicitUnknown" | "suggestExplicitAny" | "suggestExplicitError", readonly {
124
124
  allowExplicitAny?: boolean;
125
+ allowExplicitError?: boolean;
125
126
  }[], {
126
- description: "Disallow implicit `any` error parameters in `catchError` operators.";
127
+ description: "Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`.";
127
128
  recommended: {
128
129
  recommended: true;
129
130
  strict: [{
@@ -267,7 +268,7 @@ declare const allRules: {
267
268
  description: "Enforce the use of a suffix in subject identifiers.";
268
269
  requiresTypeChecking: true;
269
270
  }, TSESLint.RuleListener>;
270
- 'throw-error': TSESLint.RuleModule<"forbidden", readonly {
271
+ 'throw-error': TSESLint.RuleModule<"forbidden" | "suggestErrorConstructor", readonly {
271
272
  allowThrowingAny?: boolean;
272
273
  allowThrowingUnknown?: boolean;
273
274
  }[], {
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.9.1";
3
+ var version = "0.9.3";
4
4
 
5
5
  // src/configs/recommended.ts
6
6
  var createRecommendedConfig = (plugin2) => ({
@@ -117,7 +117,10 @@ function couldBeType(type, name2, qualified) {
117
117
  if (tsutils.isTypeReference(type)) {
118
118
  type = type.target;
119
119
  }
120
- if (isType(type, name2, qualified)) {
120
+ if (isType(type.symbol, name2, qualified)) {
121
+ return true;
122
+ }
123
+ if (type.aliasSymbol && isType(type.aliasSymbol, name2, qualified)) {
121
124
  return true;
122
125
  }
123
126
  if (tsutils.isUnionOrIntersectionType(type)) {
@@ -132,16 +135,16 @@ function couldBeType(type, name2, qualified) {
132
135
  }
133
136
  return false;
134
137
  }
135
- function isType(type, name2, qualified) {
136
- if (!type.symbol) {
138
+ function isType(symbol, name2, qualified) {
139
+ if (!symbol) {
137
140
  return false;
138
141
  }
139
142
  if (qualified && !qualified.name.test(
140
- qualified.typeChecker.getFullyQualifiedName(type.symbol)
143
+ qualified.typeChecker.getFullyQualifiedName(symbol)
141
144
  )) {
142
145
  return false;
143
146
  }
144
- return typeof name2 === "string" ? type.symbol.name === name2 : Boolean(type.symbol.name.match(name2));
147
+ return typeof name2 === "string" ? symbol.name === name2 : Boolean(symbol.name.match(name2));
145
148
  }
146
149
  function couldImplement(type, name2, qualified) {
147
150
  const { symbol } = type;
@@ -274,6 +277,9 @@ function isJSXExpressionContainer(node) {
274
277
  function isLiteral(node) {
275
278
  return node.type === _utils.AST_NODE_TYPES.Literal;
276
279
  }
280
+ function isTemplateLiteral(node) {
281
+ return node.type === _utils.AST_NODE_TYPES.TemplateLiteral;
282
+ }
277
283
  function isMemberExpression(node) {
278
284
  return node.type === _utils.AST_NODE_TYPES.MemberExpression;
279
285
  }
@@ -1103,19 +1109,20 @@ var noCreateRule = ruleCreator({
1103
1109
  defaultOptions: [],
1104
1110
  meta: {
1105
1111
  docs: {
1106
- description: "Disallow the static `Observable.create` function.",
1112
+ description: "Disallow the static `Observable.create` and `Subject.create` functions.",
1107
1113
  recommended: "recommended",
1108
1114
  requiresTypeChecking: true
1109
1115
  },
1110
1116
  messages: {
1111
- forbidden: "Observable.create is forbidden; use new Observable."
1117
+ forbidden: "Observable.create is forbidden; use new Observable.",
1118
+ forbiddenSubject: "Subject.create is forbidden."
1112
1119
  },
1113
1120
  schema: [],
1114
1121
  type: "problem"
1115
1122
  },
1116
1123
  name: "no-create",
1117
1124
  create: (context) => {
1118
- const { couldBeObservable } = getTypeServices(context);
1125
+ const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
1119
1126
  return {
1120
1127
  "CallExpression > MemberExpression[object.name='Observable'] > Identifier[name='create']": (node) => {
1121
1128
  const memberExpression = node.parent;
@@ -1125,6 +1132,15 @@ var noCreateRule = ruleCreator({
1125
1132
  node
1126
1133
  });
1127
1134
  }
1135
+ },
1136
+ "CallExpression > MemberExpression[object.name=/^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/] > Identifier[name='create']": (node) => {
1137
+ const memberExpression = node.parent;
1138
+ if (couldBeType2(memberExpression.object, /^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/)) {
1139
+ context.report({
1140
+ messageId: "forbiddenSubject",
1141
+ node
1142
+ });
1143
+ }
1128
1144
  }
1129
1145
  };
1130
1146
  }
@@ -2090,7 +2106,7 @@ var noImplicitAnyCatchRule = ruleCreator({
2090
2106
  defaultOptions: defaultOptions8,
2091
2107
  meta: {
2092
2108
  docs: {
2093
- description: "Disallow implicit `any` error parameters in `catchError` operators.",
2109
+ description: "Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`.",
2094
2110
  recommended: {
2095
2111
  recommended: true,
2096
2112
  strict: [{
@@ -2105,8 +2121,10 @@ var noImplicitAnyCatchRule = ruleCreator({
2105
2121
  explicitAny: "Explicit `any` in error callback.",
2106
2122
  implicitAny: "Implicit `any` in error callback.",
2107
2123
  narrowed: "Error type must be `unknown` or `any`.",
2124
+ narrowedAllowError: "Error type must be `unknown`, `any`, or `Error`.",
2108
2125
  suggestExplicitUnknown: "Use `unknown` instead to explicitly and safely assert the type is correct.",
2109
- suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety."
2126
+ suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety.",
2127
+ suggestExplicitError: "Use `Error` instead."
2110
2128
  },
2111
2129
  schema: [
2112
2130
  {
@@ -2116,6 +2134,11 @@ var noImplicitAnyCatchRule = ruleCreator({
2116
2134
  type: "boolean",
2117
2135
  description: "Allow error variable to be explicitly typed as `any`.",
2118
2136
  default: true
2137
+ },
2138
+ allowExplicitError: {
2139
+ type: "boolean",
2140
+ description: "Allow narrowing error type to `Error`.",
2141
+ default: false
2119
2142
  }
2120
2143
  },
2121
2144
  type: "object"
@@ -2126,7 +2149,7 @@ var noImplicitAnyCatchRule = ruleCreator({
2126
2149
  name: "no-implicit-any-catch",
2127
2150
  create: (context) => {
2128
2151
  const [config = {}] = context.options;
2129
- const { allowExplicitAny = true } = config;
2152
+ const { allowExplicitAny = true, allowExplicitError = false } = config;
2130
2153
  const { couldBeObservable } = getTypeServices(context);
2131
2154
  const sourceCode = context.sourceCode;
2132
2155
  function createReplacerFix(typeAnnotation, replaceWith) {
@@ -2171,20 +2194,33 @@ var noImplicitAnyCatchRule = ruleCreator({
2171
2194
  ]
2172
2195
  });
2173
2196
  } else if (type !== _utils.AST_NODE_TYPES.TSUnknownKeyword) {
2174
- context.report({
2175
- messageId: "narrowed",
2176
- node: param,
2177
- suggest: [
2178
- {
2179
- messageId: "suggestExplicitUnknown",
2180
- fix: createReplacerFix(typeAnnotation, "unknown")
2181
- },
2182
- allowExplicitAny ? {
2183
- messageId: "suggestExplicitAny",
2184
- fix: createReplacerFix(typeAnnotation, "any")
2185
- } : null
2186
- ].filter((x) => !!x)
2187
- });
2197
+ let isAllowedError = false;
2198
+ if (allowExplicitError && type === _utils.AST_NODE_TYPES.TSTypeReference) {
2199
+ const typeRef = typeAnnotation.typeAnnotation;
2200
+ if (isIdentifier(typeRef.typeName)) {
2201
+ isAllowedError = typeRef.typeName.name === "Error";
2202
+ }
2203
+ }
2204
+ if (!isAllowedError) {
2205
+ context.report({
2206
+ messageId: allowExplicitError ? "narrowedAllowError" : "narrowed",
2207
+ node: param,
2208
+ suggest: [
2209
+ {
2210
+ messageId: "suggestExplicitUnknown",
2211
+ fix: createReplacerFix(typeAnnotation, "unknown")
2212
+ },
2213
+ allowExplicitAny ? {
2214
+ messageId: "suggestExplicitAny",
2215
+ fix: createReplacerFix(typeAnnotation, "any")
2216
+ } : null,
2217
+ allowExplicitError && !isAllowedError ? {
2218
+ messageId: "suggestExplicitError",
2219
+ fix: createReplacerFix(typeAnnotation, "Error")
2220
+ } : null
2221
+ ].filter((x) => !!x)
2222
+ });
2223
+ }
2188
2224
  }
2189
2225
  } else {
2190
2226
  const hasRestParams = restParams.length > 0;
@@ -3356,7 +3392,7 @@ var noUnboundMethodsRule = ruleCreator({
3356
3392
  const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
3357
3393
  const nodeMap = /* @__PURE__ */ new WeakMap();
3358
3394
  const [config = {}] = context.options;
3359
- const { allowTypes = [] } = config;
3395
+ const { allowTypes = DEFAULT_UNBOUND_ALLOWED_TYPES } = config;
3360
3396
  function mapArguments(node) {
3361
3397
  node.arguments.filter(isMemberExpression).forEach((arg) => {
3362
3398
  const argType = getTypeAtLocation(arg);
@@ -3678,6 +3714,16 @@ var noUnsafeSubjectNext = ruleCreator({
3678
3714
  // src/rules/no-unsafe-switchmap.ts
3679
3715
 
3680
3716
  var _decamelize = require('decamelize'); var _decamelize2 = _interopRequireDefault(_decamelize);
3717
+ var DEFAULT_DISALLOW = [
3718
+ "add",
3719
+ "create",
3720
+ "delete",
3721
+ "post",
3722
+ "put",
3723
+ "remove",
3724
+ "set",
3725
+ "update"
3726
+ ];
3681
3727
  var defaultOptions15 = [];
3682
3728
  var noUnsafeSwitchmapRule = ruleCreator({
3683
3729
  defaultOptions: defaultOptions15,
@@ -3704,7 +3750,8 @@ var noUnsafeSwitchmapRule = ruleCreator({
3704
3750
  oneOf: [
3705
3751
  { type: "string", description: "A regular expression string." },
3706
3752
  { type: "array", items: { type: "string" }, description: "An array of words." }
3707
- ]
3753
+ ],
3754
+ default: DEFAULT_DISALLOW
3708
3755
  },
3709
3756
  observable: {
3710
3757
  type: "string",
@@ -3727,29 +3774,15 @@ var noUnsafeSwitchmapRule = ruleCreator({
3727
3774
  name: "no-unsafe-switchmap",
3728
3775
  create: (context) => {
3729
3776
  var _a, _b, _c;
3730
- const defaultDisallow = [
3731
- "add",
3732
- "create",
3733
- "delete",
3734
- "post",
3735
- "put",
3736
- "remove",
3737
- "set",
3738
- "update"
3739
- ];
3740
- let allowRegExp;
3741
- let disallowRegExp;
3742
- let observableRegExp;
3777
+ let allowRegExp = void 0;
3778
+ let disallowRegExp = void 0;
3743
3779
  const [config = {}] = context.options;
3744
- if (config.allow || config.disallow) {
3780
+ if (config.allow) {
3745
3781
  allowRegExp = createRegExpForWords((_a = config.allow) != null ? _a : []);
3746
- disallowRegExp = createRegExpForWords((_b = config.disallow) != null ? _b : []);
3747
- observableRegExp = new RegExp((_c = config.observable) != null ? _c : defaultObservable);
3748
3782
  } else {
3749
- allowRegExp = void 0;
3750
- disallowRegExp = createRegExpForWords(defaultDisallow);
3751
- observableRegExp = new RegExp(defaultObservable);
3783
+ disallowRegExp = createRegExpForWords((_b = config.disallow) != null ? _b : DEFAULT_DISALLOW);
3752
3784
  }
3785
+ const observableRegExp = new RegExp((_c = config.observable) != null ? _c : defaultObservable);
3753
3786
  const { couldBeObservable } = getTypeServices(context);
3754
3787
  function shouldDisallow(args) {
3755
3788
  const names = args.map((arg) => {
@@ -4317,7 +4350,8 @@ var throwErrorRule = ruleCreator({
4317
4350
  requiresTypeChecking: true
4318
4351
  },
4319
4352
  messages: {
4320
- forbidden: "Passing non-Error values is forbidden."
4353
+ forbidden: "Passing non-Error values is forbidden.",
4354
+ suggestErrorConstructor: "Wrap string in Error constructor."
4321
4355
  },
4322
4356
  schema: [
4323
4357
  {
@@ -4328,7 +4362,8 @@ var throwErrorRule = ruleCreator({
4328
4362
  type: "object"
4329
4363
  }
4330
4364
  ],
4331
- type: "problem"
4365
+ type: "problem",
4366
+ hasSuggestions: true
4332
4367
  },
4333
4368
  name: "throw-error",
4334
4369
  create: (context) => {
@@ -4356,9 +4391,22 @@ var throwErrorRule = ruleCreator({
4356
4391
  if (couldBeType(type, /^Error$/)) {
4357
4392
  return;
4358
4393
  }
4394
+ const isString = isTemplateLiteral(reportNode) || isLiteral(reportNode) && typeof reportNode.value === "string";
4359
4395
  context.report({
4360
4396
  messageId: "forbidden",
4361
- node: reportNode
4397
+ node: reportNode,
4398
+ ...isString && {
4399
+ suggest: [
4400
+ {
4401
+ messageId: "suggestErrorConstructor",
4402
+ fix: (fixer) => {
4403
+ const sourceCode = context.sourceCode;
4404
+ const nodeText = sourceCode.getText(reportNode);
4405
+ return fixer.replaceText(reportNode, `new Error(${nodeText})`);
4406
+ }
4407
+ }
4408
+ ]
4409
+ }
4362
4410
  });
4363
4411
  }
4364
4412
  function checkThrowError(node) {
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.9.1";
3
+ var version = "0.9.3";
4
4
 
5
5
  // src/configs/recommended.ts
6
6
  var createRecommendedConfig = (plugin2) => ({
@@ -117,7 +117,10 @@ function couldBeType(type, name2, qualified) {
117
117
  if (tsutils.isTypeReference(type)) {
118
118
  type = type.target;
119
119
  }
120
- if (isType(type, name2, qualified)) {
120
+ if (isType(type.symbol, name2, qualified)) {
121
+ return true;
122
+ }
123
+ if (type.aliasSymbol && isType(type.aliasSymbol, name2, qualified)) {
121
124
  return true;
122
125
  }
123
126
  if (tsutils.isUnionOrIntersectionType(type)) {
@@ -132,16 +135,16 @@ function couldBeType(type, name2, qualified) {
132
135
  }
133
136
  return false;
134
137
  }
135
- function isType(type, name2, qualified) {
136
- if (!type.symbol) {
138
+ function isType(symbol, name2, qualified) {
139
+ if (!symbol) {
137
140
  return false;
138
141
  }
139
142
  if (qualified && !qualified.name.test(
140
- qualified.typeChecker.getFullyQualifiedName(type.symbol)
143
+ qualified.typeChecker.getFullyQualifiedName(symbol)
141
144
  )) {
142
145
  return false;
143
146
  }
144
- return typeof name2 === "string" ? type.symbol.name === name2 : Boolean(type.symbol.name.match(name2));
147
+ return typeof name2 === "string" ? symbol.name === name2 : Boolean(symbol.name.match(name2));
145
148
  }
146
149
  function couldImplement(type, name2, qualified) {
147
150
  const { symbol } = type;
@@ -274,6 +277,9 @@ function isJSXExpressionContainer(node) {
274
277
  function isLiteral(node) {
275
278
  return node.type === AST_NODE_TYPES.Literal;
276
279
  }
280
+ function isTemplateLiteral(node) {
281
+ return node.type === AST_NODE_TYPES.TemplateLiteral;
282
+ }
277
283
  function isMemberExpression(node) {
278
284
  return node.type === AST_NODE_TYPES.MemberExpression;
279
285
  }
@@ -1103,19 +1109,20 @@ var noCreateRule = ruleCreator({
1103
1109
  defaultOptions: [],
1104
1110
  meta: {
1105
1111
  docs: {
1106
- description: "Disallow the static `Observable.create` function.",
1112
+ description: "Disallow the static `Observable.create` and `Subject.create` functions.",
1107
1113
  recommended: "recommended",
1108
1114
  requiresTypeChecking: true
1109
1115
  },
1110
1116
  messages: {
1111
- forbidden: "Observable.create is forbidden; use new Observable."
1117
+ forbidden: "Observable.create is forbidden; use new Observable.",
1118
+ forbiddenSubject: "Subject.create is forbidden."
1112
1119
  },
1113
1120
  schema: [],
1114
1121
  type: "problem"
1115
1122
  },
1116
1123
  name: "no-create",
1117
1124
  create: (context) => {
1118
- const { couldBeObservable } = getTypeServices(context);
1125
+ const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
1119
1126
  return {
1120
1127
  "CallExpression > MemberExpression[object.name='Observable'] > Identifier[name='create']": (node) => {
1121
1128
  const memberExpression = node.parent;
@@ -1125,6 +1132,15 @@ var noCreateRule = ruleCreator({
1125
1132
  node
1126
1133
  });
1127
1134
  }
1135
+ },
1136
+ "CallExpression > MemberExpression[object.name=/^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/] > Identifier[name='create']": (node) => {
1137
+ const memberExpression = node.parent;
1138
+ if (couldBeType2(memberExpression.object, /^(Subject|BehaviorSubject|AsyncSubject|ReplaySubject)$/)) {
1139
+ context.report({
1140
+ messageId: "forbiddenSubject",
1141
+ node
1142
+ });
1143
+ }
1128
1144
  }
1129
1145
  };
1130
1146
  }
@@ -2090,7 +2106,7 @@ var noImplicitAnyCatchRule = ruleCreator({
2090
2106
  defaultOptions: defaultOptions8,
2091
2107
  meta: {
2092
2108
  docs: {
2093
- description: "Disallow implicit `any` error parameters in `catchError` operators.",
2109
+ description: "Disallow implicit `any` error parameters in `catchError`, `subscribe`, and `tap`.",
2094
2110
  recommended: {
2095
2111
  recommended: true,
2096
2112
  strict: [{
@@ -2105,8 +2121,10 @@ var noImplicitAnyCatchRule = ruleCreator({
2105
2121
  explicitAny: "Explicit `any` in error callback.",
2106
2122
  implicitAny: "Implicit `any` in error callback.",
2107
2123
  narrowed: "Error type must be `unknown` or `any`.",
2124
+ narrowedAllowError: "Error type must be `unknown`, `any`, or `Error`.",
2108
2125
  suggestExplicitUnknown: "Use `unknown` instead to explicitly and safely assert the type is correct.",
2109
- suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety."
2126
+ suggestExplicitAny: "Use `any` instead to explicitly opt out of type safety.",
2127
+ suggestExplicitError: "Use `Error` instead."
2110
2128
  },
2111
2129
  schema: [
2112
2130
  {
@@ -2116,6 +2134,11 @@ var noImplicitAnyCatchRule = ruleCreator({
2116
2134
  type: "boolean",
2117
2135
  description: "Allow error variable to be explicitly typed as `any`.",
2118
2136
  default: true
2137
+ },
2138
+ allowExplicitError: {
2139
+ type: "boolean",
2140
+ description: "Allow narrowing error type to `Error`.",
2141
+ default: false
2119
2142
  }
2120
2143
  },
2121
2144
  type: "object"
@@ -2126,7 +2149,7 @@ var noImplicitAnyCatchRule = ruleCreator({
2126
2149
  name: "no-implicit-any-catch",
2127
2150
  create: (context) => {
2128
2151
  const [config = {}] = context.options;
2129
- const { allowExplicitAny = true } = config;
2152
+ const { allowExplicitAny = true, allowExplicitError = false } = config;
2130
2153
  const { couldBeObservable } = getTypeServices(context);
2131
2154
  const sourceCode = context.sourceCode;
2132
2155
  function createReplacerFix(typeAnnotation, replaceWith) {
@@ -2171,20 +2194,33 @@ var noImplicitAnyCatchRule = ruleCreator({
2171
2194
  ]
2172
2195
  });
2173
2196
  } else if (type !== AST_NODE_TYPES4.TSUnknownKeyword) {
2174
- context.report({
2175
- messageId: "narrowed",
2176
- node: param,
2177
- suggest: [
2178
- {
2179
- messageId: "suggestExplicitUnknown",
2180
- fix: createReplacerFix(typeAnnotation, "unknown")
2181
- },
2182
- allowExplicitAny ? {
2183
- messageId: "suggestExplicitAny",
2184
- fix: createReplacerFix(typeAnnotation, "any")
2185
- } : null
2186
- ].filter((x) => !!x)
2187
- });
2197
+ let isAllowedError = false;
2198
+ if (allowExplicitError && type === AST_NODE_TYPES4.TSTypeReference) {
2199
+ const typeRef = typeAnnotation.typeAnnotation;
2200
+ if (isIdentifier(typeRef.typeName)) {
2201
+ isAllowedError = typeRef.typeName.name === "Error";
2202
+ }
2203
+ }
2204
+ if (!isAllowedError) {
2205
+ context.report({
2206
+ messageId: allowExplicitError ? "narrowedAllowError" : "narrowed",
2207
+ node: param,
2208
+ suggest: [
2209
+ {
2210
+ messageId: "suggestExplicitUnknown",
2211
+ fix: createReplacerFix(typeAnnotation, "unknown")
2212
+ },
2213
+ allowExplicitAny ? {
2214
+ messageId: "suggestExplicitAny",
2215
+ fix: createReplacerFix(typeAnnotation, "any")
2216
+ } : null,
2217
+ allowExplicitError && !isAllowedError ? {
2218
+ messageId: "suggestExplicitError",
2219
+ fix: createReplacerFix(typeAnnotation, "Error")
2220
+ } : null
2221
+ ].filter((x) => !!x)
2222
+ });
2223
+ }
2188
2224
  }
2189
2225
  } else {
2190
2226
  const hasRestParams = restParams.length > 0;
@@ -3356,7 +3392,7 @@ var noUnboundMethodsRule = ruleCreator({
3356
3392
  const { couldBeObservable, couldBeSubscription } = getTypeServices(context);
3357
3393
  const nodeMap = /* @__PURE__ */ new WeakMap();
3358
3394
  const [config = {}] = context.options;
3359
- const { allowTypes = [] } = config;
3395
+ const { allowTypes = DEFAULT_UNBOUND_ALLOWED_TYPES } = config;
3360
3396
  function mapArguments(node) {
3361
3397
  node.arguments.filter(isMemberExpression).forEach((arg) => {
3362
3398
  const argType = getTypeAtLocation(arg);
@@ -3678,6 +3714,16 @@ var noUnsafeSubjectNext = ruleCreator({
3678
3714
  // src/rules/no-unsafe-switchmap.ts
3679
3715
  import { stripIndent as stripIndent7 } from "common-tags";
3680
3716
  import decamelize from "decamelize";
3717
+ var DEFAULT_DISALLOW = [
3718
+ "add",
3719
+ "create",
3720
+ "delete",
3721
+ "post",
3722
+ "put",
3723
+ "remove",
3724
+ "set",
3725
+ "update"
3726
+ ];
3681
3727
  var defaultOptions15 = [];
3682
3728
  var noUnsafeSwitchmapRule = ruleCreator({
3683
3729
  defaultOptions: defaultOptions15,
@@ -3704,7 +3750,8 @@ var noUnsafeSwitchmapRule = ruleCreator({
3704
3750
  oneOf: [
3705
3751
  { type: "string", description: "A regular expression string." },
3706
3752
  { type: "array", items: { type: "string" }, description: "An array of words." }
3707
- ]
3753
+ ],
3754
+ default: DEFAULT_DISALLOW
3708
3755
  },
3709
3756
  observable: {
3710
3757
  type: "string",
@@ -3727,29 +3774,15 @@ var noUnsafeSwitchmapRule = ruleCreator({
3727
3774
  name: "no-unsafe-switchmap",
3728
3775
  create: (context) => {
3729
3776
  var _a, _b, _c;
3730
- const defaultDisallow = [
3731
- "add",
3732
- "create",
3733
- "delete",
3734
- "post",
3735
- "put",
3736
- "remove",
3737
- "set",
3738
- "update"
3739
- ];
3740
- let allowRegExp;
3741
- let disallowRegExp;
3742
- let observableRegExp;
3777
+ let allowRegExp = void 0;
3778
+ let disallowRegExp = void 0;
3743
3779
  const [config = {}] = context.options;
3744
- if (config.allow || config.disallow) {
3780
+ if (config.allow) {
3745
3781
  allowRegExp = createRegExpForWords((_a = config.allow) != null ? _a : []);
3746
- disallowRegExp = createRegExpForWords((_b = config.disallow) != null ? _b : []);
3747
- observableRegExp = new RegExp((_c = config.observable) != null ? _c : defaultObservable);
3748
3782
  } else {
3749
- allowRegExp = void 0;
3750
- disallowRegExp = createRegExpForWords(defaultDisallow);
3751
- observableRegExp = new RegExp(defaultObservable);
3783
+ disallowRegExp = createRegExpForWords((_b = config.disallow) != null ? _b : DEFAULT_DISALLOW);
3752
3784
  }
3785
+ const observableRegExp = new RegExp((_c = config.observable) != null ? _c : defaultObservable);
3753
3786
  const { couldBeObservable } = getTypeServices(context);
3754
3787
  function shouldDisallow(args) {
3755
3788
  const names = args.map((arg) => {
@@ -4317,7 +4350,8 @@ var throwErrorRule = ruleCreator({
4317
4350
  requiresTypeChecking: true
4318
4351
  },
4319
4352
  messages: {
4320
- forbidden: "Passing non-Error values is forbidden."
4353
+ forbidden: "Passing non-Error values is forbidden.",
4354
+ suggestErrorConstructor: "Wrap string in Error constructor."
4321
4355
  },
4322
4356
  schema: [
4323
4357
  {
@@ -4328,7 +4362,8 @@ var throwErrorRule = ruleCreator({
4328
4362
  type: "object"
4329
4363
  }
4330
4364
  ],
4331
- type: "problem"
4365
+ type: "problem",
4366
+ hasSuggestions: true
4332
4367
  },
4333
4368
  name: "throw-error",
4334
4369
  create: (context) => {
@@ -4356,9 +4391,22 @@ var throwErrorRule = ruleCreator({
4356
4391
  if (couldBeType(type, /^Error$/)) {
4357
4392
  return;
4358
4393
  }
4394
+ const isString = isTemplateLiteral(reportNode) || isLiteral(reportNode) && typeof reportNode.value === "string";
4359
4395
  context.report({
4360
4396
  messageId: "forbidden",
4361
- node: reportNode
4397
+ node: reportNode,
4398
+ ...isString && {
4399
+ suggest: [
4400
+ {
4401
+ messageId: "suggestErrorConstructor",
4402
+ fix: (fixer) => {
4403
+ const sourceCode = context.sourceCode;
4404
+ const nodeText = sourceCode.getText(reportNode);
4405
+ return fixer.replaceText(reportNode, `new Error(${nodeText})`);
4406
+ }
4407
+ }
4408
+ ]
4409
+ }
4362
4410
  });
4363
4411
  }
4364
4412
  function checkThrowError(node) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "eslint-plugin-rxjs-x",
3
3
  "type": "commonjs",
4
- "version": "0.9.1",
4
+ "version": "0.9.3",
5
5
  "packageManager": "yarn@4.12.0+sha512.f45ab632439a67f8bc759bf32ead036a1f413287b9042726b7cc4818b7b49e14e9423ba49b18f9e06ea4941c1ad062385b1d8760a8d5091a1a31e5f6219afca8",
6
6
  "description": "Modern ESLint plugin for RxJS",
7
7
  "author": "Jason Weinzierl <weinzierljason@gmail.com>",
@@ -84,12 +84,12 @@
84
84
  "@typescript/vfs": "^1.6.2",
85
85
  "@vitest/coverage-v8": "^3.2.4",
86
86
  "@vitest/eslint-plugin": "^1.4.0",
87
- "bumpp": "^10.4.0",
87
+ "bumpp": "^10.4.1",
88
88
  "eslint": "^9.39.2",
89
89
  "eslint-config-flat-gitignore": "^2.1.0",
90
90
  "eslint-doc-generator": "^2.4.0",
91
91
  "eslint-import-resolver-typescript": "^4.4.4",
92
- "eslint-plugin-eslint-plugin": "^7.3.0",
92
+ "eslint-plugin-eslint-plugin": "patch:eslint-plugin-eslint-plugin@npm%3A7.3.0#~/.yarn/patches/eslint-plugin-eslint-plugin-npm-7.3.0-d800475165.patch",
93
93
  "eslint-plugin-import-x": "^4.16.1",
94
94
  "eslint-plugin-n": "^17.23.2",
95
95
  "markdownlint-cli2": "~0.19.0",