Skip to content

Commit 6b932f8

Browse files
committed
feat: 实现基本功能
1 parent a5b8ed4 commit 6b932f8

File tree

13 files changed

+402
-29
lines changed

13 files changed

+402
-29
lines changed

README.md

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,44 @@
22

33
OpenAPI Specification ➡️ TypeScript
44

5-
# 安装
5+
# Install
66

77
```shell
88
npm i -D oas-gen-ts
99
```
1010

11-
# 使用
11+
# Usage
1212

13-
## 命令行
13+
## CLI
14+
15+
Create oas.config.js or oas.json in the root directory of the project, and refer to [cosmiconfig](https://www.npmjs.com/package/cosmiconfig) for the file name specification.
16+
17+
```ts
18+
// oas.config.mjs
19+
export default defineConfig({
20+
axiosImport: `import { axios } from '@/util/axios';`,
21+
list: [
22+
{
23+
name: 'pet',
24+
url: 'https://petstore3.swagger.io/api/v3/openapi.json',
25+
},
26+
],
27+
});
28+
```
29+
30+
```shell
31+
# Generate typescript files based on configuration files
32+
npx oas-gen-ts
33+
34+
# The `src/apis/pet.ts` file will be generated
35+
```
1436

1537
## API
1638

17-
[](https://)
39+
```ts
40+
import { generate } from 'oas-gen-ts';
41+
42+
generate({
43+
// ...
44+
});
45+
```

bin/index.mjs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env node
2+
3+
import { start } from '../dist';
4+
5+
start();

package-lock.json

Lines changed: 28 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,17 @@
88
"test": "echo 'test success'",
99
"build": "echo 'build success'"
1010
},
11+
"engines": {
12+
"node": ">=16"
13+
},
14+
"engineStrict": true,
1115
"type": "module",
16+
"bin": {
17+
"oas-gen-ts": "bin/index.js"
18+
},
1219
"files": [
13-
"dist"
20+
"dist",
21+
"templates"
1422
],
1523
"keywords": [
1624
"cloudcome",
@@ -25,6 +33,7 @@
2533
"repository": "https://github.com/cloudcome/oas_ts",
2634
"license": "MIT",
2735
"dependencies": {
36+
"cosmiconfig": "^8.1.0",
2837
"swagger-typescript-api": "^12.0.3"
2938
},
3039
"devDependencies": {

src/configure.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { axiosImportDefault } from './const';
2+
import { Config, UserConfig } from './types';
3+
4+
export const defaults: Config = {
5+
cwd: process.cwd(),
6+
dest: 'src/apis',
7+
axiosImport: axiosImportDefault,
8+
list: [],
9+
};
10+
11+
export function defineConfig(config: UserConfig) {
12+
return Object.assign({}, defaults, config);
13+
}

src/const.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import path from 'node:path';
2+
3+
export const templatesDir = path.join(__dirname, '../templates');
4+
export const axiosImportDefault = `import { Axios } from 'axios';
5+
const axios = new Axios();`;
6+
export const helpersImport = `import { formatHeaders, formatBody } from 'oas-gen-ts/client'`;

src/generator.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { cosmiconfig } from 'cosmiconfig';
2+
import fs from 'node:fs/promises';
3+
import path from 'node:path';
4+
import { generateApi } from 'swagger-typescript-api';
5+
import { axiosImportDefault, helpersImport, templatesDir } from './const';
6+
import { Config, Oas } from './types';
7+
8+
export async function generateItem(oas: Oas, config: Config) {
9+
const { name, url, spec, axiosImport: axiosImportScope } = oas;
10+
const { cwd, dest, axiosImport: axiosImportGlobal } = config;
11+
const axiosImport = axiosImportScope || axiosImportGlobal || axiosImportDefault;
12+
const { files } = await generateApi({
13+
name,
14+
url,
15+
spec,
16+
output: false,
17+
httpClientType: 'axios',
18+
templates: templatesDir,
19+
});
20+
21+
for (const { content, name: filename } of files) {
22+
const contentFinal = [axiosImport, helpersImport, content].join('\n');
23+
const file = path.join(cwd, dest, filename);
24+
await fs.writeFile(file, contentFinal);
25+
}
26+
}
27+
28+
export async function generate(config: Config) {
29+
const { list } = config;
30+
31+
for (const oas of list) {
32+
await generateItem(oas, config);
33+
}
34+
}
35+
36+
export async function start() {
37+
const explorer = cosmiconfig('oas');
38+
const result = await explorer.search();
39+
40+
if (!result) {
41+
throw new Error('Could not find an oas config file');
42+
}
43+
44+
const config = result.config as Config;
45+
await generate(config);
46+
}

src/helpers.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { ContentKind } from './types';
2+
3+
/**
4+
* 格式化请求头
5+
* @param {ContentKind} contentKind
6+
* @returns {{"content-type": string} | {}}
7+
*/
8+
export function formatHeaders(contentKind: ContentKind) {
9+
const contentType = {
10+
[ContentKind.JSON]: 'application/json',
11+
[ContentKind.URL_ENCODED]: 'application/x-www-form-urlencoded',
12+
[ContentKind.FORM_DATA]: 'multipart/form-data',
13+
[ContentKind.TEXT]: 'text/plain',
14+
[ContentKind.OTHER]: '',
15+
}[contentKind];
16+
return contentType ? { 'content-type': contentType } : {};
17+
}
18+
19+
/**
20+
* 格式化请求体
21+
* @param {string} contentKind
22+
* @param data
23+
* @returns {FormData | string}
24+
*/
25+
export function formatBody(contentKind: ContentKind, data: any) {
26+
switch (contentKind) {
27+
case ContentKind.URL_ENCODED:
28+
return new URLSearchParams(data).toString();
29+
30+
case ContentKind.FORM_DATA: {
31+
return Object.keys(data).reduce((fd, key) => {
32+
const val = data[key];
33+
const isFileType = val instanceof Blob || val instanceof File;
34+
const isString = typeof val === 'string' || typeof val === 'number';
35+
fd.append(key, isFileType ? val : isString ? String(val) : JSON.stringify(val));
36+
return fd;
37+
}, new FormData());
38+
}
39+
40+
default:
41+
return JSON.stringify(data);
42+
}
43+
}

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
//
2-
export {};
1+
export * from './generator';
2+
export * from './configure';

src/types.ts

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
interface OasBase {
2+
name: string;
3+
4+
/**
5+
* 全局导入 axios 客户端,优先级低于每个 oas 配置,默认从 axios 官方导入,导入名称必须为 axios,例如
6+
* ```
7+
* import { axios } from '@/utils/axios';
8+
* ```
9+
*/
10+
axiosImport?: string;
11+
}
12+
13+
interface OasAsUrl extends OasBase {
14+
url: string;
15+
}
16+
17+
interface OasAsSpec extends OasBase {
18+
spec: import('swagger-schema-official').Spec;
19+
}
20+
21+
export interface Oas extends OasAsUrl, OasAsSpec {}
22+
23+
export interface UserConfig {
24+
/**
25+
* 工作目录,默认为 process.cwd()
26+
*/
27+
cwd?: string;
28+
29+
/**
30+
* 生成文件目的地,默认为 src/apis
31+
*/
32+
dest?: string;
33+
34+
/**
35+
* 导入 axios 客户端,优先级高于全局配置,默认从 axios 官方导入,导入名称必须为 axios,例如
36+
* ```
37+
* import { axios } from '@/utils/axios';
38+
* ```
39+
*/
40+
axiosImport?: string;
41+
42+
/**
43+
* oas 列表
44+
*/
45+
list: Oas[];
46+
}
47+
48+
export type Config = Required<UserConfig>;
49+
50+
export enum ContentKind {
51+
JSON = 'JSON',
52+
URL_ENCODED = 'URL_ENCODED',
53+
FORM_DATA = 'FORM_DATA',
54+
TEXT = 'TEXT',
55+
OTHER = 'OTHER',
56+
}

0 commit comments

Comments
 (0)