82 lines
3.4 KiB
JavaScript
82 lines
3.4 KiB
JavaScript
|
import urlTemplate from "url-template";
|
||
|
import { addQueryParameters } from "./util/add-query-parameters";
|
||
|
import { extractUrlVariableNames } from "./util/extract-url-variable-names";
|
||
|
import { omit } from "./util/omit";
|
||
|
export function parse(options) {
|
||
|
// https://fetch.spec.whatwg.org/#methods
|
||
|
let method = options.method.toUpperCase();
|
||
|
// replace :varname with {varname} to make it RFC 6570 compatible
|
||
|
let url = options.url.replace(/:([a-z]\w+)/g, "{+$1}");
|
||
|
let headers = Object.assign({}, options.headers);
|
||
|
let body;
|
||
|
let parameters = omit(options, [
|
||
|
"method",
|
||
|
"baseUrl",
|
||
|
"url",
|
||
|
"headers",
|
||
|
"request",
|
||
|
"mediaType"
|
||
|
]);
|
||
|
// extract variable names from URL to calculate remaining variables later
|
||
|
const urlVariableNames = extractUrlVariableNames(url);
|
||
|
url = urlTemplate.parse(url).expand(parameters);
|
||
|
if (!/^http/.test(url)) {
|
||
|
url = options.baseUrl + url;
|
||
|
}
|
||
|
const omittedParameters = Object.keys(options)
|
||
|
.filter(option => urlVariableNames.includes(option))
|
||
|
.concat("baseUrl");
|
||
|
const remainingParameters = omit(parameters, omittedParameters);
|
||
|
const isBinaryRequset = /application\/octet-stream/i.test(headers.accept);
|
||
|
if (!isBinaryRequset) {
|
||
|
if (options.mediaType.format) {
|
||
|
// e.g. application/vnd.github.v3+json => application/vnd.github.v3.raw
|
||
|
headers.accept = headers.accept
|
||
|
.split(/,/)
|
||
|
.map(preview => preview.replace(/application\/vnd(\.\w+)(\.v3)?(\.\w+)?(\+json)?$/, `application/vnd$1$2.${options.mediaType.format}`))
|
||
|
.join(",");
|
||
|
}
|
||
|
if (options.mediaType.previews.length) {
|
||
|
const previewsFromAcceptHeader = headers.accept.match(/[\w-]+(?=-preview)/g) || [];
|
||
|
headers.accept = previewsFromAcceptHeader
|
||
|
.concat(options.mediaType.previews)
|
||
|
.map(preview => {
|
||
|
const format = options.mediaType.format
|
||
|
? `.${options.mediaType.format}`
|
||
|
: "+json";
|
||
|
return `application/vnd.github.${preview}-preview${format}`;
|
||
|
})
|
||
|
.join(",");
|
||
|
}
|
||
|
}
|
||
|
// for GET/HEAD requests, set URL query parameters from remaining parameters
|
||
|
// for PATCH/POST/PUT/DELETE requests, set request body from remaining parameters
|
||
|
if (["GET", "HEAD"].includes(method)) {
|
||
|
url = addQueryParameters(url, remainingParameters);
|
||
|
}
|
||
|
else {
|
||
|
if ("data" in remainingParameters) {
|
||
|
body = remainingParameters.data;
|
||
|
}
|
||
|
else {
|
||
|
if (Object.keys(remainingParameters).length) {
|
||
|
body = remainingParameters;
|
||
|
}
|
||
|
else {
|
||
|
headers["content-length"] = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
// default content-type for JSON if body is set
|
||
|
if (!headers["content-type"] && typeof body !== "undefined") {
|
||
|
headers["content-type"] = "application/json; charset=utf-8";
|
||
|
}
|
||
|
// GitHub expects 'content-length: 0' header for PUT/PATCH requests without body.
|
||
|
// fetch does not allow to set `content-length` header, but we can set body to an empty string
|
||
|
if (["PATCH", "PUT"].includes(method) && typeof body === "undefined") {
|
||
|
body = "";
|
||
|
}
|
||
|
// Only return body/request keys if present
|
||
|
return Object.assign({ method, url, headers }, typeof body !== "undefined" ? { body } : null, options.request ? { request: options.request } : null);
|
||
|
}
|