feat(import): expose additional BpmnTreeWalker functionality

* expose API needed for lazy sub-process imports
* also changes #handleDeferred to NOT expect deferred
  as a parameter anymore

Related to bpmn-io/bpmn-js-signavio-compat#1
This commit is contained in:
Philipp Fromme 2018-04-23 08:52:35 +02:00 committed by Nico Rehwaldt
parent a74ed871a4
commit 12a38da9c7
2 changed files with 182 additions and 2 deletions

View File

@ -10,6 +10,7 @@ import {
elementToString
} from './Util';
// TODO: should be configurable: true as well which would allow to remove binding
var diRefs = new Refs({ name: 'bpmnElement', enumerable: true }, { name: 'di' });
/**
@ -230,7 +231,7 @@ export default function BpmnTreeWalker(handler, translate) {
handleDeferred(deferred);
}
function handleDeferred(deferred) {
function handleDeferred() {
var fn;
@ -453,6 +454,9 @@ export default function BpmnTreeWalker(handler, translate) {
// API //////////////////////
return {
handleDefinitions: handleDefinitions
handleDeferred: handleDeferred,
handleDefinitions: handleDefinitions,
handleSubProcess: handleSubProcess,
registerDi: registerDi
};
}

View File

@ -0,0 +1,176 @@
/* global sinon */
import BpmnTreeWalker from 'lib/import/BpmnTreeWalker';
import BpmnModdle from 'bpmn-moddle';
import { find } from 'min-dash';
import simpleXML from 'test/fixtures/bpmn/simple.bpmn';
describe('import - BpmnTreeWalker', function() {
it('should expose functions', function() {
// when
const walker = createWalker();
// then
expect(walker.handleDeferred).to.exist;
expect(walker.handleDefinitions).to.exist;
expect(walker.handleSubProcess).to.exist;
expect(walker.registerDi).to.exist;
});
it('should walk bpmn:Definitions', function(done) {
// given
const elementSpy = sinon.spy(),
rootSpy = sinon.spy(),
errorSpy = sinon.spy();
const walker = createWalker({
element: elementSpy,
root: rootSpy,
error: errorSpy
});
createModdle(simpleXML, (err, definitions, context, moddle) => {
// when
walker.handleDefinitions(definitions);
// then
expect(elementSpy.callCount).to.equal(8);
expect(rootSpy.calledOnce).to.be.true;
expect(errorSpy.notCalled).to.be.true;
done();
});
});
it('should walk bpmn:SubProcess', function(done) {
// given
const elementSpy = sinon.spy(),
rootSpy = sinon.spy(),
errorSpy = sinon.spy();
const walker = createWalker({
element: elementSpy,
root: rootSpy,
error: errorSpy
});
createModdle(simpleXML, (err, definitions, context, moddle) => {
const subProcess = findElementWithId(definitions, 'SubProcess_1');
const plane = definitions.diagrams[0].plane,
planeElements = plane.planeElement;
// register DI
planeElements.forEach(walker.registerDi);
// when
walker.handleSubProcess(subProcess);
walker.handleDeferred();
// then
expect(elementSpy.callCount).to.equal(3);
expect(rootSpy.notCalled).to.be.true;
expect(errorSpy.notCalled).to.be.true;
done();
});
});
it('should error', function(done) {
// given
const elementSpy = sinon.spy(),
rootSpy = sinon.spy(),
errorSpy = sinon.spy();
const walker = createWalker({
element: elementSpy,
root: rootSpy,
error: errorSpy
});
createModdle(simpleXML, (err, definitions, context, moddle) => {
const element = findElementWithId(definitions, 'SubProcess_1');
// will error
element.di = 'DI';
// when
walker.handleDefinitions(definitions);
// then
expect(elementSpy.callCount).to.equal(8);
expect(rootSpy.calledOnce).to.be.true;
expect(errorSpy.calledOnce).to.be.true;
done();
});
});
});
// helpers //////////
function createModdle(xml, done) {
const moddle = new BpmnModdle();
moddle.fromXML(xml, 'bpmn:Definitions', (err, definitions, context) => {
done(err, definitions, context, moddle);
});
}
function createWalker(listeners = {}) {
const visitor = {
element(element, parent) {
listeners.element && listeners.element(element, parent);
},
root(root) {
listeners.root && listeners.root(root);
},
error(message, context) {
listeners.error && listeners.error(message, context);
}
};
return new BpmnTreeWalker(visitor, function() {});
}
function findElementWithId(definitions, id) {
function findElement(element) {
if (element.id === id) {
return element;
}
if (element.flowElements) {
return find(element.flowElements, flowElement => {
const foundElement = findElement(flowElement);
return foundElement && foundElement.id === id;
});
}
}
return definitions.rootElements.reduce((foundElement, rootElement) => {
if (rootElement.id === id) {
return rootElement;
} else {
return findElement(rootElement) || foundElement;
}
}, null);
}