From 638e2ee7c2679f21d5b5d1b2b4e5a32133daf2ad Mon Sep 17 00:00:00 2001 From: CPatchane Date: Sun, 13 Feb 2022 18:43:07 +0100 Subject: [PATCH] feat(query): allow body type customisation through mutator for mutations --- docs/src/pages/guides/custom-axios.md | 3 +++ docs/src/pages/guides/custom-client.md | 5 +++- .../pages/reference/configuration/output.md | 5 ++++ src/core/generators/imports.ts | 7 ++++-- src/core/generators/mutator.ts | 12 ++++++++++ src/core/generators/query.ts | 24 ++++++++++++++----- src/types/generator.ts | 1 + 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/docs/src/pages/guides/custom-axios.md b/docs/src/pages/guides/custom-axios.md index 40cb5905a..d089d2237 100644 --- a/docs/src/pages/guides/custom-axios.md +++ b/docs/src/pages/guides/custom-axios.md @@ -42,4 +42,7 @@ export const customInstance = (config: AxiosRequestConfig): Promise => { // In some case with react-query and swr you want to be able to override the return error type so you can also do it here like this export type ErrorType = AxiosError; +// In case you want to wrap the body type (optional) +// (if the custom instance is processing data before sending it, like changing the case for example) +export type BodyType = CamelCase ``` diff --git a/docs/src/pages/guides/custom-client.md b/docs/src/pages/guides/custom-client.md index 64078e14d..1816d016f 100644 --- a/docs/src/pages/guides/custom-client.md +++ b/docs/src/pages/guides/custom-client.md @@ -51,4 +51,7 @@ export default customInstance; // In some case with react-query and swr you want to be able to override the return error type so you can also do it here like this export type ErrorType = AxiosError; -``` \ No newline at end of file +// In case you want to wrap the body type (optional) +// (if the custom instance is processing data before sending it, like changing the case for example) +export type BodyType = CamelCase +``` diff --git a/docs/src/pages/reference/configuration/output.md b/docs/src/pages/reference/configuration/output.md index 74114d8a8..b5a096aaa 100644 --- a/docs/src/pages/reference/configuration/output.md +++ b/docs/src/pages/reference/configuration/output.md @@ -371,6 +371,9 @@ export const customInstance = (config: AxiosRequestConfig): Promise => { // In some case with react-query and swr you want to be able to override the return error type so you can also do it here like this export type ErrorType = AxiosError; +// In case you want to wrap the body type (optional) +// (if the custom instance is processing data before sending it, like changing the case for example) +export type BodyType = CamelCase ``` - If your file have some alias you will also need to define them in the mutator object. @@ -400,6 +403,7 @@ export const customInstance = (config: AxiosRequestConfig): Promise => { }; export type ErrorType = AxiosError; +export type BodyType = CamelCase ``` ```js @@ -475,6 +479,7 @@ export const useCustomInstance = (): (( export default useCustomInstance; export type ErrorType = AxiosError; +export type BodyType = CamelCase ``` #### header diff --git a/src/core/generators/imports.ts b/src/core/generators/imports.ts index 53d7dc2bb..f07053ee7 100644 --- a/src/core/generators/imports.ts +++ b/src/core/generators/imports.ts @@ -7,6 +7,7 @@ import { GeneratorVerbOptions, } from '../../types/generator'; import { camel } from '../../utils/case'; +import { BODY_TYPE_NAME } from './mutator'; export const generateImports = ({ imports = [], @@ -63,12 +64,14 @@ export const generateMutatorImports = ( const importDefault = mutator.default ? `${mutator.name}${ mutator.hasErrorType - ? `, { ErrorType as ${mutator.errorTypeName} }` + ? `, { ErrorType as ${mutator.errorTypeName}${ + mutator.bodyTypeName ? `, ${BODY_TYPE_NAME} as ${mutator.bodyTypeName}` : '' + } }` : '' }` : `{ ${mutator.name}${ mutator.hasErrorType ? `, ${mutator.errorTypeName}` : '' - } }`; + }${mutator.bodyTypeName ? `, ${mutator.bodyTypeName}` : ''} }`; return `import ${importDefault} from '${oneMore ? '../' : ''}${ mutator.path diff --git a/src/core/generators/mutator.ts b/src/core/generators/mutator.ts index a666fee98..08112bae0 100644 --- a/src/core/generators/mutator.ts +++ b/src/core/generators/mutator.ts @@ -7,6 +7,8 @@ import { getFileInfo, loadFile } from '../../utils/file'; import { createLogger } from '../../utils/messages/logs'; import { relativeSafe } from '../../utils/path'; +export const BODY_TYPE_NAME = 'BodyType'; + const getImport = (output: string, mutator: NormalizedMutator) => { const outputFileInfo = getFileInfo(output); const mutatorFileInfo = getFileInfo(mutator.path); @@ -43,10 +45,18 @@ export const generateMutator = async ({ rawFile.includes('export type ErrorType') || rawFile.includes('export interface ErrorType'); + const hasBodyType = + rawFile.includes(`export type ${BODY_TYPE_NAME}`) || + rawFile.includes(`export interface ${BODY_TYPE_NAME}`); + const errorTypeName = !mutator.default ? 'ErrorType' : `${pascal(name)}ErrorType`; + const bodyTypeName = !mutator.default + ? BODY_TYPE_NAME + : `${pascal(name)}${BODY_TYPE_NAME}`; + const { file, cached } = await loadFile>( importPath, { @@ -81,6 +91,7 @@ export const generateMutator = async ({ mutatorFn, hasErrorType, errorTypeName, + ...(hasBodyType ? { bodyTypeName } : {}), }; } else { const path = getImport(output, mutator); @@ -100,6 +111,7 @@ export const generateMutator = async ({ mutatorFn: () => undefined, hasErrorType, errorTypeName, + ...(hasBodyType ? { bodyTypeName } : {}), }; } }; diff --git a/src/core/generators/query.ts b/src/core/generators/query.ts index 537f0bd8a..d645bb79b 100644 --- a/src/core/generators/query.ts +++ b/src/core/generators/query.ts @@ -155,6 +155,13 @@ const generateQueryRequestFunction = ( isFormUrlEncoded, }); + const propsImplementation = mutator?.bodyTypeName + ? toObjectString(props, 'implementation').replace( + new RegExp(`(${verb}\\w*):\\s?(\\w*)`), + `$1: ${mutator.bodyTypeName}<$2>`, + ) + : toObjectString(props, 'implementation'); + const isMutatorHasSecondArg = mutator.mutatorFn.length > 1; const requestOptions = isRequestOptions ? generateMutatorRequestOptions( @@ -172,7 +179,7 @@ const generateQueryRequestFunction = ( response.definition.success || 'unknown' }>(); - return (\n ${toObjectString(props, 'implementation')}\n ${ + return (\n ${propsImplementation}\n ${ isRequestOptions && isMutatorHasSecondArg ? `options?: SecondParameter` : '' @@ -185,10 +192,7 @@ const generateQueryRequestFunction = ( `; } - return `export const ${operationName} = (\n ${toObjectString( - props, - 'implementation', - )}\n ${ + return `export const ${operationName} = (\n ${propsImplementation}\n ${ isRequestOptions && isMutatorHasSecondArg ? `options?: SecondParameter` : '' @@ -539,7 +543,11 @@ const generateQueryHook = ( const definitions = props .map(({ definition, type }) => - type === GetterPropType.BODY ? `data: ${body.definition}` : definition, + type === GetterPropType.BODY + ? mutator?.bodyTypeName + ? `data: ${mutator.bodyTypeName}<${body.definition}>` + : `data: ${body.definition}` + : definition, ) .join(';'); @@ -569,6 +577,10 @@ const generateQueryHook = ( export type ${pascal( operationName, )}MutationResult = NonNullable> + export type ${pascal(operationName)}MutationBody = ${definitions.replace( + /^.*data:\s?([\w<>]*),?.*$/, + '$1', + )} export type ${pascal(operationName)}MutationError = ${errorType} export const ${camel(`use-${operationName}`)} =