diff --git a/src/node/NodeRecipe.mjs b/src/node/NodeRecipe.mjs index bad8fc27..ade9ecb5 100644 --- a/src/node/NodeRecipe.mjs +++ b/src/node/NodeRecipe.mjs @@ -88,16 +88,17 @@ class NodeRecipe { * @param {NodeDish} dish * @returns {NodeDish} */ - execute(dish) { - return this.opList.reduce((prev, curr) => { - // CASE where opList item is op and args + async execute(dish) { + let prev = dish; + for (const curr of this.opList) { if (Object.prototype.hasOwnProperty.call(curr, "op") && Object.prototype.hasOwnProperty.call(curr, "args")) { - return curr.op(prev, curr.args); + prev = await curr.op(prev, curr.args); + } else { + prev = await curr(prev); } - // CASE opList item is just op. - return curr(prev); - }, dish); + } + return prev; } } diff --git a/src/node/api.mjs b/src/node/api.mjs index 88b3f834..a02af9d3 100644 --- a/src/node/api.mjs +++ b/src/node/api.mjs @@ -324,10 +324,10 @@ export function help(input) { * @returns {NodeDish} of the result * @throws {TypeError} if invalid recipe given. */ -export function bake(input, recipeConfig) { - const recipe = new NodeRecipe(recipeConfig); +export async function bake(input, recipeConfig) { + const recipe = new NodeRecipe(recipeConfig); const dish = ensureIsDish(input); - return recipe.execute(dish); + return await recipe.execute(dish); } diff --git a/tests/node/consumers/cjs-consumer.js b/tests/node/consumers/cjs-consumer.js index 3a759481..f13d9c35 100644 --- a/tests/node/consumers/cjs-consumer.js +++ b/tests/node/consumers/cjs-consumer.js @@ -8,9 +8,9 @@ const assert = require("assert"); -require("cyberchef").then(chef => { +require("cyberchef").then(async chef => { - const d = chef.bake("Testing, 1 2 3", [ + const d = await chef.bake("Testing, 1 2 3", [ chef.toHex, chef.reverse, { diff --git a/tests/node/consumers/esm-consumer.mjs b/tests/node/consumers/esm-consumer.mjs index 2919e533..3a2648e1 100644 --- a/tests/node/consumers/esm-consumer.mjs +++ b/tests/node/consumers/esm-consumer.mjs @@ -9,7 +9,7 @@ import assert from "assert"; import chef from "cyberchef"; import { bake, toHex, reverse, unique, multiply } from "cyberchef"; -const a = bake("Testing, 1 2 3", [ +const a = await bake("Testing, 1 2 3", [ toHex, reverse, { @@ -28,7 +28,7 @@ const a = bake("Testing, 1 2 3", [ assert.equal(a.value, "630957449041920"); -const b = chef.bake("Testing, 1 2 3", [ +const b = await chef.bake("Testing, 1 2 3", [ chef.toHex, chef.reverse, { diff --git a/tests/node/tests/nodeApi.mjs b/tests/node/tests/nodeApi.mjs index 92d4d991..2510ef17 100644 --- a/tests/node/tests/nodeApi.mjs +++ b/tests/node/tests/nodeApi.mjs @@ -170,77 +170,77 @@ TestRegister.addApiTests([ assert(chef.bake); }), - it("chef.bake: should return NodeDish", () => { - const result = chef.bake("input", "to base 64"); + it("chef.bake: should return NodeDish", async () => { + const result = await chef.bake("input", "to base 64"); assert(result instanceof NodeDish); }), - it("chef.bake: should take an input and an op name and perform it", () => { - const result = chef.bake("some input", "to base 32"); + it("chef.bake: should take an input and an op name and perform it", async () => { + const result = await chef.bake("some input", "to base 32"); assert.strictEqual(result.toString(), "ONXW2ZJANFXHA5LU"); }), - it("chef.bake: should complain if recipe isnt a valid object", () => { - assert.throws(() => chef.bake("some input", 3264), { + it("chef.bake: should complain if recipe isnt a valid object", async () => { + await assert.rejects(() => chef.bake("some input", 3264), { name: "TypeError", message: "Recipe can only contain function names or functions" }); }), - it("chef.bake: Should complain if string op is invalid", () => { - assert.throws(() => chef.bake("some input", "not a valid operation"), { + it("chef.bake: Should complain if string op is invalid", async () => { + await assert.rejects(() => chef.bake("some input", "not a valid operation"), { name: "TypeError", message: "Couldn't find an operation with name 'not a valid operation'." }); }), - it("chef.bake: Should take an input and an operation and perform it", () => { - const result = chef.bake("https://google.com/search?q=help", chef.parseURI); + it("chef.bake: Should take an input and an operation and perform it", async () => { + const result = await chef.bake("https://google.com/search?q=help", chef.parseURI); assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = help\n"); }), - it("chef.bake: Should complain if an invalid operation is inputted", () => { - assert.throws(() => chef.bake("https://google.com/search?q=help", () => {}), { + it("chef.bake: Should complain if an invalid operation is inputted", async () => { + await assert.rejects(() => chef.bake("https://google.com/search?q=help", () => {}), { name: "TypeError", message: "Inputted function not a Chef operation." }); }), - it("chef.bake: accepts an array of operation names and performs them all in order", () => { - const result = chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]); + it("chef.bake: accepts an array of operation names and performs them all in order", async () => { + const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]); assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n"); }), - it("chef.bake: forgiving with operation names", () =>{ - const result = chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]); + it("chef.bake: forgiving with operation names", async () =>{ + const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]); assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n"); }), - it("chef.bake: forgiving with operation names", () =>{ - const result = chef.bake("hello", ["to base 64"]); + it("chef.bake: forgiving with operation names", async () =>{ + const result = await chef.bake("hello", ["to base 64"]); assert.strictEqual(result.toString(), "aGVsbG8="); }), - it("chef.bake: if recipe is empty array, return input as dish", () => { - const result = chef.bake("some input", []); + it("chef.bake: if recipe is empty array, return input as dish", async () => { + const result = await chef.bake("some input", []); assert.strictEqual(result.toString(), "some input"); assert(result instanceof NodeDish, "Result is not instance of NodeDish"); }), - it("chef.bake: accepts an array of operations as recipe", () => { - const result = chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]); + it("chef.bake: accepts an array of operations as recipe", async () => { + const result = await chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]); assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n"); }), - it("should complain if an invalid operation is inputted as part of array", () => { - assert.throws(() => chef.bake("something", [() => {}]), { + it("should complain if an invalid operation is inputted as part of array", async () => { + await assert.rejects(() => chef.bake("something", [() => {}]), { name: "TypeError", message: "Inputted function not a Chef operation." }); }), - it("chef.bake: should take single JSON object describing op and args OBJ", () => { - const result = chef.bake("some input", { + it("chef.bake: should take single JSON object describing op and args OBJ", async () => { + const result = await chef.bake("some input", { op: chef.toHex, args: { Delimiter: "Colon" @@ -249,23 +249,23 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74"); }), - it("chef.bake: should take single JSON object desribing op with optional args", () => { - const result = chef.bake("some input", { + it("chef.bake: should take single JSON object desribing op with optional args", async () => { + const result = await chef.bake("some input", { op: chef.toHex, }); assert.strictEqual(result.toString(), "73 6f 6d 65 20 69 6e 70 75 74"); }), - it("chef.bake: should take single JSON object describing op and args ARRAY", () => { - const result = chef.bake("some input", { + it("chef.bake: should take single JSON object describing op and args ARRAY", async () => { + const result = await chef.bake("some input", { op: chef.toHex, args: ["Colon"] }); assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74"); }), - it("chef.bake: should error if op in JSON is not chef op", () => { - assert.throws(() => chef.bake("some input", { + it("chef.bake: should error if op in JSON is not chef op", async () => { + await assert.rejects(() => chef.bake("some input", { op: () => {}, args: ["Colon"], }), { @@ -274,8 +274,8 @@ TestRegister.addApiTests([ }); }), - it("chef.bake: should take multiple ops in JSON object form, some ops by string", () => { - const result = chef.bake("some input", [ + it("chef.bake: should take multiple ops in JSON object form, some ops by string", async () => { + const result = await chef.bake("some input", [ { op: chef.toHex, args: ["Colon"] @@ -290,8 +290,8 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "67;63;72;66;146;72;66;144;72;66;65;72;62;60;72;66;71;72;66;145;72;67;60;72;67;65;72;67;64"); }), - it("chef.bake: should take multiple ops in JSON object form, some without args", () => { - const result = chef.bake("some input", [ + it("chef.bake: should take multiple ops in JSON object form, some without args", async () => { + const result = await chef.bake("some input", [ { op: chef.toHex, }, @@ -305,8 +305,8 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "67;63;40;66;146;40;66;144;40;66;65;40;62;60;40;66;71;40;66;145;40;67;60;40;67;65;40;67;64"); }), - it("chef.bake: should handle op with multiple args", () => { - const result = chef.bake("some input", { + it("chef.bake: should handle op with multiple args", async () => { + const result = await chef.bake("some input", { op: "to morse code", args: { formatOptions: "Dash/Dot", @@ -317,13 +317,13 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "DotDotDot\\DashDashDash\\DashDash\\Dot,DotDot\\DashDot\\DotDashDashDot\\DotDotDash\\Dash"); }), - it("chef.bake: should take compact JSON format from Chef Website as recipe", () => { - const result = chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]); + it("chef.bake: should take compact JSON format from Chef Website as recipe", async () => { + const result = await chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]); assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something"); }), - it("chef.bake: should accept Clean JSON format from Chef website as recipe", () => { - const result = chef.bake("some input", [ + it("chef.bake: should accept Clean JSON format from Chef website as recipe", async () => { + const result = await chef.bake("some input", [ { "op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"] }, { "op": "Hex to PEM", @@ -334,8 +334,8 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something"); }), - it("chef.bake: should accept Clean JSON format from Chef website - args optional", () => { - const result = chef.bake("some input", [ + it("chef.bake: should accept Clean JSON format from Chef website - args optional", async () => { + const result = await chef.bake("some input", [ { "op": "To Morse Code" }, { "op": "Hex to PEM", "args": ["SOMETHING"] }, @@ -345,31 +345,28 @@ TestRegister.addApiTests([ assert.strictEqual(result.toString(), "begin_something_aaaaaaaaaaaaaa_end_something"); }), - it("chef.bake: should accept operation names from Chef Website which contain forward slash", () => { - const result = chef.bake("I'll have the test salmon", [ + it("chef.bake: should accept operation names from Chef Website which contain forward slash", async () => { + const result = await chef.bake("I'll have the test salmon", [ { "op": "Find / Replace", "args": [{ "option": "Regex", "string": "test" }, "good", true, false, true, false]} ]); assert.strictEqual(result.toString(), "I'll have the good salmon"); }), - it("chef.bake: should accept operation names from Chef Website which contain a hyphen", () => { - const result = chef.bake("I'll have the test salmon", [ + it("chef.bake: should accept operation names from Chef Website which contain a hyphen", async () => { + const result = await chef.bake("I'll have the test salmon", [ { "op": "Adler-32 Checksum", "args": [] } ]); assert.strictEqual(result.toString(), "6e4208f8"); }), - it("chef.bake: should accept operation names from Chef Website which contain a period", () => { - const result = chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [ + it("chef.bake: should accept operation names from Chef Website which contain a period", async () => { + const result = await chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [ { "op": "Parse ASN.1 hex string", "args": [0, 32] } ]); - assert.strictEqual(result.toString(), `SEQUENCE - INTEGER 05 - IA5String 'Anybody there?' -`); + assert.strictEqual(result.toString(), `SEQUENCE\n INTEGER 05\n IA5String 'Anybody there?'\n`); }), it("Excluded operations: throw a sensible error when you try and call one", () => { @@ -381,16 +378,16 @@ TestRegister.addApiTests([ } }), - it("chef.bake: cannot accept flowControl operations in recipe", () => { - assert.throws(() => chef.bake("some input", "magic"), { + it("chef.bake: cannot accept flowControl operations in recipe", async () => { + await assert.rejects(() => chef.bake("some input", "magic"), { name: "TypeError", message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API" }); - assert.throws(() => chef.bake("some input", magic), { + await assert.rejects(() => chef.bake("some input", magic), { name: "TypeError", message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API" }); - assert.throws(() => chef.bake("some input", ["to base 64", "magic"]), { + await assert.rejects(() => chef.bake("some input", ["to base 64", "magic"]), { name: "TypeError", message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API" });