| import { addQueryParameters } from "./util/add-query-parameters"; | |
| import { extractUrlVariableNames } from "./util/extract-url-variable-names"; | |
| import { omit } from "./util/omit"; | |
| import { parseUrl } from "./util/url-template"; | |
| 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 = parseUrl(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 isBinaryRequest = /application\/octet-stream/i.test(headers.accept); | |
| if (!isBinaryRequest) { | |
| 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); | |
| } |