All files / common/src/annotation/target/impl property-annotation-target.impl.ts

87.17% Statements 34/39
82.35% Branches 14/17
72.72% Functions 8/11
86.84% Lines 33/38

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 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 15110x               10x 10x         10x         10x 10x   10x   10x         10x                                           219x                     219x 219x               423x 423x 423x 423x             423x 423x       423x         211x                             830x 618x     212x     212x         212x               6x 5x       8x     8x     8x               8x 8x 8x      
import {
  ConstructorType,
  Prototype,
  assert,
  defineMetadata,
  getMetadata,
  getPrototype,
} from '@aspectjs/common/utils';
import { AnnotationKind } from '../../annotation.types';
import {
  AnnotationTargetRef,
  ClassAnnotationTarget,
  PropertyAnnotationTarget,
} from '../annotation-target';
import {
  BOUND_INSTANCE_SYMBOL,
  BOUND_VALUE_SYMBOL,
  _AnnotationTargetImpl,
} from '../annotation-target.impl';
import { defuseAdvices } from '../annotation-target.utils';
import { _ClassAnnotationTargetImpl } from './class-annotation-target.impl';
 
let _globalTargetId = 0;
 
export class _PropertyAnnotationTargetImpl<X>
  extends _AnnotationTargetImpl<AnnotationKind.PROPERTY, X>
  implements PropertyAnnotationTarget<X>
{
  override defineMetadata(key: string, value: any): void {
    defineMetadata(key, value, this.proto, this.propertyKey);
  }
  override getMetadata<T>(
    key: string,
    defaultvalue?: (() => T) | undefined,
  ): T {
    return getMetadata(key, this.proto, this.propertyKey, defaultvalue);
  }
 
  readonly propertyKey: string | symbol;
  readonly descriptor: PropertyDescriptor;
  protected declare [BOUND_INSTANCE_SYMBOL]?: X;
  protected declare [BOUND_VALUE_SYMBOL]?: () => unknown;
 
  private _declaringClassTarget?: ClassAnnotationTarget<X>;
  private constructor(
    proto: Prototype<X>,
    propertyKey: string | symbol,
    ref: AnnotationTargetRef,
    descriptor: PropertyDescriptor,
    isStatic: boolean,
  ) {
    super(
      AnnotationKind.PROPERTY,
      proto,
      String(propertyKey),
      `${isStatic ? 'static ' : ''}property ${proto.constructor.name}.${String(
        propertyKey,
      )}`,
      ref,
      isStatic,
    );
 
    this.propertyKey = propertyKey;
    this.descriptor = descriptor;
  }
 
  static of<X>(
    decoree: Prototype<X> | ConstructorType<X>,
    propertyKey: string | symbol,
    descriptor?: PropertyDescriptor,
  ) {
    assert(typeof decoree === 'object' || typeof decoree === 'function');
    assert(typeof propertyKey === 'string' || typeof propertyKey === 'symbol');
    assert(typeof descriptor === 'object' || typeof descriptor === 'undefined');
    const proto = getPrototype(decoree);
 
    // const descriptor = Object.getOwnPropertyDescriptor(
    //   targetArgs.decoree,
    //   targetArgs.propertyKey!,
    // )!;
 
    const isStatic = typeof decoree === 'function';
    const ref = `c[${proto.constructor.name}].${isStatic ? 's ' : ''}p[${String(
      propertyKey,
    )}]`;
 
    return getMetadata(
      `@ajs:tgrf`,
      decoree,
      ref,
      () =>
        new _PropertyAnnotationTargetImpl(
          proto,
          propertyKey,
          new AnnotationTargetRef(`${ref}#${_globalTargetId++}`),
          descriptor ?? Object.getOwnPropertyDescriptor(decoree, propertyKey)!,
          isStatic,
        ),
    );
  }
 
  asDecoratorArgs() {
    return [this.proto, this.propertyKey];
  }
 
  get declaringClass() {
    if (this._declaringClassTarget) {
      return this._declaringClassTarget;
    }
 
    const declaringClassTarget = _ClassAnnotationTargetImpl.of<X>(
      this.proto.constructor,
    );
    this._declaringClassTarget =
      typeof this[BOUND_INSTANCE_SYMBOL] !== 'undefined'
        ? declaringClassTarget._bind(this[BOUND_INSTANCE_SYMBOL])
        : declaringClassTarget;
 
    return this._declaringClassTarget;
  }
 
  get parentClass() {
    return this.declaringClass.parentClass;
  }
 
  override eval(): unknown {
    const getter = super.eval() as any;
    return defuseAdvices(this, getter);
  }
 
  override _bind(instance: X): PropertyAnnotationTarget<X> {
    Iif (this.static) {
      return this;
    }
    Iif (this[BOUND_INSTANCE_SYMBOL] === instance) {
      return this;
    }
    const bound = new _PropertyAnnotationTargetImpl(
      this.proto,
      this.propertyKey,
      this.ref,
      this.descriptor,
      this.static,
    );
 
    bound[BOUND_INSTANCE_SYMBOL] = instance;
    bound[BOUND_VALUE_SYMBOL] = () => (instance as any)[this.propertyKey];
    return bound;
  }
}