Files
hoppscotch/packages/hoppscotch-app/helpers/curl/curlparser.ts
2022-05-27 14:48:33 +05:30

180 lines
5.1 KiB
TypeScript

import parser from "yargs-parser"
import * as O from "fp-ts/Option"
import * as A from "fp-ts/Array"
import { pipe, flow } from "fp-ts/function"
import {
FormDataKeyValue,
HoppRESTReqBody,
makeRESTRequest,
} from "@hoppscotch/data"
import { getAuthObject } from "./sub_helpers/auth"
import { getHeaders, recordToHoppHeaders } from "./sub_helpers/headers"
// import { getCookies } from "./sub_helpers/cookies"
import { getQueries } from "./sub_helpers/queries"
import { getMethod } from "./sub_helpers/method"
import { concatParams, getURLObject } from "./sub_helpers/url"
import { preProcessCurlCommand } from "./sub_helpers/preproc"
import { getBody, getFArgumentMultipartData } from "./sub_helpers/body"
import { getDefaultRESTRequest } from "~/newstore/RESTSession"
import {
objHasProperty,
objHasArrayProperty,
} from "~/helpers/functional/object"
const defaultRESTReq = getDefaultRESTRequest()
export const parseCurlCommand = (curlCommand: string) => {
// const isDataBinary = curlCommand.includes(" --data-binary")
// const compressed = !!parsedArguments.compressed
curlCommand = preProcessCurlCommand(curlCommand)
const parsedArguments = parser(curlCommand)
const headerObject = getHeaders(parsedArguments)
const { headers } = headerObject
let { rawContentType } = headerObject
const hoppHeaders = pipe(
headers,
O.fromPredicate(() => Object.keys(headers).length > 0),
O.map(recordToHoppHeaders),
O.getOrElse(() => defaultRESTReq.headers)
)
const method = getMethod(parsedArguments)
// const cookies = getCookies(parsedArguments)
const urlObject = getURLObject(parsedArguments)
const auth = getAuthObject(parsedArguments, headers, urlObject)
let rawData: string | string[] = pipe(
parsedArguments,
O.fromPredicate(objHasArrayProperty("d", "string")),
O.map((args) => args.d),
O.altW(() =>
pipe(
parsedArguments,
O.fromPredicate(objHasProperty("d", "string")),
O.map((args) => args.d)
)
),
O.getOrElseW(() => "")
)
let body: HoppRESTReqBody["body"] = ""
let contentType: HoppRESTReqBody["contentType"] =
defaultRESTReq.body.contentType
let hasBodyBeenParsed = false
let { queries, danglingParams } = getQueries(
Array.from(urlObject.searchParams.entries())
)
const stringToPair = flow(
decodeURIComponent,
(pair) => <[string, string]>pair.split("=", 2)
)
const pairs = pipe(
rawData,
O.fromPredicate(Array.isArray),
O.map(A.map(stringToPair)),
O.alt(() =>
pipe(
rawData,
O.fromPredicate((s) => s.length > 0),
O.map(() => [stringToPair(rawData as string)])
)
),
O.getOrElseW(() => undefined)
)
if (objHasProperty("G", "boolean")(parsedArguments) && !!pairs) {
const newQueries = getQueries(pairs)
queries = [...queries, ...newQueries.queries]
danglingParams = [...danglingParams, ...newQueries.danglingParams]
hasBodyBeenParsed = true
} else if (
rawContentType.includes("application/x-www-form-urlencoded") &&
!!pairs
) {
body = pairs.map((p) => p.join(": ")).join("\n") || null
contentType = "application/x-www-form-urlencoded"
hasBodyBeenParsed = true
}
const urlString = concatParams(urlObject, danglingParams)
let multipartUploads: Record<string, string> = pipe(
O.of(parsedArguments),
O.chain(getFArgumentMultipartData),
O.match(
() => ({}),
(args) => {
hasBodyBeenParsed = true
rawContentType = "multipart/form-data"
return args
}
)
)
if (!hasBodyBeenParsed) {
if (typeof rawData !== "string") {
rawData = rawData.join("")
}
const bodyObject = getBody(rawData, rawContentType, contentType)
if (O.isSome(bodyObject)) {
const bodyObjectValue = bodyObject.value
if (bodyObjectValue.type === "FORMDATA") {
multipartUploads = bodyObjectValue.body
} else {
body = bodyObjectValue.body.body
contentType = bodyObjectValue.body
.contentType as HoppRESTReqBody["contentType"]
}
}
}
const finalBody: HoppRESTReqBody = pipe(
body,
O.fromNullable,
O.filter((b) => b.length > 0),
O.map((b) => <HoppRESTReqBody>{ body: b, contentType }),
O.alt(() =>
pipe(
multipartUploads,
O.of,
O.map((m) => Object.entries(m)),
O.filter((m) => m.length > 0),
O.map(
flow(
A.map(
([key, value]) =>
<FormDataKeyValue>{
active: true,
isFile: false,
key,
value,
}
),
(b) =>
<HoppRESTReqBody>{ body: b, contentType: "multipart/form-data" }
)
)
)
),
O.getOrElse(() => defaultRESTReq.body)
)
return makeRESTRequest({
name: defaultRESTReq.name,
endpoint: urlString,
method: (method || defaultRESTReq.method).toUpperCase(),
params: queries ?? defaultRESTReq.params,
headers: hoppHeaders,
preRequestScript: defaultRESTReq.preRequestScript,
testScript: defaultRESTReq.testScript,
auth,
body: finalBody,
})
}