import { Optional } from 'ts-data-forge'; import { SyncChildObservableClass } from '../class/index.mjs'; import { type DropInitialValueOperator, type Observable, type SkipUntilOperatorObservable, type UpdateToken, } from '../types/index.mjs'; /** * Skips all values from the source observable until the notifier observable emits. * * @template A - The type of values from the source * @param notifier - An observable that signals when to start emitting * @returns An operator that skips values until the notifier emits * * @example * ```ts * // Timeline: * // * // num$ 1 2 3 start 4 5 6 * // startNotifier X * // skipped$ 4 5 6 * // |------ skipped -------| * // * // Explanation: * // - skipUntil ignores all values until the notifier emits * // - After the notifier emits, all subsequent values are passed through * // - Opposite of takeUntil (which completes when notifier emits) * * const num$ = source(); * * const [startNotifier, start_] = createEventEmitter(); * * const skipped$ = num$.pipe(skipUntil(startNotifier)); * * const valueHistory: number[] = []; * * skipped$.subscribe((x) => { * valueHistory.push(x); * }); * * num$.next(1); // nothing logged * * num$.next(2); // nothing logged * * assert.deepStrictEqual(valueHistory, []); * * start_(); * * num$.next(4); // logs: 4 * * assert.deepStrictEqual(valueHistory, [4]); * * num$.next(5); // logs: 5 * * assert.deepStrictEqual(valueHistory, [4, 5]); * ``` */ export const skipUntil = (notifier: Observable): DropInitialValueOperator => (parentObservable) => new SkipUntilObservableClass(parentObservable, notifier); class SkipUntilObservableClass extends SyncChildObservableClass implements SkipUntilOperatorObservable { #mut_isSkipping: boolean; constructor(parentObservable: Observable, notifier: Observable) { super({ parents: [parentObservable], initialValue: Optional.none, }); this.#mut_isSkipping = true; notifier.subscribe( () => { this.#mut_isSkipping = false; }, () => { this.#mut_isSkipping = false; }, ); } override tryUpdate(updateToken: UpdateToken): void { const par = this.parents[0]; const sn = par.getSnapshot(); if ( par.updateToken !== updateToken || Optional.isNone(sn) || this.#mut_isSkipping ) { return; // skip update } this.setNext(sn.value, updateToken); } }