eslint-plugin-rxjs-x 0.7.1 → 0.7.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.
Files changed (50) hide show
  1. package/dist/index.d.mts +4 -1
  2. package/dist/index.d.ts +4 -1
  3. package/dist/index.js +216 -153
  4. package/dist/index.mjs +252 -189
  5. package/package.json +19 -20
  6. package/docs/rules/ban-observables.md +0 -42
  7. package/docs/rules/ban-operators.md +0 -44
  8. package/docs/rules/finnish.md +0 -91
  9. package/docs/rules/just.md +0 -20
  10. package/docs/rules/macro.md +0 -11
  11. package/docs/rules/no-async-subscribe.md +0 -54
  12. package/docs/rules/no-compat.md +0 -13
  13. package/docs/rules/no-connectable.md +0 -33
  14. package/docs/rules/no-create.md +0 -43
  15. package/docs/rules/no-cyclic-action.md +0 -88
  16. package/docs/rules/no-explicit-generics.md +0 -32
  17. package/docs/rules/no-exposed-subjects.md +0 -68
  18. package/docs/rules/no-finnish.md +0 -42
  19. package/docs/rules/no-floating-observables.md +0 -68
  20. package/docs/rules/no-ignored-default-value.md +0 -43
  21. package/docs/rules/no-ignored-error.md +0 -53
  22. package/docs/rules/no-ignored-notifier.md +0 -47
  23. package/docs/rules/no-ignored-replay-buffer.md +0 -47
  24. package/docs/rules/no-ignored-subscribe.md +0 -46
  25. package/docs/rules/no-ignored-subscription.md +0 -46
  26. package/docs/rules/no-ignored-takewhile-value.md +0 -35
  27. package/docs/rules/no-implicit-any-catch.md +0 -109
  28. package/docs/rules/no-index.md +0 -34
  29. package/docs/rules/no-internal.md +0 -38
  30. package/docs/rules/no-misused-observables.md +0 -101
  31. package/docs/rules/no-nested-subscribe.md +0 -46
  32. package/docs/rules/no-redundant-notify.md +0 -50
  33. package/docs/rules/no-sharereplay.md +0 -49
  34. package/docs/rules/no-subclass.md +0 -23
  35. package/docs/rules/no-subject-unsubscribe.md +0 -63
  36. package/docs/rules/no-subject-value.md +0 -19
  37. package/docs/rules/no-subscribe-handlers.md +0 -53
  38. package/docs/rules/no-subscribe-in-pipe.md +0 -55
  39. package/docs/rules/no-tap.md +0 -7
  40. package/docs/rules/no-topromise.md +0 -37
  41. package/docs/rules/no-unbound-methods.md +0 -61
  42. package/docs/rules/no-unsafe-catch.md +0 -74
  43. package/docs/rules/no-unsafe-first.md +0 -40
  44. package/docs/rules/no-unsafe-subject-next.md +0 -46
  45. package/docs/rules/no-unsafe-switchmap.md +0 -64
  46. package/docs/rules/no-unsafe-takeuntil.md +0 -72
  47. package/docs/rules/prefer-observer.md +0 -66
  48. package/docs/rules/prefer-root-operators.md +0 -45
  49. package/docs/rules/suffix-subjects.md +0 -81
  50. package/docs/rules/throw-error.md +0 -53
package/dist/index.d.mts CHANGED
@@ -124,7 +124,10 @@ declare const rxjsX: {
124
124
  'no-ignored-notifier': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
125
125
  'no-ignored-replay-buffer': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
126
126
  'no-ignored-subscribe': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
127
- 'no-ignored-subscription': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
127
+ 'no-ignored-subscription': TSESLint.RuleModule<"forbidden", readonly {
128
+ completers?: string[];
129
+ postCompleters?: string[];
130
+ }[], RxjsXRuleDocs, TSESLint.RuleListener>;
128
131
  'no-ignored-takewhile-value': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
129
132
  'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown", readonly {
130
133
  allowExplicitAny?: boolean;
package/dist/index.d.ts CHANGED
@@ -124,7 +124,10 @@ declare const rxjsX: {
124
124
  'no-ignored-notifier': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
125
125
  'no-ignored-replay-buffer': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
126
126
  'no-ignored-subscribe': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
127
- 'no-ignored-subscription': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
127
+ 'no-ignored-subscription': TSESLint.RuleModule<"forbidden", readonly {
128
+ completers?: string[];
129
+ postCompleters?: string[];
130
+ }[], RxjsXRuleDocs, TSESLint.RuleListener>;
128
131
  'no-ignored-takewhile-value': TSESLint.RuleModule<"forbidden", [], RxjsXRuleDocs, TSESLint.RuleListener>;
129
132
  'no-implicit-any-catch': TSESLint.RuleModule<"explicitAny" | "implicitAny" | "narrowed" | "suggestExplicitUnknown", readonly {
130
133
  allowExplicitAny?: boolean;
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.1";
3
+ var version = "0.7.3";
4
4
 
5
5
  // src/configs/recommended.ts
6
6
  var createRecommendedConfig = (plugin2) => ({
@@ -77,8 +77,7 @@ var createStrictConfig = (plugin2) => ({
77
77
  var _utils = require('@typescript-eslint/utils');
78
78
  var _commontags = require('common-tags');
79
79
 
80
- // src/utils.ts
81
-
80
+ // src/utils/create-regexp-for-words.ts
82
81
  function createRegExpForWords(config) {
83
82
  if (!(config == null ? void 0 : config.length)) {
84
83
  return void 0;
@@ -91,81 +90,11 @@ function createRegExpForWords(config) {
91
90
  const joined = words.map((word) => String.raw`(\b|_)${word}(\b|_)`).join("|");
92
91
  return new RegExp(`(${joined})`, flags);
93
92
  }
93
+
94
+ // src/utils/escape-regexp.ts
94
95
  function escapeRegExp(text) {
95
96
  return text.replace(/[-/\\^$*+?.()|[\]{}]/g, "\\$&");
96
97
  }
97
- var REPO_URL = "https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x";
98
- var ruleCreator = _utils.ESLintUtils.RuleCreator(
99
- (name2) => `${REPO_URL}/blob/v${version}/docs/rules/${name2}.md`
100
- );
101
-
102
- // src/rules/ban-observables.ts
103
- var defaultOptions = [];
104
- var banObservablesRule = ruleCreator({
105
- defaultOptions,
106
- meta: {
107
- docs: {
108
- description: "Disallow banned observable creators."
109
- },
110
- messages: {
111
- forbidden: "RxJS observable is banned: {{name}}{{explanation}}."
112
- },
113
- schema: [
114
- {
115
- type: "object",
116
- description: _commontags.stripIndent`
117
- An object containing keys that are names of observable factory functions
118
- and values that are either booleans or strings containing the explanation for the ban.`
119
- }
120
- ],
121
- type: "problem"
122
- },
123
- name: "ban-observables",
124
- create: (context) => {
125
- const bans = [];
126
- const [config] = context.options;
127
- if (!config) {
128
- return {};
129
- }
130
- Object.entries(config).forEach(([key, value]) => {
131
- if (value !== false) {
132
- bans.push({
133
- explanation: typeof value === "string" ? value : "",
134
- regExp: new RegExp(`^${key}$`)
135
- });
136
- }
137
- });
138
- function getFailure(name2) {
139
- for (let b = 0, length = bans.length; b < length; ++b) {
140
- const ban = bans[b];
141
- if (ban.regExp.test(name2)) {
142
- const explanation = ban.explanation ? `: ${ban.explanation}` : "";
143
- return {
144
- messageId: "forbidden",
145
- data: { name: name2, explanation }
146
- };
147
- }
148
- }
149
- return void 0;
150
- }
151
- return {
152
- "ImportDeclaration[source.value='rxjs'] > ImportSpecifier": (node) => {
153
- const identifier = node.imported;
154
- const name2 = identifier.type === _utils.AST_NODE_TYPES.Identifier ? identifier.name : identifier.value;
155
- const failure = getFailure(name2);
156
- if (failure) {
157
- context.report({
158
- ...failure,
159
- node: identifier
160
- });
161
- }
162
- }
163
- };
164
- }
165
- });
166
-
167
- // src/rules/ban-operators.ts
168
-
169
98
 
170
99
  // src/etc/could-be-function.ts
171
100
  var _typescript = require('typescript'); var _typescript2 = _interopRequireDefault(_typescript);
@@ -370,11 +299,19 @@ function getTypeServices(context) {
370
299
  );
371
300
  };
372
301
  const couldReturnType = (node, name2, qualified) => {
373
- var _a;
374
302
  let tsTypeNode;
375
303
  const tsNode = esTreeNodeToTSNodeMap.get(node);
376
304
  if (_typescript2.default.isArrowFunction(tsNode) || _typescript2.default.isFunctionDeclaration(tsNode) || _typescript2.default.isMethodDeclaration(tsNode) || _typescript2.default.isFunctionExpression(tsNode)) {
377
- tsTypeNode = (_a = tsNode.type) != null ? _a : tsNode.body;
305
+ if (tsNode.type) {
306
+ tsTypeNode = tsNode.type;
307
+ } else if (tsNode.body && _typescript2.default.isBlock(tsNode.body)) {
308
+ const returnStatement = tsNode.body.statements.find(_typescript2.default.isReturnStatement);
309
+ if (returnStatement == null ? void 0 : returnStatement.expression) {
310
+ tsTypeNode = returnStatement.expression;
311
+ }
312
+ } else {
313
+ tsTypeNode = tsNode.body;
314
+ }
378
315
  } else if (_typescript2.default.isCallSignatureDeclaration(tsNode) || _typescript2.default.isMethodSignature(tsNode)) {
379
316
  tsTypeNode = tsNode.type;
380
317
  } else if (_typescript2.default.isPropertySignature(tsNode)) {
@@ -418,7 +355,114 @@ function isImport(scope, name2, source) {
418
355
  return scope.upper ? isImport(scope.upper, name2, source) : false;
419
356
  }
420
357
 
358
+ // src/utils/find-is-last-operator-order-valid.ts
359
+ function findIsLastOperatorOrderValid(pipeCallExpression, operatorsRegExp, allow) {
360
+ let isOrderValid = true;
361
+ let operatorNode;
362
+ for (let i = pipeCallExpression.arguments.length - 1; i >= 0; i--) {
363
+ const arg = pipeCallExpression.arguments[i];
364
+ if (operatorNode) {
365
+ break;
366
+ }
367
+ if (!isCallExpression(arg)) {
368
+ isOrderValid = false;
369
+ continue;
370
+ }
371
+ let operatorName;
372
+ if (isIdentifier(arg.callee)) {
373
+ operatorName = arg.callee.name;
374
+ } else if (isMemberExpression(arg.callee) && isIdentifier(arg.callee.property)) {
375
+ operatorName = arg.callee.property.name;
376
+ } else {
377
+ isOrderValid = false;
378
+ continue;
379
+ }
380
+ if (operatorsRegExp.test(operatorName)) {
381
+ operatorNode = arg.callee;
382
+ break;
383
+ }
384
+ if (!allow.includes(operatorName)) {
385
+ isOrderValid = false;
386
+ continue;
387
+ }
388
+ }
389
+ return { isOrderValid, operatorNode };
390
+ }
391
+
392
+ // src/utils/rule-creator.ts
393
+
394
+ var REPO_URL = "https://github.com/JasonWeinzierl/eslint-plugin-rxjs-x";
395
+ var ruleCreator = _utils.ESLintUtils.RuleCreator(
396
+ (name2) => `${REPO_URL}/blob/v${version}/docs/rules/${name2}.md`
397
+ );
398
+
399
+ // src/rules/ban-observables.ts
400
+ var defaultOptions = [];
401
+ var banObservablesRule = ruleCreator({
402
+ defaultOptions,
403
+ meta: {
404
+ docs: {
405
+ description: "Disallow banned observable creators."
406
+ },
407
+ messages: {
408
+ forbidden: "RxJS observable is banned: {{name}}{{explanation}}."
409
+ },
410
+ schema: [
411
+ {
412
+ type: "object",
413
+ description: _commontags.stripIndent`
414
+ An object containing keys that are names of observable factory functions
415
+ and values that are either booleans or strings containing the explanation for the ban.`
416
+ }
417
+ ],
418
+ type: "problem"
419
+ },
420
+ name: "ban-observables",
421
+ create: (context) => {
422
+ const bans = [];
423
+ const [config] = context.options;
424
+ if (!config) {
425
+ return {};
426
+ }
427
+ Object.entries(config).forEach(([key, value]) => {
428
+ if (value !== false) {
429
+ bans.push({
430
+ explanation: typeof value === "string" ? value : "",
431
+ regExp: new RegExp(`^${key}$`)
432
+ });
433
+ }
434
+ });
435
+ function getFailure(name2) {
436
+ for (let b = 0, length = bans.length; b < length; ++b) {
437
+ const ban = bans[b];
438
+ if (ban.regExp.test(name2)) {
439
+ const explanation = ban.explanation ? `: ${ban.explanation}` : "";
440
+ return {
441
+ messageId: "forbidden",
442
+ data: { name: name2, explanation }
443
+ };
444
+ }
445
+ }
446
+ return void 0;
447
+ }
448
+ return {
449
+ "ImportDeclaration[source.value='rxjs'] > ImportSpecifier": (node) => {
450
+ const identifier = node.imported;
451
+ const name2 = identifier.type === _utils.AST_NODE_TYPES.Identifier ? identifier.name : identifier.value;
452
+ const failure = getFailure(name2);
453
+ if (failure) {
454
+ context.report({
455
+ ...failure,
456
+ node: identifier
457
+ });
458
+ }
459
+ }
460
+ };
461
+ }
462
+ });
463
+
421
464
  // src/rules/ban-operators.ts
465
+
422
466
  var defaultOptions2 = [];
423
467
  var banOperatorsRule = ruleCreator({
424
468
  defaultOptions: defaultOptions2,
@@ -987,6 +1031,29 @@ var noCreateRule = ruleCreator({
987
1031
 
988
1032
  // src/constants.ts
989
1033
  var defaultObservable = String.raw`[Aa]ction(s|s\$|\$)$`;
1034
+ var DEFAULT_VALID_POST_COMPLETION_OPERATORS = [
1035
+ "count",
1036
+ "defaultIfEmpty",
1037
+ "endWith",
1038
+ "every",
1039
+ "finalize",
1040
+ "finally",
1041
+ "isEmpty",
1042
+ "last",
1043
+ "max",
1044
+ "min",
1045
+ "publish",
1046
+ "publishBehavior",
1047
+ "publishLast",
1048
+ "publishReplay",
1049
+ "reduce",
1050
+ "share",
1051
+ "shareReplay",
1052
+ "skipLast",
1053
+ "takeLast",
1054
+ "throwIfEmpty",
1055
+ "toArray"
1056
+ ];
990
1057
 
991
1058
  // src/rules/no-cyclic-action.ts
992
1059
  function isTypeReference2(type) {
@@ -1757,8 +1824,10 @@ var noIgnoredSubscribeRule = ruleCreator({
1757
1824
  });
1758
1825
 
1759
1826
  // src/rules/no-ignored-subscription.ts
1827
+
1828
+ var defaultOptions7 = [];
1760
1829
  var noIgnoredSubscriptionRule = ruleCreator({
1761
- defaultOptions: [],
1830
+ defaultOptions: defaultOptions7,
1762
1831
  meta: {
1763
1832
  docs: {
1764
1833
  description: "Disallow ignoring the subscription returned by `subscribe`.",
@@ -1767,12 +1836,44 @@ var noIgnoredSubscriptionRule = ruleCreator({
1767
1836
  messages: {
1768
1837
  forbidden: "Ignoring returned subscriptions is forbidden."
1769
1838
  },
1770
- schema: [],
1839
+ schema: [
1840
+ {
1841
+ properties: {
1842
+ 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"] },
1843
+ 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 }
1844
+ },
1845
+ type: "object",
1846
+ description: _commontags.stripIndent`
1847
+ An object with optional \`completers\` and \`postCompleters\` properties.
1848
+ The \`completers\` property is an array containing the names of operators that will complete the observable and silence this rule.
1849
+ The \`postCompleters\` property is an array containing the names of the operators that are allowed to follow the completion operators.
1850
+ `
1851
+ }
1852
+ ],
1771
1853
  type: "problem"
1772
1854
  },
1773
1855
  name: "no-ignored-subscription",
1774
1856
  create: (context) => {
1857
+ const [config = {}] = context.options;
1858
+ const {
1859
+ completers = ["takeUntil", "takeWhile", "take", "first", "last", "takeUntilDestroyed"],
1860
+ postCompleters = DEFAULT_VALID_POST_COMPLETION_OPERATORS
1861
+ } = config;
1862
+ const checkedOperatorsRegExp = new RegExp(
1863
+ `^(${completers.join("|")})$`
1864
+ );
1775
1865
  const { couldBeObservable, couldBeType: couldBeType2 } = getTypeServices(context);
1866
+ function hasAllowedOperator(node) {
1867
+ if (isCallExpression(node) && isMemberExpression(node.callee) && isIdentifier(node.callee.property) && node.callee.property.name === "pipe") {
1868
+ const { isOrderValid, operatorNode } = findIsLastOperatorOrderValid(
1869
+ node,
1870
+ checkedOperatorsRegExp,
1871
+ postCompleters
1872
+ );
1873
+ return isOrderValid && !!operatorNode;
1874
+ }
1875
+ return false;
1876
+ }
1776
1877
  return {
1777
1878
  "ExpressionStatement > CallExpression > MemberExpression[property.name='subscribe']": (node) => {
1778
1879
  if (couldBeObservable(node.object)) {
@@ -1780,6 +1881,9 @@ var noIgnoredSubscriptionRule = ruleCreator({
1780
1881
  if (callExpression.arguments.length === 1 && couldBeType2(callExpression.arguments[0], "Subscriber")) {
1781
1882
  return;
1782
1883
  }
1884
+ if (hasAllowedOperator(node.object)) {
1885
+ return;
1886
+ }
1783
1887
  context.report({
1784
1888
  messageId: "forbidden",
1785
1889
  node: node.property
@@ -1854,9 +1958,9 @@ function isParenthesised(sourceCode, node) {
1854
1958
  const after = sourceCode.getTokenAfter(node);
1855
1959
  return before && after && before.value === "(" && before.range[1] <= node.range[0] && after.value === ")" && after.range[0] >= node.range[1];
1856
1960
  }
1857
- var defaultOptions7 = [];
1961
+ var defaultOptions8 = [];
1858
1962
  var noImplicitAnyCatchRule = ruleCreator({
1859
- defaultOptions: defaultOptions7,
1963
+ defaultOptions: defaultOptions8,
1860
1964
  meta: {
1861
1965
  docs: {
1862
1966
  description: "Disallow implicit `any` error parameters in `catchError` operators.",
@@ -2130,9 +2234,9 @@ function parseChecksVoidReturn(checksVoidReturn) {
2130
2234
  };
2131
2235
  }
2132
2236
  }
2133
- var defaultOptions8 = [];
2237
+ var defaultOptions9 = [];
2134
2238
  var noMisusedObservablesRule = ruleCreator({
2135
- defaultOptions: defaultOptions8,
2239
+ defaultOptions: defaultOptions9,
2136
2240
  meta: {
2137
2241
  docs: {
2138
2242
  description: "Disallow Observables in places not designed to handle them.",
@@ -2620,9 +2724,9 @@ function isExpressionObserver(expressionStatement, couldBeType2) {
2620
2724
 
2621
2725
  // src/rules/no-sharereplay.ts
2622
2726
 
2623
- var defaultOptions9 = [];
2727
+ var defaultOptions10 = [];
2624
2728
  var noSharereplayRule = ruleCreator({
2625
- defaultOptions: defaultOptions9,
2729
+ defaultOptions: defaultOptions10,
2626
2730
  meta: {
2627
2731
  docs: {
2628
2732
  description: "Disallow unsafe `shareReplay` usage.",
@@ -3062,9 +3166,9 @@ var noUnboundMethodsRule = ruleCreator({
3062
3166
 
3063
3167
  // src/rules/no-unsafe-catch.ts
3064
3168
 
3065
- var defaultOptions10 = [];
3169
+ var defaultOptions11 = [];
3066
3170
  var noUnsafeCatchRule = ruleCreator({
3067
- defaultOptions: defaultOptions10,
3171
+ defaultOptions: defaultOptions11,
3068
3172
  meta: {
3069
3173
  docs: {
3070
3174
  description: "Disallow unsafe `catchError` usage in effects and epics.",
@@ -3123,9 +3227,9 @@ var noUnsafeCatchRule = ruleCreator({
3123
3227
 
3124
3228
  // src/rules/no-unsafe-first.ts
3125
3229
 
3126
- var defaultOptions11 = [];
3230
+ var defaultOptions12 = [];
3127
3231
  var noUnsafeFirstRule = ruleCreator({
3128
- defaultOptions: defaultOptions11,
3232
+ defaultOptions: defaultOptions12,
3129
3233
  meta: {
3130
3234
  docs: {
3131
3235
  description: "Disallow unsafe `first`/`take` usage in effects and epics.",
@@ -3247,9 +3351,9 @@ var noUnsafeSubjectNext = ruleCreator({
3247
3351
  // src/rules/no-unsafe-switchmap.ts
3248
3352
 
3249
3353
  var _decamelize = require('decamelize'); var _decamelize2 = _interopRequireDefault(_decamelize);
3250
- var defaultOptions12 = [];
3354
+ var defaultOptions13 = [];
3251
3355
  var noUnsafeSwitchmapRule = ruleCreator({
3252
- defaultOptions: defaultOptions12,
3356
+ defaultOptions: defaultOptions13,
3253
3357
  meta: {
3254
3358
  docs: {
3255
3359
  description: "Disallow unsafe `switchMap` usage in effects and epics.",
@@ -3372,32 +3476,9 @@ var noUnsafeSwitchmapRule = ruleCreator({
3372
3476
 
3373
3477
  // src/rules/no-unsafe-takeuntil.ts
3374
3478
 
3375
- var defaultOptions13 = [];
3376
- var allowedOperators = [
3377
- "count",
3378
- "defaultIfEmpty",
3379
- "endWith",
3380
- "every",
3381
- "finalize",
3382
- "finally",
3383
- "isEmpty",
3384
- "last",
3385
- "max",
3386
- "min",
3387
- "publish",
3388
- "publishBehavior",
3389
- "publishLast",
3390
- "publishReplay",
3391
- "reduce",
3392
- "share",
3393
- "shareReplay",
3394
- "skipLast",
3395
- "takeLast",
3396
- "throwIfEmpty",
3397
- "toArray"
3398
- ];
3479
+ var defaultOptions14 = [];
3399
3480
  var noUnsafeTakeuntilRule = ruleCreator({
3400
- defaultOptions: defaultOptions13,
3481
+ defaultOptions: defaultOptions14,
3401
3482
  meta: {
3402
3483
  docs: {
3403
3484
  description: "Disallow applying operators after `takeUntil`.",
@@ -3411,7 +3492,7 @@ var noUnsafeTakeuntilRule = ruleCreator({
3411
3492
  {
3412
3493
  properties: {
3413
3494
  alias: { type: "array", items: { type: "string" }, description: "An array of operator names that should be treated similarly to `takeUntil`." },
3414
- allow: { type: "array", items: { type: "string" }, description: "An array of operator names that are allowed to follow `takeUntil`.", default: allowedOperators }
3495
+ allow: { type: "array", items: { type: "string" }, description: "An array of operator names that are allowed to follow `takeUntil`.", default: DEFAULT_VALID_POST_COMPLETION_OPERATORS }
3415
3496
  },
3416
3497
  type: "object",
3417
3498
  description: _commontags.stripIndent`
@@ -3426,7 +3507,7 @@ var noUnsafeTakeuntilRule = ruleCreator({
3426
3507
  create: (context) => {
3427
3508
  let checkedOperatorsRegExp = /^takeUntil$/;
3428
3509
  const [config = {}] = context.options;
3429
- const { alias, allow = allowedOperators } = config;
3510
+ const { alias, allow = DEFAULT_VALID_POST_COMPLETION_OPERATORS } = config;
3430
3511
  if (alias) {
3431
3512
  checkedOperatorsRegExp = new RegExp(
3432
3513
  `^(${alias.concat("takeUntil").join("|")})$`
@@ -3438,35 +3519,17 @@ var noUnsafeTakeuntilRule = ruleCreator({
3438
3519
  if (!pipeCallExpression.arguments || !couldBeObservable(pipeCallExpression)) {
3439
3520
  return;
3440
3521
  }
3441
- pipeCallExpression.arguments.reduceRight((state, arg) => {
3442
- if (state === "taken") {
3443
- return state;
3444
- }
3445
- if (!isCallExpression(arg)) {
3446
- return "disallowed";
3447
- }
3448
- let operatorName;
3449
- if (isIdentifier(arg.callee)) {
3450
- operatorName = arg.callee.name;
3451
- } else if (isMemberExpression(arg.callee) && isIdentifier(arg.callee.property)) {
3452
- operatorName = arg.callee.property.name;
3453
- } else {
3454
- return "disallowed";
3455
- }
3456
- if (checkedOperatorsRegExp.test(operatorName)) {
3457
- if (state === "disallowed") {
3458
- context.report({
3459
- messageId: "forbidden",
3460
- node: arg.callee
3461
- });
3462
- }
3463
- return "taken";
3464
- }
3465
- if (!allow.includes(operatorName)) {
3466
- return "disallowed";
3467
- }
3468
- return state;
3469
- }, "allowed");
3522
+ const { isOrderValid, operatorNode } = findIsLastOperatorOrderValid(
3523
+ pipeCallExpression,
3524
+ checkedOperatorsRegExp,
3525
+ allow
3526
+ );
3527
+ if (!isOrderValid && operatorNode) {
3528
+ context.report({
3529
+ messageId: "forbidden",
3530
+ node: operatorNode
3531
+ });
3532
+ }
3470
3533
  }
3471
3534
  return {
3472
3535
  [`CallExpression[callee.property.name='pipe'] > CallExpression[callee.name=${checkedOperatorsRegExp}]`]: checkNode,
@@ -3476,9 +3539,9 @@ var noUnsafeTakeuntilRule = ruleCreator({
3476
3539
  });
3477
3540
 
3478
3541
  // src/rules/prefer-observer.ts
3479
- var defaultOptions14 = [];
3542
+ var defaultOptions15 = [];
3480
3543
  var preferObserverRule = ruleCreator({
3481
- defaultOptions: defaultOptions14,
3544
+ defaultOptions: defaultOptions15,
3482
3545
  meta: {
3483
3546
  docs: {
3484
3547
  description: "Disallow passing separate handlers to `subscribe` and `tap`.",
@@ -3714,9 +3777,9 @@ var preferRootOperatorsRule = ruleCreator({
3714
3777
 
3715
3778
  // src/rules/suffix-subjects.ts
3716
3779
 
3717
- var defaultOptions15 = [];
3780
+ var defaultOptions16 = [];
3718
3781
  var suffixSubjectsRule = ruleCreator({
3719
- defaultOptions: defaultOptions15,
3782
+ defaultOptions: defaultOptions16,
3720
3783
  meta: {
3721
3784
  docs: {
3722
3785
  description: "Enforce the use of a suffix in subject identifiers.",
@@ -3913,9 +3976,9 @@ var suffixSubjectsRule = ruleCreator({
3913
3976
  // src/rules/throw-error.ts
3914
3977
 
3915
3978
 
3916
- var defaultOptions16 = [];
3979
+ var defaultOptions17 = [];
3917
3980
  var throwErrorRule = ruleCreator({
3918
- defaultOptions: defaultOptions16,
3981
+ defaultOptions: defaultOptions17,
3919
3982
  meta: {
3920
3983
  docs: {
3921
3984
  description: "Enforce passing only `Error` values to `throwError`.",