11import type { AppConfig } from "@/config/type" ;
2- import { getEnv } from "@/env" ;
32import { Logger } from "@nestjs/common" ;
43import { ConfigService } from "@nestjs/config" ;
54import { NestFactory } from "@nestjs/core" ;
65import type { NestExpressApplication } from "@nestjs/platform-express" ;
7- import { SwaggerModule , DocumentBuilder } from "@nestjs/swagger" ;
8- import {
9- PathItemObject ,
10- PathsObject ,
11- OperationObject ,
12- TagObject ,
13- } from "@nestjs/swagger/dist/interfaces/open-api-spec.interface" ;
146import "dotenv/config" ;
15- import * as fs from "fs" ;
16- import { Server } from "http" ;
177import { WinstonModule } from "nest-winston" ;
188
199import { bootstrap } from "./app" ;
2010import { AppModule } from "./app.module" ;
2111import { loggerConfig } from "./lib/logger" ;
12+ import { generateSwaggerForApp } from "./swagger/generate-swagger" ;
2213
23- const HttpMethods : ( keyof PathItemObject ) [ ] = [ "get" , "post" , "put" , "delete" , "patch" , "options" , "head" ] ;
24-
25- const run = async ( ) => {
26- const app = await NestFactory . create < NestExpressApplication > ( AppModule , {
27- logger : WinstonModule . createLogger ( loggerConfig ( ) ) ,
28- bodyParser : false ,
29- } ) ;
14+ run ( ) . catch ( ( error : Error ) => {
15+ console . error ( "Failed to start Cal Platform API" , { error : error . stack } ) ;
16+ process . exit ( 1 ) ;
17+ } ) ;
3018
19+ async function run ( ) {
20+ const app = await createNestApp ( ) ;
3121 const logger = new Logger ( "App" ) ;
3222
3323 try {
3424 bootstrap ( app ) ;
3525 const port = app . get ( ConfigService < AppConfig , true > ) . get ( "api.port" , { infer : true } ) ;
36- void generateSwagger ( app ) ;
26+ generateSwaggerForApp ( app ) ;
3727 await app . listen ( port ) ;
3828 logger . log ( `Application started on port: ${ port } ` ) ;
3929 } catch ( error ) {
@@ -42,97 +32,11 @@ const run = async () => {
4232 error,
4333 } ) ;
4434 }
45- } ;
46-
47- function customTagSort ( a : string , b : string ) : number {
48- const platformPrefix = "Platform" ;
49- const orgsPrefix = "Orgs" ;
50-
51- if ( a . startsWith ( platformPrefix ) && ! b . startsWith ( platformPrefix ) ) {
52- return - 1 ;
53- }
54- if ( ! a . startsWith ( platformPrefix ) && b . startsWith ( platformPrefix ) ) {
55- return 1 ;
56- }
57-
58- if ( a . startsWith ( orgsPrefix ) && ! b . startsWith ( orgsPrefix ) ) {
59- return - 1 ;
60- }
61- if ( ! a . startsWith ( orgsPrefix ) && b . startsWith ( orgsPrefix ) ) {
62- return 1 ;
63- }
64-
65- return a . localeCompare ( b ) ;
6635}
6736
68- function isOperationObject ( obj : any ) : obj is OperationObject {
69- return obj && typeof obj === "object" && "tags" in obj ;
70- }
71-
72- function groupAndSortPathsByFirstTag ( paths : PathsObject ) : PathsObject {
73- const groupedPaths : { [ key : string ] : PathsObject } = { } ;
74-
75- Object . keys ( paths ) . forEach ( ( pathKey ) => {
76- const pathItem = paths [ pathKey ] ;
77-
78- HttpMethods . forEach ( ( method ) => {
79- const operation = pathItem [ method ] ;
80-
81- if ( isOperationObject ( operation ) && operation . tags && operation . tags . length > 0 ) {
82- const firstTag = operation . tags [ 0 ] ;
83-
84- if ( ! groupedPaths [ firstTag ] ) {
85- groupedPaths [ firstTag ] = { } ;
86- }
87-
88- groupedPaths [ firstTag ] [ pathKey ] = pathItem ;
89- }
90- } ) ;
91- } ) ;
92-
93- const sortedTags = Object . keys ( groupedPaths ) . sort ( customTagSort ) ;
94- const sortedPaths : PathsObject = { } ;
95-
96- sortedTags . forEach ( ( tag ) => {
97- Object . assign ( sortedPaths , groupedPaths [ tag ] ) ;
37+ export async function createNestApp ( ) {
38+ return NestFactory . create < NestExpressApplication > ( AppModule , {
39+ logger : WinstonModule . createLogger ( loggerConfig ( ) ) ,
40+ bodyParser : false ,
9841 } ) ;
99-
100- return sortedPaths ;
101- }
102-
103- async function generateSwagger ( app : NestExpressApplication < Server > ) {
104- const logger = new Logger ( "App" ) ;
105- logger . log ( `Generating Swagger documentation...\n` ) ;
106-
107- const config = new DocumentBuilder ( ) . setTitle ( "Cal.com API v2" ) . build ( ) ;
108- const document = SwaggerModule . createDocument ( app , config ) ;
109- document . paths = groupAndSortPathsByFirstTag ( document . paths ) ;
110-
111- const swaggerOutputFile = "./swagger/documentation.json" ;
112- const docsOutputFile = "../../../docs/api-reference/v2/openapi.json" ;
113- const stringifiedContents = JSON . stringify ( document , null , 2 ) ;
114-
115- if ( fs . existsSync ( swaggerOutputFile ) ) {
116- fs . unlinkSync ( swaggerOutputFile ) ;
117- }
118-
119- fs . writeFileSync ( swaggerOutputFile , stringifiedContents , { encoding : "utf8" } ) ;
120-
121- if ( fs . existsSync ( docsOutputFile ) && getEnv ( "NODE_ENV" ) === "development" ) {
122- fs . unlinkSync ( docsOutputFile ) ;
123- fs . writeFileSync ( docsOutputFile , stringifiedContents , { encoding : "utf8" } ) ;
124- }
125-
126- if ( ! process . env . DOCS_URL ) {
127- SwaggerModule . setup ( "docs" , app , document , {
128- customCss : ".swagger-ui .topbar { display: none }" ,
129- } ) ;
130-
131- logger . log ( `Swagger documentation available in the "/docs" endpoint\n` ) ;
132- }
13342}
134-
135- run ( ) . catch ( ( error : Error ) => {
136- console . error ( "Failed to start Cal Platform API" , { error : error . stack } ) ;
137- process . exit ( 1 ) ;
138- } ) ;
0 commit comments