diff --git a/src/select.ts b/src/select.ts new file mode 100644 index 0000000..3bedf47 --- /dev/null +++ b/src/select.ts @@ -0,0 +1,12 @@ +import { Source } from './source' +import { SourceLike } from './types' + + +export function select(source: SourceLike) { + return new Source(emit => { + const listener = (val: T) => emit(val) + source.get(listener) + + return () => source.remove(listener) + }) +} diff --git a/src/state.ts b/src/state.ts new file mode 100644 index 0000000..2736d44 --- /dev/null +++ b/src/state.ts @@ -0,0 +1,9 @@ +import { Subject } from './subject' + + +export class State extends Subject { + constructor(initial: T) { + super() + this.set(initial) + } +} diff --git a/src/test/select.test.ts b/src/test/select.test.ts new file mode 100644 index 0000000..eccd069 --- /dev/null +++ b/src/test/select.test.ts @@ -0,0 +1,88 @@ +import { State } from '../state' +import { observe } from '../observe' +import { select } from '../select' + + +describe(select, () => { + test('proxies a source.', () => { + const src = new State(0) + const selected = select(src) + + const cb = jest.fn() + + observe($ => cb($(selected)!)) + + src.set(1) + expect(cb).toHaveBeenCalledWith(1) + + src.set(2) + expect(cb).toHaveBeenCalledWith(2) + }) + + test('without select, higher order sources are stopped after switch.', () => { + const flag = new State(false) + const a = new State('a') + const b = new State('b') + + const cb = jest.fn() + const switched = $ => $(flag) ? a : b + + observe($ => cb($($(switched)!))) + + expect(a.stopped).toBe(false) + expect(b.stopped).toBe(false) + + flag.set(true) + + expect(a.stopped).toBe(false) + expect(b.stopped).toBe(true) + + flag.set(false) + + expect(a.stopped).toBe(true) + expect(b.stopped).toBe(true) + }) + + test('with select, higher order sources are not stopped after switch.', () => { + const flag = new State(false) + const a = new State('a') + const b = new State('b') + + const cb = jest.fn() + const switched = $ => $(flag) ? select(a) : select(b) + + observe($ => cb($($(switched)!))) + + expect(a.stopped).toBe(false) + expect(b.stopped).toBe(false) + + flag.set(true) + + expect(a.stopped).toBe(false) + expect(b.stopped).toBe(false) + + flag.set(false) + + expect(a.stopped).toBe(false) + expect(b.stopped).toBe(false) + }) + + test('removes its subscription when stopped.', () => { + const get = jest.fn() + const remove = jest.fn() + const stop = jest.fn() + const src = select({ + get, + remove, + stop, + stops: jest.fn(), + stopped: false + }) + + expect(get).toHaveBeenCalled() + + src.stop() + expect(remove).toHaveBeenCalled() + expect(stop).not.toHaveBeenCalled() + }) +})