Skip to content

Commit bb240ef

Browse files
authoredDec 6, 2023
fix(generators): formdata handling oneof and allof (#1091)
* fix(generators): formdata handling oneof and allof * fix(form-data): handling oneof and anyof typing * test(form-data): improve specification * test(react-query): generation folder name
1 parent 603573d commit bb240ef

File tree

4 files changed

+124
-72
lines changed

4 files changed

+124
-72
lines changed
 

‎packages/core/src/getters/res-req-types.ts

+97-51
Original file line numberDiff line numberDiff line change
@@ -236,64 +236,48 @@ const getSchemaFormDataAndUrlEncoded = ({
236236
);
237237

238238
const variableName = isUrlEncoded ? 'formUrlEncoded' : 'formData';
239-
const form = isUrlEncoded
239+
let form = isUrlEncoded
240240
? `const ${variableName} = new URLSearchParams();\n`
241241
: `const ${variableName} = new FormData();\n`;
242242

243-
if (schema.type === 'object' && schema.properties) {
244-
const formDataValues = Object.entries(schema.properties).reduce(
245-
(acc, [key, value]) => {
246-
const { schema: property } = resolveRef<SchemaObject>(value, context);
247-
248-
let formDataValue = '';
249-
250-
const formatedKey = !keyword.isIdentifierNameES5(key)
251-
? `['${key}']`
252-
: `.${key}`;
253-
254-
if (property.type === 'object') {
255-
formDataValue = `${variableName}.append('${key}', JSON.stringify(${propName}${formatedKey}));\n`;
256-
} else if (property.type === 'array') {
257-
formDataValue = `${propName}${formatedKey}.forEach(value => ${variableName}.append('${key}', value));\n`;
258-
} else if (
259-
property.type === 'number' ||
260-
property.type === 'integer' ||
261-
property.type === 'boolean'
262-
) {
263-
formDataValue = `${variableName}.append('${key}', ${propName}${formatedKey}.toString())\n`;
264-
} else {
265-
formDataValue = `${variableName}.append('${key}', ${propName}${formatedKey})\n`;
266-
}
267-
268-
const isRequired = schema.required?.includes(key);
243+
if (schema.type === 'object') {
244+
if (schema.oneOf || schema.anyOf || schema.allOf) {
245+
const combinedSchemas = schema.oneOf || schema.anyOf || schema.allOf;
269246

270-
if (property.nullable) {
271-
if (isRequired) {
272-
return (
273-
acc +
274-
`if(${propName}${formatedKey} !== null) {\n ${formDataValue} }\n`
275-
);
276-
}
247+
const shouldCast = !!schema.oneOf || !!schema.anyOf;
277248

278-
return (
279-
acc +
280-
`if(${propName}${formatedKey} !== undefined && ${propName}${formatedKey} !== null) {\n ${formDataValue} }\n`
249+
const combinedSchemasFormData = combinedSchemas!
250+
.map((schema) => {
251+
const { schema: combinedSchema, imports } = resolveRef<SchemaObject>(
252+
schema,
253+
context,
281254
);
282-
}
283-
284-
if (isRequired) {
285-
return acc + formDataValue;
286-
}
287-
288-
return (
289-
acc +
290-
`if(${propName}${formatedKey} !== undefined) {\n ${formDataValue} }\n`
291-
);
292-
},
293-
'',
294-
);
295255

296-
return `${form}${formDataValues}`;
256+
return resolveSchemaPropertiesToFormData({
257+
schema: combinedSchema,
258+
variableName,
259+
propName: shouldCast ? `(${propName} as any)` : propName,
260+
context,
261+
});
262+
})
263+
.filter((x) => x)
264+
.join('\n');
265+
266+
form += combinedSchemasFormData;
267+
}
268+
269+
if (schema.properties) {
270+
const formDataValues = resolveSchemaPropertiesToFormData({
271+
schema,
272+
variableName,
273+
propName,
274+
context,
275+
});
276+
277+
form += formDataValues;
278+
}
279+
280+
return form;
297281
}
298282

299283
if (schema.type === 'array') {
@@ -306,3 +290,65 @@ const getSchemaFormDataAndUrlEncoded = ({
306290

307291
return `${form}${variableName}.append('data', ${propName})\n`;
308292
};
293+
294+
const resolveSchemaPropertiesToFormData = ({
295+
schema,
296+
variableName,
297+
propName,
298+
context,
299+
}: {
300+
schema: SchemaObject;
301+
variableName: string;
302+
propName: string;
303+
context: ContextSpecs;
304+
}) => {
305+
const formDataValues = Object.entries(schema.properties ?? {}).reduce(
306+
(acc, [key, value]) => {
307+
const { schema: property } = resolveRef<SchemaObject>(value, context);
308+
309+
let formDataValue = '';
310+
311+
const formatedKey = !keyword.isIdentifierNameES5(key)
312+
? `['${key}']`
313+
: `.${key}`;
314+
315+
const valueKey = `${propName}${formatedKey}`;
316+
317+
if (property.type === 'object') {
318+
formDataValue = `${variableName}.append('${key}', JSON.stringify(${valueKey}));\n`;
319+
} else if (property.type === 'array') {
320+
formDataValue = `${valueKey}.forEach(value => ${variableName}.append('${key}', value));\n`;
321+
} else if (
322+
property.type === 'number' ||
323+
property.type === 'integer' ||
324+
property.type === 'boolean'
325+
) {
326+
formDataValue = `${variableName}.append('${key}', ${valueKey}.toString())\n`;
327+
} else {
328+
formDataValue = `${variableName}.append('${key}', ${valueKey})\n`;
329+
}
330+
331+
const isRequired = schema.required?.includes(key);
332+
333+
if (property.nullable) {
334+
if (isRequired) {
335+
return acc + `if(${valueKey} !== null) {\n ${formDataValue} }\n`;
336+
}
337+
338+
return (
339+
acc +
340+
`if(${valueKey} !== undefined && ${valueKey} !== null) {\n ${formDataValue} }\n`
341+
);
342+
}
343+
344+
if (isRequired) {
345+
return acc + formDataValue;
346+
}
347+
348+
return acc + `if(${valueKey} !== undefined) {\n ${formDataValue} }\n`;
349+
},
350+
'',
351+
);
352+
353+
return formDataValues;
354+
};

‎tests/configs/react-query.config.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ export default defineConfig({
150150
},
151151
formData: {
152152
output: {
153-
target: '../generated/react-query/formData/endpoints.ts',
154-
schemas: '../generated/react-query/formData/model',
153+
target: '../generated/react-query/form-data/endpoints.ts',
154+
schemas: '../generated/react-query/form-data/model',
155155
client: 'react-query',
156156
mock: true,
157157
override: {
@@ -184,8 +184,8 @@ export default defineConfig({
184184
},
185185
formDataMutator: {
186186
output: {
187-
target: '../generated/react-query/form-data/endpoints.ts',
188-
schemas: '../generated/react-query/form-data/model',
187+
target: '../generated/react-query/form-data-with-mutator/endpoints.ts',
188+
schemas: '../generated/react-query/form-data-with-mutator/model',
189189
client: 'react-query',
190190
mock: true,
191191
override: {

‎tests/mutators/custom-form-data.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export const customFormData = <Body extends Record<string, string | Blob>>(
1+
export const customFormData = <Body extends Record<string, any>>(
22
body: Body,
33
): FormData => {
44
const formData = new FormData();

‎tests/specifications/form-data.yaml

+22-16
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,7 @@ paths:
1818
content:
1919
multipart/form-data:
2020
schema:
21-
type: object
22-
required:
23-
- 'name'
24-
- 'tag'
25-
properties:
26-
name:
27-
type: string
28-
tag:
29-
type: string
21+
$ref: '#/components/schemas/Pet'
3022
responses:
3123
'200':
3224
description: Created Pet
@@ -44,20 +36,16 @@ components:
4436
schemas:
4537
Pet:
4638
type: object
39+
oneOf:
40+
- $ref: '#/components/schemas/PetBase'
41+
- $ref: '#/components/schemas/PetExtended'
4742
required:
4843
- id
4944
- name
5045
properties:
5146
'@id':
5247
type: string
5348
format: iri-reference
54-
id:
55-
type: integer
56-
format: int64
57-
name:
58-
type: string
59-
tag:
60-
type: string
6149
email:
6250
type: string
6351
format: email
@@ -78,3 +66,21 @@ components:
7866
format: int32
7967
message:
8068
type: string
69+
70+
PetBase:
71+
type: object
72+
properties:
73+
name:
74+
type: string
75+
tag:
76+
type: string
77+
PetExtended:
78+
type: object
79+
properties:
80+
id:
81+
type: integer
82+
format: int64
83+
name:
84+
type: string
85+
tag:
86+
type: string

0 commit comments

Comments
 (0)
Please sign in to comment.