From e294caeeb4b8d7fbb61534987708eaeef008f233 Mon Sep 17 00:00:00 2001 From: 0xff1ce <167429331+0xff1ce@users.noreply.github.com> Date: Fri, 8 May 2026 15:58:19 +0100 Subject: [PATCH] feat(operation-wrap): add new Wrap operation to format text at specified line width (#1882) --- src/core/config/Categories.json | 1 + src/core/operations/Wrap.mjs | 47 +++++++++++++++++++++++++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/Wrap.mjs | 44 ++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+) create mode 100644 src/core/operations/Wrap.mjs create mode 100644 tests/operations/tests/Wrap.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index ab1dafb0d..5fcba2977 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -348,6 +348,7 @@ "Pseudo-Random Number Generator", "Sleep", "File Tree", + "Wrap", "Take nth bytes", "Drop nth bytes" ] diff --git a/src/core/operations/Wrap.mjs b/src/core/operations/Wrap.mjs new file mode 100644 index 000000000..c6e57f885 --- /dev/null +++ b/src/core/operations/Wrap.mjs @@ -0,0 +1,47 @@ +/** + * @author 0xff1ce [github.com/0xff1ce] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; + +/** + * Wrap operation + */ +class Wrap extends Operation { + + /** + * Wrap constructor + */ + constructor() { + super(); + + this.name = "Wrap"; + this.module = "Default"; + this.description = "Wraps the input text at a specified number of characters per line."; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Line Width", + "type": "number", + "value": 64, + }, + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (!input) return ""; // Handle empty input + const lineWidth = args[0]; + const regex = new RegExp(`.{1,${lineWidth}}`, "g"); + return input.match(regex).join("\n"); + } +} + +export default Wrap; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index b25a2c2c7..03ad0e10b 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -181,6 +181,7 @@ import "./tests/TranslateDateTimeFormat.mjs"; import "./tests/Typex.mjs"; import "./tests/UnescapeString.mjs"; import "./tests/Unicode.mjs"; +import "./tests/Wrap.mjs"; import "./tests/URLEncodeDecode.mjs"; import "./tests/RSA.mjs"; import "./tests/CBOREncode.mjs"; diff --git a/tests/operations/tests/Wrap.mjs b/tests/operations/tests/Wrap.mjs new file mode 100644 index 000000000..8d7c9a517 --- /dev/null +++ b/tests/operations/tests/Wrap.mjs @@ -0,0 +1,44 @@ +/** + * @author 0xff1ce [github.com/0xff1ce] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + // Add tests specific to the Wrap operation + { + name: "Wrap text at 64 characters", + input: "A".repeat(128), // Generate an input string of 128 'A' characters + expectedOutput: "A".repeat(64) + "\n" + "A".repeat(64), // Expected output with a line break after 64 characters + recipeConfig: [ + { + "op": "Wrap", + "args": [64] + }, + ], + }, + { + name: "Wrap text at 32 characters", + input: "B".repeat(96), // Generate an input string of 96 'B' characters + expectedOutput: "B".repeat(32) + "\n" + "B".repeat(32) + "\n" + "B".repeat(32), // Expected output with line breaks after every 32 characters + recipeConfig: [ + { + "op": "Wrap", + "args": [32] + }, + ], + }, + { + name: "Wrap text at 10 characters", + input: "1234567890".repeat(10), // Generate an input string by repeating '1234567890' + expectedOutput: Array(10).fill("1234567890").join("\n"), // Expected output with line breaks every 10 characters + recipeConfig: [ + { + "op": "Wrap", + "args": [10] + }, + ], + } +]);