Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/core/config/Categories.json
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,10 @@
"Sleep",
"File Tree",
"Take nth bytes",
"Drop nth bytes"
"Drop nth bytes",
"Append",
"Prepend",
"Insert At"
]
},
{
Expand Down
64 changes: 64 additions & 0 deletions src/core/operations/Append.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import { DELIM_OPTIONS } from "../lib/Delim.mjs";

/**
* Append operation.
*/
class Append extends Operation {
/**
* Append constructor.
*/
constructor() {
super();

this.name = "Append";
this.module = "Default";
this.description = "Add characters to the end of the input string, optionally with respect to a delimeter.";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Text",
"type": "binaryString",
"value": ""
},
{
"name": "Delimiter",
"type": "option",
"value": ["None", ...DELIM_OPTIONS]
},
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [text, delim] = args;

if (delim === "None") {
return input + text;
}

const output = [],
delimChar = Utils.charRep(delim),
subs = input.split(Utils.charRep(delim));

for (let i = 0; i < subs.length; i++) {
output.push(subs[i] + text);
}

return output.join(delimChar);
}
}

export default Append;
88 changes: 88 additions & 0 deletions src/core/operations/InsertAt.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import { DELIM_OPTIONS } from "../lib/Delim.mjs";

/**
* Insert At operation.
*/
class InsertAt extends Operation {
/**
* InsertAt constructor.
*/
constructor() {
super();

this.name = "Insert At";
this.module = "Default";
this.description = "Add characters to input string at a given index, optionally with respect to a delimeter.";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Text",
"type": "binaryString",
"value": ""
},
{
"name": "Index",
"type": "number",
"value": 0,
"min": 0
},
{
"name": "Delimiter",
"type": "option",
"value": ["None", ...DELIM_OPTIONS]
},
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [text, index, delim] = args;

if (delim === "None") {
return InsertAt.performInsert(input, text, index);
}

const output = [],
delimChar = Utils.charRep(delim),
subs = input.split(Utils.charRep(delim));

for (let i = 0; i < subs.length; i++) {
output.push(InsertAt.performInsert(subs[i], text, index));
}

return output.join(delimChar);
}

/**
* @param {string} input
* @param {string} text
* @param {number} index
* @returns {string}
*/
static performInsert(input, text, index) {
if (index >= input.length) {
return input + text;
}

if (index <= 0) {
return text + input;
}

return input.slice(0, index) + text + input.slice(index);
}
}

export default InsertAt;
64 changes: 64 additions & 0 deletions src/core/operations/Prepend.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/**
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/

import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import { DELIM_OPTIONS } from "../lib/Delim.mjs";

/**
* Prepend operation.
*/
class Prepend extends Operation {
/**
* Prepend constructor.
*/
constructor() {
super();

this.name = "Prepend";
this.module = "Default";
this.description = "Add characters to the start of the input string, optionally with respect to a delimeter.";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Text",
"type": "binaryString",
"value": ""
},
{
"name": "Delimiter",
"type": "option",
"value": ["None", ...DELIM_OPTIONS]
},
];
}

/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [text, delim] = args;

if (delim === "None") {
return input + text;
}

const output = [],
delimChar = Utils.charRep(delim),
subs = input.split(Utils.charRep(delim));

for (let i = 0; i < subs.length; i++) {
output.push(text + subs[i]);
}

return output.join(delimChar);
}
}

export default Prepend;
42 changes: 42 additions & 0 deletions tests/operations/tests/Append.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Media operation tests.
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";

TestRegister.addTests([
{
name: "Append empty",
input: "test",
expectedOutput: "test",
recipeConfig: [
{ op: "Append", args: ["", "None"] } // [text, delimiter]
]
},
{
name: "Append empty input",
input: "",
expectedOutput: "test",
recipeConfig: [
{ op: "Append", args: ["test", "None"] } // [text, delimiter]
]
},
{
name: "Append with input and text",
input: "hello ",
expectedOutput: "hello world",
recipeConfig: [
{ op: "Append", args: ["world", "None"] } // [text, delimiter]
]
},
{
name: "Append with space delim",
input: "hello world",
expectedOutput: "hello: world:",
recipeConfig: [
{ op: "Append", args: [":", "Space"] } // [text, delimiter]
]
}
]);
66 changes: 66 additions & 0 deletions tests/operations/tests/InsertAt.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* Media operation tests.
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";

TestRegister.addTests([
{
name: "Insert At empty",
input: "test",
expectedOutput: "test",
recipeConfig: [
{ op: "Insert At", args: ["", 0, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At empty input",
input: "",
expectedOutput: "test",
recipeConfig: [
{ op: "Insert At", args: ["test", 0, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At with input and text",
input: "hello ",
expectedOutput: "hello world",
recipeConfig: [
{ op: "Insert At", args: ["world", 6, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At negative",
input: " world",
expectedOutput: "hello world",
recipeConfig: [
{ op: "Insert At", args: ["hello", -5, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At beyond string length",
input: "hello ",
expectedOutput: "hello world",
recipeConfig: [
{ op: "Insert At", args: ["world", 100, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At inside",
input: "heo",
expectedOutput: "hello",
recipeConfig: [
{ op: "Insert At", args: ["ll", 2, "None"] } // [text, index, delimiter]
]
},
{
name: "Insert At with space delim",
input: "hello world",
expectedOutput: "he:llo wo:rld",
recipeConfig: [
{ op: "Insert At", args: [":", 2, "Space"] } // [text, index, delimiter]
]
}
]);
42 changes: 42 additions & 0 deletions tests/operations/tests/Prepend.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* Media operation tests.
* @author oliver-mitchell [oliver@polymerlabs.dev]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";

TestRegister.addTests([
{
name: "Prepend empty",
input: "test",
expectedOutput: "test",
recipeConfig: [
{ op: "Prepend", args: ["", "None"] } // [text, delimiter]
]
},
{
name: "Prepend empty input",
input: "",
expectedOutput: "test",
recipeConfig: [
{ op: "Prepend", args: ["test", "None"] } // [text, delimiter]
]
},
{
name: "Prepend with input and text",
input: " world",
expectedOutput: "hello world",
recipeConfig: [
{ op: "Prepend", args: ["hello", "None"] } // [text, delimiter]
]
},
{
name: "Prepend with space delim",
input: "hello world",
expectedOutput: ":hello :world",
recipeConfig: [
{ op: "Prepend", args: [":", "Space"] } // [text, delimiter]
]
}
]);
Loading