@alterior/annotations
Version:
Create and interact with Typescript metadata decorators
385 lines • 16.2 kB
TypeScript
/**
* @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