@@ -18,7 +18,7 @@ const PATH_PARAM_RE = /\{[^}]+\}/g;
18
18
* Transform the PathsObject node (4.8.8)
19
19
* @see https://spec.openapis.org/oas/v3.1.0#operation-object
20
20
*/
21
- export default function transformPathsObject ( pathsObject : PathsObject , ctx : GlobalContext ) : ts . TypeNode {
21
+ export function transformPathsObject ( pathsObject : PathsObject , ctx : GlobalContext ) : ts . TypeNode {
22
22
const type : ts . TypeElement [ ] = [ ] ;
23
23
for ( const [ url , pathItemObject ] of getEntries ( pathsObject , ctx ) ) {
24
24
if ( ! pathItemObject || typeof pathItemObject !== "object" ) {
@@ -43,67 +43,121 @@ export default function transformPathsObject(pathsObject: PathsObject, ctx: Glob
43
43
ctx,
44
44
} ) ;
45
45
46
- // pathParamsAsTypes
47
- if ( ctx . pathParamsAsTypes && url . includes ( "{" ) ) {
48
- const pathParams = extractPathParams ( pathItemObject , ctx ) ;
49
- const matches = url . match ( PATH_PARAM_RE ) ;
50
- let rawPath = `\`${ url } \`` ;
51
- if ( matches ) {
52
- for ( const match of matches ) {
53
- const paramName = match . slice ( 1 , - 1 ) ;
54
- const param = pathParams [ paramName ] ;
55
- switch ( param ?. schema ?. type ) {
56
- case "number" :
57
- case "integer" :
58
- rawPath = rawPath . replace ( match , "${number}" ) ;
59
- break ;
60
- case "boolean" :
61
- rawPath = rawPath . replace ( match , "${boolean}" ) ;
62
- break ;
63
- default :
64
- rawPath = rawPath . replace ( match , "${string}" ) ;
65
- break ;
66
- }
67
- }
68
- // note: creating a string template literal’s AST manually is hard!
69
- // just pass an arbitrary string to TS
70
- const pathType = ( stringToAST ( rawPath ) [ 0 ] as any ) ?. expression ;
71
- if ( pathType ) {
72
- type . push (
73
- ts . factory . createIndexSignature (
74
- /* modifiers */ tsModifiers ( { readonly : ctx . immutable } ) ,
75
- /* parameters */ [
76
- ts . factory . createParameterDeclaration (
77
- /* modifiers */ undefined ,
78
- /* dotDotDotToken */ undefined ,
79
- /* name */ "path" ,
80
- /* questionToken */ undefined ,
81
- /* type */ pathType ,
82
- /* initializer */ undefined ,
83
- ) ,
84
- ] ,
85
- /* type */ pathItemType ,
86
- ) ,
87
- ) ;
88
- continue ;
89
- }
46
+ if ( ! ( ctx . pathParamsAsTypes && url . includes ( "{" ) ) ) {
47
+ type . push (
48
+ ts . factory . createPropertySignature (
49
+ /* modifiers */ tsModifiers ( { readonly : ctx . immutable } ) ,
50
+ /* name */ tsPropertyIndex ( url ) ,
51
+ /* questionToken */ undefined ,
52
+ /* type */ pathItemType ,
53
+ ) ,
54
+ ) ;
55
+ }
56
+
57
+ debug ( `Transformed path "${ url } "` , "ts" , performance . now ( ) - pathT ) ;
58
+ }
59
+ }
60
+
61
+ return ts . factory . createTypeLiteralNode ( type ) ;
62
+ }
63
+
64
+ export function transformDynamicPathsObject ( pathsObject : PathsObject , ctx : GlobalContext ) : ts . TypeNode {
65
+ if ( ! ctx . pathParamsAsTypes ) {
66
+ return ts . factory . createTypeLiteralNode ( [ ] ) ;
67
+ }
68
+
69
+ const types : ts . TypeNode [ ] = [ ] ;
70
+ for ( const [ url , pathItemObject ] of getEntries ( pathsObject , ctx ) ) {
71
+ if ( ! pathItemObject || typeof pathItemObject !== "object" ) {
72
+ continue ;
73
+ }
74
+
75
+ if ( ! url . includes ( "{" ) ) {
76
+ continue ;
77
+ }
78
+ if ( "$ref" in pathItemObject ) {
79
+ continue ;
80
+ }
81
+
82
+ const pathT = performance . now ( ) ;
83
+
84
+ // handle $ref
85
+ const pathItemType = transformPathItemObject ( pathItemObject , {
86
+ path : createRef ( [ "paths" , url ] ) ,
87
+ ctx,
88
+ } ) ;
89
+
90
+ // pathParamsAsTypes
91
+ const pathParams = extractPathParams ( pathItemObject , ctx ) ;
92
+ const matches = url . match ( PATH_PARAM_RE ) ;
93
+ let rawPath = `\`${ url } \`` ;
94
+ if ( matches ) {
95
+ for ( const match of matches ) {
96
+ const paramName = match . slice ( 1 , - 1 ) ;
97
+ const param = pathParams [ paramName ] ;
98
+ switch ( param ?. schema ?. type ) {
99
+ case "number" :
100
+ case "integer" :
101
+ rawPath = rawPath . replace ( match , "${number}" ) ;
102
+ break ;
103
+ case "boolean" :
104
+ rawPath = rawPath . replace ( match , "${boolean}" ) ;
105
+ break ;
106
+ default :
107
+ rawPath = rawPath . replace ( match , "${string}" ) ;
108
+ break ;
90
109
}
91
110
}
111
+ // note: creating a string template literal's AST manually is hard!
112
+ // just pass an arbitrary string to TS
113
+ const pathType = ( stringToAST ( rawPath ) [ 0 ] as any ) ?. expression ;
114
+ if ( pathType ) {
115
+ types . push (
116
+ ts . factory . createTypeLiteralNode ( [
117
+ ts . factory . createIndexSignature (
118
+ /* modifiers */ tsModifiers ( { readonly : ctx . immutable } ) ,
119
+ /* parameters */ [
120
+ ts . factory . createParameterDeclaration (
121
+ /* modifiers */ undefined ,
122
+ /* dotDotDotToken */ undefined ,
123
+ /* name */ "path" ,
124
+ /* questionToken */ undefined ,
125
+ /* type */ pathType ,
126
+ /* initializer */ undefined ,
127
+ ) ,
128
+ ] ,
129
+ /* type */ pathItemType ,
130
+ ) ,
131
+ ] ) ,
132
+ ) ;
133
+ continue ;
134
+ }
135
+ }
92
136
93
- type . push (
137
+ types . push (
138
+ ts . factory . createTypeLiteralNode ( [
94
139
ts . factory . createPropertySignature (
95
140
/* modifiers */ tsModifiers ( { readonly : ctx . immutable } ) ,
96
141
/* name */ tsPropertyIndex ( url ) ,
97
142
/* questionToken */ undefined ,
98
143
/* type */ pathItemType ,
99
144
) ,
100
- ) ;
145
+ ] ) ,
146
+ ) ;
101
147
102
- debug ( `Transformed path "${ url } "` , "ts" , performance . now ( ) - pathT ) ;
103
- }
148
+ debug ( `Transformed path "${ url } "` , "ts" , performance . now ( ) - pathT ) ;
104
149
}
105
150
106
- return ts . factory . createTypeLiteralNode ( type ) ;
151
+ // // Combine all types with intersection
152
+ // if (types.length === 0) {
153
+ // return ts.factory.createTypeLiteralNode([]);
154
+ // }
155
+
156
+ // if (types.length === 1) {
157
+ // return types[0];
158
+ // }
159
+
160
+ return ts . factory . createIntersectionTypeNode ( types ) ;
107
161
}
108
162
109
163
function extractPathParams ( pathItemObject : PathItemObject , ctx : GlobalContext ) {
0 commit comments