All files / common/src/annotation annotation-ref.ts

81.81% Statements 27/33
60% Branches 9/15
100% Functions 5/5
81.81% Lines 27/33

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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 11210x           10x 10x                                                                   37x 37x 37x 37x 37x 37x           37x         37x       37x 37x               2186x                               2866x 1094x 1094x   1772x 1772x 1772x 1772x         37x       2866x 2866x 37x 37x     2866x      
import { assert } from '@aspectjs/common/utils';
 
/**
 * An annotation is identified by its name and its group id.
 * An AnnotationRef represents the identity of an annotation.
 */
export class AnnotationRef {
  private static readonly registry = new Map<string, AnnotationRef>();
 
  /**
   * The value of the annotation reference.
   */
  public readonly value: string;
  /**
   * The name of the referenced annotation.
   */
  public readonly name: string;
  /**
   * The group id of the referenced annotation.
   */
  public readonly groupId: string;
 
  /**
   * @internal
   * @param ref
   */
  private constructor(ref: string);
  /**
   * @internal
   * @param groupId
   * @param name
   */
  private constructor(groupId: string, name: string);
  /**
   * @internal
   * @param groupIdOrRef
   * @param name
   */
  private constructor(groupIdOrRef: string, name?: string) {
    let _groupId: string | undefined;
    let _name: string | undefined;
    if (!name) {
      this.value = groupIdOrRef.replace(/^@/, '');
      const ANNOTATION_REF_REGEX = /(?<groupId>\S+):(?<name>\S+)/;
      const match = ANNOTATION_REF_REGEX.exec(this.value);
      _groupId = match?.groups?.['groupId'];
      _name = match?.groups?.['name'];
    } else E{
      this.value = `${groupIdOrRef}:${name}`;
      _name = name;
      _groupId = groupIdOrRef;
    }
    Iif (!_name) {
      assert(false);
      throw new Error('cannot create annotation without name');
    }
 
    Iif (!_groupId) {
      throw new Error('cannot create annotation without groupId');
    }
 
    this.name = _name;
    this.groupId = _groupId;
  }
 
  /**
   * Get the string representation of the annotation in the format: `@<groupId>:<name>`
   * @returns The string representation of the annotation.
   */
  toString(): string {
    return `@${this.value}`;
  }
 
  /**
   * Create a new Annotation Reference out of an Annotation, a string, or an AnnotationRef.
   * @param obj
   * @returns
   */
  static of(groupId: string, name: string): AnnotationRef;
  static of(
    obj: Pick<AnnotationRef, 'groupId' | 'name'> | string,
  ): AnnotationRef;
  static of(
    obj: Pick<AnnotationRef, 'groupId' | 'name'> | string,
    name?: string,
  ): AnnotationRef {
    if (typeof obj === 'string') {
      const refStr = typeof name === 'string' ? `${obj}:${name}` : obj;
      return AnnotationRef.get(refStr) ?? new AnnotationRef(refStr);
    } else {
      const ref = obj as AnnotationRef;
      assert(!!ref);
      const refStr = `${ref.groupId}:${ref.name}`;
      return AnnotationRef.get(refStr) ?? new AnnotationRef(refStr);
    }
  }
 
  private static register(ref: AnnotationRef) {
    AnnotationRef.registry.set(ref.value, ref);
  }
 
  private static get(ref: AnnotationRef | string): AnnotationRef {
    let val = AnnotationRef.registry.get(ref.toString());
    if (!val) {
      val = typeof ref === 'string' ? new AnnotationRef(ref) : ref;
      this.register(val);
    }
 
    return val;
  }
}