@@ -41,7 +41,6 @@ const serviceMethodGenSpec = {
4141 parameters : [ { name : 'limit' , in : 'query' , type : 'integer' } ] // No 'schema' key
4242 }
4343 } ,
44-
4544 '/post-no-req-schema' : {
4645 post : {
4746 operationId : 'postNoReqSchema' ,
@@ -50,6 +49,26 @@ const serviceMethodGenSpec = {
5049 responses : { '204' : { } }
5150 }
5251 } ,
52+ // NEW paths for coverage
53+ '/all-required/{id}' : {
54+ post : {
55+ tags : [ 'RequiredParams' ] ,
56+ operationId : 'postAllRequired' ,
57+ parameters : [ { name : 'id' , in : 'path' , required : true , schema : { type : 'string' } } ] ,
58+ requestBody : {
59+ required : true ,
60+ content : { 'application/json' : { schema : { type : 'string' } } }
61+ }
62+ }
63+ } ,
64+ '/form-data-no-consumes' : {
65+ post : {
66+ tags : [ 'FormData' ] ,
67+ operationId : 'postFormDataNoConsumes' ,
68+ // No 'consumes' array here
69+ parameters : [ { name : 'file' , in : 'formData' , type : 'file' } ]
70+ }
71+ }
5372 }
5473} ;
5574
@@ -121,6 +140,37 @@ describe('Emitter: ServiceMethodGenerator', () => {
121140 } ) ;
122141 } ) ;
123142
143+ describe ( 'Overload Generation' , ( ) => {
144+ it ( 'should make options optional if other parameters are optional' , ( ) => {
145+ const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
146+ // This operation has an optional query param
147+ const op = parser . operations . find ( o => o . operationId === 'getWithSwagger2Param' ) ! ;
148+ op . methodName = 'getWithSwagger2Param' ;
149+ methodGen . addServiceMethod ( serviceClass , op ) ;
150+
151+ const method = serviceClass . getMethodOrThrow ( 'getWithSwagger2Param' ) ;
152+ const responseOverload = method . getOverloads ( ) . find ( o => o . getReturnType ( ) . getText ( ) . includes ( 'HttpResponse' ) ) ! ;
153+ const optionsParam = responseOverload . getParameters ( ) . find ( p => p . getName ( ) === 'options' ) ! ;
154+
155+ // because 'limit' is optional, 'options' must also be optional.
156+ expect ( optionsParam . hasQuestionToken ( ) ) . toBe ( true ) ;
157+ } ) ;
158+
159+ it ( 'should keep options required if all other parameters are required' , ( ) => {
160+ const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
161+ const op = parser . operations . find ( o => o . operationId === 'postAllRequired' ) ! ;
162+ op . methodName = 'postAllRequired' ;
163+ methodGen . addServiceMethod ( serviceClass , op ) ;
164+
165+ const method = serviceClass . getMethodOrThrow ( 'postAllRequired' ) ;
166+ const responseOverload = method . getOverloads ( ) . find ( o => o . getReturnType ( ) . getText ( ) . includes ( 'HttpResponse' ) ) ! ;
167+ const optionsParam = responseOverload . getParameters ( ) . find ( p => p . getName ( ) === 'options' ) ! ;
168+
169+ // because 'id' and 'body' are required, 'options' for observe:'response' remains required.
170+ expect ( optionsParam . hasQuestionToken ( ) ) . toBe ( false ) ;
171+ } ) ;
172+ } ) ;
173+
124174 describe ( 'Parameter and Body Generation' , ( ) => {
125175 const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
126176
@@ -171,6 +221,30 @@ describe('Emitter: ServiceMethodGenerator', () => {
171221 const param = impl . getParameters ( ) . find ( p => p . getType ( ) . getText ( ) === 'string' ) ;
172222 expect ( param ?. getName ( ) ) . toBe ( 'body' ) ;
173223 } ) ;
224+
225+ it ( 'should handle request body without a schema' , ( ) => {
226+ const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
227+ const op = parser . operations . find ( o => o . operationId === 'postNoReqSchema' ) ! ;
228+ op . methodName = 'postNoReqSchema' ;
229+ methodGen . addServiceMethod ( serviceClass , op ) ;
230+
231+ const method = serviceClass . getMethodOrThrow ( 'postNoReqSchema' ) ;
232+ const bodyParam = method . getParameters ( ) . find ( p => p . getName ( ) === 'body' ) ! ;
233+ expect ( bodyParam ) . toBeDefined ( ) ;
234+ expect ( bodyParam . getType ( ) . getText ( ) ) . toBe ( 'unknown' ) ;
235+ } ) ;
236+
237+ it ( 'should handle formData params when consumes array is missing' , ( ) => {
238+ const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
239+ const op = parser . operations . find ( o => o . operationId === 'postFormDataNoConsumes' ) ! ;
240+ op . methodName = 'postFormDataNoConsumes' ;
241+ methodGen . addServiceMethod ( serviceClass , op ) ;
242+
243+ const body = serviceClass . getMethodOrThrow ( 'postFormDataNoConsumes' ) . getBodyText ( ) ! ;
244+ // isMultipartForm will be false, so it falls through. Since there's no other body, 'null' is used.
245+ expect ( body ) . toContain ( 'return this.http.post(url, null, requestOptions);' ) ;
246+ expect ( body ) . not . toContain ( 'new FormData()' ) ;
247+ } ) ;
174248 } ) ;
175249
176250 describe ( 'Response Type Resolution' , ( ) => {
@@ -204,7 +278,6 @@ describe('Emitter: ServiceMethodGenerator', () => {
204278 } ) ;
205279 } ) ;
206280
207- // --- Existing Tests from original file for regression ---
208281 it ( 'should fall back to a generic `body: unknown` parameter for non-json content' , ( ) => {
209282 const { methodGen, serviceClass, parser } = createTestEnvironment ( ) ;
210283 const operation = parser . operations . find ( op => op . operationId === 'allParams' ) ! ;
0 commit comments