rapidoc
Version:
RapiDoc - Open API spec viewer with built in console
127 lines (117 loc) • 4.48 kB
JavaScript
/**
* Normalizes header values by deduplicating comma-separated tokens (e.g. Accept headers).
*
* @param {string} value - Raw header value
* @returns {string} Deduplicated header value
*/
export function deduplicateHeaderValues(value) {
if (!value || typeof value !== "string") {
return value || "";
}
const seenValues = [];
return value
.split(",")
.map((val) => {
const trimmed = val.trim();
const normalizedValue = trimmed.toLowerCase();
if (seenValues.includes(normalizedValue)) {
return null;
}
seenValues.push(normalizedValue);
return trimmed;
})
.filter((val) => val !== null)
.join(", ");
}
/**
* Generates a clean, copyable cURL command string from request parameters.
* Pure utility decoupled from the DOM.
*
* @param {object} options
* @param {string} [options.method='GET'] - HTTP method (GET, POST, etc.)
* @param {string} options.url - Request URL
* @param {Headers|Map|Array<[string, string]>|object} [options.headers] - Request headers
* @param {URLSearchParams|FormData|File|string|object} [options.body] - Request body payload
* @param {string} [options.contentType=''] - Content type of the payload
* @param {Object<string, string>} [options.partContentTypes] - Content-Type of multipart parts, by field name
* @param {string} [options.baseLocation] - Optional base location to resolve relative URLs
* @returns {string} Formatted cURL snippet
*/
export function generateCurlCommand({
method = "GET",
url = "",
headers,
body,
contentType = "",
partContentTypes = {},
baseLocation = typeof location !== "undefined" ? location.href : "",
} = {}) {
let curlUrl = url;
if (!url.startsWith("http://") && !url.startsWith("https://") && baseLocation) {
try {
curlUrl = new URL(url, baseLocation).href;
} catch {
curlUrl = url;
}
}
let curl = `curl -X ${method.toUpperCase()} "${curlUrl}" \\\n`;
// Process headers into key-value pairs with deduplicated comma values
const headerEntries = [];
if (headers instanceof Headers || (headers && typeof headers.forEach === "function")) {
headers.forEach((value, key) => {
headerEntries.push([key, deduplicateHeaderValues(value)]);
});
} else if (Array.isArray(headers)) {
headers.forEach(([key, value]) => {
headerEntries.push([key, deduplicateHeaderValues(value)]);
});
} else if (headers && typeof headers === "object") {
Object.entries(headers).forEach(([key, value]) => {
headerEntries.push([key, deduplicateHeaderValues(String(value))]);
});
}
let curlHeaders = headerEntries.map(([key, value]) => ` -H '${key}: ${value}'`).join("\\\n");
if (curlHeaders) {
curlHeaders = `${curlHeaders} \\\n`;
}
let curlData = "";
let curlForm = "";
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {
curlData = ` -d ${body.toString()} \\\n`;
} else if (typeof File !== "undefined" && body instanceof File) {
curlData = ` --data-binary @${body.name} \\\n`;
} else if (typeof FormData !== "undefined" && body instanceof FormData) {
curlForm = Array.from(body)
.map(([key, value]) => {
const type = partContentTypes?.[key] ? `;type=${partContentTypes[key]}` : "";
if (typeof File !== "undefined" && value instanceof File) {
return ` -F "${key}=@${value.name}${value.type ? "" : type}"`;
}
const sanitizedVal =
typeof value === "string" ? value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') : value;
return ` -F "${key}=${sanitizedVal}${type}"`;
})
.join("\\\n");
if (curlForm) {
curlForm = `${curlForm} \\\n`;
}
} else if (body !== undefined && body !== null && body !== "") {
const rawBody = typeof body === "object" ? JSON.stringify(body) : String(body);
const isJson =
contentType.includes("json") ||
(rawBody.trim().startsWith("{") && rawBody.trim().endsWith("}"));
if (isJson) {
try {
const compactJson = JSON.stringify(JSON.parse(rawBody));
curlData = ` -d '${compactJson.replace(/'/g, "'\\''")}' \\\n`;
} catch {
// If JSON.parse fails, fall through to regular string escape
}
}
if (!curlData) {
curlData = ` -d '${rawBody.replace(/'/g, "'\"'\"'")}' \\\n`;
}
}
const result = `${curl}${curlHeaders}${curlData}${curlForm}`;
return result.endsWith(" \\\n") ? result.slice(0, -3) : result;
}