diff --git a/CHANGELOG.md b/CHANGELOG.md index 82e42b3d..9bd0ec4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All notable changes to this project will be documented in this file. +### [8.3.0] - 2018-08-21 +- 'To MessagePack' and 'From MessagePack' operations added @artemisbot #338 + ### [8.2.0] - 2018-08-21 - Added information links to most operations, accessible in the description popover @PenguinGeorge #298 diff --git a/package-lock.json b/package-lock.json index 9f1b13bb..7f2fa5f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7566,6 +7566,11 @@ "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", "dev": true }, + "notepack.io": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/notepack.io/-/notepack.io-2.1.3.tgz", + "integrity": "sha512-AgSt+cP5XMooho1Ppn8NB3FFaVWefV+qZoZncYTUSch2GAEwlYLcIIbT5YVkMlFeNHnfwOvc4HDlbvrB5BRxXA==" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", diff --git a/package.json b/package.json index b7918e77..f172ce5a 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "moment-timezone": "^0.5.21", "node-forge": "^0.7.5", "node-md6": "^0.1.0", + "notepack.io": "^2.1.3", "nwmatcher": "^1.4.4", "otp": "^0.1.3", "popper.js": "^1.14.4", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 56de45d9..3e0d9145 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -47,7 +47,9 @@ "Change IP format", "Encode text", "Decode text", - "Swap endianness" + "Swap endianness", + "To MessagePack", + "From MessagePack" ] }, { @@ -313,7 +315,9 @@ "To Camel case", "To Kebab case", "BSON serialise", - "BSON deserialise" + "BSON deserialise", + "To MessagePack", + "From MessagePack" ] }, { diff --git a/src/core/operations/FromMessagePack.mjs b/src/core/operations/FromMessagePack.mjs new file mode 100644 index 00000000..cea7c498 --- /dev/null +++ b/src/core/operations/FromMessagePack.mjs @@ -0,0 +1,47 @@ +/** + * @author Matt C [matt@artemisbot.uk] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; +import notepack from "notepack.io"; + +/** + * From MessagePack operation + */ +class FromMessagePack extends Operation { + + /** + * FromMessagePack constructor + */ + constructor() { + super(); + + this.name = "From MessagePack"; + this.module = "Code"; + this.description = "Converts MessagePack encoded data to JSON. MessagePack is a computer data interchange format. It is a binary form for representing simple data structures like arrays and associative arrays."; + this.infoURL = "https://wikipedia.org/wiki/MessagePack"; + this.inputType = "ArrayBuffer"; + this.outputType = "JSON"; + this.args = []; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {JSON} + */ + run(input, args) { + try { + const buf = Buffer.from(new Uint8Array(input)); + return notepack.decode(buf); + } catch (err) { + throw new OperationError(`Could not decode MessagePack to JSON: ${err}`); + } + } + +} + +export default FromMessagePack; diff --git a/src/core/operations/ToMessagePack.mjs b/src/core/operations/ToMessagePack.mjs new file mode 100644 index 00000000..40e31a41 --- /dev/null +++ b/src/core/operations/ToMessagePack.mjs @@ -0,0 +1,50 @@ +/** + * @author Matt C [matt@artemisbot.uk] + * @copyright Crown Copyright 2018 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError.mjs"; +import notepack from "notepack.io"; + +/** + * To MessagePack operation + */ +class ToMessagePack extends Operation { + + /** + * ToMessagePack constructor + */ + constructor() { + super(); + + this.name = "To MessagePack"; + this.module = "Code"; + this.description = "Converts JSON to MessagePack encoded byte buffer. MessagePack is a computer data interchange format. It is a binary form for representing simple data structures like arrays and associative arrays."; + this.infoURL = "https://wikipedia.org/wiki/MessagePack"; + this.inputType = "JSON"; + this.outputType = "ArrayBuffer"; + this.args = []; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {ArrayBuffer} + */ + run(input, args) { + try { + if (ENVIRONMENT_IS_WORKER()) { + return notepack.encode(input); + } else { + return notepack.encode(input).buffer; + } + } catch (err) { + throw new OperationError(`Could not encode JSON to MessagePack: ${err}`); + } + } + +} + +export default ToMessagePack; diff --git a/test/tests/operations/Code.mjs b/test/tests/operations/Code.mjs index 3b282b67..2d935ee6 100644 --- a/test/tests/operations/Code.mjs +++ b/test/tests/operations/Code.mjs @@ -9,7 +9,7 @@ */ import TestRegister from "../../TestRegister"; -const JPATH_TEST_DATA = { +const JSON_TEST_DATA = { "store": { "book": [{ "category": "reference", @@ -184,7 +184,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: Empty expression", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: "Invalid JPath expression: we need a path", recipeConfig: [ { @@ -195,7 +195,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: Fetch of values from specific object", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "\"Nigel Rees\"", "\"Evelyn Waugh\"", @@ -211,7 +211,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: Fetch of all values with matching key", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "\"Sayings of the Century\"", "\"Sword of Honour\"", @@ -229,7 +229,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: All data in object", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}]", "{\"color\":\"red\",\"price\":19.95}", @@ -244,7 +244,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: Last element in array", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: "{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}", recipeConfig: [ { @@ -255,7 +255,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: First 2 elements in array", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95}", "{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}" @@ -269,7 +269,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: All elements in array with property", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}", "{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}" @@ -283,7 +283,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: All elements in array which meet condition", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}", "{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}", @@ -298,7 +298,7 @@ TestRegister.addTests([ }, { name: "JPath Expression: All elements in object", - input: JSON.stringify(JPATH_TEST_DATA), + input: JSON.stringify(JSON_TEST_DATA), expectedOutput: [ "{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95}", "{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}" @@ -331,5 +331,65 @@ TestRegister.addTests([ "args": ["/div/p[@class=\"a\"]", "\\n"] } ] + }, + { + name: "To MessagePack: no content", + input: "", + expectedError: true, + recipeConfig: [ + { + "op": "To MessagePack", + "args": [] + }, + { + "op": "To Hex", + "args": ["Space"] + } + ] + }, + { + name: "From MessagePack: no content", + input: "", + expectedOutput: "Could not decode MessagePack to JSON: Error: Could not parse", + recipeConfig: [ + { + "op": "From Hex", + "args": ["Space"] + }, + { + "op": "From MessagePack", + "args": [] + } + ] + }, + { + name: "To MessagePack: valid json", + input: JSON.stringify(JSON_TEST_DATA), + expectedOutput: "81 a5 73 74 6f 72 65 83 a4 62 6f 6f 6b 94 84 a8 63 61 74 65 67 6f 72 79 a9 72 65 66 65 72 65 6e 63 65 a6 61 75 74 68 6f 72 aa 4e 69 67 65 6c 20 52 65 65 73 a5 74 69 74 6c 65 b6 53 61 79 69 6e 67 73 20 6f 66 20 74 68 65 20 43 65 6e 74 75 72 79 a5 70 72 69 63 65 cb 40 21 e6 66 66 66 66 66 84 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 ac 45 76 65 6c 79 6e 20 57 61 75 67 68 a5 74 69 74 6c 65 af 53 77 6f 72 64 20 6f 66 20 48 6f 6e 6f 75 72 a5 70 72 69 63 65 cb 40 29 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 af 48 65 72 6d 61 6e 20 4d 65 6c 76 69 6c 6c 65 a5 74 69 74 6c 65 a9 4d 6f 62 79 20 44 69 63 6b a4 69 73 62 6e ad 30 2d 35 35 33 2d 32 31 33 31 31 2d 33 a5 70 72 69 63 65 cb 40 21 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 b0 4a 2e 20 52 2e 20 52 2e 20 54 6f 6c 6b 69 65 6e a5 74 69 74 6c 65 b5 54 68 65 20 4c 6f 72 64 20 6f 66 20 74 68 65 20 52 69 6e 67 73 a4 69 73 62 6e ad 30 2d 33 39 35 2d 31 39 33 39 35 2d 38 a5 70 72 69 63 65 cb 40 36 fd 70 a3 d7 0a 3d a7 62 69 63 79 63 6c 65 82 a5 63 6f 6c 6f 72 a3 72 65 64 a5 70 72 69 63 65 cb 40 33 f3 33 33 33 33 33 a9 6e 65 77 73 70 61 70 65 72 92 83 a6 66 6f 72 6d 61 74 aa 62 72 6f 61 64 73 68 65 65 74 a5 74 69 74 6c 65 af 46 69 6e 61 6e 63 69 61 6c 20 54 69 6d 65 73 a5 70 72 69 63 65 cb 40 06 00 00 00 00 00 00 83 a6 66 6f 72 6d 61 74 a7 74 61 62 6c 6f 69 64 a5 74 69 74 6c 65 ac 54 68 65 20 47 75 61 72 64 69 61 6e a5 70 72 69 63 65 02", + recipeConfig: [ + { + "op": "To MessagePack", + "args": [] + }, + { + "op": "To Hex", + "args": ["Space"] + } + ] + }, + { + name: "From MessagePack: valid msgpack", + input: "81 a5 73 74 6f 72 65 83 a4 62 6f 6f 6b 94 84 a8 63 61 74 65 67 6f 72 79 a9 72 65 66 65 72 65 6e 63 65 a6 61 75 74 68 6f 72 aa 4e 69 67 65 6c 20 52 65 65 73 a5 74 69 74 6c 65 b6 53 61 79 69 6e 67 73 20 6f 66 20 74 68 65 20 43 65 6e 74 75 72 79 a5 70 72 69 63 65 cb 40 21 e6 66 66 66 66 66 84 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 ac 45 76 65 6c 79 6e 20 57 61 75 67 68 a5 74 69 74 6c 65 af 53 77 6f 72 64 20 6f 66 20 48 6f 6e 6f 75 72 a5 70 72 69 63 65 cb 40 29 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 af 48 65 72 6d 61 6e 20 4d 65 6c 76 69 6c 6c 65 a5 74 69 74 6c 65 a9 4d 6f 62 79 20 44 69 63 6b a4 69 73 62 6e ad 30 2d 35 35 33 2d 32 31 33 31 31 2d 33 a5 70 72 69 63 65 cb 40 21 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 b0 4a 2e 20 52 2e 20 52 2e 20 54 6f 6c 6b 69 65 6e a5 74 69 74 6c 65 b5 54 68 65 20 4c 6f 72 64 20 6f 66 20 74 68 65 20 52 69 6e 67 73 a4 69 73 62 6e ad 30 2d 33 39 35 2d 31 39 33 39 35 2d 38 a5 70 72 69 63 65 cb 40 36 fd 70 a3 d7 0a 3d a7 62 69 63 79 63 6c 65 82 a5 63 6f 6c 6f 72 a3 72 65 64 a5 70 72 69 63 65 cb 40 33 f3 33 33 33 33 33 a9 6e 65 77 73 70 61 70 65 72 92 83 a6 66 6f 72 6d 61 74 aa 62 72 6f 61 64 73 68 65 65 74 a5 74 69 74 6c 65 af 46 69 6e 61 6e 63 69 61 6c 20 54 69 6d 65 73 a5 70 72 69 63 65 cb 40 06 00 00 00 00 00 00 83 a6 66 6f 72 6d 61 74 a7 74 61 62 6c 6f 69 64 a5 74 69 74 6c 65 ac 54 68 65 20 47 75 61 72 64 69 61 6e a5 70 72 69 63 65 02", + expectedOutput: JSON.stringify(JSON_TEST_DATA), + recipeConfig: [ + { + "op": "From Hex", + "args": ["Space"] + }, + { + "op": "From MessagePack", + "args": [] + } + ] } ]);