diff --git a/src/core/Recipe.mjs b/src/core/Recipe.mjs
deleted file mode 100755
index 14cb39b7..00000000
--- a/src/core/Recipe.mjs
+++ /dev/null
@@ -1,348 +0,0 @@
-/**
- * @author n1474335 [n1474335@gmail.com]
- * @copyright Crown Copyright 2016
- * @license Apache-2.0
- */
-
-import OperationConfig from "./config/OperationConfig.json";
-import OperationError from "./errors/OperationError.mjs";
-import Operation from "./Operation.mjs";
-import DishError from "./errors/DishError.mjs";
-import log from "loglevel";
-import { isWorkerEnvironment } from "./Utils.mjs";
-
-// Cache container for modules
-let modules = null;
-
-/**
- * The Recipe controls a list of Operations and the Dish they operate on.
- */
-class Recipe {
-
- /**
- * Recipe constructor
- *
- * @param {Object} recipeConfig
- */
- constructor(recipeConfig) {
- this.opList = [];
-
- if (recipeConfig) {
- this._parseConfig(recipeConfig);
- }
- }
-
-
- /**
- * Reads and parses the given config.
- *
- * @private
- * @param {Object} recipeConfig
- */
- _parseConfig(recipeConfig) {
- recipeConfig.forEach(c => {
- this.opList.push({
- name: c.op,
- module: OperationConfig[c.op].module,
- ingValues: c.args,
- breakpoint: c.breakpoint,
- disabled: c.disabled,
- });
- });
- }
-
-
- /**
- * Populate elements of opList with operation instances.
- * Dynamic import here removes top-level cyclic dependency issue.
- *
- * @private
- */
- async _hydrateOpList() {
- if (!modules) {
- // Using Webpack Magic Comments to force the dynamic import to be included in the main chunk
- // https://webpack.js.org/api/module-methods/
- modules = await import(/* webpackMode: "eager" */ "./config/modules/OpModules.mjs");
- modules = modules.default;
- }
-
- this.opList = this.opList.map(o => {
- if (o instanceof Operation) {
- return o;
- } else {
- const op = new modules[o.module][o.name]();
- op.ingValues = o.ingValues;
- op.breakpoint = o.breakpoint;
- op.disabled = o.disabled;
- return op;
- }
- });
- }
-
-
- /**
- * Returns the value of the Recipe as it should be displayed in a recipe config.
- *
- * @returns {Object[]}
- */
- get config() {
- return this.opList.map(op => ({
- op: op.name,
- args: op.ingValues,
- }));
- }
-
-
- /**
- * Adds a new Operation to this Recipe.
- *
- * @param {Operation} operation
- */
- addOperation(operation) {
- this.opList.push(operation);
- }
-
-
- /**
- * Adds a list of Operations to this Recipe.
- *
- * @param {Operation[]} operations
- */
- addOperations(operations) {
- operations.forEach(o => {
- if (o instanceof Operation) {
- this.opList.push(o);
- } else {
- this.opList.push({
- name: o.name,
- module: o.module,
- ingValues: o.args,
- breakpoint: o.breakpoint,
- disabled: o.disabled,
- });
- }
- });
- }
-
-
- /**
- * Set a breakpoint on a specified Operation.
- *
- * @param {number} position - The index of the Operation
- * @param {boolean} value
- */
- setBreakpoint(position, value) {
- try {
- this.opList[position].breakpoint = value;
- } catch (err) {
- // Ignore index error
- }
- }
-
-
- /**
- * Remove breakpoints on all Operations in the Recipe up to the specified position. Used by Flow
- * Control Fork operation.
- *
- * @param {number} pos
- */
- removeBreaksUpTo(pos) {
- for (let i = 0; i < pos; i++) {
- this.opList[i].breakpoint = false;
- }
- }
-
-
- /**
- * Returns true if there is a Flow Control Operation in this Recipe.
- *
- * @returns {boolean}
- */
- containsFlowControl() {
- return this.opList.reduce((acc, curr) => {
- return acc || curr.flowControl;
- }, false);
- }
-
-
- /**
- * Executes each operation in the recipe over the given Dish.
- *
- * @param {Dish} dish
- * @param {number} [startFrom=0]
- * - The index of the Operation to start executing from
- * @param {number} [forkState={}]
- * - If this is a forked recipe, the state of the recipe up to this point
- * @returns {number}
- * - The final progress through the recipe
- */
- async execute(dish, startFrom=0, forkState={}) {
- let op, input, output,
- numJumps = 0,
- numRegisters = forkState.numRegisters || 0;
-
- if (startFrom === 0) this.lastRunOp = null;
-
- await this._hydrateOpList();
-
- log.debug(`[*] Executing recipe of ${this.opList.length} operations, starting at ${startFrom}`);
-
- for (let i = startFrom; i < this.opList.length; i++) {
- op = this.opList[i];
- log.debug(`[${i}] ${op.name} ${JSON.stringify(op.ingValues)}`);
- if (op.disabled) {
- log.debug("Operation is disabled, skipping");
- continue;
- }
- if (op.breakpoint) {
- log.debug("Pausing at breakpoint");
- return i;
- }
-
- try {
- input = await dish.get(op.inputType);
- log.debug(`Executing operation '${op.name}'`);
-
- if (isWorkerEnvironment()) {
- self.sendStatusMessage(`Baking... (${i+1}/${this.opList.length})`);
- self.sendProgressMessage(i + 1, this.opList.length);
- }
-
- if (op.flowControl) {
- // Package up the current state
- let state = {
- "progress": i,
- "dish": dish,
- "opList": this.opList,
- "numJumps": numJumps,
- "numRegisters": numRegisters,
- "forkOffset": forkState.forkOffset || 0
- };
-
- state = await op.run(state);
- i = state.progress;
- numJumps = state.numJumps;
- numRegisters = state.numRegisters;
- } else {
- output = await op.run(input, op.ingValues);
- dish.set(output, op.outputType);
- }
- this.lastRunOp = op;
- } catch (err) {
- // Return expected errors as output
- if (err instanceof OperationError ||
- (err.type && err.type === "OperationError")) {
- // Cannot rely on `err instanceof OperationError` here as extending
- // native types is not fully supported yet.
- dish.set(err.message, "string");
- return i;
- } else if (err instanceof DishError ||
- (err.type && err.type === "DishError")) {
- dish.set(err.message, "string");
- return i;
- } else {
- const e = typeof err == "string" ? { message: err } : err;
-
- e.progress = i;
- if (e.fileName) {
- e.displayStr = `${op.name} - ${e.name} in ${e.fileName} on line ` +
- `${e.lineNumber}.
Message: ${e.displayStr || e.message}`;
- } else {
- e.displayStr = `${op.name} - ${e.displayStr || e.message}`;
- }
-
- throw e;
- }
- }
- }
-
- log.debug("Recipe complete");
- return this.opList.length;
- }
-
-
- /**
- * Present the results of the final operation.
- *
- * @param {Dish} dish
- */
- async present(dish) {
- if (!this.lastRunOp) return;
-
- const output = await this.lastRunOp.present(
- await dish.get(this.lastRunOp.outputType),
- this.lastRunOp.ingValues
- );
- dish.set(output, this.lastRunOp.presentType);
- }
-
-
- /**
- * Returns the recipe configuration in string format.
- *
- * @returns {string}
- */
- toString() {
- return JSON.stringify(this.config);
- }
-
-
- /**
- * Creates a Recipe from a given configuration string.
- *
- * @param {string} recipeStr
- */
- fromString(recipeStr) {
- const recipeConfig = JSON.parse(recipeStr);
- this._parseConfig(recipeConfig);
- }
-
-
- /**
- * Generates a list of all the highlight functions assigned to operations in the recipe, if the
- * entire recipe supports highlighting.
- *
- * @returns {Object[]} highlights
- * @returns {function} highlights[].f
- * @returns {function} highlights[].b
- * @returns {Object[]} highlights[].args
- */
- async generateHighlightList() {
- await this._hydrateOpList();
- const highlights = [];
-
- for (let i = 0; i < this.opList.length; i++) {
- const op = this.opList[i];
- if (op.disabled) continue;
-
- // If any breakpoints are set, do not attempt to highlight
- if (op.breakpoint) return false;
-
- // If any of the operations do not support highlighting, fail immediately.
- if (op.highlight === false || op.highlight === undefined) return false;
-
- highlights.push({
- f: op.highlight,
- b: op.highlightReverse,
- args: op.ingValues
- });
- }
-
- return highlights;
- }
-
-
- /**
- * Determines whether the previous operation has a different presentation type to its normal output.
- *
- * @param {number} progress
- * @returns {boolean}
- */
- lastOpPresented(progress) {
- if (progress < 1) return false;
- return this.opList[progress-1].presentType !== this.opList[progress-1].outputType;
- }
-
-}
-
-export default Recipe;