Skip to content

Commit ecfe2cd

Browse files
committed
feat: uri模式下支持分组
1 parent e3748b5 commit ecfe2cd

File tree

5 files changed

+277
-170
lines changed

5 files changed

+277
-170
lines changed

src/bin.ts

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,9 @@ spinner.add({
7373

7474
await Promise.all(
7575
ctx.configs.map(async (config, i) => {
76-
const result = await generateTemplate(
77-
ctx.docs[i]!,
78-
config.projectName,
79-
config.classMode || 'method',
80-
);
8176
ctx.projects = {
8277
...ctx.projects,
83-
...result,
78+
...(await generateTemplate(ctx.docs[i]!, config)),
8479
};
8580
}),
8681
);

src/define-config.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@ export interface OpenapiClientConfig {
2626
/**
2727
* 类的生成方式。默认值:`method`
2828
* - `method`,仅生成 `get|post|put|patch|delete` 几个方法,uri作为第一个参数传入
29-
* - `uri`,所有的 method+uri 都会重新拼接成一个方法,比如`postUsersById()`
29+
* - `uri`, method+uri 拼接成一个方法,比如 `POST /users/{id}` 会变成 `postUsersById()`
3030
*/
3131
classMode?: 'method' | 'uri';
32+
/**
33+
* 根据Tag生成不同的分组,以类似`client.user.getUsers()`这种方式调用。仅在 `classMode=uri` 场景下生效。默认值:`true`
34+
*/
35+
tagToGroup?: boolean;
3236
}
3337

3438
export const defineConfig = (options: OpenapiClientConfig | OpenapiClientConfig[]) => {

src/lib/document-to-meta.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export type Metas = Record<
1818
responseTypes: string[];
1919
description?: string;
2020
deprecated?: boolean;
21+
tags: string[];
2122
}[]
2223
>;
2324

@@ -42,8 +43,9 @@ export const documentToMeta = (docs: OpenAPIV3.Document) => {
4243
params: parseParameters(docs, pathItem, methodItem, 'path'),
4344
...parseRequestBody(docs, methodItem),
4445
...parseResponse(docs, methodItem),
45-
deprecated: methodItem.deprecated || false,
46-
description: methodItem.description || '',
46+
deprecated: methodItem.deprecated,
47+
description: methodItem.description,
48+
tags: methodItem.tags && methodItem.tags.length ? methodItem.tags : ['default'],
4749
});
4850
});
4951
});

src/lib/generate-template.ts

Lines changed: 108 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,34 @@
11
import type { OpenAPIV3 } from 'openapi-types';
2-
import { upperFirst, camelCase } from 'lodash-es';
2+
import { upperFirst, camelCase, snakeCase } from 'lodash-es';
33
import { documentToMeta, type Metas } from './document-to-meta';
44
import { methods } from './adapter';
55
import prettier from 'prettier';
66
import { generateComments } from './generate-comments';
7+
import type { OpenapiClientConfig } from '../define-config';
78

89
export const generateTemplate = async (
910
docs: OpenAPIV3.Document,
10-
projectName: string = '',
11-
classMode: 'method' | 'uri',
11+
config: Pick<OpenapiClientConfig, 'projectName' | 'classMode' | 'tagToGroup'>,
1212
) => {
13+
const { projectName, classMode = 'method', tagToGroup = true } = config;
1314
const className = `OpenapiClient${upperFirst(camelCase(projectName))}`;
1415
const metas = documentToMeta(docs);
16+
17+
const classTpl =
18+
classMode === 'method'
19+
? generateMethodModeClass(className, metas)
20+
: tagToGroup
21+
? generateUriModelClassWithNamespace(className, metas)
22+
: generateUriModelClass(className, metas);
23+
1524
const dts = `
1625
${generateNamespaceTpl(className, metas)}
17-
${classMode === 'method' ? generateMethodModeClassForDTS(className, metas) : generateUriModelClassForDTS(className, metas)}
26+
${classTpl.dts}
1827
${generatePathRelationTpl(className, metas)}
1928
`;
2029

2130
const js = `
22-
${classMode === 'method' ? generateMethodModeClassForJS(className) : generateUriModeClassForJS(className, metas)}
31+
${classTpl.js}
2332
${generateContentTypeTpl(className, metas)}
2433
`;
2534

@@ -65,8 +74,9 @@ declare namespace ${className} {
6574
}`;
6675
};
6776

68-
export const generateMethodModeClassForDTS = (className: string, metas: Metas) => {
69-
return `
77+
export const generateMethodModeClass = (className: string, metas: Metas) => {
78+
return {
79+
dts: `
7080
declare class ${className} extends BaseOpenapiClient {
7181
${methods
7282
.map((method) => {
@@ -98,11 +108,28 @@ declare class ${className} extends BaseOpenapiClient {
98108
BaseOpenapiClient.UserInputOpts['requestBodyType'],
99109
BaseOpenapiClient.UserInputOpts['responseType'],
100110
];
101-
}`;
111+
}`,
112+
js: `
113+
var ${className} = class extends BaseOpenapiClient {
114+
${methods
115+
.map((method) => {
116+
if (!metas[method].length) return '';
117+
return `${method}(uri, opts) {
118+
return this.request(uri, "get", opts);
119+
}`;
120+
})
121+
.join('\n')}
122+
123+
getContentTypes(uri, method) {
124+
return contentTypes${className}[method + " " + uri] || [void 0, void 0];
125+
}
126+
};`,
127+
};
102128
};
103129

104-
export const generateUriModelClassForDTS = (className: string, metas: Metas) => {
105-
return `
130+
export const generateUriModelClass = (className: string, metas: Metas) => {
131+
return {
132+
dts: `
106133
declare class ${className} extends BaseOpenapiClient {
107134
${methods
108135
.flatMap((method) => {
@@ -116,40 +143,13 @@ declare class ${className} extends BaseOpenapiClient {
116143
});
117144
})
118145
.join('\n')}
119-
}`;
120-
};
121146
122-
export const generateMethodModeClassForJS = (className: string) => {
123-
return `
124-
var ${className} = class extends BaseOpenapiClient {
125-
get(uri, opts) {
126-
return this.request(uri, "get", opts);
127-
}
128-
129-
post(uri, opts) {
130-
return this.request(uri, "post", opts);
131-
}
132-
133-
put(uri, opts) {
134-
return this.request(uri, "put", opts);
135-
}
136-
137-
patch(uri, opts) {
138-
return this.request(uri, "patch", opts);
139-
}
140-
141-
delete(uri, opts) {
142-
return this.request(uri, "delete", opts);
143-
}
144-
145-
getContentTypes(uri, method) {
146-
return contentTypes${className}[method + " " + uri] || [void 0, void 0];
147-
}
148-
};`;
149-
};
150-
151-
export const generateUriModeClassForJS = (className: string, metas: Metas) => {
152-
return `
147+
protected getContentTypes(uri: string, method: string) : [
148+
BaseOpenapiClient.UserInputOpts['requestBodyType'],
149+
BaseOpenapiClient.UserInputOpts['responseType'],
150+
];
151+
}`,
152+
js: `
153153
var ${className} = class extends BaseOpenapiClient {
154154
${methods
155155
.flatMap((method) => {
@@ -165,7 +165,71 @@ var ${className} = class extends BaseOpenapiClient {
165165
getContentTypes(uri, method) {
166166
return contentTypes${className}[method + " " + uri] || [void 0, void 0];
167167
}
168-
};`;
168+
};`,
169+
};
170+
};
171+
172+
export const generateUriModelClassWithNamespace = (className: string, metas: Metas) => {
173+
const namespaces = [
174+
...new Set(
175+
methods.flatMap((method) => metas[method].flatMap((meta) => meta.tags || [])),
176+
),
177+
];
178+
179+
return {
180+
dts: `
181+
declare class ${className} extends BaseOpenapiClient {
182+
${namespaces
183+
.map((ns) => {
184+
return `readonly ${snakeCase(ns)}: {
185+
${methods
186+
.flatMap((method) => {
187+
return metas[method]
188+
.filter((meta) => meta.tags.includes(ns))
189+
.map((meta) => {
190+
const optional =
191+
meta.query.optional && meta.params.optional && meta.body.optional;
192+
193+
return `
194+
${generateComments(meta)}
195+
${camelCase(meta.key)}(opts${optional ? '?' : ''}: ${className}_${method}_paths['${meta.uri}']['request']): Promise<${className}_${method}_paths['${meta.uri}']['response']>`;
196+
});
197+
})
198+
.join('\n')}
199+
}`;
200+
})
201+
.join('\n')}
202+
203+
protected getContentTypes(uri: string, method: string) : [
204+
BaseOpenapiClient.UserInputOpts['requestBodyType'],
205+
BaseOpenapiClient.UserInputOpts['responseType'],
206+
];
207+
}`,
208+
js: `
209+
var ${className} = class extends BaseOpenapiClient {
210+
${namespaces
211+
.map((ns) => {
212+
return `${snakeCase(ns)} = {
213+
${methods
214+
.flatMap((method) => {
215+
return metas[method]
216+
.filter((meta) => meta.tags.includes(ns))
217+
.map((meta) => {
218+
return `${camelCase(meta.key)}(opts) {
219+
return this.request('${meta.uri}', '${method}', opts);
220+
},`;
221+
});
222+
})
223+
.join('\n')}
224+
}`;
225+
})
226+
.join('\n')}
227+
228+
getContentTypes(uri, method) {
229+
return contentTypes${className}[method + ' ' + uri] || [void 0, void 0];
230+
}
231+
};`,
232+
};
169233
};
170234

171235
export const generateContentTypeTpl = (className: string, metas: Metas) => {

0 commit comments

Comments
 (0)