import { generic } from "./decorators" ; import { createClass , reflection } from "./helpers" ; import { getMetadata , getMetadataForApplyTo , getOwnMetadata , mergeMetadata } from "./storage" ; import { Class , DecoratorOption , DecoratorOptionId , DESIGN_PARAMETER_TYPE , DESIGN_RETURN_TYPE , DESIGN_TYPE , MethodReflection , ParameterPropertiesDecorator , ParameterPropertyReflection , ParameterReflection , PrivateDecorator , PropertyReflection , TypeDecorator , } from "./types" ; import { TypedReflection , WalkMemberContext } from "./walker" ; export function addsDesignTypes ( meta , ctx ) { const getType = ( type , i ) => type [ i ] === Array ? [ Object ] : type [ i ] ; if ( meta . kind === "Method" ) { const returnType = Reflect . getOwnMetadata ( DESIGN_RETURN_TYPE , ctx . target . prototype , meta . name ) ; return { ... meta , returnType } ; } else if ( reflection . isParameterProperties ( meta ) ) { const parTypes = Reflect . getOwnMetadata ( DESIGN_PARAMETER_TYPE , ctx . target ) || [ ] ; return { ... meta , type : getType ( parTypes , meta . index ) } ; } else if ( meta . kind === "Property" ) { const type = Reflect . getOwnMetadata ( DESIGN_TYPE , ctx . target . prototype , meta . name ) ; return { ... meta , type } ; } else if ( meta . kind === "Parameter" && ctx . parent . kind === "Constructor" ) { const parTypes = Reflect . getOwnMetadata ( DESIGN_PARAMETER_TYPE , ctx . target ) || [ ] ; return { ... meta , type : getType ( parTypes , meta . index ) } ; } else if ( meta . kind === "Parameter" && ctx . parent . kind === "Method" ) { const parTypes = Reflect . getOwnMetadata ( DESIGN_PARAMETER_TYPE , ctx . target . prototype , ctx . parent . name ) || [ ] ; return { ... meta , type : getType ( parTypes , meta . index ) } ; } else return meta ; } export function addsDecorators ( meta , ctx ) { if ( meta . kind === "Parameter" ) { const decorators = ctx . parent . name === "constructor" ? getOwnMetadata ( ctx . target , ctx . parent . name , meta . index ) : getMetadata ( ctx . target , ctx . parent . name , meta . index ) ; return { ... meta , decorators : meta . decorators . concat ( decorators ) } ; } if ( reflection . isParameterProperties ( meta ) ) { const decorators = getOwnMetadata ( ctx . target , "constructor" , meta . index ) . concat ( ... getMetadata ( ctx . target , meta . name ) ) ; return { ... meta , decorators : meta . decorators . concat ( decorators ) } ; } if ( meta . kind === "Method" || meta . kind === "Property" ) { const decorators = getMetadata ( ctx . target , meta . name ) ; return { ... meta , decorators : meta . decorators . concat ( decorators ) } ; } if ( meta . kind === "Class" ) { const decorators = getMetadata ( meta . type ) ; return { ... meta , decorators : meta . decorators . concat ( decorators ) } ; } return meta ; } export function addsApplyToDecorator ( meta , ctx ) { if ( reflection . isParameterProperties ( meta ) ) { const decorators = getMetadataForApplyTo ( ctx . target , "constructor" , meta . index ) . concat ( ... getMetadataForApplyTo ( ctx . target , meta . name ) ) ; return { ... meta , decorators : meta . decorators . concat ( decorators ) } ; } if ( meta . kind === "Method" || meta . kind === "Property" ) { const decorators = getMetadataForApplyTo ( ctx . target , meta . name ) ; return { ... meta , decorators : mergeMetadata ( decorators , meta . decorators , false ) } ; } if ( meta . kind === "Class" ) { const rawDecorators = getMetadataForApplyTo ( meta . type ) ; const removedDecorators = rawDecorators . filter ( x => { const option = x [ DecoratorOptionId ] ; return option . removeApplied ; } ) ; const decorators = rawDecorators . filter ( x => { const option = x [ DecoratorOptionId ] ; return ! option . removeApplied ; } ) ; const result = { ... meta , decorators : meta . decorators . concat ( decorators ) } ; if ( removedDecorators . length > 0 ) result . removedDecorators = removedDecorators ; return result ; } return meta ; } function isGeneric ( decorator ) { const [ singleType ] = reflection . getTypeFromDecorator ( decorator ) ; return typeof singleType === "string" ; } function isDynamic ( decorator ) { const [ singleType ] = reflection . getTypeFromDecorator ( decorator ) ; return typeof singleType === "object" ; } function isTypeWithGenericParameter ( decorator ) { const [ singleType ] = reflection . getTypeFromDecorator ( decorator ) ; return typeof singleType === "function" && decorator . genericArguments . length > 0 ; } function setType ( meta , type ) { if ( meta . kind === "Method" ) return { returnType : type } ; return { type } ; } export function addsTypeByTypeDecorator ( meta , ctx ) { if ( meta . kind === "Constructor" || meta . kind === "Class" ) return meta ; const decorator = meta . decorators . find ( ( x ) : x is TypeDecorator => x . kind === "Override" ) ; if ( ! decorator ) return meta ; if ( isGeneric ( decorator ) ) { const type = generic . getType ( decorator , ctx . target ) ! ; return { ... meta , ... setType ( meta , type ) } ; } if ( isDynamic ( decorator ) ) { const [ rawType , isArray ] = reflection . getTypeFromDecorator ( decorator ) ; const type = createClass ( rawType as { } ) ; return { ... meta , ... setType ( meta , isArray ? [ type ] : type as any ) } ; } if ( isTypeWithGenericParameter ( decorator ) ) { const genericParams = decorator . genericArguments . map ( x => { const s = Array . isArray ( x ) ? x [ 0 ] : x ; return typeof s === "function" ? x : generic . getType ( { type : x , target : decorator . target } , ctx . target ) ; } ) ; const [ parentType , isArray ] = reflection . getTypeFromDecorator ( decorator ) ; const dynType = createClass ( { } , { extends : parentType as any , genericParams } ) ; const type = isArray ? [ dynType ] : dynType ; return { ... meta , ... setType ( meta , type ) } ; } const [ type , isArray ] = reflection . getTypeFromDecorator ( decorator ) ; return { ... meta , ... setType ( meta , isArray ? [ type ] : type as any ) } ; } export function addsTypeClassification ( meta , ctx ) { const get = ( type ) : "Class" | "Array" | "Primitive" | undefined => { if ( type === undefined ) return undefined ; else if ( Array . isArray ( type ) ) return "Array" ; else if ( reflection . isCustomClass ( type ) ) return "Class" ; else return "Primitive" ; } ; if ( meta . kind === "Method" ) return { ... meta , typeClassification : get ( meta . returnType ) } ; else if ( meta . kind === "Property" || meta . kind === "Parameter" ) return { ... meta , typeClassification : get ( meta . type ) } ; else if ( meta . kind === "Class" ) return { ... meta , typeClassification : "Class" } ; return meta ; } export function addsParameterProperties ( meta , ctx ) { if ( reflection . isParameterProperties ( meta ) && ctx . parent . kind === "Class" ) { const isParamProp = ctx . parent . decorators . some ( ( x ) => x . type === "ParameterProperties" ) ; return ! ! isParamProp ? meta : undefined ; } return meta ; } export function removeIgnored ( meta , ctx ) { if ( meta . kind === "Property" || meta . kind === "Method" ) { const decorator = meta . decorators . find ( ( x ) : x is PrivateDecorator => x . kind === "Ignore" ) ; return ! decorator ? meta : undefined ; } return meta ; }