Skip to content

Commit d7660cb

Browse files
committed
feat(generator): 添加 OpenAPI schema 生成功能
- 在 Generator 中增加 schema 文件生成逻辑 - 在 Reader 中添加错误收集功能 - 修改 migrations 中的 migrate 函数,支持多版本 OpenAPI 文档- 在 PrinterConfigs 中添加 writeSchema 配置项,用于控制是否生成 schema
1 parent b8374e2 commit d7660cb

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

src/generator/Generator.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { PrintResult } from '../printer/types';
2+
import type { OpenAPILatest } from '../types/openapi';
23
import type {
34
GeneratingOptions,
45
GeneratingPayload,
@@ -15,6 +16,7 @@ import process from 'node:process';
1516
import { Emitter } from 'strict-event-emitter';
1617
import { normalizeError } from 'try-flatten';
1718
import { Printer } from '../printer';
19+
import { OpenAPIVersion } from '../types/openapi';
1820
import { isString } from '../utils/type-is';
1921
import { Reader } from './Reader';
2022

@@ -60,6 +62,11 @@ export class Generator extends Emitter<GeneratorEmits> {
6062
const mainFile = path.join(cwd, dest, fileName);
6163
const typeFile = mainFile.replace(/\.ts$/, '.type.ts');
6264
const zodFile = mainFile.replace(/\.ts$/, '.zod.ts');
65+
const schemaFiles: Record<OpenAPIVersion, string> = {
66+
[OpenAPIVersion.V2_0]: mainFile.replace(/\.ts$/, '.v2_0.json'),
67+
[OpenAPIVersion.V3_0]: mainFile.replace(/\.ts$/, '.v3_0.json'),
68+
[OpenAPIVersion.V3_1]: mainFile.replace(/\.ts$/, '.v3_1.json'),
69+
};
6370

6471
// 1. 参数合并
6572
const printerOptions = Object.assign({}, globalPrinter, scopePrinter);
@@ -82,11 +89,11 @@ export class Generator extends Emitter<GeneratorEmits> {
8289
this.emit('process', makePayload('reading'));
8390
const reader = new Reader();
8491
reader.cwd = cwd;
85-
const openAPIV3Document = await reader.read(document);
92+
const migrated = await reader.read(document);
8693

8794
// 3. 输出
8895
this.emit('process', makePayload('printing'));
89-
const printer = new Printer(openAPIV3Document, printerOptions);
96+
const printer = new Printer(migrated.at(-1)!.document! as OpenAPILatest.Document, printerOptions);
9097
const { type, main, zod } = printer.print({ document: name, cwd, mainFile, typeFile, zodFile });
9198

9299
// 4. 写入
@@ -100,6 +107,15 @@ export class Generator extends Emitter<GeneratorEmits> {
100107
this.#writePrintResult('zod', zodFile, zod);
101108
}
102109

110+
if (printerOptions.writeSchema) {
111+
migrated.forEach(({ version, document, errors }) => {
112+
this.#writePrintResult(`schema@${version}`, schemaFiles[version], {
113+
code: JSON.stringify(document, null, 2),
114+
errors,
115+
});
116+
});
117+
}
118+
103119
this.emit('process', makePayload('generated'));
104120
}
105121

src/generator/Reader.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,17 @@ export class Reader {
1515
const source = await this._read(document);
1616
const config = await createConfig({});
1717
const { problems, bundle } = await bundleFromString({ config, source });
18+
const errors: string[] = [];
1819

1920
if (problems.length) {
20-
console.warn(`[parse] 发现了 ${problems.length} 处错误,请检查文档,可能会出现非预期错误`);
2121
problems.forEach((p) => {
22-
console.warn(p.message);
22+
errors.push(p.message);
2323
});
2424
}
2525

26-
return migrate(bundle.parsed);
26+
const migrated = migrate(bundle.parsed);
27+
migrated[0].errors.push(...errors);
28+
return migrated;
2729
}
2830

2931
private async _read(document: AcceptDocument): Promise<string> {

src/migrations/index.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { OpenAPIAll, OpenAPILatest } from '../types/openapi';
1+
import type { OpenAPIAll, OpenAPIV2, OpenAPIV3, OpenAPIV3_1 } from '../types/openapi';
22
import { OpenAPIVersion } from '../types/openapi';
33
import { migrate_2_0To3_0 } from './openapi-2_0';
44
import { migrate_3_0To3_1 } from './openapi-3_0';
@@ -23,16 +23,29 @@ const migrations = [
2323
//
2424
{ from: OpenAPIVersion.V2_0, migrate: migrate_2_0To3_0 },
2525
{ from: OpenAPIVersion.V3_0, migrate: migrate_3_0To3_1 },
26+
{ from: OpenAPIVersion.V3_1 },
2627
];
2728

29+
export interface MigratedV2_0 { version: OpenAPIVersion.V2_0; document: OpenAPIV2.Document; errors: string[] }
30+
export interface MigratedV3_0 { version: OpenAPIVersion.V3_0; document: OpenAPIV3.Document; errors: string[] }
31+
export interface MigratedV3_1 { version: OpenAPIVersion.V3_1; document: OpenAPIV3_1.Document; errors: string[] }
32+
2833
export function migrate(openapi: OpenAPIAll.Document) {
29-
return migrations.reduce((acc, { from, migrate }) => {
34+
const migrated: Array<MigratedV2_0 | MigratedV3_0 | MigratedV3_1> = [];
35+
36+
migrations.reduce((acc, { from, migrate }) => {
3037
if (detectVersion(acc) === from) {
3138
// eslint-disable-next-line ts/ban-ts-comment
32-
// @ts-ignore
33-
return migrate(acc);
39+
// @ts-expect-error
40+
const result = migrate?.(acc) || acc;
41+
// eslint-disable-next-line ts/ban-ts-comment
42+
// @ts-expect-error
43+
migrated.push({ version: from, document: acc, errors: [] });
44+
return result;
3445
}
3546

3647
return acc;
37-
}, openapi) as OpenAPILatest.Document;
48+
}, openapi);
49+
50+
return migrated;
3851
}

src/printer/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,11 @@ export interface PrinterOptions {
132132
* 是否需要在运行时验证接口的出入参
133133
*/
134134
runtimeValidate?: boolean;
135+
136+
/**
137+
* 是否生成 schema
138+
*/
139+
writeSchema?: boolean;
135140
}
136141

137142
export interface PrinterConfigs {

0 commit comments

Comments
 (0)