diff --git a/src/node/api.mjs b/src/node/api.mjs index 4b44daee..e006076a 100644 --- a/src/node/api.mjs +++ b/src/node/api.mjs @@ -96,8 +96,28 @@ const ensureIsDish = function ensureIsDish(input) { return dish; }; +/** + * prepareOp: transform args, make input the right type. + * @param opInstance - instance of the operation + * @param input - operation input + * @param args - operation args + */ +const prepareOp = function prepareOp(opInstance, input, args) { + const dish = ensureIsDish(input); + let transformedArgs; + // Transform object-style args to original args array + if (!Array.isArray(args)) { + transformedArgs = transformArgs(opInstance.args, args); + } else { + transformedArgs = args; + } + const transformedInput = dish.get(opInstance.inputType); + return {transformedInput, transformedArgs}; +}; + /** * Wrap an operation to be consumed by node API. + * Checks to see if run function is async or not. * new Operation().run() becomes operation() * Perform type conversion on input * @private @@ -106,29 +126,47 @@ const ensureIsDish = function ensureIsDish(input) { * some type conversion logic */ export function wrap(OpClass) { - /** - * Wrapped operation run function - * @param {*} input - * @param {Object | String[]} args - either in Object or normal args array - * @returns {SyncDish} operation's output, on a Dish. - * @throws {OperationError} if the operation throws one. - */ - const wrapped = (input, args=null) => { - const operation = new OpClass(); - const dish = ensureIsDish(input); + // Check to see if class's run function is async. + const opInstance = new OpClass(); + const isAsync = opInstance.run.constructor.name === "AsyncFunction"; - // Transform object-style args to original args array - if (!Array.isArray(args)) { - args = transformArgs(operation.args, args); - } - const transformedInput = dish.get(operation.inputType); - const result = operation.run(transformedInput, args); - return new SyncDish({ - value: result, - type: operation.outputType - }); - }; + let wrapped; + + // If async, wrap must be async. + if (isAsync) { + /** + * Async wrapped operation run function + * @param {*} input + * @param {Object | String[]} args - either in Object or normal args array + * @returns {Promise} operation's output, on a Dish. + * @throws {OperationError} if the operation throws one. + */ + wrapped = async (input, args=null) => { + const {transformedInput, transformedArgs} = prepareOp(opInstance, input, args); + const result = await opInstance.run(transformedInput, transformedArgs); + return new SyncDish({ + value: result, + type: opInstance.outputType + }); + }; + } else { + /** + * wrapped operation run function + * @param {*} input + * @param {Object | String[]} args - either in Object or normal args array + * @returns {SyncDish} operation's output, on a Dish. + * @throws {OperationError} if the operation throws one. + */ + wrapped = (input, args=null) => { + const {transformedInput, transformedArgs} = prepareOp(opInstance, input, args); + const result = opInstance.run(transformedInput, transformedArgs); + return new SyncDish({ + value: result, + type: opInstance.outputType + }); + }; + } // used in chef.help wrapped.opName = OpClass.name; diff --git a/test/tests/nodeApi/ops.mjs b/test/tests/nodeApi/ops.mjs index 4343b7df..c1563774 100644 --- a/test/tests/nodeApi/ops.mjs +++ b/test/tests/nodeApi/ops.mjs @@ -118,20 +118,20 @@ Tiger-128`; assert.strictEqual(result.toString(), "Szkkb zh z Xozn"); }), - it("Bcrypt", () => { - const result = chef.bcrypt("Put a Sock In It"); + it("Bcrypt", async () => { + const result = await chef.bcrypt("Put a Sock In It"); assert.strictEqual(result.toString(), "$2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6"); }), - it("bcryptCompare", () => { - const result = chef.bcryptCompare("Put a Sock In It", { + it("bcryptCompare", async() => { + const result = await chef.bcryptCompare("Put a Sock In It", { hash: "$2a$10$2rT4a3XnIecBsd1H33dMTuyYE1HJ1n9F.V2rjQtAH73rh1qvOf/ae", }); assert.strictEqual(result.toString(), "Match: Put a Sock In It"); }), - it("Bcrypt Parse", () => { - const result = chef.bcryptParse("$2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6"); + it("Bcrypt Parse", async () => { + const result = await chef.bcryptParse("$2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6"); const expected = `Rounds: 10 Salt: $2a$10$ODeP1.6fMsb.ENk2ngPUCO Password hash: 7qTGVPyHA9TqDVcyupyed8FjsiF65L6 @@ -567,8 +567,8 @@ Password: 034148`; assert.strictEqual(result.toString(), expected); }), - it("Generate PGP Key Pair", () => { - const result = chef.generatePGPKeyPair("Back To the Drawing Board", { + it("Generate PGP Key Pair", async () => { + const result = await chef.generatePGPKeyPair("Back To the Drawing Board", { keyType: "ECC-256", }); const expected = `-----BEGIN PGP PRIVATE KEY BLOCK----- @@ -772,7 +772,7 @@ CPU assert.strictEqual(result.toString(), expected); }), - it("PGP Encrypt", () => { + it("PGP Encrypt", async () => { const pbkey = `-----BEGIN PGP PUBLIC KEY BLOCK----- Version: GnuPG v1 @@ -793,7 +793,7 @@ jKHiPvjXhSfP3lmrQ7brja9LgSzkiBqQzvPW55G67nGQdUC+mqZNJNlRh+8atf9I =xw3e -----END PGP PUBLIC KEY BLOCK-----`; - const result = chef.PGPEncrypt("A Fool and His Money are Soon Parted", { + const result = await chef.PGPEncrypt("A Fool and His Money are Soon Parted", { publicKeyOfRecipient: pbkey, }); const expected = `-----BEGIN PGP MESSAGE-----