Skip to content

Commit 322a5d9

Browse files
committed
fix(printer): 优化请求验证逻辑
- 在运行时验证中增加了对可选参数的处理 - 通过添加条件判断,避免在参数为 undefined 时进行解析 - 提高了代码的健壮性和性能
1 parent fd66f2b commit 322a5d9

File tree

4 files changed

+308
-8
lines changed

4 files changed

+308
-8
lines changed

src/printer/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -584,7 +584,10 @@ export class Printer {
584584

585585
// validate request
586586
if (runtimeValidate) {
587-
this.#mainContent.push('block', validateAbleRequestArgs.map(arg => `${arg.zodName}.parse(${arg.argName})`));
587+
this.#mainContent.push('block', validateAbleRequestArgs.map((arg) => {
588+
const optionalIf = arg.required ? '' : `(${arg.argName} !== undefined) && `;
589+
return `${optionalIf}${arg.zodName}.parse(${arg.argName})`;
590+
}));
588591
}
589592

590593
this.#mainContent.push('block', `const ${AXIOS_RESPONSE_NAME} = await ${AXIOS_IMPORT_NAME}<${responseType}>({`);

test/example-dest/2.0/pet-store.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ return resp;
134134
*/
135135
export async function deletePet(petId:Type.DeletePetPath,apiKey?:Type.DeletePetHeaders,config?:AxiosRequestConfig) {
136136
zDeletePetPath.parse(petId)
137-
zDeletePetHeaders.parse(apiKey)
137+
(apiKey !== undefined) && zDeletePetHeaders.parse(apiKey)
138138
const resp = await axios<unknown>({
139139
method: "DELETE",
140140
url: `/pet/${petId}`,

test/example-dest/3.0/pet-store.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ return resp;
6868
* @returns successful operation
6969
*/
7070
export async function findPetsByStatus(status?:Type.FindPetsByStatusParams,config?:AxiosRequestConfig) {
71-
zFindPetsByStatusParams.parse(status)
71+
(status !== undefined) && zFindPetsByStatusParams.parse(status)
7272
const resp = await axios<Type.FindPetsByStatusResponse>({
7373
method: "GET",
7474
url: `/pet/findByStatus`,
@@ -87,7 +87,7 @@ return resp;
8787
* @returns successful operation
8888
*/
8989
export async function findPetsByTags(tags?:Type.FindPetsByTagsParams,config?:AxiosRequestConfig) {
90-
zFindPetsByTagsParams.parse(tags)
90+
(tags !== undefined) && zFindPetsByTagsParams.parse(tags)
9191
const resp = await axios<Type.FindPetsByTagsResponse>({
9292
method: "GET",
9393
url: `/pet/findByTags`,
@@ -125,7 +125,7 @@ return resp;
125125
*/
126126
export async function updatePetWithForm(petId:Type.UpdatePetWithFormPath,params?:Type.UpdatePetWithFormParams,config?:AxiosRequestConfig) {
127127
zUpdatePetWithFormPath.parse(petId)
128-
zUpdatePetWithFormParams.parse(params)
128+
(params !== undefined) && zUpdatePetWithFormParams.parse(params)
129129
const resp = await axios<unknown>({
130130
method: "POST",
131131
url: `/pet/${petId}`,
@@ -144,7 +144,7 @@ return resp;
144144
*/
145145
export async function deletePet(petId:Type.DeletePetPath,apiKey?:Type.DeletePetHeaders,config?:AxiosRequestConfig) {
146146
zDeletePetPath.parse(petId)
147-
zDeletePetHeaders.parse(apiKey)
147+
(apiKey !== undefined) && zDeletePetHeaders.parse(apiKey)
148148
const resp = await axios<unknown>({
149149
method: "DELETE",
150150
url: `/pet/${petId}`,
@@ -166,7 +166,7 @@ return resp;
166166
export async function uploadFile(petId:Type.UploadFilePath,data:Type.UploadFileData,additionalMetadata?:Type.UploadFileParams,config?:AxiosRequestConfig) {
167167
zUploadFilePath.parse(petId)
168168
zUploadFileData.parse(data)
169-
zUploadFileParams.parse(additionalMetadata)
169+
(additionalMetadata !== undefined) && zUploadFileParams.parse(additionalMetadata)
170170
const resp = await axios<Type.UploadFileResponse>({
171171
method: "POST",
172172
url: `/pet/${petId}/uploadImage`,
@@ -291,7 +291,7 @@ return resp;
291291
* @returns successful operation
292292
*/
293293
export async function loginUser(params?:Type.LoginUserParams,config?:AxiosRequestConfig) {
294-
zLoginUserParams.parse(params)
294+
(params !== undefined) && zLoginUserParams.parse(params)
295295
const resp = await axios<Type.LoginUserResponse>({
296296
method: "GET",
297297
url: `/user/login`,

test/printer/validate.test.ts

Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
import type { OpenAPILatest } from '../../src';
2+
import { Printer } from '../../src/printer';
3+
4+
const doc1: OpenAPILatest.Document = {
5+
openapi: '3.1.0',
6+
info: {
7+
title: 'test',
8+
version: '1.0.0',
9+
},
10+
paths: {
11+
'/pets/{pet-id}': {
12+
get: {
13+
operationId: 'getPet',
14+
parameters: [
15+
{
16+
in: 'path',
17+
name: 'pet-id',
18+
schema: {
19+
type: 'string',
20+
},
21+
required: true,
22+
},
23+
{
24+
in: 'query',
25+
name: 'category-id',
26+
schema: {
27+
type: 'string',
28+
},
29+
},
30+
],
31+
responses: {
32+
200: {
33+
description: 'pet name',
34+
content: {
35+
'*': {},
36+
},
37+
},
38+
},
39+
},
40+
},
41+
},
42+
};
43+
const doc2: OpenAPILatest.Document = {
44+
openapi: '3.1.0',
45+
info: {
46+
title: 'test',
47+
version: '1.0.0',
48+
},
49+
paths: {
50+
'/pets/{pet-id}': {
51+
get: {
52+
operationId: 'getPet',
53+
parameters: [
54+
{
55+
in: 'path',
56+
name: 'pet-id',
57+
schema: {
58+
type: 'string',
59+
},
60+
required: true,
61+
},
62+
{
63+
in: 'query',
64+
name: 'category-id',
65+
schema: {
66+
type: 'string',
67+
},
68+
},
69+
],
70+
responses: {
71+
200: {
72+
description: 'pet name',
73+
content: {
74+
'*': {
75+
schema: {
76+
type: 'string',
77+
},
78+
},
79+
},
80+
},
81+
},
82+
},
83+
},
84+
},
85+
};
86+
87+
describe('runtimeValidate = true', () => {
88+
it('response unknown', () => {
89+
const printer = new Printer(doc1, {
90+
runtimeValidate: true,
91+
});
92+
const result = printer.print({
93+
hideImports: true,
94+
hideHeaders: true,
95+
hideFooters: true,
96+
hideInfo: true,
97+
hideAlert: true,
98+
});
99+
100+
expect(result.main.code).toMatchInlineSnapshot(`
101+
"/**
102+
* @param petId request path "pet-id"
103+
* @param [categoryId] request params "category-id"
104+
* @param [config] request config
105+
*/
106+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
107+
zGetPetPath.parse(petId)
108+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
109+
const resp = await axios<unknown>({
110+
method: "GET",
111+
url: \`/pets/\${petId}\`,
112+
params: {"category-id": categoryId},
113+
...config
114+
});
115+
return resp;
116+
}"
117+
`);
118+
});
119+
120+
it('response type', () => {
121+
const printer = new Printer(doc2, {
122+
runtimeValidate: true,
123+
});
124+
const result = printer.print({
125+
hideImports: true,
126+
hideHeaders: true,
127+
hideFooters: true,
128+
hideInfo: true,
129+
hideAlert: true,
130+
});
131+
132+
expect(result.main.code).toMatchInlineSnapshot(`
133+
"/**
134+
* @param petId request path "pet-id"
135+
* @param [categoryId] request params "category-id"
136+
* @param [config] request config
137+
* @returns pet name
138+
*/
139+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
140+
zGetPetPath.parse(petId)
141+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
142+
const resp = await axios<Type.GetPetResponse>({
143+
method: "GET",
144+
url: \`/pets/\${petId}\`,
145+
params: {"category-id": categoryId},
146+
...config
147+
});
148+
zGetPetResponse.parse(resp["data"]);
149+
return resp;
150+
}"
151+
`);
152+
});
153+
});
154+
155+
describe('runtimeValidate = {responseDataProps: []}', () => {
156+
it('response unknown', () => {
157+
const printer = new Printer(doc1, {
158+
runtimeValidate: {
159+
responseDataProps: [],
160+
},
161+
});
162+
const result = printer.print({
163+
hideImports: true,
164+
hideHeaders: true,
165+
hideFooters: true,
166+
hideInfo: true,
167+
hideAlert: true,
168+
});
169+
170+
expect(result.main.code).toMatchInlineSnapshot(`
171+
"/**
172+
* @param petId request path "pet-id"
173+
* @param [categoryId] request params "category-id"
174+
* @param [config] request config
175+
*/
176+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
177+
zGetPetPath.parse(petId)
178+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
179+
const resp = await axios<unknown>({
180+
method: "GET",
181+
url: \`/pets/\${petId}\`,
182+
params: {"category-id": categoryId},
183+
...config
184+
});
185+
return resp;
186+
}"
187+
`);
188+
});
189+
190+
it('response type', () => {
191+
const printer = new Printer(doc2, {
192+
runtimeValidate: {
193+
responseDataProps: [],
194+
},
195+
});
196+
const result = printer.print({
197+
hideImports: true,
198+
hideHeaders: true,
199+
hideFooters: true,
200+
hideInfo: true,
201+
hideAlert: true,
202+
});
203+
204+
expect(result.main.code).toMatchInlineSnapshot(`
205+
"/**
206+
* @param petId request path "pet-id"
207+
* @param [categoryId] request params "category-id"
208+
* @param [config] request config
209+
* @returns pet name
210+
*/
211+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
212+
zGetPetPath.parse(petId)
213+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
214+
const resp = await axios<Type.GetPetResponse>({
215+
method: "GET",
216+
url: \`/pets/\${petId}\`,
217+
params: {"category-id": categoryId},
218+
...config
219+
});
220+
zGetPetResponse.parse(resp);
221+
return resp;
222+
}"
223+
`);
224+
});
225+
});
226+
227+
describe('runtimeValidate = {responseDataProps: [a, b-c]}', () => {
228+
it('response unknown', () => {
229+
const printer = new Printer(doc1, {
230+
runtimeValidate: {
231+
responseDataProps: ['a', 'b-c'],
232+
},
233+
});
234+
const result = printer.print({
235+
hideImports: true,
236+
hideHeaders: true,
237+
hideFooters: true,
238+
hideInfo: true,
239+
hideAlert: true,
240+
});
241+
242+
expect(result.main.code).toMatchInlineSnapshot(`
243+
"/**
244+
* @param petId request path "pet-id"
245+
* @param [categoryId] request params "category-id"
246+
* @param [config] request config
247+
*/
248+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
249+
zGetPetPath.parse(petId)
250+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
251+
const resp = await axios<unknown>({
252+
method: "GET",
253+
url: \`/pets/\${petId}\`,
254+
params: {"category-id": categoryId},
255+
...config
256+
});
257+
return resp;
258+
}"
259+
`);
260+
});
261+
262+
it('response type', () => {
263+
const printer = new Printer(doc2, {
264+
runtimeValidate: {
265+
responseDataProps: ['a', 'b-c'],
266+
},
267+
});
268+
const result = printer.print({
269+
hideImports: true,
270+
hideHeaders: true,
271+
hideFooters: true,
272+
hideInfo: true,
273+
hideAlert: true,
274+
});
275+
276+
expect(result.main.code).toMatchInlineSnapshot(`
277+
"/**
278+
* @param petId request path "pet-id"
279+
* @param [categoryId] request params "category-id"
280+
* @param [config] request config
281+
* @returns pet name
282+
*/
283+
export async function getPet(petId:Type.GetPetPath,categoryId?:Type.GetPetParams,config?:AxiosRequestConfig) {
284+
zGetPetPath.parse(petId)
285+
(categoryId !== undefined) && zGetPetParams.parse(categoryId)
286+
const resp = await axios<Type.GetPetResponse>({
287+
method: "GET",
288+
url: \`/pets/\${petId}\`,
289+
params: {"category-id": categoryId},
290+
...config
291+
});
292+
zGetPetResponse.parse(resp["a"]["b-c"]);
293+
return resp;
294+
}"
295+
`);
296+
});
297+
});

0 commit comments

Comments
 (0)