UNPKG

openapi-ts-request

Version:

Swagger2/OpenAPI3/Apifox to TypeScript/JavaScript, request client(support any client), request mock service, enum and enum translation, react-query/vue-query, type field label, JSON Schemas

274 lines (273 loc) 10.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.camelCase = exports.getOpenAPIConfig = exports.getOpenAPIConfigByApifox = exports.getImportStatement = void 0; exports.parseSwaggerOrOpenapi = parseSwaggerOrOpenapi; exports.translateChineseModuleNodeToEnglish = translateChineseModuleNodeToEnglish; const tslib_1 = require("tslib"); const axios_1 = tslib_1.__importDefault(require("axios")); const bing_translate_api_1 = require("bing-translate-api"); const http_1 = tslib_1.__importDefault(require("http")); const https_1 = tslib_1.__importDefault(require("https")); const yaml = tslib_1.__importStar(require("js-yaml")); const lodash_1 = require("lodash"); const node_fs_1 = require("node:fs"); const swagger2openapi_1 = tslib_1.__importDefault(require("swagger2openapi")); const log_1 = tslib_1.__importStar(require("./log")); const getImportStatement = (requestLibPath) => { if (requestLibPath) { if (requestLibPath.startsWith('import')) { return requestLibPath; } return `import request from '${requestLibPath}';`; } return `import { request } from 'axios';`; }; exports.getImportStatement = getImportStatement; const getApifoxIncludeTags = (tags) => { let _tags_ = '*'; if (tags && Array.isArray(tags)) { if (!tags.length) { return '*'; } _tags_ = []; for (const tag of tags) { if (typeof tag === 'string') { if (tag === '*') { _tags_ = '*'; break; } } else if (tag instanceof RegExp) { _tags_ = '*'; break; // TODO:后期添加支持判断字符串是否为正则 } else { _tags_.push(tag); } } } else if (tags) { _tags_ = [tags]; } return _tags_; }; /** * 通过 apifox 获取 openapi 文档 * @param params {object} * @param params.projectId {string} 项目 id * @param params.locale {string} 语言 * @param params.apifoxVersion {string} apifox 版本 目前固定为 2024-03-28 可通过 https://api.apifox.com/v1/versions 获取最新版本 * @returns */ const getSchemaByApifox = (_a) => tslib_1.__awaiter(void 0, [_a], void 0, function* ({ projectId, locale = 'zh-CN', apifoxVersion = '2024-03-28', includeTags, excludeTags = [], apifoxToken, oasVersion = '3.0', exportFormat = 'JSON', includeApifoxExtensionProperties = false, addFoldersToTags = false, }) { try { const body = { scope: { excludeTags, }, options: { includeApifoxExtensionProperties, addFoldersToTags, }, oasVersion, exportFormat, }; const tags = getApifoxIncludeTags(includeTags); if (tags === '*') { body.scope.type = 'ALL'; } else { body.scope.type = 'SELECTED_TAGS'; body.scope.includeTags = tags; } const res = yield axios_1.default.post(`https://api.apifox.com/v1/projects/${projectId}/export-openapi?locale=${locale}`, body, { headers: { 'X-Apifox-Api-Version': apifoxVersion, Authorization: `Bearer ${apifoxToken}`, }, }); return res.data; } catch (error) { (0, log_1.logError)('fetch openapi error:', error); return null; } }); function getSchema(schemaPath, authorization, timeout) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (schemaPath.startsWith('http')) { const isHttps = schemaPath.startsWith('https:'); const protocol = isHttps ? https_1.default : http_1.default; try { const agent = new protocol.Agent({ rejectUnauthorized: false, }); const config = isHttps ? { httpsAgent: agent } : { httpAgent: agent }; const json = yield axios_1.default .get(schemaPath, Object.assign(Object.assign({}, config), { headers: { authorization }, timeout })) .then((res) => res.data); return json; } catch (error) { console.log('fetch openapi error:', error); } return; } if (require.cache[schemaPath]) { delete require.cache[schemaPath]; } let schema = ''; try { schema = (yield require(schemaPath)); } catch (_a) { try { schema = (0, node_fs_1.readFileSync)(schemaPath, 'utf8'); } catch (error) { console.error('Error reading schema file:', error); } } return schema; }); } function converterSwaggerToOpenApi(swagger) { return new Promise((resolve, reject) => { const convertOptions = { patch: true, warnOnly: true, resolveInternal: true, }; // options.patch = true; // fix up small errors in the source definition // options.warnOnly = true; // Do not throw on non-patchable errors // options.warnOnly = true; // enable resolution of internal $refs, also disables deduplication of requestBodies swagger2openapi_1.default.convertObj(swagger, convertOptions, (err, options) => { (0, log_1.default)(['💺 将 Swagger 转化为 openAPI']); if (err) { return reject(err); } resolve(options.openapi); }); }); } const getOpenAPIConfigByApifox = (props) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const schema = yield getSchemaByApifox(props); if (!schema) { return; } return yield parseSwaggerOrOpenapi(schema); }); exports.getOpenAPIConfigByApifox = getOpenAPIConfigByApifox; const getOpenAPIConfig = (schemaPath, authorization, timeout) => tslib_1.__awaiter(void 0, void 0, void 0, function* () { const schema = yield getSchema(schemaPath, authorization, timeout); if (!schema) { return; } const openAPI = yield parseSwaggerOrOpenapi(schema); return openAPI; }); exports.getOpenAPIConfig = getOpenAPIConfig; function parseSwaggerOrOpenapi(content) { return tslib_1.__awaiter(this, void 0, void 0, function* () { let openapi = {}; if ((0, lodash_1.isObject)(content)) { openapi = content; // if is swagger2.0 json, covert swagger2.0 to openapi3.0 if (openapi.swagger) { openapi = yield converterSwaggerToOpenApi(openapi); } } else { if (isJSONString(content)) { openapi = JSON.parse(content); } else { openapi = yaml.load(content); } if (openapi.swagger) { openapi = yield converterSwaggerToOpenApi(openapi); } } return openapi; }); } function isJSONString(str) { try { JSON.parse(str); return true; } catch (error) { return false; } } function translateChineseModuleNodeToEnglish(openAPI) { return tslib_1.__awaiter(this, void 0, void 0, function* () { return new Promise((resolve, reject) => { const translateMap = {}; const operations = []; let tags = []; (0, lodash_1.forEach)((0, lodash_1.keys)(openAPI.paths), (path) => { const pathItemObject = openAPI.paths[path]; (0, lodash_1.forEach)((0, lodash_1.keys)(pathItemObject), (method) => { if (pathItemObject[method]) { const operation = pathItemObject[method]; operations.push(operation); tags = tags.concat(operation.tags); } }); }); void Promise.all((0, lodash_1.map)((0, lodash_1.uniq)(tags), (tagName) => { return new Promise((resolve) => { if (tagName && /[\u3220-\uFA29]/.test(tagName)) { void (0, bing_translate_api_1.translate)(tagName, null, 'en') .then((translateRes) => { const text = (0, exports.camelCase)(translateRes === null || translateRes === void 0 ? void 0 : translateRes.translation); if (text) { translateMap[tagName] = text; resolve(text); } }) .catch(() => { resolve(tagName); }); } else { resolve(tagName); } }); })) .then(() => { (0, lodash_1.forEach)(operations, (operation) => { (0, lodash_1.forEach)(operation.tags, (tagName, index) => { if (translateMap[tagName]) { operation.tags[index] = translateMap[tagName]; } }); }); resolve(true); }) .catch(() => { reject(false); }); }); }); } /** * Converts a string to camelCase format, with an option to capitalize the first letter. * 将字符串转换为驼峰格式,并可以选择将首字母大写。 * * @param {string} str - The string to convert. * @param {string} str - 要转换的字符串。 * * @param {boolean} [upper=false] - Whether to capitalize the first letter of the resulting string. * @param {boolean} [upper=false] - 是否将结果字符串的首字母大写。 * * @returns {string} The camelCase formatted string, optionally with a capitalized first letter. * @returns {string} 返回驼峰格式的字符串,可选择首字母大写。 */ const camelCase = (str, upper = false) => { const res = (0, lodash_1.camelCase)(str); return upper ? res.charAt(0).toUpperCase() + res.slice(1) : res; }; exports.camelCase = camelCase;