/**
 * @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