"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
exports.dangerousOperationIdReg = /_[0-9]{1,}$/g;
exports.defaultPrefixReg = /^(\/)?api\//g;
exports.defaultBadParamsReg = /[^a-z0-9_.$]/gi;
/**
 *
 * @param swagger json
 * @param savedMethodUrl2OperationIdMap  http method + url : oldOperationId 安全映射，用以校正风险 swagger
 */
function operationIdGuard(swagger, config) {
    if (config === void 0) { config = {}; }
    var _a = config.methodUrl2OperationIdMap, savedMethodUrl2OperationIdMap = _a === void 0 ? {} : _a, mode = config.mode, _b = config.prefixReg, prefixReg = _b === void 0 ? exports.defaultPrefixReg : _b, _c = config.badParamsReg, badParamsReg = _c === void 0 ? exports.defaultBadParamsReg : _c;
    var paths = swagger.paths;
    // http method + url => api info 映射
    var methodUrl2ApiMap = {};
    // operationId 匹配 _[0-9] 格式，及存在被 swagger
    var dangerousOperationId2ApiMap = {};
    var copySavedMethodUrl2OperationIdMap = tslib_1.__assign({}, savedMethodUrl2OperationIdMap);
    // @cc: 风险日志
    var errors = [];
    // @cc: 根据锁定关系自动校正日志
    var warnings = [];
    // @cc: 自动推断出来的锁定映射关系
    var suggestions = {};
    var isSafe = mode === 'safe';
    var isStrict = mode === 'strict';
    // @cc: 新项目，检测 tags 是否符合规范
    var dangers = Object.keys(Object.keys(paths).reduce(function (dangers, url) {
        var apiItem = paths[url];
        Object.keys(apiItem).forEach(function (method) {
            var api = apiItem[method];
            var operationId = api.operationId, _a = api.parameters, parameters = _a === void 0 ? [] : _a;
            // @cc: 扫描参数名字
            parameters.forEach(function (_a) {
                var _b = _a.name, name = _b === void 0 ? '' : _b, pType = _a.in, _c = _a.description, description = _c === void 0 ? '' : _c;
                if (name.match(badParamsReg)) {
                    errors.push("\u3010\u9519\u8BEF\u3011\u63A5\u53E3 \"" + method + " " + url + "\" \"" + pType + "\" \u53C2\u6570 \"" + name + "\" \"" + description + "\" \u4E0D\u7B26\u5408\u89C4\u8303\uFF0C\u8BF7\u8054\u7CFB\u63A5\u53E3\u65B9\u4FEE\u6539");
                }
            });
            if (operationId) {
                // @cc: urlUsingMethod 作为 operationId
                api.privateOperationId =
                    url
                        .replace(prefixReg, '')
                        .replace(/(^\/|})/g, '')
                        .replace(/[/{-]{1,}([^/])/g, function (mat, u) { return u.toUpperCase(); }) +
                        'Using' +
                        method[0].toUpperCase() +
                        method.substring(1);
                var methodUrl = method.toLocaleLowerCase() + " " + url;
                api.privateMethodUrl = methodUrl;
                methodUrl2ApiMap[methodUrl] = api;
                var dangerousOperationId = operationId.replace(exports.dangerousOperationIdReg, '');
                if (("" + (operationId || '')).match(exports.dangerousOperationIdReg)) {
                    dangers[dangerousOperationId] = '';
                }
                dangerousOperationId2ApiMap[dangerousOperationId] =
                    dangerousOperationId2ApiMap[dangerousOperationId] || [];
                dangerousOperationId2ApiMap[dangerousOperationId].push(api);
            }
        });
        return dangers;
    }, {}));
    if (errors.length) {
        return {
            errors: errors,
            warnings: warnings,
            suggestions: []
        };
    }
    var validateThrowAndFix = function (api) {
        var _a = api.operationId, operationId = _a === void 0 ? '' : _a, _b = api.privateMethodUrl, privateMethodUrl = _b === void 0 ? '' : _b;
        var savedOperationId = copySavedMethodUrl2OperationIdMap[privateMethodUrl];
        if (!savedOperationId) {
            errors.push("\u3010\u9519\u8BEF\u3011\u65B9\u6CD5 \"" + operationId + "\" & \"" + privateMethodUrl + "\" \u5B58\u5728\u4E0D\u53EF\u63A7\u98CE\u9669\uFF0C\u9700\u9501\u5B9A\u6620\u5C04\u5173\u7CFB");
            suggestions[privateMethodUrl] = operationId;
        }
        else if (savedOperationId !== operationId) {
            /**
             * 尝试自动人工干涉
             *  干涉配置:
             *    get /api/get   => get
             *    get /api/get-1 => get_1
             *  实际返回
             *    get /api/get   => get_1
             *    get /api/get-1 => get
             *  干涉结果
             *    get /api/get   => get
             *    get /api/get-1 => get_1
             */
            warnings.push("\u3010\u8B66\u544A\u3011\u65B9\u6CD5 \"" + operationId + "\" \u4E0E \"" + privateMethodUrl + "\" \u4E0D\u5339\u914D\uFF0C\u81EA\u52A8\u7EA0\u6B63\u4E3A \"" + savedOperationId + "\"");
            api.operationId = savedOperationId;
            delete api.privateMethodUrl;
        } // else 映射关系匹配
        // @cc: 风险已处理
        delete copySavedMethodUrl2OperationIdMap[privateMethodUrl];
    };
    dangers.reduce(function (errors, dangerousOperationId) {
        var group = dangerousOperationId2ApiMap[dangerousOperationId];
        group.forEach(function (api) { return validateThrowAndFix(api); });
        return errors;
    }, errors);
    Object.keys(copySavedMethodUrl2OperationIdMap).reduce(function (errors, methodUrl) {
        // @cc: 人工干涉配置多于 swagger 配置
        var operationId = copySavedMethodUrl2OperationIdMap[methodUrl];
        var api = methodUrl2ApiMap[methodUrl];
        if (!api) {
            errors.push("\u3010\u9519\u8BEF\u3011\u65B9\u6CD5 \"" + operationId + "\" \u5BF9\u5E94\u7684 \"" + methodUrl + "\" \u4F3C\u4E4E\u5DF2\u88AB\u79FB\u9664\u6216\u8005\u53D1\u751F\u4E86\u53D8\u5316\uFF0C\u8BF7\u66F4\u65B0");
        }
        else {
            validateThrowAndFix(api);
        }
        return errors;
    }, errors);
    // @cc: 校正成功之后才可迁移
    if (!errors.length && !Object.keys(suggestions).length && (isSafe || isStrict)) {
        Object.keys(paths).forEach(function (url) {
            var apiItem = paths[url];
            Object.keys(apiItem).forEach(function (method) {
                var api = apiItem[method];
                var operationId = api.operationId, privateOperationId = api.privateOperationId;
                if (operationId) {
                    // @cc: urlUsingMethod 作为 operationId
                    api.operationId = privateOperationId;
                    suggestions[operationId] = privateOperationId;
                }
            });
        });
        return {
            errors: errors,
            warnings: warnings,
            suggestions: Object.keys(suggestions).length
                ? [
                    '旧 => 新 方法替换映射关系，请按建议顺序降序逐一替换',
                    Object.keys(suggestions)
                        .sort(function (a, b) {
                        return -(parseInt(a.split('_')[1]) || 0) + (parseInt(b.split('_')[1]) || 0);
                    })
                        .reduce(function (s, id) {
                        s[id] = suggestions[id];
                        return s;
                    }, {})
                ]
                : []
        };
    }
    return {
        errors: errors,
        warnings: warnings,
        suggestions: Object.keys(suggestions).length
            ? [
                '锁定映射建议，添加到 service 配置',
                {
                    guardConfig: {
                        methodUrl2OperationIdMap: suggestions
                    }
                }
            ]
            : []
    };
}
exports.operationIdGuard = operationIdGuard;
// @cc: 检测是否手写了 tags
exports.InstableTagsReg = /^[a-z-0-9_$A-Z]+-controller$/g;
// @cc: 检测是否全英文
exports.validTagsReg = /^[a-z-0-9_$]+$/gi;
exports.validDefinitionReg = /^[a-z-0-9_$«»]+$/gi;
function strictModeGuard(swagger, config) {
    var _a = swagger.tags, tags = _a === void 0 ? [] : _a, _b = swagger.definitions, definitions = _b === void 0 ? {} : _b;
    var mode = config.mode;
    var info = {
        errors: Array(),
        warnings: Array()
    };
    if (mode === 'strict') {
        // @cc: tags 是否符合规范
        tags.reduce(function (errors, tag) {
            var _a = tag.name, name = _a === void 0 ? '' : _a;
            if (name.match(exports.InstableTagsReg)) {
                errors.push("\u3010\u9519\u8BEF\u3011 tags \"" + JSON.stringify(tag, null, 2) + "\" \u547D\u540D\u4E0D\u7B26\u5408\u89C4\u8303\u6216\u7531\u4E8E @Api \u88C5\u9970\u5668\u672A\u6DFB\u52A0 tags\uFF0C\u5B58\u5728\u4E0D\u53EF\u63A7\u98CE\u9669\uFF0C\u8BF7\u8054\u7CFB\u63A5\u53E3\u65B9\u4FEE\u6539");
            }
            if (!name.match(exports.validTagsReg)) {
                errors.push("\u3010\u9519\u8BEF\u3011 tags \"" + JSON.stringify(tag, null, 2) + "\" \u547D\u540D\u5305\u542B\u975E\u82F1\u6587\u5B57\u7B26\uFF0C@Api \u88C5\u9970\u5668\u4E0D\u80FD\u6DFB\u52A0\u975E\u6CD5 tags\uFF0C\u8BF7\u8054\u7CFB\u63A5\u53E3\u65B9\u4FEE\u6539");
            }
            return errors;
        }, info.errors);
        // @cc: definitions 是否符合规范
        Object.keys(definitions).reduce(function (errors, dto) {
            if (!dto.match(exports.validDefinitionReg)) {
                errors.push("\u3010\u9519\u8BEF\u3011 definitions name - DTO \"" + dto + "\" \u547D\u540D\u5305\u542B\u975E\u82F1\u6587\u5B57\u7B26\uFF0C\u8BF7\u8054\u7CFB\u63A5\u53E3\u65B9\u4FEE\u6539");
            }
            return errors;
        }, info.errors);
    }
    return Promise.resolve(info);
}
exports.strictModeGuard = strictModeGuard;
//# sourceMappingURL=guard.js.map