1
1
import fs from 'fs' ;
2
2
import path from 'path' ;
3
- import { Project } from 'ts-morph' ;
3
+ import { MethodDeclarationStructure , OptionalKind , Project } from 'ts-morph' ;
4
4
5
5
import endpoints from '../src/utils/Endpoints.js' ;
6
6
import rootEndpoints from '../src/utils/RootEndpoints.js' ;
@@ -115,34 +115,40 @@ console.timeLog(mainLabel, ' - Base generated, generating methods...');
115
115
116
116
// Add the get generic resource array method
117
117
const getResourceCode = `try {
118
+ // Fail if the endpoint is not supplied
118
119
if (!endpoint) {
119
120
throw new Error('Param "endpoint" is required needs to be a string or array of strings');
120
121
}
121
122
123
+ // Fail if the input types aren't accepted
124
+ if (!Array.isArray(endpoint) && typeof endpoint !== 'string') {
125
+ throw new Error('Param "endpoint" needs to be a string or array of strings');
126
+ }
127
+
128
+ /// If the user has submitted a string, return the JSON promise
122
129
if (typeof endpoint === 'string') {
123
130
return getJSON<any>(this.options, endpoint, callback);
124
- } else if (typeof endpoint === 'object') {
125
- const mapper = async (endpoints: string) => {
126
- const queryRes = await getJSON<any>(this.options, endpoints);
127
- return queryRes;
128
- };
131
+ }
129
132
130
- // Fetch data asynchronously to be faster
131
- const mappedResults = await pMap(endpoint, mapper, { concurrency: 4 });
133
+ // If the user has submitted an Array return a new promise which will resolve when all getJSON calls are ended
134
+ const mapper = async (endpoints: string) => {
135
+ const queryRes = await getJSON<any>(this.options, endpoints);
136
+ return queryRes;
137
+ };
132
138
133
- if (callback) {
134
- callback(mappedResults);
135
- }
139
+ // Fetch data asynchronously to be faster
140
+ const mappedResults = await pMap(endpoint, mapper, { concurrency: 4 });
136
141
137
- return mappedResults;
138
- } else {
139
- throw new Error('Param "endpoint" needs to be a string or array of strings');
142
+ if (callback) {
143
+ callback(mappedResults);
140
144
}
145
+
146
+ return mappedResults;
141
147
} catch (error) {
142
148
handleError(error, callback);
143
149
}` ;
144
150
145
- let methodStructure = {
151
+ let methodStructure : OptionalKind < MethodDeclarationStructure > = {
146
152
name : 'getResource' ,
147
153
isAsync : true ,
148
154
parameters : [ {
@@ -155,6 +161,36 @@ let methodStructure = {
155
161
hasQuestionToken : true ,
156
162
} ] ,
157
163
returnType : 'Promise<any | any[]>' ,
164
+ overloads : [
165
+ {
166
+ parameters : [
167
+ {
168
+ name : 'endpoint' ,
169
+ type : 'string' ,
170
+ } ,
171
+ {
172
+ name : 'callback' ,
173
+ type : '(result: any, error?: any) => any' ,
174
+ hasQuestionToken : true ,
175
+ } ,
176
+ ] ,
177
+ returnType : 'Promise<any>' ,
178
+ } ,
179
+ {
180
+ parameters : [
181
+ {
182
+ name : 'endpoint' ,
183
+ type : 'string[]' ,
184
+ } ,
185
+ {
186
+ name : 'callback' ,
187
+ type : '(result: any[], error?: any) => any' ,
188
+ hasQuestionToken : true ,
189
+ } ,
190
+ ] ,
191
+ returnType : 'Promise<any[]>' ,
192
+ } ,
193
+ ] ,
158
194
} ;
159
195
160
196
pokeApiClass . addMethod ( methodStructure ) . setBodyText ( getResourceCode ) ;
@@ -182,6 +218,11 @@ for (const [methodName, endpoint, jsdocs] of endpoints) {
182
218
const inputParam = methodName . match ( / B y N a m e $ / ) ? 'nameOrId' : 'id' ;
183
219
const inputParamType = methodName . match ( / B y N a m e $ / ) ? 'string | number | Array<string | number>' : 'number | number[]' ;
184
220
221
+ const singleParamType = methodName . match ( / B y N a m e $ / ) ? 'string | number' : 'number' ;
222
+ const multipleParamType = methodName . match ( / B y N a m e $ / ) ? 'Array<string | number>' : 'number[]' ;
223
+
224
+ const returnType = `PokeAPITypes.${ apiMap [ endpoint ] } ` ;
225
+
185
226
methodStructure = {
186
227
name : methodName ,
187
228
isAsync : true ,
@@ -191,50 +232,80 @@ for (const [methodName, endpoint, jsdocs] of endpoints) {
191
232
} ,
192
233
{
193
234
name : 'callback' ,
194
- type : `(result: PokeAPITypes. ${ apiMap [ endpoint ] } | PokeAPITypes. ${ apiMap [ endpoint ] } [], error?: any) => any` ,
235
+ type : `(( result: ${ returnType } , error?: any) => any) & ((result: ${ returnType } [], error?: any) => any) ` ,
195
236
hasQuestionToken : true ,
196
237
} ] ,
197
- returnType : `Promise<PokeAPITypes.${ apiMap [ endpoint ] } | PokeAPITypes.${ apiMap [ endpoint ] } []>` ,
238
+ returnType : `Promise<${ returnType } | ${ returnType } []>` ,
239
+ overloads : [
240
+ {
241
+ parameters : [
242
+ {
243
+ name : inputParam ,
244
+ type : singleParamType ,
245
+ } ,
246
+ {
247
+ name : 'callback' ,
248
+ type : `(result: ${ returnType } , error?: any) => any` ,
249
+ hasQuestionToken : true ,
250
+ } ,
251
+ ] ,
252
+ returnType : `Promise<${ returnType } >` ,
253
+ } ,
254
+ {
255
+ parameters : [
256
+ {
257
+ name : inputParam ,
258
+ type : multipleParamType ,
259
+ } ,
260
+ {
261
+ name : 'callback' ,
262
+ type : `(result: ${ returnType } [], error?: any) => any` ,
263
+ hasQuestionToken : true ,
264
+ } ,
265
+ ] ,
266
+ returnType : `Promise<${ returnType } []>` ,
267
+ } ,
268
+ ] ,
198
269
} ;
199
270
200
271
const generatedMethod = pokeApiClass . addMethod ( methodStructure ) . setBodyText ( `try {
201
- if (${ inputParam } ) {
202
- // If the user has submitted a Name or an ID, return the JSON promise
203
- if (typeof ${ inputParam } === 'number' || typeof ${ inputParam } === 'string') {
204
- return getJSON<PokeAPITypes.${ apiMap [ endpoint ] } >(this.options, \`\${this.options.protocol}\${this.options.hostName}\${this.options.versionPath}${ endpoint } /\${${ inputParam } }/\`, callback);
205
- }
272
+ // Fail if the param is not supplied
273
+ if (!${ inputParam } ) {
274
+ throw new Error('Param "${ inputParam } " is required (Must be a ${ methodName . match ( / B y N a m e $ / ) ? 'string, array of strings or array of string and/or numbers' : 'number or array of numbers' } )');
275
+ }
206
276
207
- // If the user has submitted an Array return a new promise which will
208
- // resolve when all getJSON calls are ended
209
- else if (typeof ${ inputParam } === 'object') {
210
- const mapper = async (${ inputParam } s: ${ inputParamType } ) => {
211
- const queryRes = await getJSON<PokeAPITypes.${ apiMap [ endpoint ] } >(this.options, \`\${this.options.protocol}\${this.options.hostName}\${this.options.versionPath}${ endpoint } /\${${ inputParam } s}/\`);
212
- return queryRes;
213
- };
277
+ // Fail if the input types aren't accepted
278
+ if (!Array.isArray(${ inputParam } ) && typeof ${ inputParam } !== 'number' && typeof ${ inputParam } !== 'string') {
279
+ throw new Error('Param "${ inputParam } " must be a ${ methodName . match ( / B y N a m e $ / ) ? 'string, array of strings or array of string and/or numbers' : 'number or array of numbers' } ');
280
+ }
214
281
215
- // Fetch data asynchronously to be faster
216
- const mappedResults = await pMap(${ inputParam } , mapper, { concurrency: 4 });
282
+ // If the user has submitted a Name or an ID, return the JSON promise
283
+ if (typeof ${ inputParam } === 'number' || typeof ${ inputParam } === 'string') {
284
+ return getJSON<${ returnType } >(this.options, \`\${this.options.protocol}\${this.options.hostName}\${this.options.versionPath}${ endpoint } /\${${ inputParam } }/\`, callback);
285
+ }
217
286
218
- if (callback) {
219
- callback(mappedResults);
220
- }
287
+ // If the user has submitted an Array return a new promise which will resolve when all getJSON calls are ended
288
+ const mapper = async (${ inputParam } s: ${ inputParamType } ) => {
289
+ const queryRes = await getJSON<${ returnType } >(this.options, \`\${this.options.protocol}\${this.options.hostName}\${this.options.versionPath}${ endpoint } /\${${ inputParam } s}/\`);
290
+ return queryRes;
291
+ };
221
292
222
- return mappedResults;
223
- } else {
224
- throw new Error('Param " ${ inputParam } " must be a ${ methodName . match ( / B y N a m e $ / ) ? 'string, array of strings or array of string and/or numbers' : 'number or array of numbers' } ');
225
- }
226
- } else {
227
- throw new Error('Param " ${ inputParam } " is required (Must be a ${ methodName . match ( / B y N a m e $ / ) ? 'string, array of strings or array of string and/or numbers' : 'number or array of numbers' } )' );
293
+ // Fetch data asynchronously to be faster
294
+ const mappedResults = await pMap( ${ inputParam } , mapper, { concurrency: 4 });
295
+
296
+ // Invoke the callback if we have one
297
+ if (callback) {
298
+ callback(mappedResults );
228
299
}
229
- } catch (error) {
300
+
301
+ return mappedResults;
302
+ } catch (error) {
230
303
handleError(error, callback);
231
- }`) ;
304
+ }` ) ;
232
305
233
306
// Add the declaration to the types file
234
- // Sanitizing the namespace and remove the async keyword
307
+ // Removing the async keyword
235
308
methodStructure . isAsync = false ;
236
- methodStructure . parameters [ 1 ] . type = methodStructure . parameters [ 1 ] . type . replace ( / P o k e A P I T y p e s / g, 'PokeAPI' ) ;
237
- methodStructure . returnType = methodStructure . returnType . replace ( / P o k e A P I T y p e s / g, 'PokeAPI' ) ;
238
309
const declaredMethod = declarationClass . addMethod ( methodStructure ) ;
239
310
240
311
// If the method has a JSDoc, add it
@@ -263,7 +334,7 @@ for (const [method, rawEndpoint, jsdocs] of rootEndpoints) {
263
334
}
264
335
265
336
// Infer the return type from the name
266
- const returnType = apiMap [ endpoint ] . includes ( 'NamedList' ) ? 'NamedAPIResourceList' : 'APIResourceList' ;
337
+ const returnType = `PokeAPITypes. ${ apiMap [ endpoint ] . includes ( 'NamedList' ) ? 'NamedAPIResourceList' : 'APIResourceList' } ` ;
267
338
268
339
const methodStructure = {
269
340
name : method ,
@@ -275,10 +346,10 @@ for (const [method, rawEndpoint, jsdocs] of rootEndpoints) {
275
346
} ,
276
347
{
277
348
name : 'callback' ,
278
- type : `(result: PokeAPITypes. ${ returnType } , error?: any) => any` ,
349
+ type : `(result: ${ returnType } , error?: any) => any` ,
279
350
hasQuestionToken : true ,
280
351
} ] ,
281
- returnType : `Promise<PokeAPITypes. ${ returnType } >` ,
352
+ returnType : `Promise<${ returnType } >` ,
282
353
} ;
283
354
284
355
const generatedMethod = pokeApiClass . addMethod ( methodStructure ) . setBodyText ( `try {
@@ -300,10 +371,8 @@ for (const [method, rawEndpoint, jsdocs] of rootEndpoints) {
300
371
}` ) ;
301
372
302
373
// Add the declaration to the types file
303
- // Sanitizing the namespace and remove the async keyword
374
+ // Removing the async keyword
304
375
methodStructure . isAsync = false ;
305
- methodStructure . parameters [ 1 ] . type = methodStructure . parameters [ 1 ] . type . replace ( / P o k e A P I T y p e s / g, 'PokeAPI' ) ;
306
- methodStructure . returnType = methodStructure . returnType . replace ( / P o k e A P I T y p e s / g, 'PokeAPI' ) ;
307
376
const declaredMethod = declarationClass . addMethod ( methodStructure ) ;
308
377
309
378
// If the method has a JSDoc, add it
@@ -378,6 +447,10 @@ declarationClass.getParentModule().addExportAssignment({
378
447
expression : 'PokeAPI' ,
379
448
} ) ;
380
449
450
+ // Sanitize the namespaces of the declaration file and format it again
451
+ declarationClass . replaceWithText ( declarationClass . getFullText ( ) . replace ( / P o k e A P I T y p e s / g, 'PokeAPI' ) ) ;
452
+ declarationClass . formatText ( ) ;
453
+
381
454
// Top level async function
382
455
( async ( ) => {
383
456
// Save and compile to JS
0 commit comments