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

157 lines (156 loc) 8.29 kB
#!/usr/bin/env node "use strict"; 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();