@logicflow/extension
Version:
LogicFlow Extensions
793 lines (792 loc) • 31.4 kB
JavaScript
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
import { getBpmnId } from './bpmnIds';
import { handleAttributes, lfJson2Xml } from './json2xml';
import { lfXml2Json } from './xml2json';
/**
* 模块说明(BPMN Adapter)
*
* 该模块负责在 LogicFlow 内部图数据(GraphData)与 BPMN XML/JSON 之间进行双向转换:
* - adapterOut:将 LogicFlow 图数据转换为 BPMN JSON(随后由 json2xml 转为 XML)
* - adapterIn:将 BPMN JSON 转换为 LogicFlow 图数据(如果是 XML,则先经 xml2json 转为 JSON)
*
* 设计要点与特殊处理:
* - BPMN XML 的属性在 JSON 中以前缀 '-' 表示(如 '-id'、'-name'),本模块严格遵循该约定。
* - XML 中同名子节点可能出现多次,xml2json 解析后会以数组表示;本模块对数组与单对象场景均做兼容处理。
* - BPMN 画布坐标以元素左上角为基准,而 LogicFlow 以元素中心为基准;转换时需进行坐标基准转换。
* - 文本内容在导出时进行 XML 转义,在导入时进行反转义,确保特殊字符(如 <, >, & 等)能被正确保留。
*/
import { ExclusiveGatewayConfig, StartEventConfig, EndEventConfig, ServiceTaskConfig, UserTaskConfig, } from '../bpmn/constant';
/**
* BPMN 元素类型映射(用于在 JSON 中定位具体的 BPMN 节点类型)
*/
var BpmnElements;
(function (BpmnElements) {
BpmnElements["START"] = "bpmn:startEvent";
BpmnElements["END"] = "bpmn:endEvent";
BpmnElements["GATEWAY"] = "bpmn:exclusiveGateway";
BpmnElements["USER"] = "bpmn:userTask";
BpmnElements["SYSTEM"] = "bpmn:serviceTask";
BpmnElements["FLOW"] = "bpmn:sequenceFlow";
})(BpmnElements || (BpmnElements = {}));
/**
* BPMN 过程元素的标准属性键列表
* - 在解析 `processValue` 时,这些键会被视为标准属性而非扩展属性;
* - 其余未在列表中的键会进入 LogicFlow 的 `properties` 中,以保留扩展数据。
*/
var defaultAttrs = [
'-name',
'-id',
'bpmn:incoming',
'bpmn:outgoing',
'-sourceRef',
'-targetRef',
];
/**
* 将普通json转换为xmlJson
* xmlJson中property会以“-”开头
* 如果没有“-”表示为子节点
* fix issue https://github.com/didi/LogicFlow/issues/718, contain the process of #text/#cdata and array
* @param retainedFields retainedField会和默认的defaultRetainedFields:
* ["properties", "startPoint", "endPoint", "pointsList"]合并
* 这意味着出现在这个数组里的字段当它的值是数组或是对象时不会被视为一个节点而是一个属性
* @reference node type reference https://www.w3schools.com/xml/dom_nodetype.asp
*/
/**
* 导出至 BPMN JSON 时,作为属性保留的字段列表
* - 当这些字段的值为对象或数组时,仍视为属性(在 JSON 中以 '-' 前缀表示),而非子节点。
*/
var defaultRetainedFields = [
'properties',
'startPoint',
'endPoint',
'pointsList',
];
/**
* XML 实体反转义:
* - 将常见的 XML 实体还原为字符:`<`→`<`、`>`→`>`、`&`→`&`、`"`→`"`、`'`→`'`;保障流程图能正常回填
* - 使用 `String(text || '')` 规范化输入,避免 `null/undefined` 导致错误;
* - 注意:此实现为单次替换,若存在嵌套/二次编码(例如 `&lt;`),会先还原为 `<`,
* 如需完全解码,可在外层循环调用或调整替换顺序策略。
*/
var unescapeXml = function (text) {
return String(text || '')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/&/g, '&')
.replace(/"/g, '"')
.replace(/'/g, "'");
};
/**
* 将普通 JSON 转换为 XML 风格 JSON(xmlJson)
* 输入:任意 JSON 对象;可选的保留属性字段 retainedFields
* 输出:遵循 XML 属性前缀约定的 xmlJson(属性键以 '-' 开头)
* 规则:
* - 原始字符串直接返回;数组逐项转换;对象根据键类型决定是否加 '-' 前缀。
* - 保留字段(fields)中出现的键以属性形式(带 '-')保留,否则视为子节点。
*/
function toXmlJson(retainedFields) {
var fields = retainedFields
? defaultRetainedFields.concat(retainedFields)
: defaultRetainedFields;
return function (json) {
/**
* 递归转换核心方法
* @param obj 输入对象/数组/字符串
* @returns 转换后的 xmlJson
*/
function ToXmlJson(obj) {
var xmlJson = {};
if (typeof obj === 'string') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(function (j) { return ToXmlJson(j); });
}
Object.entries(obj).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
if (typeof value !== 'object') {
// node type reference https://www.w3schools.com/xml/dom_nodetype.asp
if (key.indexOf('-') === 0 ||
['#text', '#cdata-section', '#comment'].includes(key)) {
xmlJson[key] = value;
}
else {
xmlJson["-".concat(key)] = value;
}
}
else if (fields.includes(key)) {
xmlJson["-".concat(key)] = ToXmlJson(value);
}
else {
xmlJson[key] = ToXmlJson(value);
}
});
return xmlJson;
}
return ToXmlJson(json);
};
}
/**
* 将 XML 风格 JSON(xmlJson)转换回普通 JSON(内部使用)
* 输入:遵循 '-' 属性前缀约定的 xmlJson
* 输出:去除前缀并恢复原有结构的普通 JSON
*/
function toNormalJson(xmlJson) {
var json = {};
Object.entries(xmlJson).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
if (key.indexOf('-') === 0) {
json[key.substring(1)] = handleAttributes(value);
}
else if (typeof value === 'string') {
json[key] = value;
}
else if (Object.prototype.toString.call(value) === '[object Object]') {
json[key] = toNormalJson(value);
}
else if (Array.isArray(value)) {
// contain the process of array
json[key] = value.map(function (v) { return toNormalJson(v); });
}
else {
json[key] = value;
}
});
return json;
}
/**
* 设置bpmn process信息
* 目标格式请参考examples/bpmn.json
* bpmn因为是默认基于xml格式的,其特点与json存在差异。
* 1) 如果是xml的属性,json中属性用'-'开头
* 2)如果只有一个子元素,json中表示为正常属性
* 3)如果是多个子元素,json中使用数组存储
*/
/**
* 将 LogicFlow 图数据中的节点与边转换为 BPMN 的 process 数据结构
* 输入:
* - bpmnProcessData:输出目标对象(会被填充 '-id'、各 bpmn:* 节点以及 sequenceFlow)
* - data:LogicFlow 图数据(nodes/edges)
* - retainedFields:可选保留属性字段,用于控制属性与子节点的映射
* 输出:直接修改 bpmnProcessData
* 特殊处理:
* - 节点文本(node.text.value)作为 BPMN 的 '-name' 属性;
* - 维护 incoming/outgoing 的顺序,保证解析兼容性;
* - 多子元素时转为数组结构(XML 约定)。
*/
function convertLf2ProcessData(bpmnProcessData, data, retainedFields) {
var nodeMap = new Map();
data.nodes.forEach(function (node) {
var _a;
var processNode = {
'-id': node.id, // 如果是xml的属性,json中属性用'-'开头
};
if ((_a = node.text) === null || _a === void 0 ? void 0 : _a.value) {
processNode['-name'] = node.text.value;
}
if (node.properties) {
var properties = toXmlJson(retainedFields)(node.properties);
Object.assign(processNode, properties);
}
nodeMap.set(node.id, processNode);
if (!bpmnProcessData[node.type]) {
bpmnProcessData[node.type] = processNode; // 如果只有一个子元素,json中表示为正常属性
}
else if (Array.isArray(bpmnProcessData[node.type])) {
// 如果是多个子元素,json中使用数组存储
bpmnProcessData[node.type].push(processNode);
}
else {
// 如果是多个子元素,json中使用数组存储
bpmnProcessData[node.type] = [bpmnProcessData[node.type], processNode];
}
});
var sequenceFlow = data.edges.map(function (edge) {
var _a, _b;
var targetNode = nodeMap.get(edge.targetNodeId);
if (!targetNode['bpmn:incoming']) {
targetNode['bpmn:incoming'] = edge.id;
}
else if (Array.isArray(targetNode['bpmn:incoming'])) {
targetNode['bpmn:incoming'].push(edge.id);
}
else {
targetNode['bpmn:incoming'] = [targetNode['bpmn:incoming'], edge.id];
}
var edgeConfig = {
'-id': edge.id,
'-sourceRef': edge.sourceNodeId,
'-targetRef': edge.targetNodeId,
};
if ((_a = edge.text) === null || _a === void 0 ? void 0 : _a.value) {
edgeConfig['-name'] = (_b = edge.text) === null || _b === void 0 ? void 0 : _b.value;
}
if (edge.properties) {
var properties = toXmlJson(retainedFields)(edge.properties);
Object.assign(edgeConfig, properties);
}
return edgeConfig;
});
// @see https://github.com/didi/LogicFlow/issues/325
// 需要保证incoming在outgoing之前
data.edges.forEach(function (edge) {
var sourceNode = nodeMap.get(edge.sourceNodeId);
if (!sourceNode['bpmn:outgoing']) {
sourceNode['bpmn:outgoing'] = edge.id;
}
else if (Array.isArray(sourceNode['bpmn:outgoing'])) {
sourceNode['bpmn:outgoing'].push(edge.id);
}
else {
// 字符串转数组
sourceNode['bpmn:outgoing'] = [sourceNode['bpmn:outgoing'], edge.id];
}
});
bpmnProcessData[BpmnElements.FLOW] = sequenceFlow;
}
/**
* adapterOut 设置bpmn diagram信息
*/
/**
* 将 LogicFlow 图数据转换为 BPMN 的图形数据(BPMNDiagram/BPMNPlane 下的 Shape 与 Edge)
* 输入:
* - bpmnDiagramData:输出目标对象(填充 BPMNShape/BPMNEdge)
* - data:LogicFlow 图数据(nodes/edges)
* 输出:直接修改 bpmnDiagramData
* 特殊处理:
* - 节点坐标从中心点转换为左上角基准;
* - 文本的显示边界(Bounds)根据文本长度近似计算,用于在 BPMN 渲染器正确定位标签。
*/
function convertLf2DiagramData(bpmnDiagramData, data) {
bpmnDiagramData['bpmndi:BPMNEdge'] = data.edges.map(function (edge) {
var _a;
var edgeId = edge.id;
var pointsList = edge.pointsList.map(function (_a) {
var x = _a.x, y = _a.y;
return ({
'-x': x,
'-y': y,
});
});
var diagramData = {
'-id': "".concat(edgeId, "_di"),
'-bpmnElement': edgeId,
'di:waypoint': pointsList,
};
if ((_a = edge.text) === null || _a === void 0 ? void 0 : _a.value) {
diagramData['bpmndi:BPMNLabel'] = {
'dc:Bounds': {
'-x': edge.text.x - (edge.text.value.length * 10) / 2,
'-y': edge.text.y - 7,
'-width': edge.text.value.length * 10,
'-height': 14,
},
};
}
return diagramData;
});
bpmnDiagramData['bpmndi:BPMNShape'] = data.nodes.map(function (node) {
var _a;
var nodeId = node.id;
var width = 100;
var height = 80;
var x = node.x, y = node.y;
// bpmn坐标是基于左上角,LogicFlow基于中心点,此处处理一下。
var shapeConfig = BpmnAdapter.shapeConfigMap.get(node.type);
if (shapeConfig) {
width = shapeConfig.width;
height = shapeConfig.height;
}
x -= width / 2;
y -= height / 2;
var diagramData = {
'-id': "".concat(nodeId, "_di"),
'-bpmnElement': nodeId,
'dc:Bounds': {
'-x': x,
'-y': y,
'-width': width,
'-height': height,
},
};
if ((_a = node.text) === null || _a === void 0 ? void 0 : _a.value) {
diagramData['bpmndi:BPMNLabel'] = {
'dc:Bounds': {
'-x': node.text.x - (node.text.value.length * 10) / 2,
'-y': node.text.y - 7,
'-width': node.text.value.length * 10,
'-height': 14,
},
};
}
return diagramData;
});
}
/**
* 将bpmn数据转换为LogicFlow内部能识别数据
*/
/**
* 将 BPMN JSON 转换为 LogicFlow 可识别的图数据
* 输入:
* - bpmnData:包含 'bpmn:definitions' 的 BPMN JSON
* 输出:{ nodes, edges }:LogicFlow 的 GraphConfigData
* 特殊处理:
* - 若缺失 process 或 plane,返回空数据以避免渲染错误。
*/
function convertBpmn2LfData(bpmnData) {
var nodes = [];
var edges = [];
var definitions = bpmnData['bpmn:definitions'];
if (definitions) {
// 如后续需多图/多流程支持,再扩展为遍历与合并,现在看起来是没有这个场景
var process_1 = definitions['bpmn:process'];
var diagram = definitions['bpmndi:BPMNDiagram'];
var plane_1 = diagram === null || diagram === void 0 ? void 0 : diagram['bpmndi:BPMNPlane'];
if (!process_1 || !plane_1) {
return { nodes: nodes, edges: edges };
}
Object.keys(process_1).forEach(function (key) {
if (key.indexOf('bpmn:') === 0) {
var value = process_1[key];
if (key === BpmnElements.FLOW) {
var edgesRaw = plane_1['bpmndi:BPMNEdge'];
var bpmnEdges = Array.isArray(edgesRaw) ? edgesRaw : edgesRaw;
edges = getLfEdges(value, bpmnEdges);
}
else {
var shapesRaw = plane_1['bpmndi:BPMNShape'];
var shapes = Array.isArray(shapesRaw) ? shapesRaw : shapesRaw;
nodes = nodes.concat(getLfNodes(value, shapes, key));
}
}
});
}
return {
nodes: nodes,
edges: edges,
};
}
/**
* 根据 BPMN 的 process 子节点与 plane 中的 BPMNShape 生成 LogicFlow 节点数组
* 输入:
* - value:当前类型(如 bpmn:userTask)的值,可能为对象或数组
* - shapes:plane['bpmndi:BPMNShape'],可能为对象或数组
* - key:当前处理的 BPMN 类型键名(如 'bpmn:userTask')
* 输出:LogicFlow 节点数组
*/
function getLfNodes(value, shapes, key) {
var nodes = [];
if (Array.isArray(value)) {
// 数组
value.forEach(function (val) {
var shapeValue;
if (Array.isArray(shapes)) {
shapeValue = shapes.find(function (shape) { return shape['-bpmnElement'] === val['-id']; });
}
else {
shapeValue = shapes;
}
var node = getNodeConfig(shapeValue, key, val);
nodes.push(node);
});
}
else {
var shapeValue = void 0;
if (Array.isArray(shapes)) {
shapeValue = shapes.find(function (shape) { return shape['-bpmnElement'] === value['-id']; });
}
else {
shapeValue = shapes;
}
var node = getNodeConfig(shapeValue, key, value);
nodes.push(node);
}
return nodes;
}
/**
* 将单个 BPMNShape 与其对应的 process 节点合成为 LogicFlow 节点配置
* 输入:
* - shapeValue:plane 中的 BPMNShape(包含 Bounds 与可选 BPMNLabel)
* - type:BPMN 节点类型键(如 'bpmn:userTask')
* - processValue:process 中对应的节点对象(包含 '-id'、'-name' 等)
* 输出:LogicFlow NodeConfig
* 特殊处理:
* - 坐标从左上角转为中心点;
* - 文本从 '-name' 读取并进行 XML 实体反转义;
* - 文本位置优先使用 BPMNLabel 的 Bounds。
*/
function getNodeConfig(shapeValue, type, processValue) {
var x = Number(shapeValue['dc:Bounds']['-x']);
var y = Number(shapeValue['dc:Bounds']['-y']);
// 反转义 XML 实体,确保导入后文本包含特殊字符时能被完整还原
var name = unescapeXml(processValue['-name']);
var shapeConfig = BpmnAdapter.shapeConfigMap.get(type);
if (shapeConfig) {
x += shapeConfig.width / 2;
y += shapeConfig.height / 2;
}
var properties;
// 判断是否存在额外的属性,将额外的属性放到properties中
Object.entries(processValue).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
if (defaultAttrs.indexOf(key) === -1) {
if (!properties)
properties = {};
properties[key] = value;
}
});
if (properties) {
properties = toNormalJson(properties);
}
var text;
if (name) {
text = {
x: x,
y: y,
value: name,
};
// 自定义文本位置
if (shapeValue['bpmndi:BPMNLabel'] &&
shapeValue['bpmndi:BPMNLabel']['dc:Bounds']) {
var textBounds = shapeValue['bpmndi:BPMNLabel']['dc:Bounds'];
text.x = Number(textBounds['-x']) + Number(textBounds['-width']) / 2;
text.y = Number(textBounds['-y']) + Number(textBounds['-height']) / 2;
}
}
var nodeConfig = {
id: shapeValue['-bpmnElement'],
type: type,
x: x,
y: y,
properties: properties,
};
if (text) {
nodeConfig.text = text;
}
return nodeConfig;
}
/**
* 根据 BPMN 的 sequenceFlow 与 BPMNEdge 生成 LogicFlow 边数组
* 输入:
* - value:process['bpmn:sequenceFlow'],对象或数组
* - bpmnEdges:plane['bpmndi:BPMNEdge'],对象或数组
* 输出:LogicFlow 边数组
*/
function getLfEdges(value, bpmnEdges) {
var edges = [];
if (Array.isArray(value)) {
value.forEach(function (val) {
var edgeValue;
if (Array.isArray(bpmnEdges)) {
edgeValue = bpmnEdges.find(function (edge) { return edge['-bpmnElement'] === val['-id']; });
}
else {
edgeValue = bpmnEdges;
}
edges.push(getEdgeConfig(edgeValue, val));
});
}
else {
var edgeValue = void 0;
if (Array.isArray(bpmnEdges)) {
edgeValue = bpmnEdges.find(function (edge) { return edge['-bpmnElement'] === value['-id']; });
}
else {
edgeValue = bpmnEdges;
}
edges.push(getEdgeConfig(edgeValue, value));
}
return edges;
}
/**
* 将单个 BPMNEdge 与其对应的 sequenceFlow 合成为 LogicFlow 边配置
* 输入:
* - edgeValue:BPMNEdge(包含 di:waypoint 以及可选 BPMNLabel/Bounds)
* - processValue:sequenceFlow(包含 '-id'、'-sourceRef'、'-targetRef'、'-name' 等)
* 输出:LogicFlow EdgeConfig
* 特殊处理:
* - 文本从 '-name' 读取并进行 XML 实体反转义;
* - 若缺失 BPMNLabel,则以边的几何中心近似作为文本位置;
* - pointsList 由 waypoints 转换得到,数值类型统一为 Number。
*/
function getEdgeConfig(edgeValue, processValue) {
var text;
// 反转义 XML 实体,确保导入后文本包含特殊字符时能被完整还原
var textVal = processValue['-name']
? unescapeXml("".concat(processValue['-name']))
: '';
if (textVal) {
var textBounds = void 0;
if (edgeValue['bpmndi:BPMNLabel'] &&
edgeValue['bpmndi:BPMNLabel']['dc:Bounds']) {
textBounds = edgeValue['bpmndi:BPMNLabel']['dc:Bounds'];
}
// 如果边文本换行,则其偏移量应该是最长一行的位置
var textLength_1 = 0;
textVal.split('\n').forEach(function (textSpan) {
if (textLength_1 < textSpan.length) {
textLength_1 = textSpan.length;
}
});
if (textBounds) {
text = {
value: textVal,
x: Number(textBounds['-x']) + (textLength_1 * 10) / 2,
y: Number(textBounds['-y']) + 7,
};
}
else {
// 兼容缺少 BPMNLabel 的图:使用边的几何中心作为文本位置
var waypoints = edgeValue['di:waypoint'] || [];
var first = waypoints[0];
var last = waypoints[waypoints.length - 1] || first;
var centerX = (Number((first === null || first === void 0 ? void 0 : first['-x']) || 0) + Number((last === null || last === void 0 ? void 0 : last['-x']) || 0)) / 2;
var centerY = (Number((first === null || first === void 0 ? void 0 : first['-y']) || 0) + Number((last === null || last === void 0 ? void 0 : last['-y']) || 0)) / 2;
text = {
value: textVal,
x: centerX,
y: centerY,
};
}
}
var properties;
// 判断是否存在额外的属性,将额外的属性放到properties中
Object.entries(processValue).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
if (defaultAttrs.indexOf(key) === -1) {
if (!properties)
properties = {};
properties[key] = value;
}
});
if (properties) {
properties = toNormalJson(properties);
}
var edge = {
id: processValue['-id'],
type: BpmnElements.FLOW,
pointsList: edgeValue['di:waypoint'].map(function (point) { return ({
x: Number(point['-x']),
y: Number(point['-y']),
}); }),
sourceNodeId: processValue['-sourceRef'],
targetNodeId: processValue['-targetRef'],
properties: properties,
};
if (text) {
edge.text = text;
}
return edge;
}
/**
* BpmnAdapter:基础适配器
*
* 作用:在 LogicFlow 数据与 BPMN JSON 之间进行转换,并注入 adapterIn/adapterOut 钩子。
* - processAttributes:导出时 BPMN process 的基础属性(可配置 isExecutable、id 等)。
* - definitionAttributes:导出时 BPMN definitions 的基础属性与命名空间声明。
* - shapeConfigMap:不同 BPMN 元素类型的默认宽高,用于坐标/Bounds 计算。
*/
var BpmnAdapter = /** @class */ (function () {
/**
* 构造函数
* - 注入 LogicFlow 的 adapterIn/adapterOut(处理 JSON 方向的适配)
* - 初始化 process 与 definitions 的基础属性
*/
function BpmnAdapter(_a) {
var lf = _a.lf;
var _this = this;
/**
* @param retainedFields?: string[] (可选)属性保留字段,retainedField会和默认的defaultRetainedFields:
* ["properties", "startPoint", "endPoint", "pointsList"]合并,
* 这意味着出现在这个数组里的字段当它的值是数组或是对象时不会被视为一个节点而是一个属性。
*/
/**
* adapterOut:将 LogicFlow 图数据转换为 BPMN JSON
* 输入:
* - data:LogicFlow GraphData
* - retainedFields:扩展属性保留字段
* 输出:BPMN JSON(包含 definitions/process/diagram/plane)
*/
this.adapterOut = function (data, retainedFields) {
var bpmnProcessData = __assign({}, _this.processAttributes);
convertLf2ProcessData(bpmnProcessData, data, retainedFields);
var bpmnDiagramData = {
'-id': 'BPMNPlane_1',
'-bpmnElement': bpmnProcessData['-id'],
};
convertLf2DiagramData(bpmnDiagramData, data);
var definitions = _this.definitionAttributes;
definitions['bpmn:process'] = bpmnProcessData;
definitions['bpmndi:BPMNDiagram'] = {
'-id': 'BPMNDiagram_1',
'bpmndi:BPMNPlane': bpmnDiagramData,
};
var bpmnData = {
'bpmn:definitions': definitions,
};
return bpmnData;
};
/**
* adapterIn:将 BPMN JSON 转换为 LogicFlow 图数据
* 输入:bpmnData:BPMN JSON
* 输出:GraphConfigData(nodes/edges)
*/
this.adapterIn = function (bpmnData) {
if (bpmnData) {
return convertBpmn2LfData(bpmnData);
}
};
lf.adapterIn = function (data) { return _this.adapterIn(data); };
lf.adapterOut = function (data, retainedFields) {
return _this.adapterOut(data, retainedFields);
};
this.processAttributes = {
'-isExecutable': 'true',
'-id': "Process_".concat(getBpmnId()),
};
this.definitionAttributes = {
'-id': "Definitions_".concat(getBpmnId()),
'-xmlns:xsi': 'http://www.w3.org/2001/XMLSchema-instance',
'-xmlns:bpmn': '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',
'-xmlns:di': 'http://www.omg.org/spec/DD/20100524/DI',
'-targetNamespace': 'http://logic-flow.org',
'-exporter': 'logicflow',
'-exporterVersion': '1.2.0',
};
}
BpmnAdapter.prototype.setCustomShape = function (key, val) {
BpmnAdapter.shapeConfigMap.set(key, val);
};
BpmnAdapter.pluginName = 'bpmn-adapter';
BpmnAdapter.shapeConfigMap = new Map();
return BpmnAdapter;
}());
BpmnAdapter.shapeConfigMap.set(BpmnElements.START, {
width: StartEventConfig.width,
height: StartEventConfig.height,
});
BpmnAdapter.shapeConfigMap.set(BpmnElements.END, {
width: EndEventConfig.width,
height: EndEventConfig.height,
});
BpmnAdapter.shapeConfigMap.set(BpmnElements.GATEWAY, {
width: ExclusiveGatewayConfig.width,
height: ExclusiveGatewayConfig.height,
});
BpmnAdapter.shapeConfigMap.set(BpmnElements.SYSTEM, {
width: ServiceTaskConfig.width,
height: ServiceTaskConfig.height,
});
BpmnAdapter.shapeConfigMap.set(BpmnElements.USER, {
width: UserTaskConfig.width,
height: UserTaskConfig.height,
});
/**
* BpmnXmlAdapter:XML 适配器(继承 BpmnAdapter)
*
* 作用:处理 XML 输入/输出的适配,使用 xml2json/json2xml 完成格式转换。
* 特殊处理:在 XML 导入前对 name 属性的非法字符进行预处理转义,提升容错。
*/
var BpmnXmlAdapter = /** @class */ (function (_super) {
__extends(BpmnXmlAdapter, _super);
/**
* 构造函数
* - 覆盖 LogicFlow 的 adapterIn/adapterOut,使其面向 XML 输入与输出。
*/
function BpmnXmlAdapter(data) {
var _this = _super.call(this, data) || this;
/**
* adapterXmlIn:将 BPMN XML 转换为 LogicFlow 图数据
* 输入:bpmnData:XML 字符串或对象
* 步骤:
* 1) 若为字符串,先对 name 属性进行预处理转义;
* 2) 使用 lfXml2Json 转换为 BPMN JSON;
* 3) 调用基础 adapterIn 转换为 GraphData。
*/
_this.adapterXmlIn = function (bpmnData) {
var xmlStr = typeof bpmnData === 'string'
? _this.sanitizeNameAttributes(bpmnData)
: bpmnData;
var json = lfXml2Json(xmlStr);
return _this.adapterIn(json);
};
/**
* adapterXmlOut:将 LogicFlow 图数据转换为 BPMN XML
* 输入:
* - data:GraphData
* - retainedFields:保留属性字段
* 步骤:
* 1) 调用基础 adapterOut 生成 BPMN JSON;
* 2) 使用 lfJson2Xml 转为合法的 XML 字符串(包含属性与文本的转义)。
*/
_this.adapterXmlOut = function (data, retainedFields) {
var outData = _this.adapterOut(data, retainedFields);
return lfJson2Xml(outData);
};
var lf = data.lf;
lf.adapterIn = _this.adapterXmlIn;
lf.adapterOut = _this.adapterXmlOut;
return _this;
}
// 预处理:修复属性值中非法的XML字符(仅针对 name 属性)
/**
* 预处理 XML:仅对 name 属性值进行非法字符转义(<, >, &),避免 DOM 解析失败。
* 注意:不影响已合法的实体(如 &),仅在属性值中生效,不修改其它内容。
*/
BpmnXmlAdapter.prototype.sanitizeNameAttributes = function (xml) {
return xml.replace(/name="([^"]*)"/g, function (_, val) {
var safe = val
.replace(/&(?!#?\w+;)/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>');
return "name=\"".concat(safe, "\"");
});
};
BpmnXmlAdapter.pluginName = 'bpmnXmlAdapter';
return BpmnXmlAdapter;
}(BpmnAdapter));
export { BpmnAdapter, BpmnXmlAdapter, toXmlJson, toNormalJson };
export default BpmnAdapter;