'use strict' ; import * as _ from 'lodash' ; import 'reflect-metadata' ; import { ServiceClass , ServiceMethod } from '../server/model/metadata' ; import { ParserType , ServiceProcessor } from '../server/model/server-types' ; import { ServerContainer } from '../server/server-container' ; export function Path ( path ) { return new ServiceDecorator ( 'Path' ) . withProperty ( 'path' , path ) . createDecorator ( ) ; } export function Security ( roles ? , name ? ) { roles = _ . castArray ( roles || '*' ) ; return new SecurityServiceDecorator ( 'Security' ) . withObjectProperty ( 'authenticator' , name || 'default' , roles ) . createDecorator ( ) ; } export function PreProcessor ( preprocessor ) { return new ProcessorServiceDecorator ( 'PreProcessor' ) . withArrayProperty ( 'preProcessors' , preprocessor , true ) . createDecorator ( ) ; } export function PostProcessor ( postprocessor ) { return new ProcessorServiceDecorator ( 'PostProcessor' ) . withArrayProperty ( 'postProcessors' , postprocessor , true ) . createDecorator ( ) ; } export function AcceptLanguage ( ... languages ) { languages = _ . compact ( languages ) ; return new AcceptServiceDecorator ( 'AcceptLanguage' ) . withArrayProperty ( 'languages' , languages , true ) . createDecorator ( ) ; } export function Accept ( ... accepts ) { accepts = _ . compact ( accepts ) ; return new AcceptServiceDecorator ( 'Accept' ) . withArrayProperty ( 'accepts' , accepts , true ) . createDecorator ( ) ; } /**
 * A decorator to inform options to pe passed to bodyParser.
 * You can inform any property accepted by
 * [[bodyParser]](https://www.npmjs.com/package/body-parser)
 */ export function BodyOptions ( options ) { return new ServiceDecorator ( 'BodyOptions' ) . withProperty ( 'bodyParserOptions' , options ) . createDecorator ( ) ; } /**
 * A decorator to inform the type of parser to be used to parse the body.
 * The default type is json.
 */ export function BodyType ( type ) { return new ServiceDecorator ( 'BodyType' ) . withProperty ( 'bodyParserType' , type ) . createDecorator ( ) ; } /**
 * A decorator to inform that server should ignore other middlewares.
 * It makes server does not call next function after service invocation.
 */ export function IgnoreNextMiddlewares ( ... args ) { return new ServiceDecorator ( 'IgnoreNextMiddlewares' ) . withProperty ( 'ignoreNextMiddlewares' , true ) . decorateTypeOrMethod ( args ) ; } export function Abstract ( ... args ) { args = _ . without ( args , undefined ) ; if ( args . length === 1 ) { const classData = ServerContainer . get ( ) . registerServiceClass ( args [ 0 ] ) ; classData . isAbstract = true ; } else { throw new Error ( 'Invalid @Abstract Decorator declaration.' ) ; } } interface DecoratorProperty { property : string ; value : any ; required : boolean ; process : ( target : any ) => void ; checkRequired : ( ) => boolean ; } class ServiceDecorator { protected decorator : string ; protected properties : Array < DecoratorProperty > = [ ] ; constructor ( decorator ) { this . decorator = decorator ; } public withProperty ( property , value , required = false ) { this . properties . push ( { checkRequired : ( ) => required && ! value , process : ( target ) => { target [ property ] = value ; } , property : property , required : required , value : value } ) ; return this ; } public createDecorator ( ) { return ( ... args ) => { this . checkRequiredValue ( ) ; this . decorateTypeOrMethod ( args ) ; } ; } public decorateTypeOrMethod ( args ) { args = _ . without ( args , undefined ) ; if ( args . length === 1 ) { this . decorateType ( args [ 0 ] ) ; } else if ( args . length === 3 && typeof args [ 2 ] === 'object' ) { this . decorateMethod ( args [ 0 ] , args [ 1 ] ) ; } else { throw new Error ( `Invalid @${ this . decorator } Decorator declaration.` ) ; } } protected checkRequiredValue ( ) { this . properties . forEach ( property => { if ( property . checkRequired ( ) ) { throw new Error ( `Invalid @${ this . decorator } Decorator declaration.` ) ; } } ) ; } protected decorateType ( target ) { const classData = ServerContainer . get ( ) . registerServiceClass ( target ) ; if ( classData ) { this . updateClassMetadata ( classData ) ; } } protected decorateMethod ( target , propertyKey ) { const serviceMethod = ServerContainer . get ( ) . registerServiceMethod ( target . constructor , propertyKey ) ; if ( serviceMethod ) { this . updateMethodMetadada ( serviceMethod ) ; } } protected updateClassMetadata ( classData ) { this . properties . forEach ( property => { property . process ( classData ) ; } ) ; } protected updateMethodMetadada ( serviceMethod ) { this . properties . forEach ( property => { property . process ( serviceMethod ) ; } ) ; } } class SecurityServiceDecorator extends ServiceDecorator { public withObjectProperty ( property , subtext , value , required = false ) { this . properties . push ( { checkRequired : ( ) => required && ! value , process : ( target ) => { if ( ! target [ property ] ) { target [ property ] = { } ; } target [ property ] [ subtext ] = value ; } , property : property , required : required , value : value } ) ; return this ; } } class ProcessorServiceDecorator extends ServiceDecorator { public withArrayProperty ( property , value , required = false ) { this . properties . push ( { checkRequired : ( ) => required && ! value , process : ( target ) => { if ( ! target [ property ] ) { target [ property ] = [ ] ; } target [ property ] . unshift ( value ) ; } , property : property , required : required , value : value } ) ; return this ; } } class AcceptServiceDecorator extends ServiceDecorator { public withArrayProperty ( property , value , required = false ) { this . properties . push ( { checkRequired : ( ) => required && ( ! value || ! value . length ) , process : ( target ) => { target [ property ] = _ . union ( target [ property ] , value ) ; } , property : property , required : required , value : value } ) ; return this ; } }