Skip to content

Commit d0b9191

Browse files
committed
publish. need to refactor .spec.ts files
0 parents  commit d0b9191

13 files changed

+999
-0
lines changed

.gitignore

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Editor-specific
2+
.idea/
3+
*.iml
4+
*.sublime-project
5+
*.sublime-workspace
6+
.settings
7+
.vscode
8+
9+
# Installed libs
10+
node_modules/
11+
12+
# Generated
13+
dist/

.prettierrc

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"trailingComma": "es5",
3+
"tabWidth": 4,
4+
"semi": false,
5+
"singleQuote": true,
6+
"printWidth": 140
7+
}

package.json

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "custom-rxjs-operators",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "cross-env TS_NODE_PROJECT=spec/tsconfig.json mocha --opts spec/default.opts \"src/operators/*.spec.ts\""
8+
},
9+
"author": "",
10+
"license": "ISC",
11+
"dependencies": {
12+
"@types/chai": "^4.2.3",
13+
"@types/mocha": "^5.2.7",
14+
"chai": "^4.2.0",
15+
"cross-env": "^6.0.0",
16+
"mocha": "^6.2.1",
17+
"rxjs": "^6.5.3",
18+
"ts-node": "^8.4.1",
19+
"tsconfig-paths": "^3.9.0",
20+
"typescript": "^3.6.3"
21+
}
22+
}

spec/default.opts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
--require ts-node/register
2+
--require tsconfig-paths/register
3+
4+
--reporter dot
5+
6+
--check-leaks
7+
8+
--recursive
9+
--timeout 5000

spec/tsconfig.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../tsconfig.json"
3+
}

src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as operators from './operators'
2+
3+
export { operators }
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import { expect } from 'chai'
2+
import { TestScheduler } from 'rxjs/testing'
3+
import { delayAndTakeLast, wrappedWithDelay } from './delay-and-take-last'
4+
5+
describe('delay-and-take-last', () => {
6+
it('should not undelayed event', () => {
7+
const testScheduler = new TestScheduler((actual, expected) => {
8+
expect(actual).deep.equal(expected)
9+
})
10+
11+
testScheduler.run(helpers => {
12+
const { cold, expectObservable, expectSubscriptions } = helpers
13+
14+
const e1 = cold<wrappedWithDelay<string>>('-a--b--c---|', { a: { event: 'a' }, b: { event: 'b', delay: 0 }, c: { event: 'c' } })
15+
const subs = '^----------!'
16+
const expected = '-a--b--c---|'
17+
18+
expectObservable(e1.pipe(delayAndTakeLast())).toBe(expected)
19+
expectSubscriptions(e1.subscriptions).toBe(subs)
20+
})
21+
})
22+
23+
it('should throw delayed event', () => {
24+
const testScheduler = new TestScheduler((actual, expected) => {
25+
expect(actual).deep.equal(expected)
26+
})
27+
28+
testScheduler.run(helpers => {
29+
const { cold, expectObservable, expectSubscriptions } = helpers
30+
31+
const e1 = cold<{
32+
event: string
33+
delay?: number
34+
}>('-a--b--c---|', { a: { event: 'a' }, b: { event: 'b', delay: 10 }, c: { event: 'c' } })
35+
const subs = '^----------!'
36+
const expected = '-a-----c---|'
37+
38+
expectObservable(e1.pipe(delayAndTakeLast())).toBe(expected)
39+
expectSubscriptions(e1.subscriptions).toBe(subs)
40+
})
41+
})
42+
43+
it('should emit delayed event', () => {
44+
const testScheduler = new TestScheduler((actual, expected) => {
45+
expect(actual).deep.equal(expected)
46+
})
47+
48+
testScheduler.run(helpers => {
49+
const { cold, expectObservable, expectSubscriptions } = helpers
50+
51+
const e1 = cold<{
52+
event: string
53+
delay?: number
54+
}>('a---c|', { a: { event: 'a', delay: 2 }, c: { event: 'c' } })
55+
const subs = '^----!'
56+
const expected = '--a-c|'
57+
58+
expectObservable(e1.pipe(delayAndTakeLast())).toBe(expected)
59+
expectSubscriptions(e1.subscriptions).toBe(subs)
60+
})
61+
})
62+
})

src/operators/delay-and-take-last.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { Observable, of, Subscription } from 'rxjs'
2+
import { delay } from 'rxjs/operators'
3+
4+
// code based on https://rxjs-dev.firebaseapp.com/guide/v6/pipeable-operators
5+
6+
export const delayAndTakeLast = () => <T>(source: Observable<wrappedWithDelay<T>>) =>
7+
new Observable<T>(observer => {
8+
let nextIndex = 0
9+
let prevFiredIndex = -1
10+
let delayedEvents: { index: number; event: T; subscription: Subscription }[] = []
11+
12+
function onDestroy() {
13+
clearDelayedEvents()
14+
}
15+
16+
function dispatch(value: T, index: number) {
17+
clearDelayedEvents(index)
18+
observer.next(value)
19+
prevFiredIndex = index
20+
}
21+
22+
function clearDelayedEvents(toIndex = Number.MAX_SAFE_INTEGER) {
23+
delayedEvents = delayedEvents.filter(delayedEvent => {
24+
if (delayedEvent.index > toIndex) {
25+
return true
26+
} else {
27+
delayedEvent.subscription.unsubscribe()
28+
return false
29+
}
30+
})
31+
}
32+
33+
return source.subscribe({
34+
next(value) {
35+
const index = nextIndex++
36+
37+
if (value.delay) {
38+
const subscription = of(0)
39+
.pipe(delay(value.delay))
40+
.subscribe(() => {
41+
if (prevFiredIndex < index) {
42+
dispatch(value.event, index)
43+
}
44+
})
45+
46+
delayedEvents.push({
47+
event: value.event,
48+
index,
49+
subscription,
50+
})
51+
} else {
52+
dispatch(value.event, index)
53+
}
54+
},
55+
error(err) {
56+
onDestroy()
57+
observer.error(err)
58+
},
59+
complete() {
60+
onDestroy()
61+
observer.complete()
62+
},
63+
})
64+
})
65+
66+
export type wrappedWithDelay<T> = {
67+
event: T
68+
delay?: number
69+
}

src/operators/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './delay-and-take-last'
2+
export * from './unique-event-counter'
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { expect } from 'chai'
2+
import { TestScheduler } from 'rxjs/testing'
3+
import { uniqueEventCounter } from './unique-event-counter'
4+
5+
describe('unique-event-counter', () => {
6+
it('should register single clicks', () => {
7+
const testScheduler = new TestScheduler((actual, expected) => {
8+
expect(actual).deep.equal(expected)
9+
})
10+
11+
testScheduler.run(helpers => {
12+
const { cold, expectObservable, expectSubscriptions } = helpers
13+
14+
const e1 = cold<string>('-a--b--c-|')
15+
const subs = '^--------!'
16+
const expected = '-a--b--c-|'
17+
18+
expectObservable(e1.pipe(uniqueEventCounter(2, undefined, 1))).toBe(expected, {
19+
a: { value: 'a', times: 1 },
20+
b: { value: 'b', times: 1 },
21+
c: { value: 'c', times: 1 },
22+
})
23+
expectSubscriptions(e1.subscriptions).toBe(subs)
24+
})
25+
})
26+
27+
it('should register single and double clicks', () => {
28+
const testScheduler = new TestScheduler((actual, expected) => {
29+
expect(actual).deep.equal(expected)
30+
})
31+
32+
testScheduler.run(helpers => {
33+
const { cold, expectObservable, expectSubscriptions } = helpers
34+
35+
const e1 = cold<string>('-aa--b---c----|')
36+
const subs = '^-------------!'
37+
const expected = '--a-----b---c-|'
38+
39+
expectObservable(e1.pipe(uniqueEventCounter(3, undefined, 2))).toBe(expected, {
40+
a: { value: 'a', times: 2 },
41+
b: { value: 'b', times: 1 },
42+
c: { value: 'c', times: 1 },
43+
})
44+
expectSubscriptions(e1.subscriptions).toBe(subs)
45+
})
46+
})
47+
})

0 commit comments

Comments
 (0)