ng-openapi 0.0.41 → 0.0.42-pr-9-feature-http-resource-e6134bb.0

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.
Files changed (4) hide show
  1. package/cli.cjs +427 -511
  2. package/index.d.ts +108 -23
  3. package/index.js +484 -516
  4. package/package.json +1 -1
package/cli.cjs CHANGED
@@ -29,7 +29,400 @@ var import_commander = require("commander");
29
29
  var path10 = __toESM(require("path"));
30
30
  var fs4 = __toESM(require("fs"));
31
31
 
32
- // src/lib/core/swagger-parser.ts
32
+ // src/lib/core/generator.ts
33
+ var import_ts_morph6 = require("ts-morph");
34
+
35
+ // src/lib/generators/type/type.generator.ts
36
+ var import_ts_morph = require("ts-morph");
37
+
38
+ // ../shared/src/utils/string.utils.ts
39
+ function camelCase(str) {
40
+ const cleaned = str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
41
+ return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
42
+ }
43
+ __name(camelCase, "camelCase");
44
+ function pascalCase(str) {
45
+ return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
46
+ }
47
+ __name(pascalCase, "pascalCase");
48
+
49
+ // ../shared/src/utils/type.utils.ts
50
+ function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, context = "type") {
51
+ let schema;
52
+ let nullable;
53
+ if (typeof schemaOrType === "string" || schemaOrType === void 0) {
54
+ schema = {
55
+ type: schemaOrType,
56
+ format: typeof formatOrNullable === "string" ? formatOrNullable : void 0
57
+ };
58
+ nullable = typeof formatOrNullable === "boolean" ? formatOrNullable : isNullable;
59
+ } else {
60
+ schema = schemaOrType;
61
+ nullable = typeof formatOrNullable === "boolean" ? formatOrNullable : schema.nullable;
62
+ }
63
+ if (!schema) {
64
+ return "any";
65
+ }
66
+ if (schema.$ref) {
67
+ const refName = schema.$ref.split("/").pop();
68
+ return nullableType(pascalCase(refName), nullable);
69
+ }
70
+ if (schema.type === "array") {
71
+ const itemType = schema.items ? getTypeScriptType(schema.items, config, void 0, void 0, context) : "unknown";
72
+ return nullable ? `(${itemType}[] | null)` : `${itemType}[]`;
73
+ }
74
+ switch (schema.type) {
75
+ case "string":
76
+ if (schema.enum) {
77
+ return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
78
+ }
79
+ if (schema.format === "date" || schema.format === "date-time") {
80
+ const dateType = config.options.dateType === "Date" ? "Date" : "string";
81
+ return nullableType(dateType, nullable);
82
+ }
83
+ if (schema.format === "binary") {
84
+ const binaryType = context === "type" ? "Blob" : "File";
85
+ return nullableType(binaryType, nullable);
86
+ }
87
+ if (schema.format === "uuid" || schema.format === "email" || schema.format === "uri" || schema.format === "hostname" || schema.format === "ipv4" || schema.format === "ipv6") {
88
+ return nullableType("string", nullable);
89
+ }
90
+ return nullableType("string", nullable);
91
+ case "number":
92
+ case "integer":
93
+ return nullableType("number", nullable);
94
+ case "boolean":
95
+ return nullableType("boolean", nullable);
96
+ case "object":
97
+ return nullableType(context === "type" ? "Record<string, unknown>" : "any", nullable);
98
+ case "null":
99
+ return "null";
100
+ default:
101
+ console.warn(`Unknown swagger type: ${schema.type}`);
102
+ return nullableType("any", nullable);
103
+ }
104
+ }
105
+ __name(getTypeScriptType, "getTypeScriptType");
106
+ function nullableType(type, isNullable) {
107
+ return type + (isNullable ? " | null" : "");
108
+ }
109
+ __name(nullableType, "nullableType");
110
+ function escapeString(str) {
111
+ return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
112
+ }
113
+ __name(escapeString, "escapeString");
114
+
115
+ // ../shared/src/utils/functions/collect-used-types.ts
116
+ function collectUsedTypes(operations) {
117
+ const usedTypes = /* @__PURE__ */ new Set();
118
+ operations.forEach((operation) => {
119
+ operation.parameters?.forEach((param) => {
120
+ collectTypesFromSchema(param.schema || param, usedTypes);
121
+ });
122
+ if (operation.requestBody) {
123
+ collectTypesFromRequestBody(operation.requestBody, usedTypes);
124
+ }
125
+ if (operation.responses) {
126
+ Object.values(operation.responses).forEach((response) => {
127
+ collectTypesFromResponse(response, usedTypes);
128
+ });
129
+ }
130
+ });
131
+ return usedTypes;
132
+ }
133
+ __name(collectUsedTypes, "collectUsedTypes");
134
+ function collectTypesFromSchema(schema, usedTypes) {
135
+ if (!schema) return;
136
+ if (schema.$ref) {
137
+ const refName = schema.$ref.split("/").pop();
138
+ if (refName) {
139
+ usedTypes.add(pascalCase(refName));
140
+ }
141
+ }
142
+ if (schema.type === "array" && schema.items) {
143
+ collectTypesFromSchema(schema.items, usedTypes);
144
+ }
145
+ if (schema.type === "object" && schema.properties) {
146
+ Object.values(schema.properties).forEach((prop) => {
147
+ collectTypesFromSchema(prop, usedTypes);
148
+ });
149
+ }
150
+ if (schema.allOf) {
151
+ schema.allOf.forEach((subSchema) => {
152
+ collectTypesFromSchema(subSchema, usedTypes);
153
+ });
154
+ }
155
+ if (schema.oneOf) {
156
+ schema.oneOf.forEach((subSchema) => {
157
+ collectTypesFromSchema(subSchema, usedTypes);
158
+ });
159
+ }
160
+ if (schema.anyOf) {
161
+ schema.anyOf.forEach((subSchema) => {
162
+ collectTypesFromSchema(subSchema, usedTypes);
163
+ });
164
+ }
165
+ }
166
+ __name(collectTypesFromSchema, "collectTypesFromSchema");
167
+ function collectTypesFromRequestBody(requestBody, usedTypes) {
168
+ const content = requestBody.content || {};
169
+ Object.values(content).forEach((mediaType) => {
170
+ if (mediaType.schema) {
171
+ collectTypesFromSchema(mediaType.schema, usedTypes);
172
+ }
173
+ });
174
+ }
175
+ __name(collectTypesFromRequestBody, "collectTypesFromRequestBody");
176
+ function collectTypesFromResponse(response, usedTypes) {
177
+ const content = response.content || {};
178
+ Object.values(content).forEach((mediaType) => {
179
+ if (mediaType.schema) {
180
+ collectTypesFromSchema(mediaType.schema, usedTypes);
181
+ }
182
+ });
183
+ }
184
+ __name(collectTypesFromResponse, "collectTypesFromResponse");
185
+
186
+ // ../shared/src/utils/functions/token-names.ts
187
+ function getClientContextTokenName(clientName = "default") {
188
+ const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
189
+ return `CLIENT_CONTEXT_TOKEN_${clientSuffix}`;
190
+ }
191
+ __name(getClientContextTokenName, "getClientContextTokenName");
192
+ function getBasePathTokenName(clientName = "default") {
193
+ const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
194
+ return `BASE_PATH_${clientSuffix}`;
195
+ }
196
+ __name(getBasePathTokenName, "getBasePathTokenName");
197
+
198
+ // ../shared/src/utils/functions/duplicate-function-name.ts
199
+ function hasDuplicateFunctionNames(arr) {
200
+ return new Set(arr.map((fn) => fn.getName())).size !== arr.length;
201
+ }
202
+ __name(hasDuplicateFunctionNames, "hasDuplicateFunctionNames");
203
+
204
+ // ../shared/src/utils/functions/extract-paths.ts
205
+ function extractPaths(swaggerPaths = {}, methods = [
206
+ "get",
207
+ "post",
208
+ "put",
209
+ "patch",
210
+ "delete",
211
+ "options",
212
+ "head"
213
+ ]) {
214
+ const paths = [];
215
+ Object.entries(swaggerPaths).forEach(([path11, pathItem]) => {
216
+ methods.forEach((method) => {
217
+ if (pathItem[method]) {
218
+ const operation = pathItem[method];
219
+ paths.push({
220
+ path: path11,
221
+ method: method.toUpperCase(),
222
+ operationId: operation.operationId,
223
+ summary: operation.summary,
224
+ description: operation.description,
225
+ tags: operation.tags || [],
226
+ parameters: parseParameters(operation.parameters || [], pathItem.parameters || []),
227
+ requestBody: operation.requestBody,
228
+ responses: operation.responses || {}
229
+ });
230
+ }
231
+ });
232
+ });
233
+ return paths;
234
+ }
235
+ __name(extractPaths, "extractPaths");
236
+ function parseParameters(operationParams, pathParams) {
237
+ const allParams = [
238
+ ...pathParams,
239
+ ...operationParams
240
+ ];
241
+ return allParams.map((param) => ({
242
+ name: param.name,
243
+ in: param.in,
244
+ required: param.required || param.in === "path",
245
+ schema: param.schema,
246
+ type: param.type,
247
+ format: param.format,
248
+ description: param.description
249
+ }));
250
+ }
251
+ __name(parseParameters, "parseParameters");
252
+
253
+ // ../shared/src/utils/functions/extract-swagger-response-type.ts
254
+ function getResponseTypeFromResponse(response, responseTypeMapping) {
255
+ const content = response.content || {};
256
+ if (Object.keys(content).length === 0) {
257
+ return "json";
258
+ }
259
+ const responseTypes = [];
260
+ for (const [contentType, mediaType] of Object.entries(content)) {
261
+ const schema = mediaType?.schema;
262
+ const mapping = responseTypeMapping || {};
263
+ if (mapping[contentType]) {
264
+ responseTypes.push({
265
+ type: mapping[contentType],
266
+ priority: 1,
267
+ contentType
268
+ });
269
+ continue;
270
+ }
271
+ if (schema?.format === "binary" || schema?.format === "byte") {
272
+ responseTypes.push({
273
+ type: "blob",
274
+ priority: 2,
275
+ contentType
276
+ });
277
+ continue;
278
+ }
279
+ if (schema?.type === "string" && (schema?.format === "binary" || schema?.format === "byte")) {
280
+ responseTypes.push({
281
+ type: "blob",
282
+ priority: 2,
283
+ contentType
284
+ });
285
+ continue;
286
+ }
287
+ const isPrimitive = isPrimitiveType(schema);
288
+ const inferredType = inferResponseTypeFromContentType(contentType);
289
+ let priority = 3;
290
+ let finalType = inferredType;
291
+ if (inferredType === "json" && isPrimitive) {
292
+ finalType = "text";
293
+ priority = 2;
294
+ } else if (inferredType === "json") {
295
+ priority = 2;
296
+ }
297
+ responseTypes.push({
298
+ type: finalType,
299
+ priority,
300
+ contentType,
301
+ isPrimitive
302
+ });
303
+ }
304
+ responseTypes.sort((a, b) => a.priority - b.priority);
305
+ return responseTypes[0]?.type || "json";
306
+ }
307
+ __name(getResponseTypeFromResponse, "getResponseTypeFromResponse");
308
+ function isPrimitiveType(schema) {
309
+ if (!schema) return false;
310
+ const primitiveTypes = [
311
+ "string",
312
+ "number",
313
+ "integer",
314
+ "boolean"
315
+ ];
316
+ if (primitiveTypes.includes(schema.type)) {
317
+ return true;
318
+ }
319
+ if (schema.type === "array") {
320
+ return false;
321
+ }
322
+ if (schema.type === "object" || schema.properties) {
323
+ return false;
324
+ }
325
+ if (schema.$ref) {
326
+ return false;
327
+ }
328
+ if (schema.allOf || schema.oneOf || schema.anyOf) {
329
+ return false;
330
+ }
331
+ return false;
332
+ }
333
+ __name(isPrimitiveType, "isPrimitiveType");
334
+ function inferResponseTypeFromContentType(contentType) {
335
+ const normalizedType = contentType.split(";")[0].trim().toLowerCase();
336
+ if (normalizedType.includes("json") || normalizedType === "application/ld+json" || normalizedType === "application/hal+json" || normalizedType === "application/vnd.api+json") {
337
+ return "json";
338
+ }
339
+ if (normalizedType.includes("xml") || normalizedType === "application/soap+xml" || normalizedType === "application/atom+xml" || normalizedType === "application/rss+xml") {
340
+ return "text";
341
+ }
342
+ if (normalizedType.startsWith("text/")) {
343
+ const binaryTextTypes = [
344
+ "text/rtf",
345
+ "text/cache-manifest",
346
+ "text/vcard",
347
+ "text/calendar"
348
+ ];
349
+ if (binaryTextTypes.includes(normalizedType)) {
350
+ return "blob";
351
+ }
352
+ return "text";
353
+ }
354
+ if (normalizedType === "application/x-www-form-urlencoded" || normalizedType === "multipart/form-data") {
355
+ return "text";
356
+ }
357
+ if (normalizedType === "application/javascript" || normalizedType === "application/typescript" || normalizedType === "application/css" || normalizedType === "application/yaml" || normalizedType === "application/x-yaml" || normalizedType === "application/toml") {
358
+ return "text";
359
+ }
360
+ if (normalizedType.startsWith("image/") || normalizedType.startsWith("audio/") || normalizedType.startsWith("video/") || normalizedType === "application/pdf" || normalizedType === "application/zip" || normalizedType.includes("octet-stream")) {
361
+ return "arraybuffer";
362
+ }
363
+ return "blob";
364
+ }
365
+ __name(inferResponseTypeFromContentType, "inferResponseTypeFromContentType");
366
+ function getResponseType(response, config) {
367
+ const responseType = getResponseTypeFromResponse(response);
368
+ switch (responseType) {
369
+ case "blob":
370
+ return "Blob";
371
+ case "arraybuffer":
372
+ return "ArrayBuffer";
373
+ case "text":
374
+ return "string";
375
+ case "json": {
376
+ const content = response.content || {};
377
+ for (const [contentType, mediaType] of Object.entries(content)) {
378
+ if (inferResponseTypeFromContentType(contentType) === "json" && mediaType?.schema) {
379
+ return getTypeScriptType(mediaType.schema, config, mediaType.schema.nullable);
380
+ }
381
+ }
382
+ return "any";
383
+ }
384
+ default:
385
+ return "any";
386
+ }
387
+ }
388
+ __name(getResponseType, "getResponseType");
389
+
390
+ // ../shared/src/config/constants.ts
391
+ var disableLinting = `/* @ts-nocheck */
392
+ /* eslint-disable */
393
+ /* @noformat */
394
+ /* @formatter:off */
395
+ `;
396
+ var authorComment = `/**
397
+ * Generated by ng-openapi
398
+ `;
399
+ var defaultHeaderComment = disableLinting + authorComment;
400
+ var TYPE_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated TypeScript interfaces from Swagger specification
401
+ * Do not edit this file manually
402
+ */
403
+ `;
404
+ var SERVICE_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated service exports
405
+ * Do not edit this file manually
406
+ */
407
+ `;
408
+ var SERVICE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((controllerName) => defaultHeaderComment + `* Generated Angular service for ${controllerName} controller
409
+ * Do not edit this file manually
410
+ */
411
+ `, "SERVICE_GENERATOR_HEADER_COMMENT");
412
+ var MAIN_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Entrypoint for the client
413
+ * Do not edit this file manually
414
+ */
415
+ `;
416
+ var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated provider functions for easy setup
417
+ * Do not edit this file manually
418
+ */
419
+ `;
420
+ var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => defaultHeaderComment + `* Generated Base Interceptor for client ${clientName}
421
+ * Do not edit this file manually
422
+ */
423
+ `, "BASE_INTERCEPTOR_HEADER_COMMENT");
424
+
425
+ // ../shared/src/core/swagger-parser.ts
33
426
  var fs = __toESM(require("fs"));
34
427
  var path = __toESM(require("path"));
35
428
  var yaml = __toESM(require("js-yaml"));
@@ -70,7 +463,7 @@ var SwaggerParser = class _SwaggerParser {
70
463
  const response = await fetch(url, {
71
464
  method: "GET",
72
465
  headers: {
73
- "Accept": "application/json, application/yaml, text/yaml, text/plain, */*",
466
+ Accept: "application/json, application/yaml, text/yaml, text/plain, */*",
74
467
  "User-Agent": "ng-openapi"
75
468
  },
76
469
  // 30 second timeout
@@ -186,47 +579,6 @@ var SwaggerParser = class _SwaggerParser {
186
579
  }
187
580
  };
188
581
 
189
- // src/lib/core/generator.ts
190
- var import_ts_morph6 = require("ts-morph");
191
-
192
- // src/lib/generators/type/type.generator.ts
193
- var import_ts_morph = require("ts-morph");
194
-
195
- // src/lib/config/constants.ts
196
- var disableLinting = `/* @ts-nocheck */
197
- /* eslint-disable */
198
- /* @noformat */
199
- /* @formatter:off */
200
- `;
201
- var authorComment = `/**
202
- * Generated by ng-openapi
203
- `;
204
- var defaultHeaderComment = disableLinting + authorComment;
205
- var TYPE_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated TypeScript interfaces from Swagger specification
206
- * Do not edit this file manually
207
- */
208
- `;
209
- var SERVICE_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated service exports
210
- * Do not edit this file manually
211
- */
212
- `;
213
- var SERVICE_GENERATOR_HEADER_COMMENT = /* @__PURE__ */ __name((controllerName) => defaultHeaderComment + `* Generated Angular service for ${controllerName} controller
214
- * Do not edit this file manually
215
- */
216
- `, "SERVICE_GENERATOR_HEADER_COMMENT");
217
- var MAIN_INDEX_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Entrypoint for the client
218
- * Do not edit this file manually
219
- */
220
- `;
221
- var PROVIDER_GENERATOR_HEADER_COMMENT = defaultHeaderComment + `* Generated provider functions for easy setup
222
- * Do not edit this file manually
223
- */
224
- `;
225
- var BASE_INTERCEPTOR_HEADER_COMMENT = /* @__PURE__ */ __name((clientName) => defaultHeaderComment + `* Generated Base Interceptor for client ${clientName}
226
- * Do not edit this file manually
227
- */
228
- `, "BASE_INTERCEPTOR_HEADER_COMMENT");
229
-
230
582
  // src/lib/generators/type/type.generator.ts
231
583
  var TypeGenerator = class _TypeGenerator {
232
584
  static {
@@ -269,6 +621,7 @@ var TypeGenerator = class _TypeGenerator {
269
621
  Object.entries(definitions).forEach(([name, definition]) => {
270
622
  this.generateInterface(name, definition);
271
623
  });
624
+ this.sourceFile.formatText();
272
625
  this.sourceFile.saveSync();
273
626
  } catch (error) {
274
627
  console.error("Error in generate():", error);
@@ -639,6 +992,7 @@ var TokenGenerator = class {
639
992
  `
640
993
  });
641
994
  }
995
+ sourceFile.formatText();
642
996
  sourceFile.saveSync();
643
997
  }
644
998
  getBasePathTokenName() {
@@ -792,6 +1146,7 @@ var FileDownloadGenerator = class {
792
1146
 
793
1147
  return fallbackFilename;`
794
1148
  });
1149
+ sourceFile.formatText();
795
1150
  sourceFile.saveSync();
796
1151
  }
797
1152
  };
@@ -927,6 +1282,7 @@ var DateTransformerGenerator = class {
927
1282
  }
928
1283
  ]
929
1284
  });
1285
+ sourceFile.formatText();
930
1286
  sourceFile.saveSync();
931
1287
  }
932
1288
  };
@@ -971,6 +1327,7 @@ var MainIndexGenerator = class {
971
1327
  });
972
1328
  }
973
1329
  }
1330
+ sourceFile.formatText();
974
1331
  sourceFile.saveSync();
975
1332
  }
976
1333
  };
@@ -1069,6 +1426,7 @@ var ProviderGenerator = class {
1069
1426
  ]
1070
1427
  });
1071
1428
  this.addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName);
1429
+ sourceFile.formatText();
1072
1430
  sourceFile.saveSync();
1073
1431
  }
1074
1432
  addMainProviderFunction(sourceFile, basePathTokenName, interceptorsTokenName, baseInterceptorClassName) {
@@ -1298,6 +1656,7 @@ var BaseInterceptorGenerator = class {
1298
1656
  }
1299
1657
  ]
1300
1658
  });
1659
+ sourceFile.formatText();
1301
1660
  sourceFile.saveSync();
1302
1661
  }
1303
1662
  getInterceptorsTokenName() {
@@ -1317,83 +1676,6 @@ var BaseInterceptorGenerator = class {
1317
1676
  var import_ts_morph5 = require("ts-morph");
1318
1677
  var path8 = __toESM(require("path"));
1319
1678
 
1320
- // src/lib/utils/string.utils.ts
1321
- function camelCase(str) {
1322
- const cleaned = str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase());
1323
- return cleaned.charAt(0).toLowerCase() + cleaned.slice(1);
1324
- }
1325
- __name(camelCase, "camelCase");
1326
- function pascalCase(str) {
1327
- return str.replace(/(?:^|[-_])([a-z])/g, (_, char) => char.toUpperCase());
1328
- }
1329
- __name(pascalCase, "pascalCase");
1330
-
1331
- // src/lib/utils/type.utils.ts
1332
- function getTypeScriptType(schemaOrType, config, formatOrNullable, isNullable, context = "type") {
1333
- let schema;
1334
- let nullable;
1335
- if (typeof schemaOrType === "string" || schemaOrType === void 0) {
1336
- schema = {
1337
- type: schemaOrType,
1338
- format: typeof formatOrNullable === "string" ? formatOrNullable : void 0
1339
- };
1340
- nullable = typeof formatOrNullable === "boolean" ? formatOrNullable : isNullable;
1341
- } else {
1342
- schema = schemaOrType;
1343
- nullable = typeof formatOrNullable === "boolean" ? formatOrNullable : schema.nullable;
1344
- }
1345
- if (!schema) {
1346
- return "any";
1347
- }
1348
- if (schema.$ref) {
1349
- const refName = schema.$ref.split("/").pop();
1350
- return nullableType(pascalCase(refName), nullable);
1351
- }
1352
- if (schema.type === "array") {
1353
- const itemType = schema.items ? getTypeScriptType(schema.items, config, void 0, void 0, context) : "unknown";
1354
- return nullable ? `(${itemType}[] | null)` : `${itemType}[]`;
1355
- }
1356
- switch (schema.type) {
1357
- case "string":
1358
- if (schema.enum) {
1359
- return schema.enum.map((value) => typeof value === "string" ? `'${escapeString(value)}'` : String(value)).join(" | ");
1360
- }
1361
- if (schema.format === "date" || schema.format === "date-time") {
1362
- const dateType = config.options.dateType === "Date" ? "Date" : "string";
1363
- return nullableType(dateType, nullable);
1364
- }
1365
- if (schema.format === "binary") {
1366
- const binaryType = context === "type" ? "Blob" : "File";
1367
- return nullableType(binaryType, nullable);
1368
- }
1369
- if (schema.format === "uuid" || schema.format === "email" || schema.format === "uri" || schema.format === "hostname" || schema.format === "ipv4" || schema.format === "ipv6") {
1370
- return nullableType("string", nullable);
1371
- }
1372
- return nullableType("string", nullable);
1373
- case "number":
1374
- case "integer":
1375
- return nullableType("number", nullable);
1376
- case "boolean":
1377
- return nullableType("boolean", nullable);
1378
- case "object":
1379
- return nullableType(context === "type" ? "Record<string, unknown>" : "any", nullable);
1380
- case "null":
1381
- return "null";
1382
- default:
1383
- console.warn(`Unknown swagger type: ${schema.type}`);
1384
- return nullableType("any", nullable);
1385
- }
1386
- }
1387
- __name(getTypeScriptType, "getTypeScriptType");
1388
- function nullableType(type, isNullable) {
1389
- return type + (isNullable ? " | null" : "");
1390
- }
1391
- __name(nullableType, "nullableType");
1392
- function escapeString(str) {
1393
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
1394
- }
1395
- __name(escapeString, "escapeString");
1396
-
1397
1679
  // src/lib/generators/service/service-method/service-method-body.generator.ts
1398
1680
  var ServiceMethodBodyGenerator = class {
1399
1681
  static {
@@ -1433,84 +1715,6 @@ var ServiceMethodBodyGenerator = class {
1433
1715
  const properties = operation.requestBody?.content?.["multipart/form-data"]?.schema?.properties || {};
1434
1716
  return Object.keys(properties);
1435
1717
  }
1436
- getResponseTypeFromResponse(response) {
1437
- const content = response.content || {};
1438
- if (Object.keys(content).length === 0) {
1439
- return "json";
1440
- }
1441
- const responseTypes = [];
1442
- for (const [contentType, mediaType] of Object.entries(content)) {
1443
- const schema = mediaType?.schema;
1444
- const mapping = this.config?.options?.responseTypeMapping || {};
1445
- if (mapping[contentType]) {
1446
- responseTypes.push({
1447
- type: mapping[contentType],
1448
- priority: 1,
1449
- contentType
1450
- });
1451
- continue;
1452
- }
1453
- if (schema?.format === "binary" || schema?.format === "byte") {
1454
- responseTypes.push({
1455
- type: "blob",
1456
- priority: 2,
1457
- contentType
1458
- });
1459
- continue;
1460
- }
1461
- if (schema?.type === "string" && (schema?.format === "binary" || schema?.format === "byte")) {
1462
- responseTypes.push({
1463
- type: "blob",
1464
- priority: 2,
1465
- contentType
1466
- });
1467
- continue;
1468
- }
1469
- const isPrimitive = this.isPrimitiveType(schema);
1470
- const inferredType = this.inferResponseTypeFromContentType(contentType);
1471
- let priority = 3;
1472
- let finalType = inferredType;
1473
- if (inferredType === "json" && isPrimitive) {
1474
- finalType = "text";
1475
- priority = 2;
1476
- } else if (inferredType === "json") {
1477
- priority = 2;
1478
- }
1479
- responseTypes.push({
1480
- type: finalType,
1481
- priority,
1482
- contentType,
1483
- isPrimitive
1484
- });
1485
- }
1486
- responseTypes.sort((a, b) => a.priority - b.priority);
1487
- return responseTypes[0]?.type || "json";
1488
- }
1489
- isPrimitiveType(schema) {
1490
- if (!schema) return false;
1491
- const primitiveTypes = [
1492
- "string",
1493
- "number",
1494
- "integer",
1495
- "boolean"
1496
- ];
1497
- if (primitiveTypes.includes(schema.type)) {
1498
- return true;
1499
- }
1500
- if (schema.type === "array") {
1501
- return false;
1502
- }
1503
- if (schema.type === "object" || schema.properties) {
1504
- return false;
1505
- }
1506
- if (schema.$ref) {
1507
- return false;
1508
- }
1509
- if (schema.allOf || schema.oneOf || schema.anyOf) {
1510
- return false;
1511
- }
1512
- return false;
1513
- }
1514
1718
  createGenerationContext(operation) {
1515
1719
  return {
1516
1720
  pathParams: operation.parameters?.filter((p) => p.in === "path") || [],
@@ -1647,7 +1851,7 @@ return this.httpClient.${httpMethod}(url, requestOptions);`;
1647
1851
  for (const statusCode of successResponses) {
1648
1852
  const response = operation.responses?.[statusCode];
1649
1853
  if (!response) continue;
1650
- return this.getResponseTypeFromResponse(response);
1854
+ return getResponseTypeFromResponse(response);
1651
1855
  }
1652
1856
  return "json";
1653
1857
  }
@@ -1665,47 +1869,6 @@ return this.httpClient.${httpMethod}(url, requestOptions);`;
1665
1869
  ];
1666
1870
  return !invalidTypes.some((invalidType) => type.includes(invalidType));
1667
1871
  }
1668
- inferResponseTypeFromContentType(contentType) {
1669
- const normalizedType = contentType.split(";")[0].trim().toLowerCase();
1670
- if (normalizedType.includes("json") || normalizedType === "application/ld+json" || normalizedType === "application/hal+json" || normalizedType === "application/vnd.api+json") {
1671
- return "json";
1672
- }
1673
- if (normalizedType.includes("xml") || normalizedType === "application/soap+xml" || normalizedType === "application/atom+xml" || normalizedType === "application/rss+xml") {
1674
- return "text";
1675
- }
1676
- if (normalizedType.startsWith("text/")) {
1677
- const binaryTextTypes = [
1678
- "text/rtf",
1679
- "text/cache-manifest",
1680
- "text/vcard",
1681
- "text/calendar"
1682
- ];
1683
- if (binaryTextTypes.includes(normalizedType)) {
1684
- return "blob";
1685
- }
1686
- return "text";
1687
- }
1688
- if (normalizedType === "application/x-www-form-urlencoded" || normalizedType === "multipart/form-data") {
1689
- return "text";
1690
- }
1691
- if (normalizedType === "application/javascript" || normalizedType === "application/typescript" || normalizedType === "application/css" || normalizedType === "application/yaml" || normalizedType === "application/x-yaml" || normalizedType === "application/toml") {
1692
- return "text";
1693
- }
1694
- if (normalizedType.startsWith("image/") || normalizedType.startsWith("audio/") || normalizedType.startsWith("video/") || normalizedType === "application/pdf" || normalizedType === "application/zip" || normalizedType.includes("octet-stream")) {
1695
- return "arraybuffer";
1696
- }
1697
- return "blob";
1698
- }
1699
- generateContextHelper() {
1700
- return `
1701
- /**
1702
- * Creates HttpContext with client identification
1703
- */
1704
- private createContextWithClientId(existingContext?: HttpContext): HttpContext {
1705
- const context = existingContext || new HttpContext();
1706
- return context.set(this.clientContextToken, '${this.config.clientName || "default"}');
1707
- }`;
1708
- }
1709
1872
  };
1710
1873
 
1711
1874
  // src/lib/generators/service/service-method/service-method-params.generator.ts
@@ -1770,7 +1933,7 @@ var ServiceMethodParamsGenerator = class {
1770
1933
  hasQuestionToken: !param.required
1771
1934
  });
1772
1935
  });
1773
- return params;
1936
+ return params.sort((a, b) => Number(a.hasQuestionToken) - Number(b.hasQuestionToken));
1774
1937
  }
1775
1938
  addOptionsParameter() {
1776
1939
  return [
@@ -1882,7 +2045,7 @@ var ServiceMethodOverloadsGenerator = class {
1882
2045
  if (!response) {
1883
2046
  return "any";
1884
2047
  }
1885
- return this.getResponseType(response);
2048
+ return getResponseType(response, this.config);
1886
2049
  }
1887
2050
  generateOverloadReturnType(responseType, observe) {
1888
2051
  switch (observe) {
@@ -1896,106 +2059,6 @@ var ServiceMethodOverloadsGenerator = class {
1896
2059
  throw new Error(`Unsupported observe type: ${observe}`);
1897
2060
  }
1898
2061
  }
1899
- getResponseTypeFromResponse(response) {
1900
- const content = response.content || {};
1901
- if (Object.keys(content).length === 0) {
1902
- return "json";
1903
- }
1904
- const responseTypes = [];
1905
- for (const [contentType, mediaType] of Object.entries(content)) {
1906
- const schema = mediaType?.schema;
1907
- const mapping = this.config?.options?.responseTypeMapping || {};
1908
- if (mapping[contentType]) {
1909
- responseTypes.push({
1910
- type: mapping[contentType],
1911
- priority: 1,
1912
- contentType
1913
- });
1914
- continue;
1915
- }
1916
- if (schema?.format === "binary" || schema?.format === "byte") {
1917
- responseTypes.push({
1918
- type: "blob",
1919
- priority: 2,
1920
- contentType
1921
- });
1922
- continue;
1923
- }
1924
- if (schema?.type === "string" && (schema?.format === "binary" || schema?.format === "byte")) {
1925
- responseTypes.push({
1926
- type: "blob",
1927
- priority: 2,
1928
- contentType
1929
- });
1930
- continue;
1931
- }
1932
- const isPrimitive = this.isPrimitiveType(schema);
1933
- const inferredType = this.inferResponseTypeFromContentType(contentType);
1934
- let priority = 3;
1935
- let finalType = inferredType;
1936
- if (inferredType === "json" && isPrimitive) {
1937
- finalType = "text";
1938
- priority = 2;
1939
- } else if (inferredType === "json") {
1940
- priority = 2;
1941
- }
1942
- responseTypes.push({
1943
- type: finalType,
1944
- priority,
1945
- contentType,
1946
- isPrimitive
1947
- });
1948
- }
1949
- responseTypes.sort((a, b) => a.priority - b.priority);
1950
- return responseTypes[0]?.type || "json";
1951
- }
1952
- isPrimitiveType(schema) {
1953
- if (!schema) return false;
1954
- const primitiveTypes = [
1955
- "string",
1956
- "number",
1957
- "integer",
1958
- "boolean"
1959
- ];
1960
- if (primitiveTypes.includes(schema.type)) {
1961
- return true;
1962
- }
1963
- if (schema.type === "array") {
1964
- return false;
1965
- }
1966
- if (schema.type === "object" || schema.properties) {
1967
- return false;
1968
- }
1969
- if (schema.$ref) {
1970
- return false;
1971
- }
1972
- if (schema.allOf || schema.oneOf || schema.anyOf) {
1973
- return false;
1974
- }
1975
- return false;
1976
- }
1977
- getResponseType(response) {
1978
- const responseType = this.getResponseTypeFromResponse(response);
1979
- switch (responseType) {
1980
- case "blob":
1981
- return "Blob";
1982
- case "arraybuffer":
1983
- return "ArrayBuffer";
1984
- case "text":
1985
- return "string";
1986
- case "json": {
1987
- const content = response.content || {};
1988
- for (const [contentType, mediaType] of Object.entries(content)) {
1989
- if (this.inferResponseTypeFromContentType(contentType) === "json" && mediaType?.schema) {
1990
- return getTypeScriptType(mediaType.schema, this.config, mediaType.schema.nullable);
1991
- }
1992
- }
1993
- return "any";
1994
- }
1995
- default:
1996
- return "any";
1997
- }
1998
- }
1999
2062
  determineResponseTypeForOperation(operation) {
2000
2063
  const successResponses = [
2001
2064
  "200",
@@ -2007,41 +2070,10 @@ var ServiceMethodOverloadsGenerator = class {
2007
2070
  for (const statusCode of successResponses) {
2008
2071
  const response = operation.responses?.[statusCode];
2009
2072
  if (!response) continue;
2010
- return this.getResponseTypeFromResponse(response);
2073
+ return getResponseTypeFromResponse(response);
2011
2074
  }
2012
2075
  return "json";
2013
2076
  }
2014
- inferResponseTypeFromContentType(contentType) {
2015
- const normalizedType = contentType.split(";")[0].trim().toLowerCase();
2016
- if (normalizedType.includes("json") || normalizedType === "application/ld+json" || normalizedType === "application/hal+json" || normalizedType === "application/vnd.api+json") {
2017
- return "json";
2018
- }
2019
- if (normalizedType.includes("xml") || normalizedType === "application/soap+xml" || normalizedType === "application/atom+xml" || normalizedType === "application/rss+xml") {
2020
- return "text";
2021
- }
2022
- if (normalizedType.startsWith("text/")) {
2023
- const binaryTextTypes = [
2024
- "text/rtf",
2025
- "text/cache-manifest",
2026
- "text/vcard",
2027
- "text/calendar"
2028
- ];
2029
- if (binaryTextTypes.includes(normalizedType)) {
2030
- return "blob";
2031
- }
2032
- return "text";
2033
- }
2034
- if (normalizedType === "application/x-www-form-urlencoded" || normalizedType === "multipart/form-data") {
2035
- return "text";
2036
- }
2037
- if (normalizedType === "application/javascript" || normalizedType === "application/typescript" || normalizedType === "application/css" || normalizedType === "application/yaml" || normalizedType === "application/x-yaml" || normalizedType === "application/toml") {
2038
- return "text";
2039
- }
2040
- if (normalizedType.startsWith("image/") || normalizedType.startsWith("audio/") || normalizedType.startsWith("video/") || normalizedType === "application/pdf" || normalizedType === "application/zip" || normalizedType.includes("octet-stream")) {
2041
- return "arraybuffer";
2042
- }
2043
- return "blob";
2044
- }
2045
2077
  };
2046
2078
 
2047
2079
  // src/lib/generators/service/service-method.generator.ts
@@ -2124,7 +2156,7 @@ var ServiceGenerator = class _ServiceGenerator {
2124
2156
  }
2125
2157
  generate(outputRoot) {
2126
2158
  const outputDir = path8.join(outputRoot, "services");
2127
- const paths = this.extractPaths();
2159
+ const paths = extractPaths(this.spec.paths);
2128
2160
  if (paths.length === 0) {
2129
2161
  console.warn("No API paths found in the specification");
2130
2162
  return;
@@ -2134,53 +2166,6 @@ var ServiceGenerator = class _ServiceGenerator {
2134
2166
  this.generateServiceFile(controllerName, operations, outputDir);
2135
2167
  });
2136
2168
  }
2137
- extractPaths() {
2138
- const paths = [];
2139
- const swaggerPaths = this.spec.paths || {};
2140
- Object.entries(swaggerPaths).forEach(([path11, pathItem]) => {
2141
- const methods = [
2142
- "get",
2143
- "post",
2144
- "put",
2145
- "patch",
2146
- "delete",
2147
- "options",
2148
- "head"
2149
- ];
2150
- methods.forEach((method) => {
2151
- if (pathItem[method]) {
2152
- const operation = pathItem[method];
2153
- paths.push({
2154
- path: path11,
2155
- method: method.toUpperCase(),
2156
- operationId: operation.operationId,
2157
- summary: operation.summary,
2158
- description: operation.description,
2159
- tags: operation.tags || [],
2160
- parameters: this.parseParameters(operation.parameters || [], pathItem.parameters || []),
2161
- requestBody: operation.requestBody,
2162
- responses: operation.responses || {}
2163
- });
2164
- }
2165
- });
2166
- });
2167
- return paths;
2168
- }
2169
- parseParameters(operationParams, pathParams) {
2170
- const allParams = [
2171
- ...pathParams,
2172
- ...operationParams
2173
- ];
2174
- return allParams.map((param) => ({
2175
- name: param.name,
2176
- in: param.in,
2177
- required: param.required || param.in === "path",
2178
- schema: param.schema,
2179
- type: param.type,
2180
- format: param.format,
2181
- description: param.description
2182
- }));
2183
- }
2184
2169
  groupPathsByController(paths) {
2185
2170
  const groups = {};
2186
2171
  paths.forEach((path11) => {
@@ -2207,79 +2192,15 @@ var ServiceGenerator = class _ServiceGenerator {
2207
2192
  const sourceFile = this.project.createSourceFile(filePath, "", {
2208
2193
  overwrite: true
2209
2194
  });
2210
- const usedTypes = this.collectUsedTypes(operations);
2195
+ const usedTypes = collectUsedTypes(operations);
2211
2196
  this.addImports(sourceFile, usedTypes);
2212
2197
  this.addServiceClass(sourceFile, controllerName, operations);
2198
+ sourceFile.formatText();
2213
2199
  sourceFile.saveSync();
2214
2200
  }
2215
- collectUsedTypes(operations) {
2216
- const usedTypes = /* @__PURE__ */ new Set();
2217
- operations.forEach((operation) => {
2218
- operation.parameters?.forEach((param) => {
2219
- this.collectTypesFromSchema(param.schema || param, usedTypes);
2220
- });
2221
- if (operation.requestBody) {
2222
- this.collectTypesFromRequestBody(operation.requestBody, usedTypes);
2223
- }
2224
- if (operation.responses) {
2225
- Object.values(operation.responses).forEach((response) => {
2226
- this.collectTypesFromResponse(response, usedTypes);
2227
- });
2228
- }
2229
- });
2230
- return usedTypes;
2231
- }
2232
- collectTypesFromSchema(schema, usedTypes) {
2233
- if (!schema) return;
2234
- if (schema.$ref) {
2235
- const refName = schema.$ref.split("/").pop();
2236
- if (refName) {
2237
- usedTypes.add(pascalCase(refName));
2238
- }
2239
- }
2240
- if (schema.type === "array" && schema.items) {
2241
- this.collectTypesFromSchema(schema.items, usedTypes);
2242
- }
2243
- if (schema.type === "object" && schema.properties) {
2244
- Object.values(schema.properties).forEach((prop) => {
2245
- this.collectTypesFromSchema(prop, usedTypes);
2246
- });
2247
- }
2248
- if (schema.allOf) {
2249
- schema.allOf.forEach((subSchema) => {
2250
- this.collectTypesFromSchema(subSchema, usedTypes);
2251
- });
2252
- }
2253
- if (schema.oneOf) {
2254
- schema.oneOf.forEach((subSchema) => {
2255
- this.collectTypesFromSchema(subSchema, usedTypes);
2256
- });
2257
- }
2258
- if (schema.anyOf) {
2259
- schema.anyOf.forEach((subSchema) => {
2260
- this.collectTypesFromSchema(subSchema, usedTypes);
2261
- });
2262
- }
2263
- }
2264
- collectTypesFromRequestBody(requestBody, usedTypes) {
2265
- const content = requestBody.content || {};
2266
- Object.values(content).forEach((mediaType) => {
2267
- if (mediaType.schema) {
2268
- this.collectTypesFromSchema(mediaType.schema, usedTypes);
2269
- }
2270
- });
2271
- }
2272
- collectTypesFromResponse(response, usedTypes) {
2273
- const content = response.content || {};
2274
- Object.values(content).forEach((mediaType) => {
2275
- if (mediaType.schema) {
2276
- this.collectTypesFromSchema(mediaType.schema, usedTypes);
2277
- }
2278
- });
2279
- }
2280
2201
  addImports(sourceFile, usedTypes) {
2281
- const basePathTokenName = this.getBasePathTokenName();
2282
- const clientContextTokenName = this.getClientContextTokenName();
2202
+ const basePathTokenName = getBasePathTokenName(this.config.clientName);
2203
+ const clientContextTokenName = getClientContextTokenName(this.config.clientName);
2283
2204
  sourceFile.addImportDeclarations([
2284
2205
  {
2285
2206
  namedImports: [
@@ -2295,7 +2216,8 @@ var ServiceGenerator = class _ServiceGenerator {
2295
2216
  "HttpHeaders",
2296
2217
  "HttpContext",
2297
2218
  "HttpResponse",
2298
- "HttpEvent"
2219
+ "HttpEvent",
2220
+ "HttpContextToken"
2299
2221
  ],
2300
2222
  moduleSpecifier: "@angular/common/http"
2301
2223
  },
@@ -2322,8 +2244,8 @@ var ServiceGenerator = class _ServiceGenerator {
2322
2244
  }
2323
2245
  addServiceClass(sourceFile, controllerName, operations) {
2324
2246
  const className = `${controllerName}Service`;
2325
- const basePathTokenName = this.getBasePathTokenName();
2326
- const clientContextTokenName = this.getClientContextTokenName();
2247
+ const basePathTokenName = getBasePathTokenName(this.config.clientName);
2248
+ const clientContextTokenName = getClientContextTokenName(this.config.clientName);
2327
2249
  sourceFile.insertText(0, SERVICE_GENERATOR_HEADER_COMMENT(controllerName));
2328
2250
  const serviceClass = sourceFile.addClass({
2329
2251
  name: className,
@@ -2353,7 +2275,7 @@ var ServiceGenerator = class _ServiceGenerator {
2353
2275
  });
2354
2276
  serviceClass.addProperty({
2355
2277
  name: "clientContextToken",
2356
- type: "any",
2278
+ type: "HttpContextToken<string>",
2357
2279
  scope: import_ts_morph5.Scope.Private,
2358
2280
  isReadonly: true,
2359
2281
  initializer: clientContextTokenName
@@ -2369,30 +2291,16 @@ var ServiceGenerator = class _ServiceGenerator {
2369
2291
  }
2370
2292
  ],
2371
2293
  returnType: "HttpContext",
2372
- statements: `
2373
- const context = existingContext || new HttpContext();
2294
+ statements: `const context = existingContext || new HttpContext();
2374
2295
  return context.set(this.clientContextToken, '${this.config.clientName || "default"}');`
2375
2296
  });
2376
2297
  operations.forEach((operation) => {
2377
2298
  this.methodGenerator.addServiceMethod(serviceClass, operation);
2378
2299
  });
2379
- if (this.hasDuplicateMethodNames(serviceClass.getMethods())) {
2300
+ if (hasDuplicateFunctionNames(serviceClass.getMethods())) {
2380
2301
  throw new Error(`Duplicate method names found in service class ${className}. Please ensure unique method names for each operation.`);
2381
2302
  }
2382
2303
  }
2383
- getClientContextTokenName() {
2384
- const clientName = this.config.clientName || "default";
2385
- const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
2386
- return `CLIENT_CONTEXT_TOKEN_${clientSuffix}`;
2387
- }
2388
- getBasePathTokenName() {
2389
- const clientName = this.config.clientName || "default";
2390
- const clientSuffix = clientName.toUpperCase().replace(/[^A-Z0-9]/g, "_");
2391
- return `BASE_PATH_${clientSuffix}`;
2392
- }
2393
- hasDuplicateMethodNames(arr) {
2394
- return new Set(arr.map((method) => method.getName())).size !== arr.length;
2395
- }
2396
2304
  };
2397
2305
 
2398
2306
  // src/lib/generators/service/service-index.generator.ts
@@ -2497,6 +2405,14 @@ async function generateFromConfig(config) {
2497
2405
  const baseInterceptorGenerator = new BaseInterceptorGenerator(project, config.clientName);
2498
2406
  baseInterceptorGenerator.generate(outputPath);
2499
2407
  }
2408
+ if (config.plugins?.length) {
2409
+ for (const plugin of config.plugins) {
2410
+ const PluginClass = plugin;
2411
+ const pluginGenerator = await PluginClass.create(config.input, project, config);
2412
+ pluginGenerator.generate(outputPath);
2413
+ }
2414
+ console.log(`\u2705 Plugins are generated`);
2415
+ }
2500
2416
  const mainIndexGenerator = new MainIndexGenerator(project, config);
2501
2417
  mainIndexGenerator.generateMainIndex(outputPath);
2502
2418
  const sourceInfo = `from ${inputType}: ${config.input}`;
@@ -2521,7 +2437,7 @@ async function generateFromConfig(config) {
2521
2437
  __name(generateFromConfig, "generateFromConfig");
2522
2438
 
2523
2439
  // package.json
2524
- var version = "0.0.40";
2440
+ var version = "0.0.41";
2525
2441
 
2526
2442
  // src/lib/cli.ts
2527
2443
  var program = new import_commander.Command();