Skip to content

Commit

Permalink
fix(generators): formdata handling oneof and allof (#1091)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
anymaniax authored Dec 6, 2023
1 parent 603573d commit bb240ef
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 72 deletions.
148 changes: 97 additions & 51 deletions packages/core/src/getters/res-req-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,64 +236,48 @@ const getSchemaFormDataAndUrlEncoded = ({
);

const variableName = isUrlEncoded ? 'formUrlEncoded' : 'formData';
const form = isUrlEncoded
let form = isUrlEncoded
? `const ${variableName} = new URLSearchParams();\n`
: `const ${variableName} = new FormData();\n`;

if (schema.type === 'object' && schema.properties) {
const formDataValues = Object.entries(schema.properties).reduce(
(acc, [key, value]) => {
const { schema: property } = resolveRef<SchemaObject>(value, context);

let formDataValue = '';

const formatedKey = !keyword.isIdentifierNameES5(key)
? `['${key}']`
: `.${key}`;

if (property.type === 'object') {
formDataValue = `${variableName}.append('${key}', JSON.stringify(${propName}${formatedKey}));\n`;
} else if (property.type === 'array') {
formDataValue = `${propName}${formatedKey}.forEach(value => ${variableName}.append('${key}', value));\n`;
} else if (
property.type === 'number' ||
property.type === 'integer' ||
property.type === 'boolean'
) {
formDataValue = `${variableName}.append('${key}', ${propName}${formatedKey}.toString())\n`;
} else {
formDataValue = `${variableName}.append('${key}', ${propName}${formatedKey})\n`;
}

const isRequired = schema.required?.includes(key);
if (schema.type === 'object') {
if (schema.oneOf || schema.anyOf || schema.allOf) {
const combinedSchemas = schema.oneOf || schema.anyOf || schema.allOf;

if (property.nullable) {
if (isRequired) {
return (
acc +
`if(${propName}${formatedKey} !== null) {\n ${formDataValue} }\n`
);
}
const shouldCast = !!schema.oneOf || !!schema.anyOf;

return (
acc +
`if(${propName}${formatedKey} !== undefined && ${propName}${formatedKey} !== null) {\n ${formDataValue} }\n`
const combinedSchemasFormData = combinedSchemas!
.map((schema) => {
const { schema: combinedSchema, imports } = resolveRef<SchemaObject>(
schema,
context,
);
}

if (isRequired) {
return acc + formDataValue;
}

return (
acc +
`if(${propName}${formatedKey} !== undefined) {\n ${formDataValue} }\n`
);
},
'',
);

return `${form}${formDataValues}`;
return resolveSchemaPropertiesToFormData({
schema: combinedSchema,
variableName,
propName: shouldCast ? `(${propName} as any)` : propName,
context,
});
})
.filter((x) => x)
.join('\n');

form += combinedSchemasFormData;
}

if (schema.properties) {
const formDataValues = resolveSchemaPropertiesToFormData({
schema,
variableName,
propName,
context,
});

form += formDataValues;
}

return form;
}

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

return `${form}${variableName}.append('data', ${propName})\n`;
};

const resolveSchemaPropertiesToFormData = ({
schema,
variableName,
propName,
context,
}: {
schema: SchemaObject;
variableName: string;
propName: string;
context: ContextSpecs;
}) => {
const formDataValues = Object.entries(schema.properties ?? {}).reduce(
(acc, [key, value]) => {
const { schema: property } = resolveRef<SchemaObject>(value, context);

let formDataValue = '';

const formatedKey = !keyword.isIdentifierNameES5(key)
? `['${key}']`
: `.${key}`;

const valueKey = `${propName}${formatedKey}`;

if (property.type === 'object') {
formDataValue = `${variableName}.append('${key}', JSON.stringify(${valueKey}));\n`;
} else if (property.type === 'array') {
formDataValue = `${valueKey}.forEach(value => ${variableName}.append('${key}', value));\n`;
} else if (
property.type === 'number' ||
property.type === 'integer' ||
property.type === 'boolean'
) {
formDataValue = `${variableName}.append('${key}', ${valueKey}.toString())\n`;
} else {
formDataValue = `${variableName}.append('${key}', ${valueKey})\n`;
}

const isRequired = schema.required?.includes(key);

if (property.nullable) {
if (isRequired) {
return acc + `if(${valueKey} !== null) {\n ${formDataValue} }\n`;
}

return (
acc +
`if(${valueKey} !== undefined && ${valueKey} !== null) {\n ${formDataValue} }\n`
);
}

if (isRequired) {
return acc + formDataValue;
}

return acc + `if(${valueKey} !== undefined) {\n ${formDataValue} }\n`;
},
'',
);

return formDataValues;
};
8 changes: 4 additions & 4 deletions tests/configs/react-query.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,8 @@ export default defineConfig({
},
formData: {
output: {
target: '../generated/react-query/formData/endpoints.ts',
schemas: '../generated/react-query/formData/model',
target: '../generated/react-query/form-data/endpoints.ts',
schemas: '../generated/react-query/form-data/model',
client: 'react-query',
mock: true,
override: {
Expand Down Expand Up @@ -184,8 +184,8 @@ export default defineConfig({
},
formDataMutator: {
output: {
target: '../generated/react-query/form-data/endpoints.ts',
schemas: '../generated/react-query/form-data/model',
target: '../generated/react-query/form-data-with-mutator/endpoints.ts',
schemas: '../generated/react-query/form-data-with-mutator/model',
client: 'react-query',
mock: true,
override: {
Expand Down
2 changes: 1 addition & 1 deletion tests/mutators/custom-form-data.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const customFormData = <Body extends Record<string, string | Blob>>(
export const customFormData = <Body extends Record<string, any>>(
body: Body,
): FormData => {
const formData = new FormData();
Expand Down
38 changes: 22 additions & 16 deletions tests/specifications/form-data.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,7 @@ paths:
content:
multipart/form-data:
schema:
type: object
required:
- 'name'
- 'tag'
properties:
name:
type: string
tag:
type: string
$ref: '#/components/schemas/Pet'
responses:
'200':
description: Created Pet
Expand All @@ -44,20 +36,16 @@ components:
schemas:
Pet:
type: object
oneOf:
- $ref: '#/components/schemas/PetBase'
- $ref: '#/components/schemas/PetExtended'
required:
- id
- name
properties:
'@id':
type: string
format: iri-reference
id:
type: integer
format: int64
name:
type: string
tag:
type: string
email:
type: string
format: email
Expand All @@ -78,3 +66,21 @@ components:
format: int32
message:
type: string

PetBase:
type: object
properties:
name:
type: string
tag:
type: string
PetExtended:
type: object
properties:
id:
type: integer
format: int64
name:
type: string
tag:
type: string

0 comments on commit bb240ef

Please sign in to comment.