Skip to content

Commit

Permalink
Converted root engine
Browse files Browse the repository at this point in the history
  • Loading branch information
Christopher Patty committed May 13, 2022
1 parent 340a36c commit 68a0928
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 37 deletions.
112 changes: 79 additions & 33 deletions src/RootEngine.js → src/RootEngine.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,50 @@
import {
PortResolver,
NodeResolver,
NodeMap,
ConnectionMap,
Connection,
FlumeNode,
NodeType,
NodeTypeMap,
Connections,
RootEngineOptions
} from "./types";
import { FlumeConfig } from "./typeBuilders";

class LoopError extends Error {
constructor(message, code) {
public code: number;
static maxLoopsExceeded = 1;

constructor(message: string, code: number) {
super(message);
this.code = code;
}
static maxLoopsExceeded = 1;
}

export class RootEngine {
constructor(config, resolveInputControls, fireNodeFunction) {
public config: FlumeConfig;
private resolveInputControls: PortResolver;
private fireNodeFunction: NodeResolver;
private loops: number;
private maxLoops: number;

constructor(
config: FlumeConfig,
resolveInputControls: PortResolver,
fireNodeFunction: NodeResolver
) {
this.config = config;
this.fireNodeFunction = fireNodeFunction;
this.resolveInputControls = resolveInputControls;
this.loops = 0;
this.maxLoops = 1000;
}
resetLoops = maxLoops => {
private resetLoops = (maxLoops?: number) => {
this.maxLoops = maxLoops !== undefined ? maxLoops : 1000;
this.loops = 0;
};
checkLoops = () => {
private checkLoops = () => {
if (this.maxLoops >= 0 && this.loops > this.maxLoops) {
throw new LoopError(
"Max loop count exceeded.",
Expand All @@ -28,7 +54,7 @@ export class RootEngine {
this.loops++;
}
};
getRootNode = nodes => {
private getRootNode = (nodes: NodeMap) => {
const roots = Object.values(nodes).filter(n => n.root);
if (roots.length > 1) {
throw new Error(
Expand All @@ -37,16 +63,27 @@ export class RootEngine {
}
return roots[0];
};
reduceRootInputs = (inputs, callback) =>
Object.entries(inputs).reduce((obj, [inputName, connection]) => {
const input = callback(inputName, connection);
private reduceRootInputs = (
inputs: ConnectionMap,
callback: (
inputName: string,
connection: Connection[]
) => { name: string; value: any }
) =>
Object.entries(inputs).reduce((obj, [inputName, connections]) => {
const input = callback(inputName, connections);
obj[input.name] = input.value;
return obj;
}, {});
resolveInputValues = (node, nodeType, nodes, context) => {
let inputs = nodeType.inputs
if (typeof inputs === 'function') {
inputs = inputs(node.inputData, node.connections, context)
private resolveInputValues = (
node: FlumeNode,
nodeType: NodeType,
nodes: NodeMap,
context: any
) => {
let inputs = nodeType.inputs;
if (typeof inputs === "function") {
inputs = inputs(node.inputData, node.connections, context);
}
return inputs.reduce((obj, input) => {
const inputConnections = node.connections.inputs[input.name] || [];
Expand All @@ -66,7 +103,11 @@ export class RootEngine {
return obj;
}, {});
};
getValueOfConnection = (connection, nodes, context) => {
private getValueOfConnection = (
connection: Connection,
nodes: NodeMap,
context: any
) => {
this.checkLoops();
const outputNode = nodes[connection.nodeId];
const outputNodeType = this.config.nodeTypes[outputNode.type];
Expand All @@ -84,42 +125,47 @@ export class RootEngine {
)[connection.portName];
return outputResult;
};
resolveRootNode(nodes, options = {}) {
public resolveRootNode(nodes: NodeMap, rawOptions?: RootEngineOptions) {
const options = rawOptions ?? {};
const rootNode = options.rootNodeId
? nodes[options.rootNodeId]
: this.getRootNode(nodes);
if (rootNode) {
let inputs = this.config.nodeTypes[rootNode.type].inputs;
if (typeof inputs === 'function') {
inputs = inputs(rootNode.inputData, rootNode.connections, options.context);
if (typeof inputs === "function") {
inputs = inputs(
rootNode.inputData,
rootNode.connections,
options.context
);
}
const controlValues = inputs.reduce(
(obj, input) => {
obj[input.name] = this.resolveInputControls(
input.type,
rootNode.inputData[input.name] || {},
options.context
);
return obj;
},
{}
);
const controlValues = inputs.reduce((obj, input) => {
obj[input.name] = this.resolveInputControls(
input.type,
rootNode.inputData[input.name] || {},
options.context
);
return obj;
}, {});
const inputValues = this.reduceRootInputs(
rootNode.connections.inputs,
(inputName, connection) => {
(inputName, connections) => {
this.resetLoops(options.maxLoops);
let value;
try {
value = this.getValueOfConnection(
connection[0],
connections[0],
nodes,
options.context
);
} catch (e) {
if (e.code === LoopError.maxLoopsExceeded) {
console.error(`${e.message} Circular nodes detected in ${inputName} port.`);
const err = e as LoopError;
if (err.code === LoopError.maxLoopsExceeded) {
console.error(
`${err.message} Circular nodes detected in ${inputName} port.`
);
} else {
console.error(e)
console.error(e);
}
} finally {
return {
Expand Down
8 changes: 5 additions & 3 deletions src/components/Toaster/Toaster.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import React from "react";
import { ToastAction, ToastActionTypes } from "../../toastsReducer";
import { Toast } from "../../types";
import { Toast as ToastType } from "../../types";
import styles from "./Toaster.css";

type ToasterProps = {
toasts: Toast[];
toasts: ToastType[];
dispatchToasts: (action: ToastAction) => void;
};

export default ({ toasts = [], dispatchToasts }: ToasterProps) => {
const Toaster = ({ toasts = [], dispatchToasts }: ToasterProps) => {
const setHeight = React.useCallback(
(id: string, height: number) => {
dispatchToasts({
Expand Down Expand Up @@ -143,3 +143,5 @@ const Toast = ({
</div>
);
};

export default Toaster;
File renamed without changes.
22 changes: 21 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,10 +227,30 @@ export type NodeHeaderActions = {
openMenu: (event: MouseEvent | React.MouseEvent) => void | any;
closeMenu: () => void | any;
deleteNode: () => void | any;
}
};

export type NodeHeaderRenderCallback = (
Wrapper: React.FC<HTMLProps<HTMLHeadingElement>>,
nodeType: NodeType,
actions: NodeHeaderActions
) => ReactNode;

export type PortResolver = (
portType: string,
data: InputData,
context: any
) => any;

export type NodeResolver = (
node: FlumeNode,
inputValues: InputData,
nodeType: NodeType,
context: any
) => { [outputPortName: string]: any };

export interface RootEngineOptions {
rootNodeId?: string;
context?: any;
maxLoops?: number;
onlyResolveConnected?: boolean;
}

0 comments on commit 68a0928

Please sign in to comment.