+} {
+ return pipe(
+ params,
+ O.of,
+ O.map(
+ flow(
+ A.partition(isDangling),
+ Sep.bimap(
+ A.map(([key, value]) => ({
+ key,
+ value,
+ active: true,
+ })),
+ A.map(([key]) => key)
+ ),
+ (sep) => ({
+ queries: sep.left,
+ danglingParams: sep.right,
+ })
+ )
+ ),
+ O.getOrElseW(() => ({
+ queries: [],
+ danglingParams: [],
+ }))
+ )
+}
diff --git a/packages/hoppscotch-app/helpers/curl/sub_helpers/url.ts b/packages/hoppscotch-app/helpers/curl/sub_helpers/url.ts
new file mode 100644
index 000000000..2fdb1d9ce
--- /dev/null
+++ b/packages/hoppscotch-app/helpers/curl/sub_helpers/url.ts
@@ -0,0 +1,80 @@
+import parser from "yargs-parser"
+import { pipe } from "fp-ts/function"
+import * as O from "fp-ts/Option"
+import { getDefaultRESTRequest } from "~/newstore/RESTSession"
+import { stringArrayJoin } from "~/helpers/functional/array"
+
+const defaultRESTReq = getDefaultRESTRequest()
+
+const getProtocolForBaseURL = (baseURL: string) =>
+ pipe(
+ // get the base URL
+ /^([^\s:@]+:[^\s:@]+@)?([^:/\s]+)([:]*)/.exec(baseURL),
+ O.fromNullable,
+ O.filter((burl) => burl.length > 1),
+ O.map((burl) => burl[2]),
+ // set protocol to http for local URLs
+ O.map((burl) =>
+ burl === "localhost" || burl === "127.0.0.1"
+ ? "http://" + baseURL
+ : "https://" + baseURL
+ )
+ )
+
+/**
+ * Processes URL string and returns the URL object
+ * @param parsedArguments Parsed Arguments object
+ * @returns URL object
+ */
+export function parseURL(parsedArguments: parser.Arguments) {
+ return pipe(
+ // contains raw url string
+ parsedArguments._[1],
+ O.fromNullable,
+ // preprocess url string
+ O.map((u) => u.toString().replace(/["']/g, "").trim()),
+ O.chain((u) =>
+ pipe(
+ // check if protocol is available
+ /^[^:\s]+(?=:\/\/)/.exec(u),
+ O.fromNullable,
+ O.map((_) => u),
+ O.alt(() => getProtocolForBaseURL(u))
+ )
+ ),
+ O.map((u) => new URL(u)),
+ // no url found
+ O.getOrElse(() => new URL(defaultRESTReq.endpoint))
+ )
+}
+
+/**
+ * Joins dangling params to origin
+ * @param urlObject URL object containing origin and pathname
+ * @param danglingParams Keys of params with empty values
+ * @returns origin string concatenated with dangling paramas
+ */
+export function concatParams(urlObject: URL, danglingParams: string[]) {
+ return pipe(
+ O.Do,
+
+ O.bind("originString", () =>
+ pipe(
+ urlObject.origin,
+ O.fromPredicate((h) => h !== "")
+ )
+ ),
+
+ O.map(({ originString }) =>
+ pipe(
+ danglingParams,
+ O.fromPredicate((dp) => dp.length > 0),
+ O.map(stringArrayJoin("&")),
+ O.map((h) => originString + (urlObject.pathname || "") + "?" + h),
+ O.getOrElse(() => originString + (urlObject.pathname || ""))
+ )
+ ),
+
+ O.getOrElse(() => defaultRESTReq.endpoint)
+ )
+}
diff --git a/packages/hoppscotch-app/helpers/functional/object.ts b/packages/hoppscotch-app/helpers/functional/object.ts
index 1d6d9334b..018eaba44 100644
--- a/packages/hoppscotch-app/helpers/functional/object.ts
+++ b/packages/hoppscotch-app/helpers/functional/object.ts
@@ -18,3 +18,74 @@ export const objFieldMatches =
// eslint-disable-next-line no-unused-vars
(obj: T): obj is T & { [_ in K]: V } =>
matches.findIndex((x) => isEqual(obj[fieldName], x)) !== -1
+
+type JSPrimitive =
+ | "undefined"
+ | "object"
+ | "boolean"
+ | "number"
+ | "bigint"
+ | "string"
+ | "symbol"
+ | "function"
+
+type TypeFromPrimitive =
+ P extends "undefined"
+ ? undefined
+ : P extends "object"
+ ? object | null // typeof null === "object"
+ : P extends "boolean"
+ ? boolean
+ : P extends "number"
+ ? number
+ : P extends "bigint"
+ ? BigInt
+ : P extends "string"
+ ? string
+ : P extends "symbol"
+ ? Symbol
+ : P extends "function"
+ ? Function
+ : unknown
+
+type TypeFromPrimitiveArray
=
+ P extends "undefined"
+ ? undefined
+ : P extends "object"
+ ? object[] | null
+ : P extends "boolean"
+ ? boolean[]
+ : P extends "number"
+ ? number[]
+ : P extends "bigint"
+ ? BigInt[]
+ : P extends "string"
+ ? string[]
+ : P extends "symbol"
+ ? Symbol[]
+ : P extends "function"
+ ? Function[]
+ : unknown[]
+
+export const objHasProperty =
+ (
+ prop: K,
+ type: P
+ ) =>
+ // eslint-disable-next-line
+ (obj: O): obj is O & { [_ in K]: TypeFromPrimitive } =>
+ // eslint-disable-next-line
+ prop in obj && typeof (obj as any)[prop] === type
+
+export const objHasArrayProperty =
+ (
+ prop: K,
+ type: P
+ ) =>
+ // eslint-disable-next-line
+ (obj: O): obj is O & { [_ in K]: TypeFromPrimitiveArray } =>
+ prop in obj &&
+ Array.isArray((obj as any)[prop]) &&
+ (obj as any)[prop].every(
+ (val: unknown) => typeof val === type // eslint-disable-line
+ )
diff --git a/packages/hoppscotch-app/helpers/functional/option.ts b/packages/hoppscotch-app/helpers/functional/option.ts
new file mode 100644
index 000000000..3c67ef585
--- /dev/null
+++ b/packages/hoppscotch-app/helpers/functional/option.ts
@@ -0,0 +1,19 @@
+import * as O from "fp-ts/Option"
+import * as A from "fp-ts/Array"
+import { pipe } from "fp-ts/function"
+
+/**
+ * Tries to match one of the given predicates.
+ * If a predicate is matched, the associated value is returned in a Some.
+ * Else if none of the predicates is matched, None is returned.
+ * @param choice An array of tuples having a predicate function and the selected value
+ * @returns A function which takes the input and returns an Option
+ */
+export const optionChoose =
+ (choice: Array<[(x: T) => boolean, V]>) =>
+ (input: T): O.Option =>
+ pipe(
+ choice,
+ A.findFirst(([pred]) => pred(input)),
+ O.map(([_, value]) => value)
+ )