'use strict' ; import * as _ from 'lodash' ; import 'reflect-metadata' ; import { FileParam , MethodParam , ParamType , ServiceMethod } from '../server/model/metadata' ; import { HttpMethod } from '../server/model/server-types' ; import { ServerContainer } from '../server/server-container' ; export function GET ( target , propertyKey ) { new MethodDecorator ( HttpMethod . GET ) . decorateMethod ( target , propertyKey ) ; } export function POST ( target , propertyKey ) { new MethodDecorator ( HttpMethod . POST ) . decorateMethod ( target , propertyKey ) ; } export function PUT ( target , propertyKey ) { new MethodDecorator ( HttpMethod . PUT ) . decorateMethod ( target , propertyKey ) ; } export function DELETE ( target , propertyKey ) { new MethodDecorator ( HttpMethod . DELETE ) . decorateMethod ( target , propertyKey ) ; } export function HEAD ( target , propertyKey ) { new MethodDecorator ( HttpMethod . HEAD ) . decorateMethod ( target , propertyKey ) ; } export function OPTIONS ( target , propertyKey ) { new MethodDecorator ( HttpMethod . OPTIONS ) . decorateMethod ( target , propertyKey ) ; } export function PATCH ( target , propertyKey ) { new MethodDecorator ( HttpMethod . PATCH ) . decorateMethod ( target , propertyKey ) ; } class MethodDecorator { private static PROCESSORS = getParameterProcessors ( ) ; private httpMethod : HttpMethod ; constructor ( httpMethod ) { this . httpMethod = httpMethod ; } public decorateMethod ( target , propertyKey ) { const serviceMethod = ServerContainer . get ( ) . registerServiceMethod ( target . constructor , propertyKey ) ; if ( serviceMethod ) { if ( ! serviceMethod . httpMethod ) { serviceMethod . httpMethod = this . httpMethod ; this . processServiceMethod ( target , propertyKey , serviceMethod ) ; } else if ( serviceMethod . httpMethod !== this . httpMethod ) { throw new Error ( 'Method is already annotated with @' + HttpMethod [ serviceMethod . httpMethod ] + '. You can only map a method to one HTTP verb.' ) ; } } } /**
     * Extract metadata for rest methods
     */ private processServiceMethod ( target , propertyKey , serviceMethod ) { serviceMethod . name = propertyKey ; const paramTypes = Reflect . getOwnMetadata ( 'design:paramtypes' , target , propertyKey ) ; this . registerUndecoratedParameters ( paramTypes , serviceMethod ) ; serviceMethod . parameters . forEach ( param => { const processor = MethodDecorator . PROCESSORS . get ( param . paramType ) ; if ( processor ) { processor ( serviceMethod , param ) ; } } ) ; } private registerUndecoratedParameters ( paramTypes , serviceMethod ) { while ( paramTypes && paramTypes . length > serviceMethod . parameters . length ) { serviceMethod . parameters . push ( new MethodParam ( null , paramTypes [ serviceMethod . parameters . length ] , ParamType . body ) ) ; } } } type ParamProcessor = ( serviceMethod : ServiceMethod , param ? : MethodParam ) => void ; function getParameterProcessors ( ) { const result = new Map < ParamType , ParamProcessor > ( ) ; result . set ( ParamType . cookie , ( serviceMethod ) => { serviceMethod . mustParseCookies = true ; } ) ; result . set ( ParamType . file , ( serviceMethod , param ) => { serviceMethod . files . push ( new FileParam ( param . name , true ) ) ; } ) ; result . set ( ParamType . files , ( serviceMethod , param ) => { serviceMethod . files . push ( new FileParam ( param . name , false ) ) ; } ) ; result . set ( ParamType . param , ( serviceMethod ) => { serviceMethod . acceptMultiTypedParam = true ; } ) ; result . set ( ParamType . form , ( serviceMethod ) => { if ( serviceMethod . mustParseBody ) { throw Error ( 'Can not use form parameters with a body parameter on the same method.' ) ; } serviceMethod . mustParseForms = true ; } ) ; result . set ( ParamType . body , ( serviceMethod ) => { if ( serviceMethod . mustParseForms ) { throw Error ( 'Can not use form parameters with a body parameter on the same method.' ) ; } if ( serviceMethod . mustParseBody ) { throw Error ( 'Can not use more than one body parameter on the same method.' ) ; } serviceMethod . mustParseBody = true ; } ) ; return result ; }