@lakutata/core
Version:
Lakutata Framework Core
81 lines (78 loc) • 3.47 kB
text/typescript
import {AnySchema} from 'yup/lib/schema'
import {InvalidMethodReturnException} from '../exceptions/InvalidMethodReturnException'
import {InvalidMethodAcceptException} from '../exceptions/InvalidMethodAcceptException'
/**
* 返回方法验证装饰器
* @param {AnySchema} returnSchema
* @param {{strict?: boolean, stripUnknown?: boolean}} options
* @returns {(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => any>) => TypedPropertyDescriptor<(...args: any[]) => any>}
* @constructor
*/
export const Return = (returnSchema: AnySchema, options: { strict?: boolean, stripUnknown?: boolean } = {
strict: true,
stripUnknown: true
}) => {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => any | Promise<any>>) => {
descriptor.writable = false
const originalMethod: (...args: any[]) => any | Promise<any> = descriptor.value as any
returnSchema = returnSchema.label(`Method [${propertyKey}] return value`).nullable(false).required(`Method [${propertyKey}] must return ${returnSchema.type}`)
descriptor.value = function (...args: any[]) {
const originalMethodResult = originalMethod.apply(this, args)
if (originalMethodResult instanceof Promise) {
return new Promise((resolve, reject) => {
return originalMethodResult.then(originalAsyncMethodResult => {
try {
const methodResult = returnSchema.validateSync(originalAsyncMethodResult, options)
resolve(methodResult)
} catch (e) {
reject(new InvalidMethodReturnException((e as Error).message))
}
}).catch(reject)
})
} else {
try {
return returnSchema.validateSync(originalMethodResult, options)
} catch (e) {
if (target['generateException']) {
throw target['generateException'](InvalidMethodReturnException, (e as Error).message)
} else {
throw new InvalidMethodReturnException((e as Error).message)
}
}
}
}
return descriptor
}
}
/**
* 方法接收参数验证装饰器
* @param {AnySchema | AnySchema[]} argumentSchemas
* @param {{strict?: boolean, stripUnknown?: boolean}} options
* @returns {(target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => any>) => TypedPropertyDescriptor<(...args: any[]) => any>}
* @constructor
*/
export const Accept = (argumentSchemas: AnySchema | AnySchema[], options: { strict?: boolean, stripUnknown?: boolean } = {
strict: false,
stripUnknown: true
}) => {
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<(...args: any[]) => any | Promise<any>>) => {
descriptor.writable = false
const originalMethod: (...args: any[]) => any | Promise<any> = descriptor.value as any
descriptor.value = function (...args: any[]) {
const schemas: AnySchema[] = Array.isArray(argumentSchemas) ? argumentSchemas : [argumentSchemas]
try {
for (let argumentIndex = 0; argumentIndex < schemas.length; argumentIndex++) {
args[argumentIndex] = schemas[argumentIndex].label(`Method [${propertyKey}] accept argument[${argumentIndex}]`).validateSync(args[argumentIndex], options)
}
} catch (e) {
if (target['generateException']) {
throw target['generateException'](InvalidMethodAcceptException, (e as Error).message)
} else {
throw new InvalidMethodAcceptException((e as Error).message)
}
}
return originalMethod.apply(this, args)
}
return descriptor
}
}