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
157 lines (156 loc) • 8.29 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const prompts_1 = require("@clack/prompts");
const commander_1 = require("commander");
const lodash_1 = require("lodash");
const path_1 = require("path");
const pkg = tslib_1.__importStar(require("../../package.json"));
const index_1 = require("../index");
const log_1 = require("../log");
const readConfig_1 = require("../readConfig");
const utils_1 = require("./utils");
const params = commander_1.program
.name('openapi')
.usage('[options]')
.version(pkg.version)
.option('-i, --input <string>', 'OpenAPI specification, can be a path, url')
.option('-o, --output <string>', 'output directory')
.option('-cfn, --configFileName <string>', 'config file name')
.option('-cfp, --configFilePath <string>', 'config file path')
.option('--requestLibPath <string>', 'custom request lib path, for example: "@/request", "node-fetch" (default: "axios")')
.option('--isSplitTypesByModule <boolean>', 'split types by module, generates {module}.type.ts, common.type.ts, enum.ts, types.ts', false)
.option('-f, --full <boolean>', 'full replacement', true)
.option('--enableLogging <boolean>', 'open the log', false)
.option('--priorityRule <string>', 'priority rule, include/exclude/both (default: "include")')
.option('--filterCaseInsensitive <boolean>', 'whether to perform a case-insensitive match with includeTags, includePaths, excludeTags, excludePaths filters', false)
.option('--includeTags <(string|RegExp)[]>', 'generate code from include tags')
.option('--includePaths <(string|RegExp)[]>', 'generate code from include paths')
.option('--excludeTags <(string|RegExp)[]>', 'generate code from exclude tags')
.option('--excludePaths <(string|RegExp)[]>', 'generate code from exclude paths')
.option('--requestOptionsType <string>', 'custom request method options parameter type (default: "{ [key: string]: unknown }")')
.option('--requestImportStatement <string>', `custom request import statement, for example: "const request = require('@/request')"`)
.option('--apiPrefix <string>', `custom the prefix of the api path, for example: "api"(variable), "'api'"(string)`)
.option('--isGenReactQuery <boolean>', 'generate react-query', false)
.option('--reactQueryMode <string>', 'react-query mode, react/vue (default: "react")')
.option('--isGenJavaScript <boolean>', 'generate JavaScript', false)
.option('--isDisplayTypeLabel <boolean>', 'generate label matching type field', false)
.option('--isGenJsonSchemas <boolean>', 'generate JSON Schemas', false)
.option('--mockFolder <string>', 'mock file path')
.option('--authorization <string>', 'docs authorization')
.option('--nullable <boolean>', 'null instead of optional', false)
.option('--isTranslateToEnglishTag <boolean>', 'translate chinese tag name to english tag name', false)
.option('--isOnlyGenTypeScriptType <boolean>', 'only generate typescript type', false)
.option('--isCamelCase <boolean>', 'camelCase naming of controller files and request client', true)
.option('--isSupportParseEnumDesc <boolean>', 'parse enum description to generate enum label', false)
.option('--supportParseEnumDescByReg <string>', 'custom regex for parsing enum description')
.option('-i, --interactive <boolean>', 'enable interactive mode', true)
.parse(process.argv)
.opts();
function getPath(path) {
const isUrl = path.startsWith('http');
if (isUrl) {
return path;
}
return (0, path_1.join)(process.cwd(), path);
}
const baseGenerate = (_params_) => {
const input = getPath(_params_.input);
const output = getPath(_params_.output);
const options = {
schemaPath: input,
serversPath: output,
requestLibPath: _params_.requestLibPath,
full: JSON.parse(_params_.full) === true,
enableLogging: JSON.parse(_params_.enableLogging) === true,
priorityRule: _params_.priorityRule,
filterCaseInsensitive: JSON.parse(_params_.filterCaseInsensitive) === true,
includeTags: _params_.includeTags,
includePaths: _params_.includePaths,
excludeTags: _params_.excludeTags,
excludePaths: _params_.excludePaths,
requestOptionsType: _params_.requestOptionsType,
apiPrefix: _params_.apiPrefix,
isGenReactQuery: JSON.parse(_params_.isGenReactQuery) === true,
reactQueryMode: _params_.reactQueryMode,
isGenJavaScript: JSON.parse(_params_.isGenJavaScript) === true,
isDisplayTypeLabel: JSON.parse(_params_.isDisplayTypeLabel) === true,
isGenJsonSchemas: JSON.parse(_params_.isGenJsonSchemas) === true,
mockFolder: _params_.mockFolder,
authorization: _params_.authorization,
nullable: JSON.parse(_params_.nullable) === true,
isTranslateToEnglishTag: JSON.parse(_params_.isTranslateToEnglishTag) === true,
isOnlyGenTypeScriptType: JSON.parse(_params_.isOnlyGenTypeScriptType) === true,
isCamelCase: JSON.parse(_params_.isCamelCase) === true,
isSupportParseEnumDesc: JSON.parse(_params_.isSupportParseEnumDesc) === true,
supportParseEnumDescByReg: _params_.supportParseEnumDescByReg,
isSplitTypesByModule: JSON.parse(_params_.isSplitTypesByModule) === true,
};
return options;
};
function run() {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
if (params.input && params.output) {
const options = baseGenerate(params);
yield (0, index_1.generateService)((0, lodash_1.pickBy)(options, (value) => value !== null && value !== undefined && value !== ''));
process.exit(0);
}
const cnf = yield (0, readConfig_1.readConfig)({
fallbackName: 'openapi-ts-request',
filePath: params.configFilePath,
fileName: params.configFileName,
});
try {
if (cnf) {
const tasks = [];
let configs = Array.isArray(cnf) ? cnf : [cnf];
/** 是否交互式 */
let isInteractive = false;
if (configs.length > 1 && (0, utils_1.parseInteractiveMode)(params.interactive)) {
// 有多个配置,则交互式选择
isInteractive = true;
console.log(''); // 添加一个空行
(0, prompts_1.intro)('🎉 欢迎使用 openapi-ts-request 生成器');
const selected = yield (0, prompts_1.multiselect)({
message: '请选择要生成的 service',
options: (0, utils_1.createMultiselectOptions)(configs),
});
if ((0, prompts_1.isCancel)(selected)) {
(0, prompts_1.cancel)('👋 Has cancelled');
process.exit(0);
}
configs = selected;
}
for (const config of configs) {
tasks.push((0, index_1.generateService)(config));
}
const results = yield Promise.allSettled(tasks);
let errorMsg = '';
for (let i = 0; i < results.length; i++) {
const result = results[i];
if (result.status === 'rejected') {
const cnf = configs[i];
const label = cnf.describe ||
('schemaPath' in cnf ? cnf.schemaPath : 'Apifox Config');
errorMsg += `${label}${label && ':'}${result.reason}\n`;
}
}
if (errorMsg) {
throw new Error(errorMsg);
}
if (isInteractive && !errorMsg) {
(0, prompts_1.outro)('🎉 All done!');
}
}
else {
throw new Error('Please provide either input/output options or a configuration file path and name.');
}
}
catch (error) {
(0, log_1.logError)(error);
process.exit(1);
}
});
}
void run();