UNPKG

@alterior/annotations

Version:
385 lines 16.2 kB
/** * @alterior/annotations * A class library for handling Typescript metadata decorators via "annotation" classes * * (C) 2017-2019 William Lahti * */ import { NotSupportedError } from '@alterior/common'; /** * Represents an annotation which could be stored in the standard annotation lists * on a class. */ export interface IAnnotation { $metadataName?: string; } export declare const ANNOTATIONS_KEY = "__annotations__"; export declare const CONSTRUCTOR_PARAMETERS_ANNOTATIONS_KEY = "__parameters__"; export declare const PROPERTY_ANNOTATIONS_KEY = "__prop__metadata__"; export declare const METHOD_PARAMETER_ANNOTATIONS_KEY = "__parameter__metadata__"; /** * Represents an Annotation subclass from the perspective of using it to * construct itself by passing an options object. */ interface AnnotationConstructor<AnnoT extends Annotation, TS extends any[]> { new (...args: TS): AnnoT; getMetadataName(): any; } export type AnnotationClassDecorator<TS extends any[]> = (...args: TS) => ((target: any) => void); export type AnnotationPropertyDecorator<TS extends any[]> = (...args: TS) => ((target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => void); export type AnnotationMethodDecorator<TS extends any[]> = (...args: TS) => ((target: any, propertyKey: string | symbol) => void); export type AnnotationParameterDecorator<TS extends any[]> = (...args: TS) => ((target: any, propertyKey: string | symbol, index: number) => void); type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends ((x: infer I) => void) ? I : never; type DecoratorTypeUnionForValidTargets<Targets> = Targets extends 'class' ? ClassDecorator : Targets extends 'method' ? MethodDecorator : Targets extends 'property' ? PropertyDecorator : Targets extends 'parameter' ? ParameterDecorator : never; type DecoratorTypeForValidTargets<Targets> = UnionToIntersection<DecoratorTypeUnionForValidTargets<Targets>>; /** * Represents a decorator which accepts an Annotation's options object. */ export type AnnotationDecorator<TS extends any[]> = (...args: TS) => ClassDecorator & PropertyDecorator & MethodDecorator & ParameterDecorator; export interface DecoratorSite { type: 'class' | 'method' | 'property' | 'parameter'; target: any; propertyKey?: string; propertyDescriptor?: PropertyDescriptor; index?: number; } export type AnnotationDecoratorTarget = 'class' | 'property' | 'method' | 'parameter'; export interface AnnotationDecoratorOptions<AnnoT, TS extends any[] = []> { factory?: (target: DecoratorSite, ...args: TS) => AnnoT | void; validTargets?: AnnotationDecoratorTarget[]; allowMultiple?: boolean; } /** * Thrown when a caller attempts to decorate an annotation target when the * annotation does not support that target. */ export declare class AnnotationTargetError extends NotSupportedError { constructor(annotationClass: any, invalidType: string, supportedTypes: string[], message?: string); private _invalidType; private _annotationClass; private _supportedTypes; get invalidType(): string; get supportedTypes(): string[]; get annotationClass(): Function; } export declare function MetadataName(name: string): (target: any) => any; export interface MutatorDefinition { invoke: (site: DecoratorSite) => void; options?: AnnotationDecoratorOptions<void>; } /** * Represents a metadata annotation which can be applied to classes, * constructor parameters, methods, properties, or method parameters * via decorators. * * Custom annotations are defined as subclasses of this class. * By convention, all custom annotation classes should have a name * which ends in "Annotation" such as "NameAnnotation". * * To create a new annotation create a subclass of `Annotation` * with a constructor that takes the parameters you are interested in * storing, and save the appropriate information onto fields of the * new instance. For your convenience, Annotation provides a default * constructor which takes a map object and applies its properties onto * the current instance, but you may replace it with a constructor that * takes any arguments you wish. * * You may wish to add type safety to the default constructor parameter. * To do so, override the constructor and define it: * ``` class XYZ extends Annotation { constructor( options : MyOptions ) { super(options); } } ``` * * Annotations are applied by using decorators. * When you define a custom annotation, you must also define a * custom decorator: * ``` const Name = NameAnnotation.decorator(); ``` * You can then use that decorator: ``` @Name() class ABC { // ... } ``` * */ export declare class Annotation implements IAnnotation { constructor(props?: any); readonly $metadataName: string; toString(): string; static getMetadataName(): string; /** * Construct a decorator suitable for attaching annotations of the called type * onto classes, constructor parameters, methods, properties, and parameters. * Must be called while referencing the subclass of Annotation you wish to construct * the decorator for. E.g., for FooAnnotation, call FooAnnotation.decorator(). * * @param this The Annotation subclass for which the decorator is being constructed * @param options Allows for specifying options which will modify the behavior of the decorator. * See the DecoratorOptions documentation for more information. */ static decorator<T extends Annotation, TS extends any[], U extends AnnotationDecoratorTarget>(this: AnnotationConstructor<T, TS>, options?: Exclude<AnnotationDecoratorOptions<T, TS>, 'validTargets'> & { validTargets: U[]; }): (...args: TS) => DecoratorTypeForValidTargets<U>; static decorator<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, options?: AnnotationDecoratorOptions<T, TS>): AnnotationDecorator<TS>; /** * Clone this annotation instance into a new one. This is not a deep copy. */ clone(): this; /** * Apply this annotation to a given target. * @param target */ applyToClass(target: any): this; /** * Apply this annotation instance to the given property. * @param target * @param name */ applyToProperty(target: any, name: string): this; /** * Apply this annotation instance to the given method. * @param target * @param name */ applyToMethod(target: any, name: string): this; /** * Apply this annotation instance to the given method parameter. * @param target * @param name * @param index */ applyToParameter(target: any, name: string, index: number): this; /** * Apply this annotation instance to the given constructor parameter. * @param target * @param name * @param index */ applyToConstructorParameter(target: any, index: number): this; /** * Filter the given list of annotations for the ones which match this annotation class * based on matching $metadataName. * * @param this * @param annotations */ static filter<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, annotations: IAnnotation[]): T[]; /** * Get all instances of this annotation class attached to the given class. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * @param this * @param type The class to check */ static getAllForClass<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any): T[]; /** * Get a single instance of this annotation class attached to the given class. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type */ static getForClass<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any): T; /** * Get all instances of this annotation class attached to the given method. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where the method is defined * @param methodName The name of the method to check */ static getAllForMethod<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any, methodName: string): T[]; /** * Get one instance of this annotation class attached to the given method. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where the method is defined * @param methodName The name of the method to check */ static getForMethod<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any, methodName: string): T; /** * Get all instances of this annotation class attached to the given property. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where the property is defined * @param propertyName The name of the property to check */ static getAllForProperty<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any, propertyName: string): T[]; /** * Get one instance of this annotation class attached to the given property. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where the property is defined * @param propertyName The name of the property to check */ static getForProperty<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any, propertyName: string): T; /** * Get all instances of this annotation class attached to the parameters of the given method. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where the method is defined * @param methodName The name of the method where parameter annotations should be checked for */ static getAllForParameters<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any, methodName: string): T[][]; /** * Get all instances of this annotation class attached to the parameters of the constructor * for the given class. * If called on a subclass of Annotation, it returns only annotations that match * that subclass. * * @param this * @param type The class where constructor parameter annotations should be checked for */ static getAllForConstructorParameters<T extends Annotation, TS extends any[]>(this: AnnotationConstructor<T, TS>, type: any): T[][]; } /** * A helper class for managing annotations */ export declare class Annotations { /** * Copy the annotations defined for one class onto another. * @param from The class to copy annotations from * @param to The class to copy annotations to */ static copyClassAnnotations(from: Function, to: Function): void; /** * Apply this annotation to a given target. * @param target */ static applyToClass<T extends IAnnotation>(annotation: T, target: any): T; /** * Apply this annotation instance to the given property. * @param target * @param name */ static applyToProperty<T extends IAnnotation>(annotation: T, target: any, name: string): T; /** * Apply this annotation instance to the given method. * @param target * @param name */ static applyToMethod<T extends IAnnotation>(annotation: T, target: any, name: string): T; /** * Apply this annotation instance to the given method parameter. * @param target * @param name * @param index */ static applyToParameter<T extends IAnnotation>(annotation: T, target: any, name: string, index: number): T; /** * Apply this annotation instance to the given constructor parameter. * @param target * @param name * @param index */ static applyToConstructorParameter<T extends IAnnotation>(annotation: T, target: any, index: number): T; /** * Clone the given Annotation instance into a new instance. This is not * a deep copy. * * @param annotation */ static clone<T extends IAnnotation>(annotation: T): T; /** * Get all annotations (including from Angular and other compatible * frameworks). * * @param target The target to fetch annotations for */ static getClassAnnotations(target: any): IAnnotation[]; /** * Get all annotations (including from Angular and other compatible * frameworks). * * @param target The target to fetch annotations for */ static getMethodAnnotations(target: any, methodName: string, isStatic?: boolean): IAnnotation[]; /** * Get all annotations (including from Angular and other compatible * frameworks). * * @param target The target to fetch annotations for */ static getPropertyAnnotations(target: any, methodName: string, isStatic?: boolean): IAnnotation[]; /** * Get the annotations defined on the parameters of the given method of the given * class. * * @param type * @param methodName * @param isStatic Whether `type` itself (isStatic = true), or `type.prototype` (isStatic = false) should be the target. * Note that passing true may indicate that the passed `type` is already the prototype of a class. */ static getParameterAnnotations(type: any, methodName: string, isStatic?: boolean): IAnnotation[][]; /** * Get the annotations defined on the parameters of the given method of the given * class. * * @param type * @param methodName */ static getConstructorParameterAnnotations(type: any): IAnnotation[][]; /** * Get a list of annotations for the given class. * @param target */ private static getListForClass; /** * Get a list of own annotations for the given class, or create that list. * @param target */ private static getOrCreateListForClass; /** * Gets a map of the annotations defined on all properties of the given class/function. To get the annotations of instance fields, * make sure to use `Class.prototype`, otherwise static annotations are returned. */ static getMapForClassProperties(target: Object, mapToPopulate?: Record<string, IAnnotation[]>): Record<string, IAnnotation[]>; private static getOrCreateMapForClassProperties; private static getListForProperty; private static getOrCreateListForProperty; private static getOrCreateListForMethod; private static getListForMethod; /** * Get a map of the annotations defined on all parameters of all methods of the given class/function. * To get instance methods, make sure to pass `Class.prototype`, otherwise the results are for static fields. */ static getMapForMethodParameters(target: Object, mapToPopulate?: Record<string, IAnnotation[][]>): Record<string, IAnnotation[][]>; private static getOrCreateMapForMethodParameters; private static getListForMethodParameters; private static getOrCreateListForMethodParameters; private static getOrCreateListForConstructorParameters; private static getListForConstructorParameters; } /** * An annotation for attaching a label to a programmatic element. * Can be queried with LabelAnnotation.getForClass() for example. */ export declare class LabelAnnotation extends Annotation { readonly text: string; constructor(text: string); } export declare const Label: (text: string) => ClassDecorator & PropertyDecorator & MethodDecorator & ParameterDecorator; export {}; //# sourceMappingURL=annotations.d.ts.map