chore: split app to commons and web (squash commit)

This commit is contained in:
Andrew Bastin
2022-12-02 02:57:46 -05:00
parent fb827e3586
commit 3d004f2322
535 changed files with 1487 additions and 501 deletions

View File

@@ -0,0 +1,113 @@
import * as RA from "fp-ts/ReadonlyArray"
import * as S from "fp-ts/string"
import { pipe, flow } from "fp-ts/function"
import * as Har from "har-format"
import { HoppRESTRequest } from "@hoppscotch/data"
import { FieldEquals, objectFieldIncludes } from "../typeutils"
// Hoppscotch support HAR Spec 1.2
// For more info on the spec: http://www.softwareishard.com/blog/har-12-spec/
const buildHarHeaders = (req: HoppRESTRequest): Har.Header[] => {
return req.headers
.filter((header) => header.active)
.map((header) => ({
name: header.key,
value: header.value,
}))
}
const buildHarQueryStrings = (req: HoppRESTRequest): Har.QueryString[] => {
return req.params
.filter((param) => param.active)
.map((param) => ({
name: param.key,
value: param.value,
}))
}
const buildHarPostParams = (
req: HoppRESTRequest &
FieldEquals<HoppRESTRequest, "method", ["POST", "PUT"]> & {
body: {
contentType: "application/x-www-form-urlencoded" | "multipart/form-data"
}
}
): Har.Param[] => {
// URL Encoded strings have a string style of contents
if (req.body.contentType === "application/x-www-form-urlencoded") {
return pipe(
req.body.body,
S.split("\n"),
RA.map(
flow(
// Define how each lines are parsed
S.split(":"), // Split by ":"
RA.map(S.trim), // Remove trailing spaces in key/value begins and ends
([key, value]) => ({
// Convert into a proper key value definition
name: key,
value: value ?? "", // Value can be undefined (if no ":" is present)
})
)
),
RA.toArray
)
} else {
// FormData has its own format
return req.body.body.flatMap((entry) => {
if (entry.isFile) {
// We support multiple files
return entry.value.map(
(file) =>
<Har.Param>{
name: entry.key,
fileName: entry.key, // TODO: Blob doesn't contain file info, anyway to bring file name here ?
contentType: file.type,
}
)
} else {
return {
name: entry.key,
value: entry.value,
}
}
})
}
}
const buildHarPostData = (req: HoppRESTRequest): Har.PostData | undefined => {
if (!req.body.contentType) return undefined
if (
objectFieldIncludes(req.body, "contentType", [
"application/x-www-form-urlencoded",
"multipart/form-data",
] as const)
) {
return {
mimeType: req.body.contentType, // By default assume JSON ?
params: buildHarPostParams(req as any),
}
}
return {
mimeType: req.body.contentType, // Let's assume by default content type is JSON
text: req.body.body,
}
}
export const buildHarRequest = (req: HoppRESTRequest): Har.Request => {
return {
bodySize: -1, // TODO: It would be cool if we can calculate the body size
headersSize: -1, // TODO: It would be cool if we can calculate the header size
httpVersion: "HTTP/1.1",
cookies: [], // Hoppscotch does not have formal support for Cookies as of right now
headers: buildHarHeaders(req),
method: req.method,
queryString: buildHarQueryStrings(req),
url: req.endpoint,
postData: buildHarPostData(req),
}
}

View File

@@ -0,0 +1,224 @@
import HTTPSnippet from "httpsnippet"
import { HoppRESTRequest } from "@hoppscotch/data"
import * as O from "fp-ts/Option"
import * as E from "fp-ts/Either"
import { pipe } from "fp-ts/function"
import { buildHarRequest } from "./har"
// Hoppscotch's Code Generation is Powered by HTTPSnippet (https://github.com/Kong/httpsnippet)
// If you want to add support for your favorite language/library, please contribute to the HTTPSnippet repo <3
/**
* An array defining all the code generators and their info
*/
export const CodegenDefinitions = [
{
name: "c-curl",
lang: "c",
mode: "libcurl",
caption: "C - cURL",
},
{
name: "clojure-clj_http",
lang: "clojure",
mode: "clj_http",
caption: "Clojure - clj-http",
},
{
name: "csharp-httpclient",
lang: "csharp",
mode: "httpclient",
caption: "C# - HttpClient",
},
{
name: "csharp-restsharp",
lang: "csharp",
mode: "restsharp",
caption: "C# - RestSharp",
},
{
name: "go-native",
lang: "go",
mode: "native",
caption: "Go",
},
{
name: "http-http1.1",
lang: "http",
mode: "http1.1",
caption: "HTTP - HTTP 1.1 Request String",
},
{
name: "java-asynchttp",
lang: "java",
mode: "asynchttp",
caption: "Java - AsyncHTTPClient",
},
{
name: "java-nethttp",
lang: "java",
mode: "nethttp",
caption: "Java - java.net.http",
},
{
name: "java-okhttp",
lang: "java",
mode: "okhttp",
caption: "Java - OkHttp",
},
{
name: "java-unirest",
lang: "java",
mode: "unirest",
caption: "Java - Unirest",
},
{
name: "javascript-axios",
lang: "javascript",
mode: "axios",
caption: "JavaScript - Axios",
},
{
name: "javascript-fetch",
lang: "javascript",
mode: "fetch",
caption: "JavaScript - Fetch",
},
{
name: "javascript-jquery",
lang: "javascript",
mode: "jquery",
caption: "JavaScript - jQuery",
},
{
name: "javascript-xhr",
lang: "javascript",
mode: "xhr",
caption: "JavaScript - XMLHttpRequest",
},
{
name: "kotlin-okhttp",
lang: "kotlin",
mode: "okhttp",
caption: "Kotlin - OkHttp",
},
{
name: "objc-nsurlsession",
lang: "objc",
mode: "nsurlsession",
caption: "Objective C - NSURLSession",
},
{
name: "ocaml-cohttp",
lang: "ocaml",
mode: "cohttp",
caption: "OCaml - cohttp",
},
{
name: "php-curl",
lang: "php",
mode: "curl",
caption: "PHP - cURL",
},
{
name: "powershell-restmethod",
lang: "powershell",
mode: "restmethod",
caption: "Powershell - Invoke-RestMethod",
},
{
name: "powershell-webrequest",
lang: "powershell",
mode: "webrequest",
caption: "Powershell - Invoke-WebRequest",
},
{
name: "python-python3",
lang: "python",
mode: "python3",
caption: "Python - Python 3 Native",
},
{
name: "python-requests",
lang: "python",
mode: "requests",
caption: "Python - Requests",
},
{
name: "r-httr",
lang: "r",
mode: "httr",
caption: "R - httr",
},
{
name: "ruby-native",
lang: "ruby",
mode: "native",
caption: "Ruby - Ruby Native",
},
{
name: "shell-curl",
lang: "shell",
mode: "curl",
caption: "Shell - cURL",
},
{
name: "shell-httpie",
lang: "shell",
mode: "httpie",
caption: "Shell - HTTPie",
},
{
name: "shell-wget",
lang: "shell",
mode: "wget",
caption: "Shell - Wget",
},
{
name: "swift-nsurlsession",
lang: "swift",
mode: "nsurlsession",
caption: "Swift - NSURLSession",
},
] as const
/**
* A type which defines all the valid code generators
*/
export type CodegenName = typeof CodegenDefinitions[number]["name"]
/**
* Generates Source Code for the given codgen
* @param codegen The codegen to apply
* @param req The request to generate using
* @returns An Option with the generated code snippet
*/
export const generateCode = (
codegen: CodegenName,
req: HoppRESTRequest
): O.Option<string> => {
// Since the Type contract guarantees a match in the array, we are enforcing non-null
const codegenInfo = CodegenDefinitions.find((v) => v.name === codegen)!
return pipe(
E.tryCatch(
() =>
new HTTPSnippet({
...buildHarRequest(req),
}).convert(codegenInfo.lang, codegenInfo.mode, {
indent: " ",
}),
(e) => e
),
// Only allow string output to pass through, else none
E.chainW(
E.fromPredicate(
(val): val is string => typeof val === "string",
() => "code generator failed" as const
)
),
O.fromEither
)
}