@@ -87,7 +87,13 @@ function assertTypeOnlyIncludes(
8787 )
8888}
8989
90- function assertGeneratedClientsCompile ( spec : OpenAPISpec ) {
90+ function assertGeneratedClientsCompile (
91+ spec : OpenAPISpec ,
92+ options : {
93+ readonly exactOptionalPropertyTypes ?: boolean | undefined
94+ readonly formats ?: ReadonlyArray < "httpclient" | "httpclient-type-only" > | undefined
95+ } = { }
96+ ) {
9197 const generate = (
9298 format : "httpclient" | "httpclient-type-only" ,
9399 layer : typeof OpenApiGenerator . layerTransformerSchema
@@ -98,23 +104,29 @@ function assertGeneratedClientsCompile(spec: OpenAPISpec) {
98104 } ) . pipe ( Effect . provide ( layer ) )
99105
100106 return Effect . gen ( function * ( ) {
101- const [ schemaClient , typeOnlyClient ] = yield * Effect . all ( [
102- generate ( "httpclient" , OpenApiGenerator . layerTransformerSchema ) ,
103- generate ( "httpclient-type-only" , OpenApiGenerator . layerTransformerTs )
104- ] )
107+ const formats = options . formats ?? [ "httpclient" , "httpclient-type-only" ]
108+ const clients = yield * Effect . all ( formats . map ( ( format ) =>
109+ generate (
110+ format ,
111+ format === "httpclient"
112+ ? OpenApiGenerator . layerTransformerSchema
113+ : OpenApiGenerator . layerTransformerTs
114+ )
115+ ) )
105116 const directory = mkdtempSync ( join ( dirname ( fileURLToPath ( import . meta. url ) ) , ".generated-clients-" ) )
106117 try {
107- const schemaPath = join ( directory , "SchemaClient.ts" )
108- const typeOnlyPath = join ( directory , "TypeOnlyClient.ts" )
109- writeFileSync ( schemaPath , schemaClient )
110- writeFileSync ( typeOnlyPath , typeOnlyClient )
118+ const files = clients . map ( ( client , index ) => {
119+ const path = join ( directory , `Client${ index } .ts` )
120+ writeFileSync ( path , client )
121+ return path
122+ } )
111123 const configPath = join ( directory , "tsconfig.json" )
112124 writeFileSync (
113125 configPath ,
114126 JSON . stringify ( {
115127 compilerOptions : {
116128 allowImportingTsExtensions : true ,
117- exactOptionalPropertyTypes : true ,
129+ exactOptionalPropertyTypes : options . exactOptionalPropertyTypes ?? true ,
118130 lib : [ "ESNext" , "DOM" ] ,
119131 module : "NodeNext" ,
120132 noEmit : true ,
@@ -124,7 +136,7 @@ function assertGeneratedClientsCompile(spec: OpenAPISpec) {
124136 types : [ ] ,
125137 verbatimModuleSyntax : true
126138 } ,
127- files : [ schemaPath , typeOnlyPath ]
139+ files
128140 } )
129141 )
130142 const repositoryRoot = join ( dirname ( fileURLToPath ( import . meta. url ) ) , "../../../.." )
@@ -2770,5 +2782,54 @@ export const __HttpApiMultipartFiles = Multipart.FilesSchema`,
27702782 operationId : "getUser"
27712783 }
27722784 ] ) )
2785+
2786+ it . effect ( "emits compilable open objects with optional properties" , ( ) =>
2787+ assertGeneratedClientsCompile (
2788+ {
2789+ openapi : "3.1.0" ,
2790+ info : {
2791+ title : "Open object regression API" ,
2792+ version : "1.0.0"
2793+ } ,
2794+ paths : {
2795+ "/widget" : {
2796+ get : {
2797+ operationId : "getWidget" ,
2798+ parameters : [ ] ,
2799+ responses : {
2800+ 200 : {
2801+ description : "OK" ,
2802+ content : {
2803+ "application/json" : {
2804+ schema : {
2805+ type : "object" ,
2806+ properties : {
2807+ optionalValue : {
2808+ type : "string"
2809+ }
2810+ } ,
2811+ additionalProperties : true
2812+ }
2813+ }
2814+ }
2815+ }
2816+ } ,
2817+ tags : [ "Widgets" ] ,
2818+ security : [ ]
2819+ }
2820+ }
2821+ } ,
2822+ components : {
2823+ schemas : { } ,
2824+ securitySchemes : { }
2825+ } ,
2826+ security : [ ] ,
2827+ tags : [ ]
2828+ } ,
2829+ {
2830+ exactOptionalPropertyTypes : false ,
2831+ formats : [ "httpclient" ]
2832+ }
2833+ ) )
27732834 } )
27742835} )
0 commit comments