Skip to content

Commit

Permalink
feat: possible to generate a function using useSWRInfinite on the `…
Browse files Browse the repository at this point in the history
…swr` client. (#1138)

* feat: add `swr/infinite` dependesies

* chore: refactor string construction process

* feat: add `useInfinite` property into `SwrOptions` type

* feat: define `swrKeyLoader` function generator

* chore: refactoring to store the function that defines `useSrw` in a variable

* feat: add useInfinite function string generator implementation

* chore: refactoring to separate enable and key implementation

* fix: enerated implementation mess

* fix: change presence/absence of definition with `override.swr.useinfinite`

* docs: add document for `orverride.swr.useInfinite`
  • Loading branch information
soartec-lab authored Jan 3, 2024
1 parent f67681f commit 67bf84f
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 25 deletions.
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

0 comments on commit 67bf84f

Please sign in to comment.