import { EventStream, EventStreamSeed, Observer, Property, PropertySeed, Event, isValue, valueEvent, AtomSeed, Subscribe, isProperty, isEventStream, isEventStreamSeed, isPropertySeed, Desc, } from "./abstractions" import { cachedFn } from "./cachedFn" import { StatelessEventStream } from "./eventstream" import { EventStreamSeedImpl } from "./eventstream" import { PropertySeedImpl } from "./property" import { StatelessProperty } from "./property" import { In } from "./transform" export type MapResult = O extends Property ? Property : O extends PropertySeed ? PropertySeed : O extends EventStream ? EventStream : EventStreamSeed export interface MapOp { (o: In): MapResult } export function map(fn: (value: A) => B): MapOp export function map(sampledProperty: Property): MapOp export function map(x: ((value: A) => B) | Property): any { return (o: any) => { const desc = [o, "map", [x]] as Desc let fn = isProperty(x) ? () => x.get() : x if (isEventStream(o)) { return new StatelessEventStream( desc, mapSubscribe(o.subscribe.bind(o), fn), o.getScope() ) } else if (isEventStreamSeed(o)) { const source = o.consume() return new EventStreamSeedImpl( desc, mapSubscribe(source.subscribe.bind(source), fn) ) } else if (isProperty(o)) { fn = cachedFn(fn) return new StatelessProperty( desc, () => fn(o.get()), mapSubscribe(o.onChange.bind(o), fn), o.getScope() ) } else if (isPropertySeed(o)) { const source = o.consume() fn = cachedFn(fn) return new PropertySeedImpl( desc, () => fn(source.get()), mapSubscribe(source.onChange.bind(source), fn) ) } throw Error("Unknown observable") } } export function mapSubscribe( subscribe: Subscribe, fn: (value: A) => B ): Subscribe { return (onValue, onEnd) => subscribe(mapObserver(onValue, fn), onEnd) } export function mapObserver( observer: Observer, fn: (value: A) => B ): Observer { return (event: A) => observer(fn(event)) } export function mapEvent(event: Event, fn: (value: A) => B): Event { if (isValue(event)) { return valueEvent(fn(event.value)) } else { return event } }