Skip to content

Commit 67bf84f

Browse files
authoredJan 3, 2024
feat: possible to generate a function using useSWRInfinite on the 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`
1 parent f67681f commit 67bf84f

File tree

3 files changed

+156
-25
lines changed

3 files changed

+156
-25
lines changed
 

‎docs/src/pages/reference/configuration/output.md

+31
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,37 @@ Default Value: `'root'`.
778778

779779
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`.
780780

781+
#### swr
782+
783+
Type: `Object`.
784+
785+
Give options to the generated `swr` client. It is also possible to extend the generated functions.
786+
787+
```js
788+
module.exports = {
789+
petstore: {
790+
output: {
791+
...
792+
override: {
793+
swr: {
794+
useInfinite: true,
795+
options: {
796+
dedupingInterval: 10000,
797+
},
798+
},
799+
},
800+
},
801+
...
802+
},
803+
};
804+
```
805+
806+
##### useInfinite
807+
808+
Type: `Boolean`.
809+
810+
Use to generate a <a href="https://swr.vercel.app/docs/pagination#useswrinfinite" target="_blank">useSWRInfinite</a> custom hook.
811+
781812
#### mock
782813

783814
Type: `Object`.

‎packages/core/src/types.ts

+1
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,7 @@ export type AngularOptions = {
356356

357357
export type SwrOptions = {
358358
options?: any;
359+
useInfinite?: boolean;
359360
};
360361

361362
export type InputTransformerFn = (spec: OpenAPIObject) => OpenAPIObject;

‎packages/swr/src/index.ts

+124-25
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,25 @@ const SWR_DEPENDENCIES: GeneratorDependency[] = [
7070
},
7171
];
7272

73+
const SWR_INFINITE_DEPENDENCIES: GeneratorDependency[] = [
74+
{
75+
exports: [
76+
{ name: 'useSWRInfinite', values: true, default: true },
77+
{ name: 'SWRInfiniteConfiguration' },
78+
{ name: 'SWRInfiniteKeyLoader' },
79+
],
80+
dependency: 'swr/infinite',
81+
},
82+
];
83+
7384
export const getSwrDependencies: ClientDependenciesBuilder = (
7485
hasGlobalMutator: boolean,
7586
hasParamsSerializerOptions: boolean,
7687
) => [
7788
...(!hasGlobalMutator ? AXIOS_DEPENDENCIES : []),
7889
...(hasParamsSerializerOptions ? PARAMS_SERIALIZER_DEPENDENCIES : []),
7990
...SWR_DEPENDENCIES,
91+
...SWR_INFINITE_DEPENDENCIES,
8092
];
8193

8294
const generateSwrRequestFunction = (
@@ -191,12 +203,20 @@ const generateSwrArguments = ({
191203
operationName,
192204
mutator,
193205
isRequestOptions,
206+
isInfinite,
194207
}: {
195208
operationName: string;
196209
mutator?: GeneratorMutator;
197210
isRequestOptions: boolean;
211+
isInfinite: boolean;
198212
}) => {
199-
const definition = `SWRConfiguration<Awaited<ReturnType<typeof ${operationName}>>, TError> & { swrKey?: Key, enabled?: boolean }`;
213+
const configType = isInfinite
214+
? 'SWRInfiniteConfiguration'
215+
: 'SWRConfiguration';
216+
const optionsType = isInfinite
217+
? '{ swrKeyLoader?: SWRInfiniteKeyLoader, enabled?: boolean }'
218+
: '{ swrKey?: Key, enabled?: boolean }';
219+
const definition = `${configType}<Awaited<ReturnType<typeof ${operationName}>>, TError> & ${optionsType}`;
200220

201221
if (!isRequestOptions) {
202222
return `swrOptions?: ${definition}`;
@@ -214,6 +234,7 @@ const generateSwrArguments = ({
214234
const generateSwrImplementation = ({
215235
operationName,
216236
swrKeyFnName,
237+
swrKeyLoaderFnName,
217238
swrProperties,
218239
swrKeyProperties,
219240
params,
@@ -227,6 +248,7 @@ const generateSwrImplementation = ({
227248
isRequestOptions: boolean;
228249
operationName: string;
229250
swrKeyFnName: string;
251+
swrKeyLoaderFnName: string;
230252
swrProperties: string;
231253
swrKeyProperties: string;
232254
params: GetterParams;
@@ -245,12 +267,13 @@ const generateSwrImplementation = ({
245267

246268
const httpFunctionProps = swrProperties;
247269

248-
const swrKeyImplementation = `const isEnabled = swrOptions?.enabled !== false${
270+
const enabledImplementation = `const isEnabled = swrOptions?.enabled !== false${
249271
params.length
250272
? ` && !!(${params.map(({ name }) => name).join(' && ')})`
251273
: ''
252-
}
253-
const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? ${swrKeyFnName}(${swrKeyProperties}) : null);`;
274+
}`;
275+
const swrKeyImplementation = `const swrKey = swrOptions?.swrKey ?? (() => isEnabled ? ${swrKeyFnName}(${swrKeyProperties}) : null);`;
276+
const swrKeyLoaderImplementation = `const swrKeyLoader = swrOptions?.swrKeyLoader ?? (() => isEnabled ? ${swrKeyLoaderFnName}(${swrKeyProperties}) : null);`;
254277

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

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

263-
return `
286+
const useSWRInfiniteImplementation = swrOptions.useInfinite
287+
? `
288+
export type ${pascal(
289+
operationName,
290+
)}InfiniteQueryResult = NonNullable<Awaited<ReturnType<typeof ${operationName}>>>
291+
export type ${pascal(operationName)}InfiniteError = ${errorType}
292+
293+
${doc}export const ${camel(
294+
`use-${operationName}-infinite`,
295+
)} = <TError = ${errorType}>(
296+
${swrProps} ${generateSwrArguments({
297+
operationName,
298+
mutator,
299+
isRequestOptions,
300+
isInfinite: true,
301+
})}) => {
302+
${
303+
isRequestOptions
304+
? `const {swr: swrOptions${
305+
!mutator
306+
? `, axios: axiosOptions`
307+
: mutator?.hasSecondArg
308+
? ', request: requestOptions'
309+
: ''
310+
}} = options ?? {}`
311+
: ''
312+
}
313+
314+
${enabledImplementation}
315+
${swrKeyLoaderImplementation}
316+
const swrFn = () => ${operationName}(${httpFunctionProps}${
317+
httpFunctionProps ? ', ' : ''
318+
}${
319+
isRequestOptions
320+
? !mutator
321+
? `axiosOptions`
322+
: mutator?.hasSecondArg
323+
? 'requestOptions'
324+
: ''
325+
: ''
326+
});
327+
328+
const ${queryResultVarName} = useSWRInfinite<Awaited<ReturnType<typeof swrFn>>, TError>(swrKeyLoader, swrFn, ${
329+
swrOptions.options
330+
? `{
331+
${stringify(swrOptions.options)?.slice(1, -1)}
332+
...swrOptions
333+
}`
334+
: 'swrOptions'
335+
})
336+
337+
return {
338+
swrKeyLoader,
339+
...${queryResultVarName}
340+
}
341+
}\n`
342+
: '';
343+
344+
const useSwrImplementation = `
264345
export type ${pascal(
265346
operationName,
266347
)}QueryResult = NonNullable<Awaited<ReturnType<typeof ${operationName}>>>
267348
export type ${pascal(operationName)}QueryError = ${errorType}
268349
269-
${doc}export const ${camel(
270-
`use-${operationName}`,
271-
)} = <TError = ${errorType}>(\n ${swrProps} ${generateSwrArguments({
350+
${doc}export const ${camel(`use-${operationName}`)} = <TError = ${errorType}>(
351+
${swrProps} ${generateSwrArguments({
272352
operationName,
273353
mutator,
274354
isRequestOptions,
275-
})}\n ) => {
276-
355+
isInfinite: false,
356+
})}) => {
277357
${
278358
isRequestOptions
279359
? `const {swr: swrOptions${
@@ -286,6 +366,7 @@ ${doc}export const ${camel(
286366
: ''
287367
}
288368
369+
${enabledImplementation}
289370
${swrKeyImplementation}
290371
const swrFn = () => ${operationName}(${httpFunctionProps}${
291372
httpFunctionProps ? ', ' : ''
@@ -313,6 +394,8 @@ ${doc}export const ${camel(
313394
...${queryResultVarName}
314395
}
315396
}\n`;
397+
398+
return useSWRInfiniteImplementation + useSwrImplementation;
316399
};
317400

318401
const generateSwrHook = (
@@ -364,26 +447,42 @@ const generateSwrHook = (
364447
'implementation',
365448
);
366449

450+
const swrKeyLoaderFnName = camel(`get-${operationName}-infinite-key-loader`);
451+
const swrKeyLoader = override.swr.useInfinite
452+
? `export const ${swrKeyLoaderFnName} = (${queryKeyProps}) => {
453+
return (_: number, previousPageData: Awaited<ReturnType<typeof ${operationName}>>) => {
454+
if (previousPageData && !previousPageData.data) return null
455+
456+
return [\`${route}\`${queryParams ? ', ...(params ? [params]: [])' : ''}${
457+
body.implementation ? `, ${body.implementation}` : ''
458+
}] as const;
459+
}
460+
}\n`
461+
: '';
462+
367463
const doc = jsDoc({ summary, deprecated });
368464

369-
return `export const ${swrKeyFnName} = (${queryKeyProps}) => [\`${route}\`${
465+
const swrKeyFn = `
466+
export const ${swrKeyFnName} = (${queryKeyProps}) => [\`${route}\`${
370467
queryParams ? ', ...(params ? [params]: [])' : ''
371468
}${body.implementation ? `, ${body.implementation}` : ''}] as const;
469+
\n`;
372470

373-
${generateSwrImplementation({
374-
operationName,
375-
swrKeyFnName,
376-
swrProperties,
377-
swrKeyProperties,
378-
params,
379-
props,
380-
mutator,
381-
isRequestOptions,
382-
response,
383-
swrOptions: override.swr,
384-
doc,
385-
})}
386-
`;
471+
const swrImplementation = generateSwrImplementation({
472+
operationName,
473+
swrKeyFnName,
474+
swrKeyLoaderFnName,
475+
swrProperties,
476+
swrKeyProperties,
477+
params,
478+
props,
479+
mutator,
480+
isRequestOptions,
481+
response,
482+
swrOptions: override.swr,
483+
doc,
484+
});
485+
return swrKeyFn + swrKeyLoader + swrImplementation;
387486
};
388487

389488
export const generateSwrHeader: ClientHeaderBuilder = ({

0 commit comments

Comments
 (0)
Please sign in to comment.