All files run-many-sync-for.ts

97.4% Statements 75/77
93.33% Branches 14/15
100% Functions 7/7
97.4% Lines 75/77

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 781x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 7x 7x 7x 1x 1x 7x 7x 7x 9x 7x 7x 7x 9x 7x 7x 2x     2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 7x 7x 7x 1x 1x 1x 4x 4x 4x 7x 7x 7x 7x 7x 7x 4x 1x 1x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x 4x  
/**
 * Copyright (c) OpenLens Authors. All rights reserved.
 * Licensed under MIT License. See LICENSE in root directory for more information.
 */
import type { DiContainerForInjection, InjectionToken } from "@ogre-tools/injectable";
import type { Disposer } from "@k8slens/utilities";
import type { RunnableSync, RunSync, RunnableSyncWithId } from "./types";
import { convertToWithIdWith, verifyRunnablesAreDAG } from "./helpers";
import type TypedEventEmitter from "typed-emitter";
import EventEmitter from "events";
 
export type RunManySync = <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => RunSync<Param>;
 
class SyncBarrier {
  private readonly finishedIds = new Set<string>();
  private readonly events: TypedEventEmitter<Record<string, () => void>> = new EventEmitter();
 
  setFinished(id: string): void {
    this.finishedIds.add(id);
    this.events.emit(id);
  }
 
  onceParentsAreFinished(id: string, parentIds: string[], action: () => void) {
    const finishers = new Map<string, Disposer>();
 
    const checkAndRun = () => {
      if (finishers.size === 0) {
        action();
        this.setFinished(id);
      }
    };
 
    for (const parentId of parentIds) {
      if (this.finishedIds.has(parentId)) {
        continue;
      }
 
      const onParentFinished = () => {
        this.events.removeListener(parentId, onParentFinished);
        finishers.delete(parentId);
        checkAndRun();
      };
 
      finishers.set(parentId, onParentFinished);
      this.events.once(parentId, onParentFinished);
    }
 
    checkAndRun();
  }
}
 
const executeRunnableWith = <Param>(param: Param) => {
  const barrier = new SyncBarrier();
 
  return (runnable: RunnableSyncWithId<Param>) => {
    barrier.onceParentsAreFinished(
      runnable.id,
      runnable.runAfter.map(r => r.id),
      () => runnable.run(param),
    );
  };
};
 
export function runManySyncFor(di: DiContainerForInjection): RunManySync {
  const convertToWithId = convertToWithIdWith(di);
 
  return <Param>(injectionToken: InjectionToken<RunnableSync<Param>, void>) => (param: Param): undefined => {
    const executeRunnable = executeRunnableWith(param);
    const allRunnables = di.injectManyWithMeta(injectionToken).map(convertToWithId);
 
    verifyRunnablesAreDAG(injectionToken.id, allRunnables);
 
    allRunnables.forEach(executeRunnable);
 
    return undefined;
  };
}