import * as ERROR_MSGS from "../constants/error_msgs" ; import * as METADATA_KEY from "../constants/metadata_keys" ; import { interfaces } from "../interfaces/interfaces" ; import { getFirstArrayDuplicate } from "../utils/js" ; function targetIsConstructorFunction < T = Object > ( target ) { return ( target as ConstructorFunction < T > ) . prototype !== undefined ; } type Prototype < T > = { [ Property in keyof T ] : T [ Property ] extends NewableFunction ? T [ Property ] : T [ Property ] | undefined ; } & { constructor : NewableFunction ; } ; interface ConstructorFunction < T = Record < string , unknown > > { new ( ... args ) : T ; prototype : Prototype < T > ; } export type DecoratorTarget < T = unknown > = ConstructorFunction < T > | Prototype < T > ; function _throwIfMethodParameter ( parameterName ) { if ( parameterName !== undefined ) { throw new Error ( ERROR_MSGS . INVALID_DECORATOR_OPERATION ) ; } } function tagParameter ( annotationTarget , parameterName , parameterIndex , metadata ) { _throwIfMethodParameter ( parameterName ) ; _tagParameterOrProperty ( METADATA_KEY . TAGGED , annotationTarget as ConstructorFunction , parameterIndex . toString ( ) , metadata ) ; } function tagProperty ( annotationTarget , propertyName , metadata ) { if ( targetIsConstructorFunction ( annotationTarget ) ) { throw new Error ( ERROR_MSGS . INVALID_DECORATOR_OPERATION ) ; } _tagParameterOrProperty ( METADATA_KEY . TAGGED_PROP , annotationTarget . constructor , propertyName , metadata ) ; } function _ensureNoMetadataKeyDuplicates ( metadata ) { let metadatas = [ ] ; if ( Array . isArray ( metadata ) ) { metadatas = metadata ; const duplicate = getFirstArrayDuplicate ( metadatas . map ( md => md . key ) ) ; if ( duplicate !== undefined ) { throw new Error ( `${ ERROR_MSGS . DUPLICATED_METADATA } ${ duplicate . toString ( ) }` ) ; } } else { metadatas = [ metadata ] ; } return metadatas ; } function _tagParameterOrProperty ( metadataKey , annotationTarget , key , metadata ) { const metadatas = _ensureNoMetadataKeyDuplicates ( metadata ) ; let paramsOrPropertiesMetadata = { } ; if ( Reflect . hasOwnMetadata ( metadataKey , annotationTarget ) ) { paramsOrPropertiesMetadata = Reflect . getMetadata ( metadataKey , annotationTarget ) ; } let paramOrPropertyMetadata = paramsOrPropertiesMetadata [ key as string ] ; if ( paramOrPropertyMetadata === undefined ) { paramOrPropertyMetadata = [ ] ; } else { for ( const m of paramOrPropertyMetadata ) { if ( metadatas . some ( md => md . key === m . key ) ) { throw new Error ( `${ ERROR_MSGS . DUPLICATED_METADATA } ${ m . key . toString ( ) }` ) ; } } } paramOrPropertyMetadata . push ( ... metadatas ) ; paramsOrPropertiesMetadata [ key ] = paramOrPropertyMetadata ; Reflect . defineMetadata ( metadataKey , paramsOrPropertiesMetadata , annotationTarget ) ; } function createTaggedDecorator ( metadata ) { return < T > ( target , targetKey ? , indexOrPropertyDescriptor ? ) => { if ( typeof indexOrPropertyDescriptor === "number" ) { tagParameter ( target , targetKey , indexOrPropertyDescriptor , metadata ) ; } else { tagProperty ( target , targetKey as string | symbol , metadata ) ; } } ; } function _decorate ( decorators , target ) { Reflect . decorate ( decorators as ClassDecorator [ ] , target ) ; } function _param ( paramIndex , decorator ) { return function ( target , key ) { decorator ( target , key , paramIndex ) ; } ; } function decorate ( decorator , target , parameterIndexOrProperty ? ) { if ( typeof parameterIndexOrProperty === "number" ) { _decorate ( [ _param ( parameterIndexOrProperty , decorator as ParameterDecorator ) ] , target ) ; } else if ( typeof parameterIndexOrProperty === "string" ) { Reflect . decorate ( [ decorator as MethodDecorator ] , target , parameterIndexOrProperty ) ; } else { _decorate ( [ decorator ] , target ) ; } } export { decorate , tagParameter , tagProperty , createTaggedDecorator } ;