All files deregister-feature.ts

100% Statements 73/73
100% Branches 26/26
100% Functions 5/5
100% Lines 73/73

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 741x 1x 1x 1x 1x 40x 40x 40x 77x 77x 77x 30x 37x 30x 30x 47x 77x 77x 40x 40x 40x 1x 1x 42x 42x 42x 42x 42x 2x 2x 40x 40x 40x 40x 40x 40x 40x 42x 4x 4x 4x 4x 4x 4x 36x 42x 19x 19x 19x 19x 19x 19x 19x 14x 14x 19x 36x 41x 23x 23x 23x 23x 36x 42x 19x 19x 42x 1x 1x 19x 23x 23x 19x  
import type { DiContainer } from "@ogre-tools/injectable";
import type { Feature } from "./feature";
import { featureContextMapInjectable } from "./feature-context-map-injectable";
 
const getDependingFeaturesFor = (
  featureContextMap: Map<Feature, { dependedBy: Map<Feature, number> }>,
) => {
  const getDependingFeaturesForRecursion = (feature: Feature, atRoot = true): string[] => {
    const context = featureContextMap.get(feature);
 
    if (context?.dependedBy.size) {
      return [...context?.dependedBy.entries()].flatMap(([dependant]) =>
        getDependingFeaturesForRecursion(dependant, false),
      );
    }
 
    return atRoot ? [] : [feature.id];
  };
 
  return getDependingFeaturesForRecursion;
};
 
const deregisterFeatureRecursed = (di: DiContainer, feature: Feature, dependedBy?: Feature) => {
  const featureContextMap = di.inject(featureContextMapInjectable);
 
  const featureContext = featureContextMap.get(feature);
 
  if (!featureContext) {
    throw new Error(`Tried to deregister feature "${feature.id}", but it was not registered.`);
  }
 
  featureContext.numberOfRegistrations--;
 
  const getDependingFeatures = getDependingFeaturesFor(featureContextMap);
 
  const dependingFeatures = getDependingFeatures(feature);
 
  if (!dependedBy && dependingFeatures.length) {
    throw new Error(
      `Tried to deregister Feature "${
        feature.id
      }", but it is the dependency of Features "${dependingFeatures.join(", ")}"`,
    );
  }
 
  if (dependedBy) {
    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    const oldNumberOfDependents = featureContext.dependedBy.get(dependedBy)!;
    const newNumberOfDependants = oldNumberOfDependents - 1;
 
    featureContext.dependedBy.set(dependedBy, newNumberOfDependants);
 
    if (newNumberOfDependants === 0) {
      featureContext.dependedBy.delete(dependedBy);
    }
  }
 
  if (featureContext.numberOfRegistrations === 0) {
    featureContextMap.delete(feature);
 
    featureContext.deregister();
  }
 
  feature.dependencies?.forEach((dependency) => {
    deregisterFeatureRecursed(di, dependency, feature);
  });
};
 
export const deregisterFeature = (di: DiContainer, ...features: Feature[]) => {
  features.forEach((feature) => {
    deregisterFeatureRecursed(di, feature);
  });
};