-
Notifications
You must be signed in to change notification settings - Fork 88
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(create-repeat): implement the function, docs and tests
- Loading branch information
lgarcia
committed
May 21, 2024
1 parent
5baf2fc
commit bebeee9
Showing
10 changed files
with
10,706 additions
and
8,865 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
{ | ||
"name": "Lucas Garcia" | ||
"name": "Lucas Garcia", | ||
"twitter": "https://x.com/LcsGa_", | ||
"github": "https://github.com/LcsGa" | ||
} |
62 changes: 62 additions & 0 deletions
62
docs/src/content/docs/utilities/Operators/create-repeat.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
title: createRepeat | ||
description: ngxtension/create-repeat | ||
entryPoint: create-repeat | ||
badge: stable | ||
contributors: ['lucas-garcia'] | ||
--- | ||
|
||
## Import | ||
|
||
```ts | ||
import { createRepeat } from 'ngxtension/create-repeat'; | ||
``` | ||
|
||
## Usage | ||
|
||
Create an RxJS `repeat` operator with an `emit` method on it, to notify when the source should be repeated. | ||
|
||
```ts | ||
@Component({ | ||
..., | ||
template: ` | ||
... | ||
<button (click)="repeat.emit()">Repeat</button> | ||
` | ||
}) | ||
export class SomeComponent { | ||
readonly repeat = createRepeat(); | ||
|
||
// Will log 'hello' directly, then each time the 'Repeat' button gets clicked | ||
readonly #sayHello = rxEffect(of('hello').pipe(this.repeat()), console.log); | ||
} | ||
``` | ||
|
||
## API | ||
|
||
### `createRepeat` overloads | ||
|
||
#### Overload 1 | ||
|
||
| arguments | type | description | | ||
| ------------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | ||
| `globalCount` | `number` | Optional. Default is `undefined`.<br>The number of times (applied globally) the source Observable items are repeated (a count of 0 will yield an empty Observable) | | ||
| `destroyRef` | `DestroyRef` | Optional. Default is `undefined`.<br>The `DestroyRef` to pass when `createRepeat` is used outside of an injection context. | | ||
|
||
#### Overload 2 | ||
|
||
| arguments | type | description | | ||
| ------------ | ------------ | -------------------------------------------------------------------------------------------------------------------------- | | ||
| `destroyRef` | `DestroyRef` | Optional. Default is `undefined`.<br>The `DestroyRef` to pass when `createRepeat` is used outside of an injection context. | | ||
|
||
### Returned `repeat` operator | ||
|
||
| arguments | type | description | | ||
| --------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | ||
| `count` | `number` | Optional. Default is `undefined`.<br>The number of times the source Observable items are repeated (a count of 0 will yield an empty Observable) | | ||
|
||
## See also | ||
|
||
- [`rxEffect`](https://ngxtension.netlify.app/utilities/operators/rx-effect) | ||
- RxJS [`repeat`](https://rxjs.dev/api/index/function/repeat) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# ngxtension/create-repeat | ||
|
||
Secondary entry point of `ngxtension`. It can be used by importing from `ngxtension/create-repeat`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"lib": { | ||
"entryFile": "src/index.ts" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "ngxtension/create-repeat", | ||
"$schema": "../../../node_modules/nx/schemas/project-schema.json", | ||
"projectType": "library", | ||
"sourceRoot": "libs/ngxtension/create-repeat/src", | ||
"targets": { | ||
"test": { | ||
"executor": "@nx/jest:jest", | ||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"], | ||
"options": { | ||
"jestConfig": "libs/ngxtension/jest.config.ts", | ||
"testPathPattern": ["create-repeat"], | ||
"passWithNoTests": true | ||
}, | ||
"configurations": { | ||
"ci": { | ||
"ci": true, | ||
"codeCoverage": true | ||
} | ||
} | ||
}, | ||
"lint": { | ||
"executor": "@nx/eslint:lint", | ||
"outputs": ["{options.outputFile}"] | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { TestBed } from '@angular/core/testing'; | ||
import { of } from 'rxjs'; | ||
import { createRepeat } from './create-repeat'; | ||
|
||
type Tests = { | ||
expectation: string; | ||
input: { | ||
globalCount?: number; | ||
emitCount: number; | ||
count?: number; | ||
}; | ||
expected: number[]; | ||
}[]; | ||
|
||
describe('createRepeat', () => { | ||
const sourceValue = 123; | ||
|
||
const tests: Tests = [ | ||
{ | ||
expectation: 'should repeat the source stream once after repeat emits', | ||
input: { emitCount: 1 }, | ||
expected: [sourceValue, sourceValue], | ||
}, | ||
{ | ||
expectation: | ||
'should emit the source stream value only once with the global count set to 1', | ||
input: { globalCount: 1, emitCount: 2 }, | ||
expected: [sourceValue], | ||
}, | ||
{ | ||
expectation: | ||
'should emit the source stream value twice with the global count set to 2', | ||
input: { globalCount: 2, emitCount: 2 }, | ||
expected: [sourceValue, sourceValue], | ||
}, | ||
{ | ||
expectation: | ||
'should emit the source stream value twice with the count set to 2', | ||
input: { count: 2, emitCount: 2 }, | ||
expected: [sourceValue, sourceValue], | ||
}, | ||
{ | ||
expectation: | ||
'should emit the source stream value twice with the count set to 2, even if the global count is set to 1', | ||
input: { globalCount: 1, count: 2, emitCount: 2 }, | ||
expected: [sourceValue, sourceValue], | ||
}, | ||
]; | ||
|
||
tests.forEach( | ||
({ expectation, input: { globalCount, count, emitCount }, expected }) => | ||
it(expectation, () => | ||
TestBed.runInInjectionContext(() => { | ||
const repeat = createRepeat(globalCount); | ||
const notifs: number[] = []; | ||
|
||
of(sourceValue) | ||
.pipe(repeat(count)) | ||
.subscribe((n) => notifs.push(n)); | ||
|
||
for (let i = 0; i < emitCount; i++) repeat.emit(); | ||
|
||
expect(notifs).toEqual(expected); | ||
}), | ||
), | ||
); | ||
|
||
it('should throw an error when it is invoked outside an injection context', () => | ||
expect(createRepeat).toThrow()); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
import { assertInInjectionContext, DestroyRef, inject } from '@angular/core'; | ||
import { repeat, Subject, type MonoTypeOperatorFunction } from 'rxjs'; | ||
|
||
type CreateRepeat = (<T>(count?: number) => MonoTypeOperatorFunction<T>) & { | ||
emit: () => void; | ||
}; | ||
|
||
export function createRepeat(destroyRef?: DestroyRef): CreateRepeat; | ||
export function createRepeat( | ||
generalCount?: number, | ||
destroyRef?: DestroyRef, | ||
): CreateRepeat; | ||
export function createRepeat( | ||
generalCountOrDestroyRef?: number | DestroyRef, | ||
destroyRef?: DestroyRef, | ||
) { | ||
const [generalCount, _destroyRef] = parseArgs( | ||
generalCountOrDestroyRef, | ||
destroyRef, | ||
); | ||
|
||
const repeat$ = new Subject<void>(); | ||
|
||
_destroyRef.onDestroy(() => repeat$.complete()); | ||
|
||
const repeatFn = <T>(count?: number) => | ||
repeat<T>({ count: count ?? generalCount, delay: () => repeat$ }); | ||
|
||
repeatFn.emit = () => repeat$.next(); | ||
|
||
return repeatFn; | ||
} | ||
|
||
function parseArgs( | ||
generalCountOrDestroyRef?: number | DestroyRef, | ||
destroyRef?: DestroyRef, | ||
) { | ||
const isGeneralCount = typeof generalCountOrDestroyRef === 'number'; | ||
|
||
const generalCount = isGeneralCount ? generalCountOrDestroyRef : undefined; | ||
|
||
destroyRef ??= !isGeneralCount ? generalCountOrDestroyRef : undefined; | ||
|
||
if (!destroyRef) assertInInjectionContext(createRepeat); | ||
destroyRef ??= inject(DestroyRef); | ||
|
||
return [generalCount, destroyRef] as const; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './create-repeat'; |
Oops, something went wrong.