From 446a123fd87693405860e2789492160fa730312a Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 11:32:29 -0400 Subject: [PATCH 01/14] feat: read a json file with run command to do request --- .gitignore | 4 +++- cli.ts | 24 ++++++++++++++++++++---- import_map.json | 1 + types.ts | 5 +++++ utils/args/parser.ts | 5 +++++ utils/args/validate.ts | 9 ++++++++- utils/customFetch.ts | 15 +++++++++++++-- utils/readJson.ts | 12 ++++++++++++ 8 files changed, 67 insertions(+), 8 deletions(-) create mode 100644 utils/readJson.ts diff --git a/.gitignore b/.gitignore index 6df9520..9e82420 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,6 @@ CHANGELOG.md # code what you want: poc.js poc.ts -code \ No newline at end of file +poc + +request.json \ No newline at end of file diff --git a/cli.ts b/cli.ts index 97e8706..19a2457 100644 --- a/cli.ts +++ b/cli.ts @@ -10,8 +10,11 @@ import helpCommand from "./commands/help.ts"; import versionCommand from "./commands/version.ts"; import parse from "./utils/args/parser.ts"; import output from "./utils/output/output.ts"; -import customFetch from "./utils/customFetch.ts"; +import { customFetch, runFetch } from "./utils/customFetch.ts"; import { validateArgs } from "./utils/args/validate.ts"; +import { red, yellow } from "./utils/color/colors.ts"; +import { runJson } from "./types.ts"; +import { readJson } from "./utils/readJson.ts"; const denoArgs = Deno.args; const args = parse(denoArgs); @@ -25,9 +28,22 @@ if (unexpect && unexpect.exit) { } if (args) { - const { flags } = args; + const { flags, command } = args; - if (flags?.help) { + if (command) { + const request = await readJson("./request.json") as runJson; + const alias = request[command.split(" ")[1]]; + if (!alias) { + console.error( + `${red("error")}: ${yellow(alias)} alias not found in ${ + yellow("request.json") + }`, + ); + Deno.exit(); + } + + output(await runFetch(alias.url, alias)); + } else if (flags?.help) { console.log(helpCommand); } else if (flags?.version) { console.log(versionCommand); @@ -39,4 +55,4 @@ if (args) { if (unexpect) { const { type, msg } = unexpect; console.error(`\n${type}: ${msg}`); -} \ No newline at end of file +} diff --git a/import_map.json b/import_map.json index 0d73820..95e9cef 100644 --- a/import_map.json +++ b/import_map.json @@ -1,6 +1,7 @@ { "imports": { "fmt/": "https://deno.land/std@0.101.0/fmt/", + "fs/": "https://deno.land/std/fs/", "merlin": "https://deno.land/x/merlin@v1.0.6/mod.ts" } } diff --git a/types.ts b/types.ts index 27e3ffa..b418e56 100644 --- a/types.ts +++ b/types.ts @@ -23,4 +23,9 @@ export interface Args { flags?: Record; body?: string | FormData | Record; headers?: Record; + command?: string; } + +export interface runJson { + [key:string]: Request; +} \ No newline at end of file diff --git a/utils/args/parser.ts b/utils/args/parser.ts index 8ec16ec..fe402ad 100644 --- a/utils/args/parser.ts +++ b/utils/args/parser.ts @@ -19,6 +19,11 @@ export default function parse(args: string[]) { const obj: Args = {}; const body: string[] = []; + if (args.join(" ").startsWith("run")) { + obj.command = args.join(" "); + return obj as Required; + } + args.forEach((arg) => { if (arg.match(method)) { obj.method = arg as Method; diff --git a/utils/args/validate.ts b/utils/args/validate.ts index d925b65..3faa433 100644 --- a/utils/args/validate.ts +++ b/utils/args/validate.ts @@ -8,10 +8,17 @@ interface Invalid { } export function validateArgs(args: Required): Invalid | false { - const { method, flags, url } = args; + const { method, flags, url, command } = args; const miss = missData(args); + if (command.startsWith("run") && command.split(" ").length > 2) { + return { + msg: `the command ${purple("run")} expect only a command from ${yellow("request.json")}`, + exit: true, + type: red("error") + } + } if (flags?.form && (!url || !method)) { return { msg: `the flag ${purple("form")} needs the following arguments: ${miss}`, diff --git a/utils/customFetch.ts b/utils/customFetch.ts index f6dbe50..f0bad1c 100644 --- a/utils/customFetch.ts +++ b/utils/customFetch.ts @@ -9,7 +9,7 @@ import type { Args, Output } from "../types.ts"; import { HandleResponseData } from "./validate.ts"; -async function customFetch(config: Required): Promise { +export async function customFetch(config: Required): Promise { const { method, body, flags, headers, url: URL } = config; const form = flags?.form; const hasProtocol = URL.includes("http"); @@ -92,4 +92,15 @@ function parseHeaders(headers: Headers) { return outputHeaders; } -export default customFetch; +export async function runFetch(url: string, init: Request): Promise { + const response = await fetch(url, init); + const data = await HandleResponseData>(response); + + return { + ok: response.ok, + protocol: response.url.includes("https") ? "HTTPS" : "HTTP", + status: response.status, + headers: parseHeaders(response.headers), + body: data, + }; +} diff --git a/utils/readJson.ts b/utils/readJson.ts new file mode 100644 index 0000000..9ac5daf --- /dev/null +++ b/utils/readJson.ts @@ -0,0 +1,12 @@ +export async function readJson(filePath: string): Promise { + const decoder = new TextDecoder("utf-8"); + + const content = decoder.decode(await Deno.readFile(filePath)); + + try { + return JSON.parse(content); + } catch (err) { + err.message = `${filePath}: ${err.message}`; + throw err; + } +} \ No newline at end of file From 95733eff73247cad68b071a72118786a01074c7b Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 11:47:00 -0400 Subject: [PATCH 02/14] test refactor --- tests/args.test.ts | 94 +++--------------------------------- tests/form.test.ts | 48 ++++++++++++++++++ tests/help.test.ts | 20 ++++++++ tests/types.ts | 4 ++ tests/unexpectedArgs.test.ts | 18 ------- tests/version.test.ts | 41 ++++++++++++++++ 6 files changed, 120 insertions(+), 105 deletions(-) create mode 100644 tests/form.test.ts create mode 100644 tests/help.test.ts create mode 100644 tests/types.ts create mode 100644 tests/version.test.ts diff --git a/tests/args.test.ts b/tests/args.test.ts index de25ec9..68c3319 100644 --- a/tests/args.test.ts +++ b/tests/args.test.ts @@ -1,46 +1,9 @@ import { Merlin } from "merlin"; import parse from "../utils/args/parser.ts"; -import type { Args } from "../types.ts"; +import type { ArgResult } from "./types.ts"; const test = new Merlin(); -type ArgResult = void | Args; -type FlagResult = { short: ArgResult; complete: ArgResult }; - -//#region basic flags - -test.assertEqual("version flag", { - expect() { - const short = parse(["-v"]); - const complete = parse(["--version"]); - return { short, complete }; - }, - toBe(): FlagResult { - const result: ArgResult = { flags: { version: true } }; - return { - short: result, - complete: result, - }; - }, -}); - -test.assertEqual("help flag", { - expect() { - const short = parse(["-h"]); - const complete = parse(["--help"]); - return { short, complete }; - }, - toBe(): FlagResult { - const result: ArgResult = { flags: { help: true } }; - return { - short: result, - complete: result, - }; - }, -}); - -//#endregion - test.assertEqual("GET: api.github.com", { expect() { return parse(["api.github.com"]); @@ -65,17 +28,17 @@ test.assertEqual("GET (explicit): api.github.com", { }, }); -test.assertEqual("complex url", { +test.assertEqual("GET: complex url", { expect() { - return parse(["localhost:8080/[pgk]/?id=20"]) + return parse(["localhost:8080/[pgk]/?id=20"]); }, toBe(): ArgResult { return { url: "localhost:8080/[pgk]/?id=20", method: "GET", - } - } -}) + }; + }, +}); test.assertEqual("POST: send a email", { expect() { @@ -208,7 +171,7 @@ test.assertEqual("PATCH: with object and array", { test.assertEqual("DELETE", { expect() { - return parse(["DELETE","localhost:8080"]); + return parse(["DELETE", "localhost:8080"]); }, toBe(): ArgResult { return { @@ -217,46 +180,3 @@ test.assertEqual("DELETE", { }; }, }); - -test.assertEqual("POST a formData with -f flag", { - expect() { - const args = [ - "-f", - "POST", - "localhost:8080", - "person={name=Deno Merlin", - "age=24", - "hobbies=[test", - "movies]}", - ]; - const short = parse(args); - args[0] = "--form"; - const complete = parse(args); - - return { short, complete }; - }, - toBe(): FlagResult { - const formData = new FormData(); - formData.append( - "person", - JSON.parse(`{ - "name": "Deno Merlin", - "age": 24, - "hobbies": ["test", "movies"] - }`), - ); - - const result: ArgResult = { - method: "POST", - url: "localhost:8080", - flags: { form: true }, - headers: undefined, - body: formData, - }; - - return { - short: result, - complete: result, - }; - }, -}); diff --git a/tests/form.test.ts b/tests/form.test.ts new file mode 100644 index 0000000..861d966 --- /dev/null +++ b/tests/form.test.ts @@ -0,0 +1,48 @@ +import { Merlin } from "merlin"; +import parse from "../utils/args/parser.ts"; +import type { ArgResult, FlagResult } from "./types.ts"; + +const test = new Merlin(); + +test.assertEqual("POST a formData with -f flag", { + expect() { + const args = [ + "-f", + "POST", + "localhost:8080", + "person={name=Deno Merlin", + "age=24", + "hobbies=[test", + "movies]}", + ]; + const short = parse(args); + args[0] = "--form"; + const complete = parse(args); + + return { short, complete }; + }, + toBe(): FlagResult { + const formData = new FormData(); + formData.append( + "person", + JSON.parse(`{ + "name": "Deno Merlin", + "age": 24, + "hobbies": ["test", "movies"] + }`), + ); + + const result: ArgResult = { + method: "POST", + url: "localhost:8080", + flags: { form: true }, + headers: undefined, + body: formData, + }; + + return { + short: result, + complete: result, + }; + }, +}); diff --git a/tests/help.test.ts b/tests/help.test.ts new file mode 100644 index 0000000..fcf7696 --- /dev/null +++ b/tests/help.test.ts @@ -0,0 +1,20 @@ +import { Merlin } from "merlin"; +import parse from "../utils/args/parser.ts"; +import type { ArgResult, FlagResult } from "./types.ts"; + +const test = new Merlin(); + +test.assertEqual("help flag", { + expect() { + const short = parse(["-h"]); + const complete = parse(["--help"]); + return { short, complete }; + }, + toBe(): FlagResult { + const result: ArgResult = { flags: { help: true } }; + return { + short: result, + complete: result, + }; + }, +}); diff --git a/tests/types.ts b/tests/types.ts new file mode 100644 index 0000000..86f0905 --- /dev/null +++ b/tests/types.ts @@ -0,0 +1,4 @@ +import type { Args } from "../types.ts"; + +export type ArgResult = void | Args; +export type FlagResult = { short: ArgResult; complete: ArgResult }; \ No newline at end of file diff --git a/tests/unexpectedArgs.test.ts b/tests/unexpectedArgs.test.ts index 378b2f5..5f5048e 100644 --- a/tests/unexpectedArgs.test.ts +++ b/tests/unexpectedArgs.test.ts @@ -5,24 +5,6 @@ import type { Args } from "../types.ts"; const test = new Merlin(); -test.assertEqual("version", { - expect() { - const obj: Args = { - flags: { version: true }, - url: "ajio.com", - method: "GET", - }; - return validateArgs(obj as Required); - }, - toBe() { - return { - msg: `the flag ${purple("version")} doesn't need arguments`, - exit: false, - type: `${yellow("warn")}`, - }; - }, -}); - test.assertEqual("form", { expect() { const obj: Args = { flags: { form: true } }; diff --git a/tests/version.test.ts b/tests/version.test.ts new file mode 100644 index 0000000..4d9ec2e --- /dev/null +++ b/tests/version.test.ts @@ -0,0 +1,41 @@ +import { Merlin } from "merlin"; +import parse from "../utils/args/parser.ts"; +import { validateArgs } from "../utils/args/validate.ts"; +import { purple, yellow } from "../utils/color/colors.ts"; +import type { Args } from "../types.ts"; +import type { ArgResult, FlagResult } from "./types.ts"; + +const test = new Merlin(); + +test.assertEqual("version flag", { + expect() { + const short = parse(["-v"]); + const complete = parse(["--version"]); + return { short, complete }; + }, + toBe(): FlagResult { + const result: ArgResult = { flags: { version: true } }; + return { + short: result, + complete: result, + }; + }, +}); + +test.assertEqual("version unexpected args", { + expect() { + const obj: Args = { + flags: { version: true }, + url: "ajio.com", + method: "GET", + }; + return validateArgs(obj as Required); + }, + toBe() { + return { + msg: `the flag ${purple("version")} doesn't need arguments`, + exit: false, + type: `${yellow("warn")}`, + }; + }, +}); From cef226c83b5c935d056ce387cb51a2b82c677f55 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 11:53:10 -0400 Subject: [PATCH 03/14] fix: error relationated with run command --- utils/args/validate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/args/validate.ts b/utils/args/validate.ts index 3faa433..164a205 100644 --- a/utils/args/validate.ts +++ b/utils/args/validate.ts @@ -12,7 +12,7 @@ export function validateArgs(args: Required): Invalid | false { const miss = missData(args); - if (command.startsWith("run") && command.split(" ").length > 2) { + if (command?.startsWith("run") && command?.split(" ").length > 2) { return { msg: `the command ${purple("run")} expect only a command from ${yellow("request.json")}`, exit: true, From e799c42f05fe120f463d304bf97f53149a8262de Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 12:11:36 -0400 Subject: [PATCH 04/14] refactor: run command for test --- cli.ts | 19 ++++--------------- utils/readJson.ts | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/cli.ts b/cli.ts index 19a2457..6ab2f2f 100644 --- a/cli.ts +++ b/cli.ts @@ -12,9 +12,7 @@ import parse from "./utils/args/parser.ts"; import output from "./utils/output/output.ts"; import { customFetch, runFetch } from "./utils/customFetch.ts"; import { validateArgs } from "./utils/args/validate.ts"; -import { red, yellow } from "./utils/color/colors.ts"; -import { runJson } from "./types.ts"; -import { readJson } from "./utils/readJson.ts"; +import { getRequest } from "./utils/readJson.ts"; const denoArgs = Deno.args; const args = parse(denoArgs); @@ -31,18 +29,9 @@ if (args) { const { flags, command } = args; if (command) { - const request = await readJson("./request.json") as runJson; - const alias = request[command.split(" ")[1]]; - if (!alias) { - console.error( - `${red("error")}: ${yellow(alias)} alias not found in ${ - yellow("request.json") - }`, - ); - Deno.exit(); - } - - output(await runFetch(alias.url, alias)); + const alias = command.split(" ")[1]; + const request = await getRequest(alias); + output(await runFetch(request.url, request)); } else if (flags?.help) { console.log(helpCommand); } else if (flags?.version) { diff --git a/utils/readJson.ts b/utils/readJson.ts index 9ac5daf..d8c48ee 100644 --- a/utils/readJson.ts +++ b/utils/readJson.ts @@ -1,3 +1,6 @@ +import { red, yellow } from "./color/colors.ts"; +import { runJson } from "../types.ts"; + export async function readJson(filePath: string): Promise { const decoder = new TextDecoder("utf-8"); @@ -9,4 +12,19 @@ export async function readJson(filePath: string): Promise { err.message = `${filePath}: ${err.message}`; throw err; } +} + +export async function getRequest(alias: string): Promise { + const json = await readJson("./request.json") as runJson; + const request = json[alias]; + if (!request) { + console.error( + `${red("error")}: ${yellow(alias)} alias not found in ${ + yellow("request.json") + }`, + ); + Deno.exit(); + } + + return request; } \ No newline at end of file From 04d37e698736f8e1c635e50fbdaaaac884f81523 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 15:03:08 -0400 Subject: [PATCH 05/14] test(run): send json and some refactor --- cli.ts | 4 +++- info.ts | 1 + run.json | 2 +- tests/request.test.json | 17 +++++++++++++++++ tests/run.test.ts | 32 ++++++++++++++++++++++++++++++++ utils/readJson.ts | 12 +++++++++--- 6 files changed, 63 insertions(+), 5 deletions(-) create mode 100644 tests/request.test.json create mode 100644 tests/run.test.ts diff --git a/cli.ts b/cli.ts index 6ab2f2f..cf7667d 100644 --- a/cli.ts +++ b/cli.ts @@ -13,6 +13,7 @@ import output from "./utils/output/output.ts"; import { customFetch, runFetch } from "./utils/customFetch.ts"; import { validateArgs } from "./utils/args/validate.ts"; import { getRequest } from "./utils/readJson.ts"; +import { filePath } from "./info.ts"; const denoArgs = Deno.args; const args = parse(denoArgs); @@ -30,7 +31,8 @@ if (args) { if (command) { const alias = command.split(" ")[1]; - const request = await getRequest(alias); + const request = await getRequest(alias, filePath); + output(await runFetch(request.url, request)); } else if (flags?.help) { console.log(helpCommand); diff --git a/info.ts b/info.ts index 92bccf1..825d8bb 100644 --- a/info.ts +++ b/info.ts @@ -8,3 +8,4 @@ export const name = "Piwo"; export const version = "v0.4.2"; +export const filePath = "./request.json"; diff --git a/run.json b/run.json index 1d6d40e..fc69ef4 100644 --- a/run.json +++ b/run.json @@ -2,6 +2,6 @@ "scripts": { "dev": "deno run -A --unstable --import-map=./import_map.json ./cli.ts", "piwo": "deno run --allow-net --no-check --import-map=./import_map.json ./cli.ts", - "test": "deno test --import-map=./import_map.json" + "test": "deno test --allow-read --import-map=./import_map.json" } } diff --git a/tests/request.test.json b/tests/request.test.json new file mode 100644 index 0000000..7f37325 --- /dev/null +++ b/tests/request.test.json @@ -0,0 +1,17 @@ +{ + "github": { + "method": "GET", + "url": "https://api.github.com" + }, + "new-task": { + "method": "POST", + "url": "http://localhost:8080/task/", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "name": "read json file", + "description": "make piwo read a json file for doing request running a simple script" + } + } +} \ No newline at end of file diff --git a/tests/run.test.ts b/tests/run.test.ts new file mode 100644 index 0000000..b9eb63f --- /dev/null +++ b/tests/run.test.ts @@ -0,0 +1,32 @@ +import { Merlin } from "merlin"; +import { getRequest } from "../utils/readJson.ts"; + +const test = new Merlin(); +const filePath = "./tests/request.test.json"; + +test.assertEqual("run GET: api.github.com", { + async expect() { + return await getRequest("github", filePath); + }, + toBe() { + return { method: "GET", url: "https://api.github.com" }; + }, +}); + +test.assertEqual("run POST: json body to localhost", { + async expect() { + return await getRequest("new-task", filePath); + }, + toBe() { + return { + method: "POST", + url: "http://localhost:8080/task/", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ + name: "read json file", + description: + "make piwo read a json file for doing request running a simple script", + }), + } as unknown as Request; + }, +}); diff --git a/utils/readJson.ts b/utils/readJson.ts index d8c48ee..106c548 100644 --- a/utils/readJson.ts +++ b/utils/readJson.ts @@ -14,8 +14,8 @@ export async function readJson(filePath: string): Promise { } } -export async function getRequest(alias: string): Promise { - const json = await readJson("./request.json") as runJson; +export async function getRequest(alias: string, filePath: string) { + const json = await readJson(filePath) as runJson; const request = json[alias]; if (!request) { console.error( @@ -26,5 +26,11 @@ export async function getRequest(alias: string): Promise { Deno.exit(); } + if (request.body) { + Object.defineProperty(request, "body", { + value: JSON.stringify(request.body), + }); + } + return request; -} \ No newline at end of file +} From 16a8a36106dab343d651e29c675f397fcd5bc08c Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 15:05:57 -0400 Subject: [PATCH 06/14] allow-read flag for piwo script in run.json --- run.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/run.json b/run.json index fc69ef4..2ef1f2f 100644 --- a/run.json +++ b/run.json @@ -1,7 +1,7 @@ { "scripts": { "dev": "deno run -A --unstable --import-map=./import_map.json ./cli.ts", - "piwo": "deno run --allow-net --no-check --import-map=./import_map.json ./cli.ts", + "piwo": "deno run --allow-net --allow-read --no-check --import-map=./import_map.json ./cli.ts", "test": "deno test --allow-read --import-map=./import_map.json" } } From f7cc0f86da9744093335de286feed0ba4fb872dd Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 15:06:51 -0400 Subject: [PATCH 07/14] update version --- info.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.ts b/info.ts index 825d8bb..41b1502 100644 --- a/info.ts +++ b/info.ts @@ -7,5 +7,5 @@ */ export const name = "Piwo"; -export const version = "v0.4.2"; +export const version = "v0.5.0"; export const filePath = "./request.json"; From a467dae557edbfda517b653f28c2ffddf19afce9 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 15:44:27 -0400 Subject: [PATCH 08/14] docs(run): help command --- commands/help.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/commands/help.ts b/commands/help.ts index 52b8d20..d830e49 100644 --- a/commands/help.ts +++ b/commands/help.ts @@ -7,14 +7,14 @@ */ import { purple, yellow } from "../utils/color/colors.ts"; -import { name } from "../info.ts"; +import { name, filePath } from "../info.ts"; const cliName = name.toLowerCase(); export default `${purple("USAGE:")} - ${cliName} ${yellow("[OPTIONS] [METHOD] [URL] [BODY]")} + ${cliName} ${yellow("[OPTION] [METHOD] [URL] [BODY]")} -${purple("OPTIONS:")} +${purple("OPTION:")} ${yellow("--help, -h")} show help info ${yellow("--version, -v")} show version ${yellow("--form, -f")} send a body as form @@ -27,10 +27,13 @@ ${purple("METHOD:")} ${yellow("DELETE")} ${purple("URL:")} - you can no specify the protocol. + you can no specify the protocol ${purple("BODY:")} send a body as JSON (default) +${purple("RUN COMMAND:")} + ${yellow("run")} a request defined in a ${filePath} file + ${purple("EXAMPLE:")} ${cliName} api.github.com`; From 4b450bfad02ed4bc1d556e19bfee2d0f96e79fcb Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Thu, 16 Sep 2021 17:25:35 -0400 Subject: [PATCH 09/14] docs(run): update readme with the run command feature --- README.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 799b684..59a509f 100644 --- a/README.md +++ b/README.md @@ -12,17 +12,18 @@ request body as JSON. ## Installation ```console -deno install --allow-net --import-map=https://deno.land/x/piwo/import_map.json -n piwo --no-check https://deno.land/x/piwo/cli.ts +deno install --allow-net --allow-read --import-map=https://deno.land/x/piwo/import_map.json -n piwo --no-check https://deno.land/x/piwo/cli.ts ``` The permissions that Piwo uses are: - --allow-net +- --allow-read ## Updating Piwo ```console -deno install -f -r --allow-net --import-map=https://deno.land/x/piwo/import_map.json -n piwo --no-check https://deno.land/x/piwo/cli.ts +deno install -f -r --allow-net --allow-read --import-map=https://deno.land/x/piwo/import_map.json -n piwo --no-check https://deno.land/x/piwo/cli.ts ``` Check if Piwo has been updated @@ -108,6 +109,49 @@ You just need to add the --form flag piwo --form POST localhost:3000/ search_query="foo bar" ``` +## Run command usage + +Create a `request.json` file in your project. +The keys that piwo are expecting from the file are names or aliases that can be called in the console, and this aliases should have as value a init similar to the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#headers) considering that it is not possible to execute javascript code in a json file + +#### Example + +```json +{ + "github": { + "method": "GET", + "url": "https://api.github.com" + } +} +``` + +Run the next code in your command-line: + +```console +piwo run github +``` + +### Send a JSON + +```json +{ + "new-task": { + "method": "POST", + "url": "http://localhost:8080/task/", + "headers": { + "Content-Type": "application/json" + }, + "body": { + "name": "read a json file", + "description": "piwo should read a json file to simplify a request" + } + } +} +``` +```console +piwo run new-task +``` + ## Some nice tips ### How URL argument works From 9f38872e1884aacf21715b32aa2ce908a763ad3d Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Fri, 17 Sep 2021 09:42:03 -0400 Subject: [PATCH 10/14] refactor: protocol output --- utils/customFetch.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/customFetch.ts b/utils/customFetch.ts index f0bad1c..ecdcfc0 100644 --- a/utils/customFetch.ts +++ b/utils/customFetch.ts @@ -68,7 +68,7 @@ export async function customFetch(config: Required): Promise { return { ok: response.ok, - protocol: response.url.includes("https") ? "HTTPS" : "HTTP", + protocol: getProtocol(response.url), status: response.status, headers: parseHeaders(response.headers), body: !form ? data : "", @@ -98,9 +98,11 @@ export async function runFetch(url: string, init: Request): Promise { return { ok: response.ok, - protocol: response.url.includes("https") ? "HTTPS" : "HTTP", + protocol: getProtocol(response.url), status: response.status, headers: parseHeaders(response.headers), body: data, }; } + +const getProtocol = (url: string) => url.startsWith("https") ? "HTTPS" : "HTTP"; From cb28459e45794f14fc46753d578a371f1a8fe4f8 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Fri, 17 Sep 2021 10:35:29 -0400 Subject: [PATCH 11/14] feat(run): send a form --- types.ts | 4 ---- utils/args/body.ts | 9 +++------ utils/formData.ts | 5 +++++ utils/readJson.ts | 18 ++++++++++++------ 4 files changed, 20 insertions(+), 16 deletions(-) create mode 100644 utils/formData.ts diff --git a/types.ts b/types.ts index b418e56..8035377 100644 --- a/types.ts +++ b/types.ts @@ -25,7 +25,3 @@ export interface Args { headers?: Record; command?: string; } - -export interface runJson { - [key:string]: Request; -} \ No newline at end of file diff --git a/utils/args/body.ts b/utils/args/body.ts index 24d3fe4..d7e467f 100644 --- a/utils/args/body.ts +++ b/utils/args/body.ts @@ -6,8 +6,9 @@ * */ -import { dontNeedToBeMutated, readBody, equal } from "./regex.ts"; +import { dontNeedToBeMutated, equal, readBody } from "./regex.ts"; import { red } from "../color/colors.ts"; +import { formData } from "../formData.ts"; export default class Body { static parseToJSON(body: string[]) { @@ -22,12 +23,8 @@ export default class Body { } static parseToFormData(body: string[]) { - const fd = new FormData(); const json = this.parseToJSON(body); - - Object.keys(json).map((key: string) => fd.append(key, json[key])); - - return fd; + return formData(json); } } diff --git a/utils/formData.ts b/utils/formData.ts new file mode 100644 index 0000000..e86e6b4 --- /dev/null +++ b/utils/formData.ts @@ -0,0 +1,5 @@ +export function formData(body: Record) { + const fd = new FormData(); + Object.keys(body).forEach((key: string) => fd.append(key, body[key] as Blob)); + return fd; +} diff --git a/utils/readJson.ts b/utils/readJson.ts index 106c548..208bcd3 100644 --- a/utils/readJson.ts +++ b/utils/readJson.ts @@ -1,7 +1,7 @@ import { red, yellow } from "./color/colors.ts"; -import { runJson } from "../types.ts"; +import { formData } from "./formData.ts"; -export async function readJson(filePath: string): Promise { +export async function readJson(filePath: string) { const decoder = new TextDecoder("utf-8"); const content = decoder.decode(await Deno.readFile(filePath)); @@ -15,7 +15,7 @@ export async function readJson(filePath: string): Promise { } export async function getRequest(alias: string, filePath: string) { - const json = await readJson(filePath) as runJson; + const json = await readJson(filePath); const request = json[alias]; if (!request) { console.error( @@ -27,9 +27,15 @@ export async function getRequest(alias: string, filePath: string) { } if (request.body) { - Object.defineProperty(request, "body", { - value: JSON.stringify(request.body), - }); + const { headers, body } = request; + const contentType = headers?.["Content-Type"] || headers?.["content-type"]; + const formRegex = /application\/x-www-form-urlencoded|multipart\/form-data/; + + if (contentType?.match("application/json")) { + request.body = JSON.stringify(body); + } else if (contentType?.match(formRegex) || !contentType) { + request.body = formData(body); + } } return request; From 451e10225e1526ae7b330f1171b704b366389a01 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Fri, 17 Sep 2021 11:10:43 -0400 Subject: [PATCH 12/14] test(run): send a form --- tests/request.test.json | 27 +++++++++++++++++++++++++++ tests/run.test.ts | 32 +++++++++++++++++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/request.test.json b/tests/request.test.json index 7f37325..447685f 100644 --- a/tests/request.test.json +++ b/tests/request.test.json @@ -13,5 +13,32 @@ "name": "read json file", "description": "make piwo read a json file for doing request running a simple script" } + }, + "foo:undefined": { + "method": "POST", + "url": "http://localhost:8080/", + "body": { + "foo": "bar" + } + }, + "foo:form": { + "method": "POST", + "url": "http://localhost:8080/", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": { + "foo": "bar" + } + }, + "foo:multipart-form": { + "method": "POST", + "url": "http://localhost:8080/", + "headers": { + "Content-Type": "multipart/form-data" + }, + "body": { + "foo": "bar" + } } } \ No newline at end of file diff --git a/tests/run.test.ts b/tests/run.test.ts index b9eb63f..9236b83 100644 --- a/tests/run.test.ts +++ b/tests/run.test.ts @@ -27,6 +27,36 @@ test.assertEqual("run POST: json body to localhost", { description: "make piwo read a json file for doing request running a simple script", }), - } as unknown as Request; + }; + }, +}); + +test.assertEqual("run POST: send form", { + async expect() { + return { + noHeaders: await getRequest("foo:undefined", filePath), + form: await getRequest("foo:form", filePath), + multipartForm: await getRequest("foo:multipart-form", filePath), + }; + }, + toBe() { + const body = new FormData(); + body.append("foo", "bar"); + + const noHeaders = { + method: "POST", + url: "http://localhost:8080/", + body, + }; + + const form = Object.assign({ + headers: { "Content-Type": "application/x-www-form-urlencoded" }, + }, noHeaders); + + const multipartForm = Object.assign({ + headers: { "Content-Type": "multipart/form-data" }, + }, noHeaders); + + return { noHeaders, form, multipartForm }; }, }); From 5d591fb8db4ea8432b0e04490ab41492d629e48b Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Fri, 17 Sep 2021 11:24:02 -0400 Subject: [PATCH 13/14] docs(run): send a form --- README.md | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 59a509f..6f182a5 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ piwo --form POST localhost:3000/ search_query="foo bar" ## Run command usage Create a `request.json` file in your project. -The keys that piwo are expecting from the file are names or aliases that can be called in the console, and this aliases should have as value a init similar to the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#headers) considering that it is not possible to execute javascript code in a json file +The keys that piwo are expecting from the file are names or aliases that can be called in the console, and this aliases should have as value a config similar to the [fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#headers) considering that it is not possible to execute javascript code in a json file #### Example @@ -152,6 +152,26 @@ piwo run github piwo run new-task ``` +### Send a Form + +```json + "foo:form": { + "method": "POST", + "url": "http://localhost:8080/", + "headers": { + "Content-Type": "application/x-www-form-urlencoded" + }, + "body": { + "foo": "bar" + } + } +``` +```console +piwo run foo:form +``` + +`Content-Type` value can be `multipart/form-data`; + ## Some nice tips ### How URL argument works From 66c9b22ffc4daaf55791404224f16d858772e3e2 Mon Sep 17 00:00:00 2001 From: ghaerdi Date: Fri, 17 Sep 2021 11:33:58 -0400 Subject: [PATCH 14/14] test(run): send text and send html --- tests/request.test.json | 16 ++++++++++++++++ tests/run.test.ts | 28 ++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/request.test.json b/tests/request.test.json index 447685f..1903c74 100644 --- a/tests/request.test.json +++ b/tests/request.test.json @@ -40,5 +40,21 @@ "body": { "foo": "bar" } + }, + "foo:text": { + "method": "POST", + "url": "http://localhost:8080/", + "headers": { + "Content-Type": "text/plain" + }, + "body": "bar" + }, + "foo:html": { + "method": "POST", + "url": "http://localhost:8080/", + "headers": { + "Content-Type": "text/html" + }, + "body": "bar" } } \ No newline at end of file diff --git a/tests/run.test.ts b/tests/run.test.ts index 9236b83..39ccb49 100644 --- a/tests/run.test.ts +++ b/tests/run.test.ts @@ -60,3 +60,31 @@ test.assertEqual("run POST: send form", { return { noHeaders, form, multipartForm }; }, }); + +test.assertEqual("run POST: send text", { + async expect() { + return await getRequest("foo:text", filePath) + }, + toBe() { + return { + method: "POST", + url: "http://localhost:8080/", + headers: { "Content-Type": "text/plain" }, + body: "bar" + }; + } +}); + +test.assertEqual("run POST: send html", { + async expect() { + return await getRequest("foo:html", filePath); + }, + toBe() { + return { + method: "POST", + url: "http://localhost:8080/", + headers: { "Content-Type": "text/html" }, + body: "bar", + }; + }, +}); \ No newline at end of file