diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 434c8bb6..925989e5 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -299,6 +299,7 @@ "From Case Insensitive Regex", "Add line numbers", "Remove line numbers", + "Line Break", "Get All Casings", "To Table", "Reverse", diff --git a/src/core/operations/LineBreak.mjs b/src/core/operations/LineBreak.mjs new file mode 100644 index 00000000..b2457556 --- /dev/null +++ b/src/core/operations/LineBreak.mjs @@ -0,0 +1,79 @@ +/** + * @author ThomasNotTom + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; + + +/** + * Line Break operation + */ +class LineBreak extends Operation { + + /** + * LineBreak constructor + */ + constructor() { + super(); + + this.name = "Line Break"; + this.module = "Default"; + this.description = "Breaks the input text every n characters."; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = [ + { + "name": "Line break width", + "type": "number", + "value": 16, + "min": 1 + }, { + "name": "Remove leading whitespace", + "type": "boolean", + "value": false + } + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const lines = []; + const lineWidth = args[0]; + const removeLeading = args[1]; + const msg = Utils.arrayBufferToStr(input, false); + let i = 0; + + while (i < msg.length) { + let slice = msg.slice(i, i + lineWidth); + let leadingWhitespace = 0; + + if (removeLeading) { + const match = slice.match(/^\s*/); + leadingWhitespace = match ? match[0].length : 0; + slice = slice.trimStart(); + } + + slice = msg.slice(i, i + lineWidth + leadingWhitespace); + + if (removeLeading) { + slice = slice.trimStart(); + } + + i += lineWidth + leadingWhitespace; + + if (slice.length === 0) continue; + lines.push(slice); + } + + return lines.join("\n"); + } +} + +export default LineBreak; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index f147e9e7..a1b4c2e2 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -100,6 +100,7 @@ import "./tests/JWTDecode.mjs"; import "./tests/JWTSign.mjs"; import "./tests/JWTVerify.mjs"; import "./tests/LevenshteinDistance.mjs"; +import "./tests/LineBreak.mjs"; import "./tests/Lorenz.mjs"; import "./tests/LS47.mjs"; import "./tests/LuhnChecksum.mjs"; diff --git a/tests/operations/tests/LineBreak.mjs b/tests/operations/tests/LineBreak.mjs new file mode 100644 index 00000000..8e56a5d6 --- /dev/null +++ b/tests/operations/tests/LineBreak.mjs @@ -0,0 +1,43 @@ +/** + * @author ThomasNotTom + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + // Check line remains unbroken + name: "Line Break: No break", + input: "Hello, world!", + expectedOutput: "Hello, world!", + recipeConfig: [ + { + "op": "Line Break", + "args": [32, false] + } + ] + }, { + // Check line breaks + name: "Line Break: With break", + input: "Hello, world!", + expectedOutput: "Hello,\n world\n!", + recipeConfig: [ + { + "op": "Line Break", + "args": [6, false] + } + ] + }, { + // Check line breaks and leading whitespace is removed. + name: "Line Break: With break and no leading whitespace", + input: "Hello, world!", + expectedOutput: "Hello,\nworld!", + recipeConfig: [ + { + "op": "Line Break", + "args": [6, true] + } + ] + } +]);