{"version":3,"file":"observable.mjs","names":[],"sources":["../../src/tools/observable.ts"],"sourcesContent":["import { queueMicrotask } from './queueMicrotask'\n\nexport interface Subscription {\n  unsubscribe: () => void\n}\n\ntype Observer<T> = (data: T) => void\n\n// eslint-disable-next-line no-restricted-syntax\nexport class Observable<T> {\n  protected observers: Array<Observer<T>> = []\n  private onLastUnsubscribe?: () => void\n\n  constructor(private onFirstSubscribe?: (observable: Observable<T>) => (() => void) | void) {}\n\n  subscribe(observer: Observer<T>): Subscription {\n    this.addObserver(observer)\n    return {\n      unsubscribe: () => this.removeObserver(observer),\n    }\n  }\n\n  notify(data: T) {\n    this.observers.forEach((observer) => observer(data))\n  }\n\n  protected addObserver(observer: Observer<T>) {\n    this.observers.push(observer)\n    if (this.observers.length === 1 && this.onFirstSubscribe) {\n      this.onLastUnsubscribe = this.onFirstSubscribe(this) || undefined\n    }\n  }\n\n  protected removeObserver(observer: Observer<T>) {\n    this.observers = this.observers.filter((other) => observer !== other)\n    if (!this.observers.length && this.onLastUnsubscribe) {\n      this.onLastUnsubscribe()\n    }\n  }\n}\n\nexport function mergeObservables<T>(...observables: Array<Observable<T>>) {\n  return new Observable<T>((globalObservable) => {\n    const subscriptions: Subscription[] = observables.map((observable) =>\n      observable.subscribe((data) => globalObservable.notify(data))\n    )\n    return () => subscriptions.forEach((subscription) => subscription.unsubscribe())\n  })\n}\n\n// eslint-disable-next-line no-restricted-syntax\nexport class BufferedObservable<T> extends Observable<T> {\n  private buffer: T[] = []\n  private droppedCount = 0\n\n  constructor(\n    private maxBufferSize: number,\n    private onDrop?: (count: number) => void\n  ) {\n    super()\n  }\n\n  notify(data: T) {\n    this.buffer.push(data)\n    if (this.buffer.length > this.maxBufferSize) {\n      this.buffer.shift()\n      this.droppedCount++\n    }\n    super.notify(data)\n  }\n\n  subscribe(observer: Observer<T>): Subscription {\n    let closed = false\n\n    const subscription = {\n      unsubscribe: () => {\n        closed = true\n        this.removeObserver(observer)\n      },\n    }\n\n    queueMicrotask(() => {\n      for (const data of this.buffer) {\n        if (closed) {\n          return\n        }\n        observer(data)\n      }\n\n      if (!closed) {\n        this.addObserver(observer)\n      }\n    })\n\n    return subscription\n  }\n\n  /**\n   * Drop buffered data and don't buffer future data. This is to avoid leaking memory when it's not\n   * needed anymore. This can be seen as a performance optimization, and things will work probably\n   * even if this method isn't called, but still useful to clarify our intent and lowering our\n   * memory impact.\n   */\n  unbuffer() {\n    queueMicrotask(() => {\n      if (this.droppedCount > 0 && this.onDrop) {\n        this.onDrop(this.droppedCount)\n      }\n      this.maxBufferSize = this.buffer.length = 0\n    })\n  }\n}\n"],"mappings":";;AASA,IAAa,aAAb,MAA2B;CAIzB,YAAY,kBAA+E;EAAvE,KAAA,mBAAA;mBAHsB,CAAC;CAGiD;CAE5F,UAAU,UAAqC;EAC7C,KAAK,YAAY,QAAQ;EACzB,OAAO,EACL,mBAAmB,KAAK,eAAe,QAAQ,EACjD;CACF;CAEA,OAAO,MAAS;EACd,KAAK,UAAU,SAAS,aAAa,SAAS,IAAI,CAAC;CACrD;CAEA,YAAsB,UAAuB;EAC3C,KAAK,UAAU,KAAK,QAAQ;EAC5B,IAAI,KAAK,UAAU,WAAW,KAAK,KAAK,kBACtC,KAAK,oBAAoB,KAAK,iBAAiB,IAAI,KAAK,KAAA;CAE5D;CAEA,eAAyB,UAAuB;EAC9C,KAAK,YAAY,KAAK,UAAU,QAAQ,UAAU,aAAa,KAAK;EACpE,IAAI,CAAC,KAAK,UAAU,UAAU,KAAK,mBACjC,KAAK,kBAAkB;CAE3B;AACF;AAEA,SAAgB,iBAAoB,GAAG,aAAmC;CACxE,OAAO,IAAI,YAAe,qBAAqB;EAC7C,MAAM,gBAAgC,YAAY,KAAK,eACrD,WAAW,WAAW,SAAS,iBAAiB,OAAO,IAAI,CAAC,CAC9D;EACA,aAAa,cAAc,SAAS,iBAAiB,aAAa,YAAY,CAAC;CACjF,CAAC;AACH;AAGA,IAAa,qBAAb,cAA2C,WAAc;CAIvD,YACE,eACA,QACA;EACA,MAAM;EAHE,KAAA,gBAAA;EACA,KAAA,SAAA;gBALY,CAAC;sBACA;CAOvB;CAEA,OAAO,MAAS;EACd,KAAK,OAAO,KAAK,IAAI;EACrB,IAAI,KAAK,OAAO,SAAS,KAAK,eAAe;GAC3C,KAAK,OAAO,MAAM;GAClB,KAAK;EACP;EACA,MAAM,OAAO,IAAI;CACnB;CAEA,UAAU,UAAqC;EAC7C,IAAI,SAAS;EAEb,MAAM,eAAe,EACnB,mBAAmB;GACjB,SAAS;GACT,KAAK,eAAe,QAAQ;EAC9B,EACF;EAEA,qBAAqB;GACnB,KAAK,MAAM,QAAQ,KAAK,QAAQ;IAC9B,IAAI,QACF;IAEF,SAAS,IAAI;GACf;GAEA,IAAI,CAAC,QACH,KAAK,YAAY,QAAQ;EAE7B,CAAC;EAED,OAAO;CACT;;;;;;;CAQA,WAAW;EACT,qBAAqB;GACnB,IAAI,KAAK,eAAe,KAAK,KAAK,QAChC,KAAK,OAAO,KAAK,YAAY;GAE/B,KAAK,gBAAgB,KAAK,OAAO,SAAS;EAC5C,CAAC;CACH;AACF"}