All files / common/src/annotation/context/registry annotation-context-set.ts

100% Statements 22/22
100% Branches 14/14
100% Functions 9/9
100% Lines 21/21

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 7410x   10x 10x                 10x     76x                         65x 125x 125x 125x   45x     397x 393x   393x               176x               1706x 1706x 1706x         1706x     1706x 1706x       1706x      
import { assert } from '@aspectjs/common/utils';
import { AnnotationContext } from '../../annotation-context';
import { AnnotationRef } from '../../annotation-ref';
import { AnnotationKind } from '../../annotation.types';
import { AnnotationTargetRef } from '../../target/annotation-target';
 
type ByAnnotationSet = {
  byClassTargetRef: Map<AnnotationTargetRef, AnnotationContext[]>;
}; /**
 
 * @internal
 */
export class _AnnotationContextSet {
  private buckets: {
    [k in AnnotationKind]: Map<AnnotationRef, ByAnnotationSet>;
  } = {
    [AnnotationKind.CLASS]: new Map(),
    [AnnotationKind.PROPERTY]: new Map(),
    [AnnotationKind.METHOD]: new Map(),
    [AnnotationKind.PARAMETER]: new Map(),
  };
 
  getAnnotations(
    decoratorTypes: AnnotationKind[],
    annotationRefs?: Set<AnnotationRef>,
    classTargetRef?: AnnotationTargetRef | undefined,
    propertyKey?: string | number | symbol | undefined,
  ): AnnotationContext[] {
    return decoratorTypes.flatMap((t) => {
      const _propertyKey = t === AnnotationKind.CLASS ? undefined : propertyKey;
      const m = this.buckets[t];
      return (
        annotationRefs
          ? [...annotationRefs].map((ref) => m.get(AnnotationRef.of(ref)))
          : [...m.values()]
      )
        .filter((set) => !!set)
        .map((set) => set!.byClassTargetRef)
        .flatMap((byClassTargetRef) => {
          return classTargetRef
            ? byClassTargetRef?.get(classTargetRef) ?? []
            : [...byClassTargetRef.values()].flat();
        })
        .filter(
          (annotation) =>
            // keep annotations if search for target = class
            // keep annotations if does not search for specific property
            _propertyKey === undefined ||
            (annotation as AnnotationContext<AnnotationKind.METHOD>).target
              .propertyKey === propertyKey,
        );
    });
  }
 
  addAnnotation(ctxt: AnnotationContext) {
    const bucket = this.buckets[ctxt.target.kind];
    assert(() => !!bucket);
    const byAnnotationSet = bucket.get(ctxt.ref) ?? {
      byClassTargetRef: new Map<AnnotationTargetRef, AnnotationContext[]>(),
    };
 
    const contexts =
      byAnnotationSet.byClassTargetRef.get(ctxt.target.declaringClass.ref) ??
      [];
 
    contexts.push(ctxt);
    byAnnotationSet.byClassTargetRef.set(
      ctxt.target.declaringClass.ref,
      contexts,
    );
    bucket.set(ctxt.ref, byAnnotationSet);
  }
}