@@ -212,6 +212,295 @@ describe("wihout operationId", () => {
212212 } ) ;
213213} ) ;
214214
215+ describe ( "tags" , ( ) => {
216+ it ( "generates Tag type with all tags from spec" , ( ) => {
217+ const spec = {
218+ openapi : "3.0.0" ,
219+ info : { } ,
220+ paths : {
221+ "/pets" : {
222+ get : {
223+ operationId : "listPets" ,
224+ tags : [ "pet" ] ,
225+ responses : {
226+ 200 : {
227+ content : {
228+ "application/json" : {
229+ schema : { type : "object" } ,
230+ } ,
231+ } ,
232+ } ,
233+ } ,
234+ } ,
235+ } ,
236+ "/users" : {
237+ get : {
238+ operationId : "listUsers" ,
239+ tags : [ "user" ] ,
240+ responses : {
241+ 200 : {
242+ content : {
243+ "application/json" : {
244+ schema : { type : "object" } ,
245+ } ,
246+ } ,
247+ } ,
248+ } ,
249+ } ,
250+ } ,
251+ } ,
252+ } ;
253+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
254+ const tagType = sourceFile . getTypeAlias ( "Tag" ) ;
255+ assert ( tagType ) ;
256+ assert ( tagType . isExported ( ) ) ;
257+ const tagTypeText = tagType . getType ( ) . getText ( ) ;
258+ assert . match ( tagTypeText , / " p e t " / ) ;
259+ assert . match ( tagTypeText , / " u s e r " / ) ;
260+ } ) ;
261+
262+ it ( "generates Tag type with null for untagged operations" , ( ) => {
263+ const spec = {
264+ openapi : "3.0.0" ,
265+ info : { } ,
266+ paths : {
267+ "/pets" : {
268+ get : {
269+ operationId : "listPets" ,
270+ responses : {
271+ 200 : {
272+ content : {
273+ "application/json" : {
274+ schema : { type : "object" } ,
275+ } ,
276+ } ,
277+ } ,
278+ } ,
279+ } ,
280+ } ,
281+ } ,
282+ } ;
283+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
284+ const tagType = sourceFile . getTypeAlias ( "Tag" ) ;
285+ assert ( tagType ) ;
286+ assert ( tagType . isExported ( ) ) ;
287+ const tagTypeText = tagType . getType ( ) . getText ( ) ;
288+ assert . equal ( tagTypeText , "null" ) ;
289+ } ) ;
290+
291+ it ( "generates Tag type with both tags and null for mixed operations" , ( ) => {
292+ const spec = {
293+ openapi : "3.0.0" ,
294+ info : { } ,
295+ paths : {
296+ "/pets" : {
297+ get : {
298+ operationId : "listPets" ,
299+ tags : [ "pet" ] ,
300+ responses : {
301+ 200 : {
302+ content : {
303+ "application/json" : {
304+ schema : { type : "object" } ,
305+ } ,
306+ } ,
307+ } ,
308+ } ,
309+ } ,
310+ } ,
311+ "/status" : {
312+ get : {
313+ operationId : "getStatus" ,
314+ responses : {
315+ 200 : {
316+ content : {
317+ "application/json" : {
318+ schema : { type : "object" } ,
319+ } ,
320+ } ,
321+ } ,
322+ } ,
323+ } ,
324+ } ,
325+ } ,
326+ } ;
327+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
328+ const tagType = sourceFile . getTypeAlias ( "Tag" ) ;
329+ assert ( tagType ) ;
330+ const tagTypeText = tagType . getType ( ) . getText ( ) ;
331+ assert . match ( tagTypeText , / " p e t " / ) ;
332+ assert . match ( tagTypeText , / n u l l / ) ;
333+ } ) ;
334+ } ) ;
335+
336+ describe ( "registerRouteHandlersByTag" , ( ) => {
337+ it ( "generates function with correct signature" , ( ) => {
338+ const spec = {
339+ openapi : "3.0.0" ,
340+ info : { } ,
341+ paths : {
342+ "/pets" : {
343+ get : {
344+ operationId : "listPets" ,
345+ tags : [ "pet" ] ,
346+ responses : {
347+ 200 : {
348+ content : {
349+ "application/json" : {
350+ schema : { type : "object" } ,
351+ } ,
352+ } ,
353+ } ,
354+ } ,
355+ } ,
356+ } ,
357+ } ,
358+ } ;
359+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
360+ const func = sourceFile . getFunction ( "registerRouteHandlersByTag" ) ;
361+ assert ( func ) ;
362+ assert ( func . isExported ( ) ) ;
363+ assert . equal ( func . getTypeParameters ( ) . length , 2 ) ;
364+ assert . equal ( func . getParameters ( ) . length , 2 ) ;
365+
366+ const tagParam = func . getParameters ( ) [ 0 ] ;
367+ assert ( tagParam ) ;
368+ assert . equal ( tagParam . getName ( ) , "tag" ) ;
369+ assert . equal ( tagParam . getType ( ) . getText ( ) , '"pet"' ) ;
370+
371+ const serverParam = func . getParameters ( ) [ 1 ] ;
372+ assert ( serverParam ) ;
373+ assert . equal ( serverParam . getName ( ) , "server" ) ;
374+ assert . match ( serverParam . getType ( ) . getText ( ) , / P a r t i a l < S e r v e r < R e q , R e s > > / ) ;
375+
376+ assert . match ( func . getReturnType ( ) . getText ( ) , / R o u t e \[ \] / ) ;
377+ } ) ;
378+
379+ it ( "generates switch statement for each tag" , ( ) => {
380+ const spec = {
381+ openapi : "3.0.0" ,
382+ info : { } ,
383+ paths : {
384+ "/pets" : {
385+ get : {
386+ operationId : "listPets" ,
387+ tags : [ "pet" ] ,
388+ responses : {
389+ 200 : {
390+ content : {
391+ "application/json" : {
392+ schema : { type : "object" } ,
393+ } ,
394+ } ,
395+ } ,
396+ } ,
397+ } ,
398+ } ,
399+ "/users" : {
400+ get : {
401+ operationId : "listUsers" ,
402+ tags : [ "user" ] ,
403+ responses : {
404+ 200 : {
405+ content : {
406+ "application/json" : {
407+ schema : { type : "object" } ,
408+ } ,
409+ } ,
410+ } ,
411+ } ,
412+ } ,
413+ } ,
414+ } ,
415+ } ;
416+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
417+ const func = sourceFile . getFunction ( "registerRouteHandlersByTag" ) ;
418+ const bodyText = func ?. getBodyText ( ) || "" ;
419+
420+ assert . match ( bodyText , / s w i t c h \( t a g \) / ) ;
421+ assert . match ( bodyText , / c a s e " p e t " : / ) ;
422+ assert . match ( bodyText , / c a s e " u s e r " : / ) ;
423+ assert . match ( bodyText , / i f \( s e r v e r \. l i s t P e t s \) / ) ;
424+ assert . match ( bodyText , / i f \( s e r v e r \. l i s t U s e r s \) / ) ;
425+ } ) ;
426+
427+ it ( "groups operations by tag correctly" , ( ) => {
428+ const spec = {
429+ openapi : "3.0.0" ,
430+ info : { } ,
431+ paths : {
432+ "/pets" : {
433+ get : {
434+ operationId : "listPets" ,
435+ tags : [ "pet" ] ,
436+ responses : {
437+ 200 : {
438+ content : {
439+ "application/json" : {
440+ schema : { type : "object" } ,
441+ } ,
442+ } ,
443+ } ,
444+ } ,
445+ } ,
446+ post : {
447+ operationId : "createPet" ,
448+ tags : [ "pet" ] ,
449+ responses : {
450+ 201 : {
451+ content : {
452+ "application/json" : {
453+ schema : { type : "object" } ,
454+ } ,
455+ } ,
456+ } ,
457+ } ,
458+ } ,
459+ } ,
460+ } ,
461+ } ;
462+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
463+ const func = sourceFile . getFunction ( "registerRouteHandlersByTag" ) ;
464+ const bodyText = func ?. getBodyText ( ) || "" ;
465+
466+ // Both operations should be in the same case block
467+ const petCaseMatch = bodyText . match ( / c a s e " p e t " : [ \s \S ] * ?b r e a k ; / ) ;
468+ assert ( petCaseMatch ) ;
469+ const petCaseBlock = petCaseMatch [ 0 ] ;
470+ assert . match ( petCaseBlock , / i f \( s e r v e r \. l i s t P e t s \) / ) ;
471+ assert . match ( petCaseBlock , / i f \( s e r v e r \. c r e a t e P e t \) / ) ;
472+ } ) ;
473+
474+ it ( "handles untagged operations with null case" , ( ) => {
475+ const spec = {
476+ openapi : "3.0.0" ,
477+ info : { } ,
478+ paths : {
479+ "/status" : {
480+ get : {
481+ operationId : "getStatus" ,
482+ responses : {
483+ 200 : {
484+ content : {
485+ "application/json" : {
486+ schema : { type : "object" } ,
487+ } ,
488+ } ,
489+ } ,
490+ } ,
491+ } ,
492+ } ,
493+ } ,
494+ } ;
495+ const sourceFile = generate ( spec , "./schema.d.ts" , "outdir.ts" ) ;
496+ const func = sourceFile . getFunction ( "registerRouteHandlersByTag" ) ;
497+ const bodyText = func ?. getBodyText ( ) || "" ;
498+
499+ assert . match ( bodyText , / c a s e n u l l : / ) ;
500+ assert . match ( bodyText , / i f \( s e r v e r \. g e t S t a t u s \) / ) ;
501+ } ) ;
502+ } ) ;
503+
215504describe ( "request body" , ( ) => {
216505 it ( "writes required request body" , ( ) => {
217506 const spec = {
0 commit comments