@alova/wormhole
Version:
More modern openAPI generating solution for alova.js
152 lines (151 loc) • 5.48 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPlatformOpenApiData = getPlatformOpenApiData;
exports.getOpenApiData = getOpenApiData;
const promises_1 = __importDefault(require("node:fs/promises"));
const node_path_1 = __importDefault(require("node:path"));
const import_fresh_1 = __importDefault(require("import-fresh"));
const js_yaml_1 = __importDefault(require("js-yaml"));
const swagger2openapi_1 = __importDefault(require("swagger2openapi"));
const helper_1 = require("../../../helper");
const utils_1 = require("../../../utils");
const supportedExtname = ['json', 'yaml'];
const supportedPlatformType = ['swagger'];
function isSwagger2(data) {
return !!data?.swagger;
}
// Parse local openapi files
async function parseLocalFile(url, projectPath = process.cwd()) {
const [, extname] = /\.([^.]+)$/.exec(url) ?? [];
if (!supportedExtname.includes(extname)) {
throw helper_1.logger.throwError(`Unsupported file type: ${extname}`, {
url,
projectPath,
});
}
switch (extname) {
case 'yaml': {
const file = await promises_1.default.readFile(node_path_1.default.resolve(projectPath, url), 'utf-8');
const data = js_yaml_1.default.load(file);
return data;
}
// Json
default: {
const data = (0, import_fresh_1.default)(node_path_1.default.resolve(projectPath, url));
return data;
}
}
}
// Parse remote openapi files
async function parseRemoteFile(url, platformType) {
// no extension and platform types
if (platformType) {
return getPlatformOpenApiData(url, platformType);
}
const dataText = (await (0, utils_1.fetchData)(url)) ?? '';
let data;
try {
// 尝试解析为 JSON 格式
data = JSON.parse(dataText);
}
catch (jsonError) {
try {
// 若 JSON 解析失败,尝试解析为 YAML 格式
data = js_yaml_1.default.load(dataText);
}
catch (yamlError) {
throw helper_1.logger.throwError(`Only JSON and YAML formats are supported. Parsing failed:
${jsonError instanceof Error ? jsonError.message : String(jsonError)}
${yamlError instanceof Error ? yamlError.message : String(yamlError)}`, {
url,
});
}
}
// Validate if the data is valid (prevent server from returning error responses)
if (!isValidOpenApiData(data)) {
throw new Error(`Data retrieved from URL ${url} is not a valid OpenAPI document`);
}
return data;
}
// Parse platform openapi files
function isValidOpenApiData(data) {
if (!data || typeof data !== 'object') {
return false;
}
// Check if it's an error response format (e.g., {"code": -1, "msg": "URL does not exist", "data": null})
if (data.code !== undefined && data.msg !== undefined) {
return false;
}
// Check if it contains required OpenAPI/Swagger structure
return !!(data.openapi || data.swagger || data.info || data.paths);
}
async function getPlatformOpenApiData(url, platformType) {
if (!supportedPlatformType.includes(platformType)) {
throw helper_1.logger.throwError(`Platform type ${platformType} is not supported.`, {
url,
platformType,
});
}
switch (platformType) {
case 'swagger': {
const urlsToTry = [url, `${url}/openapi.json`, `${url}/v2/swagger.json`];
for (const tryUrl of urlsToTry) {
try {
const dataText = await (0, utils_1.fetchData)(tryUrl);
if (!dataText)
continue;
const data = JSON.parse(dataText);
if (isValidOpenApiData(data)) {
return data;
}
// If data is invalid, continue to next URL
}
catch {
// If request or parsing fails, continue to next URL
continue;
}
}
// If all URLs fail or return invalid data, throw error
throw helper_1.logger.throwError(`Unable to retrieve valid OpenAPI document from any URL: ${urlsToTry.join(', ')}`);
}
default:
break;
}
}
// Parse openapi files
async function getOpenApiData(url, projectPath, platformType) {
let data = null;
try {
if (!/^https?:\/\//.test(url)) {
// local file
data = await parseLocalFile(url, projectPath);
}
else {
// remote file
data = await parseRemoteFile(url, platformType);
}
// If it is a swagger2 file
if (isSwagger2(data)) {
data = (await swagger2openapi_1.default.convertObj(data, { warnOnly: true })).openapi;
}
}
catch (error) {
throw helper_1.logger.throwError(`Cannot read file from ${url}`, {
error: error.message,
projectPath,
url,
platformType,
});
}
if (!data) {
throw helper_1.logger.throwError(`Cannot read file from ${url}`, {
projectPath,
url,
platformType,
});
}
return data;
}