wrekenfile-converter 2.0.7 → 2.1.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 (52) hide show
  1. package/README.md +45 -26
  2. package/dist/example-usage.d.ts +1 -1
  3. package/dist/index.d.ts +6 -5
  4. package/dist/index.js +53 -20
  5. package/dist/v1/index.d.ts +3 -0
  6. package/dist/v1/index.js +21 -0
  7. package/dist/{wrekenfile-validator.js → v1/wrekenfile-validator.js} +30 -8
  8. package/dist/v2/cli/cli-mini-wrekenfile-generator.d.ts +2 -0
  9. package/dist/v2/cli/cli-mini-wrekenfile-generator.js +107 -0
  10. package/dist/v2/cli/cli-openapi-to-wrekenfile.d.ts +2 -0
  11. package/dist/v2/cli/cli-openapi-to-wrekenfile.js +115 -0
  12. package/dist/v2/cli/cli-openapi-v2-to-wrekenfile.d.ts +2 -0
  13. package/dist/v2/cli/cli-openapi-v2-to-wrekenfile.js +115 -0
  14. package/dist/v2/cli/cli-postman-to-wrekenfile.d.ts +2 -0
  15. package/dist/v2/cli/cli-postman-to-wrekenfile.js +54 -0
  16. package/dist/v2/index.d.ts +4 -0
  17. package/dist/v2/index.js +25 -0
  18. package/dist/v2/mini-wrekenfile-generator.d.ts +13 -0
  19. package/dist/v2/mini-wrekenfile-generator.js +289 -0
  20. package/dist/v2/openapi-to-wreken.d.ts +2 -0
  21. package/dist/v2/openapi-to-wreken.js +829 -0
  22. package/dist/v2/openapi-v2-to-wrekenfile.d.ts +2 -0
  23. package/dist/v2/openapi-v2-to-wrekenfile.js +806 -0
  24. package/dist/v2/postman-to-wrekenfile.d.ts +11 -0
  25. package/dist/v2/postman-to-wrekenfile.js +742 -0
  26. package/dist/v2/utils/constants.d.ts +80 -0
  27. package/dist/v2/utils/constants.js +104 -0
  28. package/dist/v2/utils/response-utils.d.ts +11 -0
  29. package/dist/v2/utils/response-utils.js +39 -0
  30. package/dist/v2/utils/yaml-utils.d.ts +4 -0
  31. package/dist/v2/utils/yaml-utils.js +96 -0
  32. package/dist/versions.d.ts +9 -0
  33. package/dist/versions.js +12 -0
  34. package/package.json +12 -14
  35. package/dist/openapi-to-wrekenfile.d.ts +0 -0
  36. package/dist/openapi-to-wrekenfile.js +0 -10
  37. package/wrekenfile.md +0 -726
  38. /package/dist/{cli → v1/cli}/cli-mini-wrekenfile-generator.d.ts +0 -0
  39. /package/dist/{cli → v1/cli}/cli-mini-wrekenfile-generator.js +0 -0
  40. /package/dist/{cli → v1/cli}/cli-openapi-to-wrekenfile.d.ts +0 -0
  41. /package/dist/{cli → v1/cli}/cli-openapi-to-wrekenfile.js +0 -0
  42. /package/dist/{cli → v1/cli}/cli-postman-to-wrekenfile.d.ts +0 -0
  43. /package/dist/{cli → v1/cli}/cli-postman-to-wrekenfile.js +0 -0
  44. /package/dist/{mini-wrekenfile-generator.d.ts → v1/mini-wrekenfile-generator.d.ts} +0 -0
  45. /package/dist/{mini-wrekenfile-generator.js → v1/mini-wrekenfile-generator.js} +0 -0
  46. /package/dist/{openapi-to-wreken.d.ts → v1/openapi-to-wreken.d.ts} +0 -0
  47. /package/dist/{openapi-to-wreken.js → v1/openapi-to-wreken.js} +0 -0
  48. /package/dist/{openapi-v2-to-wrekenfile.d.ts → v1/openapi-v2-to-wrekenfile.d.ts} +0 -0
  49. /package/dist/{openapi-v2-to-wrekenfile.js → v1/openapi-v2-to-wrekenfile.js} +0 -0
  50. /package/dist/{postman-to-wrekenfile.d.ts → v1/postman-to-wrekenfile.d.ts} +0 -0
  51. /package/dist/{postman-to-wrekenfile.js → v1/postman-to-wrekenfile.js} +0 -0
  52. /package/dist/{wrekenfile-validator.d.ts → v1/wrekenfile-validator.d.ts} +0 -0
@@ -0,0 +1,742 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __rest = (this && this.__rest) || function (s, e) {
36
+ var t = {};
37
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
38
+ t[p] = s[p];
39
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
40
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
41
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
42
+ t[p[i]] = s[p[i]];
43
+ }
44
+ return t;
45
+ };
46
+ Object.defineProperty(exports, "__esModule", { value: true });
47
+ exports.generateWrekenfile = generateWrekenfile;
48
+ exports.extractStructs = extractStructs;
49
+ exports.extractOperations = extractOperations;
50
+ exports.mapType = mapType;
51
+ exports.parseJsonExample = parseJsonExample;
52
+ exports.extractFieldsFromObject = extractFieldsFromObject;
53
+ exports.loadEnvironmentFile = loadEnvironmentFile;
54
+ exports.extractCollectionVariables = extractCollectionVariables;
55
+ exports.resolveVariables = resolveVariables;
56
+ // postman-to-wrekenfile.ts
57
+ // Converts Postman collections to Wrekenfile v2.0.1 format
58
+ const fs = __importStar(require("fs"));
59
+ const js_yaml_1 = require("js-yaml");
60
+ const yaml_utils_1 = require("./utils/yaml-utils");
61
+ const constants_1 = require("./utils/constants");
62
+ const response_utils_1 = require("./utils/response-utils");
63
+ function mapType(value) {
64
+ if (typeof value === 'string') {
65
+ // Check for common patterns
66
+ if (/^\d{4}-\d{2}-\d{2}/.test(value))
67
+ return 'DATE';
68
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value))
69
+ return 'STRING'; // UUID as string
70
+ if (/^\d+$/.test(value))
71
+ return 'INT';
72
+ if (/^\d+\.\d+$/.test(value))
73
+ return 'FLOAT';
74
+ if (value === 'true' || value === 'false')
75
+ return 'BOOL';
76
+ return 'STRING';
77
+ }
78
+ if (typeof value === 'number') {
79
+ return Number.isInteger(value) ? 'INT' : 'FLOAT';
80
+ }
81
+ if (typeof value === 'boolean')
82
+ return 'BOOL';
83
+ if (Array.isArray(value))
84
+ return 'ANY'; // Arrays will be handled specially
85
+ if (value === null || value === undefined)
86
+ return 'ANY';
87
+ return 'ANY';
88
+ }
89
+ function getItemDescription(item) {
90
+ var _a, _b, _c, _d, _e;
91
+ let description = (_c = (_a = item === null || item === void 0 ? void 0 : item.description) !== null && _a !== void 0 ? _a : (_b = item === null || item === void 0 ? void 0 : item.request) === null || _b === void 0 ? void 0 : _b.description) !== null && _c !== void 0 ? _c : (_e = (_d = item === null || item === void 0 ? void 0 : item.request) === null || _d === void 0 ? void 0 : _d.body) === null || _e === void 0 ? void 0 : _e.description;
92
+ if (!description)
93
+ return '';
94
+ // Postman can store description as an object with { content: string }
95
+ if (typeof description === 'object' && typeof description.content === 'string') {
96
+ description = description.content;
97
+ }
98
+ if (typeof description !== 'string')
99
+ return '';
100
+ return description.replace(/<[^>]*>/g, '').replace(/\n+/g, ' ').trim();
101
+ }
102
+ function generateSummary(item, method, path) {
103
+ const cleaned = getItemDescription(item);
104
+ if (cleaned) {
105
+ // Use first sentence as summary
106
+ const firstSentence = cleaned.split(/[.!?]\s/)[0];
107
+ return firstSentence || cleaned.substring(0, 100);
108
+ }
109
+ const verb = {
110
+ get: 'Fetch',
111
+ post: 'Create',
112
+ put: 'Update',
113
+ delete: 'Delete',
114
+ patch: 'Modify',
115
+ }[method.toLowerCase()] || 'Call';
116
+ const entity = path.split('/').filter(p => p && !p.startsWith('{')).pop() || 'resource';
117
+ return `${verb} ${entity}`;
118
+ }
119
+ function generateStructName(itemName, method, path, suffix) {
120
+ const cleanName = itemName.replace(/[^a-zA-Z0-9]/g, '');
121
+ const cleanPath = path.replace(/[\/{}]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
122
+ return `${method.toLowerCase()}-${cleanPath}-${suffix}`;
123
+ }
124
+ function parseJsonExample(jsonStr) {
125
+ try {
126
+ return JSON.parse(jsonStr);
127
+ }
128
+ catch (_a) {
129
+ return null;
130
+ }
131
+ }
132
+ function extractFieldsFromObject(obj, depth = 0, prefix = '') {
133
+ if (depth > 3)
134
+ return [];
135
+ if (!obj)
136
+ return [];
137
+ // If the root object is an array, extract fields from the first object
138
+ if (Array.isArray(obj) && obj.length > 0 && typeof obj[0] === 'object' && obj[0] !== null) {
139
+ return extractFieldsFromObject(obj[0], depth + 1, prefix);
140
+ }
141
+ if (Array.isArray(obj))
142
+ return [];
143
+ if (typeof obj !== 'object')
144
+ return [];
145
+ const fields = [];
146
+ const keyCount = {};
147
+ for (const [key, value] of Object.entries(obj)) {
148
+ let type = 'ANY';
149
+ let required = false;
150
+ // Handle duplicate keys
151
+ let fieldName = key;
152
+ if (keyCount[key] === undefined) {
153
+ keyCount[key] = 1;
154
+ }
155
+ else {
156
+ keyCount[key] += 1;
157
+ fieldName = `${key} ${keyCount[key]}`;
158
+ }
159
+ if (Array.isArray(value)) {
160
+ if (value.length > 0) {
161
+ const firstItem = value[0];
162
+ if (typeof firstItem === 'object' && firstItem !== null) {
163
+ type = `[]STRUCT(${prefix}${fieldName}Item)`;
164
+ }
165
+ else {
166
+ type = `[]${mapType(firstItem)}`;
167
+ }
168
+ }
169
+ else {
170
+ type = '[]ANY';
171
+ }
172
+ }
173
+ else if (typeof value === 'object' && value !== null) {
174
+ type = `STRUCT(${prefix}${fieldName})`;
175
+ }
176
+ else {
177
+ type = mapType(value);
178
+ }
179
+ fields.push({
180
+ name: fieldName,
181
+ type,
182
+ REQUIRED: required,
183
+ });
184
+ }
185
+ return fields;
186
+ }
187
+ function loadEnvironmentFile(envPath) {
188
+ try {
189
+ const envData = fs.readFileSync(envPath, 'utf8');
190
+ const env = JSON.parse(envData);
191
+ const variables = {};
192
+ if (env.values) {
193
+ for (const variable of env.values) {
194
+ if (variable.key && variable.value) {
195
+ variables[variable.key] = variable.value;
196
+ }
197
+ }
198
+ }
199
+ return variables;
200
+ }
201
+ catch (error) {
202
+ return {};
203
+ }
204
+ }
205
+ function extractCollectionVariables(collection) {
206
+ const variables = {};
207
+ // Extract collection-level variables
208
+ if (collection.variable) {
209
+ for (const variable of collection.variable) {
210
+ if (variable.key && variable.value) {
211
+ variables[variable.key] = variable.value;
212
+ }
213
+ }
214
+ }
215
+ return variables;
216
+ }
217
+ function resolveVariables(value, variables) {
218
+ if (typeof value !== 'string')
219
+ return value;
220
+ // Replace {{variable}} patterns with actual values
221
+ return value.replace(/\{\{([^}]+)\}\}/g, (match, varName) => {
222
+ return variables[varName] || match;
223
+ });
224
+ }
225
+ function extractStructs(collection, variables) {
226
+ const structs = {};
227
+ const structNameCount = {};
228
+ function getUniqueStructName(name) {
229
+ if (structs[name] === undefined) {
230
+ structNameCount[name] = 1;
231
+ return name;
232
+ }
233
+ else {
234
+ structNameCount[name] = (structNameCount[name] || 1) + 1;
235
+ return `${name} ${structNameCount[name]}`;
236
+ }
237
+ }
238
+ function processItem(item) {
239
+ var _a;
240
+ if (item.request) {
241
+ const method = item.request.method || 'GET';
242
+ const url = item.request.url;
243
+ const path = extractPathFromUrl(url, variables);
244
+ const itemName = item.name || 'unknown';
245
+ // Extract request body structs
246
+ if (((_a = item.request.body) === null || _a === void 0 ? void 0 : _a.mode) === 'raw' && item.request.body.raw) {
247
+ const bodyData = parseJsonExample(item.request.body.raw);
248
+ if (bodyData) {
249
+ let requestStructName = generateStructName(itemName, method, path, 'Request');
250
+ requestStructName = getUniqueStructName(requestStructName);
251
+ const fields = extractFieldsFromObject(bodyData, 0, requestStructName);
252
+ if (fields.length > 0) {
253
+ structs[requestStructName] = fields;
254
+ }
255
+ extractNestedStructs(bodyData, structs, requestStructName);
256
+ }
257
+ }
258
+ // Extract response structs from examples
259
+ if (item.response) {
260
+ for (const response of item.response) {
261
+ let responseStructName = generateStructName(itemName, method, path, `Response${response.code || '200'}`);
262
+ responseStructName = getUniqueStructName(responseStructName);
263
+ if (response.body) {
264
+ const responseData = parseJsonExample(response.body);
265
+ if (responseData) {
266
+ const fields = extractFieldsFromObject(responseData, 0, responseStructName);
267
+ if (fields.length > 0) {
268
+ structs[responseStructName] = fields;
269
+ }
270
+ extractNestedStructs(responseData, structs, responseStructName);
271
+ }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ if (item.item) {
277
+ for (const subItem of item.item) {
278
+ processItem(subItem);
279
+ }
280
+ }
281
+ }
282
+ for (const item of collection.item) {
283
+ processItem(item);
284
+ }
285
+ return structs;
286
+ }
287
+ function extractNestedStructs(obj, structs, prefix = '') {
288
+ if (!obj || typeof obj !== 'object' || Array.isArray(obj))
289
+ return;
290
+ for (const [key, value] of Object.entries(obj)) {
291
+ if (Array.isArray(value) && value.length > 0) {
292
+ const firstItem = value[0];
293
+ if (typeof firstItem === 'object' && firstItem !== null) {
294
+ const structName = `${prefix}${key}Item`;
295
+ const fields = extractFieldsFromObject(firstItem, 0, structName);
296
+ if (fields.length > 0) {
297
+ structs[structName] = fields;
298
+ }
299
+ extractNestedStructs(firstItem, structs, `${prefix}${key}Item`);
300
+ }
301
+ }
302
+ else if (typeof value === 'object' && value !== null) {
303
+ const structName = `${prefix}${key}`;
304
+ const fields = extractFieldsFromObject(value, 0, structName);
305
+ if (fields.length > 0) {
306
+ structs[structName] = fields;
307
+ }
308
+ extractNestedStructs(value, structs, `${prefix}${key}`);
309
+ }
310
+ }
311
+ }
312
+ function extractPathFromUrl(url, variables) {
313
+ if (url === null || url === void 0 ? void 0 : url.raw) {
314
+ // Remove base URL and protocol
315
+ let path = url.raw;
316
+ path = resolveVariables(path, variables); // Resolve variables first
317
+ path = path.replace(/^https?:\/\/[^\/]+/, ''); // Remove protocol and host
318
+ path = path.replace(/\{\{.*?\}\}/g, ''); // Remove any remaining Postman variables
319
+ path = path.replace(/\/+/g, '/'); // Normalize slashes
320
+ path = path.replace(/^\/|\/$/g, ''); // Remove leading/trailing slashes
321
+ return path;
322
+ }
323
+ if (url === null || url === void 0 ? void 0 : url.path) {
324
+ const resolvedPath = url.path.map((segment) => resolveVariables(segment, variables));
325
+ return resolvedPath.join('/');
326
+ }
327
+ return '';
328
+ }
329
+ function getContentTypeAndBodyType(request) {
330
+ const headers = request.header || [];
331
+ const contentTypeHeader = headers.find((h) => { var _a; return ((_a = h.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'content-type'; });
332
+ let contentType = 'application/json';
333
+ if (contentTypeHeader) {
334
+ contentType = contentTypeHeader.value || 'application/json';
335
+ }
336
+ let bodyType = 'raw';
337
+ if (contentType === 'multipart/form-data') {
338
+ bodyType = 'form-data';
339
+ }
340
+ else if (contentType === 'application/x-www-form-urlencoded') {
341
+ bodyType = 'x-www-form-urlencoded';
342
+ }
343
+ return { contentType, bodyType };
344
+ }
345
+ function getHeadersForOperation(request, variables) {
346
+ var _a;
347
+ const { contentType } = getContentTypeAndBodyType(request);
348
+ const headerMap = new Map();
349
+ // Add Content-Type header for POST/PUT/PATCH requests
350
+ if (['post', 'put', 'patch'].includes(((_a = request.method) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '')) {
351
+ headerMap.set('Content-Type', contentType);
352
+ }
353
+ // Add authentication headers
354
+ const authHeaders = request.header || [];
355
+ for (const header of authHeaders) {
356
+ if (header.key && header.value) {
357
+ const key = header.key.toLowerCase();
358
+ if (key === 'x-api-key' || key === 'authorization' || key === 'x-signature') {
359
+ let value = resolveVariables(header.value, variables);
360
+ if (key === 'x-api-key')
361
+ value = 'api_key';
362
+ else if (key === 'authorization')
363
+ value = 'bearer_token';
364
+ else if (key === 'x-signature')
365
+ value = 'signature';
366
+ headerMap.set(header.key, value);
367
+ }
368
+ }
369
+ }
370
+ // Convert Map to object
371
+ const headers = {};
372
+ for (const [key, value] of headerMap.entries()) {
373
+ headers[key] = value;
374
+ }
375
+ return headers;
376
+ }
377
+ function extractParameters(request, variables) {
378
+ const inputParams = [];
379
+ // Extract URL parameters
380
+ const url = request.url;
381
+ if (url === null || url === void 0 ? void 0 : url.variable) {
382
+ for (const variable of url.variable) {
383
+ const isRequired = !variable.disabled;
384
+ const inputParam = {};
385
+ if (isRequired) {
386
+ // Simple form
387
+ inputParam[variable.key] = 'STRING';
388
+ }
389
+ else {
390
+ // Extended form
391
+ inputParam[variable.key] = {
392
+ TYPE: 'STRING',
393
+ REQUIRED: false,
394
+ };
395
+ }
396
+ inputParams.push(inputParam);
397
+ }
398
+ }
399
+ // Extract query parameters
400
+ if (url === null || url === void 0 ? void 0 : url.query) {
401
+ for (const query of url.query) {
402
+ const isRequired = !query.disabled;
403
+ const inputParam = {};
404
+ if (isRequired) {
405
+ // Simple form
406
+ inputParam[query.key] = 'STRING';
407
+ }
408
+ else {
409
+ // Extended form
410
+ inputParam[query.key] = {
411
+ TYPE: 'STRING',
412
+ REQUIRED: false,
413
+ };
414
+ }
415
+ inputParams.push(inputParam);
416
+ }
417
+ }
418
+ return inputParams;
419
+ }
420
+ function extractRequestBody(request, itemName, method, path) {
421
+ var _a, _b, _c;
422
+ const inputParams = [];
423
+ if (((_a = request.body) === null || _a === void 0 ? void 0 : _a.mode) === 'raw' && request.body.raw) {
424
+ const bodyData = parseJsonExample(request.body.raw);
425
+ if (bodyData) {
426
+ const requestStructName = generateStructName(itemName, method, path, 'Request');
427
+ const inputParam = {};
428
+ inputParam.body = {
429
+ TYPE: `STRUCT(${requestStructName})`,
430
+ REQUIRED: true,
431
+ };
432
+ inputParams.push(inputParam);
433
+ }
434
+ }
435
+ // Handle form-data and urlencoded
436
+ if (((_b = request.body) === null || _b === void 0 ? void 0 : _b.mode) === 'formdata' || ((_c = request.body) === null || _c === void 0 ? void 0 : _c.mode) === 'urlencoded') {
437
+ const formData = request.body.formdata || request.body.urlencoded || [];
438
+ for (const field of formData) {
439
+ const type = field.type === 'file' ? 'STRING' : 'STRING';
440
+ const isRequired = !field.disabled;
441
+ const inputParam = {};
442
+ if (isRequired) {
443
+ inputParam[field.key] = type;
444
+ }
445
+ else {
446
+ inputParam[field.key] = {
447
+ TYPE: type,
448
+ REQUIRED: false,
449
+ };
450
+ }
451
+ inputParams.push(inputParam);
452
+ }
453
+ }
454
+ return inputParams;
455
+ }
456
+ function extractResponses(item, itemName, method, path) {
457
+ var _a;
458
+ const returns = [];
459
+ const seenCodes = new Set();
460
+ if (item.response) {
461
+ for (const response of item.response) {
462
+ const code = ((_a = response.code) === null || _a === void 0 ? void 0 : _a.toString()) || '200';
463
+ const statusCode = parseInt(code);
464
+ // Only include success responses (2xx) in RETURNS section
465
+ // Error responses go in ERRORS section
466
+ if (isNaN(statusCode) || statusCode < 200 || statusCode >= 300) {
467
+ continue;
468
+ }
469
+ // Avoid duplicate response codes
470
+ if (seenCodes.has(code))
471
+ continue;
472
+ seenCodes.add(code);
473
+ // Skip 204 No Content
474
+ if (code === '204')
475
+ continue;
476
+ let returnType = 'ANY';
477
+ if (response.body) {
478
+ const responseData = parseJsonExample(response.body);
479
+ if (responseData) {
480
+ const responseStructName = generateStructName(itemName, method, path, `Response${code}`);
481
+ returnType = `STRUCT(${responseStructName})`;
482
+ }
483
+ }
484
+ // Only add if there's actually a return type
485
+ if (returnType !== constants_1.TYPE_VOID) {
486
+ // Generate descriptive RETURNVAR name based on response code and operation
487
+ // Clean itemName: replace spaces and special chars with underscores, convert to lowercase
488
+ const cleanItemName = itemName
489
+ .replace(/[^a-zA-Z0-9]/g, '_')
490
+ .replace(/_+/g, '_')
491
+ .replace(/^_|_$/g, '')
492
+ .toLowerCase();
493
+ const returnVarName = (0, response_utils_1.generateReturnVarName)(cleanItemName, code);
494
+ returns.push({
495
+ RETURNTYPE: returnType,
496
+ RETURNVAR: returnVarName,
497
+ });
498
+ }
499
+ }
500
+ }
501
+ return returns;
502
+ }
503
+ function extractErrors(item, itemName, method, path) {
504
+ var _a;
505
+ const errors = [];
506
+ if (item.response) {
507
+ for (const response of item.response) {
508
+ const code = parseInt(((_a = response.code) === null || _a === void 0 ? void 0 : _a.toString()) || '200');
509
+ if (isNaN(code) || code < 400)
510
+ continue;
511
+ let errorType = 'ANY';
512
+ let when = `HTTP ${code}`;
513
+ if (response.body) {
514
+ const responseData = parseJsonExample(response.body);
515
+ if (responseData) {
516
+ const errorStructName = `Error${code}`;
517
+ errorType = `STRUCT(${errorStructName})`;
518
+ }
519
+ }
520
+ when = (0, response_utils_1.generateErrorWhen)(response, code.toString());
521
+ errors.push({
522
+ TYPE: errorType,
523
+ WHEN: when,
524
+ });
525
+ }
526
+ }
527
+ return errors;
528
+ }
529
+ function extractOperations(collection, variables) {
530
+ const operations = [];
531
+ const operationNameCount = {};
532
+ function getUniqueOperationName(name) {
533
+ if (operationNameCount[name] === undefined) {
534
+ operationNameCount[name] = 1;
535
+ return name;
536
+ }
537
+ else {
538
+ operationNameCount[name] += 1;
539
+ return `${name} ${operationNameCount[name]}`;
540
+ }
541
+ }
542
+ function processItem(item, parentName = null) {
543
+ if (item.request) {
544
+ const method = item.request.method || 'GET';
545
+ const url = item.request.url;
546
+ const path = extractPathFromUrl(url, variables);
547
+ const itemName = item.name || 'unknown';
548
+ const immediateParentName = parentName || null;
549
+ // Generate operation ID (alias)
550
+ let operationId = itemName.toLowerCase().replace(/[^a-z0-9]/g, '-');
551
+ operationId = getUniqueOperationName(operationId);
552
+ const summary = generateSummary(item, method, path);
553
+ const { bodyType } = getContentTypeAndBodyType(item.request);
554
+ const headers = getHeadersForOperation(item.request, variables);
555
+ const inputs = extractParameters(item.request, variables);
556
+ const bodyInputs = extractRequestBody(item.request, itemName, method, path);
557
+ const returns = extractResponses(item, itemName, method, path);
558
+ const errors = extractErrors(item, itemName, method, path);
559
+ const allInputs = [...inputs];
560
+ if (bodyInputs.length > 0) {
561
+ allInputs.push(...bodyInputs);
562
+ }
563
+ // Build method in v2.0.1 format
564
+ const methodDef = {
565
+ SUMMARY: summary,
566
+ };
567
+ // Add DESC if description exists
568
+ const desc = getItemDescription(item);
569
+ if (desc) {
570
+ methodDef.DESC = desc;
571
+ }
572
+ // HTTP section (mandatory for API methods)
573
+ methodDef.HTTP = {
574
+ METHOD: method.toUpperCase(),
575
+ ENDPOINT: `/${path}`,
576
+ HEADERS: headers,
577
+ };
578
+ if (bodyType !== constants_1.BODYTYPE_RAW) {
579
+ methodDef.HTTP.BODYTYPE = bodyType;
580
+ }
581
+ // EXECUTION section (mandatory)
582
+ methodDef.EXECUTION = {
583
+ MODE: constants_1.EXECUTION_MODE_ASYNC, // HTTP methods default to async
584
+ };
585
+ // ASYNC section (required when MODE = async)
586
+ const resultType = returns.length > 0 ? returns[0].RETURNTYPE : constants_1.TYPE_VOID;
587
+ methodDef.ASYNC = {
588
+ RETURNS: constants_1.ASYNC_RETURNS_RESULT,
589
+ RESULT: {
590
+ TYPE: resultType,
591
+ },
592
+ };
593
+ // INPUTS section (optional)
594
+ if (allInputs.length > 0) {
595
+ methodDef.INPUTS = allInputs;
596
+ }
597
+ // RETURNS section (optional - omit for void)
598
+ if (returns.length > 0) {
599
+ methodDef.RETURNS = returns;
600
+ }
601
+ // ERRORS section (optional)
602
+ if (errors.length > 0) {
603
+ methodDef.ERRORS = errors;
604
+ }
605
+ operations.push(Object.assign({ name: operationId }, methodDef));
606
+ }
607
+ if (item.item) {
608
+ for (const subItem of item.item) {
609
+ processItem(subItem, item.name || parentName || null);
610
+ }
611
+ }
612
+ }
613
+ for (const item of collection.item) {
614
+ processItem(item, null);
615
+ }
616
+ return operations;
617
+ }
618
+ function extractBaseUrl(collection, variables) {
619
+ // First, try to get from collection variables (merged with passed variables)
620
+ const collectionVars = extractCollectionVariables(collection);
621
+ const allVariables = Object.assign(Object.assign({}, collectionVars), variables);
622
+ // Check for common base URL variable names
623
+ for (const varName of constants_1.BASE_URL_VARIABLE_NAMES) {
624
+ if (allVariables[varName]) {
625
+ let baseUrl = allVariables[varName];
626
+ // Remove trailing slash
627
+ baseUrl = baseUrl.replace(/\/$/, '');
628
+ // If it's a variable placeholder, skip it
629
+ if (!baseUrl.startsWith('{{')) {
630
+ return baseUrl;
631
+ }
632
+ }
633
+ }
634
+ // Try to extract from first request URL
635
+ function findFirstRequestUrl(item) {
636
+ var _a;
637
+ if ((_a = item.request) === null || _a === void 0 ? void 0 : _a.url) {
638
+ const url = item.request.url;
639
+ if (url.raw) {
640
+ // Extract base URL from raw URL
641
+ // Handle cases like "{{url}}/api/v1/endpoint" or "https://api.example.com/api/v1/endpoint"
642
+ let rawUrl = url.raw;
643
+ // Try to resolve variables first
644
+ rawUrl = resolveVariables(rawUrl, allVariables);
645
+ // Extract base URL (protocol + host)
646
+ const match = rawUrl.match(/^(https?:\/\/[^\/\s]+)/);
647
+ if (match) {
648
+ return match[1];
649
+ }
650
+ // If still has variables, try to extract from host array
651
+ if (url.host && Array.isArray(url.host) && url.host.length > 0) {
652
+ const host = url.host[0];
653
+ const resolvedHost = resolveVariables(host, allVariables);
654
+ // If host is resolved and not a variable placeholder
655
+ if (resolvedHost && !resolvedHost.startsWith('{{') && !resolvedHost.includes('{{')) {
656
+ const protocol = (url.protocol && !url.protocol.startsWith('{{'))
657
+ ? url.protocol.replace(':', '')
658
+ : 'https';
659
+ return `${protocol}://${resolvedHost}`;
660
+ }
661
+ }
662
+ }
663
+ }
664
+ if (item.item && Array.isArray(item.item)) {
665
+ for (const subItem of item.item) {
666
+ const found = findFirstRequestUrl(subItem);
667
+ if (found)
668
+ return found;
669
+ }
670
+ }
671
+ return null;
672
+ }
673
+ if (collection.item && Array.isArray(collection.item)) {
674
+ for (const item of collection.item) {
675
+ const baseUrl = findFirstRequestUrl(item);
676
+ if (baseUrl) {
677
+ return baseUrl.replace(/\/$/, '');
678
+ }
679
+ }
680
+ }
681
+ // Default fallback
682
+ return constants_1.DEFAULT_BASE_URL;
683
+ }
684
+ function generateWrekenfile(collection, variables) {
685
+ if (!collection || typeof collection !== 'object') {
686
+ throw new Error("Argument 'collection' is required and must be an object");
687
+ }
688
+ if (!variables || typeof variables !== 'object') {
689
+ throw new Error("Argument 'variables' is required and must be an object");
690
+ }
691
+ // Extract base URL from collection
692
+ const baseUrl = extractBaseUrl(collection, variables);
693
+ // Merge collection variables with passed variables
694
+ const collectionVars = extractCollectionVariables(collection);
695
+ const allVariables = Object.assign(Object.assign({}, collectionVars), variables);
696
+ const structs = extractStructs(collection, allVariables);
697
+ const operations = extractOperations(collection, allVariables);
698
+ const wrekenfile = {
699
+ VERSION: constants_1.WREKENFILE_VERSION,
700
+ };
701
+ // Add DEFAULTS if we have any
702
+ const defaults = {};
703
+ // Add base URL first
704
+ defaults.w_base_url = baseUrl;
705
+ // Add other variables
706
+ if (Object.keys(allVariables).length > 0) {
707
+ for (const [key, value] of Object.entries(allVariables)) {
708
+ // Skip base URL variables as we've already added w_base_url
709
+ if (constants_1.BASE_URL_VARIABLE_NAMES.includes(key)) {
710
+ continue;
711
+ }
712
+ const isSensitive = constants_1.SENSITIVE_KEYS.some(sensitiveKey => key.toLowerCase().includes(sensitiveKey));
713
+ if (isSensitive) {
714
+ defaults[key] = `{{${key}}}`;
715
+ }
716
+ else {
717
+ defaults[key] = value;
718
+ }
719
+ }
720
+ }
721
+ if (Object.keys(defaults).length > 0) {
722
+ wrekenfile.DEFAULTS = defaults;
723
+ }
724
+ // Add METHODS (mandatory)
725
+ const methods = {};
726
+ for (const operation of operations) {
727
+ const { name } = operation, methodDef = __rest(operation, ["name"]);
728
+ methods[name] = methodDef;
729
+ }
730
+ wrekenfile.METHODS = methods;
731
+ // Add STRUCTS if we have any
732
+ if (Object.keys(structs).length > 0) {
733
+ wrekenfile.STRUCTS = structs;
734
+ }
735
+ let yamlString = (0, js_yaml_1.dump)(wrekenfile, constants_1.YAML_DUMP_OPTIONS);
736
+ // Post-process to remove quotes from type strings
737
+ yamlString = (0, yaml_utils_1.removeTypeQuotes)(yamlString);
738
+ yamlString = (0, yaml_utils_1.cleanYaml)(yamlString);
739
+ (0, yaml_utils_1.checkYamlForHiddenChars)(yamlString);
740
+ (0, yaml_utils_1.validateYaml)(yamlString);
741
+ return yamlString;
742
+ }