@devlearning/swagger-generator 1.1.14 → 1.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/generator.js CHANGED
@@ -74,7 +74,10 @@ export class Generator {
74
74
  const apiSwaggerMethodKey = this._swagger.paths[apiName];
75
75
  const apiMethod = Object.getOwnPropertyNames(apiSwaggerMethodKey)[0];
76
76
  const apiSwaggerMethod = apiSwaggerMethodKey[apiMethod];
77
- if (apiSwaggerMethod.requestBody?.content[contentTypeMultipartFormData]?.schema != null) {
77
+ const multipartSchema = apiSwaggerMethod.requestBody?.content?.[contentTypeMultipartFormData]?.schema;
78
+ // Only create an ad-hoc request model when the multipart schema is inline.
79
+ // If the schema is a $ref, it's already part of components/schemas and will be generated there.
80
+ if (multipartSchema != null && multipartSchema.$ref == null) {
78
81
  usedMultiPart.push(apiName);
79
82
  }
80
83
  }
@@ -114,6 +117,9 @@ export class Generator {
114
117
  const method = Object.getOwnPropertyNames(swaggerMethod)[0];
115
118
  const swaggerMethodInfo = swaggerMethod[method];
116
119
  const schema = swaggerMethodInfo.requestBody.content[contentTypeMultipartFormData].schema;
120
+ if (schema?.$ref != null) {
121
+ return;
122
+ }
117
123
  this._models.push({
118
124
  typeName: this.getApiNameNormalized(apiName),
119
125
  modelType: 'class',
@@ -164,24 +170,58 @@ export class Generator {
164
170
  return [];
165
171
  let parameters = [];
166
172
  try {
173
+ // Path params are always explicit parameters.
174
+ swaggerMethod.parameters?.filter(x => x.in == 'path').forEach(parameter => {
175
+ const name = this.toFirstLetterLowercase(parameter.name);
176
+ if (parameter.schema?.$ref != null) {
177
+ const type = this.retrieveType(parameter.schema);
178
+ parameters.push({
179
+ name,
180
+ typeName: type.typeName,
181
+ nullable: false,
182
+ swaggerParameter: parameter,
183
+ isQuery: false,
184
+ isEnum: this.isEnum(parameter.schema.$ref),
185
+ isTypeReference: false,
186
+ isNativeType: false,
187
+ isArray: false,
188
+ isVoid: false,
189
+ });
190
+ }
191
+ else {
192
+ parameters.push({
193
+ name,
194
+ typeName: this.getNativeType(parameter.schema),
195
+ nullable: false,
196
+ swaggerParameter: parameter,
197
+ isQuery: false,
198
+ isEnum: false,
199
+ isTypeReference: false,
200
+ isNativeType: true,
201
+ isArray: false,
202
+ isVoid: false,
203
+ });
204
+ }
205
+ });
167
206
  if (swaggerMethod.requestBody != null && swaggerMethod.requestBody.content[contentTypeMultipartFormData] != null) {
168
- var modelName = this.getApiNameNormalized(apiName);
169
- parameters.push({
207
+ const schema = swaggerMethod.requestBody.content[contentTypeMultipartFormData].schema;
208
+ const type = this.retrieveType(schema);
209
+ parameters.unshift({
170
210
  name: 'request',
171
- typeName: modelName,
211
+ typeName: type.typeName,
172
212
  nullable: false,
173
213
  isQuery: false,
174
214
  isEnum: false,
175
- isTypeReference: true,
176
- isNativeType: false,
177
- isArray: false,
178
- isVoid: false,
215
+ isTypeReference: type.isTypeReference ?? true,
216
+ isNativeType: type.isNativeType ?? false,
217
+ isArray: type.isArray ?? false,
218
+ isVoid: type.isVoid ?? false,
179
219
  });
180
220
  }
181
221
  else {
182
222
  if (swaggerMethod.requestBody != null) {
183
223
  const type = this.retrieveType(swaggerMethod.requestBody.content[contentTypeApplicationJson].schema);
184
- parameters.push({
224
+ parameters.unshift({
185
225
  name: 'request',
186
226
  typeName: type.typeName,
187
227
  nullable: false,
@@ -327,12 +367,16 @@ export class Generator {
327
367
  };
328
368
  }
329
369
  else {
370
+ // Array of native types (including binary/file)
371
+ const itemType = swaggerComponentProperty.items
372
+ ? this.getNativeType(swaggerComponentProperty.items)
373
+ : this.getNativeType(swaggerComponentProperty);
330
374
  return {
331
- typeName: this.getNativeType(swaggerComponentProperty),
375
+ typeName: itemType,
332
376
  isTypeReference: false,
333
377
  isNativeType: true,
334
378
  nullable: swaggerComponentProperty.nullable ?? false,
335
- isArray: false,
379
+ isArray: true,
336
380
  isVoid: false,
337
381
  };
338
382
  }
@@ -105,17 +105,32 @@ export class ApiDartWriter {
105
105
  if (methodName.toLowerCase().indexOf("productsave") >= 0) {
106
106
  debugger;
107
107
  }
108
+ const pathParams = (api.parameters ?? [])
109
+ .filter(p => p.name !== 'request' && p.isQuery === false)
110
+ .map(p => ({
111
+ name: p.name,
112
+ type: p.typeName ? Normalizator.mapTsTypeToDart(p.typeName) : 'String',
113
+ nullable: false,
114
+ }));
115
+ // Build a Dart-interpolated path string (e.g. '/x/{id}' -> '/x/$id')
116
+ const pathExpression = api.url.replace(/\{([^}]+)\}/g, (_, rawName) => {
117
+ const varName = Utils.toFirstLetterLowercase(rawName);
118
+ return `\$${varName}`;
119
+ });
108
120
  const endpoint = {
109
121
  methodName: methodName,
110
122
  httpMethod: api.method.toLowerCase(),
111
- path: api.url,
123
+ path: pathExpression,
112
124
  responseType: responseType,
113
125
  isResponseNativeType: api.returnType ? api.returnType.isNativeType : true,
114
126
  haveRequest: api.haveRequest,
115
127
  requestType: requestType,
128
+ pathParams,
129
+ isMultiPart: api.isMultiPart === true,
116
130
  };
117
131
  if (api.parameters && api.parameters.length > 0 && !api.haveRequest) {
118
132
  endpoint.queryParams = api.parameters
133
+ .filter(p => p.isQuery === true)
119
134
  .map(p => ({
120
135
  name: p.name,
121
136
  type: p.typeName ? Normalizator.mapTsTypeToDart(p.typeName) : 'String',
@@ -136,6 +151,22 @@ export class ApiDartWriter {
136
151
  });
137
152
  }
138
153
  }
154
+ // Multipart: include request model fields so template can build FormData
155
+ if (endpoint.isMultiPart && api.haveRequest && api.parameters[0]?.typeName) {
156
+ const requestModelTypeName = api.parameters[0].typeName;
157
+ const requestModel = models.find(m => m.typeName === requestModelTypeName);
158
+ if (requestModel) {
159
+ endpoint.multipartFields = requestModel.properties.map(p => ({
160
+ name: p.name,
161
+ isFile: p.typeName === 'File',
162
+ isArray: p.isArray === true,
163
+ nullable: p.nullable === true,
164
+ }));
165
+ }
166
+ else {
167
+ endpoint.multipartFields = [];
168
+ }
169
+ }
139
170
  if (api.returnType && !api.returnType.isNativeType) {
140
171
  if (imports.findIndex(x => x.type.typeName == api.returnType.typeName) == -1) {
141
172
  models.forEach(model => {
@@ -33,15 +33,30 @@ export class ModelDartWriter {
33
33
  imports: [],
34
34
  };
35
35
  var imports = [];
36
+ const needsDartIo = model.properties.some(p => {
37
+ const normalized = (p.typeName ?? '').trim();
38
+ return normalized === 'File' || (p.isArray && normalized === 'File');
39
+ });
40
+ if (needsDartIo) {
41
+ imports.push({
42
+ type: { typeName: 'dart:io' },
43
+ import: `import 'dart:io';`
44
+ });
45
+ }
36
46
  model.properties.forEach(property => {
37
47
  var fieldTypeName = Normalizator.mapTsTypeToDart(property.typeName);
38
48
  fieldTypeName = Normalizator.getNormalizedTypeName(fieldTypeName);
49
+ const isFileField = property.typeName === 'File';
50
+ const jsonKeyAnnotation = isFileField
51
+ ? "@JsonKey(includeFromJson: false, includeToJson: false)"
52
+ : undefined;
39
53
  dartModel.fields.push({
40
54
  name: property.name,
41
55
  type: property.isArray ? `List<${fieldTypeName}>` : fieldTypeName,
42
56
  typeName: property.typeName,
43
57
  nullable: property.nullable && !property.isArray ? '?' : '',
44
58
  required: property.nullable && !property.isArray ? '' : 'required ',
59
+ jsonKeyAnnotation,
45
60
  });
46
61
  if (property.isTypeReference) {
47
62
  if (imports.findIndex(x => x.type.typeName == property.typeName) == -1) {
@@ -11,15 +11,80 @@ class {{apiClassName}} {
11
11
 
12
12
  {{#endpoints}}
13
13
  Future<{{responseType}}> {{methodName}}(
14
- {{#haveRequest}}{{requestType}} request{{/haveRequest}}
14
+ {{#haveRequest}}{{requestType}} request,{{/haveRequest}}
15
+ {{#pathParams}}
16
+ {{type}}{{#nullable}}?{{/nullable}} {{name}},
17
+ {{/pathParams}}
15
18
  {{#queryParams}}
16
19
  {{type}}{{#nullable}}?{{/nullable}} {{name}},
17
20
  {{/queryParams}}
18
21
  ) async {
22
+ {{#isMultiPart}}
23
+ final formData = FormData();
24
+ {{#multipartFields}}
25
+ {{#isFile}}
26
+ {{#isArray}}
27
+ {{^nullable}}
28
+ for (final file in request.{{name}}) {
29
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(file.path)));
30
+ }
31
+ {{/nullable}}
32
+ {{#nullable}}
33
+ if (request.{{name}} != null) {
34
+ for (final file in request.{{name}}!) {
35
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(file.path)));
36
+ }
37
+ }
38
+ {{/nullable}}
39
+ {{/isArray}}
40
+ {{^isArray}}
41
+ {{^nullable}}
42
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(request.{{name}}.path)));
43
+ {{/nullable}}
44
+ {{#nullable}}
45
+ if (request.{{name}} != null) {
46
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(request.{{name}}!.path)));
47
+ }
48
+ {{/nullable}}
49
+ {{/isArray}}
50
+ {{/isFile}}
51
+ {{^isFile}}
52
+ {{#isArray}}
53
+ {{^nullable}}
54
+ for (final value in request.{{name}}) {
55
+ formData.fields.add(MapEntry('{{name}}', value.toString()));
56
+ }
57
+ {{/nullable}}
58
+ {{#nullable}}
59
+ if (request.{{name}} != null) {
60
+ for (final value in request.{{name}}!) {
61
+ formData.fields.add(MapEntry('{{name}}', value.toString()));
62
+ }
63
+ }
64
+ {{/nullable}}
65
+ {{/isArray}}
66
+ {{^isArray}}
67
+ {{^nullable}}
68
+ formData.fields.add(MapEntry('{{name}}', request.{{name}}.toString()));
69
+ {{/nullable}}
70
+ {{#nullable}}
71
+ if (request.{{name}} != null) {
72
+ formData.fields.add(MapEntry('{{name}}', request.{{name}}!.toString()));
73
+ }
74
+ {{/nullable}}
75
+ {{/isArray}}
76
+ {{/isFile}}
77
+ {{/multipartFields}}
78
+ {{/isMultiPart}}
19
79
  final response = await _dio.{{httpMethod}}(
20
80
  '{{{path}}}',
21
81
  {{#haveRequest}}
82
+ {{#isMultiPart}}
83
+ data: formData,
84
+ {{/isMultiPart}}
85
+ {{^isMultiPart}}
22
86
  data: request.toJson(),
87
+ {{/isMultiPart}}
23
88
  {{/haveRequest}}
24
89
  {{^haveRequest}}
25
90
  queryParameters: {
@@ -10,6 +10,9 @@ part '{{filename}}.g.dart';
10
10
  abstract class {{className}} with _${{className}} {
11
11
  const factory {{className}}({
12
12
  {{#fields}}
13
+ {{#jsonKeyAnnotation}}
14
+ {{{jsonKeyAnnotation}}}
15
+ {{/jsonKeyAnnotation}}
13
16
  {{required}}{{{type}}}{{nullable}} {{name}},
14
17
  {{/fields}}
15
18
  }) = _{{className}};
@@ -8,6 +8,6 @@ export declare class Utils {
8
8
  static isDate(schema?: SwaggerSchema): boolean;
9
9
  static toDartFileName(name: string): string;
10
10
  static toDartClassName(name: string): string | undefined;
11
- static ensureDirectorySync(dirPath: string): Promise<void>;
12
- static clearDirectory(dirPath: string): Promise<void>;
11
+ static ensureDirectorySync(dirPath: string): void;
12
+ static clearDirectory(dirPath: string): void;
13
13
  }
@@ -10,6 +10,8 @@ export class Utils {
10
10
  return normalizedApiName;
11
11
  }
12
12
  static getNormalizedApiPathDart(apiName) {
13
+ // Remove path params like {id} from the method name.
14
+ apiName = apiName.replace(/\{[^}]+\}/g, '');
13
15
  let normalizedApiName = apiName.replace('/api/v{version}/', '').replaceAll('/', '_');
14
16
  if (normalizedApiName.charAt(0) == '_') {
15
17
  normalizedApiName = normalizedApiName.slice(1);
@@ -47,12 +49,12 @@ export class Utils {
47
49
  return undefined;
48
50
  return name.replace(/\./g, ''); // rimuove i punti per ottenere PascalCase
49
51
  }
50
- static async ensureDirectorySync(dirPath) {
52
+ static ensureDirectorySync(dirPath) {
51
53
  if (!fs.existsSync(dirPath)) {
52
54
  fs.mkdirSync(dirPath, { recursive: true });
53
55
  }
54
56
  }
55
- static async clearDirectory(dirPath) {
57
+ static clearDirectory(dirPath) {
56
58
  if (!fs.existsSync(dirPath))
57
59
  return;
58
60
  for (const file of fs.readdirSync(dirPath)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devlearning/swagger-generator",
3
- "version": "1.1.14",
3
+ "version": "1.1.15",
4
4
  "description": "Swagger generator apis and models for Angular and NextJS",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/src/generator.ts CHANGED
@@ -103,7 +103,10 @@ export class Generator {
103
103
  const apiMethod = Object.getOwnPropertyNames(apiSwaggerMethodKey)[0];
104
104
  const apiSwaggerMethod = apiSwaggerMethodKey[apiMethod];
105
105
 
106
- if (apiSwaggerMethod.requestBody?.content[contentTypeMultipartFormData]?.schema != null) {
106
+ const multipartSchema = apiSwaggerMethod.requestBody?.content?.[contentTypeMultipartFormData]?.schema;
107
+ // Only create an ad-hoc request model when the multipart schema is inline.
108
+ // If the schema is a $ref, it's already part of components/schemas and will be generated there.
109
+ if (multipartSchema != null && multipartSchema.$ref == null) {
107
110
  usedMultiPart.push(apiName);
108
111
  }
109
112
  }
@@ -154,6 +157,10 @@ export class Generator {
154
157
  const swaggerMethodInfo = swaggerMethod[method];
155
158
  const schema = swaggerMethodInfo.requestBody.content[contentTypeMultipartFormData].schema;
156
159
 
160
+ if (schema?.$ref != null) {
161
+ return;
162
+ }
163
+
157
164
  this._models.push({
158
165
  typeName: this.getApiNameNormalized(apiName),
159
166
  modelType: 'class',
@@ -209,23 +216,57 @@ export class Generator {
209
216
 
210
217
  let parameters: ParameterDto[] = [];
211
218
  try {
219
+ // Path params are always explicit parameters.
220
+ swaggerMethod.parameters?.filter(x => x.in == 'path').forEach(parameter => {
221
+ const name = this.toFirstLetterLowercase(parameter.name);
222
+ if (parameter.schema?.$ref != null) {
223
+ const type = this.retrieveType(parameter.schema);
224
+ parameters.push({
225
+ name,
226
+ typeName: type.typeName,
227
+ nullable: false,
228
+ swaggerParameter: parameter,
229
+ isQuery: false,
230
+ isEnum: this.isEnum(parameter.schema.$ref),
231
+ isTypeReference: false,
232
+ isNativeType: false,
233
+ isArray: false,
234
+ isVoid: false,
235
+ });
236
+ } else {
237
+ parameters.push({
238
+ name,
239
+ typeName: this.getNativeType(parameter.schema),
240
+ nullable: false,
241
+ swaggerParameter: parameter,
242
+ isQuery: false,
243
+ isEnum: false,
244
+ isTypeReference: false,
245
+ isNativeType: true,
246
+ isArray: false,
247
+ isVoid: false,
248
+ });
249
+ }
250
+ });
251
+
212
252
  if (swaggerMethod.requestBody != null && swaggerMethod.requestBody.content[contentTypeMultipartFormData] != null) {
213
- var modelName = this.getApiNameNormalized(apiName);
214
- parameters.push({
253
+ const schema = swaggerMethod.requestBody.content[contentTypeMultipartFormData].schema;
254
+ const type = this.retrieveType(schema);
255
+ parameters.unshift({
215
256
  name: 'request',
216
- typeName: modelName,
257
+ typeName: type.typeName,
217
258
  nullable: false,
218
259
  isQuery: false,
219
260
  isEnum: false,
220
- isTypeReference: true,
221
- isNativeType: false,
222
- isArray: false,
223
- isVoid: false,
261
+ isTypeReference: type.isTypeReference ?? true,
262
+ isNativeType: type.isNativeType ?? false,
263
+ isArray: type.isArray ?? false,
264
+ isVoid: type.isVoid ?? false,
224
265
  });
225
266
  } else {
226
267
  if (swaggerMethod.requestBody != null) {
227
268
  const type = this.retrieveType(swaggerMethod.requestBody.content[contentTypeApplicationJson].schema);
228
- parameters.push({
269
+ parameters.unshift({
229
270
  name: 'request',
230
271
  typeName: type.typeName, //swaggerMethod.requestBody.content[contentTypeApplicationJson].schema.$ref.replace('#/components/schemas/', ''),
231
272
  nullable: false,
@@ -376,12 +417,16 @@ export class Generator {
376
417
  };
377
418
  }
378
419
  else {
420
+ // Array of native types (including binary/file)
421
+ const itemType = swaggerComponentProperty.items
422
+ ? this.getNativeType(swaggerComponentProperty.items)
423
+ : this.getNativeType(swaggerComponentProperty);
379
424
  return {
380
- typeName: this.getNativeType(swaggerComponentProperty),
425
+ typeName: itemType,
381
426
  isTypeReference: false,
382
427
  isNativeType: true,
383
428
  nullable: swaggerComponentProperty.nullable ?? false,
384
- isArray: false,
429
+ isArray: true,
385
430
  isVoid: false,
386
431
  };
387
432
  }
@@ -30,6 +30,16 @@ interface EndpointDefinitionDart {
30
30
  haveRequest: boolean;
31
31
  requestType?: string; // solo se haveRequest è true
32
32
  queryParams?: Parameter[],
33
+ pathParams?: Parameter[],
34
+ isMultiPart: boolean;
35
+ multipartFields?: MultipartFieldDefinitionDart[];
36
+ }
37
+
38
+ interface MultipartFieldDefinitionDart {
39
+ name: string;
40
+ isFile: boolean;
41
+ isArray: boolean;
42
+ nullable: boolean;
33
43
  }
34
44
 
35
45
  interface Parameter {
@@ -167,18 +177,35 @@ export class ApiDartWriter {
167
177
  debugger
168
178
  }
169
179
 
180
+ const pathParams: Parameter[] = (api.parameters ?? [])
181
+ .filter(p => p.name !== 'request' && p.isQuery === false)
182
+ .map(p => ({
183
+ name: p.name,
184
+ type: p.typeName ? Normalizator.mapTsTypeToDart(p.typeName)! : 'String',
185
+ nullable: false,
186
+ }));
187
+
188
+ // Build a Dart-interpolated path string (e.g. '/x/{id}' -> '/x/$id')
189
+ const pathExpression = api.url.replace(/\{([^}]+)\}/g, (_, rawName) => {
190
+ const varName = Utils.toFirstLetterLowercase(rawName);
191
+ return `\$${varName}`;
192
+ });
193
+
170
194
  const endpoint = <EndpointDefinitionDart>{
171
195
  methodName: methodName,
172
196
  httpMethod: api.method.toLowerCase() as HttpMethodDart,
173
- path: api.url,
197
+ path: pathExpression,
174
198
  responseType: responseType,
175
199
  isResponseNativeType: api.returnType ? api.returnType.isNativeType : true,
176
200
  haveRequest: api.haveRequest,
177
201
  requestType: requestType,
202
+ pathParams,
203
+ isMultiPart: api.isMultiPart === true,
178
204
  };
179
205
 
180
206
  if (api.parameters && api.parameters.length > 0 && !api.haveRequest) {
181
207
  endpoint.queryParams = api.parameters
208
+ .filter(p => p.isQuery === true)
182
209
  .map(p => ({
183
210
  name: p.name,
184
211
  type: p.typeName ? Normalizator.mapTsTypeToDart(p.typeName)! : 'String',
@@ -201,6 +228,22 @@ export class ApiDartWriter {
201
228
  }
202
229
  }
203
230
 
231
+ // Multipart: include request model fields so template can build FormData
232
+ if (endpoint.isMultiPart && api.haveRequest && api.parameters[0]?.typeName) {
233
+ const requestModelTypeName = api.parameters[0].typeName;
234
+ const requestModel = models.find(m => m.typeName === requestModelTypeName);
235
+ if (requestModel) {
236
+ endpoint.multipartFields = requestModel.properties.map(p => ({
237
+ name: p.name,
238
+ isFile: p.typeName === 'File',
239
+ isArray: p.isArray === true,
240
+ nullable: p.nullable === true,
241
+ }));
242
+ } else {
243
+ endpoint.multipartFields = [];
244
+ }
245
+ }
246
+
204
247
  if (api.returnType && !api.returnType.isNativeType) {
205
248
  if (imports.findIndex(x => x.type.typeName == api.returnType!.typeName) == -1) {
206
249
  models.forEach(model => {
@@ -32,6 +32,7 @@ interface FieldDefinitionDart {
32
32
  typeName: string;
33
33
  nullable: string;
34
34
  required: string;
35
+ jsonKeyAnnotation?: string;
35
36
  }
36
37
 
37
38
  interface ExportClassDefinitionDart {
@@ -82,17 +83,35 @@ export class ModelDartWriter {
82
83
 
83
84
  var imports = <ImportDefinitionDart[]>[];
84
85
 
86
+ const needsDartIo = model.properties.some(p => {
87
+ const normalized = (p.typeName ?? '').trim();
88
+ return normalized === 'File' || (p.isArray && normalized === 'File');
89
+ });
90
+
91
+ if (needsDartIo) {
92
+ imports.push({
93
+ type: { typeName: 'dart:io' } as any,
94
+ import: `import 'dart:io';`
95
+ });
96
+ }
97
+
85
98
  model.properties.forEach(property => {
86
99
  var fieldTypeName = Normalizator.mapTsTypeToDart(property.typeName);
87
100
 
88
101
  fieldTypeName = Normalizator.getNormalizedTypeName(fieldTypeName);
89
102
 
103
+ const isFileField = property.typeName === 'File';
104
+ const jsonKeyAnnotation = isFileField
105
+ ? "@JsonKey(includeFromJson: false, includeToJson: false)"
106
+ : undefined;
107
+
90
108
  dartModel.fields!.push(<FieldDefinitionDart>{
91
109
  name: property.name,
92
110
  type: property.isArray ? `List<${fieldTypeName}>` : fieldTypeName,
93
111
  typeName: property.typeName,
94
112
  nullable: property.nullable && !property.isArray ? '?' : '',
95
113
  required: property.nullable && !property.isArray ? '' : 'required ',
114
+ jsonKeyAnnotation,
96
115
  });
97
116
 
98
117
  if (property.isTypeReference) {
@@ -11,15 +11,80 @@ class {{apiClassName}} {
11
11
 
12
12
  {{#endpoints}}
13
13
  Future<{{responseType}}> {{methodName}}(
14
- {{#haveRequest}}{{requestType}} request{{/haveRequest}}
14
+ {{#haveRequest}}{{requestType}} request,{{/haveRequest}}
15
+ {{#pathParams}}
16
+ {{type}}{{#nullable}}?{{/nullable}} {{name}},
17
+ {{/pathParams}}
15
18
  {{#queryParams}}
16
19
  {{type}}{{#nullable}}?{{/nullable}} {{name}},
17
20
  {{/queryParams}}
18
21
  ) async {
22
+ {{#isMultiPart}}
23
+ final formData = FormData();
24
+ {{#multipartFields}}
25
+ {{#isFile}}
26
+ {{#isArray}}
27
+ {{^nullable}}
28
+ for (final file in request.{{name}}) {
29
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(file.path)));
30
+ }
31
+ {{/nullable}}
32
+ {{#nullable}}
33
+ if (request.{{name}} != null) {
34
+ for (final file in request.{{name}}!) {
35
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(file.path)));
36
+ }
37
+ }
38
+ {{/nullable}}
39
+ {{/isArray}}
40
+ {{^isArray}}
41
+ {{^nullable}}
42
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(request.{{name}}.path)));
43
+ {{/nullable}}
44
+ {{#nullable}}
45
+ if (request.{{name}} != null) {
46
+ formData.files.add(MapEntry('{{name}}', await MultipartFile.fromFile(request.{{name}}!.path)));
47
+ }
48
+ {{/nullable}}
49
+ {{/isArray}}
50
+ {{/isFile}}
51
+ {{^isFile}}
52
+ {{#isArray}}
53
+ {{^nullable}}
54
+ for (final value in request.{{name}}) {
55
+ formData.fields.add(MapEntry('{{name}}', value.toString()));
56
+ }
57
+ {{/nullable}}
58
+ {{#nullable}}
59
+ if (request.{{name}} != null) {
60
+ for (final value in request.{{name}}!) {
61
+ formData.fields.add(MapEntry('{{name}}', value.toString()));
62
+ }
63
+ }
64
+ {{/nullable}}
65
+ {{/isArray}}
66
+ {{^isArray}}
67
+ {{^nullable}}
68
+ formData.fields.add(MapEntry('{{name}}', request.{{name}}.toString()));
69
+ {{/nullable}}
70
+ {{#nullable}}
71
+ if (request.{{name}} != null) {
72
+ formData.fields.add(MapEntry('{{name}}', request.{{name}}!.toString()));
73
+ }
74
+ {{/nullable}}
75
+ {{/isArray}}
76
+ {{/isFile}}
77
+ {{/multipartFields}}
78
+ {{/isMultiPart}}
19
79
  final response = await _dio.{{httpMethod}}(
20
80
  '{{{path}}}',
21
81
  {{#haveRequest}}
82
+ {{#isMultiPart}}
83
+ data: formData,
84
+ {{/isMultiPart}}
85
+ {{^isMultiPart}}
22
86
  data: request.toJson(),
87
+ {{/isMultiPart}}
23
88
  {{/haveRequest}}
24
89
  {{^haveRequest}}
25
90
  queryParameters: {
@@ -10,6 +10,9 @@ part '{{filename}}.g.dart';
10
10
  abstract class {{className}} with _${{className}} {
11
11
  const factory {{className}}({
12
12
  {{#fields}}
13
+ {{#jsonKeyAnnotation}}
14
+ {{{jsonKeyAnnotation}}}
15
+ {{/jsonKeyAnnotation}}
13
16
  {{required}}{{{type}}}{{nullable}} {{name}},
14
17
  {{/fields}}
15
18
  }) = _{{className}};
@@ -17,6 +17,9 @@ export class Utils {
17
17
  }
18
18
 
19
19
  public static getNormalizedApiPathDart(apiName: string) {
20
+ // Remove path params like {id} from the method name.
21
+ apiName = apiName.replace(/\{[^}]+\}/g, '');
22
+
20
23
  let normalizedApiName = apiName.replace('/api/v{version}/', '').replaceAll('/', '_');
21
24
 
22
25
  if (normalizedApiName.charAt(0) == '_') {
@@ -67,13 +70,13 @@ export class Utils {
67
70
  return name.replace(/\./g, ''); // rimuove i punti per ottenere PascalCase
68
71
  }
69
72
 
70
- public static async ensureDirectorySync(dirPath: string) {
73
+ public static ensureDirectorySync(dirPath: string) {
71
74
  if (!fs.existsSync(dirPath)) {
72
75
  fs.mkdirSync(dirPath, { recursive: true });
73
76
  }
74
77
  }
75
78
 
76
- public static async clearDirectory(dirPath: string) {
79
+ public static clearDirectory(dirPath: string) {
77
80
  if (!fs.existsSync(dirPath)) return;
78
81
 
79
82
  for (const file of fs.readdirSync(dirPath)) {