UNPKG

wrekenfile-converter

Version:

Convert OpenAPI and Postman specs into Wrekenfiles, with chunking for vector database storage

891 lines 37.8 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.generateWrekenfile = generateWrekenfile; exports.extractStructs = extractStructs; exports.extractOperations = extractOperations; exports.mapType = mapType; exports.parseJsonExample = parseJsonExample; exports.extractFieldsFromObject = extractFieldsFromObject; exports.loadEnvironmentFile = loadEnvironmentFile; exports.extractCollectionVariables = extractCollectionVariables; exports.resolveVariables = resolveVariables; // postman-to-wrekenfile.ts // Converts Postman collections to Wrekenfile v2.0.1 format const fs = __importStar(require("fs")); const yaml_utils_1 = require("./utils/yaml-utils"); const constants_1 = require("./utils/constants"); const response_utils_1 = require("./utils/response-utils"); const error_utils_1 = require("./utils/error-utils"); const canonical_id_1 = require("./utils/canonical-id"); const struct_utils_1 = require("./utils/struct-utils"); function mapType(value) { if (typeof value === 'string') { // Check for common patterns if (/^\d{4}-\d{2}-\d{2}/.test(value)) return 'DATE'; if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(value)) return 'STRING'; // UUID as string if (/^\d+$/.test(value)) return 'INT'; if (/^\d+\.\d+$/.test(value)) return 'FLOAT'; if (value === 'true' || value === 'false') return 'BOOL'; return 'STRING'; } if (typeof value === 'number') { return Number.isInteger(value) ? 'INT' : 'FLOAT'; } if (typeof value === 'boolean') return 'BOOL'; if (Array.isArray(value)) return 'ANY'; // Arrays will be handled specially if (value === null || value === undefined) return 'ANY'; return 'ANY'; } function getItemDescription(item) { var _a, _b, _c, _d, _e; 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; if (!description) return ''; // Postman can store description as an object with { content: string } if (typeof description === 'object' && typeof description.content === 'string') { description = description.content; } if (typeof description !== 'string') return ''; return description.replace(/<[^>]*>/g, '').replace(/\n+/g, ' ').trim(); } function generateSummary(item, method, path) { const cleaned = getItemDescription(item); if (cleaned) { // Use first sentence as summary const firstSentence = cleaned.split(/[.!?]\s/)[0]; return firstSentence || cleaned.substring(0, 100); } const verb = constants_1.SUMMARY_VERBS[method.toLowerCase()] || 'Call'; const entity = path.split('/').filter(p => p && !p.startsWith('{')).pop() || 'resource'; return `${verb} ${entity}`; } function generateStructName(_itemName, method, path, suffix) { // Use canonical ID as the semantic base for Postman-derived structs // (Request, ResponseXXX). This keeps struct names aligned with methods. const canonicalId = (0, canonical_id_1.computeCanonicalId)('api', method.toUpperCase(), path); return `${canonicalId}${suffix}`; } function parseJsonExample(jsonStr) { try { return JSON.parse(jsonStr); } catch (_a) { return null; } } function extractFieldsFromObject(obj, depth = 0, prefix = '') { if (depth > 3) return []; if (!obj) return []; // If the root object is an array, extract fields from the first object if (Array.isArray(obj) && obj.length > 0 && typeof obj[0] === 'object' && obj[0] !== null) { return extractFieldsFromObject(obj[0], depth + 1, prefix); } if (Array.isArray(obj)) return []; if (typeof obj !== 'object') return []; const fields = []; const keyCount = {}; for (const [key, value] of Object.entries(obj)) { let type = 'ANY'; let required = false; // Handle duplicate keys let fieldName = key; if (keyCount[key] === undefined) { keyCount[key] = 1; } else { keyCount[key] += 1; fieldName = `${key} ${keyCount[key]}`; } if (Array.isArray(value)) { if (value.length > 0) { const firstItem = value[0]; if (typeof firstItem === 'object' && firstItem !== null) { type = `[]STRUCT(${prefix}${fieldName}Item)`; } else { type = `[]${mapType(firstItem)}`; } } else { type = '[]ANY'; } } else if (typeof value === 'object' && value !== null) { type = `STRUCT(${prefix}${fieldName})`; } else { type = mapType(value); } fields.push({ name: fieldName, type, REQUIRED: required, }); } return fields; } function loadEnvironmentFile(envPath) { try { const envData = fs.readFileSync(envPath, 'utf8'); const env = JSON.parse(envData); const variables = {}; if (env.values) { for (const variable of env.values) { if (variable.key && variable.value) { variables[variable.key] = variable.value; } } } return variables; } catch (error) { return {}; } } function extractCollectionVariables(collection) { const variables = {}; // Extract collection-level variables if (collection.variable) { for (const variable of collection.variable) { if (variable.key && variable.value) { variables[variable.key] = variable.value; } } } return variables; } function resolveVariables(value, variables) { if (typeof value !== 'string') return value; // Replace {{variable}} patterns with actual values return value.replace(/\{\{([^}]+)\}\}/g, (match, varName) => { return variables[varName] || match; }); } function extractStructs(collection, variables) { const structs = {}; const structNameCount = {}; function getUniqueStructName(name) { if (structs[name] === undefined) { structNameCount[name] = 1; return name; } else { structNameCount[name] = (structNameCount[name] || 1) + 1; return `${name} ${structNameCount[name]}`; } } function processItem(item) { var _a; if (item.request) { const method = item.request.method || constants_1.HTTP_METHOD_GET; const url = item.request.url; const path = extractPathFromUrl(url, variables); const itemName = item.name || 'unknown'; // Extract request body structs if (((_a = item.request.body) === null || _a === void 0 ? void 0 : _a.mode) === 'raw' && item.request.body.raw) { const bodyData = parseJsonExample(item.request.body.raw); if (bodyData) { let requestStructName = generateStructName(itemName, method, path, 'Request'); requestStructName = getUniqueStructName(requestStructName); const fields = extractFieldsFromObject(bodyData, 0, requestStructName); if (fields.length > 0) { structs[requestStructName] = fields; } extractNestedStructs(bodyData, structs, requestStructName); } } // Extract response structs from examples if (item.response) { for (const response of item.response) { let responseStructName = generateStructName(itemName, method, path, `Response${response.code || '200'}`); responseStructName = getUniqueStructName(responseStructName); if (response.body) { const responseData = parseJsonExample(response.body); if (responseData) { const fields = extractFieldsFromObject(responseData, 0, responseStructName); if (fields.length > 0) { structs[responseStructName] = fields; } extractNestedStructs(responseData, structs, responseStructName); } } } } } if (item.item) { for (const subItem of item.item) { processItem(subItem); } } } for (const item of collection.item) { processItem(item); } return structs; } function extractNestedStructs(obj, structs, basePrefix = '') { if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return; for (const [key, value] of Object.entries(obj)) { if (Array.isArray(value) && value.length > 0) { const firstItem = value[0]; if (typeof firstItem === 'object' && firstItem !== null) { const structName = `${basePrefix}${key}Item`; const fields = extractFieldsFromObject(firstItem, 0, structName); if (fields.length > 0) { structs[structName] = fields; } // For deeper levels, keep using the same base prefix to avoid runaway name growth extractNestedStructs(firstItem, structs, basePrefix); } } else if (typeof value === 'object' && value !== null) { const structName = `${basePrefix}${key}`; const fields = extractFieldsFromObject(value, 0, structName); if (fields.length > 0) { structs[structName] = fields; } // For deeper levels, keep using the same base prefix extractNestedStructs(value, structs, basePrefix); } } } function extractPathFromUrl(url, _variables) { if (url === null || url === void 0 ? void 0 : url.raw) { // Remove base URL and protocol let path = url.raw; path = path.replace(/^https?:\/\/[^\/]+/, ''); // Remove protocol and host // Remove base URL variables like {{url}} from path (they belong in base URL) path = path.replace(/\{\{url\}\}/gi, ''); // Strip query string if present path = path.split('?')[0]; // Convert Postman path variables {{var}} to OpenAPI-style {var} path = path.replace(/\{\{([^}]+)\}\}/g, '{$1}'); path = path.replace(/\/+/g, '/'); // Normalize slashes path = path.replace(/^\/|\/$/g, ''); // Remove leading/trailing slashes return path; } if (url === null || url === void 0 ? void 0 : url.path) { const pathSegments = url.path .filter((segment) => { // Filter out base URL variables like {{url}} return !segment.match(/^\{\{url\}\}$/i); }) .map((segment) => { // Convert Postman variables {{var}} to OpenAPI-style {var} return segment.replace(/\{\{([^}]+)\}\}/g, '{$1}'); }); return pathSegments.join('/'); } return ''; } function getContentTypeAndBodyType(request) { const headers = request.header || []; const contentTypeHeader = headers.find((h) => { var _a; return ((_a = h.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === constants_1.HEADER_CONTENT_TYPE.toLowerCase(); }); let contentType = constants_1.CONTENT_TYPE_JSON; if (contentTypeHeader) { contentType = contentTypeHeader.value || constants_1.CONTENT_TYPE_JSON; } let bodyType = constants_1.BODYTYPE_RAW; if (contentType === constants_1.CONTENT_TYPE_FORM_DATA) { bodyType = 'form-data'; } else if (contentType === constants_1.CONTENT_TYPE_URLENCODED) { bodyType = 'x-www-form-urlencoded'; } return { contentType, bodyType }; } function getAcceptContentType(item) { var _a; // Get the first content type from the first success response (2xx) if (item.response) { for (const response of item.response) { const code = parseInt(((_a = response.code) === null || _a === void 0 ? void 0 : _a.toString()) || '200'); if (code >= 200 && code < 300) { // Check Content-Type header in response if (response.header) { const acceptHeader = response.header.find((h) => { var _a; return ((_a = h.key) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === 'content-type'; }); if (acceptHeader === null || acceptHeader === void 0 ? void 0 : acceptHeader.value) { return acceptHeader.value; } } } } } // Default to JSON if no response content type found return constants_1.CONTENT_TYPE_JSON; } function getHeadersForOperation(request, variables) { var _a; const { contentType } = getContentTypeAndBodyType(request); const headerMap = new Map(); // Add Content-Type header for POST/PUT/PATCH requests if (constants_1.HTTP_METHODS_WITH_BODY.includes(((_a = request.method) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || '')) { headerMap.set(constants_1.HEADER_CONTENT_TYPE, contentType); } // Add authentication headers const authHeaders = request.header || []; for (const header of authHeaders) { if (header.key && header.value) { const key = header.key.toLowerCase(); if (key === constants_1.AUTH_HEADER_X_API_KEY || key === constants_1.AUTH_HEADER_AUTHORIZATION || key === constants_1.AUTH_HEADER_X_SIGNATURE) { let value = resolveVariables(header.value, variables); if (key === constants_1.AUTH_HEADER_X_API_KEY) value = constants_1.AUTH_API_KEY; else if (key === constants_1.AUTH_HEADER_AUTHORIZATION) value = constants_1.AUTH_BEARER_TOKEN; else if (key === constants_1.AUTH_HEADER_X_SIGNATURE) value = constants_1.AUTH_SIGNATURE; headerMap.set(header.key, value); } } } // Convert Map to object const headers = {}; for (const [key, value] of headerMap.entries()) { headers[key] = value; } return headers; } function extractParameters(request, _variables) { var _a; const inputParams = []; // v2.0.2: All parameters (path, query, header) must be in INPUTS with LOCATION // Path variables are also in ENDPOINT (e.g., /users/{userId}) // Header parameters are also in HTTP.HEADERS const url = request.url; // Extract path variables from URL if ((url === null || url === void 0 ? void 0 : url.raw) || (url === null || url === void 0 ? void 0 : url.path)) { const urlStr = url.raw || (Array.isArray(url.path) ? url.path.join('/') : url.path || ''); const pathMatches = urlStr.match(/\{\{(\w+)\}\}/g) || []; for (const match of pathMatches) { const varName = match.replace(/\{\{|\}\}/g, ''); const inputParam = {}; inputParam[varName] = { TYPE: 'STRING', LOCATION: 'path', }; inputParams.push(inputParam); } } // Extract query parameters if (url === null || url === void 0 ? void 0 : url.query) { for (const query of url.query) { // Skip disabled query parameters if (query.disabled) { continue; } const isRequired = !query.disabled; const inputParam = {}; // v2.0.2: All INPUTS must have LOCATION field if (isRequired) { // Simple form with LOCATION inputParam[query.key] = { TYPE: 'STRING', LOCATION: 'query', }; } else { // Extended form with LOCATION inputParam[query.key] = { TYPE: 'STRING', REQUIRED: false, LOCATION: 'query', }; } inputParams.push(inputParam); } } // Extract header parameters (non-auth headers that should be in INPUTS) if (request.header) { for (const header of request.header) { // Skip disabled headers if (header.disabled) { continue; } // Skip Content-Type and Authorization - they're in HTTP.HEADERS const headerKey = (_a = header.key) === null || _a === void 0 ? void 0 : _a.toLowerCase(); if (headerKey === 'content-type' || headerKey === 'authorization') { continue; } const isRequired = !header.disabled; const inputParam = {}; // v2.0.2: All INPUTS must have LOCATION field if (isRequired) { inputParam[header.key] = { TYPE: 'STRING', LOCATION: 'header', }; } else { inputParam[header.key] = { TYPE: 'STRING', REQUIRED: false, LOCATION: 'header', }; } inputParams.push(inputParam); } } return inputParams; } function extractRequestBody(request, itemName, method, path) { var _a, _b, _c; const inputParams = []; if (((_a = request.body) === null || _a === void 0 ? void 0 : _a.mode) === 'raw' && request.body.raw) { const bodyData = parseJsonExample(request.body.raw); if (bodyData) { const requestStructName = generateStructName(itemName, method, path, 'Request'); const inputParam = {}; // v2.0.2: All INPUTS must have LOCATION field inputParam.body = { TYPE: `STRUCT(${requestStructName})`, REQUIRED: true, LOCATION: 'body', }; inputParams.push(inputParam); } } // Handle form-data and urlencoded 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') { const formData = request.body.formdata || request.body.urlencoded || []; for (const field of formData) { const type = field.type === 'file' ? 'STRING' : 'STRING'; const isRequired = !field.disabled; const inputParam = {}; // v2.0.2: All INPUTS must have LOCATION field if (isRequired) { inputParam[field.key] = { TYPE: type, LOCATION: 'body', }; } else { inputParam[field.key] = { TYPE: type, REQUIRED: false, LOCATION: 'body', }; } inputParams.push(inputParam); } } return inputParams; } function extractResponses(item, itemName, method, path) { var _a; const returns = []; const seenCodes = new Set(); if (item.response) { for (const response of item.response) { const code = ((_a = response.code) === null || _a === void 0 ? void 0 : _a.toString()) || '200'; const statusCode = parseInt(code); // Only include success responses (2xx) in RETURNS section // Error responses go in ERRORS section if (isNaN(statusCode) || statusCode < 200 || statusCode >= 300) { continue; } // Avoid duplicate response codes if (seenCodes.has(code)) continue; seenCodes.add(code); // Skip 204 No Content if (code === '204') continue; let returnType = 'ANY'; if (response.body) { const responseData = parseJsonExample(response.body); if (responseData) { const responseStructName = generateStructName(itemName, method, path, `Response${code}`); returnType = `STRUCT(${responseStructName})`; } } // Only add if there's actually a return type if (returnType !== constants_1.TYPE_VOID) { // Generate descriptive RETURNVAR name based on response code and operation // Clean itemName: replace spaces and special chars with underscores, convert to lowercase const cleanItemName = itemName .replace(/[^a-zA-Z0-9]/g, '_') .replace(/_+/g, '_') .replace(/^_|_$/g, '') .toLowerCase(); const returnVarName = (0, response_utils_1.generateReturnVarName)(cleanItemName, code); // v2.0.2: STATUS code is required in RETURNS returns.push({ RETURNTYPE: returnType, RETURNVAR: returnVarName, STATUS: statusCode, }); } } } return returns; } function extractErrors(item, _itemName, _method, _path) { var _a; const errors = []; if (item.response) { for (const response of item.response) { const code = parseInt(((_a = response.code) === null || _a === void 0 ? void 0 : _a.toString()) || '200'); if (isNaN(code) || code < 400) continue; let errorType = 'ANY'; let when = `HTTP ${code}`; if (response.body) { const responseData = parseJsonExample(response.body); if (responseData) { const errorStructName = `Error${code}`; errorType = `STRUCT(${errorStructName})`; } } when = (0, response_utils_1.generateErrorWhen)(response, code.toString()); // v2.0.2: STATUS code is required in ERRORS errors.push({ TYPE: errorType, STATUS: code, WHEN: when, }); } } return errors; } function extractOperations(collection, variables) { const operations = []; const operationNameCount = {}; function getUniqueOperationName(name) { if (operationNameCount[name] === undefined) { operationNameCount[name] = 1; return name; } else { operationNameCount[name] += 1; return `${name} ${operationNameCount[name]}`; } } function processItem(item, parentName = null) { if (item.request) { const method = item.request.method || constants_1.HTTP_METHOD_GET; const url = item.request.url; const path = extractPathFromUrl(url, variables); const itemName = item.name || 'unknown'; // Generate operation ID (alias) let operationId = itemName.toLowerCase().replace(/[^a-z0-9]/g, '-'); operationId = getUniqueOperationName(operationId); const summary = generateSummary(item, method, path); const { contentType, bodyType } = getContentTypeAndBodyType(item.request); const headers = getHeadersForOperation(item.request, variables); const inputs = extractParameters(item.request, variables); const bodyInputs = extractRequestBody(item.request, itemName, method, path); const returns = extractResponses(item, itemName, method, path); const errors = extractErrors(item, itemName, method, path); const allInputs = [...inputs]; if (bodyInputs.length > 0) { allInputs.push(...bodyInputs); } // Build method in v2.0.2 format const methodDef = { SUMMARY: summary, }; // Add DESC if description exists const desc = getItemDescription(item); if (desc) { methodDef.DESC = desc; } // Get accept content type from responses const acceptContentType = getAcceptContentType(item); // HTTP section (mandatory for API methods) methodDef.HTTP = { METHOD: method.toUpperCase(), ENDPOINT: `/${path}`, HEADERS: headers, CONTENT_TYPE: contentType, ACCEPT: acceptContentType, }; // v2.0.2: BODY.TYPE should be STRUCT(...) format if (bodyInputs.length > 0 && bodyInputs[0].body) { const bodyTypeValue = bodyInputs[0].body.TYPE || bodyInputs[0].body; methodDef.HTTP.BODY = { TYPE: bodyTypeValue, }; } if (bodyType !== constants_1.BODYTYPE_RAW) { methodDef.HTTP.BODYTYPE = bodyType; } // EXECUTION section (mandatory) - v2.0.2 requires KIND methodDef.EXECUTION = { KIND: 'http', MODE: constants_1.EXECUTION_MODE_SYNC, // REST APIs are synchronous request/response }; // INPUTS section (optional) if (allInputs.length > 0) { methodDef.INPUTS = allInputs; } // RETURNS section (optional - omit for void) if (returns.length > 0) { methodDef.RETURNS = returns; } // ERRORS section (optional) if (errors.length > 0) { methodDef.ERRORS = errors; } operations.push(Object.assign({ name: operationId }, methodDef)); } if (item.item) { for (const subItem of item.item) { processItem(subItem, item.name || parentName || null); } } } for (const item of collection.item) { processItem(item, null); } return operations; } function extractBaseUrl(collection, variables) { // First, try to get from collection variables (merged with passed variables) const collectionVars = extractCollectionVariables(collection); const allVariables = Object.assign(Object.assign({}, collectionVars), variables); // Check for common base URL variable names for (const varName of constants_1.BASE_URL_VARIABLE_NAMES) { if (allVariables[varName]) { let baseUrl = allVariables[varName]; // Remove trailing slash baseUrl = baseUrl.replace(/\/$/, ''); // If it's a variable placeholder, skip it if (!baseUrl.startsWith('{{')) { return baseUrl; } } } // Try to extract from first request URL function findFirstRequestUrl(item) { var _a; if ((_a = item.request) === null || _a === void 0 ? void 0 : _a.url) { const url = item.request.url; if (url.raw) { // Extract base URL from raw URL // Handle cases like "{{url}}/api/v1/endpoint" or "https://api.example.com/api/v1/endpoint" let rawUrl = url.raw; // Try to resolve variables first rawUrl = resolveVariables(rawUrl, allVariables); // Extract base URL (protocol + host) const match = rawUrl.match(/^(https?:\/\/[^\/\s]+)/); if (match) { return match[1]; } // If still has variables, try to extract from host array if (url.host && Array.isArray(url.host) && url.host.length > 0) { const host = url.host[0]; const resolvedHost = resolveVariables(host, allVariables); // If host is resolved and not a variable placeholder if (resolvedHost && !resolvedHost.startsWith('{{') && !resolvedHost.includes('{{')) { const protocol = (url.protocol && !url.protocol.startsWith('{{')) ? url.protocol.replace(':', '') : 'https'; return `${protocol}://${resolvedHost}`; } } } } if (item.item && Array.isArray(item.item)) { for (const subItem of item.item) { const found = findFirstRequestUrl(subItem); if (found) return found; } } return null; } if (collection.item && Array.isArray(collection.item)) { for (const item of collection.item) { const baseUrl = findFirstRequestUrl(item); if (baseUrl) { return baseUrl.replace(/\/$/, ''); } } } // Default fallback return constants_1.DEFAULT_BASE_URL; } function generateWrekenfile(collection, variables) { var _a, _b, _c, _d, _e; try { // Validate inputs (0, error_utils_1.validatePostmanCollection)(collection); if (!variables || typeof variables !== 'object') { throw (0, error_utils_1.createConverterError)("Argument 'variables' is required and must be an object", "INVALID_VARIABLES", { variablesType: typeof variables }); } // Extract base URL from collection const baseUrl = extractBaseUrl(collection, variables); // Merge collection variables with passed variables const collectionVars = extractCollectionVariables(collection); const allVariables = Object.assign(Object.assign({}, collectionVars), variables); const structs = extractStructs(collection, allVariables); const operations = extractOperations(collection, allVariables); const wrekenfile = { VERSION: constants_1.WREKENFILE_VERSION, }; // Add DEFAULTS if we have any const defaults = {}; // Add base URL first defaults.w_base_url = baseUrl; // Add other variables if (Object.keys(allVariables).length > 0) { for (const [key, value] of Object.entries(allVariables)) { // Skip base URL variables as we've already added w_base_url if (constants_1.BASE_URL_VARIABLE_NAMES.includes(key)) { continue; } const isSensitive = constants_1.SENSITIVE_KEYS.some(sensitiveKey => key.toLowerCase().includes(sensitiveKey)); if (isSensitive) { defaults[key] = `{{${key}}}`; } else { // Ensure value is a string for DEFAULTS section if (value !== undefined && value !== null) { defaults[key] = String(value); } } } } if (Object.keys(defaults).length > 0) { wrekenfile.DEFAULTS = defaults; } // Add METHODS (mandatory) const methods = {}; for (const operation of operations) { const { name } = operation, methodDef = __rest(operation, ["name"]); methods[name] = methodDef; } // Resolve canonical IDs for all methods const canonicalInputs = Object.entries(methods).map(([methodId, methodData]) => { var _a, _b; return ({ methodId, httpMethod: (_a = methodData.HTTP) === null || _a === void 0 ? void 0 : _a.METHOD, endpoint: (_b = methodData.HTTP) === null || _b === void 0 ? void 0 : _b.ENDPOINT, existingCanonicalId: methodData.CANONICAL_ID, }); }); const libraryName = ((_a = collection === null || collection === void 0 ? void 0 : collection.info) === null || _a === void 0 ? void 0 : _a.name) || 'unknown'; const canonicalIdMap = (0, canonical_id_1.resolveCanonicalIds)(canonicalInputs, libraryName); // Add CANONICAL_ID to each method for (const [methodId, methodData] of Object.entries(methods)) { const canonicalId = canonicalIdMap.get(methodId); if (canonicalId) { methodData.CANONICAL_ID = canonicalId; } } // Update RETURNVARs to be derived from CANONICAL_ID for (const methodData of Object.values(methods)) { const canonicalId = methodData.CANONICAL_ID; if (!canonicalId || !Array.isArray(methodData.RETURNS)) continue; const baseVar = canonicalId.replace(/\./g, '_'); for (const ret of methodData.RETURNS) { const status = ret.STATUS; if (status === 200 || status === '200') { ret.RETURNVAR = baseVar; } else if (status !== undefined && status !== null) { ret.RETURNVAR = `${baseVar}_${status}`; } else { ret.RETURNVAR = baseVar; } } } // Use CANONICAL_ID as key when available const renamedMethods = {}; for (const [oldId, methodData] of Object.entries(methods)) { const canonicalId = methodData.CANONICAL_ID; const key = canonicalId || oldId; renamedMethods[key] = methodData; } wrekenfile.METHODS = renamedMethods; // Add STRUCTS if we have any if (Object.keys(structs).length > 0) { wrekenfile.STRUCTS = structs; } // Remove unused STRUCTS (keep only those referenced by METHODS) (0, struct_utils_1.filterStructsByUsage)(wrekenfile); // Generate YAML string using the standard pipeline return (0, yaml_utils_1.generateYamlString)(wrekenfile); } catch (err) { // Log error with context (0, error_utils_1.logError)(err, { converter: 'postman-to-wrekenfile', collectionName: ((_b = collection === null || collection === void 0 ? void 0 : collection.info) === null || _b === void 0 ? void 0 : _b.name) || 'unknown', collectionSchema: ((_c = collection === null || collection === void 0 ? void 0 : collection.info) === null || _c === void 0 ? void 0 : _c.schema) || 'unknown' }); // Re-throw with additional context if it's not already a ConverterError if (err.code && (err.code.startsWith('INVALID_') || err.code.startsWith('MISSING_') || err.code.startsWith('EMPTY_'))) { throw err; } throw (0, error_utils_1.createConverterError)(`Failed to generate Wrekenfile from Postman collection: ${err.message}`, "GENERATION_FAILED", { converter: 'postman-to-wrekenfile', collectionName: ((_d = collection === null || collection === void 0 ? void 0 : collection.info) === null || _d === void 0 ? void 0 : _d.name) || 'unknown', collectionSchema: ((_e = collection === null || collection === void 0 ? void 0 : collection.info) === null || _e === void 0 ? void 0 : _e.schema) || 'unknown' }, err); } } //# sourceMappingURL=postman-to-wrekenfile.js.map