1- import type { MethodDeclaration } from "ts-morph" ;
1+ import type { MethodDeclaration , Symbol as TMSymbol } from "ts-morph" ;
22import ts from "typescript" ;
33import {
44 BuildCommonTypeName ,
@@ -19,7 +19,10 @@ import { addJSDocToNode } from "./util.mjs";
1919export const createApiResponseType = ( {
2020 className,
2121 methodName,
22- } : { className : string ; methodName : string } ) => {
22+ } : {
23+ className : string ;
24+ methodName : string ;
25+ } ) => {
2326 /** Awaited<ReturnType<typeof myClass.myMethod>> */
2427 const awaitedResponseDataType = ts . factory . createTypeReferenceNode (
2528 ts . factory . createIdentifier ( "Awaited" ) ,
@@ -44,7 +47,9 @@ export const createApiResponseType = ({
4447 const apiResponse = ts . factory . createTypeAliasDeclaration (
4548 [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
4649 ts . factory . createIdentifier (
47- `${ capitalizeFirstLetter ( className ) } ${ capitalizeFirstLetter ( methodName ) } DefaultResponse` ,
50+ `${ capitalizeFirstLetter ( className ) } ${ capitalizeFirstLetter (
51+ methodName ,
52+ ) } DefaultResponse`,
4853 ) ,
4954 undefined ,
5055 awaitedResponseDataType ,
@@ -146,7 +151,9 @@ export function createReturnTypeExport({
146151 return ts . factory . createTypeAliasDeclaration (
147152 [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
148153 ts . factory . createIdentifier (
149- `${ capitalizeFirstLetter ( className ) } ${ capitalizeFirstLetter ( methodName ) } QueryResult` ,
154+ `${ capitalizeFirstLetter ( className ) } ${ capitalizeFirstLetter (
155+ methodName ,
156+ ) } QueryResult`,
150157 ) ,
151158 [
152159 ts . factory . createTypeParameterDeclaration (
@@ -179,7 +186,11 @@ export function createQueryKeyExport({
179186 className,
180187 methodName,
181188 queryKey,
182- } : { className : string ; methodName : string ; queryKey : string } ) {
189+ } : {
190+ className : string ;
191+ methodName : string ;
192+ queryKey : string ;
193+ } ) {
183194 return ts . factory . createVariableStatement (
184195 [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
185196 ts . factory . createVariableDeclarationList (
@@ -201,20 +212,56 @@ export function createQueryKeyExport({
201212export function hookNameFromMethod ( {
202213 method,
203214 className,
204- } : { method : MethodDeclaration ; className : string } ) {
215+ } : {
216+ method : MethodDeclaration ;
217+ className : string ;
218+ } ) {
205219 const methodName = getNameFromMethod ( method ) ;
206220 return `use${ className } ${ capitalizeFirstLetter ( methodName ) } ` ;
207221}
208222
209223export function createQueryKeyFromMethod ( {
210224 method,
211225 className,
212- } : { method : MethodDeclaration ; className : string } ) {
226+ } : {
227+ method : MethodDeclaration ;
228+ className : string ;
229+ } ) {
213230 const customHookName = hookNameFromMethod ( { method, className } ) ;
214231 const queryKey = `${ customHookName } Key` ;
215232 return queryKey ;
216233}
217234
235+ /**
236+ * Extracts the type of the next page parameter from the given properties.
237+ *
238+ * @param properties The properties to search through.
239+ * @param nextPageParam The name of the next page parameter.
240+ * @returns The type of the next page parameter, if found.
241+ */
242+ function findNextPageParamType (
243+ properties : TMSymbol [ ] | undefined ,
244+ nextPageParam : string ,
245+ ) : string | undefined {
246+ if ( ! properties ) return undefined ;
247+
248+ for ( const property of properties ) {
249+ if ( property . getName ( ) === nextPageParam ) {
250+ return property ?. getDeclarations ( ) ?. at ( 0 ) ?. getType ( ) ?. getText ( ) ;
251+ }
252+
253+ const type = property . getDeclarations ( ) . at ( 0 ) ?. getType ( ) ;
254+ const nestedProperties = type ?. getProperties ( ) ;
255+
256+ if ( ! type ?. isObject ( ) || type . isArray ( ) ) continue ;
257+
258+ const result = findNextPageParamType ( nestedProperties , nextPageParam ) ;
259+ if ( result ) return result ;
260+ }
261+
262+ return undefined ;
263+ }
264+
218265/**
219266 * Creates a custom hook for a query
220267 * @param queryString The type of query to use from react-query
@@ -260,6 +307,18 @@ export function createQueryHook({
260307 const responseDataTypeIdentifier =
261308 responseDataTypeRef . typeName as ts . Identifier ;
262309
310+ const arg = method . getReturnType ( ) . getTypeArguments ( ) . at ( 0 ) ;
311+
312+ const nextPageParamTypePropetires = arg ?. getProperties ( ) ;
313+
314+ const nextPageParamType =
315+ arg ?. isObject ( ) && nextPageParam
316+ ? findNextPageParamType (
317+ nextPageParamTypePropetires ,
318+ nextPageParam . split ( "." ) . at ( - 1 ) ?? "" ,
319+ )
320+ : undefined ;
321+
263322 const hookExport = ts . factory . createVariableStatement (
264323 [ ts . factory . createModifier ( ts . SyntaxKind . ExportKeyword ) ] ,
265324 ts . factory . createVariableDeclarationList (
@@ -430,7 +489,11 @@ export function createQueryHook({
430489 "pageParam" ,
431490 ) ,
432491 ts . factory . createKeywordTypeNode (
433- ts . SyntaxKind . NumberKeyword ,
492+ p . type ?. getText ( ) === "number"
493+ ? ts . SyntaxKind
494+ . NumberKeyword
495+ : ts . SyntaxKind
496+ . StringKeyword ,
434497 ) ,
435498 ) ,
436499 )
@@ -453,6 +516,7 @@ export function createQueryHook({
453516 pageParam ,
454517 nextPageParam ,
455518 initialPageParam ,
519+ nextPageParamType ,
456520 ) ,
457521 ts . factory . createSpreadAssignment (
458522 ts . factory . createIdentifier ( "options" ) ,
@@ -637,6 +701,7 @@ function createInfiniteQueryParams(
637701 pageParam ?: string ,
638702 nextPageParam ?: string ,
639703 initialPageParam = "1" ,
704+ type ?: string ,
640705) {
641706 if ( pageParam === undefined || nextPageParam === undefined ) {
642707 return [ ] ;
@@ -667,18 +732,23 @@ function createInfiniteQueryParams(
667732 ts . factory . createParenthesizedExpression (
668733 ts . factory . createAsExpression (
669734 ts . factory . createIdentifier ( "response" ) ,
670- nextPageParam . split ( "." ) . reduceRight ( ( acc , segment ) => {
671- return ts . factory . createTypeLiteralNode ( [
672- ts . factory . createPropertySignature (
673- undefined ,
674- ts . factory . createIdentifier ( segment ) ,
675- undefined ,
676- acc ,
677- ) ,
678- ] ) ;
679- } , ts . factory . createKeywordTypeNode (
680- ts . SyntaxKind . NumberKeyword ,
681- ) as ts . TypeNode ) ,
735+ nextPageParam . split ( "." ) . reduceRight (
736+ ( acc , segment ) => {
737+ return ts . factory . createTypeLiteralNode ( [
738+ ts . factory . createPropertySignature (
739+ undefined ,
740+ ts . factory . createIdentifier ( segment ) ,
741+ undefined ,
742+ acc ,
743+ ) ,
744+ ] ) ;
745+ } ,
746+ ts . factory . createKeywordTypeNode (
747+ type === "number"
748+ ? ts . SyntaxKind . NumberKeyword
749+ : ts . SyntaxKind . StringKeyword ,
750+ ) as ts . TypeNode ,
751+ ) ,
682752 ) ,
683753 ) ,
684754 ts . factory . createIdentifier ( nextPageParam ) ,
0 commit comments