mirror of
https://github.com/sartography/bpmn-js.git
synced 2025-02-18 11:56:30 +00:00
fix(import): forgive invalid flowElements
Instead of failing hard when we parse invalid flow elements (i.e. TextAnnotation) we log a warning that may be handled by the diagram import. Related to #74
This commit is contained in:
parent
55d9215e62
commit
8ad29d034d
@ -1,6 +1,6 @@
|
|||||||
var _ = require('lodash');
|
var _ = require('lodash');
|
||||||
|
|
||||||
function BpmnTraverser(handler) {
|
function BpmnTreeWalker(handler) {
|
||||||
|
|
||||||
var elementDiMap = {};
|
var elementDiMap = {};
|
||||||
var elementGfxMap = {};
|
var elementGfxMap = {};
|
||||||
@ -26,7 +26,7 @@ function BpmnTraverser(handler) {
|
|||||||
|
|
||||||
// avoid multiple rendering of elements
|
// avoid multiple rendering of elements
|
||||||
if (gfx) {
|
if (gfx) {
|
||||||
return gfx;
|
throw new Error('already rendered <' + element.id + '>');
|
||||||
}
|
}
|
||||||
|
|
||||||
// call handler
|
// call handler
|
||||||
@ -133,8 +133,8 @@ function BpmnTraverser(handler) {
|
|||||||
|
|
||||||
// walk through all processes that have not yet been drawn and draw them
|
// walk through all processes that have not yet been drawn and draw them
|
||||||
// (in case they contain lanes with DI information)
|
// (in case they contain lanes with DI information)
|
||||||
var processes = _.forEach(rootElements, function(e) {
|
var processes = _.filter(rootElements, function(e) {
|
||||||
return e.$type === 'bpmn:Process' && e.laneSets && handledProcesses.indexOf(e) !== -1;
|
return e.$type === 'bpmn:Process' && e.laneSets && handledProcesses.indexOf(e) === -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
processes.forEach(contextual(handleProcess));
|
processes.forEach(contextual(handleProcess));
|
||||||
@ -272,7 +272,9 @@ function BpmnTraverser(handler) {
|
|||||||
if (is(e, 'bpmn:DataObjectReference')) {
|
if (is(e, 'bpmn:DataObjectReference')) {
|
||||||
handleDataElement(e, context);
|
handleDataElement(e, context);
|
||||||
} else {
|
} else {
|
||||||
throw new Error('unrecognized element <' + e.$type + '> in context ' + (context ? context.id : null));
|
logError(
|
||||||
|
'unrecognized flowElement <' + e.$type + '> in context ' + (context ? context.id : null),
|
||||||
|
{ element: e, context: context });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -326,4 +328,4 @@ function BpmnTraverser(handler) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = BpmnTraverser;
|
module.exports = BpmnTreeWalker;
|
@ -110,6 +110,7 @@ function importBpmnDiagram(diagram, definitions, done) {
|
|||||||
data.label = label;
|
data.label = label;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var warnings = [];
|
||||||
|
|
||||||
var visitor = {
|
var visitor = {
|
||||||
|
|
||||||
@ -161,16 +162,23 @@ function importBpmnDiagram(diagram, definitions, done) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
error: function(message, context) {
|
error: function(message, context) {
|
||||||
console.warn('[import]', message, context);
|
warnings.push({ message: message, context: context });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var walker = new BpmnTreeWalker(visitor);
|
var walker = new BpmnTreeWalker(visitor);
|
||||||
walker.handleDefinitions(definitions);
|
|
||||||
|
|
||||||
commandStack.clear();
|
try {
|
||||||
|
// import
|
||||||
|
walker.handleDefinitions(definitions);
|
||||||
|
|
||||||
done();
|
// clear command stack
|
||||||
|
commandStack.clear();
|
||||||
|
|
||||||
|
done(null, warnings);
|
||||||
|
} catch (e) {
|
||||||
|
done(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.importBpmnDiagram = Util.failSafeAsync(importBpmnDiagram);
|
module.exports.importBpmnDiagram = importBpmnDiagram;
|
2
test/fixtures/bpmn/collaboration.bpmn
vendored
2
test/fixtures/bpmn/collaboration.bpmn
vendored
@ -40,7 +40,7 @@
|
|||||||
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_3" bpmnElement="StartEvent_1">
|
<bpmndi:BPMNShape id="_BPMNShape_StartEvent_3" bpmnElement="StartEvent_1">
|
||||||
<dc:Bounds height="36.0" width="36.0" x="324.0" y="448.0"/>
|
<dc:Bounds height="36.0" width="36.0" x="324.0" y="448.0"/>
|
||||||
<bpmndi:BPMNLabel>
|
<bpmndi:BPMNLabel>
|
||||||
<dc:Bounds height="0.0" width="0.0" x="342.0" y="489.0"/>
|
<dc:Bounds height="1.0" width="0.0" x="342.0" y="489.0"/>
|
||||||
</bpmndi:BPMNLabel>
|
</bpmndi:BPMNLabel>
|
||||||
</bpmndi:BPMNShape>
|
</bpmndi:BPMNShape>
|
||||||
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="Task_1">
|
<bpmndi:BPMNShape id="_BPMNShape_Task_3" bpmnElement="Task_1">
|
||||||
|
36
test/fixtures/bpmn/error/invalid-flow-element.bpmn
vendored
Normal file
36
test/fixtures/bpmn/error/invalid-flow-element.bpmn
vendored
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<bpmn2:definitions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xsi:schemaLocation="http://www.omg.org/spec/BPMN/20100524/MODEL BPMN20.xsd" id="_u8q6UPrKEeOYcLGs4Ul9qQ" targetNamespace="http://activiti.org/bpmn">
|
||||||
|
<bpmn2:collaboration id="_Collaboration_2">
|
||||||
|
<bpmn2:participant id="_Participant_2" name="Pool" processRef="Process_1"/>
|
||||||
|
</bpmn2:collaboration>
|
||||||
|
<bpmn2:process id="Process_1" isExecutable="false">
|
||||||
|
<bpmn2:laneSet id="LaneSet_1" name="Lane Set 1">
|
||||||
|
<bpmn2:lane id="Lane_1" name="Lane 1">
|
||||||
|
<bpmn2:flowNodeRef>Task_1</bpmn2:flowNodeRef>
|
||||||
|
<bpmn2:flowNodeRef>TextAnnotation_1</bpmn2:flowNodeRef>
|
||||||
|
</bpmn2:lane>
|
||||||
|
</bpmn2:laneSet>
|
||||||
|
<bpmn2:task id="Task_1"/>
|
||||||
|
<bpmn2:textAnnotation id="TextAnnotation_1">
|
||||||
|
<bpmn2:text><![CDATA[FOOO
|
||||||
|
BAR
|
||||||
|
YOO!]]></bpmn2:text>
|
||||||
|
</bpmn2:textAnnotation>
|
||||||
|
</bpmn2:process>
|
||||||
|
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
|
||||||
|
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="_Collaboration_2">
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Participant_2" bpmnElement="_Participant_2" isHorizontal="true">
|
||||||
|
<dc:Bounds height="215.0" width="540.0" x="409.0" y="161.0"/>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Lane_2" bpmnElement="Lane_1" isHorizontal="true">
|
||||||
|
<dc:Bounds height="215.0" width="510.0" x="439.0" y="161.0"/>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_Task_2" bpmnElement="Task_1">
|
||||||
|
<dc:Bounds height="80.0" width="100.0" x="490.0" y="195.0"/>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
<bpmndi:BPMNShape id="_BPMNShape_TextAnnotation_2" bpmnElement="TextAnnotation_1">
|
||||||
|
<dc:Bounds height="106.0" width="85.0" x="744.0" y="195.0"/>
|
||||||
|
</bpmndi:BPMNShape>
|
||||||
|
</bpmndi:BPMNPlane>
|
||||||
|
</bpmndi:BPMNDiagram>
|
||||||
|
</bpmn2:definitions>
|
@ -39,29 +39,40 @@ describe('import - importer', function() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diagram;
|
||||||
|
|
||||||
it('should fire <bpmn.element.add> during import', function(done) {
|
beforeEach(function() {
|
||||||
|
diagram = createDiagram();
|
||||||
|
});
|
||||||
|
|
||||||
// given
|
|
||||||
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
|
||||||
|
|
||||||
var diagram = createDiagram();
|
function runImport(diagram, xml, done) {
|
||||||
|
|
||||||
var events = [];
|
|
||||||
|
|
||||||
// log events
|
|
||||||
diagram.get('eventBus').on('bpmn.element.add', function(e) {
|
|
||||||
events.push({ type: 'add', semantic: e.semantic.id, di: e.di.id, diagramElement: e.diagramElement.id });
|
|
||||||
});
|
|
||||||
|
|
||||||
// when
|
|
||||||
BpmnModel.fromXML(xml, function(err, definitions) {
|
BpmnModel.fromXML(xml, function(err, definitions) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return done(err);
|
return done(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Importer.importBpmnDiagram(diagram, definitions, done);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
describe('event emitter', function() {
|
||||||
|
|
||||||
|
it('should fire <bpmn.element.add> during import', function(done) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var events = [];
|
||||||
|
|
||||||
|
// log events
|
||||||
|
diagram.get('eventBus').on('bpmn.element.add', function(e) {
|
||||||
|
events.push({ type: 'add', semantic: e.semantic.id, di: e.di.id, diagramElement: e.diagramElement.id });
|
||||||
|
});
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Importer.importBpmnDiagram(diagram, definitions, function(err) {
|
runImport(diagram, xml, function(err, warnings) {
|
||||||
|
|
||||||
// then
|
// then
|
||||||
expect(events).toEqual([
|
expect(events).toEqual([
|
||||||
@ -74,31 +85,112 @@ describe('import - importer', function() {
|
|||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should clear commandStack after import', function(done) {
|
describe('basics', function() {
|
||||||
|
|
||||||
// given
|
it('should import process', function(done) {
|
||||||
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
|
||||||
|
|
||||||
var diagram = createDiagram();
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
|
||||||
var commandStack = diagram.get('commandStack');
|
var events = [];
|
||||||
|
|
||||||
// when
|
// log events
|
||||||
BpmnModel.fromXML(xml, function(err, definitions) {
|
diagram.get('eventBus').on('bpmn.element.add', function(e) {
|
||||||
if (err) {
|
events.push({ type: 'add', semantic: e.semantic.id, di: e.di.id, diagramElement: e.diagramElement.id });
|
||||||
return done(err);
|
});
|
||||||
}
|
|
||||||
|
|
||||||
// when
|
// when
|
||||||
Importer.importBpmnDiagram(diagram, definitions, function(err) {
|
runImport(diagram, xml, function(err, warnings) {
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(events).toEqual([
|
||||||
|
{ type: 'add', semantic: 'SubProcess_1', di: '_BPMNShape_SubProcess_2', diagramElement: 'SubProcess_1' },
|
||||||
|
{ type: 'add', semantic: 'StartEvent_1', di: '_BPMNShape_StartEvent_2', diagramElement: 'StartEvent_1' },
|
||||||
|
{ type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_2', diagramElement: 'Task_1' },
|
||||||
|
{ type: 'add', semantic: 'SequenceFlow_1', di: 'BPMNEdge_SequenceFlow_1', diagramElement: 'SequenceFlow_1' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should import collaboration', function(done) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/collaboration.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var events = [];
|
||||||
|
|
||||||
|
// log events
|
||||||
|
diagram.get('eventBus').on('bpmn.element.add', function(e) {
|
||||||
|
events.push({ type: 'add', semantic: e.semantic.id, di: e.di.id, diagramElement: e.diagramElement.id });
|
||||||
|
});
|
||||||
|
|
||||||
|
// when
|
||||||
|
runImport(diagram, xml, function(err, warnings) {
|
||||||
|
|
||||||
|
// then
|
||||||
|
expect(events).toEqual([
|
||||||
|
{ type: 'add', semantic: 'Participant_2', di: '_BPMNShape_Participant_2', diagramElement: 'Participant_2' },
|
||||||
|
{ type: 'add', semantic: 'Lane_1', di: '_BPMNShape_Lane_2', diagramElement: 'Lane_1' },
|
||||||
|
{ type: 'add', semantic: 'Lane_2', di: '_BPMNShape_Lane_3', diagramElement: 'Lane_2' },
|
||||||
|
{ type: 'add', semantic: 'Lane_3', di: '_BPMNShape_Lane_4', diagramElement: 'Lane_3' },
|
||||||
|
{ type: 'add', semantic: 'Task_1', di: '_BPMNShape_Task_3', diagramElement: 'Task_1' },
|
||||||
|
{ type: 'add', semantic: 'Participant_1', di: '_BPMNShape_Participant_3', diagramElement: 'Participant_1' },
|
||||||
|
{ type: 'add', semantic: 'StartEvent_1', di: '_BPMNShape_StartEvent_3', diagramElement: 'StartEvent_1' }
|
||||||
|
]);
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('command stack integration', function() {
|
||||||
|
|
||||||
|
it('should clear stack after import', function(done) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/simple.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var commandStack = diagram.get('commandStack');
|
||||||
|
|
||||||
|
// when
|
||||||
|
runImport(diagram, xml, function(err, warnings) {
|
||||||
|
|
||||||
|
// then
|
||||||
expect(commandStack.getStack()).toEqual([]);
|
expect(commandStack.getStack()).toEqual([]);
|
||||||
|
|
||||||
done(err);
|
done(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('forgiveness', function() {
|
||||||
|
|
||||||
|
it('should import invalid flowElement', function(done) {
|
||||||
|
|
||||||
|
// given
|
||||||
|
var xml = fs.readFileSync('test/fixtures/bpmn/error/invalid-flow-element.bpmn', 'utf8');
|
||||||
|
|
||||||
|
var commandStack = diagram.get('commandStack');
|
||||||
|
|
||||||
|
// when
|
||||||
|
runImport(diagram, xml, function(err, warnings) {
|
||||||
|
|
||||||
|
expect(warnings.length).toBe(1);
|
||||||
|
|
||||||
|
done(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
Loading…
x
Reference in New Issue
Block a user