-
Notifications
You must be signed in to change notification settings - Fork 3.5k
Adding a new operation
-
Create a new file in the
src/core/operations
directory and name it using CamelCase. e.g.MyOperation.js
-
In this file, create a namespace with the same name and populate it with a single function looking like this (all function and variable names should be written in camelCase):
const MyOperation = { runMyOperation: function (input, args) { return input; } }; export default MyOperation;
-
input
will be the input data passed on from the previous operation (or the data entered by the user if yours is the first operation). Its data type is specified in the next step byinputType
. -
args
will be an array of the arguments for your operation. They are specified in the next step byargs
. - Make sure that you return the output data in the format specified in the next step by
outputType
.
-
-
Choose which module to add it to. This decision should be based on how much extra code your operation will add to the app, including any dependencies it imports. If it doesn't require any dependencies, add it to the 'Default' module in
src/core/config/modules/Default.js
. Import it at the top of the file:import MyOperation from "../../operations/MyOperation.js";
and then add it to the operation list like so:
"My Operation": MyOperation.runMyOperation, // a reference to the function that runs your operation
If it imports the same dependencies as other operations, add it to the relevant existing module. If it imports entirely new dependencies that are not related to other operations in any way, create a new module using an existing module as a template and then import this new module into the
src/core/config/modules/OpModules.js
file. -
In
src/core/config/OperationConfig.js
, import your operation at the top of the file:import MyOperation from "../operations/MyOperation.js";
Then create a new entry:
"My Operation": { module: "Module name", description: "A short description if necessary, optionally containing HTML code (e.g. lists and paragraphs)", inputType: "byteArray", // the input type for your operation, see the next section for valid types outputType: "byteArray", // the output type for your operation, see the next section for valid types highlight: true, // [optional] true if the operation does not change the position of bytes in the output (so that highlighting can be calculated) highlightReverse: true, // [optional] same as above but for the reverse of the operation (output to input highlighting) manualBake: false, // [optional] true if auto-bake should be disabled when this operation is added to the recipe args: [ // A list of the arguments that the user will be presented with { name: "Argument name", type: "string", // the argument data type, see the next section for valid types value: MyOperation.DEFAULT_VALUE // the default value of the argument } ] }
For example:
"XOR": { module: "Default", description: "XOR the input with the given key, provided as either a hex or ASCII string.<br>e.g. fe023da5<br><br><b>Options</b><br><u>Null preserving:</u> If the current byte is 0x00 or the same as the key, skip it.<br><br><u>Differential:</u> Set the key to the value of the previously decoded byte.", inputType: "byteArray", outputType: "byteArray", args: [ { name: "Key", type: "binaryString", value: "" }, { name: "Key format", type: "option", value: BitwiseOp.KEY_FORMAT }, { name: "Null preserving", type: "boolean", value: BitwiseOp.XOR_PRESERVE_NULLS }, { name: "Differential", type: "boolean", value: BitwiseOp.XOR_DIFFERENTIAL } ] }
-
In
src/core/config/Categories.js
, add your operation name to an appropriate list. This determines which menu it will appear in. You can add it to multiple menus if you feel it is appropriate. -
Finally, run
grunt dev
if you haven't already. If it's already running, it should automatically build a development version when you save the files. -
You should now be able to view your operation on the site by browsing to
localhost:8080
. -
You can write whatever code you like as long as it is encapsulated within the namespace you created (
MyOperation
). Take a look atsrc/core/operations/Entropy.js
for a good example. -
You may find it useful to use some helper functions which have been written in
src/core/Utils.js
. These are available in theUtils
object (e.g.Utils.strToByteArray("Hello")
returns[72,101,108,108,111]
).
Input and Output
Four data types are supported for the input and output of operations:
-
string
- e.g."hello"
-
byteArray
- e.g.[104,101,108,108,111]
-
number
- e.g.562
or3.14159265
-
html
- e.g."<p>hello</p>"
-
ArrayBuffer
- e.g.new Uint8Array([104,101,108,108,111]).buffer
Each operation can define any of these data types as their input or output. The data will be automatically converted to the specified type before running the operation.
Ingredients
Operation arguments (ingredients) can be set to any of the following types:
-
string
orshortString
- e.g.
"hello"
- A
shortString
will simply display a smaller input box.
- e.g.
-
binaryString
orbinaryShortString
- e.g.
"hello\nworld"
- Escaped characters entered by the user will be automatically converted to the bytes they represent. A simple
string
type will return"hello\\nworld"
in the above case.
- e.g.
-
text
- User is given a textbox for free-flow text.
-
byteArray
- e.g. user inputs
"68 65 6c 6c 6f"
, operation receives[104,101,108,108,111]
.
- e.g. user inputs
-
number
- e.g.
562
- This can handle both integer and float values.
- e.g.
-
boolean
- User is presented with a checkbox, operation receives
true
orfalse
.
- User is presented with a checkbox, operation receives
-
option
- Given an array of strings, the user is presented with a dropdown selection box with each of those strings as an option. The selected string is sent to the operation.
-
populateOption
- Given an array of
{name: "", value: ""}
objects, the user is presented with a dropdown selection box with the names as options. The corresponding value will be assigned to whichever argument index thetarget
parameter is set to. - See the Regular expression configuration in
src/core/config/OperationConfig.js
for an example of how this works.
- Given an array of
-
editableOption
- Given an array of
{name: "", value: ""}
objects, the user is presented with an editable dropdown menu. The items in the dropdown are labelled withname
and set the argument tovalue
when selected.
- Given an array of
-
toggleString
- User is presented with a string input box with a toggleable dropdown attached.
- Populate the dropdown using the
toggleValues
property. - Operation receives an object with two properties:
option
containing the user's dropdown selection, andstring
containing the input box contents. - Particularly useful for arguments that can be specified in various different formats.
- See the XOR configuration in
src/core/config/OperationConfig.js
for an example of how this works.