@@ -2,117 +2,162 @@ import { BaseBuildModuleReturn, BuildModuleReturn } from '@/api/lib/module';
22import { Route } from '@/api/lib/route' ;
33import { usersModule } from '@/api/modules/users/users.module' ;
44
5- interface RouteSpec {
6- readonly method : string ;
7- readonly path : string ;
8- }
5+ // --- Core Type Definitions ---
96
7+ // Represents the expected shape of a route for type extraction
108interface RouteShape {
11- readonly route : RouteSpec ;
9+ readonly route : {
10+ readonly method : string ;
11+ readonly path : string ;
12+ } ;
1213}
1314
15+ // Represents the expected shape of a module for type extraction
1416interface ModuleSpec {
1517 readonly modules ?: readonly ModuleSpec [ ] ;
1618 readonly name : string ;
1719 readonly routes : readonly RouteShape [ ] ;
1820}
1921
22+ // --- Utility Types ---
23+
24+ // Splits a path string like "a/b/c" into ["a", "b", "c"]
2025type SplitPath < S extends string > = S extends `${infer First } /${infer Rest } `
2126 ? [ First , ...SplitPath < Rest > ]
22- : [ S ] ;
27+ : S extends '' // Handle empty string case
28+ ? [ ]
29+ : [ S ] ;
2330
31+ // Recursively finds a nested module definition based on a path array
2432type FindModuleNested <
2533 M extends { modules ?: readonly ModuleSpec [ ] } ,
2634 Path extends string [ ] ,
2735> = Path extends [ infer First extends string , ...infer Rest extends string [ ] ]
28- ? Rest [ 'length' ] extends 0
29- ? Extract < M [ 'modules' ] , readonly ModuleSpec [ ] > [ number ] extends infer SubM
30- ? Extract < SubM , { name : First } >
36+ ? // Find the sub-module matching the first path segment
37+ Extract < M [ 'modules' ] , readonly ModuleSpec [ ] > [ number ] extends infer SubModule
38+ ? SubModule extends ModuleSpec & { name : First }
39+ ? // If this is the last segment, return the found sub-module
40+ Rest [ 'length' ] extends 0
41+ ? SubModule
42+ : // Otherwise, recurse into the found sub-module
43+ FindModuleNested < SubModule , Rest >
44+ : never // No sub-module found with that name
45+ : never // M['modules'] is not an array or is empty
46+ : // If Path is empty, it implies we are looking for the module M itself
47+ M ;
48+
49+ // Helper to get the target module specification based on the module path string
50+ // It handles the base module case and nested module cases.
51+ type GetTargetModule <
52+ ModulePath extends string ,
53+ MainModuleName extends string ,
54+ MainRoutes extends readonly RouteShape [ ] ,
55+ SubModules extends readonly ModuleSpec [ ] ,
56+ > = ModulePath extends MainModuleName
57+ ? { modules : SubModules ; name : MainModuleName ; routes : MainRoutes } // Return the main module spec
58+ : ModulePath extends `${MainModuleName } /${infer Rest } `
59+ ? SplitPath < Rest > extends infer PathArray extends string [ ]
60+ ? PathArray [ 'length' ] extends 0
61+ ? never // Path like "main/" is invalid
62+ : FindModuleNested < { modules : SubModules } , PathArray >
3163 : never
32- : FindModuleNested <
33- Extract <
34- Extract < M [ 'modules' ] , readonly ModuleSpec [ ] > [ number ] ,
35- { name : First }
36- > ,
37- Rest
38- >
39- : M ;
64+ : never ; // Path doesn't start with the main module name
4065
66+ // Extracts all possible path strings from a module's routes
4167type ExtractPaths < M extends { routes : readonly RouteShape [ ] } > =
4268 M [ 'routes' ] [ number ] [ 'route' ] [ 'path' ] ;
4369
44- type ExtractMethod <
70+ // Extracts the method string for a specific path within a module's routes
71+ type ExtractMethodForPath <
4572 M extends { routes : readonly RouteShape [ ] } ,
4673 P extends string ,
47- > = Extract < M [ 'routes' ] [ number ] [ 'route' ] , { path : P } > [ 'method' ] ;
74+ > = Extract < M [ 'routes' ] [ number ] , { route : { path : P } } > [ 'route' ] [ 'method' ] ;
75+
76+ // --- Derived Types for Fetcher ---
4877
49- type GetModulePaths <
78+ // Gets all valid path strings for a given module path (e.g., "users" or "users/sso")
79+ type GetValidPathsForModule <
5080 ModulePath extends string ,
51- MainModule extends string ,
52- Routes extends Route [ ] ,
53- Modules extends BaseBuildModuleReturn [ ] ,
54- > = ModulePath extends MainModule
55- ? ExtractPaths < { routes : Routes } >
56- : ModulePath extends `${MainModule } /${infer Rest } `
57- ? ExtractPaths < FindModuleNested < { modules : Modules } , SplitPath < Rest > > >
58- : never ;
59-
60- type GetModuleMethod <
81+ MainModuleName extends string ,
82+ MainRoutes extends readonly RouteShape [ ] ,
83+ SubModules extends readonly ModuleSpec [ ] ,
84+ > = ExtractPaths <
85+ GetTargetModule < ModulePath , MainModuleName , MainRoutes , SubModules >
86+ > ;
87+
88+ // Gets the valid method (lowercase) for a given module path and a specific path within that module
89+ type GetValidMethodForPath <
6190 ModulePath extends string ,
62- MainModule extends string ,
6391 Path extends string ,
64- Routes extends Route [ ] ,
65- Modules extends BaseBuildModuleReturn [ ] ,
66- > = ModulePath extends MainModule
67- ? ExtractMethod < { routes : Routes } , Path >
68- : ModulePath extends `${MainModule } /${infer Rest } `
69- ? ExtractMethod <
70- FindModuleNested < { modules : Modules } , SplitPath < Rest > > ,
71- Path
72- >
73- : never ;
92+ MainModuleName extends string ,
93+ MainRoutes extends readonly RouteShape [ ] ,
94+ SubModules extends readonly ModuleSpec [ ] ,
95+ > = Lowercase <
96+ Extract <
97+ ExtractMethodForPath <
98+ GetTargetModule < ModulePath , MainModuleName , MainRoutes , SubModules > ,
99+ Path
100+ > ,
101+ string // Ensure we only get string methods
102+ >
103+ > ;
74104
105+ // --- Fetcher Function Definition ---
106+
107+ // Define the structure for the fetcher parameters, using the derived types for constraints
75108interface FetcherParams <
109+ // Generic parameters from BuildModuleReturn
76110 P extends string ,
77111 M extends string ,
78112 Routes extends Route [ ] ,
79113 Modules extends BaseBuildModuleReturn < P > [ ] ,
80- ModuleName extends string ,
81- SelectedPath extends GetModulePaths < ModuleName , M , Routes , Modules > ,
114+ // The specific module path string provided by the user (e.g., "users/sso")
115+ // This complex union type accurately constrains valid module paths.
116+ ModuleName extends
117+ | `${M } /${Modules [ number ] [ 'name' ] } /${Extract <
118+ Modules [ number ] [ 'modules' ] ,
119+ readonly BaseBuildModuleReturn < P > [ ]
120+ > [ number ] [ 'name' ] } ` // Second level sub-module
121+ | `${M } /${Modules [ number ] [ 'name' ] } ` // First level sub-module (e.g., "users/sso")
122+ // Add support for deeper nesting if necessary:
123+ | M , // Base module name (e.g., "users")
124+ // The specific path string selected within the chosen module
125+ SelectedPath extends GetValidPathsForModule < ModuleName , M , Routes , Modules > ,
82126> {
83- input ?: string ;
84- method : Lowercase <
85- GetModuleMethod < ModuleName , M , SelectedPath , Routes , Modules >
86- > ;
127+ input ?: unknown ; // TODO: Define input type based on the route if possible
128+ method : GetValidMethodForPath < ModuleName , SelectedPath , M , Routes , Modules > ;
87129 module : ModuleName ;
88130 path : SelectedPath ;
89131}
90132
133+ // The fetcher function signature
91134export function fetcher <
135+ // Generic parameters matching BuildModuleReturn
92136 P extends string ,
93137 M extends string ,
94138 Routes extends Route [ ] ,
95139 Modules extends BaseBuildModuleReturn < P > [ ] ,
140+ // Constrain ModuleName to valid possibilities based on the module structure
96141 ModuleName extends
97142 | `${M } /${Modules [ number ] [ 'name' ] } /${Extract <
98143 Modules [ number ] [ 'modules' ] ,
99144 readonly BaseBuildModuleReturn < P > [ ]
100145 > [ number ] [ 'name' ] } `
101146 | `${M } /${Modules [ number ] [ 'name' ] } `
102147 | M ,
103- SelectedPath extends GetModulePaths < ModuleName , M , Routes , Modules > ,
148+ // SelectedPath is constrained based on the chosen ModuleName
149+ SelectedPath extends GetValidPathsForModule < ModuleName , M , Routes , Modules > ,
104150> (
105- moduleInput : BuildModuleReturn < P , M , Routes , Modules > ,
151+ _moduleInput : BuildModuleReturn < P , M , Routes , Modules > , // Mark as unused
106152 params : FetcherParams < P , M , Routes , Modules , ModuleName , SelectedPath > ,
107153) : void {
108- void moduleInput ;
109- void params ;
154+ // Function implementation would go here
155+ void params ; // Mark as unused for now
110156}
111157
112- // Example usage
113158( ( ) => {
114159 fetcher ( usersModule , {
115- path : '/session ' ,
160+ path : '/test ' ,
116161 method : 'get' ,
117162 module : 'users' ,
118163 } ) ;
@@ -124,13 +169,7 @@ export function fetcher<
124169 } ) ;
125170
126171 fetcher ( usersModule , {
127- path : '/session' ,
128- method : 'post' ,
129- module : 'users' ,
130- } ) ;
131-
132- fetcher ( usersModule , {
133- path : '/{providerId}' ,
172+ path : '/{providerId}/callback' ,
134173 method : 'get' ,
135174 module : 'users/sso' ,
136175 } ) ;
0 commit comments