UNPKG

openapi-to-postmanv2

Version:

Convert a given OpenAPI specification to Postman Collection v2.0

127 lines 5.47 kB
"use strict"; /** * General utility functions shared across SpecificationCollection modules */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.getRequestIdentifier = getRequestIdentifier; exports.stripVendorExtensions = stripVendorExtensions; exports.isRef = isRef; exports.isEqualAfterIgnoringVendorExtensions = isEqualAfterIgnoringVendorExtensions; exports.deepMergeWithVendorExtensions = deepMergeWithVendorExtensions; const lodash_1 = __importDefault(require("lodash")); /** * Get the request identifier (method + path) for an item. * @param {Item} item - The item to get the identifier for. * @returns {string} The request identifier (method + path) */ function getRequestIdentifier(item) { // @ts-expect-error - Suppress type-checking for .getPath() as its type validations are defined incorrectly // and gives boolean assignment error // Correct usage can be found: https://www.postmanlabs.com/postman-collection/Url.html#getPath // Tracking the fix https://postmanlabs.atlassian.net/browse/AB-610 return item.request.method + item.request.url.getPath(true); } /** * Recursively clones a fragment of the specification while removing any * vendor-extension keys (those starting with "x-") and the OpenAPI `default` key. * This is used solely for equality comparisons so that differences due to `default` and vendor extensions * do not cause `$ref` expansion or unnecessary diffs. * * @param {unknown} node - The fragment (object/array/primitive) from which keys should be stripped. * @returns {unknown} A deep clone of the fragment with all `x-*` and `default` keys removed. * Primitive values are returned unchanged. */ function stripVendorExtensions(node) { if (!node || typeof node !== 'object') { return node; } if (Array.isArray(node)) { return node.map(stripVendorExtensions); } const result = {}; Object.entries(node).forEach(([k, v]) => { if (!k.startsWith('x-') && k !== 'default') { result[k] = stripVendorExtensions(v); } }); return result; } /** * Checks if an object contains a $ref property. * @param {unknown} obj The object to check. * @returns {boolean} True if the object contains a $ref property at the top level, otherwise false. */ function isRef(obj) { return Boolean(obj) && typeof obj === 'object' && obj !== null && Object.hasOwn(obj, '$ref'); } /** * Determines whether two fragments are deeply equal after removing all * vendor-extensions (`x-*` keys). * * @param {unknown} firstFragment - First fragment to compare. * @param {unknown} secondFragment - Second fragment to compare. * @returns {boolean} `true` if the fragments are equal once vendor extensions are ignored, otherwise `false`. */ function isEqualAfterIgnoringVendorExtensions(firstFragment, secondFragment) { return lodash_1.default.isEqual(stripVendorExtensions(firstFragment), stripVendorExtensions(secondFragment)); } /** * Deep merge function that preserves vendor extensions at all levels * and ignores the `default` key from `latest` as per the rules: * - If `current` has a `default`, it is preserved. * - If `current` does not have `default`, it is removed from the merged result even if present in `latest`. * @param {unknown} latest - The latest object (source of truth for standard properties) * @param {unknown} current - The current object (source for vendor extensions) * @returns {unknown} Merged object with vendor extensions preserved at all levels */ function deepMergeWithVendorExtensions(latest, current) { if (!latest || typeof latest !== 'object') { return latest; } if (!current || typeof current !== 'object') { return latest; } if (Array.isArray(latest)) { if (!Array.isArray(current)) { return latest; } const result = [...latest]; for (let i = 0; i < Math.max(latest.length, current.length); i++) { if (i < latest.length && i < current.length) { result[i] = deepMergeWithVendorExtensions(latest[i], current[i]); } } return result; } if (Array.isArray(current)) { return latest; } const latestObj = latest, currentObj = current, result = { ...latestObj }; Object.keys(currentObj).forEach((key) => { if (key.startsWith('x-')) { result[key] = currentObj[key]; } else if (latestObj[key] && currentObj[key]) { result[key] = deepMergeWithVendorExtensions(latestObj[key], currentObj[key]); } }); // default handling rules: // - If both have `default`, take it from latest (even if unequal) // - If only latest has `default`, remove it (ignore introduction from latest) // - If only current has `default`, keep it (propagate from current) const hasCurrentDefault = Object.hasOwn(currentObj, 'default'), hasLatestDefault = Object.hasOwn(latestObj, 'default'); if (hasCurrentDefault && hasLatestDefault) { result.default = latestObj.default; } else if (!hasCurrentDefault && hasLatestDefault) { delete result.default; } else if (hasCurrentDefault && !hasLatestDefault) { result.default = currentObj.default; } return result; } //# sourceMappingURL=utils.js.map