From 19366e3624f20564d3145bead8dd6fc661dc0009 Mon Sep 17 00:00:00 2001 From: d98762625 Date: Fri, 7 Dec 2018 15:46:05 +0000 Subject: [PATCH 1/2] arg array options to wrapped func --- src/node/api.mjs | 26 +++++++++++----- src/node/apiUtils.mjs | 70 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 82 insertions(+), 14 deletions(-) diff --git a/src/node/api.mjs b/src/node/api.mjs index 1f85dc12..322716e4 100644 --- a/src/node/api.mjs +++ b/src/node/api.mjs @@ -11,7 +11,7 @@ import SyncDish from "./SyncDish"; import NodeRecipe from "./NodeRecipe"; import OperationConfig from "./config/OperationConfig.json"; -import { sanitise } from "./apiUtils"; +import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils"; import ExludedOperationError from "../core/errors/ExcludedOperationError"; @@ -58,12 +58,7 @@ function transformArgs(originalArgs, newArgs) { // See Strings op for example. const allArgs = Object.assign([], originalArgs).map((a) => { if (Array.isArray(a.value)) { - a.value = a.value.filter((v) => { - if (typeof v === "string") { - return !v.match(/^\[[\s\S]*\]$/); // Matches anything surrounded in [ ] - } - return true; - }); + a.value = removeSubheadingsFromArray(a.value); } return a; }); @@ -187,6 +182,23 @@ export function wrap(OpClass) { // used in chef.help wrapped.opName = OpClass.name; + + /** */ + const addArgs = (op) => { + const result = {}; + op.args.forEach((a) => { + if (a.type === "option") { + result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.value); + } else if (a.type === "toggleString") { + result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.toggleValues); + } + }); + + return result; + }; + + wrapped.args = addArgs(opInstance); + return wrapped; } diff --git a/src/node/apiUtils.mjs b/src/node/apiUtils.mjs index 87658ce4..b2d88c8b 100644 --- a/src/node/apiUtils.mjs +++ b/src/node/apiUtils.mjs @@ -6,24 +6,61 @@ * @license Apache-2.0 */ + +/** + * someName => Somename + * + * @param {String} str = string to be altered + * @returns {String} + */ +const capitalise = function capitalise(str) { + // Don't edit names that start with 2+ caps + if (/^[A-Z0-9]{2,}/g.test(str)) { + return str; + } + // reserved. Don't change for now. + if (str === "Return") { + return str; + } + + return `${str.charAt(0).toUpperCase()}${str.substr(1).toLowerCase()}`; +}; + + /** * SomeName => someName * @param {String} name - string to be altered * @returns {String} decapitalised */ -export function decapitalise(name) { - // Don't decapitalise names that start with 2+ caps - if (/^[A-Z0-9]{2,}/g.test(name)) { - return name; +export function decapitalise(str) { + // Don't decapitalise str that start with 2+ caps + if (/^[A-Z0-9]{2,}/g.test(str)) { + return str; } // reserved. Don't change for now. - if (name === "Return") { - return name; + if (str === "Return") { + return str; } - return `${name.charAt(0).toLowerCase()}${name.substr(1)}`; + return `${str.charAt(0).toLowerCase()}${str.substr(1)}`; } + +/** + * Remove strings surrounded with [] from the given array. +*/ +export function removeSubheadingsFromArray(array) { + if (Array.isArray(array)) { + return array.filter((i) => { + if (typeof i === "string") { + return !i.match(/^\[[\s\S]*\]$/); + } + return true; + }); + } +} + + /** * Remove spaces, make lower case. * @param str @@ -31,3 +68,22 @@ export function decapitalise(name) { export function sanitise(str) { return str.replace(/ /g, "").toLowerCase(); } + + +/** + * sonething like this => somethingLikeThis + * ABC a sentence => ABCASentence +*/ +export function sentenceToCamelCase(str) { + return str.split(" ") + .map((s, index) => { + if (index === 0) { + return decapitalise(s); + } + return capitalise(s); + }) + .reduce((prev, curr) => `${prev}${curr}`, ""); +} + + + From a010bba04740ad0ee22346f9067c6e25373cc353 Mon Sep 17 00:00:00 2001 From: d98762625 Date: Fri, 21 Dec 2018 09:46:30 +0000 Subject: [PATCH 2/2] add test and change name of property to argOptions --- src/node/api.mjs | 52 +++++++++++++++++++++++----------- test/tests/nodeApi/nodeApi.mjs | 20 +++++++++++++ 2 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/node/api.mjs b/src/node/api.mjs index 322716e4..ac0ac205 100644 --- a/src/node/api.mjs +++ b/src/node/api.mjs @@ -91,6 +91,7 @@ function transformArgs(originalArgs, newArgs) { return allArgs.map(extractArg); } + /** * Ensure an input is a SyncDish object. * @param input @@ -107,6 +108,7 @@ function ensureIsDish(input) { } } + /** * prepareOp: transform args, make input the right type. * Also convert any Buffers to ArrayBuffers. @@ -127,6 +129,32 @@ function prepareOp(opInstance, input, args) { return {transformedInput, transformedArgs}; } + +/** + * createArgOptions + * + * Create an object of options for each option or togglestring argument + * in the given operation. + * + * Argument names are converted to camel case for consistency. + * + * @param {Operation} op - the operation to extract args from + * @returns {{}} - arrays of options for option and toggleString args. +*/ +function createArgOptions(op) { + const result = {}; + op.args.forEach((a) => { + if (a.type === "option") { + result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.value); + } else if (a.type === "toggleString") { + result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.toggleValues); + } + }); + + return result; +} + + /** * Wrap an operation to be consumed by node API. * Checks to see if run function is async or not. @@ -182,30 +210,16 @@ export function wrap(OpClass) { // used in chef.help wrapped.opName = OpClass.name; - - /** */ - const addArgs = (op) => { - const result = {}; - op.args.forEach((a) => { - if (a.type === "option") { - result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.value); - } else if (a.type === "toggleString") { - result[sentenceToCamelCase(a.name)] = removeSubheadingsFromArray(a.toggleValues); - } - }); - - return result; - }; - - wrapped.args = addArgs(opInstance); + wrapped.argOptions = createArgOptions(opInstance); return wrapped; } + /** - * @namespace Api * 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[]} Config of matching operations. @@ -260,6 +274,7 @@ export function help(input) { return null; } + /** * bake [Wrapped] - Perform an array of operations on some input. * @param operations array of chef's operations (used in wrapping stage) @@ -283,7 +298,10 @@ export function bake(operations){ }; } + /** + * explainExcludedFunction + * * Explain that the given operation is not included in the Node.js version. * @param {String} name - name of operation */ diff --git a/test/tests/nodeApi/nodeApi.mjs b/test/tests/nodeApi/nodeApi.mjs index 2d1d57aa..7069d2e3 100644 --- a/test/tests/nodeApi/nodeApi.mjs +++ b/test/tests/nodeApi/nodeApi.mjs @@ -383,6 +383,26 @@ TestRegister.addApiTests([ assert.strictEqual(e.type, "ExcludedOperationError"); assert.strictEqual(e.message, "Sorry, the RenderImage operation is not available in the Node.js version of CyberChef."); } + }), + + it("Operation arguments: should be accessible from operation object if op has array arg", () => { + assert.ok(chef.toCharcode.argOptions); + assert.equal(chef.unzip.argOptions, undefined); + }), + + it("Operation arguments: should have key for each array-based argument in operation", () => { + assert.ok(chef.convertDistance.argOptions.inputUnits); + assert.ok(chef.convertDistance.argOptions.outputUnits); + + assert.ok(chef.bitShiftRight.argOptions.type); + // is a number type, so not included. + assert.equal(chef.bitShiftRight.argOptions.amount, undefined); + }), + + it("Operation arguments: should list all options excluding subheadings", () => { + // First element (subheading) removed + assert.equal(chef.convertDistance.argOptions.inputUnits[0], "Nanometres (nm)"); + assert.equal(chef.defangURL.argOptions.process[1], "Only full URLs"); }) ]);