Skip to content

Commit

Permalink
feat: add openApi code
Browse files Browse the repository at this point in the history
  • Loading branch information
MriLiuJY committed Jun 2, 2023
1 parent 48b2be5 commit 6db1947
Show file tree
Hide file tree
Showing 16 changed files with 2,301 additions and 12 deletions.
29 changes: 28 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,21 @@
"license": "MIT",
"devDependencies": {
"@types/conventional-changelog": "^3.1.1",
"@types/express": "^4.17.11",
"@types/fs-extra": "^9.0.13",
"@types/inquirer": "^8.2.0",
"@types/lodash": "^4.14.195",
"@types/memoizee": "^0.4.8",
"@types/mockjs": "^1.0.7",
"@types/node": "^18.13.0",
"@types/npmlog": "^4.1.4",
"@types/nunjucks": "^3.2.2",
"@types/ora": "^3.2.0",
"@types/prettier": "^2.2.1",
"@types/reserved-words": "^0.1.0",
"@types/rimraf": "^4.0.5",
"@types/shelljs": "^0.8.11",
"@types/swagger2openapi": "^7.0.0",
"@typescript-eslint/eslint-plugin": "^5.10.2",
"@typescript-eslint/parser": "^5.10.2",
"@umijs/fabric": "^3.0.0",
Expand All @@ -34,6 +43,7 @@
"eslint-plugin-import": "^2.25.4",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.2.0",
"np": "^7.2.0",
"rimraf": "^3.0.2",
"tslib": "^2.3.1",
"typescript": "^4.5.5"
Expand All @@ -45,20 +55,37 @@
"@commitlint/config-conventional": "^17.4.4",
"@commitlint/lint": "^17.4.4",
"@commitlint/load": "^17.5.0",
"@umijs/fabric": "^2.5.6",
"axios": "^1.3.3",
"chalk": "^4.1.2",
"commander": "^9.0.0",
"commitizen": "^4.2.5",
"conventional-changelog": "^3.1.25",
"cz-conventional-changelog": "^3.3.0",
"dayjs": "^1.10.3",
"download-git-repo": "^3.0.2",
"eslint": "^7.18.0",
"execa": "^5.1.1",
"fs-extra": "^10.0.0",
"glob": "^7.1.6",
"inquirer": "^8.2.0",
"lodash": "^4.17.21",
"memoizee": "^0.4.15",
"minimist": "^1.2.6",
"mock.js": "^0.2.0",
"mockjs": "^1.1.0",
"node-fetch": "^3.3.1",
"npmlog": "^7.0.1",
"nunjucks": "^3.2.4",
"openapi3-ts": "^2.0.1",
"ora": "^5.4.1",
"prettier": "^2.8.8",
"reserved-words": "^0.1.2",
"rimraf": "^3.0.2",
"semver": "^7.3.8",
"simple-git": "^3.16.1"
"simple-git": "^3.16.1",
"swagger2openapi": "^7.0.8",
"tiny-pinyin": "^1.3.2"
},
"repository": {
"type": "git",
Expand Down
11 changes: 10 additions & 1 deletion src/bin/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Command } from 'commander';
import create from '../commands/create/index';
import cz from '../commands/cz';
import publish from '../commands/publish';
// import init from '../commands/init';
import { generateService } from '../commands/openapi/index';
import { checkLogin, checkVersion, log, PREFIX } from '../utils/index';

const program = new Command();
Expand Down Expand Up @@ -47,6 +47,15 @@ program
await publish();
});

// ---------- openApi ----------
program
.command('openapi')
.description('openapi 自动生成 service')
.action(() => {
generateService();
});


// ---------- 这里设置的是全局配置 ----------
program
.name(Object.keys(pkg.bin)[0])
Expand Down
168 changes: 168 additions & 0 deletions src/commands/openapi/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
import http from 'http';
import https from 'https';
import fetch from 'node-fetch';
import converter from 'swagger2openapi';
import type { OperationObject, SchemaObject } from 'openapi3-ts';
import type { Options as prettierOptions } from 'prettier';

import Log from './log';
import { mockGenerator } from './mockGenerator';
import { ServiceGenerator } from './serviceGenerator';

const getImportStatement = (requestLibPath: string) => {
if (requestLibPath && requestLibPath.startsWith('import')) {
return requestLibPath;
}
if (requestLibPath) {
return `import request from '${requestLibPath}'`;
}
return `import { request } from "umi"`;
};

export type GenerateServiceProps = {
requestLibPath?: string;
requestImportStatement?: string;
/**
* api 的前缀
*/
apiPrefix?:
| string
| ((params: {
path: string;
method: string;
namespace: string;
functionName: string;
autoExclude?: boolean;
}) => string);
/**
* 生成的文件夹的路径
*/
serversPath?: string;
/**
* Swagger 2.0 或 OpenAPI 3.0 的地址
*/
schemaPath?: string;
/**
* 项目名称
*/
projectName?: string;

hook?: {
/** 自定义函数名称 */
customFunctionName?: (data: OperationObject) => string;
/** 自定义类型名称 */
customTypeName?: (data: OperationObject) => string;
/** 自定义类名 */
customClassName?: (tagName: string) => string;
/** 自定义swagger ref类型 */
customRefType?: (data: {
schemaName: string;
typeName: string;
props: (SchemaObject & { name: string; type: string; desc: string; required: string })[];
}) => (SchemaObject & { name: string; type: string; desc: string; required: string })[];
};

namespace?: string;

mockFolder?: string;
/**
* 模板文件的文件路径
*/
templatesFolder?: string;

/**
* 枚举样式
*/
enumStyle?: 'string-literal' | 'enum';

/**
* 增量修改
*/
increment?: {
/** 类型增量 */
types?: boolean;

/** controller 白名单增量 */
includes?: string[];

// /** controller 黑名单 */
// excludes?: string[];
};

/** 自定义 prettier 选项 */
prettierOptions?: prettierOptions;
};

const converterSwaggerToOpenApi = (swagger: any) => {
if (!swagger.swagger) {
return swagger;
}
return new Promise((resolve, reject) => {
converter.convertObj(swagger, {}, (err, options) => {
Log(['💺 将 Swagger 转化为 openAPI']);
if (err) {
reject(err);
return;
}
resolve(options.openapi);
});
});
};

export const getSchema = async (schemaPath: string) => {
if (schemaPath.startsWith('http')) {
const protocol = schemaPath.startsWith('https:') ? https : http;
try {
const agent = new protocol.Agent({
rejectUnauthorized: false,
});
const json = await fetch(schemaPath, { agent }).then((rest) => rest.json());
return json;
} catch (error) {
// eslint-disable-next-line no-console
console.log('fetch openapi error:', error);
}
return null;
}
const schema = require(schemaPath);
return schema;
};

const getOpenAPIConfig = async (schemaPath: string) => {
const schema = await getSchema(schemaPath);
if (!schema) {
return null;
}
const openAPI = await converterSwaggerToOpenApi(schema);
return openAPI;
};

// 从 appName 生成 service 数据
export const generateService = async ({
requestLibPath,
schemaPath,
mockFolder,
...rest
}: GenerateServiceProps) => {
const openAPI = await getOpenAPIConfig(schemaPath);
const requestImportStatement = getImportStatement(requestLibPath);
const serviceGenerator = new ServiceGenerator(
{
namespace: 'API',
requestImportStatement,
enumStyle: 'string-literal',
...rest,
},
openAPI,
);
serviceGenerator.genFile();

if (mockFolder) {
await mockGenerator({
openAPI,
mockFolder: mockFolder || './mocks/',
});
}
};
6 changes: 6 additions & 0 deletions src/commands/openapi/log.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import chalk from 'chalk';

// eslint-disable-next-line no-console
const Log = (...rest) => console.log(`${chalk.blue('[openAPI]')}: ${rest.join('\n')}`);

export default Log;
Loading

0 comments on commit 6db1947

Please sign in to comment.