Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: possible to generate a function using useSWRInfinite on the swr client. #1138

Merged
merged 10 commits into from
Jan 3, 2024
31 changes: 31 additions & 0 deletions docs/src/pages/reference/configuration/output.md
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,37 @@ Default Value: `'root'`.

Can be used to set the value of `providedIn` on the generated Angular services. If `false`, no `providedIn` will be set. If `true` or not specified, it will fall back to the default value: `root`.

#### swr

Type: `Object`.

Give options to the generated `swr` client. It is also possible to extend the generated functions.

```js
module.exports = {
petstore: {
output: {
...
override: {
swr: {
useInfinite: true,
options: {
dedupingInterval: 10000,
},
},
},
},
...
},
};
```

##### useInfinite

Type: `Boolean`.

Use to generate a <a href="https://swr.vercel.app/docs/pagination#useswrinfinite" target="_blank">useSWRInfinite</a> custom hook.

#### mock

Type: `Object`.
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,7 @@ export type AngularOptions = {

export type SwrOptions = {
options?: any;
useInfinite?: boolean;
};

export type InputTransformerFn = (spec: OpenAPIObject) => OpenAPIObject;
Expand Down
149 changes: 124 additions & 25 deletions packages/swr/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,25 @@ const SWR_DEPENDENCIES: GeneratorDependency[] = [
},
];

const SWR_INFINITE_DEPENDENCIES: GeneratorDependency[] = [
{
exports: [
{ name: 'useSWRInfinite', values: true, default: true },
{ name: 'SWRInfiniteConfiguration' },
{ name: 'SWRInfiniteKeyLoader' },
],
dependency: 'swr/infinite',
},
];

export const getSwrDependencies: ClientDependenciesBuilder = (
hasGlobalMutator: boolean,
hasParamsSerializerOptions: boolean,
) => [
...(!hasGlobalMutator ? AXIOS_DEPENDENCIES : []),
...(hasParamsSerializerOptions ? PARAMS_SERIALIZER_DEPENDENCIES : []),
...SWR_DEPENDENCIES,
...SWR_INFINITE_DEPENDENCIES,
];

const generateSwrRequestFunction = (
Expand Down Expand Up @@ -191,12 +203,20 @@ const generateSwrArguments = ({
operationName,
mutator,
isRequestOptions,
isInfinite,
}: {
operationName: string;
mutator?: GeneratorMutator;
isRequestOptions: boolean;
isInfinite: boolean;
}) => {
const definition = `SWRConfiguration<Awaited<ReturnType<typeof ${operationName}>>, TError> & { swrKey?: Key, enabled?: boolean }`;
const configType = isInfinite
? 'SWRInfiniteConfiguration'
: 'SWRConfiguration';
const optionsType = isInfinite
? '{ swrKeyLoader?: SWRInfiniteKeyLoader, enabled?: boolean }'
: '{ swrKey?: Key, enabled?: boolean }';
const definition = `${configType}<Awaited<ReturnType<typeof ${operationName}>>, TError> & ${optionsType}`;

if (!isRequestOptions) {
return `swrOptions?: ${definition}`;
Expand All @@ -214,6 +234,7 @@ const generateSwrArguments = ({
const generateSwrImplementation = ({
operationName,
swrKeyFnName,
swrKeyLoaderFnName,
swrProperties,
swrKeyProperties,
params,
Expand All @@ -227,6 +248,7 @@ const generateSwrImplementation = ({
isRequestOptions: boolean;
operationName: string;
swrKeyFnName: string;
swrKeyLoaderFnName: string;
swrProperties: string;
swrKeyProperties: string;
params: GetterParams;
Expand All @@ -245,12 +267,13 @@ const generateSwrImplementation = ({

const httpFunctionProps = swrProperties;

const swrKeyImplementation = `const isEnabled = swrOptions?.enabled !== false${
const enabledImplementation = `const isEnabled = swrOptions?.enabled !== false${
params.length
? ` && !!(${params.map(({ name }) => name).join(' && ')})`
: ''
}
const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? ${swrKeyFnName}(${swrKeyProperties}) : null);`;
}`;
const swrKeyImplementation = `const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? ${swrKeyFnName}(${swrKeyProperties}) : null);`;
const swrKeyLoaderImplementation = `const swrKeyLoader = swrOptions?.swrKeyLoader ?? (() => isEnabled ? ${swrKeyLoaderFnName}(${swrKeyProperties}) : null);`;

let errorType = `AxiosError<${response.definition.errors || 'unknown'}>`;

Expand All @@ -260,20 +283,77 @@ const generateSwrImplementation = ({
: response.definition.errors || 'unknown';
}

return `
const useSWRInfiniteImplementation = swrOptions.useInfinite
? `
export type ${pascal(
operationName,
)}InfiniteQueryResult = NonNullable<Awaited<ReturnType<typeof ${operationName}>>>
export type ${pascal(operationName)}InfiniteError = ${errorType}

${doc}export const ${camel(
`use-${operationName}-infinite`,
)} = <TError = ${errorType}>(
${swrProps} ${generateSwrArguments({
operationName,
mutator,
isRequestOptions,
isInfinite: true,
})}) => {
${
isRequestOptions
? `const {swr: swrOptions${
!mutator
? `, axios: axiosOptions`
: mutator?.hasSecondArg
? ', request: requestOptions'
: ''
}} = options ?? {}`
: ''
}

${enabledImplementation}
${swrKeyLoaderImplementation}
const swrFn = () => ${operationName}(${httpFunctionProps}${
httpFunctionProps ? ', ' : ''
}${
isRequestOptions
? !mutator
? `axiosOptions`
: mutator?.hasSecondArg
? 'requestOptions'
: ''
: ''
});

const ${queryResultVarName} = useSWRInfinite<Awaited<ReturnType<typeof swrFn>>, TError>(swrKeyLoader, swrFn, ${
swrOptions.options
? `{
${stringify(swrOptions.options)?.slice(1, -1)}
...swrOptions
}`
: 'swrOptions'
})

return {
swrKeyLoader,
...${queryResultVarName}
}
}\n`
: '';

const useSwrImplementation = `
export type ${pascal(
operationName,
)}QueryResult = NonNullable<Awaited<ReturnType<typeof ${operationName}>>>
export type ${pascal(operationName)}QueryError = ${errorType}

${doc}export const ${camel(
`use-${operationName}`,
)} = <TError = ${errorType}>(\n ${swrProps} ${generateSwrArguments({
${doc}export const ${camel(`use-${operationName}`)} = <TError = ${errorType}>(
${swrProps} ${generateSwrArguments({
operationName,
mutator,
isRequestOptions,
})}\n ) => {

isInfinite: false,
})}) => {
${
isRequestOptions
? `const {swr: swrOptions${
Expand All @@ -286,6 +366,7 @@ ${doc}export const ${camel(
: ''
}

${enabledImplementation}
${swrKeyImplementation}
const swrFn = () => ${operationName}(${httpFunctionProps}${
httpFunctionProps ? ', ' : ''
Expand Down Expand Up @@ -313,6 +394,8 @@ ${doc}export const ${camel(
...${queryResultVarName}
}
}\n`;

return useSWRInfiniteImplementation + useSwrImplementation;
};

const generateSwrHook = (
Expand Down Expand Up @@ -364,26 +447,42 @@ const generateSwrHook = (
'implementation',
);

const swrKeyLoaderFnName = camel(`get-${operationName}-infinite-key-loader`);
const swrKeyLoader = override.swr.useInfinite
? `export const ${swrKeyLoaderFnName} = (${queryKeyProps}) => {
return (_: number, previousPageData: Awaited<ReturnType<typeof ${operationName}>>) => {
if (previousPageData && !previousPageData.data) return null

return [\`${route}\`${queryParams ? ', ...(params ? [params]: [])' : ''}${
body.implementation ? `, ${body.implementation}` : ''
}] as const;
}
}\n`
: '';

const doc = jsDoc({ summary, deprecated });

return `export const ${swrKeyFnName} = (${queryKeyProps}) => [\`${route}\`${
const swrKeyFn = `
export const ${swrKeyFnName} = (${queryKeyProps}) => [\`${route}\`${
queryParams ? ', ...(params ? [params]: [])' : ''
}${body.implementation ? `, ${body.implementation}` : ''}] as const;
\n`;

${generateSwrImplementation({
operationName,
swrKeyFnName,
swrProperties,
swrKeyProperties,
params,
props,
mutator,
isRequestOptions,
response,
swrOptions: override.swr,
doc,
})}
`;
const swrImplementation = generateSwrImplementation({
operationName,
swrKeyFnName,
swrKeyLoaderFnName,
swrProperties,
swrKeyProperties,
params,
props,
mutator,
isRequestOptions,
response,
swrOptions: override.swr,
doc,
});
return swrKeyFn + swrKeyLoader + swrImplementation;
};

export const generateSwrHeader: ClientHeaderBuilder = ({
Expand Down