"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Router = require("@koa/router");
const Joi = require("joi");
const cnMessages = require("joi-messages-zh_cn");
const messages = cnMessages['zh-cn'];
/**
 * Joi路由
 */
class JoiRouter {
    constructor() {
        this.routes = [];
        this.router = new Router();
    }
    use(middleware) {
        this.router.use(middleware);
    }
    /**
     * Return koa middleware
     * @return {Function}
     * @api public
     */
    middleware() {
        return this.router.middleware();
    }
    /**
     * 添加路由
     * @param spec
     */
    addRouter(spec) {
        this.routes.push(spec);
        const router = this.router;
        const validator = makeValidator(spec);
        const handlers = [validator, spec.handler];
        router[spec.method.toLowerCase()](spec.path, ...(spec.pre != undefined ? [spec.pre, ...handlers] : handlers));
    }
    /**
     * 路由前缀
     * @param prefix
     */
    prefix(prefix) {
        return this.router.prefix(prefix);
    }
}
exports.default = JoiRouter;
/**
 * 校验中间价
 * @param spec
 */
function makeValidator(spec) {
    const props = ['header', 'query', 'params', 'body', 'files'];
    return async function validator(ctx, next) {
        if (!spec.validate)
            return await next();
        for (let i = 0; i < props.length; ++i) {
            const prop = props[i];
            if (spec.validate[prop]) {
                //当处于文件上传时，body是没有值的，将form表单的值fields赋给body
                if (prop === 'body' && spec.validate.type === 'multipart') {
                    ctx.request.body = ctx.fields;
                }
                const err = validateInput(prop, ctx, spec.validate);
                if (err) {
                    return ctx.throw(err);
                }
            }
        }
        await next();
    };
}
/**
 * 校验输入参数
 * @param prop
 * @param ctx
 * @param validate
 */
function validateInput(prop, ctx, validate) {
    const request = ctx.request;
    let requestElement;
    const validateElement = validate[prop];
    if (prop === 'files') {
        requestElement = {};
        Object.keys(validateElement).forEach(key => {
            requestElement[key] =
                ctx.files != undefined
                    ? ctx.files.filter(f => f.fieldName === key).map(f => f.fileName)
                    : [];
        });
    }
    else {
        requestElement = request[prop];
    }
    const res = Joi.compile(validateElement).validate(requestElement, {
        messages: messages,
        allowUnknown: true,
    });
    if (res.error) {
        return res.error;
    }
    // update our request w/ the casted values
    switch (prop) {
        case 'header': // request.header is getter only, cannot set it
        case 'query': // setting request.query directly causes casting back to strings
            Object.keys(res.value).forEach(key => {
                request[prop][key] = res.value[key];
            });
            break;
        case 'params':
            request.params = ctx.params = res.value;
            break;
        default:
            request[prop] = res.value;
    }
}
//# sourceMappingURL=joi.router.js.map