From 63a23e4dccd0763c28305375c686ca3954ebfeae Mon Sep 17 00:00:00 2001 From: d98762625 Date: Tue, 4 Sep 2018 09:33:49 +0100 Subject: [PATCH] make chef.help emulate search function in UI. Didnt extract search logic from web as it is fairly entwined. --- src/node/SyncDish.mjs | 6 +--- src/node/api.mjs | 63 ++++++++++++++++++++++++++-------- src/node/index.mjs | 2 +- test/tests/nodeApi/nodeApi.mjs | 37 +++++++++++++++----- test/tests/nodeApi/ops.mjs | 2 +- 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/node/SyncDish.mjs b/src/node/SyncDish.mjs index a6d0a984..70f1e807 100644 --- a/src/node/SyncDish.mjs +++ b/src/node/SyncDish.mjs @@ -20,7 +20,7 @@ class SyncDish extends Dish { /** */ constructor(inputOrDish=null, type=null) { super(inputOrDish); - + // Add operations to make it composable for (const op in ops) { this[op] = () => ops[op](this.value); @@ -174,8 +174,4 @@ class SyncDish extends Dish { } } - - - - export default SyncDish; diff --git a/src/node/api.mjs b/src/node/api.mjs index fd01dbc9..bedff90e 100644 --- a/src/node/api.mjs +++ b/src/node/api.mjs @@ -6,6 +6,9 @@ * @license Apache-2.0 */ +/*eslint no-console: ["off"] */ + + import Dish from "../core/Dish"; import SyncDish from "./SyncDish"; import NodeRecipe from "./NodeRecipe"; @@ -199,29 +202,59 @@ export function wrap(OpClass) { /** * @namespace Api - * @param {String} searchTerm - the name of the operation to get help for. + * help: Give information about operations matching the given search term, + * or inputted operation. + * @param {String || wrapped operation} input - the name of the operation to get help for. * Case and whitespace are ignored in search. - * @returns {Object} Describe function matching searchTerm. + * @returns {Object[]} Config of matching operations. */ -export function help(searchTerm) { - let sanitised = false; - if (typeof searchTerm === "string") { - sanitised = searchTerm; - } else if (typeof searchTerm === "function") { - sanitised = searchTerm.opName; +export function help(input) { + let searchTerm = false; + if (typeof input === "string") { + searchTerm = input; + } else if (typeof input === "function") { + searchTerm = input.opName; } - if (!sanitised) { + if (!searchTerm) { return null; } - const key = Object.keys(OperationConfig) - .find(o => sanitise(o) === sanitise(sanitised)); - if (key) { - const result = OperationConfig[key]; - result.name = key; - return result; + // Look for matches in operation name and description, listing name + // matches first. + const matches = Object.keys(OperationConfig) + // hydrate operation: swap op name for op config object (with name) + .map((m) => { + const hydrated = OperationConfig[m]; + hydrated.name = m; + + // Return hydrated along with what type of match it was + return { + hydrated, + nameMatch: sanitise(hydrated.name).includes(sanitise(searchTerm)), + descMatch: sanitise(hydrated.description).includes(sanitise(searchTerm)) + }; + }) + // Filter out non-matches + .filter((result) => { + return result.nameMatch || result.descMatch; + }) + // sort results with name match first + .sort((a, b) => { + const aInt = a.nameMatch ? 1 : 0; + const bInt = b.nameMatch ? 1 : 0; + return bInt - aInt; + }) + // extract just the hydrated config + .map(result => result.hydrated); + + // Concatenate matches but remove duplicates + if (matches && matches.length) { + console.log(`${matches.length} results found.`); + return matches; } + + console.log("No results found."); return null; } diff --git a/src/node/index.mjs b/src/node/index.mjs index 7a593826..7366d2fc 100644 --- a/src/node/index.mjs +++ b/src/node/index.mjs @@ -1045,7 +1045,7 @@ const operations = [ ]; const prebaked = bake(operations); -chef.bake = prebaked +chef.bake = prebaked; export default chef; // Operations as top level exports. diff --git a/test/tests/nodeApi/nodeApi.mjs b/test/tests/nodeApi/nodeApi.mjs index 24145846..59747ea5 100644 --- a/test/tests/nodeApi/nodeApi.mjs +++ b/test/tests/nodeApi/nodeApi.mjs @@ -115,12 +115,12 @@ TestRegister.addApiTests([ it("chef.help: should describe a operation", () => { const result = chef.help("tripleDESDecrypt"); - assert.strictEqual(result.name, "Triple DES Decrypt"); - assert.strictEqual(result.module, "Ciphers"); - assert.strictEqual(result.inputType, "string"); - assert.strictEqual(result.outputType, "string"); - assert.strictEqual(result.description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."); - assert.strictEqual(result.args.length, 5); + assert.strictEqual(result[0].name, "Triple DES Decrypt"); + assert.strictEqual(result[0].module, "Ciphers"); + assert.strictEqual(result[0].inputType, "string"); + assert.strictEqual(result[0].outputType, "string"); + assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."); + assert.strictEqual(result[0].args.length, 5); }), it("chef.help: null for invalid operation", () => { @@ -130,8 +130,29 @@ TestRegister.addApiTests([ it("chef.help: takes a wrapped operation as input", () => { const result = chef.help(chef.toBase32); - assert.strictEqual(result.name, "To Base32"); - assert.strictEqual(result.module, "Default"); + assert.strictEqual(result[0].name, "To Base32"); + assert.strictEqual(result[0].module, "Default"); + }), + + it("chef.help: returns multiple results", () => { + const result = chef.help("base 64"); + assert.strictEqual(result.length, 8); + }), + + it("chef.help: looks in description for matches too", () => { + // string only in one operation's description. + const result = chef.help("Converts a unit of data to another format."); + assert.strictEqual(result.length, 1); + assert.strictEqual(result[0].name, "Convert data units"); + }), + + it("chef.help: lists name matches before desc matches", () => { + const result = chef.help("MD5"); + assert.ok(result[0].name.includes("MD5")); + assert.strictEqual(result[1].name.includes("MD5"), false); + assert.strictEqual(result[2].name.includes("MD5"), false); + assert.ok(result[1].description.includes("MD5")); + assert.ok(result[2].description.includes("MD5")); }), it("chef.bake: should exist", () => { diff --git a/test/tests/nodeApi/ops.mjs b/test/tests/nodeApi/ops.mjs index e0793295..70a6ceac 100644 --- a/test/tests/nodeApi/ops.mjs +++ b/test/tests/nodeApi/ops.mjs @@ -512,7 +512,7 @@ Top Drawer`, { const expected = "{\"dataLength\":43,\"percentages\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13.953488372093023,0,0,0,0,0,0,2.3255813953488373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2.3255813953488373,4.651162790697675,2.3255813953488373,0,0,0,2.3255813953488373,0,0,0,0,0,0,0,0,0,0,0,2.3255813953488373,0,0,0,0,2.3255813953488373,0,0,0,0,0,0,0,2.3255813953488373,0,4.651162790697675,0,9.30232558139535,2.3255813953488373,0,6.976744186046512,2.3255813953488373,0,2.3255813953488373,0,0,6.976744186046512,9.30232558139535,0,0,4.651162790697675,2.3255813953488373,6.976744186046512,4.651162790697675,0,0,0,2.3255813953488373,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"distribution\":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,4,1,0,3,1,0,1,0,0,3,4,0,0,2,1,3,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],\"bytesRepresented\":22}"; assert.strictEqual(result.toString(), expected); }), - + it("From base", () => { assert.strictEqual(chef.fromBase("11", {radix: 13}).toString(), "14"); }),