diff --git a/docs/rules/no-ignored-replay-buffer.md b/docs/rules/no-ignored-replay-buffer.md index 6dd92333..327d8eab 100644 --- a/docs/rules/no-ignored-replay-buffer.md +++ b/docs/rules/no-ignored-replay-buffer.md @@ -15,6 +15,11 @@ import { ReplaySubject } from "rxjs"; const subject = new ReplaySubject(); ``` +```ts +import { of, shareReplay } from "rxjs"; +of(42).pipe(shareReplay({ refCount: true })); +``` + Examples of **correct** code for this rule: ```ts @@ -26,3 +31,8 @@ const subject = new ReplaySubject(1); import { ReplaySubject } from "rxjs"; const subject = new ReplaySubject(Infinity); ``` + +```ts +import { of, shareReplay } from "rxjs"; +of(42).pipe(shareReplay({ refCount: true, bufferSize: 1 })); +``` diff --git a/src/rules/no-ignored-replay-buffer.ts b/src/rules/no-ignored-replay-buffer.ts index f3d07aed..2ee4cc31 100644 --- a/src/rules/no-ignored-replay-buffer.ts +++ b/src/rules/no-ignored-replay-buffer.ts @@ -1,4 +1,4 @@ -import { TSESTree as es } from '@typescript-eslint/utils'; +import { AST_NODE_TYPES, TSESTree as es } from '@typescript-eslint/utils'; import { ruleCreator } from '../utils'; export const noIgnoredReplayBufferRule = ruleCreator({ @@ -17,9 +17,21 @@ export const noIgnoredReplayBufferRule = ruleCreator({ }, name: 'no-ignored-replay-buffer', create: (context) => { + function checkShareReplayConfig( + node: es.Identifier, + shareReplayConfigArg: es.ObjectExpression, + ) { + if (!shareReplayConfigArg.properties.some(p => p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier && p.key.name === 'bufferSize')) { + context.report({ + messageId: 'forbidden', + node, + }); + } + } + function checkNode( - node: es.Node, - { arguments: args }: { arguments: es.Node[] }, + node: es.Identifier, + { arguments: args }: es.NewExpression | es.CallExpression, ) { if (!args || args.length === 0) { context.report({ @@ -27,6 +39,13 @@ export const noIgnoredReplayBufferRule = ruleCreator({ node, }); } + + if (node.name === 'shareReplay' && args?.length === 1) { + const arg = args[0]; + if (arg.type === AST_NODE_TYPES.ObjectExpression) { + checkShareReplayConfig(node, arg); + } + } } return { @@ -49,6 +68,13 @@ export const noIgnoredReplayBufferRule = ruleCreator({ const callExpression = node.parent as es.CallExpression; checkNode(node, callExpression); }, + 'CallExpression > MemberExpression > Identifier[name=/^(publishReplay|shareReplay)$/]': ( + node: es.Identifier, + ) => { + const memberExpression = node.parent as es.MemberExpression; + const callExpression = memberExpression.parent as es.CallExpression; + checkNode(node, callExpression); + }, }; }, }); diff --git a/tests/rules/no-ignored-replay-buffer.test.ts b/tests/rules/no-ignored-replay-buffer.test.ts index b5fe53a7..c57d5377 100644 --- a/tests/rules/no-ignored-replay-buffer.test.ts +++ b/tests/rules/no-ignored-replay-buffer.test.ts @@ -26,6 +26,13 @@ ruleTester({ types: false }).run('no-ignored-replay-buffer', noIgnoredReplayBuff const a = of(42).pipe(shareReplay(1)); `, + fromFixture( + stripIndent` + // shareReplay with config not ignored + import { interval, shareReplay } from "rxjs"; + interval(1000).pipe(shareReplay({ bufferSize: 1, refCount: true })); + `, + ), stripIndent` // namespace ReplaySubject not ignored import * as Rx from "rxjs"; @@ -47,6 +54,13 @@ ruleTester({ types: false }).run('no-ignored-replay-buffer', noIgnoredReplayBuff const a = Rx.of(42).pipe(shareReplay(1)); `, + stripIndent` + // namespace shareReplay with config not ignored + import * as Rx from "rxjs"; + import { shareReplay } from "rxjs/operators"; + + const a = Rx.of(42).pipe(shareReplay({ bufferSize: 1, refCount: true })); + `, stripIndent` // namespace class not ignored import * as Rx from "rxjs"; @@ -91,6 +105,15 @@ ruleTester({ types: false }).run('no-ignored-replay-buffer', noIgnoredReplayBuff ~~~~~~~~~~~ [forbidden] `, ), + fromFixture( + stripIndent` + // shareReplay with config ignored + import { of, shareReplay } from "rxjs"; + + const a = of(42).pipe(shareReplay({ refCount: true })); + ~~~~~~~~~~~ [forbidden] + `, + ), fromFixture( stripIndent` // namespace ReplaySubject ignored @@ -122,6 +145,14 @@ ruleTester({ types: false }).run('no-ignored-replay-buffer', noIgnoredReplayBuff ~~~~~~~~~~~ [forbidden] `, ), + fromFixture( + stripIndent` + // namespace shareReplay with config ignored + import * as Rx from "rxjs"; + const a = Rx.of(42).pipe(Rx.shareReplay({ refCount: true })); + ~~~~~~~~~~~ [forbidden] + `, + ), fromFixture( stripIndent` // namespace class ignored