From 9a216dc1bf7efe375f55b7a71005e723e768dc92 Mon Sep 17 00:00:00 2001 From: sg5506844 <130462468+sg5506844@users.noreply.github.com> Date: Wed, 12 Apr 2023 15:09:07 +0530 Subject: [PATCH 1/3] RISON operation --- package-lock.json | 11 ++++ package.json | 1 + src/core/config/Categories.json | 4 +- src/core/operations/RisonDecode.mjs | 60 ++++++++++++++++++ src/core/operations/RisonEncode.mjs | 63 +++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/RisonEncodeDecode.mjs | 66 ++++++++++++++++++++ 7 files changed, 205 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/RisonDecode.mjs create mode 100644 src/core/operations/RisonEncode.mjs create mode 100644 tests/operations/tests/RisonEncodeDecode.mjs diff --git a/package-lock.json b/package-lock.json index 9b939b88..6b9d1787 100644 --- a/package-lock.json +++ b/package-lock.json @@ -78,6 +78,7 @@ "protobufjs": "^7.2.2", "qr-image": "^3.2.0", "reflect-metadata": "^0.1.13", + "rison": "^0.1.1", "scryptsy": "^2.1.0", "snackbarjs": "^1.1.0", "sortablejs": "^1.15.0", @@ -11704,6 +11705,11 @@ "inherits": "^2.0.1" } }, + "node_modules/rison": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/rison/-/rison-0.1.1.tgz", + "integrity": "sha512-8C+/PKKTaAYE2quDtOUwny/eQpNn9YGby7T80wntbVWSGvw0aUT9M0YgLdLkUgIQzQwaB1ZTr80rwLVKyohHig==" + }, "node_modules/robust-predicates": { "version": "3.0.1", "license": "Unlicense" @@ -21755,6 +21761,11 @@ "inherits": "^2.0.1" } }, + "rison": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/rison/-/rison-0.1.1.tgz", + "integrity": "sha512-8C+/PKKTaAYE2quDtOUwny/eQpNn9YGby7T80wntbVWSGvw0aUT9M0YgLdLkUgIQzQwaB1ZTr80rwLVKyohHig==" + }, "robust-predicates": { "version": "3.0.1" }, diff --git a/package.json b/package.json index f5d9a7f9..1127f1cd 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "protobufjs": "^7.2.2", "qr-image": "^3.2.0", "reflect-metadata": "^0.1.13", + "rison": "^0.1.1", "scryptsy": "^2.1.0", "snackbarjs": "^1.1.0", "sortablejs": "^1.15.0", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index ce2f01f5..933a8061 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -67,7 +67,9 @@ "JSON to CSV", "Avro to JSON", "CBOR Encode", - "CBOR Decode" + "CBOR Decode", + "Rison Encode", + "Rison Decode" ] }, { diff --git a/src/core/operations/RisonDecode.mjs b/src/core/operations/RisonDecode.mjs new file mode 100644 index 00000000..1b9741a8 --- /dev/null +++ b/src/core/operations/RisonDecode.mjs @@ -0,0 +1,60 @@ +/** + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import rison from "rison"; + +/** + * Rison Decode operation + */ +class RisonDecode extends Operation { + + /** + * RisonDecode constructor + */ + constructor() { + super(); + + this.name = "Rison Decode"; + this.module = "Default"; + this.description = "Rison, a data serialization format optimized for compactness in URIs. Rison is a slight variation of JSON that looks vastly superior after URI encoding. Rison still expresses exactly the same set of data structures as JSON, so data can be translated back and forth without loss or guesswork."; + this.infoURL = "https://github.com/Nanonid/rison"; + this.inputType = "string"; + this.outputType = "Object"; + this.args = [ + { + name: "Decode Option", + type: "editableOption", + value: [ + { name: "Decode", value: "Decode", }, + { name: "Decode Object", value: "Decode Object", }, + { name: "Decode Array", value: "Decode Array", }, + ] + }, + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {Object} + */ + run(input, args) { + const [decodeOption] = args; + switch (decodeOption) { + case "Decode": + return rison.decode(input); + case "Decode Object": + return rison.decode_object(input); + case "Decode Array": + return rison.decode_array(input); + } + throw new OperationError("Invalid Decode option"); + } +} + +export default RisonDecode; diff --git a/src/core/operations/RisonEncode.mjs b/src/core/operations/RisonEncode.mjs new file mode 100644 index 00000000..36a61017 --- /dev/null +++ b/src/core/operations/RisonEncode.mjs @@ -0,0 +1,63 @@ +/** + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import rison from "rison"; + +/** + * Rison Encode operation + */ +class RisonEncode extends Operation { + + /** + * RisonEncode constructor + */ + constructor() { + super(); + + this.name = "Rison Encode"; + this.module = "Default"; + this.description = "Rison, a data serialization format optimized for compactness in URIs. Rison is a slight variation of JSON that looks vastly superior after URI encoding. Rison still expresses exactly the same set of data structures as JSON, so data can be translated back and forth without loss or guesswork."; + this.infoURL = "https://github.com/Nanonid/rison"; + this.inputType = "Object"; + this.outputType = "string"; + this.args = [ + { + name: "Encode Option", + type: "editableOption", + value: [ + { name: "Encode", value: "Encode", }, + { name: "Encode Object", value: "Encode Object", }, + { name: "Encode Array", value: "Encode Array", }, + { name: "Encode URI", value: "Encode URI", } + ] + }, + ]; + } + + /** + * @param {Object} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [encodeOption] = args; + switch (encodeOption) { + case "Encode": + return rison.encode(input); + case "Encode Object": + return rison.encode_object(input); + case "Encode Array": + return rison.encode_array(input); + case "Encode URI": + return rison.encode_uri(input); + } + throw new OperationError("Invalid encode option"); + } +} + +export default RisonEncode; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 56f432e0..006649e6 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -113,6 +113,7 @@ import "./tests/Unicode.mjs"; import "./tests/RSA.mjs"; import "./tests/CBOREncode.mjs"; import "./tests/CBORDecode.mjs"; +import "./tests/RisonEncodeDecode.mjs"; import "./tests/JA3Fingerprint.mjs"; import "./tests/JA3SFingerprint.mjs"; import "./tests/HASSH.mjs"; diff --git a/tests/operations/tests/RisonEncodeDecode.mjs b/tests/operations/tests/RisonEncodeDecode.mjs new file mode 100644 index 00000000..c535651d --- /dev/null +++ b/tests/operations/tests/RisonEncodeDecode.mjs @@ -0,0 +1,66 @@ +/** + * @author sg5506844 [sg5506844@gmail.com] + * @copyright Crown Copyright 2021 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Rison Encode: Encoding example 1", + input: JSON.stringify({ any: "json", yes: true }), + expectedOutput: "(any:json,yes:!t)", + recipeConfig: [ + { + op: "Rison Encode", + args: ["Encode"] + } + ] + }, + { + name: "Rison Encode: Encoding example 2", + input: JSON.stringify({ supportsObjects: true, ints: 435 }), + expectedOutput: "ints:435,supportsObjects:!t", + recipeConfig: [ + { + op: "Rison Encode", + args: ["Encode Object"] + } + ] + }, + { + name: "Rison Encode: Encoding example 3", + input: JSON.stringify(["A", "B", { supportsObjects: true }]), + expectedOutput: "A,B,(supportsObjects:!t)", + recipeConfig: [ + { + op: "Rison Encode", + args: ["Encode Array"] + } + ] + }, + { + name: "Rison Encode: Object for an array", + input: JSON.stringify({ supportsObjects: true, ints: 435 }), + expectedOutput: "Rison Encode - rison.encode_array expects an array argument", + expectedError: "Rison Encode - rison.encode_array expects an array argument", + recipeConfig: [ + { + op: "Rison Encode", + args: ["Encode Array"] + } + ] + }, + { + name: "Rison Decode: Decoding example 1", + input: "(any:json,yes:!t)", + expectedOutput: JSON.stringify({ any: "json", yes: true }, null, 4), + recipeConfig: [ + { + op: "Rison Decode", + args: ["Decode"] + } + ] + } +]); From 76ba630d59517002581865393264318173048784 Mon Sep 17 00:00:00 2001 From: sw5678 <151949597+sw5678@users.noreply.github.com> Date: Wed, 13 Dec 2023 09:19:16 +0000 Subject: [PATCH 2/3] Added file tree functionality --- src/core/config/Categories.json | 3 +- src/core/operations/FileTree.mjs | 100 ++++++++++++++++++++++++++++ tests/operations/tests/FileTree.mjs | 21 ++++++ 3 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/FileTree.mjs create mode 100644 tests/operations/tests/FileTree.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index cf4d91be..b76b93ac 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -294,7 +294,8 @@ "Escape string", "Unescape string", "Pseudo-Random Number Generator", - "Sleep" + "Sleep", + "File Tree" ] }, { diff --git a/src/core/operations/FileTree.mjs b/src/core/operations/FileTree.mjs new file mode 100644 index 00000000..c13b9d1a --- /dev/null +++ b/src/core/operations/FileTree.mjs @@ -0,0 +1,100 @@ +/** + * @author sw5678 + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; +import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs"; + +/** + * Unique operation + */ +class FileTree extends Operation { + + /** + * Unique constructor + */ + constructor() { + super(); + + this.name = "File Tree"; + this.module = "Default"; + this.description = "Creates file tree from list of file paths (Similar too tree linux command)"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "File Path Delimiter", + type: "binaryString", + value: "/" + }, + { + name: "Delimiter", + type: "option", + value: INPUT_DELIM_OPTIONS + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + // Set up arrow and pipe for nice output display + const ARROW = '|---'; + const PIPE = '| '; + + // Get args from input + const file_delim = args[0]; + const entry_delim = Utils.charRep(args[1]); + + // Store path to print + let completed_list = []; + let print_list = []; + + // Loop through all entries + const file_paths = input.split(entry_delim).unique().sort(); + for (var i = 0; i < file_paths.length; i++) + { + // Split by file delimiter + let path = file_paths[i].split(file_delim); + + if (path[0] == '') + { + path = path.slice(1, path.length); + } + + for (var j = 0; j < path.length; j++) + { + let print_line; + let key; + if (j == 0) + { + print_line = path[j]; + key = path[j]; + } + else + { + print_line = PIPE.repeat(j-1) + ARROW + path[j] + key = path.slice(0, j+1).join("/"); + } + + // Check to see we have already added that path + if (!completed_list.includes(key)) + { + completed_list.push(key); + print_list.push(print_line); + } + } + } + return print_list.join("\n"); + } + +} + +export default FileTree; diff --git a/tests/operations/tests/FileTree.mjs b/tests/operations/tests/FileTree.mjs new file mode 100644 index 00000000..34249e3c --- /dev/null +++ b/tests/operations/tests/FileTree.mjs @@ -0,0 +1,21 @@ +/** + * @author sw5678 + * @copyright Crown Copyright 2023 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + "name": "Swap Case: basic example", + "input": "/test_dir1/test_file1.txt\n/test_dir1/test_file2.txt\n/test_dir2/test_file1.txt", + "expectedOutput": "test_dir1\n|---test_file1.txt\n|---test_file2.txt\ntest_dir2\n|---test_file1.txt", + "recipeConfig": [ + { + "op": "File Tree", + "args": [ + ], + }, + ], + } +]); From ac18b74e66612a3fe003bc10f3050a20f6bcaefc Mon Sep 17 00:00:00 2001 From: sw5678 <151949597+sw5678@users.noreply.github.com> Date: Wed, 13 Dec 2023 09:38:26 +0000 Subject: [PATCH 3/3] Fixed linting issues --- src/core/operations/FileTree.mjs | 49 ++++++++++++++------------------ 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/src/core/operations/FileTree.mjs b/src/core/operations/FileTree.mjs index c13b9d1a..c01401c6 100644 --- a/src/core/operations/FileTree.mjs +++ b/src/core/operations/FileTree.mjs @@ -46,53 +46,46 @@ class FileTree extends Operation { run(input, args) { // Set up arrow and pipe for nice output display - const ARROW = '|---'; - const PIPE = '| '; + const ARROW = "|---"; + const PIPE = "| "; // Get args from input - const file_delim = args[0]; - const entry_delim = Utils.charRep(args[1]); + const fileDelim = args[0]; + const entryDelim = Utils.charRep(args[1]); // Store path to print - let completed_list = []; - let print_list = []; + const completedList = []; + const printList = []; // Loop through all entries - const file_paths = input.split(entry_delim).unique().sort(); - for (var i = 0; i < file_paths.length; i++) - { + const filePaths = input.split(entryDelim).unique().sort(); + for (let i = 0; i < filePaths.length; i++) { // Split by file delimiter - let path = file_paths[i].split(file_delim); + let path = filePaths[i].split(fileDelim); - if (path[0] == '') - { - path = path.slice(1, path.length); + if (path[0] === "") { + path = path.slice(1, path.length); } - for (var j = 0; j < path.length; j++) - { - let print_line; + for (let j = 0; j < path.length; j++) { + let printLine; let key; - if (j == 0) - { - print_line = path[j]; + if (j === 0) { + printLine = path[j]; key = path[j]; - } - else - { - print_line = PIPE.repeat(j-1) + ARROW + path[j] + } else { + printLine = PIPE.repeat(j-1) + ARROW + path[j]; key = path.slice(0, j+1).join("/"); } // Check to see we have already added that path - if (!completed_list.includes(key)) - { - completed_list.push(key); - print_list.push(print_line); + if (!completedList.includes(key)) { + completedList.push(key); + printList.push(printLine); } } } - return print_list.join("\n"); + return printList.join("\n"); } }