1- // @ts -nocheck
2- import { OpenAPIObject } from '@nestjs/swagger' ;
3- import chalk from 'chalk' ;
4- import * as fsSync from 'node:fs' ;
5- import * as fs from 'node:fs/promises' ;
6- import openapiTS , { astToString , type OpenAPI3 } from 'openapi-typescript' ;
7- import * as ts from 'typescript' ;
8-
9- const DEFAULT_OUTPUT_DIR = './generated' ;
10- const DEFAULT_FILENAME = 'openapi.d.ts' ;
11-
12- interface OpenApiSpecBase {
13- fileName ?: string ;
14- }
1+ import { OpenAPIObject } from "@nestjs/swagger" ;
2+ import chalk from "chalk" ;
3+ import * as fsSync from "node:fs" ;
4+ import * as fs from "node:fs/promises" ;
5+ import openapiTS from "openapi-typescript" ;
6+ import * as ts from "typescript" ;
157
16- interface OpenApiSpecApiOpenAPI3 extends OpenApiSpecBase {
17- document : OpenAPI3 ;
18- }
8+ const DEFAULT_OUTPUT_DIR = "./generated" ;
9+ const DEFAULT_FILENAME = "openapi.d.ts" ;
1910
20- interface OpenApiSpecApiObject extends OpenApiSpecBase {
11+ interface OpenApiSpec {
2112 document : OpenAPIObject ;
13+ fileName ?: string ;
2214}
2315
24- type OpenApiSpec = OpenApiSpecBase &
25- ( OpenApiSpecApiOpenAPI3 | OpenApiSpecApiObject ) ;
16+ type TransformableSchema = {
17+ format ?: string ;
18+ nullable ?: boolean ;
19+ } ;
2620
2721export async function generateOpenApiSpecs (
28- specs : OpenApiSpec [ ] ,
22+ specs : OpenApiSpec [ ]
2923) : Promise < void > {
3024 if ( specs . length === 0 ) {
31- console . log ( chalk . yellow ( ' ⚠️ No OpenAPI specs provided' ) ) ;
25+ console . log ( chalk . yellow ( " ⚠️ No OpenAPI specs provided" ) ) ;
3226 return ;
3327 }
3428
3529 console . log ( chalk . blue ( `🔄 Generating ${ specs . length } OpenAPI spec(s)...` ) ) ;
3630
3731 // Generate all specs in parallel
3832 const results = await Promise . allSettled (
39- specs . map ( ( spec ) => generateSingleSpec ( spec ) ) ,
33+ specs . map ( spec => generateSingleSpec ( spec ) )
4034 ) ;
4135
4236 // Process results
4337 const successful = results . filter (
44- ( result ) => result . status === 'fulfilled' ,
45- ) . length ;
46- const failed = results . filter (
47- ( result ) => result . status === 'rejected' ,
38+ result => result . status === "fulfilled"
4839 ) . length ;
40+ const failed = results . filter ( result => result . status === "rejected" ) . length ;
4941
5042 if ( failed > 0 ) {
5143 console . log ( chalk . yellow ( `⚠️ ${ failed } spec(s) failed to generate` ) ) ;
5244 results . forEach ( ( result , index ) => {
53- if ( result . status === ' rejected' ) {
45+ if ( result . status === " rejected" ) {
5446 console . error (
5547 chalk . red (
56- `❌ Spec ${ index + 1 } (${ specs [ index ] ?. fileName || DEFAULT_FILENAME } ): ${ result . reason } ` ,
57- ) ,
48+ `❌ Spec ${ index + 1 } (${ specs [ index ] ?. fileName || DEFAULT_FILENAME } ): ${ result . reason } `
49+ )
5850 ) ;
5951 }
6052 } ) ;
6153 }
6254
6355 if ( successful > 0 ) {
6456 console . log (
65- chalk . green ( `✅ ${ successful } OpenAPI spec(s) generated successfully` ) ,
57+ chalk . green ( `✅ ${ successful } OpenAPI spec(s) generated successfully` )
6658 ) ;
6759 }
6860
6961 if ( failed === specs . length ) {
70- throw new Error ( ' All OpenAPI specs failed to generate' ) ;
62+ throw new Error ( " All OpenAPI specs failed to generate" ) ;
7163 }
7264}
7365
@@ -76,23 +68,33 @@ async function generateSingleSpec(spec: OpenApiSpec): Promise<void> {
7668 const filePath = `${ DEFAULT_OUTPUT_DIR } /${ fileName } ` ;
7769
7870 const BLOB = ts . factory . createTypeReferenceNode (
79- ts . factory . createIdentifier ( ' Blob' ) ,
71+ ts . factory . createIdentifier ( " Blob" )
8072 ) ; // `Blob`
8173 const NULL = ts . factory . createLiteralTypeNode ( ts . factory . createNull ( ) ) ; // `null`
8274
8375 try {
8476 // Generate new OpenAPI types content
85- const ast = await openapiTS ( spec . document as OpenAPI3 , {
86- transform ( schemaObject ) {
87- if ( schemaObject . format === 'binary' ) {
88- return schemaObject . nullable
89- ? ts . factory . createUnionTypeNode ( [ BLOB , NULL ] )
90- : BLOB ;
77+ const ast = await openapiTS (
78+ spec . document as Parameters < typeof openapiTS > [ 0 ] ,
79+ {
80+ transform ( schemaObject : TransformableSchema ) {
81+ if ( schemaObject . format === "binary" ) {
82+ return schemaObject . nullable
83+ ? ts . factory . createUnionTypeNode ( [ BLOB , NULL ] )
84+ : BLOB ;
85+ }
86+ return undefined ; // Use default transformation for other schema objects
9187 }
92- return undefined ; // Use default transformation for other schema objects
93- } ,
94- } ) ;
95- const newContents = astToString ( ast ) as string ;
88+ }
89+ ) ;
90+ const sourceFile = ts . factory . createSourceFile (
91+ ast as ts . Statement [ ] ,
92+ ts . factory . createToken ( ts . SyntaxKind . EndOfFileToken ) ,
93+ ts . NodeFlags . None
94+ ) ;
95+ const newContents = ts
96+ . createPrinter ( { newLine : ts . NewLineKind . LineFeed } )
97+ . printFile ( sourceFile ) ;
9698
9799 // Check if content has changed
98100 const hasChanged = await hasContentChanged ( filePath , newContents ) ;
@@ -105,21 +107,21 @@ async function generateSingleSpec(spec: OpenApiSpec): Promise<void> {
105107 } catch ( error ) {
106108 const errorMessage = error instanceof Error ? error . message : String ( error ) ;
107109 throw new Error ( `Failed to generate ${ fileName } : ${ errorMessage } ` , {
108- cause : error ,
110+ cause : error
109111 } ) ;
110112 }
111113}
112114
113115async function hasContentChanged (
114116 filePath : string ,
115- newContents : string ,
117+ newContents : string
116118) : Promise < boolean > {
117119 if ( ! fsSync . existsSync ( filePath ) ) {
118120 return true ;
119121 }
120122
121123 try {
122- const existingContents = await fs . readFile ( filePath , ' utf8' ) ;
124+ const existingContents = await fs . readFile ( filePath , " utf8" ) ;
123125 return existingContents !== newContents ;
124126 } catch {
125127 return true ;
@@ -128,13 +130,13 @@ async function hasContentChanged(
128130
129131async function writeOpenApiFile (
130132 filePath : string ,
131- contents : string ,
133+ contents : string
132134) : Promise < void > {
133135 // Ensure directory exists
134136 await fs . mkdir ( DEFAULT_OUTPUT_DIR , { recursive : true } ) ;
135137
136138 // Write file
137- await fs . writeFile ( filePath , contents , ' utf8' ) ;
139+ await fs . writeFile ( filePath , contents , " utf8" ) ;
138140}
139141
140142// Convenience function for single spec (backward compatibility)
0 commit comments