import { checkFunction, checkObservable } from "../_check" import { sendNextInTx, Source } from "../_core" import { Accum } from "../_interfaces" import { makeProperty } from "../_obs" import { Transaction } from "../_tx" import { curry3 } from "../_util" import { dispatcherOf, Observable } from "../Observable" import { Property } from "../Property" import { Operator } from "./_base" /** * Scans `EventStream` or `Property` with given seed value and accumulator * function, resulting to a `Property`. The seed value is used as an initial * value for the result property. * * @param seed Seed value to use for the accumulation * @param acc Accumulator function `(state, value) => state` * @param observable Source observable * * @example * * F.pipe(F.fromArray(["!", "!"]), * F.scan("Hello Francis", (state, value) => state + value), * F.log("Greeting:")) * // logs: "Hello Francis", "Hello Francis!", "Hello Francis!!", * * @stateful * @public */ export const scan: CurriedScan = curry3(_scan) export interface CurriedScan { ( seed: StateType, acc: Accum, observable: Observable, ): Property (seed: StateType): ( acc: Accum, observable: Observable, ) => Property (seed: StateType, acc: Accum): ( observable: Observable, ) => Property (seed: StateType): ( acc: Accum, ) => (observable: Observable) => Property } function _scan(seed: S, acc: Accum, observable: Observable): Property { checkObservable(observable) checkFunction(acc) return makeProperty(new Scan(dispatcherOf(observable), acc, seed)) } class Scan extends Operator { private has: boolean = false constructor(source: Source, private readonly acc: Accum, private state: S) { super(source) } public activate(initialNeeded: boolean): void { super.activate(initialNeeded && !this.has) this.sendInitial() } public next(tx: Transaction, val: T): void { const { acc, state } = this this.has = true this.sink.next(tx, (this.state = acc(state, val))) } private sendInitial(): void { const shouldSent = this.active && !this.has this.has = true if (shouldSent) { sendNextInTx(this.sink, this.state) } } }