Skip to content

Commit 075db30

Browse files
authored
Merge pull request #54 from cloudcome/feat/v0.x
Feat/v0.x
2 parents c3efba4 + 5dc6106 commit 075db30

18 files changed

+1008
-67
lines changed
Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
1-
name: review
1+
name: code-review
22

33
on:
44
push:
55
pull_request:
66
schedule:
7-
# 每天凌晨 3 点
7+
# 每天凌晨 3 点(UTC)
88
- cron: '0 3 * * *'
99

1010
jobs:
11-
review:
11+
code-review:
1212
runs-on: ubuntu-latest
1313
steps:
14-
- name: 修改为中国时区
15-
run: |
14+
- run: |
1615
sudo rm /etc/localtime
1716
sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
1817
- uses: actions/checkout@v3
@@ -23,3 +22,7 @@ jobs:
2322
- run: npm ci
2423
- run: npm run lint
2524
- run: npm run test
25+
- uses: codacy/codacy-coverage-reporter-action@v1
26+
with:
27+
api-token: ${{ secrets.CODACY_API_TOKEN }}
28+
coverage-reports: coverage/lcov.info

.github/workflows/release.yml renamed to .github/workflows/release-please.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: release
1+
name: release-please
22

33
on:
44
push:
@@ -10,13 +10,9 @@ permissions:
1010
pull-requests: write
1111

1212
jobs:
13-
release:
13+
release-please:
1414
runs-on: ubuntu-latest
1515
steps:
16-
- name: 修改为中国时区
17-
run: |
18-
sudo rm /etc/localtime
19-
sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
2016
- uses: google-github-actions/release-please-action@v3
2117
id: release
2218
with:

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
---
44

5-
[![review][review-badge]][review-link] ![version][version-badge] ![license][license-badge]
5+
[![code-review][code-review-badge]][code-review-link] [![code-quality][code-quality-badge]][code-quality-link] ![version][version-badge] ![license][license-badge]
66

77
OpenAPI Specification ➡️ TypeScript
88

@@ -141,7 +141,9 @@ generate({
141141

142142
**At least one of `url` and `spec` exists**
143143

144-
[review-badge]: https://github.com/cloudcome/oas-gen-ts/actions/workflows/review.yml/badge.svg
145-
[review-link]: https://github.com/cloudcome/oas-gen-ts/actions/workflows/review.yml
144+
[code-review-badge]: https://github.com/cloudcome/oas-gen-ts/actions/workflows/code-review.yml/badge.svg
145+
[code-review-link]: https://github.com/cloudcome/oas-gen-ts/actions/workflows/code-review.yml
146+
[code-quality-badge]: https://app.codacy.com/project/badge/Grade/e788387e5e27472ba3b5003bf19aeea7
147+
[code-quality-link]: https://www.codacy.com/gh/cloudcome/oas-gen-ts/dashboard?utm_source=github.com&utm_medium=referral&utm_content=cloudcome/oas-gen-ts&utm_campaign=Badge_Grade
146148
[version-badge]: https://img.shields.io/npm/v/oas-gen-ts
147149
[license-badge]: https://img.shields.io/github/license/cloudcome/oas-gen-ts

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
"license": "MIT",
5555
"dependencies": {
5656
"chalk": "^4.1.2",
57-
"cosmiconfig": "^8.1.0",
5857
"lodash-es": "^4.17.21",
5958
"swagger-typescript-api": "^12.0.3"
6059
},

src/commands.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import chalk from 'chalk';
2+
import path from 'path';
3+
import * as process from 'process';
4+
import { defineConfig } from './configure';
5+
import { generate } from './generator';
6+
import { UserConfig } from './types';
7+
import { exitError, isFile, normalizeError, tryCatch } from './utils';
8+
9+
interface StartConfig {
10+
// 指定配置文件绝对路径
11+
configFile?: string;
12+
}
13+
14+
export const startConfigFiles = ['oas.config.cjs', 'oas.config.js', 'oas.json'];
15+
16+
export async function resolveConfigFile(cwd: string, configFile?: string) {
17+
if (configFile) {
18+
if (!(await isFile(path.join(configFile)))) {
19+
throw new Error(`指定配置文件 "${configFile}" 不存在`);
20+
}
21+
22+
return configFile;
23+
}
24+
25+
for (const file of startConfigFiles.values()) {
26+
if (await isFile(path.join(cwd, file))) {
27+
return file;
28+
}
29+
}
30+
}
31+
32+
export async function start(startConfig?: StartConfig) {
33+
const configFile = await resolveConfigFile(process.cwd(), startConfig?.configFile);
34+
35+
if (!configFile) {
36+
return exitError(`配置文件未找到,配置文件可以为 ${startConfigFiles.join('、')} 之一`);
37+
}
38+
39+
// eslint-disable-next-line @typescript-eslint/no-var-requires
40+
const [err, config] = await tryCatch<UserConfig>(require(configFile));
41+
42+
if (err) {
43+
return exitError(err.message);
44+
}
45+
46+
if (!config) {
47+
return exitError('配置文件内容可能为空');
48+
}
49+
50+
const strictConfig = defineConfig(config);
51+
52+
try {
53+
await generate(strictConfig, (generated, info) => {
54+
const { oasItem } = generated;
55+
const { index, length, done, start, end } = info;
56+
const width = Math.min(String(length).length, 2);
57+
const stepText = String(index + 1).padStart(width, '0');
58+
59+
if (done) {
60+
const past = end - start;
61+
console.log(
62+
chalk.cyanBright(`[${stepText}/${length}]`),
63+
'generated ',
64+
chalk.yellowBright(oasItem.name),
65+
chalk.gray(`${past}ms`)
66+
);
67+
} else {
68+
console.log(
69+
chalk.cyanBright(`[${stepText}/${length}]`),
70+
'generating',
71+
chalk.yellowBright(oasItem.name),
72+
chalk.gray('...')
73+
);
74+
}
75+
});
76+
} catch (err) {
77+
exitError(normalizeError(err).message);
78+
}
79+
}

src/configure.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export const defaults: StrictConfig = {
77
axiosImport: axiosImportDefault,
88
unwrapResponseData: false,
99
list: [],
10+
onGenerated: () => 0,
1011
};
1112

1213
export function defineConfig(config: UserConfig) {

src/generator.ts

Lines changed: 35 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,66 @@
1-
import chalk from 'chalk';
2-
import { cosmiconfig } from 'cosmiconfig';
31
import fs from 'fs/promises';
42
import path from 'path';
53
import { generateApi } from 'swagger-typescript-api';
6-
import { defineConfig } from './configure';
74
import { axiosImportDefault, helpersImport, templatesDir } from './const';
8-
import { StrictConfig, Oas, UserConfig } from './types';
9-
import { exitError, normalizeError, tryCatch } from './utils';
5+
import { Generated, GeneratedCallback, OasItem, OasItemAsSpec, OasItemAsUrl, StrictConfig } from './types';
106

11-
export async function generateItem(oas: Oas, config: StrictConfig) {
12-
const { name, url, spec, axiosImport: axiosImportScope } = oas;
7+
export async function generateItem(oasItem: OasItem, config: StrictConfig): Promise<Generated> {
8+
const { name, axiosImport: axiosImportScope } = oasItem;
139
const { cwd, dest, axiosImport: axiosImportGlobal, unwrapResponseData } = config;
1410
const axiosImport = axiosImportScope || axiosImportGlobal || axiosImportDefault;
1511
const { files } = await generateApi({
1612
name,
17-
url,
18-
spec,
13+
url: (oasItem as OasItemAsUrl).url,
14+
spec: (oasItem as OasItemAsSpec).spec,
1915
output: false,
2016
httpClientType: 'axios',
2117
templates: templatesDir,
2218
silent: true,
2319
unwrapResponseData,
2420
});
2521

22+
const generated: Generated = {
23+
files: [],
24+
oasItem,
25+
config,
26+
};
27+
2628
for (const { content, name: filename } of files) {
2729
const contentFinal = [axiosImport, helpersImport, content].join('\n');
2830
const file = path.join(cwd, dest, filename);
2931
const dir = path.dirname(file);
3032

3133
await fs.mkdir(dir, { recursive: true });
3234
await fs.writeFile(file, contentFinal);
33-
}
34-
}
3535

36-
export async function generate(config: StrictConfig) {
37-
const { list } = config;
38-
let step = 0;
39-
const length = list.length;
40-
const width = String(length).length;
41-
42-
for (const oas of list) {
43-
step++;
44-
const stepText = String(step).padStart(width, '0');
45-
console.log(chalk.cyanBright(`[${stepText}/${length}]`), 'generating', chalk.yellow(oas.name));
46-
await generateItem(oas, config);
36+
generated.files.push(file);
4737
}
48-
}
4938

50-
export async function start() {
51-
const explorer = cosmiconfig('oas', {
52-
searchPlaces: ['oas.config.cjs', 'oas.config.js', 'oas.json'],
53-
});
54-
const [err1, result] = await tryCatch(explorer.search());
39+
return generated;
40+
}
5541

56-
if (err1) {
57-
return exitError('配置文件查找失败');
58-
}
42+
export async function generate(config: StrictConfig, callback?: GeneratedCallback): Promise<Generated[]> {
43+
const { list, onGenerated } = config;
44+
let index = 0;
45+
const length = list.length;
46+
const generatedList: Generated[] = [];
5947

60-
if (!result) {
61-
return exitError('配置文件未找到');
48+
for (const oasItem of list) {
49+
const start = Date.now();
50+
callback?.(
51+
{
52+
files: [],
53+
oasItem,
54+
config,
55+
},
56+
{ index, length, done: false, start, end: start }
57+
);
58+
const generated = await generateItem(oasItem, config);
59+
generatedList.push(generated);
60+
onGenerated(generated);
61+
callback?.(generated, { index, length, done: true, start, end: Date.now() });
62+
index++;
6263
}
6364

64-
const config = result.filepath.endsWith('js')
65-
? // js 文件使用 defineConfig,返回的是 StrictConfig
66-
(result.config as StrictConfig)
67-
: // json 文件是纯文本,返回的 UserConfig
68-
defineConfig(result.config as UserConfig);
69-
70-
try {
71-
await generate(config);
72-
} catch (err) {
73-
exitError(normalizeError(err).message);
74-
}
65+
return generatedList;
7566
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
11
export * from './generator';
22
export * from './configure';
3+
export * from './types';
4+
export * from './commands';

src/types.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
interface OasBase {
1+
interface OasItemBase {
22
name: string;
33

44
/**
@@ -10,15 +10,17 @@ interface OasBase {
1010
axiosImport?: string;
1111
}
1212

13-
interface OasAsUrl extends OasBase {
13+
export interface OasItemAsUrl extends OasItemBase {
1414
url: string;
1515
}
1616

17-
interface OasAsSpec extends OasBase {
18-
spec: import('swagger-schema-official').Spec;
17+
export type Oas = import('swagger-schema-official').Spec;
18+
19+
export interface OasItemAsSpec extends OasItemBase {
20+
spec: Oas;
1921
}
2022

21-
export interface Oas extends OasAsUrl, OasAsSpec {}
23+
export type OasItem = OasItemAsUrl | OasItemAsSpec;
2224

2325
export interface UserConfig {
2426
/**
@@ -47,10 +49,16 @@ export interface UserConfig {
4749
*/
4850
unwrapResponseData?: boolean;
4951

52+
/**
53+
* 单个 oas 生成后回调
54+
* @param {Generated} generated
55+
*/
56+
onGenerated?: (generated: Generated) => any;
57+
5058
/**
5159
* oas 列表
5260
*/
53-
list: Oas[];
61+
list: OasItem[];
5462
}
5563

5664
export type StrictConfig = Required<UserConfig>;
@@ -62,3 +70,18 @@ export enum ContentKind {
6270
TEXT = 'TEXT',
6371
OTHER = 'OTHER',
6472
}
73+
74+
export interface Generated {
75+
files: string[];
76+
oasItem: OasItem;
77+
config: StrictConfig;
78+
}
79+
80+
export type GenerateInfo = {
81+
index: number;
82+
length: number;
83+
done: boolean;
84+
start: number;
85+
end: number;
86+
};
87+
export type GeneratedCallback = (generated: Generated, info: GenerateInfo) => any;

0 commit comments

Comments
 (0)