You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

87 lines
2.1 KiB

import nodeFns from './nodeFns';
import Context from './context';
import EventEmitter from 'eventemitter3';
const SHAPES = {
START: 'imove-start',
BRANCH: 'imove-branch',
BEHAVIOR: 'imove-behavior'
}
export default class Logic extends EventEmitter{
constructor(opts = {}) {
super();
this.dsl = opts.dsl;
}
get cells() {
return this.dsl.cells;
}
get nodes() {
return this.cells.filter(cell => cell.shape !== 'edge');
}
get startNodes() {
return this.cells.filter(cell => cell.shape === SHAPES.START);
}
get edges() {
return this.cells.filter(cell => cell.shape === 'edge');
}
_getStartNode(trigger) {
for(const cell of this.startNodes) {
if(cell.data.trigger === trigger) {
return cell;
}
}
}
_getNextNode(ctx, curNode, lastRet) {
for(const edge of this.edges) {
let isMatched = edge.source.cell === curNode.id;
// NOTE: if it is a imove-branch node, each port's condition should be tested whether it is matched
if(curNode.shape === SHAPES.BRANCH) {
let matchedPort = '';
const {ports} = curNode.data;
for(const key in ports) {
const {condition} = ports[key];
const ret = new Function('ctx', 'return ' + condition)(ctx);
if(ret === lastRet) {
matchedPort = key;
break;
}
}
isMatched = isMatched && edge.source.port === matchedPort;
}
if(isMatched) {
const nextNodeId = edge.target.cell;
return this.nodes.find(item => item.id === nextNodeId);
}
}
}
_createCtx() {
const ctx = new Context();
ctx.emit = this.emit.bind(this);
return ctx;
}
async invoke(trigger, data) {
let curNode = this._getStartNode(trigger);
if(!curNode) {
return Promise.reject(`Invoke failed! No logic-start named ${trigger} found!`);
}
let lastRet;
const ctx = this._createCtx();
ctx._reset({payload: data});
while(curNode) {
ctx._transitTo(curNode, lastRet);
const fn = nodeFns[curNode.id];
lastRet = await fn(ctx);
curNode = this._getNextNode(ctx, curNode, lastRet);
}
}
}