openapi-to-postmanv2
Version:
Convert a given OpenAPI specification to Postman Collection v2.0
110 lines • 6.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.mergeResponseData = mergeResponseData;
const BodyMerger_1 = require("./BodyMerger");
const HeaderMerger_1 = require("./HeaderMerger");
const RequestMerger_1 = require("./RequestMerger");
const header_1 = require("../header");
/**
* Preserve an existing saved response's header PARAMETER values while keeping any
* implicit/generated headers (e.g. Content-Type, Accept) produced from the spec. Used when
* preserving a non-first response's originalRequest on multi-example sync: for a shared key the
* spec-generated header metadata (name casing, description, schema-derived flags) is kept and only
* the existing header's `value`/`disabled` are copied over; generated target-only headers are
* retained, and header params that only exist on the source are appended.
*
* Header keys are matched case-insensitively (HTTP header names are case-insensitive).
* @param {HeaderDefinition[] | undefined} targetHeaders - Spec-generated headers (base)
* @param {HeaderDefinition[] | undefined} sourceHeaders - Existing saved response headers to preserve
* @returns {HeaderDefinition[] | undefined} Merged header list
*/
function preserveHeaderParams(targetHeaders, sourceHeaders) {
if (!Array.isArray(sourceHeaders)) {
return targetHeaders;
}
const result = Array.isArray(targetHeaders) ? [...targetHeaders] : [], indexByLowerKey = new Map();
result.forEach((header, index) => {
if (typeof header?.key === 'string') {
indexByLowerKey.set(header.key.toLowerCase(), index);
}
});
sourceHeaders.forEach((sourceHeader) => {
if (typeof sourceHeader?.key !== 'string') {
return;
}
const lowerKey = sourceHeader.key.toLowerCase();
if (indexByLowerKey.has(lowerKey)) {
// Keep the spec-generated header (name casing + metadata); copy only the existing header's
// value/disabled state onto it.
const index = indexByLowerKey.get(lowerKey);
result[index] = { ...result[index], value: sourceHeader.value, disabled: sourceHeader.disabled };
}
else {
indexByLowerKey.set(lowerKey, result.length);
result.push(sourceHeader);
}
});
return result;
}
/**
* Merges a single response from target with a corresponding response from current.
* Returns the merged response definition.
* @param {Response} targetResponse - Response from the target request
* @param {Response } sourceResponse - Response from the source request
* @param {SyncOptions} syncOptions - Options to control what should be synced
* @param {boolean} preserveOriginalRequest - When true (and example syncing is enabled), keep the
* existing response's `originalRequest` request-side data (body, url query/path variables and
* headers) instead of overwriting it with the spec's request. The spec carries a single live
* request (body + parameter values) that maps to the first saved response; set this for every
* response after the first so a request/parameter change in the spec doesn't overwrite every
* response's originalRequest. Defaults to false (first response takes the spec request).
* @returns {ResponseDefinition} Merged response definition
*/
function mergeResponseData(targetResponse, sourceResponse, syncOptions, preserveOriginalRequest = false) {
const targetRes = targetResponse.toJSON(), sourceRes = sourceResponse.toJSON(), shouldSyncExamples = syncOptions?.syncExamples;
if (targetRes?.originalRequest && sourceRes?.originalRequest) {
targetRes.originalRequest = (0, RequestMerger_1.mergeRequestData)(targetRes.originalRequest, sourceRes.originalRequest, syncOptions);
/*
* The spec carries a single live request (its body plus the primary parameter values), which
* maps to the first saved response. For the remaining responses, preserve their existing
* request-side data — body, url (query params + path variables) and headers — so that editing
* the request or a parameter in the spec doesn't overwrite every response's originalRequest on
* sync-back. Each component is deleted when the source had none, mirroring the body rule.
* Only applies when example syncing is enabled (the multi-example flow).
*/
if (preserveOriginalRequest && shouldSyncExamples) {
// Cast for the delete-when-source-had-none branches (url/body are not always optional in the type).
const targetOriginalRequest = targetRes.originalRequest;
// Body: preserve the existing example's body wholesale (delete when the source had none).
if (sourceRes.originalRequest.body === undefined) {
delete targetOriginalRequest.body;
}
else {
targetRes.originalRequest.body = sourceRes.originalRequest.body;
}
// URL: preserve the existing example's url (query params + path variable values) wholesale.
if (sourceRes.originalRequest.url === undefined) {
delete targetOriginalRequest.url;
}
else {
targetRes.originalRequest.url = sourceRes.originalRequest.url;
}
// Headers: preserve the existing example's header PARAMETER values while keeping any
// implicit/generated headers (e.g. Content-Type, Accept) the spec produced.
targetRes.originalRequest.header = preserveHeaderParams(targetRes.originalRequest.header, sourceRes.originalRequest.header);
}
}
// Attach implicit headers from the source response to the target response
// if they are not present in the target response
// Required because the response body and implicit headers are not generated
// during collection to spec conversion for non json responses.
(0, header_1.attachImplicitHeaders)(sourceRes.header, targetRes.header);
if (targetRes?.header) {
targetRes.header = shouldSyncExamples ?
targetRes.header :
(0, HeaderMerger_1.mergeRequestAndResponseHeaders)(targetRes.header, sourceRes.header);
}
targetRes.body = shouldSyncExamples ? targetRes.body : (0, BodyMerger_1.mergeRequestAndResponseBodyRaw)(targetRes.body, sourceRes.body);
return targetRes;
}
//# sourceMappingURL=ResponseMerger.js.map